blob: bfc02cf53f3153b699be68361f7b9f37ca404779 [file] [log] [blame]
Ales Komarek1b373112017-08-08 08:48:56 +02001#!/bin/bash
2
3# Usage:
4# ./formula-fetch.sh <Formula URL> <Name> <Branch>
5#
Petr Michalec40e909d2018-03-26 21:15:50 +02006# 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 Komarek1b373112017-08-08 08:48:56 +02009# --
Petr Michalec40e909d2018-03-26 21:15:50 +020010# ./formula-fetch.sh
Ales Komarek1b373112017-08-08 08:48:56 +020011# xargs -n1 ./formula-fetch.sh < dependencies.txt
12
13
Petr Michalec40e909d2018-03-26 21:15:50 +020014## DEFAULTS
15#
16# default sources
17FORMULA_SOURCES="${SALT_FORMULA_SOURCES:-https://github.com/salt-formulas https://github.com/saltstack-formulas}"
18FORMULA_VERSION="${SALT_FORMULA_VERSION:-master}"
19# salt env/root, where formulas are found
20SALT_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
24FORMULAS_BASE=${SALT_FORMULAS_BASE:-/srv/salt/formulas}
25# reclass related
26RECLASS_BASE=${RECLASS_BASE:-/srv/salt/reclass}
27LC_ALL=en_US.UTF-8
28LANG=en_US.UTF-8
29
30
Ales Komarek1b373112017-08-08 08:48:56 +020031# 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
36function fetchDependencies() {
37 METADATA="$1";
Petr Michalec40e909d2018-03-26 21:15:50 +020038 grep -E "^dependencies:" "$METADATA" &>/dev/null || return 0
39 (python3 - "$METADATA" | while read dep; do fetchGitFormula $dep; done) <<-DEPS
Ales Komarek1b373112017-08-08 08:48:56 +020040 import sys,yaml
Petr Michalec40e909d2018-03-26 21:15:50 +020041 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 Komarek1b373112017-08-08 08:48:56 +020047 DEPS
48}
49
Petr Michalec40e909d2018-03-26 21:15:50 +020050
51# Read formula name from meetadata.yml
52# $1 - path to <formula>/metadata.yml
53function 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 Komarek1b373112017-08-08 08:48:56 +020063# Fetch formula from git repo
64# $1 - formula git repo url
65# $2 - formula name (optional)
66# $3 - branch (optional)
67function fetchGitFormula() {
68 test -n "${FETCHED}" || declare -a FETCHED=()
Petr Michalec40e909d2018-03-26 21:15:50 +020069 mkdir -p "$SALT_ENV_PATH" "$FORMULAS_BASE"
70
Ales Komarek1b373112017-08-08 08:48:56 +020071 if [ -n "$1" ]; then
Petr Michalec40e909d2018-03-26 21:15:50 +020072
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 Komarek1b373112017-08-08 08:48:56 +020092 if ! [[ "${FETCHED[*]}" =~ $name ]]; then # dependency not yet fetched
Petr Michalec40e909d2018-03-26 21:15:50 +020093 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 Komarek1b373112017-08-08 08:48:56 +020097 popd &>/dev/null
98 else
Petr Michalec40e909d2018-03-26 21:15:50 +020099 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 Komarek1b373112017-08-08 08:48:56 +0200108 fi
Petr Michalec40e909d2018-03-26 21:15:50 +0200109
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 Komarek1b373112017-08-08 08:48:56 +0200152 fi
153 else
Petr Michalec40e909d2018-03-26 21:15:50 +0200154 echo -e '[I] Usage: fetchGitFormula git_repo_uri [branch] [local formula directory name]'
Ales Komarek1b373112017-08-08 08:48:56 +0200155 fi
156}
157
Petr Michalec40e909d2018-03-26 21:15:50 +0200158# DEPRECATED, kept for backward compatibility
159# for github.com/salt-formulas (linking "service" pillar metadata from formula to reclas classes)
Ales Komarek1b373112017-08-08 08:48:56 +0200160function 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 Michalec40e909d2018-03-26 21:15:50 +0200173}
Ales Komarek1b373112017-08-08 08:48:56 +0200174
Petr Michalec40e909d2018-03-26 21:15:50 +0200175
176function 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
187function 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
210function 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 Komarek1b373112017-08-08 08:48:56 +0200221}
222
223# detect if file is being sourced
224[[ "$0" != "$BASH_SOURCE" ]] || {
Petr Michalec40e909d2018-03-26 21:15:50 +0200225 # if executed, fetch specific formula
226 fetchGitFormula ${@}
Ales Komarek1b373112017-08-08 08:48:56 +0200227}