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 an avenger5 directory above our current PWD, then that
188 # might tell us our name.
189 if find_named_parent_dir "avenger5"; then
190 # we can grab a name above the avenger5 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 locate_config_file "$dir"
242 # eases some permissions to enable apache to write log files and do other shopkeeping.
243 function fix_site_perms()
245 local app_dir="$1"; shift
247 local site_dir="$app_dir/$CHECKOUT_DIR_NAME"
249 if [ -f "$site_dir/bin/cake" ]; then
250 sudo chmod -R a+rx "$site_dir/bin/cake"
251 exit_on_error "Enabling execute bit on cake binary"
254 if [ -d "$site_dir/logs" ]; then
255 sudo chmod -R g+w "$site_dir/logs"
256 exit_on_error "Enabling group write on site's Logs directory"
259 if [ -d "$site_dir/tmp" ]; then
260 sudo chmod -R g+w "$site_dir/tmp"
261 exit_on_error "Enabling group write on site's tmp directory"
265 # tosses out any cached object data that originated from the database.
266 function clear_orm_cache()
268 local site_dir="$1"; shift
270 if [ -f "$site_dir/bin/cake" ]; then
271 # flush any cached objects from db.
272 "$site_dir/bin/cake" orm_cache clear
273 exit_on_error "Clearing ORM cache"
277 # updates the revision control repository passed in. this expects that the
278 # repo will live in a folder called "checkout_dirname" under the app path,
279 # which is the standard for our deployed sites.
280 # important: this also sets a global variable called site_store_path to the full
281 # path of the application.
282 function update_repo()
284 local full_app_dir="$1"; shift
285 local checkout_dirname="$1"; shift
286 local repo_root="$1"; shift
287 local repo_name="$1"; shift
289 echo "$(date_stringer): here are parms in update repo:" >> "$SSM_LOG_FILE"
290 echo "$(date_stringer): $(var full_app_dir checkout_dirname repo_root repo_name)" >> "$SSM_LOG_FILE"
292 # forget any prior value, since we are going to validate the path.
293 unset site_store_path
295 pushd "$full_app_dir" &>/dev/null
296 exit_on_error "Switching to our app dir '$full_app_dir'"
298 local complete_path="$full_app_dir/$checkout_dirname"
300 # see if the checkout directory exits. the repo_found variable is set to
301 # non-empty if we find it and it's a valid git repo.
303 if [ -d "$checkout_dirname" ]; then
304 # checkout directory exists, so let's check it.
305 pushd "$checkout_dirname" &>/dev/null
306 exit_on_error "Switching to our checkout directory: $checkout_dirname"
308 # ask for repository name (without .git).
309 if git rev-parse --git-dir > /dev/null 2>&1; then
310 # this is a valid git repo.
314 # we don't consider the state of having the dir exist but the repo be wrong as good.
315 if [ -z "$repo_found" ]; then
316 echo "There is a problem; this folder is not a valid repository:"
317 echo " $full_app_dir"
318 echo "This script cannot continue unless the git repository is valid."
324 if [ ! -z "$repo_found" ]; then
325 # a repository was found, so update the version here and leave.
326 echo "Repository $repo_name exists. Updating it."
328 exit_on_error "Recursive checkout on: $complete_path"
330 # clone the repo since it wasn't found.
331 echo "Cloning repository $repo_name now."
332 git clone "$repo_root/$repo_name.git" $checkout_dirname
333 exit_on_error "Git clone of repository: $repo_name"
336 #not doing this here since powerup uses this and has no sudo.
337 #fix_site_perms "$complete_path"
340 # construct the full path to where the app will actually live.
341 site_store_path="$complete_path"
346 # this function goes to the directory specified and makes it right with
347 # composer install. this is as opposed to composer update, which could
349 function composer_repuff()
351 local site_store_path="$1"; shift
353 pushd "$site_store_path" &>/dev/null
354 exit_on_error "Switching to our app dir '$site_store_path'"
356 echo "Updating site with composer..."
359 exit_on_error "Composer installation step on '$site_store_path'."
363 dir="$site_store_path/$CHECKOUT_DIR_NAME/vendor/siteavenger/avcore"
364 if [ -d "$dir" ]; then
365 echo "Running avcore database migrations..."
366 logfile="$TMP/problem-avcore_db_migration-$(date_stringer).log"
367 ./bin/cake migrations migrate -p Avcore &>"$logfile"
368 if [ $? -ne 0 ]; then
369 echo "** FAILED: Database migrations for avcore. Check log file in: $logfile"
370 # we keep going, because some sites aren't ready for this yet.
373 echo "Database for avcore migrated."
382 # this function creates the links needed to make the site function properly given our
383 # various dependencies and infrastructure.
384 function create_site_links()
386 local site_store_path="$1"; shift
387 local theme_name="$1"; shift
389 echo "Creating symbolic links for site assets..."
391 # jump into the site path so we can start making relative links.
392 pushd "$site_store_path" &>/dev/null
393 exit_on_error "Switching to our app dir '$site_store_path'"
395 pushd webroot &>/dev/null
397 # remove all symlinks that might plague us.
398 find . -maxdepth 1 -type l -exec rm -f {} ';'
399 exit_on_error "Cleaning out links in webroot"
401 # link in the avcore plugin.
402 make_safe_link "../vendor/siteavenger/avcore/webroot" avcore
404 # make the link for our theme as a lower-case version of the theme.
405 themelower=${theme_name,,}
406 make_safe_link "../plugins/$theme_name/webroot" "$themelower"
408 # link in any favicon files.
409 if [ -d "../plugins/$theme_name/favicon" ]; then
411 for fave in "../plugins/$theme_name/favicon"/*; do
412 make_safe_link "$fave" .
416 # get back out of webroot.
419 # hop up a level above where we had been.
422 # link 'public' to webroot.
423 if [ -L public ]; then
424 # public is a symlink.
426 exit_on_error "Removing public directory symlink"
427 elif [ -d public ]; then
428 # public is a folder with default files.
431 exit_on_error "Removing public directory and contents"
434 # create the main 'public' symlink
436 make_safe_link $CHECKOUT_DIR_NAME/webroot public
437 exit_on_error "Creating link to webroot called 'public'"
439 #hmmm: public/$themelower/im will be created automatically by system user with appropriate permissions
441 echo Created symbolic links.
447 # fetches composer to make sure it's up to date.
448 # (if powerup runs, composer install doesn't update git origin.)
449 function update_composer_repository()
451 local site_store_path="$1"; shift
453 pushd "$site_store_path" &>/dev/null
455 if git config remote.composer.url &>/dev/null; then
457 echo "Updated the composer repository."
459 echo "No composer repository was found for updating."
463 # fixes the ownership for a site avenger or php application.
464 # this almost certainly will require sudo capability, if there are any ownership problems
465 # that need to be resolved.
466 function fix_appdir_ownership()
468 local appsdir="$1"; shift
469 local dir="$1"; shift
471 local combo="$appsdir/$dir"
473 # go with the default user running the script.
475 if [ ! -z "$user_name" -a "$user_name" != "root" ]; then
476 echo "$(date_stringer): Chowning the app folder to be owned by: $user_name" >> "$SSM_LOG_FILE"
477 #hmmm: have to hope for now for standard group named after user
478 sudo chown -R "$user_name:$user_name" "$combo"
479 exit_on_error "Chowning $combo to be owned by $user_name"
481 echo "$(date_stringer): user name failed checks for chowning, was found as '$user_name'" >> "$SSM_LOG_FILE"
485 #probably not enough for path!
486 fix_site_perms "$combo"
489 # Jumps to an application directory given the app name. If no app name is
490 # given, it will show a menu to pick the app.
493 # check for parameters.
494 app_dirname="$1"; shift
496 check_apps_root "$app_dirname"
498 # find proper webroot where the site will be initialized.
499 if [ -z "$app_dirname" ]; then
500 # no dir was passed, so guess it.
501 export NO_AUTOMATIC_FOLDER_GUESS=true
502 find_app_folder "$BASE_APPLICATION_PATH"
504 test_app_folder "$BASE_APPLICATION_PATH" "$app_dirname"
506 if [ $? -ne 0 ]; then
507 if [ "$app_dirname" != "Quit" ]; then
508 echo "Could not locate the application directory: ${app_dirname}"
513 # where we expect to find our checkout folder underneath.
514 full_app_dir="$BASE_APPLICATION_PATH/$app_dirname"
516 pushd $full_app_dir/$CHECKOUT_DIR_NAME
517 #redundant if pushd pwd