/var/lib/sorcery/modules/libcodex
1 #!/bin/bash
2 #---------------------------------------------------------------------
3 ##
4 ## @Synopsis Set of functions for dealing with a library of grimoires (spell books).
5 ##
6 ## A grimoire is a book containing one or more spells. A codex
7 ## is a collection of one or more grimoires. There are functions
8 ## for listing the available grimiores, listing spells in a grimoire,
9 ## listing sections in a grimoire, etc.
10 ##
11 ## Note: Each of the functions that returns a spell, section, or
12 ## grimoire returns the full path. Functions that explicitly return
13 ## a spell I<name> or section I<name> do not return the full
14 ## path.
15 ##
16 ## <br>grimoires<br>
17 ##
18 ## This section contains some notes on grimoires.
19 ##
20 ## <br>Grimoire Layout<br>
21 ## The codex functions expect each grimoire to be a directory.
22 ## Each directory entry in a grimoire directory is considered
23 ## to be a section. All directory entries in a section are
24 ## considered to be a spell if they included an executable file
25 ## named F<DETAILS>.
26 ##
27 ## <br>Multiple grimoires<br>
28 ##
29 ## Multiple grimoires are specified by setting entries in the
30 ## I<GRIMOIRE_DIR> array. For example, to set two additional
31 ## grimoires, you would put something like the following in
32 ## your local SMGL grimoire file (F</etc/sorcery/local/grimoire>).
33 ## <pre>
34 ## GRIMOIRE_DIR[1]=/path/to/alternate/grimoire
35 ## GRIMOIRE_DIR[2]=/path/to/other/alternate/grimoire
36 ## </pre>
37 ## Grimoires are processed/searched in increasing order starting
38 ## at index 0. The SMGL configuration file provides the value for
39 ## the default grimoire as I<GRIMOIRE_DIR[0]> or simply I<GRIMOIRE_DIR>.
40 ##
41 ## The following two lines show how to reorder the default
42 ## grimoire so that it's not searched first (in this example
43 ## it will be searched second).
44 ## <pre>
45 ## GRIMOIRE_DIR[1]=$GRIMOIRE
46 ## GRIMOIRE_DIR[0]=/path/to/grimoire/to/search/first
47 ## </pre>
48 ## There is no limitation on the number of grimoires that can be
49 ## specified.
50 ##
51 ## It is also possible to add and remove grimoires using the
52 ## codex_add_grimoire and codex_remove_grimoire functions.
53 ##
54 ## @Copyright
55 ##
56 ## Copyright 2002 by the Source Mage Team
57 ##
58 ##
59 #---------------------------------------------------------------------
60
61 #####################GRIMOIRE FUNCTIONS###############################
62 #---------------------------------------------------------------------
63 ## @param grimoire
64 ## @param lookup (optional)
65 ## @param variable to set (optional)
66 ## @return 0 if grimoire can be canonicalized
67 ##
68 ## Outputs a grimoire in canonical form (full path)
69 ## if lookup equal to "lookup" look up the grimoire name
70 ## else build the grimoire name from $CODEX_ROOT/$grimoire
71 ## CODEX_ROOT is the default grimoire location
72 ## NOTE: one can specify partial paths
73 #---------------------------------------------------------------------
74 function codex_canonicalize_grimoire_name() {
75 local grimoire=$1
76 if [ "${grimoire:0:1}" == "/" ] ; then
77 # already a full path
78 if [[ -z $3 ]]; then
79 echo $grimoire
80 else
81 eval "$3=\"\$grimoire\""
82 fi
83 return 0
84 fi
85
86 if [ "$2" == "lookup" ] ; then
87 if [[ -z $3 ]]; then
88 codex_find_grimoire $grimoire
89 else
90 local grim idx
91 codex_find_grimoire $grimoire grim idx
92 eval "$3=\"\$grim\""
93 fi
94 else
95 if [[ -z $3 ]]; then
96 echo "$CODEX_ROOT/$grimoire"
97 else
98 eval "$3=\"\$CODEX_ROOT/\$grimoire\""
99 fi
100 fi
101 # do nothing and preserve return code
102 }
103
104 function codex_is_canonicalized() {
105 if [ ${1:0:1} != "/" ] ; then
106 message "$1 is not canonicalized!!"
107 message "If you see this please contact the sorcery team"
108 return 1
109 fi
110 }
111
112 #---------------------------------------------------------------------
113 ## @param grimoire name, or path to one
114 ## @param variable name, is set to the matching grimoire (optional)
115 ## @param variable name, is set to the matching grimoire's index (optional)
116 ## @Stdout the grimoire's path
117 ## @return 0 there is a grimoire
118 ## @return 1 there is no grimoire
119 ## NOTE: one can specify partial paths such as codex/stable
120 ## <pre>
121 ## example1:
122 ## codex_find_grimoire test; echo "returned $?"
123 ## /var/lib/sorcery/codex/test
124 ## returned 0
125 ## example2:
126 ## codex_find_grimoire sorcery/codex/stable; echo "returned $?"
127 ## /var/lib/sorcery/codex/stable
128 ## returned 0
129 ## </pre>
130 ##
131 #---------------------------------------------------------------------
132 function codex_find_grimoire() {
133 local cfg_lookup=$1
134 local cfg_grimoire
135 local use_refs=no
136 if [ $# -eq 3 ] ; then
137 use_refs=yes
138 local grim_var=$2
139 local position_var=$3
140 fi
141
142 # prepend a / so things like "able" dont match
143 # /var/lib/sorcery/codex/stable
144 [[ "${cfg_lookup:0:1}" == "/" ]] || cfg_lookup="/$cfg_lookup"
145
146 local cfg_idx
147 let cfg_idx=0
148 for cfg_grimoire in $(codex_get_all_grimoires) $CODEX_ROOT/*; do
149 [[ -d $cfg_grimoire ]] || continue
150 # this will be empty if "$foo" matches the glob "*$bar"
151 match=$(eval echo ${cfg_grimoire%%*$cfg_lookup})
152 # if empty, echo and succeed
153 if [ -z "$match" ] ; then
154 if [ "$use_refs" == yes ] ; then
155 eval "$position_var=\$cfg_idx"
156 eval "$grim_var=\$cfg_grimoire"
157 else
158 echo $cfg_grimoire
159 fi
160 return 0
161 fi
162 let cfg_idx++
163 done
164 return 1
165 }
166
167 #---------------------------------------------------------------------
168 ## @param grimoire
169 ## @param [position]
170 ## @param [overwrite]
171 ##
172 ## Adds the specified grimoire to the list of grimoires. If no
173 ## position is given, the grimoire is added to the end of the list.
174 ## Position is 0 based. Adding a grimoire to position 0 places it as
175 ## the first grimoire in the list, and moves all other grimoires down
176 ## one spot, unless [<overwrite>] is set to "overwrite".
177 ##
178 ## This function does not currently delete duplicate entries.
179 ##
180 #---------------------------------------------------------------------
181 function codex_add_grimoire() {
182 local NEW_GRIMOIRE=$1
183 local POSITION=$2
184 local OVERWRITE=$3
185
186 codex_is_canonicalized $NEW_GRIMOIRE || return 1
187
188 local GRIMOIRES=`codex_get_all_grimoires`
189
190 local CURRENT_GRIMOIRE
191 local GRIMOIRE_COUNT=0
192
193 if [ -z "$POSITION" ]; then
194 # print everything, then print the new grimoire
195 for CURRENT_GRIMOIRE in $GRIMOIRES; do
196 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$CURRENT_GRIMOIRE
197 let GRIMOIRE_COUNT++
198 done
199 # decrement to overwrite
200 if [ "$OVERWRITE" == "overwrite" ]; then
201 let GRIMOIRE_COUNT--
202 fi
203 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$NEW_GRIMOIRE
204 PAST_END=false
205 # increment so the loop at end gets all the grimoires
206 let GRIMOIRE_COUNT++
207 else
208 local PAST_END=true
209 if [ "$OVERWRITE" == "overwrite" ] ; then
210 # print everything, and overwrite at the right position
211 for CURRENT_GRIMOIRE in $GRIMOIRES; do
212 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$CURRENT_GRIMOIRE
213 if [ $POSITION -eq $GRIMOIRE_COUNT ] ; then
214 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$NEW_GRIMOIRE
215 PAST_END=false
216 fi
217 let GRIMOIRE_COUNT++
218 done
219 else
220 for CURRENT_GRIMOIRE in $GRIMOIRES; do
221 if [ $POSITION -eq $GRIMOIRE_COUNT ] ; then
222 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$NEW_GRIMOIRE
223 PAST_END=false
224 let GRIMOIRE_COUNT++
225 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$CURRENT_GRIMOIRE
226 else
227 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$CURRENT_GRIMOIRE
228 fi
229 let GRIMOIRE_COUNT++
230 done
231 fi
232 # if the range is beyond the total number of grimoires add it now
233 if [ "$PAST_END" == "true" ] ; then
234 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$NEW_GRIMOIRE
235 let GRIMOIRE_COUNT++
236 fi
237 fi
238
239
240 local i
241 touch $GRIMOIRE_LIST
242 lock_start_transaction "$GRIMOIRE_LIST" tGRIMOIRE_LIST
243 rm $tGRIMOIRE_LIST
244 for ((i=0; i<$GRIMOIRE_COUNT;i++)); do
245 echo GRIMOIRE_DIR[$i]=${GRIMOIRE_DIR[$i]} >> $tGRIMOIRE_LIST
246 done
247 lock_commit_transaction $GRIMOIRE_LIST
248
249 }
250
251
252 #---------------------------------------------------------------------
253 ## @param grimoire
254 ##
255 ## Removes the specified grimoire from the list of grimoires.
256 ##
257 #---------------------------------------------------------------------
258 function codex_remove_grimoire() {
259 local GRIMOIRE_TO_DELETE="$1"
260
261 codex_is_canonicalized $GRIMOIRE_TO_DELETE || return 1
262
263 local GRIMOIRES=`codex_get_all_grimoires`
264
265 lock_start_transaction "$GRIMOIRE_LIST" tGRIMOIRE_LIST
266 touch $GRIMOIRE_LIST
267 cp $GRIMOIRE_LIST $GRIMOIRE_LIST_BACKUP
268 rm -f $tGRIMOIRE_LIST
269 touch $tGRIMOIRE_LIST
270
271 local CURRENT_GRIMOIRE
272 local GRIMOIRE_COUNT=0
273 for CURRENT_GRIMOIRE in $GRIMOIRES ; do
274 if [ "$CURRENT_GRIMOIRE" != "$GRIMOIRE_TO_DELETE" ]; then
275 echo GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$CURRENT_GRIMOIRE >> $tGRIMOIRE_LIST
276 fi
277 let GRIMOIRE_COUNT++
278 done
279
280 lock_commit_transaction $GRIMOIRE_LIST
281 unset GRIMOIRE_DIR
282 . $GRIMOIRE_LIST
283 }
284
285 #---------------------------------------------------------------------
286 ## Removes duplicate entries from the GRIMOIRE_LIST. This parses from
287 ## 0 on up, and leaves only the first instance of a grimoire found.
288 ## All others are removed.
289 ## Then reloads the list
290 ##
291 #---------------------------------------------------------------------
292 function codex_remove_duplicates() {
293
294 local GRIMOIRES=`codex_get_all_grimoires`
295 local CURRENT_GRIMOIRE=0
296 local GRIMOIRE_COUNT=0
297 local SEEN_GRIMOIRES=""
298 local ALREADY_SEEN=""
299
300
301 touch $GRIMOIRE_LIST
302 lock_start_transaction "$GRIMOIRE_LIST" tGRIMOIRE_LIST
303 rm -f $tGRIMOIRE_LIST
304
305
306 for CURRENT_GRIMOIRE in $GRIMOIRES; do
307 ALREADY_SEEN=""
308 real_list_find "$SEEN_GRIMOIRES" "$CURRENT_GRIMOIRE" && ALREADY_SEEN="yes"
309
310 if [[ $ALREADY_SEEN ]]; then
311 SEEN_GRIMOIRES="$SEEN_GRIMOIRES $CURRENT_GRIMOIRE"
312 echo "GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$CURRENT_GRIMOIRE" >> $tGRIMOIRE_LIST
313 let GRIMOIRE_COUNT++
314 fi
315
316 done
317
318 lock_commit_transaction $GRIMOIRE_LIST
319
320 unset GRIMOIRE_DIR
321 . $GRIMOIRE_LIST
322
323 }
324
325 #---------------------------------------------------------------------
326 ## @param grimoire name | grimoire dir ....
327 ##
328 ## Unsets the list of grimoires that existed before the call, then
329 ## sets the lists of grimoires to be equal to the list of grimoires
330 ## in the argument list. Grimoire names need not be canonicalized
331 ##
332 #---------------------------------------------------------------------
333 function codex_set_grimoires() {
334
335 local NEW_GRIMOIRE
336 local GRIMOIRE_COUNT=0
337 for NEW_GRIMOIRE in "$@"; do
338 codex_canonicalize_grimoire_name $NEW_GRIMOIRE lookup NEW_GRIMOIRE &&
339 test -d $NEW_GRIMOIRE ||
340 { message "WARNING $NEW_GRIMOIRE does not exist!! skipping..."
341 continue
342 }
343 NEW_GRIMOIRE_DIR[$GRIMOIRE_COUNT]=$NEW_GRIMOIRE
344 let GRIMOIRE_COUNT++
345 done
346 unset GRIMOIRE_DIR
347 let GRIMOIRE_COUNT--
348 for ((; $GRIMOIRE_COUNT>=0;GRIMOIRE_COUNT--)) ; do
349 GRIMOIRE_DIR[$GRIMOIRE_COUNT]=${NEW_GRIMOIRE_DIR[$GRIMOIRE_COUNT]}
350 done
351 }
352
353
354 #---------------------------------------------------------------------
355 ##
356 ## @Stdout all grimoires in the codex.
357 ##
358 #---------------------------------------------------------------------
359 function codex_get_all_grimoires() {
360 debug "libcodex" "codex_get_all_grimoires()"
361 echo "${GRIMOIRE_DIR[*]}" | tr '[:blank:]' '\n'
362 return $?
363 }
364
365 #---------------------------------------------------------------------
366 ## @param grimoire-name
367 ##
368 ## returns true if the grimoire is set local, false otherwise.
369 #---------------------------------------------------------------------
370 function codex_is_local() {(
371 local g_name=$1 idx
372
373 codex_find_grimoire $g_name grimoire idx
374 if ! [[ $grimoire ]]; then
375 return 1
376 fi
377
378 . "$grimoire/GRIMOIRE"
379
380 [[ $CODEX_IS_LOCAL == "yes" ]]
381 )}
382
383 #####################SECTION FUNCTIONS###############################
384
385
386 #---------------------------------------------------------------------
387 ## @param section
388 ## @param variable to set (optional)
389 ## @return 0 if section is found
390 ## @return 1 if section is not found
391 ##
392 ## @Stdout full path to the section
393 ## Given a valid section name, this function lists the full path to
394 ## the section. If an invalid section name is provided, nothing is
395 ## listed.
396 ##
397 #---------------------------------------------------------------------
398 function codex_find_section_by_name() {
399 local SECTION_NAME="$1"
400 local GRIMOIRE=''
401
402 for GRIMOIRE in `codex_get_all_grimoires`; do
403 if [ -d "$GRIMOIRE/$SECTION_NAME" ] ; then
404 debug "libcodex" "codex_find_section_by_name() - found section $GRIMOIRE/$SECTION_NAME"
405 if [[ -z $2 ]]; then
406 echo "$GRIMOIRE/$SECTION_NAME"
407 else
408 eval "$2=\"\$GRIMOIRE/\$SECTION_NAME\""
409 fi
410 return 0
411 fi
412 done
413 return 1
414 }
415
416
417 #---------------------------------------------------------------------
418 ##
419 ## @Stdout all section names from all grimoires.
420 ##
421 #---------------------------------------------------------------------
422 function codex_get_all_section_names() {
423 codex_get_all_sections | get_basenames
424 }
425
426
427 #---------------------------------------------------------------------
428 ## @param grimoire-pathes (optional)
429 ##
430 ## @Stdout all sections from all grimoires or only from the specified grimoires.
431 ##
432 #---------------------------------------------------------------------
433 function codex_get_all_sections() {
434 if [[ $# -gt 0 ]]; then
435 codex_get_sections $@
436 else
437 codex_get_sections `codex_get_all_grimoires`
438 fi
439 }
440
441 #---------------------------------------------------------------------
442 ## @param grimoire
443 ##
444 ## @Stdout Lists all section names in the specified grimoire.
445 ## Relies on a wider-scope function <@function codex_get_sections>.
446 ##
447 #---------------------------------------------------------------------
448 function codex_get_section_names() {
449 codex_is_canonicalized $1 || return 1
450 codex_get_sections "$1" | get_basenames
451 }
452
453 #---------------------------------------------------------------------
454 ## @param canonicalized grimoire names
455 ##
456 ## @Stdout Lists all sections in the specified grimoire directories.
457 ##
458 #---------------------------------------------------------------------
459 function codex_get_sections() {
460 debug "libcodex" "codex_get_sections() - $@"
461 local GRIMOIRE
462
463 while [ $# -gt 0 ] ; do
464 # sanity check
465 codex_is_canonicalized $1 || return 1
466
467 # ensure there is a cache
468 codex_check_cache $1
469 GRIMOIRE="$1"
470
471 # comes in the format
472 # spellname /path/to/section
473 cut -d' ' -f2 "$GRIMOIRE/$SPELL_INDEX_FILE" | sort -u
474 shift
475 done
476 }
477
478
479 ###########################SPELL FUNCTIONS############################
480
481 #---------------------------------------------------------------------
482 ## @param full directory
483 ##
484 ## @return 0 if the specified directory is a spell directory.
485 ## @return 1 otherwise
486 ##
487 #---------------------------------------------------------------------
488 function codex_is_directory_a_spell() {
489 [ -x "$1/DETAILS" ]
490 }
491
492
493 #---------------------------------------------------------------------
494 ## @param spell
495 ## @param [spell ...]
496 ##
497 ## @return 0 if all the specified spells exist
498 ## @return 1 othterwise
499 ##
500 #---------------------------------------------------------------------
501 function codex_does_spell_exist() {
502 local i
503 local retValue=0
504 [[ "$#" -lt 1 ]] && return 1
505 for i in "$@" ; do
506 if [[ "$i" == "" ]] ; then
507 message "${PROBLEM_COLOR}Empty string is not a spell!${DEFAULT_COLOR}"
508 retValue=1
509 elif ! [[ $(codex_find_spell_by_name "$i") ]] ; then
510 message "${SPELL_COLOR}$i${DEFAULT_COLOR}${PROBLEM_COLOR} is not a spell!${DEFAULT_COLOR}"
511 retValue=1
512 fi
513 done
514 return $retValue
515 }
516
517
518
519 #---------------------------------------------------------------------
520 ## @param spell name
521 ## @Stdout spell name
522 ## Given a valid spell name, this function lists the full path to the
523 ## spell. If an invalid spell name is provided, nothing is listed.
524 ##
525 #---------------------------------------------------------------------
526 function codex_find_spell_by_name() {
527
528 debug "libcodex" "codex_find_spell_by_name - $*"
529
530 codex_cache_spell_lookup $1 `codex_get_all_grimoires`
531
532 }
533
534 #---------------------------------------------------------------------
535 ## @param path/section
536 ##
537 ## @Stdout spells
538 ## Lists full paths to spells in the specified section.
539 ## Nothing is listed if the section doesn't include any spells.
540 ##
541 #---------------------------------------------------------------------
542 function codex_get_spells_in_section() {
543 debug "libcodex" "codex_get_spells_in_section - $*"
544 codex_is_canonicalized $1 || return 1
545 local section="$(smgl_basename $1)"
546 local index="$(smgl_dirname $1)/$SPELL_INDEX_FILE"
547 if ! test -r $index || ! test -s $index; then
548 message "${PROBLEM_COLOR}${section:-<null>} is not a section directory!${DEFAULT_COLOR}"
549 return 1
550 fi
551 grep "/$section$" < $index | awk '{ printf("%s/%s\n",$2,$1); }'
552
553 }
554
555
556 #---------------------------------------------------------------------
557 ## @param path/section
558 ##
559 ## @Stdout spells
560 ## Lists all spell names in the specified section. Nothing is listed
561 ## if the section doesn't include any spells.
562 ##
563 #---------------------------------------------------------------------
564 function codex_get_spell_names() {
565 codex_get_spells_in_section "$1" | get_basenames
566 }
567
568
569 #---------------------------------------------------------------------
570 ## @param grimoire-pathes (optional)
571 ##
572 ## @Stdout spells
573 ## Lists all spells in all grimoires or only from the specified
574 ## grimoires. Nothing is listed if no spells exist in any of grimoires.
575 ##
576 ##
577 ## @NOTE This should be fixed so only the first of duplicate spells
578 ## @NOTE are listed.
579 ##
580 #---------------------------------------------------------------------
581 function codex_get_all_spells() {
582 local section
583 for section in `codex_get_all_sections $@`; do
584 codex_get_spells_in_section $section
585 done
586 }
587
588 #---------------------------------------------------------------------
589 ## @param spell name
590 ##
591 ## @Stdout spell name
592 ## Lists the section of the given spell name. Nothing is listed if
593 ## there are no spells with the given name.
594 ##
595 #---------------------------------------------------------------------
596 function codex_get_spell_section() {
597 codex_find_spell_by_name "$1" | get_dirnames
598 }
599
600
601 #---------------------------------------------------------------------
602 ## @param spell name
603 ##
604 ## @Stdout section name
605 ##
606 ## Given a spell name, this function lists the section name. If there
607 ## are no spells with the given name, nothing is listed.
608 ##
609 #---------------------------------------------------------------------
610 function codex_get_spell_section_name() {
611 codex_find_spell_by_name "$1" | get_dirnames | get_basenames
612 }
613
614
615
616 #---------------------------------------------------------------------
617 ##
618 ## @Globals GRIMOIRE SECTION SECTION_DIRECTORY SPELL SPELL_DIRECTORY SCRIPT_DIRECTORY SPELL_DESCRIPTION VERSION SHORT UPDATED SOURCE WEB_SITE ENTERED MAINTAINER MD5 LICENSE
619 ## Unets all these global variables.
620 ##
621 #---------------------------------------------------------------------
622 function codex_clear_current_spell() {
623 unset GRIMOIRE SECTION SECTION_DIRECTORY SPELL \
624 SPELL_DIRECTORY SCRIPT_DIRECTORY SPELL_DESCRIPTION \
625 VERSION SHORT UPDATED SOURCE WEB_SITE ENTERED MAINTAINER \
626 MD5 LICENSE BUILD_API SECURITY_PATCH PATCHLEVEL
627 }
628
629 #---------------------------------------------------------------------
630 ## @param spell directory
631 ## @Globals All vars set in a spell
632 ## Sets the GRIMOIRE, SECTION, SECTION_DIRECTORY, SPELL_DIRECTORY,
633 ## SCRIPT_DIRECTORY global variables for the
634 ## given spell directory.
635 ##
636 ## Assumes the directory passed in is a valid spell directory.
637 ##
638 #---------------------------------------------------------------------
639 function codex_set_current_spell() {
640
641 debug "libcodex" "runing codex_set_current_spell"
642
643 codex_clear_current_spell
644
645 codex_get_spell_paths $1
646
647 if [ -f $SPELL_CONFIG ]; then
648 . $SPELL_CONFIG > /dev/null 2> /dev/null
649 fi
650
651 debug "libcodex" "looking around for API_VERSION"
652 [[ -x $GRIMOIRE/API_VERSION ]] && . $GRIMOIRE/API_VERSION
653 [[ -x $SECTION_DIRECTORY/API_VERSION ]] && . $SECTION_DIRECTORY/API_VERSION
654
655 # load compatibility functions needed for any stage of cast
656 load_libcompat
657
658 debug "libcodex" "sourcing DETAILS"
659 persistent_load
660 . $SPELL_DIRECTORY/DETAILS 1>/dev/null 2>&1
661 persistent_clear
662
663 STAGE_DIRECTORY=$BUILD_DIRECTORY/stage-$SPELL-$VERSION
664
665 # set a default build api if there isn't one already
666 # this isn't strictly necessary as other code should be able to handle the
667 # lack of this variable, but I want to play it safe.
668 [[ -z $BUILD_API ]] && BUILD_API=2
669 true
670 }
671
672 #---------------------------------------------------------------------
673 ## Load just the very basics for a spell, skip build api, libcompat
674 ## and other debug stuff. Intended for use in tight loops.
675 #---------------------------------------------------------------------
676 function codex_set_current_spell_quick() {
677 codex_get_spell_paths $1
678
679 test -f "$SPELL_CONFIG" && . "$SPELL_CONFIG" &> /dev/null
680 persistent_load
681 . $1/DETAILS &> /dev/null
682 persistent_clear
683 true
684 }
685
686
687 #---------------------------------------------------------------------
688 ## Setup the various spell paths associated with a spell without
689 ## loading it.
690 #---------------------------------------------------------------------
691 function codex_get_spell_paths() {
692 SPELL_DIRECTORY=$1
693 SCRIPT_DIRECTORY=$1
694 if test -e $SPELL_DIRECTORY/SCRIBBLED ; then
695 local tmp
696 smgl_dirname "$SPELL_DIRECTORY" tmp
697 smgl_basename "$tmp" SECTION
698 smgl_dirname "$tmp" tmp
699 smgl_basename "$tmp" GRIMOIRE_NAME
700
701 SECTION_DIRECTORY=${SPELL_DIRECTORY}/section
702 GRIMOIRE=${SPELL_DIRECTORY}/grimoire
703 else
704 smgl_dirname "$SPELL_DIRECTORY" SECTION_DIRECTORY
705 smgl_basename "$SECTION_DIRECTORY" SECTION
706 smgl_dirname "$SECTION_DIRECTORY" GRIMOIRE
707 smgl_basename "$GRIMOIRE" GRIMOIRE_NAME
708 fi
709 smgl_basename "$SPELL_DIRECTORY" SPELL
710 SPELL_CONFIG="$DEPENDS_CONFIG/$SPELL"
711 return 0
712 }
713
714 #---------------------------------------------------------------------
715 ## @param spell name
716 ## Sets the GRIMOIRE, SECTION, SECTION_DIRECTORY, SPELL_DIRECTORY,
717 ## SCRIPT_DIRECTORY global variables for the given spell name.
718 ##
719 ## @return 1 if the given name is not a spell.
720 ##
721 #---------------------------------------------------------------------
722 function codex_set_current_spell_by_name() {
723 debug "libcodex" "codex_set_current_spell_by_name -- $1"
724 local SPELL_NAME=`codex_find_spell_by_name "$1"`
725 debug "libcodex" $SPELL_NAME
726
727 [ -n "$SPELL_NAME" ] && codex_set_current_spell $SPELL_NAME
728 }
729
730 #---------------------------------------------------------------------
731 ## @param spell name
732 ## Returns the features a spell is a provider off.
733 ## Example, firefox: GECKO, GRAPHICAL-WEB-BROWSER, WEB-BROWSER,
734 ## NS-PLUGIN-COMPATIBLE
735 ##
736 #---------------------------------------------------------------------
737 function codex_find_spell_provides() {
738 local spell="$1"
739 local feature grimoire
740 local features=$(
741 for grimoire in $(codex_get_all_grimoires); do
742 gawk '/\/'$spell'$/ { print $1 }' \
743 "$grimoire/$PROVIDE_INDEX_FILE"
744 done | sort -u)
745
746 # filter out providers we dont want, so far this is:
747 # a) spells that do not provide something in the first grimoire they are
748 # found in (see note in find_providers)
749 local spell_path=$(codex_find_spell_by_name $spell)
750 smgl_dirname $(smgl_dirname $spell_path) grimoire
751 for feature in $features; do
752 # ensure the first place we look for the spell is a provider
753 grep -q "^$feature $spell_path$" $grimoire/$PROVIDE_INDEX_FILE &&
754 echo $feature
755 done
756 }
757
758 #---------------------------------------------------------------------
759 ## @param category/service
760 ## @Stdout spelllist
761 ##
762 ## First argument is a category of spell. Returns a list of spells
763 ## that match that category. For example,
764 ## C<find_providers email-client> returns evolution,althea,mutt,etc.
765 ##
766 ## This will list spells exactly once, exiled spells are not listed.
767 ## This also takes into account grimoire ordering. A spell must provide
768 ## the category in the first grimoire the spell is seen in (because that
769 ## is the only one that will be cast) otherwise it is not listed.
770 #---------------------------------------------------------------------
771 function find_providers() {
772 local feature="$1"
773 local provider GRIMOIRE spell_path
774 local providers=$(
775 for GRIMOIRE in $(codex_get_all_grimoires); do
776 gawk '/^'"$feature"'[[:blank:]]/ { print $2 }' \
777 "$GRIMOIRE/$PROVIDE_INDEX_FILE"
778 done | get_basenames|sort -u)
779
780 # filter out providers we dont want, so far this is:
781 # a) do not provide something in the first grimoire they are found in
782 # b) are exiled.
783 # ex: foo provides FOOBAR in the "stable" grimoire but not the "test"
784 # grimoire and test is searched before stable in this case cast will
785 # use the spell from test which does NOT provide FOOBAR, therefore
786 # we should not list foo as a provider of FOOBAR
787 for provider in $providers; do
788 if ! spell_exiled $provider; then
789 spell_path=$(codex_find_spell_by_name $provider)
790 smgl_dirname "$(smgl_dirname $spell_path)" GRIMOIRE
791 # ensure the first place we look for the spell is a provider
792 grep -q "^$feature $spell_path$" $GRIMOIRE/$PROVIDE_INDEX_FILE &&
793 echo $provider
794 fi
795 done
796 }
797
798
799 ##############################CACHE FUNCTIONS#########################
800 #---------------------------------------------------------------------
801 ## @param spell name
802 ## @param grimoire-path
803 ## @param [grimoire-path ...]
804 ## @return 0 Spell found
805 ## @return 1 Spell not found
806 ## Searches the indicies of the specified grimories for a spell.
807 ## This will return only the first match found.
808 ##
809 #---------------------------------------------------------------------
810 function codex_cache_spell_lookup() {
811 local SECTION
812 local spell="$1"
813 shift
814 while [ $# -gt 0 ] ; do
815 debug "libcodex" "looking up $spell in ${1}'s cache"
816 codex_check_cache $1
817 SECTION=`grep -m 1 "^$spell " $1/$SPELL_INDEX_FILE | cut -d' ' -f2`
818 [[ $SECTION ]] && echo "$SECTION/$spell" && return
819 shift
820 done
821 return 1
822 }
823
824
825 #---------------------------------------------------------------------
826 ## @param grimoire-path
827 ## @Stdout error if cache doesn't exist after creation
828 ## Checks that the cache exists. if it doesn't exist, make it.
829 ## If it still doesn't exist, the barf an error
830 ##
831 #---------------------------------------------------------------------
832 function codex_check_cache() {
833 codex_is_canonicalized $1 || return 1
834 [[ -x $1 ]] || return 1
835
836 if ! [ -f $1/$SPELL_INDEX_FILE ] || ! [ -f $1/$PROVIDE_INDEX_FILE ]; then
837 codex_create_cache
838 fi
839 if ! [ -f $1/$SPELL_INDEX_FILE ] || ! [ -f $1/$PROVIDE_INDEX_FILE ]; then
840 error_message "${PROBLEM_COLOR}Eeek, $1 is not a grimoire!${DEFAULT_COLOR}"
841 exit 1
842 fi
843 }
844
845 #---------------------------------------------------------------------
846 ## @param [grimoire-path]
847 ## Creates the cache/index for the specified grimoire, or all if none
848 ## is asked for.
849 ##
850 #---------------------------------------------------------------------
851 function codex_create_cache() {
852
853 debug "libcodex" "codex_create_cache - $*"
854 local list="$*"
855 [[ $list ]] || list="${GRIMOIRE_DIR[*]}"
856
857 for i in $list ; do
858 codex_find_in_grimoire $i "DETAILS" | \
859 sed 's@\(.*\)/\([^/]*\)/DETAILS@\2 \1@' | \
860 sort > $i/$SPELL_INDEX_FILE
861
862 codex_list_provides $i > "$i/$PROVIDE_INDEX_FILE"
863 done
864
865 }
866
867
868 #---------------------------------------------------------------------
869 ## Create in-memory spell lookup table for named grimoires.
870 #---------------------------------------------------------------------
871 function codex_create_in_memory_cache() {
872 local list
873 if [[ $1 == -i ]] ; then
874 list=$SPELL_STATUS
875 shift
876 fi
877 local hash=$1
878 shift
879 eval $(
880 for each in "$@"; do
881 cat $each/$SPELL_INDEX_FILE
882 done | awk -v i=$list -v hash=$hash '{
883 if ( ! ($1 in map)) {
884 map[$1]=$2;
885 }
886 } END {
887 if (i) {
888 FS=":";
889 while (getline < i) {
890 if( $3=="installed" || $3=="held") {
891 printf("hash_put %s %s \"%s/%s\";\n",hash,$1,map[$1],$1);
892 }
893 }
894 } else {
895 for (spell in map) {
896 printf("hash_put %s %s \"%s/%s\";\n",hash,spell,map[spell],spell);
897 }
898 }
899 }'
900 )
901
902 }
903
904 #---------------------------------------------------------------------
905 ## Creae in-memory spell lookup table for all known grimoires.
906 #---------------------------------------------------------------------
907 function codex_create_in_memory_cache_all() {
908 codex_create_in_memory_cache "$@" $(codex_get_all_grimoires)
909 }
910
911 ###########################MISC FUNCTIONS#############################
912
913 #---------------------------------------------------------------------
914 ## @param grimoire-path
915 ## @param file-name
916 ##
917 ## @Stdout file names
918 ## Prints every file matching file-name in grimoire
919 ##
920 #---------------------------------------------------------------------
921 function codex_find_in_grimoire() {
922 find "$1" -follow -maxdepth 3 -mindepth 3 -perm /700 -name "$2"
923 }
924
925 #---------------------------------------------------------------------
926 ## @param grimoire-path
927 ## @Stdout provides spell
928 ## Lists all providers in grimoire in the form of "provides spell"
929 ## for instance: <br>
930 ## shell /home/martin/p4/grimoire/shell-term-fm/sash
931 ##
932 #---------------------------------------------------------------------
933 function codex_list_provides() {
934 grimoire=$1
935
936 for file in $(codex_find_in_grimoire $grimoire "PROVIDES"); do
937 smgl_dirname "$file" spell
938 for provides in $(gawk '{if (/provides/) { print $2 }
939 else { print $1 }}' $file); do
940 echo "$provides $spell"
941 done
942 done | sort
943 }
944
945 #---------------------------------------------------------------------
946 ## @param grimoire-path
947 ## Creates keyword index
948 ##
949 #---------------------------------------------------------------------
950 function codex_create_keyword_cache() { (
951 grimoire=$1
952
953 for file in $(codex_find_in_grimoire "$grimoire" "DETAILS"); do
954 unset SPELL KEYWORDS
955 codex_set_current_spell "${file%DETAILS}"
956 echo "$SPELL $KEYWORDS"
957 done | sort > $grimoire/$KEYWORD_INDEX_FILE
958 ) }
959
960 #---------------------------------------------------------------------
961 ## @param grimoire-path
962 ## Creates the version index, which additionally includes the other
963 ## queuing factors - patchlevels and UPDATED.
964 ##
965 ## Multiversioned spells will a dummy entry. Persistent
966 ## variables are ignored.
967 #---------------------------------------------------------------------
968 function codex_create_version_cache() { (
969 grimoire="$1"
970
971 for file in $(codex_find_in_grimoire "$grimoire" DETAILS); do
972 codex_get_spell_paths ${file%/DETAILS}
973 source "$file" &> /dev/null
974 if [[ $(grep -c "^[[:space:]]*VERSION=" "$file") == 1 ]]; then
975 echo "$SPELL ${VERSION:-0} ${PATCHLEVEL:-0} ${SECURITY_PATCH:-0} ${UPDATED:-0}"
976 else
977 # multiversioned or unusually formatted spell - add a dummy entry
978 echo "$SPELL multiversioned"
979 fi
980 unset SPELL VERSION PATCHLEVEL SECURITY_PATCH UPDATED
981 done | sort > $grimoire/$VERSION_INDEX_FILE
982 ) }
983
984 #---------------------------------------------------------------------
985 ## @param servicename
986 ## @return 0 if service exists
987 ## @return 1 otherwise
988 ## checks if servicename exists.
989 #---------------------------------------------------------------------
990 function codex_does_service_exist()
991 {
992 local SERVICE="$@"
993 for GRIMOIRE in $(codex_get_all_grimoires); do
994 grep -qE '^'$SERVICE' ' "$GRIMOIRE/$PROVIDE_INDEX_FILE" && return 0
995 done
996 }
997
998
999 #---------------------------------------------------------------------
1000 ## @param spell or section name
1001 ## @Globals CODEX_FOUND_SECTION CODEX_FOUND_SPELL
1002 ## @return 0 if the passed argument is a spell name or a section name.
1003 ## @return 1 otherwise
1004 ## CODEX_FOUND_SECTION is set if section was found
1005 ## CODEX_FOUND_SPELL is set if a spell was found
1006 ##
1007 #---------------------------------------------------------------------
1008 function codex_find_spell_or_section_by_name() {
1009 local SPELL_OR_SECTION="$1"
1010
1011 CODEX_FOUND_SECTION=""
1012 CODEX_FOUND_SPELL=""
1013
1014 codex_find_section_by_name $SPELL_OR_SECTION CODEX_FOUND_SECTION
1015 [ -n "$CODEX_FOUND_SECTION" ] && return
1016
1017 CODEX_FOUND_SPELL=`codex_find_spell_by_name $SPELL_OR_SECTION`
1018 [ -n "$CODEX_FOUND_SPELL" ] && return
1019
1020 return 1
1021 }
1022
1023 #---------------------------------------------------------------------
1024 ## @param spell directory
1025 ## @Stdout spell description
1026 ## Echos the long description of the given spell. Returns an
1027 ## empty string if the directory is not a valid spell.
1028 ##
1029 #---------------------------------------------------------------------
1030 function codex_get_spell_description() {
1031 local width=$(stty size | cut -d' ' -f2)
1032 codex_is_directory_a_spell "$1" && . "$1/DETAILS" | fmt -w $width -s
1033 }
1034
1035 #---------------------------------------------------------------------
1036 ##
1037 ## @License
1038 ## This software is free software; you can redistribute it and/or modify
1039 ## it under the terms of the GNU General Public License as published by
1040 ## the Free Software Foundation; either version 2 of the License, or
1041 ## (at your option) any later version.
1042 ##
1043 ## This software is distributed in the hope that it will be useful,
1044 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
1045 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1046 ## GNU General Public License for more details.
1047 ##
1048 ## You should have received a copy of the GNU General Public License
1049 ## along with this software; if not, write to the Free Software
1050 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1051 ##
1052 #---------------------------------------------------------------------