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