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 #hmmm: below code problematic for when we want a new git clone to show up!
308 if [ ! -z "$checkout_dirname" -a -d "$full_app_dir/$checkout_dirname" ]; then
309 # make the full path using the non-empty checkout dir name.
310 complete_path+="/$checkout_dirname"
312 # using the additional path component failed, so we reset that to see if
313 # we can still proceed normally.
314 unset checkout_dirname
317 echo set complete_path: $complete_path
319 # see if the checkout directory exits. the repo_found variable is set to
320 # non-empty if we find it and it's a valid git repo.
322 if [ -d "$complete_path" ]; then
323 # checkout directory exists, so let's check it.
324 pushd "$complete_path" &>/dev/null
325 exit_on_error "Switching to directory for check out: $complete_path"
327 # ask for repository name (without .git).
328 if git rev-parse --git-dir > /dev/null 2>&1; then
329 # this is a valid git repo.
333 # we don't consider the state of having the dir exist but the repo be wrong as good.
334 if [ -z "$repo_found" ]; then
335 echo "There is a problem; this folder is not a valid repository:"
336 echo " $complete_path"
337 echo "This script cannot continue unless the git repository is valid."
343 if [ ! -z "$repo_found" ]; then
344 # a repository was found, so update the version here and leave.
345 pushd "$complete_path" &>/dev/null
346 exit_on_error "Switching to directory for repo update: $complete_path"
347 echo "Repository $repo_name exists. Updating it."
348 git pull --tags --all
349 exit_on_error "Recursive checkout on: $complete_path"
352 # clone the repo since it wasn't found.
353 pushd "$complete_path/.." &>/dev/null
354 exit_on_error "Switching to parent directory prior to new clone: $complete_path/.."
355 echo "Cloning repository $repo_name now."
356 git clone "$repo_root/$repo_name.git" $checkout_dirname
357 exit_on_error "Git clone of repository: $repo_name"
362 # construct the full path to where the app will actually live.
363 site_store_path="$complete_path"
368 # this function goes to the directory specified and makes it right with
369 # composer install. this is as opposed to composer update, which could
371 function composer_repuff()
373 local site_store_path="$1"; shift
375 pushd "$site_store_path" &>/dev/null
376 exit_on_error "Switching to our app dir '$site_store_path'"
378 echo "Updating site with composer..."
381 exit_on_error "Composer installation step on '$site_store_path'."
385 dir="$site_store_path/$CHECKOUT_DIR_NAME/vendor/siteavenger/avcore"
386 if [ -d "$dir" ]; then
387 echo "Running avcore database migrations..."
388 logfile="$TMP/problem-avcore_db_migration-$(date_stringer).log"
389 ./bin/cake migrations migrate -p Avcore &>"$logfile"
390 if [ $? -ne 0 ]; then
391 echo "** FAILED: Database migrations for avcore. Check log file in: $logfile"
392 # we keep going, because some sites aren't ready for this yet.
395 echo "Database for avcore migrated."
404 # this function creates the links needed to make the site function properly given our
405 # various dependencies and infrastructure.
406 function create_site_links()
408 local site_store_path="$1"; shift
409 local theme_name="$1"; shift
411 echo "Creating symbolic links for site assets..."
413 # jump into the site path so we can start making relative links.
414 pushd "$site_store_path" &>/dev/null
415 exit_on_error "Switching to our app dir '$site_store_path'"
417 pushd webroot &>/dev/null
419 # remove all symlinks that might plague us.
420 find . -maxdepth 1 -type l -exec rm -f {} ';'
421 exit_on_error "Cleaning out links in webroot"
423 # link in the avcore plugin.
424 make_safe_link "../vendor/siteavenger/avcore/webroot" avcore
426 # make the link for our theme as a lower-case version of the theme.
427 themelower=${theme_name,,}
428 make_safe_link "../plugins/$theme_name/webroot" "$themelower"
430 # link in any favicon files.
431 if [ -d "../plugins/$theme_name/favicon" ]; then
433 for fave in "../plugins/$theme_name/favicon"/*; do
434 make_safe_link "$fave" .
438 # get back out of webroot.
441 # hop up a level above where we had been.
444 # link 'public' to webroot.
445 if [ -L public ]; then
446 # public is a symlink.
448 exit_on_error "Removing public directory symlink"
449 elif [ -d public ]; then
450 # public is a folder with default files.
453 exit_on_error "Removing public directory and contents"
456 # create the main 'public' symlink
458 make_safe_link $CHECKOUT_DIR_NAME/webroot public
459 exit_on_error "Creating link to webroot called 'public'"
461 #hmmm: public/$themelower/im will be created automatically by system user with appropriate permissions
463 echo Created symbolic links.
469 # fetches composer to make sure it's up to date.
470 # (if powerup runs, composer install doesn't update git origin.)
471 function update_composer_repository()
473 local site_store_path="$1"; shift
475 pushd "$site_store_path" &>/dev/null
477 if git config remote.composer.url &>/dev/null; then
479 echo "Updated the composer repository."
481 echo "No composer repository was found for updating."
485 # fixes the ownership for a site avenger or php application.
486 # this almost certainly will require sudo capability, if there are any ownership problems
487 # that need to be resolved.
488 function fix_appdir_ownership()
490 local appsdir="$1"; shift
491 local dir="$1"; shift
493 local combo="$appsdir/$dir"
495 # go with the default user running the script.
497 if [ ! -z "$user_name" -a "$user_name" != "root" ]; then
498 echo "$(date_stringer): Chowning the app folder to be owned by: $user_name" >> "$SSM_LOG_FILE"
499 #hmmm: have to hope for now for standard group named after user
500 sudo chown -R "$user_name:$user_name" "$combo"
501 exit_on_error "Chowning $combo to be owned by $user_name"
503 echo "$(date_stringer): user name failed checks for chowning, was found as '$user_name'" >> "$SSM_LOG_FILE"
507 #probably not enough for path!
508 fix_site_perms "$combo"
511 # Jumps to an application directory given the app name. If no app name is
512 # given, it will show a menu to pick the app.
515 # check for parameters.
516 app_dirname="$1"; shift
518 check_apps_root "$app_dirname"
520 # find proper webroot where the site will be initialized.
521 if [ -z "$app_dirname" ]; then
522 # no dir was passed, so guess it.
523 export NO_AUTOMATIC_FOLDER_GUESS=true
524 find_app_folder "$BASE_APPLICATION_PATH"
526 test_app_folder "$BASE_APPLICATION_PATH" "$app_dirname"
528 if [ $? -ne 0 ]; then
529 if [ "$app_dirname" != "Quit" ]; then
530 echo "Could not locate the application directory: ${app_dirname}"
535 # where we expect to find our checkout folder underneath.
536 full_app_dir="$BASE_APPLICATION_PATH/$app_dirname"
538 pushd $full_app_dir/$CHECKOUT_DIR_NAME
539 #redundant if pushd pwd