Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | |
| 3 | # Usage: |
| 4 | # ./formula-fetch.sh <Formula URL> <Name> <Branch> |
| 5 | # |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 6 | # Example usage: |
| 7 | # FORMULA_SOURCES=https://github.com/epcim/my-salt-formulas https://github.com/salt-formulas https://github.com/saltstack-formulas |
| 8 | # SALT_ENV_PATH=.vendor/formulas |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 9 | # -- |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 10 | # ./formula-fetch.sh |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 11 | # xargs -n1 ./formula-fetch.sh < dependencies.txt |
| 12 | |
| 13 | |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 14 | ## DEFAULTS |
| 15 | # |
| 16 | # default sources |
| 17 | FORMULA_SOURCES="${SALT_FORMULA_SOURCES:-https://github.com/salt-formulas https://github.com/saltstack-formulas}" |
| 18 | FORMULA_VERSION="${SALT_FORMULA_VERSION:-master}" |
| 19 | # salt env/root, where formulas are found |
| 20 | SALT_ENV_PATH=${SALT_ENV_PATH:-/srv/salt/env/prd} |
| 21 | #SALT_ENV_PATH=${SALT_ENV_PATH:-.vendor/formulas} |
| 22 | #SALT_ENV_PATH=${SALT_ENV_PATH:/usr/share/salt-formulas/env/_formulas} |
| 23 | # where to fetch formulas |
| 24 | FORMULAS_BASE=${SALT_FORMULAS_BASE:-/srv/salt/formulas} |
| 25 | # reclass related |
| 26 | RECLASS_BASE=${RECLASS_BASE:-/srv/salt/reclass} |
| 27 | LC_ALL=en_US.UTF-8 |
| 28 | LANG=en_US.UTF-8 |
| 29 | |
| 30 | |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 31 | # Parse git dependencies from metadata.yml |
| 32 | # $1 - path to <formula>/metadata.yml |
| 33 | # sample to output: |
| 34 | # https://github.com/salt-formulas/salt-formula-git git |
| 35 | # https://github.com/salt-formulas/salt-formula-salt salt |
| 36 | function fetchDependencies() { |
| 37 | METADATA="$1"; |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 38 | grep -E "^dependencies:" "$METADATA" &>/dev/null || return 0 |
| 39 | (python3 - "$METADATA" | while read dep; do fetchGitFormula $dep; done) <<-DEPS |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 40 | import sys,yaml |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 41 | try: |
| 42 | for dep in yaml.load(open(sys.argv[1], "r"))["dependencies"]: |
| 43 | if len(set(('name', 'source')) & set(dep.keys())) == 2: |
| 44 | print("{source} {name}".format(**dep)) |
| 45 | except: |
| 46 | pass |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 47 | DEPS |
| 48 | } |
| 49 | |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 50 | |
| 51 | # Read formula name from meetadata.yml |
| 52 | # $1 - path to <formula>/metadata.yml |
| 53 | function getFormulaName() { |
| 54 | python3 - "$1" <<-READ_NAME |
| 55 | try: |
| 56 | import sys,yaml;print(yaml.load(open(sys.argv[1], "r"))["name"]); |
| 57 | except: |
| 58 | pass |
| 59 | READ_NAME |
| 60 | } |
| 61 | |
| 62 | |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 63 | # Fetch formula from git repo |
| 64 | # $1 - formula git repo url |
| 65 | # $2 - formula name (optional) |
| 66 | # $3 - branch (optional) |
| 67 | function fetchGitFormula() { |
| 68 | test -n "${FETCHED}" || declare -a FETCHED=() |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 69 | mkdir -p "$SALT_ENV_PATH" "$FORMULAS_BASE" |
| 70 | |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 71 | if [ -n "$1" ]; then |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 72 | |
| 73 | # set origin uri |
| 74 | # FIXME, TEMP fix for not yet up to date gh:salt-formulas -> s/tcpcloud/salt-formulas/ |
| 75 | origin="${1/tcpcloud/salt-formulas}" |
| 76 | # set gh repo https://salt-formulas/salt-formula-salt -> $FORMULAS_BASE/salt-formulas/salt-formula-salt |
| 77 | repo=$(echo $origin | awk -F'/' '{ print substr($0, index($0,$4)) }') |
| 78 | # set normula name |
| 79 | test -n "$2" && name=$2 || name="$(echo ${origin//*\/} | sed -e 's/-formula$//' -e 's/^salt-formula-//' -e 's/^formula-//')" |
| 80 | # set branch |
| 81 | test -n "$3" && branch=$3 || branch=${FORMULA_VERSION} |
| 82 | |
| 83 | # DEBUG |
| 84 | #echo '--- ------------------------------' |
| 85 | #echo origin, $origin |
| 86 | #echo repo, $repo |
| 87 | #echo fetched ${FETCHED[@]} |
| 88 | #echo -e name, $name |
| 89 | #echo '---' |
| 90 | #return |
| 91 | |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 92 | if ! [[ "${FETCHED[*]}" =~ $name ]]; then # dependency not yet fetched |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 93 | echo -e "[I] Fetching: $origin -> $FORMULAS_BASE/$repo" |
| 94 | if [ -e "$FORMULAS_BASE/$repo" ]; then |
| 95 | pushd "$FORMULAS_BASE/$repo" &>/dev/null |
| 96 | git pull -r; git checkout $branch; |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 97 | popd &>/dev/null |
| 98 | else |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 99 | echo -e "[I] git clone $origin $FORMULAS_BASE/$repo -b $branch" |
| 100 | if ! git ls-remote --exit-code --heads $origin $branch; then |
| 101 | # Fallback to the master branch if the branch doesn't exist for this repository |
| 102 | branch=master |
| 103 | fi |
| 104 | if ! git clone "$origin" "$FORMULAS_BASE/$repo" -b "$branch"; then |
| 105 | echo -e "[E] Fetching formula from $origin failed." |
| 106 | return ${FAIL_ON_ERRORS:-0} |
| 107 | fi |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 108 | fi |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 109 | |
| 110 | # metadata.yml is github.com/salt-formulas specific |
| 111 | if [ ! -n "$2" -a -e "$FORMULAS_BASE/$repo/metadata.yml" ]; then |
| 112 | # try to update name as in formula metadata |
| 113 | name=$(getFormulaName "$FORMULAS_BASE/$repo/metadata.yml") |
| 114 | fi |
| 115 | |
| 116 | # SET FORMULA IN SALT ENV |
| 117 | if [ ! -e "$SALT_ENV_PATH/$name" ]; then |
| 118 | if [ -e $FORMULAS_BASE/$repo/$name ]; then |
| 119 | |
| 120 | # link formula |
| 121 | ln -svf $FORMULAS_BASE/$repo/$name $SALT_ENV_PATH/$name |
| 122 | |
| 123 | # copy custom _states, _modules, _etc ... |
| 124 | for c in $(/bin/ls $FORMULAS_BASE/$repo | grep '^_' | xargs -n1 --no-run-if-empty); do |
| 125 | test -e $SALT_ENV_PATH/$c || mkdir -p $SALT_ENV_PATH/$c |
| 126 | ln -svf $FORMULAS_BASE/$repo/$c/* $SALT_ENV_PATH/$c |
| 127 | done |
| 128 | |
| 129 | # install optional dependencies (python/pip related as of now only) |
| 130 | if [ -e $FORMULAS_BASE/$repo/requirements.txt ]; then |
| 131 | pip install -r $FORMULAS_BASE/$repo/requirements.txt |
| 132 | fi |
| 133 | |
| 134 | # NOTE: github.com/salt-formulas specific steps |
| 135 | # link formula service pillars |
| 136 | if [ ! -n "$RECLASS_BASE" -a -e "$FORMULAS_BASE/$repo/metadata/service" ]; then |
| 137 | test -e $RECLASS_BASE/service || mkdir -p $RECLASS_BASE/service |
| 138 | ln -svf $FORMULAS_BASE/$repo/metadata/service $RECLASS_BASE/service/$name |
| 139 | fi |
| 140 | # install dependencies |
| 141 | FETCHED+=($name) |
| 142 | if [ -e "$FORMULAS_BASE/$repo/metadata.yml" ]; then |
| 143 | fetchDependencies "$FORMULAS_BASE/$repo/metadata.yml" |
| 144 | fi |
| 145 | else |
| 146 | echo -e "[E] The repository $FORMULAS_BASE/$repo was not recognized as formula repository." |
| 147 | return ${FAIL_ON_ERRORS:-0} |
| 148 | fi |
| 149 | else |
| 150 | echo -e "[I] Formula "$name" already fetched." |
| 151 | fi |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 152 | fi |
| 153 | else |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 154 | echo -e '[I] Usage: fetchGitFormula git_repo_uri [branch] [local formula directory name]' |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 155 | fi |
| 156 | } |
| 157 | |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 158 | # DEPRECATED, kept for backward compatibility |
| 159 | # for github.com/salt-formulas (linking "service" pillar metadata from formula to reclas classes) |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 160 | function linkFormulas() { |
| 161 | # OPTIONAL: Link formulas from git/pkg |
| 162 | |
| 163 | SALT_ROOT=$1 |
| 164 | SALT_ENV=${2:-/usr/share/salt-formulas/env} |
| 165 | |
| 166 | # form git, development versions |
| 167 | find "$SALT_ENV"/_formulas -maxdepth 1 -mindepth 1 -type d -print0| xargs -0 -n1 --no-run-if-empty basename | xargs -I{} --no-run-if-empty \ |
| 168 | ln -fs "$SALT_ENV"/_formulas/{}/{} "$SALT_ROOT"/{}; |
| 169 | |
| 170 | # form pkgs |
| 171 | find "$SALT_ENV" -maxdepth 1 -mindepth 1 -path "*_formulas*" -prune -o -name "*" -type d -print0| xargs -0 -n1 --no-run-if-empty basename | xargs -I{} --no-run-if-empty \ |
| 172 | ln -fs "$SALT_ENV"/{} "$SALT_ROOT"/{}; |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 173 | } |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 174 | |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 175 | |
| 176 | function setupPyEnv() { |
| 177 | MODULES="pygithub pyyaml" |
| 178 | pip3 install --upgrade $MODULES || { |
| 179 | which pipenv || { |
| 180 | pip install --upgrade pipenv |
| 181 | } |
| 182 | pipenv --three |
| 183 | pipenv install $MODULES |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | function listRepos_github_com() { |
| 188 | #export python=$(pipenv --py || (setupPyEnv &>/dev/null; pipenv --py)) |
| 189 | if [ -e Pipfile.lock ]; then python=$(pipenv --py); else python=python3; fi |
| 190 | $python - "$1" <<-LIST_REPOS |
| 191 | import sys |
| 192 | import github |
| 193 | |
| 194 | def make_github_agent(user=None, password=None): |
| 195 | """ Create github agent to auth """ |
| 196 | if not user: |
| 197 | return github.Github() |
| 198 | else: |
| 199 | return github.Github(user, password) |
| 200 | |
| 201 | def get_org_repos(gh, org_name): |
| 202 | org = gh.get_organization(org_name) |
| 203 | for repo in org.get_repos(): |
| 204 | yield repo.name |
| 205 | |
| 206 | print(*get_org_repos(make_github_agent(), str(sys.argv[1])), sep="\n") |
| 207 | LIST_REPOS |
| 208 | } |
| 209 | |
| 210 | function fetchAll() { |
| 211 | for source in $(echo ${FORMULA_SOURCES} | xargs -n1 --no-run-if-empty| xargs -n1 --no-run-if-empty); do |
| 212 | hosting=$(echo ${source//\./_} | awk -F'/' '{print $3}') |
| 213 | orgname=$(echo ${source//\./_} | awk -F'/' '{print $4}') |
| 214 | for repo in $(listRepos_$hosting "$orgname" | xargs -n1 --no-run-if-empty| sort); do |
| 215 | # TODO, avoid a hardcoded pattern to filter formula repos |
| 216 | if [[ $repo =~ ^(.*formula.*)$ ]]; then |
| 217 | fetchGitFormula "$source/$repo"; |
| 218 | fi |
| 219 | done; |
| 220 | done; |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | # detect if file is being sourced |
| 224 | [[ "$0" != "$BASH_SOURCE" ]] || { |
Petr Michalec | 40e909d | 2018-03-26 21:15:50 +0200 | [diff] [blame^] | 225 | # if executed, fetch specific formula |
| 226 | fetchGitFormula ${@} |
Ales Komarek | 1b37311 | 2017-08-08 08:48:56 +0200 | [diff] [blame] | 227 | } |