/var/lib/sorcery/modules/libsorcery
1 #!/bin/bash
2 #---------------------------------------------------------------------
3 ##
4 ## @Synopsis Set of functions used by the internal sorcery scripts
5 ##
6 ## This should really be home to things related to the sorcery script
7 ## itself, not a repository for other functions. (Andrew 5/29/04)
8 ##
9 ## @Copyright Original version Copyright 2001 by Kyle Sallee
10 ## @Copyright Additions/Corrections Copyright 2002 by the Source Mage Team
11 ##
12 #---------------------------------------------------------------------
13
14 #---------------------------------------------------------------------
15 ## @param branch
16 ##
17 ## Updates the sorcery scripts to their latest version for specified
18 ## branch.
19 ##
20 #---------------------------------------------------------------------
21 function update_sorcery_scripts() {
22
23 local BRANCH=$1
24
25 debug "libsorcery" "update_sorcery_scripts() (sorcery-$BRANCH)"
26
27 {
28 #This section is to make sure that all sorcery dependencies are cast
29 #Keep this outer if until basesystem is in the grimoires properly.
30 #(2002/10/13)
31 if [[ `codex_find_spell_by_name basesystem` ]] ; then
32 if ! spell_ok basesystem ; then
33 cast basesystem
34 fi &&
35 if [[ "$UPDATEFIX" == on ]] ; then
36 cleanse --fix basesystem
37 fi
38 if [[ $? != 0 ]] ; then
39 query "Would you like to continue anyway?" y || return 1
40 fi
41 fi
42 }
43
44 pushd $TMP_DIR &>/dev/null
45 # sorcery is not a spell
46 # there is no spoon
47 SOURCE=sorcery-$BRANCH.tar.bz2
48 SOURCE_DIRECTORY=$BUILD_DIRECTORY/sorcery
49 SOURCE_URL=$SORCERY_URL/$SOURCE
50
51 message "${MESSAGE_COLOR}Downloading source file" \
52 "${FILE_COLOR}${SOURCE}${DEFAULT_COLOR}" \
53 "for sorcery update."
54 url_download "$SOURCE" "$SOURCE_URL" "" "sr_target" "sr_type" || {
55 message "${PROBLEM_COLOR}Failed to download sorcery${DEFAULT_COLOR}"
56 return 1
57 }
58 if [[ $sr_type != file ]] ; then
59 message "Downloaded type is not a file, file a bug if you see this"
60 return 1
61 fi
62 [[ $sr_target != $SOURCE ]] && mv $sr_target $SOURCE
63
64 gpg_verify_sorcery $SOURCE $SORCERY_URL
65 rc=$?
66
67 gpg_user_query $rc $SORCERY_BRANCH sorcery || return 1
68 popd &>/dev/null
69
70 local FILENAME=$TMP_DIR/$SOURCE
71 # copy the tarball to /var/spool/sorcery after we've downloaded and
72 # verified it.
73 ensure_dir "$SOURCE_CACHE"
74 cp $FILENAME $SOURCE_CACHE
75
76 mk_source_dir $SOURCE_DIRECTORY &&
77 cd $BUILD_DIRECTORY
78 bzip2 -cdf $FILENAME |
79 tar --owner=root --group=root -xf /dev/stdin &&
80 cd $SOURCE_DIRECTORY &&
81
82 echo `pwd` || return 1
83
84 # last chance to lock
85 message -n "${MESSAGE_COLOR}Waiting for${DEFAULT_COLOR} ${SPELL_COLOR}all${DEFAULT_COLOR}" \
86 "${MESSAGE_COLOR}spells to complete...${DEFAULT_COLOR}"
87 lock_resources "solo" "cast" # prevent other casts
88 excllock_resources "cast" "sorcery" # wait for other casts
89 message "done."
90 lock_resources "libgrimoire" "install" &&
91
92 if test -x ./uninstall && test -f /etc/sorcery/install.log ; then
93 message uninstalling...
94 ./uninstall
95 else
96 # rough equivalent to prepare_install...
97 rm /etc/sorcery/* 2>/dev/null
98 rm /etc/sorcery/licenses/* 2>/dev/null
99 rm /etc/sorcery/mirrors/* 2>/dev/null
100 rm /var/lib/sorcery/* 2>/dev/null
101 rm -r /var/lib/sorcery/modules/* 2>/dev/null
102 rm -r /var/lib/sorcery/archspecs/* 2>/dev/null
103 rm -r /var/lib/sorcery/build/* 2>/dev/null
104 fi
105 ./install &&
106
107 cd / &&
108 unlock_resources "libgrimoire" "install" &&
109
110 SORCERY_VERSION=`cat /etc/sorcery/version`
111
112 unlock_resources "solo" "cast"
113 unlock_resources "cast" "sorcery"
114
115 if [ $? -eq 0 ] ; then
116 activity_log "update" "sorcery-$BRANCH" "$SORCERY_VERSION" "success"
117 rm_source_dir
118 else
119 activity_log "update" "sorcery-$BRANCH" "$SORCERY_VERSION" "failure"
120 if [[ $CLEAN_SOURCE == on ]]; then
121 rm_source_dir
122 fi
123 fi
124 message "${MESSAGE_COLOR}Current" \
125 "${SPELL_COLOR}sorcery-$BRANCH${DEFAULT_COLOR} ${MESSAGE_COLOR}version" \
126 "${VERSION_COLOR}$SORCERY_VERSION${DEFAULT_COLOR}"
127 echo
128 sorcery_history
129 rm $FILENAME
130 }
131
132 #---------------------------------------------------------------------
133 ##
134 ## Menu query to user asking to set the nice value which sorcery should
135 ## use to run proccesses at.
136 ##
137 #---------------------------------------------------------------------
138 function set_nice() {
139
140 PROMPT="Please enter the process priority sorcery should run at."
141
142 if NICE=`eval $DIALOG ' --ok-label "Commit" \
143 --inputbox \
144 "$PROMPT" \
145 0 0 "$NICE"'`
146 then
147 modify_local_config "NICE" "$NICE"
148 fi
149
150 }
151
152 #---------------------------------------------------------------------
153 ##
154 ## Menu query to user asking to set the umask value which sorcery should
155 ## use to run proccesses with.
156 ##
157 #---------------------------------------------------------------------
158 function set_umask() {
159
160 PROMPT="Please enter the permissions mask sorcery should run with."
161
162 if UMASK=`eval $DIALOG ' --ok-label "Commit" \
163 --inputbox \
164 "$PROMPT" \
165 0 0 "$UMASK"'`
166 then
167 modify_local_config "UMASK" "$UMASK"
168 fi
169
170 }
171
172
173 #---------------------------------------------------------------------
174 ## @param filename
175 ##
176 ## Displays and/or mails the contents of the file given as the first
177 ## argument.
178 ##
179 #---------------------------------------------------------------------
180 function report() {
181
182 if ! [ -f $1 ]; then return; fi
183
184 if [ "$VIEW_REPORTS" == "on" ]; then
185
186 debug "libsorcery" "Prompting to view $2 for $SPELL"
187
188 VIEW_PROMPT="View $2 for ${SPELL_COLOR}${SPELL}-${VERSION_COLOR}${VERSION}${DEFAULT_COLOR}?"
189 sound REPORT
190 if query "$VIEW_PROMPT" n; then $PAGER $1; fi
191 fi
192
193 if [ "$MAIL_REPORTS" == "on" ]; then
194 debug "libsorcery" "Mailing report ($2) for $SPELL to $SORCERER"
195 date -u |
196 mail -s "Sorcery Report : $HOSTNAME : $2 for $SPELL-$VERSION" \
197 -a $1 $SORCERER 2>/dev/null
198 fi
199
200 true
201
202 }
203
204
205 #---------------------------------------------------------------------
206 ## @param filename
207 ##
208 ## Given a filename, will return the actual filename if a similar
209 ## filename with a different extension exists.
210 ##
211 #---------------------------------------------------------------------
212 function guess_filename() {
213
214 local filename=$1
215
216 debug "libsorcery" "Running guess_filename() on $filename"
217
218 if [[ -f $filename ]]; then
219 echo $filename
220 else
221 # currently only used from gaze
222 if [[ $FUZZ != on ]]; then
223 return 1
224 else
225 local basename=$(sed -r "s/\.(tar\.(gz|bz2)|tgz|gz|bz2)$//" <<< "$filename")
226 local extension
227 for extension in tar.gz tar.bz2 tgz gz bz2; do
228 if [[ -f $basename.$extension ]]; then
229 echo $basename.$extension
230 return 0
231 fi
232 done
233 return 1
234 fi
235 fi
236
237 }
238
239 #-------------------------------------------------------------------------
240 ## check if the file exists, or one with a similar compression exists
241 ## @param file
242 #-------------------------------------------------------------------------
243 function file_exists() {
244 guess_filename $1 > /dev/null
245 }
246
247 #---------------------------------------------------------------------
248 ##
249 ## Saves the current libraries associated with the spell, from /lib
250 ## and /usr/lib into $SOURCE_DIRECTORY/old.libraries/
251 ## Also runs ldconfig with the saved libraries.
252 ##
253 #---------------------------------------------------------------------
254 function save_libraries() {
255
256 if [ -z "$SOURCE_DIRECTORY" ]
257 then return
258 fi
259
260 debug "libsorcery" "Running save_libraries()"
261
262 OLD_LIBS=$SOURCE_DIRECTORY/old.libraries
263 mkdir -p "$OLD_LIBS"
264
265 SAVED=$OLD_LIBS/$SPELL.saved.libraries
266 lock_file "$SAVED"
267 rm -rf "$SAVED"
268
269 OLD_VERSION=`installed_version $SPELL`
270 OLD_LOG=$INSTALL_LOGS/$SPELL-$OLD_VERSION
271
272 grep "^/lib/\|^/usr/lib" "$OLD_LOG" |
273 while read LINE; do
274 if [[ -f $LINE ]] &&
275 file -bL "$LINE" |
276 grep -q "shared object"
277 then
278 if [[ -h $LINE ]]; then
279 local DEST=$(readlink "$LINE")
280 ln -sf "$DEST" "$OLD_LIBS/$(smgl_basename "$LINE")"
281 else
282 cp "$LINE" "$OLD_LIBS"
283 fi
284 echo $OLD_LIBS/$(smgl_basename "$LINE") >> "$SAVED"
285 fi
286
287
288 done
289
290 ldconfig "$OLD_LIBS"
291 unlock_file "$SAVED"
292
293 if [ -z "$LD_LIBRARY_PATH" ]
294 then export LD_LIBRARY_PATH="$OLD_LIBS"
295 else export LD_LIBRARY_PATH="$OLD_LIBS:$LD_LIBRARY_PATH"
296 fi
297
298 }
299
300 #---------------------------------------------------------------------
301 ##
302 ## Saves the current libraries associated with the spell, from /lib
303 ## and /usr/lib into $SOURCE_DIRECTORY/old.libraries/
304 ## Also runs ldconfig with the saved libraries.
305 ##
306 #---------------------------------------------------------------------
307 function save_binaries() {
308 local dir
309 if [ -z "$SOURCE_DIRECTORY" ]
310 then return
311 fi
312
313 debug "libsorcery" "Running save_binaries()"
314
315 OLD_BINS=$SOURCE_DIRECTORY/old.binaries
316 mkdir -p "$OLD_BINS"
317
318 SAVED=$OLD_BINS/$SPELL.saved.binaries
319 lock_file "$SAVED"
320 rm -rf "$SAVED"
321
322 OLD_VERSION=`installed_version $SPELL`
323 OLD_LOG=$INSTALL_LOGS/$SPELL-$OLD_VERSION
324
325 grep "^/bin/\|^/sbin/\|^/usr/bin/\|^/usr/sbin/" "$OLD_LOG" |
326 while read LINE; do
327 if [[ -f $LINE ]] &&
328 file -bL "$LINE" |
329 grep -q "executable"
330 then
331 mkdir -p "$( smgl_dirname "$OLD_BINS/$LINE" )"
332 if [[ -h "$LINE" ]]; then
333 DEST=$( readlink "$LINE" )
334 ln -sf "$DEST" "$OLD_BINS/$LINE"
335 else
336 cp "$LINE" "$OLD_BINS/$LINE"
337 fi
338 echo $OLD_BINS/$LINE >> "$SAVED"
339 fi
340 done
341
342 unlock_file "$SAVED"
343
344 for dir in $(find "$OLD_BINS" -type d)
345 do
346 export PATH=$(envar_prepend_path "$dir" "$PATH")
347 done
348 }
349
350
351 #---------------------------------------------------------------------
352 ##
353 ## Runs default ldconfig to stop using the saved libraries
354 ##
355 #---------------------------------------------------------------------
356 function release_saved_libraries() {
357 ldconfig
358 }
359
360
361 #---------------------------------------------------------------------
362 ##
363 ## Recovers from a CTRL-C while casting a spell
364 ##
365 #---------------------------------------------------------------------
366 function spell_recover() {
367
368 debug "libsorcery" "Running spell_recover()"
369
370 message "${MESSAGE_COLOR}Aborting dispel of ${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}" \
371 "${MESSAGE_COLOR}and recovering...${DEFAULT_COLOR}"
372
373 unlock_resources "libgrimoire" "install"
374 unlock_resources "cast" "$SPELL"
375 unlock_resources "solo" "cast"
376 local current_version=$(installed_version $SPELL)
377 SUCCESS_LIST=/dev/null
378 resurrect_spell $SPELL $current_version
379
380 exit 130
381 }
382
383
384 #---------------------------------------------------------------------
385 ## @param spell name
386 ## @Stdout section
387 ## Returns the section a spell is in.
388 ##
389 #---------------------------------------------------------------------
390 function find_section() {
391
392 debug "libsorcery" "Running find_section() on $1"
393
394 codex_get_spell_section_name $1
395
396 }
397
398
399 #---------------------------------------------------------------------
400 ##=item directories
401 ##
402 ## @Stdin list of files/dirs/..
403 ## @Stdout list of dirs
404 ##
405 ## Reads a list from standard input, and prints out each entry that is
406 ## a directory (and not a symbolic link to a directory).
407 #---------------------------------------------------------------------
408 function directories() {
409 local item
410 while read item; do
411 if [[ -d $item ]] && ! [[ -h $item ]]; then
412 echo "$item"
413 fi
414 done
415 }
416
417
418 #---------------------------------------------------------------------
419 ## @Stdin list of files/dirs/..
420 ## @Stdout list of files
421 ## Reads a list from standard input, and prints out each entry that is
422 ## a file (and not a symbolic link to a file).
423 ##
424 #---------------------------------------------------------------------
425 function files() {
426 local item
427 while read item; do
428 if [[ -f $item ]] && ! [[ -h $item ]]; then
429 echo "$item"
430 fi
431 done
432 }
433
434
435 #---------------------------------------------------------------------
436 ## @Stdin list of files/dirs/..
437 ## @Stdout list of symlinks
438 ## Reads a list from standard input, and prints out each entry that is
439 ## a symbolic linke
440 ##
441 #---------------------------------------------------------------------
442 function symlinks() {
443 local item
444 while read item; do
445 if [[ -h $item ]]; then
446 echo "$item"
447 fi
448 done
449 }
450
451
452 #---------------------------------------------------------------------
453 ## @param filename
454 ## @Stdin list of files/dirs/..
455 ## @Stdout filtered list
456 ## First argument is a file that contains (basic) grep regular expressions.
457 ## They are joined with \|'s and given to grep -v.
458 ## Which will filter standard input to remove entries that match.
459 ## Used to filter out excluded or protected files from install logs.
460 ##
461 #---------------------------------------------------------------------
462 function filter() {
463 local thing RID_LIST NOT_RID_LIST
464 local files each invert
465 for each in $@; do
466 test -f $each && files="$files $each"
467 done
468
469 if [[ $files ]] ; then
470 RID_LIST=$(
471 cat $files |
472 grep -v '^!' | while read thing; do
473 echo -n "${thing}\|"
474 done)
475 NOT_RID_LIST=$(
476 cat $files |
477 grep '^!' | while read thing; do
478 echo -n "${thing/\!/}\|"
479 done)
480 RID_LIST=${RID_LIST%\\|}
481 NOT_RID_LIST=${NOT_RID_LIST%\\|}
482
483 local TMP_SSF=$(make_safe_dir)
484 local FILE=$TMP_SSF/ssf
485
486 if [[ $RID_LIST ]]
487 then
488 if [[ $NOT_RID_LIST ]]
489 then
490 cat > $FILE
491 {
492 grep -v "$NOT_RID_LIST\|$RID_LIST" $FILE
493 grep "$NOT_RID_LIST" $FILE
494 }
495 rm $FILE 2>/dev/null
496 else
497 grep -v "$RID_LIST"
498 fi
499 else
500 cat
501 fi
502 rmdir $TMP_SSF 2>/dev/null
503 else
504 cat
505 fi
506 }
507
508 #---------------------------------------------------------------------
509 ## @param filename
510 ## @Stdin list of files/dirs/..
511 ## @Stdout filtered list
512 ## First argument is a file that contains (basic) grep regular expressions.
513 ## They are joined with \|'s and given to grep
514 ## Which will filter standard input and remove entries
515 ## that do not match.
516 ## Used to filter in config files from install logs.
517 ##
518 #---------------------------------------------------------------------
519 function filter_in() {
520 local thing RID_LIST NOT_RID_LIST
521 local files each
522 for each in $@; do
523 test -f $each && files="$files $each"
524 done
525
526 if [[ $files ]] ; then
527 RID_LIST=$(
528 cat $files |
529 grep -v '^!' | while read thing; do
530 echo -n "${thing}\|"
531 done)
532 NOT_RID_LIST=$(
533 cat $files |
534 grep '^!' | while read thing; do
535 echo -n "${thing/\!/}\|"
536 done)
537 RID_LIST=${RID_LIST%\\|}
538 NOT_RID_LIST=${NOT_RID_LIST%\\|}
539
540 if [[ $RID_LIST ]]
541 then
542 if [[ $NOT_RID_LIST ]]
543 then
544 grep "$RID_LIST" |
545 grep -v "$NOT_RID_LIST"
546 else
547 grep "$RID_LIST"
548 fi
549 else
550 # grep '' outputs everything in this case we want nothing
551 cat > /dev/null
552 fi
553 else
554 cat
555 fi
556 }
557
558 function filter_generic() {
559 local args=$1
560 local filter_name=$2
561 local system_filter=$3
562 local spell_from=$4
563 local grimoire_filter section_filter spell_filter spell_dir
564 if [[ $spell_from == "codex" ]]
565 then
566 debug libsorcery "filter_generic codex at : $SCRIPT_DIRECTORY "
567 grimoire_filter=$GRIMOIRE/$filter_name
568 section_filter=$SECTION_DIRECTORY/$filter_name
569 spell_filter=$SCRIPT_DIRECTORY/$filter_name
570 else
571 if tablet_find_spell_dir $SPELL spell_dir &>/dev/null; then
572 debug libsorcery "filter_generic tablet at : $spell_dir "
573 tablet_get_spell_filter "$spell_dir" "$filter_name" spell_filter &>/dev/null
574 tablet_get_section_filter "$spell_dir" "$filter_name" section_filter &>/dev/null
575 tablet_get_grimoire_filter "$spell_dir" "$filter_name" grimoire_filter &>/dev/null
576 fi
577 fi
578 set -- $args
579 if [ "$1" == -v ] ; then
580 shift
581 filter_in "$@" $system_filter $grimoire_filter $section_filter $spell_filter
582 else
583 filter "$@" $system_filter $grimoire_filter $section_filter $spell_filter
584 fi
585 }
586
587 function filter_volatiles() {
588 filter_generic "$*" volatiles $VOLATILES
589 }
590
591 function filter_configs() {
592 filter_generic "$*" configs $CONFIGS
593 }
594
595 function filter_excluded() {
596 filter_generic "$*" excluded $EXCLUDED
597 }
598
599 function filter_protected() {
600 filter_generic "$*" protected $PROTECTED
601 }
602
603 #---------------------------------------------------------------------
604 ## @Stdin list of files
605 ## @Stdout list of directories
606 ##
607 ## THIS FUNCTION IS DEPRECIATED, use get_dirnames instead! (remove in 1.16)
608 ## Given a list of files from standard input, returns the directory
609 ## of each file.
610 #---------------------------------------------------------------------
611 function dirnames() {
612 get_dirnames "$@"
613 }
614
615 #---------------------------------------------------------------------
616 ##
617 ## Sets some environment variables (such as C<CFLAGS>) based on the
618 ## option passed. Options may be on or more of: i386, i486, i586,
619 ## pentium, pentium-mmx, i686, pentiumpro, pentium2, pentium3,
620 ## pentium4, k6, k6-2, k6-3, athlon, athlon-tbird, athlon-4,
621 ## athlon-xp, athlon-mp, powerpc, speedy, tiny, risky, strip
622 ##
623 #---------------------------------------------------------------------
624 function optimize() {
625 debug "libsorcery" "In optimize()"
626
627 unset CFLAGS CXXFLAGS LDFLAGS CPPFLAGS
628 unset FAST PRELINK RISKY SMALL SPEEDY STRIP TINY
629
630 # if user specified --no-opts then use only the args from the command line
631 # otherwise do the normal stuff
632 if [[ $NO_OPTIMIZATION_FLAGS ]] ; then
633 export CFLAGS="$OVERRIDE_CFLAGS"
634 export CXXFLAGS="$OVERRIDE_CXXFLAGS"
635 export LDFLAGS="$OVERRIDE_LDLAGS"
636 export CPPFLAGS="$OVERRIDE_CPPFLAGS"
637 else
638 set_architecture
639 debug "ARCHITECTURE='${ARCHITECTURE}'"
640 debug "libsorcery" "TARGET='${TARGET}'"
641 debug "libsorcery" "OPTIMIZATIONS='${OPTIMIZATIONS}'"
642 BUILD=${HOST}
643
644 debug "libsorcery" "BUILD is $BUILD, HOST is $HOST"
645
646 CFLAGS="$CFLAGS -pipe"
647 for PARAM in $OPTIMIZATIONS; do
648 case $PARAM in
649 prelink)
650 CFLAGS="$CFLAGS -DPIC -fPIC"
651 PRELINK="on"
652 ;;
653
654 risky)
655 CFLAGS="$CFLAGS -ffast-math -funroll-loops"
656 RISKY="on"
657 ;;
658
659 speedy)
660 CFLAGS="$CFLAGS $FAST"
661 SPEEDY="on"
662 ;;
663
664 strip)
665 LDFLAGS="$LDFLAGS -s"
666 STRIP="on"
667 ;;
668
669 tiny)
670 CFLAGS="$CFLAGS $SMALL"
671 TINY="on"
672 ;;
673
674 esac
675 done
676 # use echo to crunch all the whitespace out for broken configure scripts
677 export CXXFLAGS=$(echo $CFLAGS $CUSTOM_CXXFLAGS $OVERRIDE_CXXFLAGS $USER_SPELL_CXXFLAGS)
678 export CFLAGS=$(echo $CFLAGS $CUSTOM_CFLAGS $OVERRIDE_CFLAGS $USER_SPELL_CFLAGS)
679 export LDFLAGS=$(echo $LDFLAGS $CUSTOM_LDFLAGS $OVERRIDE_LDLAGS $USER_SPELL_LDFLAGS)
680 export CPPFLAGS=$(echo $CPPFLAGS $CUSTOM_CPPFLAGS $OVERRIDE_CPPFLAGS $USER_SPELL_CPPFLAGS)
681 fi
682
683 }
684
685 #---------------------------------------------------------------------
686 ## @param grimoire-path
687 ## @Stdout history
688 ## Display the history of the grimoire given for review
689 #---------------------------------------------------------------------
690 function grimoire_history() {
691
692 local grimoire="$1"
693 if [ -e $grimoire/ChangeLog ] ; then
694 local grimoirename="${grimoire##*/}"
695 local date="`cat "$STATE_DIRECTORY/$grimoirename.lastupdate" 2> /dev/null`"
696 [ -z "$date" ] && date="20030818"
697 local datedash=$(echo "$date" | sed 's,^\(....\)\(..\)\(..\)$,\1-\2-\3,')
698 get_new_changes "Viewing history since last update ($datedash) for grimoire -- ${grimoirename} -- :" "$date" "$grimoire/ChangeLog"
699 else
700 echo "No ChangeLog in the $grimoire Grimoire, skipping viewing..."
701 echo ""
702 fi
703 date +%Y%m%d > "$STATE_DIRECTORY/$grimoirename.lastupdate"
704 }
705
706
707 #---------------------------------------------------------------------
708 ## @Stdout history
709 ## Display the history of sorcery for review
710 ##
711 #---------------------------------------------------------------------
712 function sorcery_history() {
713 local date="`cat "$STATE_DIRECTORY/sorcery.lastupdate" 2> /dev/null`"
714 [ -z "$date" ] && date="20030818"
715 local datedash="`echo "$date" | sed 's,^\(....\)\(..\)\(..\)$,\1-\2-\3,'`"
716
717 get_new_changes "Viewing history since last update ($datedash) for sorcery :" "$date" /usr/share/doc/sorcery/ChangeLog
718
719 date +%Y%m%d > "$STATE_DIRECTORY/sorcery.lastupdate"
720 }
721
722 #---------------------------------------------------------------------
723 ##@param old date
724 ##@param changelog
725 ## Get the new changes from passed changelog argument
726 ##
727 #---------------------------------------------------------------------
728 function get_new_changes() {
729 local msg="$1"
730 local date="$2"
731 # This needs some explaination:
732 # The first item in {}'s extracts the date, assuming the format yyyy-mm-dd
733 # then checks if its less than the last-update date ($date). The second
734 # part ensures that we're actually looking at a date and not a line
735 # of changelog. If both those are true, set 'd' to 1, otherwise d is '0'.
736 #
737 # In other words, d is 0 until it encounters a starting changelog entry
738 # from before the given $date. Then d is 1 for each starting entry. Its
739 # always 0 for bulleted changelog lines and blank lines.
740 #
741 # The second portion begins "NR==1,d". This is special awk syntax
742 # that says to run the stuff to the right in {}'s starting once the
743 # first statement is true, up through when the second one is true.
744 # For example, NR==1,NR==8 would run the right-hand block for lines 1
745 # through 8.
746 #
747 # NR is the line number, so its true on the first line. d is true once the
748 # the dates are from before the last update. The if(!d) is necessary
749 # to skip the first line where the changelog date is less than $date.
750 #
751 local changelog="$( awk -v date="$date" '{ d = (strtonum(substr($0,1,4) substr($0,6,2) substr($0,9,2)) < date && strtonum(substr($0,1,4)) > 0); }; NR == 1, d { if (!d) print }' "$3" )"
752
753 if [[ "$changelog" ]] ; then
754 {
755 echo "$msg"
756 echo "$changelog"
757 echo
758 } > $TMP_DIR/pagerdata
759 timeout_pager "$TMP_DIR/pagerdata"
760 rm $TMP_DIR/pagerdata
761 else
762 echo "$msg"
763 echo "Nothing new."
764 echo
765 fi
766 }
767
768
769 #---------------------------------------------------------------------
770 ## Pager with timeouts, cannot be used from a pipe.
771 ## Invokes a subshell in case there are other background jobs running
772 #---------------------------------------------------------------------
773 function timeout_pager() { (
774 $PAGER "$@" &
775 sleep 1
776 for ((i=0;i<PAGER_TIMEOUT*10;i++)) ; do
777 jobs &>/dev/null # this makes bash clean up so the next line works
778 [[ "$(jobs)" ]] || return 0
779 sleep .1
780 done
781 jobs -p|xargs kill
782 jobs &>/dev/null # hide the [Done [2] blah blah] message
783 stty sane
784 if query "\nPager timeout, continue viewing $@" n; then
785 $PAGER "$@"
786 fi
787 ) 2>/dev/null # hides less complaining that it was killed
788 }
789
790 #---------------------------------------------------------------------
791 ##
792 ## Attempt to fix any spells that may be broken.
793 ##
794 #---------------------------------------------------------------------
795 function fix_installed_spells() {
796
797 local ANSWER=
798
799 [ "$AUTOFIX" == "on" ] && ANSWER=y || ANSWER=n
800 if query "Attempt to fix spells that may have become broken ?" $ANSWER; then
801 cleanse --fix;
802 fi
803
804 if [ "$AUTOPRUNE" == "on" ]; then prune; fi
805 }
806
807 #---------------------------------------------------------------------
808 ## @Stdout log files list
809 ## Returns a list of the log files for each spell.
810 ##
811 #---------------------------------------------------------------------
812 function log_list() {
813 local spell version
814 while read spell version; do
815 # the install and md5sum logs are not compressed
816 echo "$INSTALL_LOGS/$spell-$version"
817 echo "$MD5SUM_LOGS/$spell-$version"
818 # the compile and castfs log usually are compressed
819 # FIXME $EXTENSION may be the wrong one if the user changed it
820 echo "$COMPILE_LOGS/$spell-$version$EXTENSION"
821 echo "$COMPILE_LOGS/$spell-$version.castfs.dbglog$EXTENSION"
822 done < <(all_spell_status | cut -d: -f1,4 --output-delimiter=" ")
823 }
824
825
826 #---------------------------------------------------------------------
827 ##
828 ## Removes stale logs.
829 ##
830 #---------------------------------------------------------------------
831 function clean_logs() {
832 debug "libsorcery" "Running clean_logs()"
833 local file
834
835 message "${CHECK_COLOR}Cleaning log files...$DEFAULT_COLOR"
836
837 {
838 # don't try to delete logs of installed spells, as they may not exist
839 # tee duplicates the output, so uniq will filter them out
840 log_list | sed p
841 find $INSTALL_LOGS $MD5SUM_LOGS $COMPILE_LOGS -type f
842 } | sort | uniq -u |
843 while read file; do
844 message "Removing stale log: $file"
845 rm "$file"
846 done
847 }
848
849 #---------------------------------------------------------------------
850 ##
851 ## Updates the activity log.
852 ##
853 #---------------------------------------------------------------------
854 function activity_log() {
855 local date command spell version outcome info
856
857 lock_file $ACTIVITY_LOG
858 date=$(date -u +%Y%m%d:%H%M\(%z\))
859 command=$1
860 spell=$2
861 version=$3
862 outcome=$4
863 info=$5
864 echo -e "$date\t$command\t$spell\t$version\t$outcome\t$info" >> $ACTIVITY_LOG
865 unlock_file $ACTIVITY_LOG
866 }
867
868
869 #---------------------------------------------------------------------
870 ##
871 ## Executes the spell's DETAILS file.
872 ##
873 #---------------------------------------------------------------------
874 function run_details() {
875 debug "libsorcery" "starting run_details for $SPELL"
876 if ! codex_set_current_spell_by_name $SPELL; then
877 local GRIMOIRES=`codex_get_all_grimoires`
878 message "${PROBLEM_COLOR}Unable to find spell" \
879 "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}${PROBLEM_COLOR}" \
880 "in grimoire(s): $GRIMOIRES ${DEFAULT_COLOR}"
881 false
882 fi
883 }
884
885 #---------------------------------------------------------------------
886 ##
887 ## unsets variables set by DETAILS. <br>
888 ## vars: SPELL VERSION SOURCE_DIRECTORY WEB_SITE UPDATED ENTERED SHORT SOURCE*
889 ##
890 ## Needs to be merged with the libcodex function since they are both
891 ## needed to fully unset a DETAILS (afk 4/21/04)
892 ##
893 #---------------------------------------------------------------------
894 function unset_details() {
895
896 local TEMP=""
897 local VARS="SPELL VERSION SOURCE_DIRECTORY WEB_SITE UPDATED ENTERED SHORT"
898 VARS="$VARS SECURITY_PATCH PATCHLEVEL"
899
900 # Take care or SOURCEx and SOURCEx_URL
901 for i in ${!SOURCE*} ; do
902 TEMP=${TEMP}${i}\\n
903 done
904 # not all SOURCE_* should be deleted (SOURCE_CACHE)
905 VARS="$VARS `echo -e $TEMP | egrep "^SOURCE[[:digit:]]*(_URL|_GPG|_IGNORE)?$"`"
906
907 unset $VARS
908 }
909
910
911
912
913 #---------------------------------------------------------------------
914 ##
915 ## Runs C<track> and C<archive> on the current spell.
916 ##
917 ## THIS FUNCTION IS DEPRECIATED AND SHOULD NOT BE CALLED FOR ANY REASON
918 ##
919 #---------------------------------------------------------------------
920 function boost() {
921
922 debug "libsorcery" "Running boost() on $SPELL THIS IS DEPRECIATED"
923 echo "Running boost() on $SPELL THIS IS DEPRECIATED, please contact the spell's maintainer and ask them to remove this call"
924 true
925 }
926
927
928 #---------------------------------------------------------------------
929 ##
930 ## Given a list of source files, returns true if each file exists.
931 ##
932 #---------------------------------------------------------------------
933 function verify_source() {
934 local source_file
935 for source_file in $@; do
936 if ! guess_filename $SOURCE_CACHE/$source_file > /dev/null; then
937 message "${PROBLEM_COLOR}Missing ${FILE_COLOR}$source_file${DEFAULT_COLOR}"
938 message "${PROBLEM_COLOR}Cast aborting.${DEFAULT_COLOR}"
939 activity_log "cast" "$SPELL" "$VERSION" "failure" \
940 "because it was missing source: $source_file"
941 log_failure_reason "missing source"
942 return 1
943 fi
944 done
945 return 0
946 }
947
948
949 #---------------------------------------------------------------------
950 ## @param spell
951 ## @Stdout filelist
952 ## Returns a list of each source file used by a spell. Most have only
953 ## one, but xfree86 for example splits the sources into three separate
954 ## source files.
955 ##
956 #---------------------------------------------------------------------
957 function sources() { (
958
959 local i srcVar
960
961 if [ -z "$SOURCE" ]; then
962 codex_set_current_spell_by_name $1
963 fi
964 get_spell_files
965
966 ) }
967
968 #---------------------------------------------------------------------
969 ## @param spell
970 ## @Stdout filelist
971 ## Returns a list of each source file used by a spell. Most have only
972 ## one, but xfree86 for example splits the sources into three separate
973 ## source files.
974 ##
975 #---------------------------------------------------------------------
976 function source_urls() { (
977
978 local i srcVar
979
980 if [ -z "$SOURCE" ]; then
981 codex_set_current_spell_by_name $1
982 fi
983 get_spell_files_and_urls|while read -a line; do
984 unset line[0]
985 echo "${line[*]}"
986 done
987
988
989 ) }
990
991
992 #---------------------------------------------------------------------
993 ## @Stdout filelist
994 ## Returns a list of files that should not be pruned.
995 ##
996 #---------------------------------------------------------------------
997 function generate_keep_list() {
998 local source_keep=$1
999 local cache_keep=$2
1000 local type=$3
1001 if [[ $type == installed_only ]] ; then
1002 get_all_spells_with_status ok |
1003 sort -u |
1004 while read spell; do
1005 codex_find_spell_by_name $spell
1006 done
1007 else
1008 codex_get_all_spells
1009 fi |
1010 (
1011 echo sorcery-$SORCERY_BRANCH.tar.bz2
1012 while read SPELL_DIRECTORY ; do
1013 codex_set_current_spell_quick $SPELL_DIRECTORY &>/dev/null
1014 sources 2>/dev/null
1015 ls $INSTALL_CACHE/$SPELL-$VERSION-* 1>&2 2>/dev/null
1016 unset VERSION SPELL ${!SOURCE*}
1017 done
1018 ) 2> $cache_keep > $source_keep
1019
1020 #Add the README in the cache to list of files to keep
1021 echo README >> $cache_keep
1022
1023 }
1024
1025
1026 #---------------------------------------------------------------------
1027 ##
1028 ## Removes unnecessary files from the source cache and install cache.
1029 ##
1030 #---------------------------------------------------------------------
1031 function prune() {
1032
1033 debug "libsorcery" "Running prune()"
1034 local NO_KEEP
1035 local NUM_NO_KEEP=0
1036
1037 message "${MESSAGE_COLOR}Generating list of files to keep...${DEFAULT_COLOR}"
1038 local SOURCE_KEEP="$TMP_DIR/prune-keep-source"
1039 local CACHE_KEEP="$TMP_DIR/prune-keep-cache"
1040 rm -rf $CACHE_KEEP
1041 rm -rf $SOURCE_KEEP
1042 generate_keep_list $SOURCE_KEEP $CACHE_KEEP $1
1043
1044 message "${MESSAGE_COLOR}Cleaning up source cache" \
1045 "(${DEFAULT_COLOR}$SOURCE_CACHE${MESSAGE_COLOR})...${DEFAULT_COLOR}"
1046 local SOURCE_RM="$TMP_DIR/prune.rm.source"
1047 find $SOURCE_CACHE -follow -mindepth 1 -maxdepth 1 -type f|
1048 awk -F/ 'BEGIN {
1049 while ( getline < ARGV[1] ) {
1050 keep[$NF] = 1;
1051 }
1052 while ( getline < ARGV[2] ) {
1053 if ( keep[$NF] != 1 ) {
1054 print $0;
1055 }
1056 }
1057 }' $SOURCE_KEEP - |sort -u > $SOURCE_RM
1058 if test -s $SOURCE_RM ; then
1059 NUM_NO_KEEP=$(cat $SOURCE_RM|wc -l)
1060
1061 message "There are $NUM_NO_KEEP files that can be removed"
1062 if query "Edit the list?" "n" ; then
1063 edit_file $SOURCE_RM
1064 fi
1065 if query "Remove the files?" "y" ; then
1066 cat $SOURCE_RM|xargs rm
1067 fi
1068 fi
1069
1070 message "${MESSAGE_COLOR}Cleaning up install cache" \
1071 "(${DEFAULT_COLOR}$INSTALL_CACHE${MESSAGE_COLOR})...${DEFAULT_COLOR}"
1072 local CACHE_RM="$TMP_DIR/prune.rm.cache"
1073 find $INSTALL_CACHE -mindepth 1 -maxdepth 1 -type f|
1074 awk -F/ 'BEGIN {
1075 while ( getline < ARGV[1] ) {
1076 keep[$NF] = 1;
1077 }
1078 while ( getline < ARGV[2] ) {
1079 if ( keep[$NF] != 1 ) {
1080 print $0;
1081 }
1082 }
1083 }' $CACHE_KEEP - |sort -u > $CACHE_RM
1084 if test -s $CACHE_RM ; then
1085 NUM_NO_KEEP=$( cat $CACHE_RM | wc -l )
1086 message "There are $NUM_NO_KEEP files that can be removed"
1087 if query "Edit the list?" "n" ; then
1088 edit_file $CACHE_RM
1089 fi
1090 if query "Remove the files?" "y" ; then
1091 cat $CACHE_RM|xargs rm
1092 fi
1093 fi
1094
1095 rm -f $SOURCE_KEEP $CACHE_KEEP $SOURCE_RM $CACHE_RM
1096
1097 }
1098
1099
1100 #---------------------------------------------------------------------
1101 ##
1102 ## Sets DISTCC=[on|off] depending on the value of DISTCC_HOSTS.
1103 ## Adds /var/lib/sorcery/build to the C<PATH> if necessary.
1104 ##
1105 #---------------------------------------------------------------------
1106 function invoke_build_dir() {
1107
1108 # This merits some explaination:
1109 #
1110 # In the /var/lib/sorcery/build dir are frontends for the compilers
1111 # they run CCACHE and DISTCC. By putting them in the front of the path
1112 # they get run first, then hand the work off to the real compilers.
1113 # The script also loads /etc/sorcery/compile_config, this made it
1114 # convenient for building stuff outside of sorcery and taking advantage
1115 # of ccache/distcc, just do "export PATH="/var/lib/sorcery/build:$PATH""
1116 # and you're set, you can also edit the DISTCC hosts on the fly.
1117 #
1118 # Then someone had the bright idea "if we set DISTCC_HOSTS to the empty
1119 # string, distcc wont run!" due to a misconception in how this function
1120 # worked, that spell hack would only work /some/ of the time: if you
1121 # used ccache in addition to distcc, distcc wouldnt get disabled. *Sigh*
1122 #
1123 # SO...now we're stuck with a bunch of spells in the field disabling
1124 # distcc in an broken way, obviously they all cant change overnight. To
1125 # make matters worse inside make() we have to fiddle with the number of
1126 # make jobs to use in case distcc is disabled (badly).
1127 #
1128 # so the answer is:
1129 # 1) make a new variable "USE_DISTCC" and set it to "off" if distcc
1130 # is being disabled by the spell
1131 # 2) check if USE_DISTCC == off in run_compiler, but still check the
1132 # other signs just in case its being run manually
1133 # 3) add a check for DISABLE_DISTCC so spells can start using that someday
1134 # (phase this in after a few months, then phase out the old check below,
1135 # but not in run_compiler)
1136 # 4) remove the old stupid logic for MAKE_NJOBS (num_hosts + 1),
1137 # instead split MAKE_NJOBS up, add a JOBS_PER_HOST multiplier, and add
1138 # MAKE_NJOBS to that. This results in the number of jobs being $MAKE_NJOBS
1139 # (default 1) when distcc is disabled (bug 6432), and allows an automatic
1140 # increase in the number of jobs per host if its desired.
1141 #
1142
1143 USE_DISTCC=off
1144 if [[ $DISABLE_DISTCC != yes ]] ; then
1145 if test -n "$DISTCC_HOSTS" && spell_ok distcc ; then
1146 USE_DISTCC=on
1147 fi
1148 fi
1149
1150 if ! spell_ok ccache ; then
1151 CCACHE=off
1152 fi
1153
1154 if [[ "$CCACHE" == on ]] || [[ "$USE_DISTCC" == on ]] ; then
1155 export PATH="$RUN_COMPILER_DIR:$PATH"
1156 fi
1157 }
1158
1159 #---------------------------------------------------------------------
1160 ## @Stdout filelist
1161 ## Returns false if one or more source files for the current spell
1162 ## are missing.
1163 ##
1164 #---------------------------------------------------------------------
1165 function verify_sources() {
1166 verify_source $(sources $SPELL)
1167 }
1168
1169
1170
1171 #---------------------------------------------------------------------
1172 ##
1173 ## Will set the prefered compression type based on user filled option
1174 ## in dialog menu (either gzip/bzip).
1175 ##
1176 #---------------------------------------------------------------------
1177 function set_compression_type() {
1178
1179 local B_HELP="bzip2 compression (slow, small files)"
1180 local P_HELP="parallel bzip2 compression (slow unless on SMP, small files)"
1181 local X_HELP="xz compression (slow compress, fast decompress, smallest files)"
1182 local G_HELP="gzip compression (fast, larger files)"
1183 local T_HELP="no compression/tar (fastest, largest files)"
1184
1185 while
1186
1187 COMMAND=`eval $DIALOG ' --title "Currently using : $COMPRESSBIN " \
1188 --item-help \
1189 --ok-label "Select" \
1190 --cancel-label "Exit" \
1191 --menu \
1192 "" \
1193 0 0 0 \
1194 "B" "bzip2 compression" "$B_HELP" \
1195 "P" "pbzip2 compression (parallel bzip2)" "$P_HELP" \
1196 "X" "xz compression" "$X_HELP" \
1197 "G" "gzip compression" "$G_HELP" \
1198 "T" "no compression/tar" "$T_HELP"'`
1199
1200 do
1201 ARCHIVEBIN="tar"
1202 modify_local_config "ARCHIVEBIN" "tar"
1203
1204 case $COMMAND in
1205 B)
1206 modify_local_config "COMPRESSBIN" "bzip2" &&
1207 COMPRESSBIN="bzip2" &&
1208 modify_local_config "EXTENSION" ".bz2" ;;
1209 P)
1210 if ! spell_ok pbzip2; then
1211 clear_line
1212 message "pbzip2 is not installed on this system! Running cast ...\n"
1213 sleep 2
1214 cast pbzip2
1215 fi &&
1216 modify_local_config "COMPRESSBIN" "pbzip2" &&
1217 COMPRESSBIN="pbzip2" &&
1218 modify_local_config "EXTENSION" ".bz2" ;;
1219 X)
1220 if ! spell_ok xz-utils; then
1221 clear_line
1222 message "xz-utils is not installed on this system! Running cast ...\n"
1223 sleep 2
1224 cast xz-utils
1225 fi &&
1226 modify_local_config "COMPRESSBIN" "xz" &&
1227 COMPRESSBIN="xz" &&
1228 modify_local_config "EXTENSION" ".xz" ;;
1229 G)
1230 modify_local_config "COMPRESSBIN" "gzip" &&
1231 COMPRESSBIN="gzip" &&
1232 modify_local_config "EXTENSION" ".gz" ;;
1233 T)
1234 modify_local_config "COMPRESSBIN" "" &&
1235 COMPRESSBIN="" &&
1236 modify_local_config "EXTENSION" "" ;;
1237 esac
1238 done
1239
1240 }
1241
1242 #---------------------------------------------------------------------
1243 ## @param filename
1244 ## @return 0 if filename seems to be compressed
1245 ## @return 1 otherwise
1246 ## Returns true if the name of the file indicates that it should be
1247 ## a compressed file. In other words, this function returns true if
1248 ## the extension is .gz, .tgz, .bz2, .zip, .rpm, .Z, .xz, .7z or .lzma.
1249 ##
1250 #---------------------------------------------------------------------
1251 function filename_indicates_compression() {
1252 grep -qE "^.*\.(gz|tgz|bz2|zip|Z|rpm|xz|7z|lzma)$" <<< "$1"
1253 }
1254
1255 #---------------------------------------------------------------------
1256 ## Check that we have all the passed grimoires and use them to
1257 ## override the default selection (all)
1258 #---------------------------------------------------------------------
1259 function override_grimoires() {
1260 local grimoires=$1
1261 local grimoire
1262
1263 for grimoire in $grimoires; do
1264 if ! codex_find_grimoire $grimoire > /dev/null; then
1265 error_message "Grimoire $grimoire does not exist!"
1266 if query "Do you want to add it?" y; then
1267 scribe add $grimoire || exit 13
1268 echo
1269 else
1270 list_remove grimoires $grimoire
1271 fi
1272 fi
1273 done
1274 [[ -z $grimoires ]] && message "Using default grimoire selection!\n"
1275
1276 export OVERRIDE_GRIMOIRES="$grimoires"
1277 }
1278
1279 #---------------------------------------------------------------------
1280 ## Sets the most appropriate params for PAGER
1281 ## @Globals PAGER
1282 #---------------------------------------------------------------------
1283 function set_pager() {
1284 if [[ -z $PAGER ]]; then
1285 if real_spell_ok less; then
1286 # pager info
1287 # -R: display color codes properly
1288 # -F: quit on one-screenfull of data (otherwise scribe pauses on empty updates)
1289 # -X: dont do screen init and deinit, gaze install
1290 # of a small spell is effectively useless otherwise as the
1291 # screen is cleared afterwards.
1292 # -f: force it, since we may not be dealing with a regular file
1293 PAGER="less -R -F -X -f"
1294 else
1295 PAGER=cat
1296 fi
1297 return
1298 fi
1299
1300 local pager_prog
1301 local pager_params=${PAGER#* }
1302 smgl_basename "${PAGER%% *}" pager_prog
1303 # setting PAGER to a single word would give bad parameters
1304 [[ $pager_prog == $PAGER ]] && unset pager_params
1305
1306 # TODO: add any needed options for the rest of the pagers
1307 case $pager_prog in
1308 less) PAGER="less -R -F -X -f $pager_params" ;;
1309 most) PAGER="most $pager_params" ;;
1310 w3m) PAGER="w3m $pager_params" ;;
1311 more) PAGER="more $pager_params";;
1312 *) ;;
1313 esac
1314 }
1315
1316 #---------------------------------------------------------------------
1317 ##
1318 ## This software is free software; you can redistribute it and/or modify
1319 ## it under the terms of the GNU General Public License as published by
1320 ## the Free Software Foundation; either version 2 of the License, or
1321 ## (at your option) any later version.
1322 ##
1323 ## This software is distributed in the hope that it will be useful,
1324 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
1325 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1326 ## GNU General Public License for more details.
1327 ##
1328 ## You should have received a copy of the GNU General Public License
1329 ## along with this software; if not, write to the Free Software
1330 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1331 ##
1332 #---------------------------------------------------------------------