3 # Author: Kevin Wentworth
4 # Author: Chris Koeritz
6 # This contains a bunch of reusable functions that help out in managing websites.
8 # This script is sourced, and relies on the value of THISDIR, which should
9 # point at the directory where the site management scripts are stored,
10 # especially this one.
12 source "$FEISTY_MEOW_SCRIPTS/core/launch_feisty_meow.sh"
14 export SSM_LOG_FILE="$TMP/$(logname)-siteavenger-script.log"
16 # configure feisty revision control to ignore vendor folders.
17 export NO_CHECKIN_VENDOR=true
19 # handles the computation of the base application path and the app dir name.
20 # this expects to be passed the application directory name, but it will attempt to
21 # do something intelligent if no name is passed in.
22 function autoconfigure_paths()
24 export app_dirname="$1"; shift
26 if [ -z "$app_dirname" ]; then
27 echo "$(date_stringer): Guessing application dir from local folder."
28 app_dirname="$(basename $(\pwd))"
29 export BASE_APPLICATION_PATH="$(dirname $(\pwd))"
30 echo "calculated application dir of '$app_dirname' and"
31 echo "a base app path of '$BASE_APPLICATION_PATH'"
34 # get our configuration loaded, if we know the config file.
35 # if there is none, we will use our default version.
36 export SITE_MANAGEMENT_CONFIG_FILE
37 if [ -z "$SITE_MANAGEMENT_CONFIG_FILE" ]; then
38 SITE_MANAGEMENT_CONFIG_FILE="$THISDIR/config/default.app"
39 echo "$(date_stringer): Site management config file was not set. Using default:" >> "$SSM_LOG_FILE"
40 echo "$(date_stringer): $SITE_MANAGEMENT_CONFIG_FILE" >> "$SSM_LOG_FILE"
43 # load in at least the default version to get us moving.
44 source "$SITE_MANAGEMENT_CONFIG_FILE"
45 exit_on_error "loading site management configuration from: $SITE_MANAGEMENT_CONFIG_FILE"
48 echo "after site config file sourced, app dirname now '$app_dirname' and"
49 echo "base app path now '$BASE_APPLICATION_PATH'"
53 # tests that the main storage folder for apps exists.
54 # the parameter passed in should be the application directory name (app_dirname), without
55 # any additional path components. the script will attempt to auto-configure the application
56 # base path (above the project folder with app_dirname) and get all the other path variables
58 function check_apps_root()
60 local temp_app_dirname="$1"; shift
62 echo new call to auto conf func...
63 autoconfigure_paths "$temp_app_dirname"
64 echo after call to auto conf func...
66 if [ -z "$BASE_APPLICATION_PATH" ]; then
67 echo fix this: we had no base app path, what to do now?
71 if [ ! -d "$BASE_APPLICATION_PATH" ]; then
72 echo "$(date_stringer): Creating the apps directory: $BASE_APPLICATION_PATH" >> "$SSM_LOG_FILE"
73 mkdir "$BASE_APPLICATION_PATH"
74 exit_on_error "Making apps directory when not already present"
78 #hmmm: extract to core somewhere...
79 # locates a parent directory of a certain name, if possible. returns success
80 # (as zero) if the directory was found, and failure if there was no parent
81 # named as requested. sets a global variable PARENT_DIR_FOUND to the full
82 # directory name that matched, including the name being sought (but omitting
83 # any deeper directories than that).
84 function find_named_parent_dir()
86 local dir_name_sought="$1"; shift
87 # clear any previous global result.
88 unset PARENT_DIR_FOUND
89 # check for degenerate case of parameter count.
90 if [ -z "$dir_name_sought" ]; then
92 find_named_parent_dir: requires a directory name parameter, which will be
93 sought out above the current directory. the return value indicates whether
94 the requested name was found or not.
98 # signal a failure by default with our return value.
100 # loop upwards in dir hierarchy to find the name.
102 local currdir="$(\pwd)"
103 if [ "$currdir" == "/" ]; then
104 # we climbed out of all subdirs. this is a failure case.
108 # get the base part of our name to check on success.
109 local base="$(basename "$currdir")"
110 if [ "$base" == "$dir_name_sought" ]; then
111 # yes, that is the right name. success case. save our result.
112 export PARENT_DIR_FOUND="$currdir"
116 # hop up a directory.
120 # rollback any directories we pushed.
121 while popd &>/dev/null; do true; done
126 # tries to find an appropriate config file for the application.
127 function locate_config_file()
129 local app_dirname="$1"; shift
131 local configfile="$THISDIR/config/${app_dirname}.app"
132 echo "$(date_stringer): config file guessed?: $configfile" >> "$SSM_LOG_FILE"
133 if [ ! -f "$configfile" ]; then
134 # this is not a good config file. we can't auto-guess the config.
135 echo -e "$(date_stringer):
136 There is no specific site configuration file in:
138 We will continue onward using the default and hope that this project follows
139 the standard pattern for cakephp projects." >> "$SSM_LOG_FILE"
140 # we'll pull in the default config file we set earlier; this will
141 # reinitialize some variables based on the app name.
143 # they gave us a valid config file. let's try using it.
144 export SITE_MANAGEMENT_CONFIG_FILE="$configfile"
147 # try to load the config.
148 source "$SITE_MANAGEMENT_CONFIG_FILE"
149 exit_on_error "loading site management configuration from: $SITE_MANAGEMENT_CONFIG_FILE"
154 # this function will seek out top-level directories in the target directory passed in.
155 # if there is only one directory, then it is returned (in the app_dirname variable).
156 # otherwise, the user is asked which directory to use.
157 # important: this sets a global variable app_dirname to the application's directory name.
158 function find_app_folder()
160 local appsdir="$1"; shift
162 # throw away any prior value so no confusion arises.
165 # count number of directories... if exactly one, then choose it.
166 numdirs=$(count_directories "$appsdir/")
168 if [ $numdirs -eq 0 ]; then
170 echo "There are no directories in the application directory:"
172 echo "Please create a directory for the site storage, based on the application"
173 echo "name that you want to work on. Or you can just pass the directory name"
174 echo "on the command line, e.g.:"
175 echo " $(basename $0) turtle"
178 elif [ $numdirs -eq 1 ]; then
179 # one directory in apps, so we'll pick that one.
180 app_dirname="$(basename $(find "$appsdir" -follow -mindepth 1 -maxdepth 1 -type d) )"
181 exit_on_error "Guessing application folder"
183 # there's more than one folder in apps...
185 # make sure we're allowed to auto-guess the folder name from our current dir.
186 if [ -z "$NO_AUTOMATIC_FOLDER_GUESS" ]; then
187 # if we can find the special checkout directory name above our current PWD, then that
188 # might tell us our project name.
189 if find_named_parent_dir "$CHECKOUT_DIR_NAME"; then
190 # we can grab a name above the checkout dir name location. let's try that.
191 app_dirname="$(basename "$(dirname $PARENT_DIR_FOUND)" )"
194 # flag maintenance, to avoid hosing other commands by leaving this set.
195 unset NO_AUTOMATIC_FOLDER_GUESS
197 # well, we couldn't guess a directory based on our current location,
198 # so ask the user to choose.
199 # Reference: https://askubuntu.com/questions/1705/how-can-i-create-a-select-menu-in-a-shell-script
201 PS3='Please pick a folder for site initialization: '
202 options=( $(find "$appsdir" -follow -mindepth 1 -maxdepth 1 -type d -exec basename {} ';') "Quit")
203 select app_dirname in "${options[@]}"; do
205 "Quit") echo ; echo "Quitting from the script."; return 1; ;;
206 *) echo ; echo "You picked folder '$app_dirname'" ; break; ;;
209 if [ -z "$app_dirname" ]; then
210 echo "The folder was not provided. This script needs a directory name"
211 echo "within which to initialize the site."
217 test_app_folder "$appsdir" "$app_dirname"
218 exit_on_error "Testing application folder: $app_dirname"
220 echo "Application folder is: $app_dirname"
224 # ensures that the app directory name is valid and then loads the config
225 # for the app (either via a specific file or using the defaults).
226 function test_app_folder()
228 local appsdir="$1"; shift
229 local dir="$1"; shift
231 local combo="$appsdir/$dir"
233 if [ ! -d "$combo" ]; then
234 echo "$(date_stringer): Creating app directory: $combo" >> "$SSM_LOG_FILE"
236 exit_on_error "Making application directory when not already present"
239 echo yo combo is $combo
241 if [ -d "$combo/$CHECKOUT_DIRNAME" ]; then
242 echo "Dropping expectation for intermediary checkout directory name."
243 unset CHECKOUT_DIRNAME
246 locate_config_file "$dir"
249 # eases some permissions to enable apache to write log files and do other shopkeeping.
250 function fix_site_perms()
252 local app_dir="$1"; shift
254 local site_dir="$app_dir/$CHECKOUT_DIR_NAME"
256 if [ -f "$site_dir/bin/cake" ]; then
257 sudo chmod -R a+rx "$site_dir/bin/cake"
258 exit_on_error "Enabling execute bit on cake binary"
261 if [ -d "$site_dir/logs" ]; then
262 sudo chmod -R g+w "$site_dir/logs"
263 exit_on_error "Enabling group write on site's Logs directory"
266 if [ -d "$site_dir/tmp" ]; then
267 sudo chmod -R g+w "$site_dir/tmp"
268 exit_on_error "Enabling group write on site's tmp directory"
272 # tosses out any cached object data that originated from the database.
273 function clear_orm_cache()
275 local site_dir="$1"; shift
277 if [ -f "$site_dir/bin/cake" ]; then
278 # flush any cached objects from db.
279 "$site_dir/bin/cake" orm_cache clear
280 exit_on_error "Clearing ORM cache"
284 # updates the revision control repository passed in. this expects that the
285 # repo will live in a folder called "checkout_dirname" under the app path,
286 # which is the standard for deployed site avenger sites. if that directory is
287 # missing, then we assume a checkout of the top-level repository instead.
288 # important: this also sets a global variable called site_store_path to the full
289 # path of the application.
290 function update_repo()
292 local full_app_dir="$1"; shift
293 local checkout_dirname="$1"; shift
294 local repo_root="$1"; shift
295 local repo_name="$1"; shift
297 echo "$(date_stringer): here are parms in update repo:" >> "$SSM_LOG_FILE"
298 echo "$(date_stringer): $(var full_app_dir checkout_dirname repo_root repo_name)" >> "$SSM_LOG_FILE"
300 # forget any prior value, since we are going to validate the path.
301 unset site_store_path
303 pushd "$full_app_dir" &>/dev/null
304 exit_on_error "Switching to our app dir '$full_app_dir'"
306 local complete_path="$full_app_dir"
307 if [ ! -z "$checkout_dirname" ]; then
308 # make the full path using the non-empty checkout dir name.
309 complete_path+="/$checkout_dirname"
312 # see if the checkout directory exits. the repo_found variable is set to
313 # non-empty if we find it and it's a valid git repo.
315 if [ -d "$full_app_dir" ]; then
316 # checkout directory exists, so let's check it.
317 pushd "$full_app_dir" &>/dev/null
318 exit_on_error "Switching to directory for check out: $full_app_dir"
320 # ask for repository name (without .git).
321 if git rev-parse --git-dir > /dev/null 2>&1; then
322 # this is a valid git repo.
326 # we don't consider the state of having the dir exist but the repo be wrong as good.
327 if [ -z "$repo_found" ]; then
328 echo "There is a problem; this folder is not a valid repository:"
329 echo " $full_app_dir"
330 echo "This script cannot continue unless the git repository is valid."
336 if [ ! -z "$repo_found" ]; then
337 # a repository was found, so update the version here and leave.
338 echo "Repository $repo_name exists. Updating it."
340 exit_on_error "Recursive checkout on: $complete_path"
342 # clone the repo since it wasn't found.
343 echo "Cloning repository $repo_name now."
344 git clone "$repo_root/$repo_name.git" $checkout_dirname
345 exit_on_error "Git clone of repository: $repo_name"
349 # construct the full path to where the app will actually live.
350 site_store_path="$complete_path"
355 # this function goes to the directory specified and makes it right with
356 # composer install. this is as opposed to composer update, which could
358 function composer_repuff()
360 local site_store_path="$1"; shift
362 pushd "$site_store_path" &>/dev/null
363 exit_on_error "Switching to our app dir '$site_store_path'"
365 echo "Updating site with composer..."
368 exit_on_error "Composer installation step on '$site_store_path'."
372 dir="$site_store_path/$CHECKOUT_DIR_NAME/vendor/siteavenger/avcore"
373 if [ -d "$dir" ]; then
374 echo "Running avcore database migrations..."
375 logfile="$TMP/problem-avcore_db_migration-$(date_stringer).log"
376 ./bin/cake migrations migrate -p Avcore &>"$logfile"
377 if [ $? -ne 0 ]; then
378 echo "** FAILED: Database migrations for avcore. Check log file in: $logfile"
379 # we keep going, because some sites aren't ready for this yet.
382 echo "Database for avcore migrated."
391 # this function creates the links needed to make the site function properly given our
392 # various dependencies and infrastructure.
393 function create_site_links()
395 local site_store_path="$1"; shift
396 local theme_name="$1"; shift
398 echo "Creating symbolic links for site assets..."
400 # jump into the site path so we can start making relative links.
401 pushd "$site_store_path" &>/dev/null
402 exit_on_error "Switching to our app dir '$site_store_path'"
404 pushd webroot &>/dev/null
406 # remove all symlinks that might plague us.
407 find . -maxdepth 1 -type l -exec rm -f {} ';'
408 exit_on_error "Cleaning out links in webroot"
410 # link in the avcore plugin.
411 make_safe_link "../vendor/siteavenger/avcore/webroot" avcore
413 # make the link for our theme as a lower-case version of the theme.
414 themelower=${theme_name,,}
415 make_safe_link "../plugins/$theme_name/webroot" "$themelower"
417 # link in any favicon files.
418 if [ -d "../plugins/$theme_name/favicon" ]; then
420 for fave in "../plugins/$theme_name/favicon"/*; do
421 make_safe_link "$fave" .
425 # get back out of webroot.
428 # hop up a level above where we had been.
431 # link 'public' to webroot.
432 if [ -L public ]; then
433 # public is a symlink.
435 exit_on_error "Removing public directory symlink"
436 elif [ -d public ]; then
437 # public is a folder with default files.
440 exit_on_error "Removing public directory and contents"
443 # create the main 'public' symlink
445 make_safe_link $CHECKOUT_DIR_NAME/webroot public
446 exit_on_error "Creating link to webroot called 'public'"
448 #hmmm: public/$themelower/im will be created automatically by system user with appropriate permissions
450 echo Created symbolic links.
456 # fetches composer to make sure it's up to date.
457 # (if powerup runs, composer install doesn't update git origin.)
458 function update_composer_repository()
460 local site_store_path="$1"; shift
462 pushd "$site_store_path" &>/dev/null
464 if git config remote.composer.url &>/dev/null; then
466 echo "Updated the composer repository."
468 echo "No composer repository was found for updating."
472 # fixes the ownership for a site avenger or php application.
473 # this almost certainly will require sudo capability, if there are any ownership problems
474 # that need to be resolved.
475 function fix_appdir_ownership()
477 local appsdir="$1"; shift
478 local dir="$1"; shift
480 local combo="$appsdir/$dir"
482 # go with the default user running the script.
484 if [ ! -z "$user_name" -a "$user_name" != "root" ]; then
485 echo "$(date_stringer): Chowning the app folder to be owned by: $user_name" >> "$SSM_LOG_FILE"
486 #hmmm: have to hope for now for standard group named after user
487 sudo chown -R "$user_name:$user_name" "$combo"
488 exit_on_error "Chowning $combo to be owned by $user_name"
490 echo "$(date_stringer): user name failed checks for chowning, was found as '$user_name'" >> "$SSM_LOG_FILE"
494 #probably not enough for path!
495 fix_site_perms "$combo"
498 # Jumps to an application directory given the app name. If no app name is
499 # given, it will show a menu to pick the app.
502 # check for parameters.
503 app_dirname="$1"; shift
505 check_apps_root "$app_dirname"
507 # find proper webroot where the site will be initialized.
508 if [ -z "$app_dirname" ]; then
509 # no dir was passed, so guess it.
510 export NO_AUTOMATIC_FOLDER_GUESS=true
511 find_app_folder "$BASE_APPLICATION_PATH"
513 test_app_folder "$BASE_APPLICATION_PATH" "$app_dirname"
515 if [ $? -ne 0 ]; then
516 if [ "$app_dirname" != "Quit" ]; then
517 echo "Could not locate the application directory: ${app_dirname}"
522 # where we expect to find our checkout folder underneath.
523 full_app_dir="$BASE_APPLICATION_PATH/$app_dirname"
525 pushd $full_app_dir/$CHECKOUT_DIR_NAME
526 #redundant if pushd pwd