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