source: tags/confman-1.5/confmanlib.sh @ 141

Revision 141, 14.6 KB checked in by ccowart, 5 years ago (diff)

Making some minor errors vanish.

  • Property rc:mode set to 0444
  • Property svn:keywords set to Id
Line 
1#! /bin/bash
2#
3# This file provides shell libraries to our configuration management system.
4# It will be sourced by the relevant Rescomp scripts.
5#
6# Author: Chris Cowart <ccowart@rescomp.berkeley.edu>
7# Date: 30 March 2006
8#
9# $Id$
10
11REPO_URI="${REPO_PROTOCOL}${REPO_HOSTNAME}${REPO_PATH}"
12REPO_ACTION="${REPO_DB}/last_action"
13REPO_SYNC_STATE="${REPO_DB}/state"
14
15# Checks out the conf tree if we don't already have it. Updates it if we do.
16function conf_checkout_tree {
17        if [ ! -d ${WORK_PATH} ] ; then
18                        local path=`echo ${WORK_PATH} | sed -E 's:/[^/]+$::'`
19                        mkdir -p ${WORK_PATH}
20
21                        # This makes sure nobody can enter your working copy. We relax the
22                        # permissions during the rollout, and restrict them again at
23                        # the end.
24                        chmod 700 ${WORK_PATH}
25
26                        svn checkout ${REPO_URI} ${WORK_PATH}
27        else
28                        svn update ${WORK_PATH}
29        fi
30}
31
32# I update the working copy of a given module to the repository's copy.
33function conf_update_module {
34        local module="$1"
35        svn update ${WORK_PATH}/${module}
36}
37
38# Updates the whole source tree
39function conf_update_tree {
40        svn update ${WORK_PATH}
41}
42
43# Revert a working file
44function conf_revert {
45        svn revert $*
46}
47
48# Assumes that we already have core setup in our work path.
49function conf_create_module {
50        local module=$1
51        svn mkdir ${WORK_PATH}/$module
52        svn mkdir ${WORK_PATH}/${REPO_CHECKPTS}/$module
53        svn commit ${WORK_PATH}/${module} ${WORK_PATH}/${REPO_CHECKPTS}/$module -m \
54                        "Created directory structure for ${module} --`whoami`"
55}
56
57# Commits module $1 with message $2
58function conf_commit {
59        local modules=$(echo $1 | tr ' ' ',')
60        local msg="$2"
61
62    # $modules is in the form foo,bar,baz. This eval trick forces
63    # curly brace expansion.
64    if echo "$modules" | grep ',' > /dev/null ; then
65            svn commit -F "$msg" $(eval echo ${WORK_PATH}/{$modules})
66    else
67        svn commit -F "$msg" ${WORK_PATH}/$modules
68    fi
69}
70
71function conf_fetch {
72    local tmpfile=`mktemp -t confman`
73    local proto="${CONF_EXPORT_URI%:/*}"
74    local remote
75
76    case $proto in
77        sftp|scp)   
78            remote="${CONF_EXPORT_URI#*://}"
79            remote="${remote/\//:/}"
80            scp -p $remote $tmpfile 
81            ;;
82        http|https|ftp)
83            fetch -o $tmpfile $remote
84            ;;
85        file)
86            remote="${CONF_EXPORT_URI#*://}"
87            cp -p $remote $tmpfile
88            ;;
89        *)
90            echo "Unsupported Protocol in conf_fetch" >&2
91            return 1
92            ;;
93    esac
94    echo $tmpfile
95    return 0
96}
97
98# A way to utilize the svn status feature.
99function conf_status {
100        svn status $*
101}
102
103# This exports a working copy of the repository to a tarball
104function conf_export {
105    local tarball="$1"
106    conf_checkout_tree
107    tar -czf "$tarball" -C "${WORK_PATH}" .
108}
109
110# Roll out the specified module, optionally at the specified checkpoint
111# eg:   conf_rollout MODULE [checkpoint]
112function conf_rollout {
113        local module="$1"
114        if [ -z $2 ] ; then
115                local moduledir="${WORK_PATH}/$module"
116        else
117                local moduledir="${WORK_PATH}/checkpoints/${module}/${2}"
118        fi
119        # This is a hack to work around NFS home dirs, for now:
120        chmod o+rx ${WORK_PATH}
121
122        for directory in `find $moduledir -type d -mindepth 1| grep -v "\.svn"`; do
123                local livedir=`echo $directory | sed "s:$moduledir::"`
124                livedir="${LIVE_ROOT}${livedir}"
125                local owner=`conf_get_prop ${directory} owner`
126                local group=`conf_get_prop ${directory} group`
127                local mode=`conf_get_prop ${directory} mode`
128                local opts="-d -o $owner -g $group -m $mode"
129                local cmd="sudo install $opts $livedir"
130                echo $cmd
131                $cmd
132        done
133        for file in `find $moduledir -type f | grep -v "\.svn"` ; do
134                local livefile=`echo "$file" | sed "s:$moduledir::"`
135                local owner=`conf_get_prop ${file} owner`
136                local group=`conf_get_prop ${file} group`
137                local mode=`conf_get_prop ${file} mode`
138                local opts="-Sp -o $owner -g $group -m $mode"
139                local cmd="sudo install $opts $file ${LIVE_ROOT}$livefile"
140                echo $cmd
141                $cmd
142        done
143        # This is a hack to work around NFS home dirs, for now:
144        chmod o-rx ${WORK_PATH}
145}
146
147function conf_install {
148        local module="$1"
149        shift
150        local file=`abspath $1`
151        shift
152        local moduledir="${WORK_PATH}/$module"
153        local livefile=`echo "$file" | sed -E "s:${WORK_PATH}/[^/]+::"`
154        local pathmodule=`echo "$file" | sed -E "s:${WORK_PATH}/([^/]+).*:\1:"`
155        local suffix
156        livefile=`echo "$livefile" | sed -E "s:-${pathmodule}$::"`
157        if [[ $SINGULARITIES =~ $livefile ]] && [ ! -d "$file" ] ; then
158                suffix="-${module}"
159        fi
160        livefile="${livefile}${suffix}"
161
162
163        # See if it even exists
164        file="${moduledir}${livefile}"
165        if [ ! -e "$file" ] && [ -z "$1" ] ; then
166                return 0
167        elif [ ! -f "$file" ] && [ ! -d "$file" ] ; then
168                conf_install $module "$@"
169                return
170        fi
171
172        # If we got here, figure it out
173        local owner=`conf_get_prop ${file} owner`
174        local group=`conf_get_prop ${file} group`
175        local mode=`conf_get_prop ${file} mode`
176
177        if [ -f "$file" ] ; then
178                local opts="-Sp -o $owner -g $group -m $mode"
179            local cmd="sudo install $opts $file ${LIVE_ROOT}$livefile"
180        else
181                local opts="-d -o $owner -g $group -m $mode"
182            local cmd="sudo install $opts ${LIVE_ROOT}$livefile"
183        fi
184
185        local cmd="sudo install $opts $file ${LIVE_ROOT}$livefile"
186
187        chmod o+rx ${WORK_PATH}
188        echo $cmd
189        $cmd
190        chmod o-rx ${WORK_PATH}
191
192    if [ -d "$file" ] ; then
193        conf_install $module "$file"/*
194    fi
195        if [ ! -z $1 ] ; then
196                conf_install $module "$@"
197        fi
198}
199
200
201function conf_list {
202        local file=$1
203        local module=`echo ${file#$WORK_PATH} | sed -E 's:/([^/]+)/.*:\1:'`
204        local livefile=`echo ${file#$WORK_PATH} | sed -E 's:/([^/]+)/:/:'`
205        local owner=`conf_get_prop ${file} owner`
206        local group=`conf_get_prop ${file} group`
207        local mode=`conf_get_prop ${file} mode`
208        local comment=`conf_get_prop ${file} comment`
209        echo -e "$mode\t$owner\t$group\t$comment\t\t$livefile"
210}
211       
212
213
214# This function assembles the singularities:
215function conf_assemble_sing {
216        local file=$1
217        local livefile="${LIVE_ROOT}${file}"
218        local tmpfile=`mktemp -t confman` || exit 1
219        local owner group mode flag livepart msg
220        for layer in $LAYERS ; do
221                livepart="${LIVE_ROOT}${file}-${layer}"
222                myfile="${WORK_PATH}/${layer}/${file}-${layer}"
223                if [ -f $myfile -a -f $livepart ] ; then
224                                owner=`conf_get_prop ${myfile} owner`
225                                group=`conf_get_prop ${myfile} group`
226                                mode=`conf_get_prop     ${myfile} mode`
227                                comment=`conf_get_prop  ${myfile} comment`
228                        cat $livepart >> $tmpfile
229                        sudo rm $livepart
230                        flag=1
231                fi
232        done
233        if [ ! -z $flag ] ; then
234                local opts="-Sp -o $owner -g $group -m $mode"
235                local cmd="sudo install $opts $tmpfile $livefile"
236                echo $cmd
237                $cmd
238        fi
239        rm -f $tmpfile
240}
241
242# This function generates a checkpoint called NAME for the given MODULE.
243# eg: conf_new_checkpoint MODULE NAME
244function conf_new_checkpoint {
245        local module=$1
246        local checkpoint=$2
247        local chkpath="${WORK_PATH}/${REPO_CHECKPTS}/${module}/${checkpoint}"
248        local revision=`conf_revision`
249        echo $revision > $chkpath
250        svn add $chkpath
251        local msg="Created a checkpoint, ${checkpoint} for ${module} --`whoami`"
252        svn commit ${WORK_PATH}/${REPO_CHECKPTS} -m "$msg"
253}
254
255# This function will remove the checkpoint NAME from MODULE.
256# eg: conf_rm_checkpoint MODULE NAME
257function conf_rm_checkpoint {
258        local module=$1
259        local checkpoint=$2
260        local chkpath="${WORK_PATH}/${REPO_CHECKPTS}/${module}/${checkpoint}"
261        svn rm ${chkpath}
262        local msg="Removed the checkpoint ${checkpoint} from ${module} --`whoami`"
263        svn commit ${WORK_PATH}/${REPO_CHECKPTS} -m "$msg"
264}
265
266# This function will restore the state of your module's working copy to the
267# named checkpoint. eg: conf_rollback MODULE NAME
268function conf_rollback {
269        local module=$1
270        local checkpoint=$2
271        local clock=$3
272        local modpath="${WORK_PATH}/${module}"
273        local chkpath="${WORK_PATH}/${REPO_CHECKPTS}/${module}/${checkpoint}"
274        local revision
275        local date=`echo $checkpoint | sed -E 's:(....)(..)(..):\1-\2-\3:'`
276
277        # Named checkpoint
278        if [ -f "${chkpath}" ] ; then
279        revision=`cat $chkpath`
280        elif [ -z $clock ] ; then               # Time checkpoint
281        revision="{${date}}"
282        else
283        clock=`echo $clock | sed -E 's#(..)(..)#\1:\2#'`
284        revision="{${date}T${clock}}"
285        fi
286
287        svn update --revision $revision $modpath
288}
289
290# This function will print the value of the specified property to STDOUT
291function conf_get_prop {
292        local file=$1
293        local prop=$2
294        svn propget "confman:${prop}" ${file}
295}
296
297# This function will set the value of the specified property.
298function conf_set_prop {
299        local file=$1
300        local prop=$2
301        local value=$3
302        svn propset "confman:${prop}" "${value}" ${file}
303}
304
305function conf_gen_file {
306        local module=$1
307        local file=$2
308        local owner=$3
309        local group=$4
310        local mode=$5
311        local comment="$6"
312        local usefile=$7
313        local myfile="${WORK_PATH}/${module}${file}"
314        local warning="${comment} ${CONF_WARNING}"
315        local morewarn="${comment} Managed under ${module} module."
316        local revision="${comment} \$Id\$"
317        echo $file
318
319        if [ -z $usefile ] ; then
320                                        echo -e "${warning}\n${morewarn}\n${revision}\n" > $myfile
321        elif head -n 1 ${usefile} | grep '^#!' >/dev/null ; then
322                                        awk "{if (NR==2)
323                                                        print \"\\n${warning}\\n${morewarn}\\n${revision}\\n\"\$0;
324                                                                else print \$0 }" ${usefile} > $myfile
325        else
326                                        echo -e "${warning}\n${morewarn}\n${revision}\n" > $myfile
327                                        cat ${usefile} >> $myfile
328        fi
329
330        svn add $myfile
331        svn ps svn:keywords "Id" $myfile
332        conf_set_prop $myfile owner $owner
333        conf_set_prop $myfile group $group
334        conf_set_prop $myfile mode      $mode
335        conf_set_prop $myfile comment "$comment"
336}
337
338function conf_rm_file {
339        svn rm $*
340}
341
342function conf_mkdir {
343        local directory=$1
344        local owner=$2
345        local group=$3
346        local mode=$4
347        local workdir="/"
348        local directories=`echo "$directory" | sed 's:/: :g'`
349        local dir
350
351        for dir in $directories ; do
352                workdir="${workdir}/${dir}"
353                if [ ! -d ${workdir} ] ; then
354                        echo svn mkdir ${workdir}
355                        svn mkdir ${workdir}
356                        conf_set_prop $workdir owner $owner
357                        conf_set_prop $workdir group $group
358                        conf_set_prop $workdir mode $mode
359                        conf_set_prop $workdir comment "dir"
360                fi
361        done
362}
363
364function conf_rmmod {
365        local module=$1
366        svn rm ${WORK_PATH}/${module}
367        svn rm ${WORK_PATH}/${REPO_CHECKPTS}/${module}
368}
369
370function conf_rename {
371        local oldmod=$1
372        local newmod=$2
373        local file
374
375        # First, we perform the easy operations
376        svn mv ${WORK_PATH}/${oldmod} ${WORK_PATH}/${newmod} || \
377                {       echo "There was a problem renaming the modules." >&4 ; \
378                        conf_clean_exit 1
379                }
380        svn mv ${WORK_PATH}/${REPO_CHECKPTS}/${oldmod} \
381                        ${WORK_PATH}/${REPO_CHECKPTS}/${newmod} || \
382                {       echo "There was a problem renaming the checkpts." >&4 ; \
383                        conf_clean_exit 1
384                }
385
386        svn update ${WORK_PATH} || \
387                {       echo "Your working copy didn't update correctly." >&4 ; \
388                        conf_clean_exit 1
389                }
390        svn commit -m "Renaming ${oldmod} to ${newmod}, phase 1." \
391                ${WORK_PATH}/{,${REPO_CHECKPTS}}/{${oldmod},${newmod}} || \
392                {       echo "Committing the changes failed." >&4 ; conf_clean_exit 1
393                }
394
395        # Next, we have to rename any singularities
396        for file in ${SINGULARITIES} ; do
397                if [ -f "${WORK_PATH}/${newmod}${file}-${oldmod}" ] ; then
398                        svn mv ${WORK_PATH}/${newmod}${file}-${oldmod} \
399                                        ${WORK_PATH}/${newmod}${file}-${newmod}
400                fi
401        done
402
403        svn update ${WORK_PATH} || \
404                {       echo "Your working copy didn't update correctly." >&4 ; \
405                        conf_clean_exit 1
406                }
407        svn commit -m "Renaming ${oldmod} to ${newmod}, phase 2." \
408                ${WORK_PATH}/${newmod} || \
409                {       echo "Committing the changes failed." >&4 ; conf_clean_exit 1
410                }
411
412        # Now, we have to go fix all the confman headers in all the files...
413        find ${WORK_PATH}/${newmod} -type f -not -path '*/.svn/*' -exec \
414                gsed -i -r "s/^(# Managed under )${oldmod}( module)/\1${newmod}\2/" \
415                {} \;
416       
417        svn update ${WORK_PATH} || \
418                {       echo "Your working copy didn't update correctly." >&4 ; \
419                        conf_clean_exit 1
420                }
421        svn commit -m "Renaming ${oldmod} to ${newmod}, complete." \
422                ${WORK_PATH}/${newmod} || \
423                {       echo "Committing the changes failed." >&4 ; conf_clean_exit 1
424                }
425}
426
427function conf_mv {
428        local oldname=$1
429        local newname=$2
430        svn mv $oldname $newname
431}
432
433function conf_cp {
434        local oldname=$1
435        local newname=$2
436        svn cp $oldname $newname
437}
438
439function conf_diff {
440        svn diff $*
441}
442
443function conf_log {
444        svn log $*
445}
446
447# Accepts log messages on stdin until EOF
448function conf_logger {
449   logger -t "$MYNAME[$$]: $USER" -s 2>&4
450}
451
452function conf_chattr {
453    local attr="confman:$1"
454    shift
455    local value="$1"
456    shift
457    svn propset "$attr" "$value" "$@"
458}
459
460function conf_lsattr {
461    local file="$1"
462    shift
463    echo "$file"
464    for prop in $(svn proplist $file | grep 'confman:' | sort) ; do
465        echo -e "\t${prop#confman:}\t" $(svn propget $prop $file)
466    done
467    if [ -n "$1" ] ; then
468        conf_lsattr "$@"
469    fi
470}
471
472function conf_rmattr {
473    local attr="confman:$1"
474    shift
475    svn propdel "$attr" "$@"
476}
477
478function conf_syncheck {
479    local cmd
480    local toReturn=true
481    for file in "$@" ; do
482        cmd=$(svn propget "confman:syncheck" "$file")
483        if [ -z "$cmd" ] ; then
484            continue
485        fi
486        if ! $cmd "$file" ; then
487            echo "Syntax verification failed for $file" >&2
488            toReturn=false
489        fi
490    done
491    $toReturn
492}
493
494function conf_markclean {
495    echo clean > $REPO_SYNC_STATE
496}
497
498function conf_markdirty {
499    echo dirty > $REPO_SYNC_STATE
500}
501
502function conf_isclean {
503    local state=`cat $REPO_SYNC_STATE`
504    case $state in
505        clean)  return 0 ;;
506        dirty)  return 1 ;;
507        *)      echo "Invalid state. Reporting dirty." >&2 ; return 1 ;;
508    esac
509}
510
511# Returns the current revision number of the repository on stdout
512function conf_revision {
513    svn info ${WORK_PATH} | awk '/Last Changed Rev:/ {print $4}'
514}
515
516# Returns the revision of the last commit or install operation on stdout
517function conf_sysrev {
518    cut -d ':' -f 2 $REPO_ACTION
519}
520
521# Returns the last action of the repository on stdout
522function conf_lastact {
523    cut -d ':' -f 1 $REPO_ACTION
524}
525
526# Records the specified action
527function conf_recordAction {
528    local action="$1"
529    local revision=`conf_revision`
530    echo "${action}:${revision}" > $REPO_ACTION
531}
532
533# WARNING: If you refer to fd 2 in this code, this function will silently
534# fail when called by trap. DO NOT ATTEMPT TO LOG TO fd 2 IN THIS FUNCTION!
535# The SIGNAL seems to kill the logger process spawned by the parent
536# process, which is receiving its input from our fd 2.
537function conf_cleanexit {
538    echo "Received a signal. Exiting cleanly." | conf_logger
539        echo "Abort, Abort! Patience is a virtue." >&4
540        echo "Please wait until I finish cleaning up after you." >&4
541
542        # And in case we got an interrupt during a rollout, we still want the
543        # permissions here to be in a consistent state.
544        chmod 700 ${WORK_PATH}
545
546        echo "Removing leftover temp files..." >&4
547        find /tmp/confman* -maxdepth 0 -user `whoami` -exec rm -rf {} \;
548
549        # And this clears any locks we may have created on our working copy:
550        echo "Undoing damage to your working copy..." >&4
551        [ -d "${WORK_PATH}" ] && svn cleanup ${WORK_PATH}
552        echo "All clean. Terminating." >&4
553
554        exit ${1:-1}
555}       
556
557# vim:ts=4
558
Note: See TracBrowser for help on using the repository browser.