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