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