4effce3c18a1ee1d1828155ab3409c06703ee42a
[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 app_dir="$1"; shift
141
142   local site_dir="$app_dir/$CHECKOUT_DIR_NAME"
143
144   if [ -f "$site_dir/bin/cake" ]; then
145     chmod -R a+rx "$site_dir/bin/cake"
146     test_or_die "Enabling execute bit on cake binary"
147   fi
148
149   if [ ! -d "$site_dir/logs" ]; then
150     mkdir -p "$site_dir/logs"
151     test_or_die "Creating logs directory"
152   fi
153   chmod -R g+w "$site_dir/logs"
154   test_or_die "Enabling group write on site's Logs directory"
155
156   if [ ! -d "$site_dir/tmp" ]; then
157     mkdir -p "$site_dir/tmp"
158     test_or_die "Creating tmp directory"
159   fi
160   chmod -R g+w "$site_dir/tmp"
161   test_or_die "Enabling group write on site's tmp directory"
162 }
163
164 # tosses out any cached object data that originated from the database.
165 function clear_orm_cache()
166 {
167   local site_dir="$1"; shift
168
169   if [ -f "$site_dir/bin/cake" ]; then
170     # flush any cached objects from db.
171     "$site_dir/bin/cake" orm_cache clear
172     test_or_die "Clearing ORM cache"
173   fi
174 }
175
176 # updates the revision control repository passed in.  this expects that the
177 # repo will live in a folder called "checkout_dirname" under the app path,
178 # which is the standard for our deployed sites.
179 # important: this also sets a global variable called site_store_path to the full
180 # path of the application.
181 function update_repo()
182 {
183   local full_app_dir="$1"; shift
184   local checkout_dirname="$1"; shift
185   local repo_root="$1"; shift
186   local repo_name="$1"; shift
187
188 echo here are parms in update repo:
189 var full_app_dir checkout_dirname repo_root repo_name
190
191   # forget any prior value, since we are going to validate the path.
192   unset site_store_path
193
194   pushd "$full_app_dir" &>/dev/null
195   test_or_die "Switching to our app dir '$full_app_dir'"
196
197   local complete_path="$full_app_dir/$checkout_dirname"
198
199   # see if the checkout directory exits.  the repo_found variable is set to
200   # non-empty if we find it and it's a valid git repo.
201   repo_found=
202   if [ -d "$checkout_dirname" ]; then
203     # checkout directory exists, so let's check it.
204     pushd "$checkout_dirname" &>/dev/null
205     test_or_die "Switching to our checkout directory: $checkout_dirname"
206
207     # ask for repository name (without .git).
208     if git rev-parse --git-dir > /dev/null 2>&1; then
209       # this is a valid git repo.
210       repo_found=yes
211     fi
212  
213     # we don't consider the state of having the dir exist but the repo be wrong as good.
214     if [ -z "$repo_found" ]; then
215       echo "There is a problem; this folder is not a valid repository:"
216       echo "  $full_app_dir"
217       echo "This script cannot continue unless the git repository is valid."
218       exit 1
219     fi
220     popd &>/dev/null
221   fi
222
223   if [ ! -z "$repo_found" ]; then
224     # a repository was found, so update the version here and leave.
225     echo "Repository $repo_name exists.  Updating it."
226     rgetem
227     test_or_die "Recursive checkout on: $complete_path"
228   else
229     # clone the repo since it wasn't found.
230     echo "Cloning repository $repo_name now."
231     git clone "$repo_root/$repo_name.git" $checkout_dirname
232     test_or_die "Git clone of repository: $repo_name"
233   fi
234
235 #not doing this here since powerup uses this and has no sudo.
236   #fix_site_perms "$complete_path"
237
238 #unused?
239   # construct the full path to where the app will actually live.
240   site_store_path="$complete_path"
241
242   popd &>/dev/null
243 }
244
245 # this function goes to the directory specified and makes it right with
246 # composer install.  this is as opposed to composer update, which could
247 # change the state. 
248 function composer_repuff()
249 {
250   local site_store_path="$1"; shift
251
252   pushd "$site_store_path" &>/dev/null
253   test_or_die "Switching to our app dir '$site_store_path'"
254
255   echo "Updating site with composer..."
256
257   composer -n install
258   test_or_die "Composer installation step on '$site_store_path'."
259   echo "Site updated."
260
261 #hmmm: argh global
262   dir="$site_store_path/$CHECKOUT_DIR_NAME/vendor/siteavenger/avcore"
263   if [ -d "$dir" ]; then
264     echo "Running avcore database migrations..."
265     logfile="$TMP/problem-avcore_db_migration-$(date_stringer).log"
266     ./bin/cake migrations migrate -p Avcore &>"$logfile"
267     if [ $? -ne 0 ]; then
268       echo "** FAILED: Database migrations for avcore.  Check log file in: $logfile"
269       # we keep going, because some sites aren't ready for this yet.
270     else
271       \rm "$logfile"
272       echo "Database for avcore migrated."
273     fi
274   fi
275
276   clear_orm_cache
277
278   popd &>/dev/null
279 }
280
281 # this function creates the links needed to make the site function properly given our
282 # various dependencies and infrastructure.
283 function create_site_links()
284 {
285   local site_store_path="$1"; shift
286   local theme_name="$1"; shift
287
288   echo "Creating symbolic links for site assets..."
289
290   # jump into the site path so we can start making relative links.
291   pushd "$site_store_path" &>/dev/null
292   test_or_die "Switching to our app dir '$site_store_path'"
293
294   pushd webroot &>/dev/null
295
296   # remove all symlinks that might plague us.
297   find . -maxdepth 1 -type l -exec rm -f {} ';'
298   test_or_die "Cleaning out links in webroot"
299
300   # link in the avcore plugin.
301   make_safe_link "../vendor/siteavenger/avcore/webroot" avcore
302
303   # make the link for our theme as a lower-case version of the theme.
304   themelower=${theme_name,,}
305   make_safe_link "../plugins/$theme_name/webroot" "$themelower"
306
307   # link in any favicon files.
308   if [ -d "../plugins/$theme_name/favicon" ]; then
309     local fave
310     for fave in "../plugins/$theme_name/favicon"/*; do
311       make_safe_link "$fave" .
312     done
313   fi
314
315   # get back out of webroot.
316   popd &>/dev/null
317
318   # hop up a level above where we had been.
319   pushd .. &>/dev/null
320
321   # link 'public' to webroot.
322   if [ -L public ]; then
323     # public is a symlink.
324     \rm public
325     test_or_die "Removing public directory symlink"
326   elif [ -d public ]; then
327     # public is a folder with default files.
328 #hmmm: is that safe?
329     \rm -rf public
330     test_or_die "Removing public directory and contents"
331   fi
332
333   # create the main 'public' symlink
334 #hmmm: argh global
335   make_safe_link $CHECKOUT_DIR_NAME/webroot public
336   test_or_die "Creating link to webroot called 'public'"
337
338 #hmmm: public/$themelower/im will be created automatically by system user with appropriate permissions
339
340   echo Created symbolic links.
341
342   popd &>/dev/null
343   popd &>/dev/null
344 }
345
346 # fetches composer to make sure it's up to date.
347 # (if powerup runs, composer install doesn't update git origin.)
348 function update_composer_repository()
349 {
350   local site_store_path="$1"; shift
351
352   pushd "$site_store_path" &>/dev/null
353
354   if git config remote.composer.url &>/dev/null; then
355     git pull composer
356     echo "Updated the composer repository."
357   else
358     echo "No composer repository was found for updating."
359   fi
360 }
361
362 # fixes the ownership for a site avenger or php application.
363 # this almost certainly will require sudo capability, if there are any ownership problems
364 # that need to be resolved.
365 function fix_appdir_ownership()
366 {
367   local appsdir="$1"; shift
368   local dir="$1"; shift
369
370   local combo="$appsdir/$dir"
371
372   # go with the default user running the script.
373   user_name="$USER"
374   if [ ! -z "$user_name" -a "$user_name" != "root" ]; then
375     echo "Chowning the apps folder to be owned by: $user_name"
376 #hmmm: have to hope for now for standard group named after user 
377     chown -R "$user_name:$user_name" "$combo"
378     test_or_die "Chowning $combo to be owned by $user_name"
379   else
380     echo "user name failed checks for chowning, was found as '$user_name'"
381   fi
382
383   # 
384 #probably not enough for path!
385   fix_site_perms "$combo"
386 }
387
388