standup finally working
[feisty_meow.git] / scripts / site_avenger / shared_site_mgr.sh
1 #!/bin/bash
2
3 # Author: Kevin Wentworth
4 # Author: Chris Koeritz
5
6 # This contains a bunch of reusable functions that help out in managing websites.
7
8 # This script is sourced, and relies on the value of WORKDIR, which should
9 # point at the directory where the site management scripts are stored,
10 # especially this one.
11
12 source "$FEISTY_MEOW_SCRIPTS/core/launch_feisty_meow.sh"
13
14 # get our configuration loaded, if we know the config file.
15 # if there is none, we will use our default version.
16 export SITE_MANAGEMENT_CONFIG_FILE
17 if [ -z "$SITE_MANAGEMENT_CONFIG_FILE" ]; then
18   SITE_MANAGEMENT_CONFIG_FILE="$WORKDIR/config/default.app"
19 fi
20
21 # load in at least the default version to get us moving.
22 source "$SITE_MANAGEMENT_CONFIG_FILE"
23 test_or_die "loading site management configuration from: $SITE_MANAGEMENT_CONFIG_FILE"
24
25 # configure feisty revision control to ignore vendor folders.
26 export NO_CHECKIN_VENDOR=true
27
28 # tests that the main storage folder for apps exists.
29 function check_application_dir()
30 {
31   local appdir="$1"; shift
32   if [ ! -d "$appdir" ]; then
33     echo "Creating the apps directory: $appdir"
34     mkdir "$appdir"
35     test_or_die "Making apps directory when not already present"
36   fi
37 }
38
39 # this function will seek out top-level directories in the target directory passed in.
40 # if there is only one directory, then it is returned (in the app_dirname variable).
41 # otherwise, the user is asked which directory to use.
42 # important: this sets a global variable app_dirname to the application's directory name.
43 function find_app_folder()
44 {
45   local appsdir="$1"; shift
46
47   # throw away any prior value so no confusion arises.
48   unset app_dirname
49   
50   # count number of directories...  if exactly one, then choose it.
51   numdirs=$(count_directories "$appsdir")
52
53   if [ $numdirs -eq 0 ]; then
54     sep
55     echo "There are no directories in the application directory:"
56     echo "  $appsdir"
57     echo "Please create a directory for the site storage, based on the application"
58     echo "name that you want to work on.  Or you can just pass the directory name"
59     echo "on the command line, e.g.:"
60     echo "  $(basename $0) turtle"
61     sep
62     exit 1
63   elif [ $numdirs -eq 1 ]; then
64     app_dirname="$(basename $(find "$appsdir" -mindepth 1 -maxdepth 1 -type d) )"
65     test_or_die "Guessing application folder"
66   else
67     # if more than one folder, force user to choose.
68     # Reference: https://askubuntu.com/questions/1705/how-can-i-create-a-select-menu-in-a-shell-script
69     holdps3="$PS3"
70     PS3='Please pick a folder for site initialization: '
71     options=( $(find "$appsdir" -mindepth 1 -maxdepth 1 -type d -exec basename {} ';') "Quit")
72     select app_dirname in "${options[@]}"; do
73       case $app_dirname in
74         "Quit") echo ; echo "Quitting from the script."; exit 1; ;;
75         *) echo ; echo "You picked folder '$app_dirname'" ; break; ;;
76       esac
77     done
78     if [ -z "$app_dirname" ]; then
79       echo "The folder was not provided.  This script needs a directory name"
80       echo "within which to initialize the site."
81       exit 1
82     fi
83     PS3="$holdps3"
84   fi
85   test_app_folder "$appsdir" "$app_dirname"
86   test_or_die "Testing application folder: $app_dirname"
87
88   echo "Application folder is: $app_dirname"
89
90   local configfile="$WORKDIR/config/${app_dirname}.app"
91   if [ ! -f "$configfile" ]; then
92     # this is not a good config file.  we can't auto-guess the config.
93     echo -e "
94 There is no specific site configuration file in:
95   $configfile
96 We will continue onward using the default and hope that this project follows
97 the standard pattern for cakephp projects."
98     # we'll pull in the default config file we set earlier; this will
99     # reinitialize some variables based on the app name.
100   else
101     # they gave us a valid config file.  let's try using it.
102     SITE_MANAGEMENT_CONFIG_FILE="$configfile"
103   fi
104
105   # try to load the config.
106   source "$SITE_MANAGEMENT_CONFIG_FILE"
107   test_or_die "loading site management configuration from: $SITE_MANAGEMENT_CONFIG_FILE"
108 }
109
110 # ensures that the app directory name is valid.
111 function test_app_folder()
112 {
113   local appsdir="$1"; shift
114   local dir="$1"; shift
115
116   local combo="$appsdir/$dir"
117
118   if [ ! -d "$combo" ]; then
119     echo "Creating app directory: $combo"
120     mkdir "$combo"
121     test_or_die "Making application directory when not already present"
122   fi
123 }
124
125 # eases some permissions to enable apache to write log files and do other shopkeeping.
126 function fix_site_perms()
127 {
128   local site_dir="$1"; shift
129
130   if [ -f "$site_dir/bin/cake" ]; then
131     chmod -R a+rx "$site_dir/bin/cake"
132     test_or_die "Enabling execute bit on cake binary"
133   fi
134
135   if [ -d "$site_dir/logs" ]; then
136     chmod -R g+w "$site_dir/logs"
137     test_or_die "Enabling group write on site's Logs directory"
138   fi
139
140   if [ -d "$site_dir/tmp" ]; then
141     chmod -R g+w "$site_dir/tmp"
142     test_or_die "Enabling group write on site's tmp directory"
143   fi
144 }
145
146 # tosses out any cached object data that originated from the database.
147 function clear_orm_cache()
148 {
149   local site_dir="$1"; shift
150
151   if [ -f "$site_dir/bin/cake" ]; then
152     # flush any cached objects from db.
153     "$site_dir/bin/cake" orm_cache clear
154     test_or_die "Clearing ORM cache"
155   fi
156 }
157
158 # updates the revision control repository passed in.  this expects that the
159 # repo will live in a folder called "checkout_dirname" under the app path,
160 # which is the standard for our deployed sites.
161 # important: this also sets a global variable called site_store_path to the full
162 # path of the application.
163 function update_repo()
164 {
165   local full_app_dir="$1"; shift
166   local checkout_dirname="$1"; shift
167   local repo_root="$1"; shift
168   local repo_name="$1"; shift
169
170 echo here are parms in update repo:
171 var full_app_dir checkout_dirname repo_root repo_name
172
173   # forget any prior value, since we are going to validate the path.
174   unset site_store_path
175
176   pushd "$full_app_dir" &>/dev/null
177   test_or_die "Switching to our app dir '$full_app_dir'"
178
179   local complete_path="$full_app_dir/$checkout_dirname"
180
181 echo A
182   # see if the checkout directory exits.  the repo_found variable is set to
183   # non-empty if we find it and it's a valid git repo.
184   repo_found=
185   if [ -d "$checkout_dirname" ]; then
186 echo B
187     # checkout directory exists, so let's check it.
188     pushd "$checkout_dirname" &>/dev/null
189     test_or_die "Switching to our checkout directory: $checkout_dirname"
190
191     # ask for repository name (without .git).
192     if git rev-parse --git-dir > /dev/null 2>&1; then
193       # this is a valid git repo.
194       repo_found=yes
195     fi
196  
197 echo C
198     # we don't consider the state of having the dir exist but the repo be wrong as good.
199     if [ -z "$repo_found" ]; then
200       echo "There is a problem; this folder is not a valid repository:"
201       echo "  $full_app_dir"
202       echo "This script cannot continue unless the git repository is valid."
203       exit 1
204     fi
205     popd &>/dev/null
206   fi
207
208 echo D
209   if [ ! -z "$repo_found" ]; then
210     # a repository was found, so update the version here and leave.
211 echo E
212     echo "Repository $repo_name exists.  Updating it."
213     rgetem
214     test_or_die "Recursive checkout on: $complete_path"
215   else
216 echo F
217     # clone the repo since it wasn't found.
218     echo "Cloning repository $repo_name now."
219     git clone "$repo_root/$repo_name.git" $checkout_dirname
220     test_or_die "Git clone of repository: $repo_name"
221   fi
222
223 echo G
224   fix_site_perms "$complete_path"
225
226   # construct the full path to where the app will actually live.
227   site_store_path="$complete_path"
228
229   popd &>/dev/null
230 }
231
232 # this function goes to the directory specified and makes it right with
233 # composer install.  this is as opposed to composer update, which could
234 # change the state. 
235 function composer_repuff()
236 {
237   local site_store_path="$1"; shift
238
239   pushd "$site_store_path" &>/dev/null
240   test_or_die "Switching to our app dir '$site_store_path'"
241
242   echo "Updating site with composer..."
243
244   composer -n install
245   test_or_die "Composer installation step on '$site_store_path'."
246   echo "Site updated."
247
248 #hmmm: argh global
249   dir="$site_store_path/$CHECKOUT_DIR_NAME/vendor/siteavenger/avcore"
250   if [ -d "$dir" ]; then
251     echo "Running avcore database migrations..."
252     logfile="$TMP/problem-avcore_db_migration-$(date_stringer).log"
253     ./bin/cake migrations migrate -p Avcore &>"$logfile"
254     if [ $? -ne 0 ]; then
255       echo "** FAILED: Database migrations for avcore.  Check log file in: $logfile"
256       # we keep going, because some sites aren't ready for this yet.
257     else
258       \rm "$logfile"
259       echo "Database for avcore migrated."
260     fi
261   fi
262
263   clear_orm_cache
264
265   popd &>/dev/null
266 }
267
268 # this function creates the links needed to make the site function properly given our
269 # various dependencies and infrastructure.
270 function create_site_links()
271 {
272   local site_store_path="$1"; shift
273   local theme_name="$1"; shift
274
275   echo "Creating symbolic links for site assets..."
276
277   # jump into the site path so we can start making relative links.
278   pushd "$site_store_path" &>/dev/null
279   test_or_die "Switching to our app dir '$site_store_path'"
280
281   pushd webroot &>/dev/null
282
283   # remove all symlinks that might plague us.
284   find . -maxdepth 1 -type l -exec rm -f {} ';'
285   test_or_die "Cleaning out links in webroot"
286
287   # link in the avcore plugin.
288   make_safe_link "../vendor/siteavenger/avcore/webroot" avcore
289
290   # make the link for our theme as a lower-case version of the theme.
291   themelower=${theme_name,,}
292   make_safe_link "../plugins/$theme_name/webroot" "$themelower"
293
294   # link in any favicon files.
295   if [ -d "../plugins/$theme_name/favicon" ]; then
296     local fave
297     for fave in "../plugins/$theme_name/favicon"/*; do
298       make_safe_link "$fave" .
299     done
300   fi
301
302   # get back out of webroot.
303   popd &>/dev/null
304
305   # hop up a level above where we had been.
306   pushd .. &>/dev/null
307
308   # link 'public' to webroot.
309   if [ -L public ]; then
310     # public is a symlink.
311     \rm public
312     test_or_die "Removing public directory symlink"
313   elif [ -d public ]; then
314     # public is a folder with default files.
315 #hmmm: is that safe?
316     \rm -rf public
317     test_or_die "Removing public directory and contents"
318   fi
319
320   # create the main 'public' symlink
321 #hmmm: argh global
322   make_safe_link $CHECKOUT_DIR_NAME/webroot public
323   test_or_die "Creating link to webroot called 'public'"
324
325 #hmmm: public/$themelower/im will be created automatically by system user with appropriate permissions
326
327   echo Created symbolic links.
328
329   popd &>/dev/null
330   popd &>/dev/null
331 }
332
333 # fetches composer to make sure it's up to date.
334 # (if powerup runs, composer install doesn't update git origin.)
335 function update_composer_repository()
336 {
337   local site_store_path="$1"; shift
338
339   pushd "$site_store_path" &>/dev/null
340
341   if git config remote.composer.url &>/dev/null; then
342     git pull composer
343     echo "Updated the composer repository."
344   else
345     echo "No composer repository was found for updating."
346   fi
347 }
348
349