/usr/sbin/scribe
1 #!/bin/bash
2 #---------------------------------------------------------------------
3 ##
4 ## @scribe
5 ##
6 ## @Synopsis scribe handles adding/updating/reindexing/etc. of grimoires
7 ##
8 ## @Copyright Original version Copywright 2002 by Ryan Abrams
9 ## @Copyright Additions/Corrections Copyright 2002-2004 by the Source Mage Team
10 ## @Copyright Released under the GPL
11 #---------------------------------------------------------------------
12
13
14 #---------------------------------------------------------------------
15 ## help">help">help
16 ##
17 ## print horribly unhelpful helpscreen
18 ##
19 #---------------------------------------------------------------------
20 function help">help">help() {
21 cat << EOF
22
23 Scribe is a utility for controlling the grimoires in your codex,
24 and the spells in your grimoires.
25
26 Invoke scribe with the desired command followed by the target.
27 Note that most options can be called with the beginning of the command.
28
29 Command Arguments Description
30 add grimoire [from source] Adds a new grimoire
31 (optionally from a different URL)
32 remove grimoire Removes a grimoire
33 update [grimoire] Updates a grimoire or all grimoires
34
35 fix grimoire Attempts to fix metadata for grimoire
36 reindex [grimoire] Recreates the list of spells
37 reindex-keyword [grimoire] Recreates keyword listing
38 (official grimoires should come with
39 a keyword listing already)
40 reindex-version [grimoire] Recreates the version listing
41
42 index Prints list of grimoires
43
44 set grim1 grim2 puts grim1 before grim2
45 swap grim1 grim2 Swaps two grimoires
46
47 localize grimoire Makes a grimoire local
48 (so scribe won't try to update it)
49 unlocalize grimoire Makes a grimoire nonlocal
50
51
52 Grimoire tarballs are located at $CODEX_TARBALL_URL
53 Grimoire rsync modules are located at $CODEX_RSYNC_URL
54
55 EOF
56
57 exit 1
58 }
59
60
61 #---------------------------------------------------------------------
62 ## Common error messag when downloading a grimoire fails.
63 #---------------------------------------------------------------------
64 function scribe_download_fail_error_msg() {
65 error_message "${PROBLEM_COLOR}Error downloading grimoire..."
66 error_message "${MESSAGE_COLOR}Grimoire tarballs are located at:" \
67 "${FILE_COLOR}$CODEX_TARBALL_URL${DEFAULT_COLOR}"
68 error_message "${MESSAGE_COLOR}Grimoire rsync modules are located at:" \
69 "${FILE_COLOR}$CODEX_RSYNC_URL${DEFAULT_COLOR}"
70 }
71
72 #---------------------------------------------------------------------
73 ## Unpackage a grimoire tarball and make sure it worked
74 #---------------------------------------------------------------------
75 function unpackage_grimoire_tarball() {
76 local tarball=$1
77 local grimoire=$2
78 local grim_name=$3
79 #untar the new grimoire tarball
80 if tar -xjf $tarball 1>/dev/null 2>&1; then
81 # ensure the grimoire unpacked where it was expected to
82 if ! [ -d $grimoire ]; then
83 error_message "${PROBLEM_COLOR}ERROR: Grimoire tarball for" \
84 "${SPELL_COLOR}$grim_name ${PROBLEM_COLOR}" \
85 "not formatted correctly!${DEFAULT_COLOR}"
86 return 1
87 fi
88 return 0
89 else
90 error_message "${PROBLEM_COLOR}ERROR: Grimoire tarball for" \
91 "${SPELL_COLOR}$grim_name ${PROBLEM_COLOR}" \
92 "did not unpack properly!${DEFAULT_COLOR}"
93 return 1
94 fi
95 }
96
97 #---------------------------------------------------------------------
98 ## Given an rsync url, make sure it has a / on the end of it
99 ## so downloading works.
100 #---------------------------------------------------------------------
101 function sanitize_rsync_url() {
102 # add a / to the end, if one isnt there, if the user types
103 # rsync://sourcemage.org::codex/games instead of
104 # rsync://sourcemage.org::codex/games/ strange things happen
105 if list_find "rsync" $prefix ; then
106 echo $from|sed 's!\([^/]\)$!\1/!'
107 else
108 echo $from
109 fi
110 }
111
112 #---------------------------------------------------------------------
113 ## Validate a grimoire tree using a manifest
114 #---------------------------------------------------------------------
115 function scribe_validate_tree_common() {
116 local scribe_target=$1
117 local grim_name=$2
118 local grimoire=$3
119 if ! test -d "$scribe_target"; then
120 error_message "${PROBLEM_COLOR}Downloaded a tree but directory doesn't exist!" \
121 "File a bug if you see this.${DEFAULT_COLOR}"
122 return 1
123 fi
124 if [[ "$scribe_target" != "$grim_name" ]] ; then
125 mv -f "$scribe_target" "$grim_name"
126 fi
127
128 verify_grimoire_tree "$grim_name" "$grimoire"
129 local rc=$?
130 if [[ $rc != 0 ]] && [[ $rc != 253 ]] ; then
131 pushd $grim_dir >/dev/null
132 grimoire_tree_user_query "$grim_name" || return 1
133 popd >/dev/null
134 fi
135 }
136
137
138 #---------------------------------------------------------------------
139 ## scribe_add
140 ##
141 ## add grimoires to codex, unless they already exist
142 ## usage:
143 ## scribe_add grimoire [ from location] [grimoire [ from location]] ...
144 ##
145 #---------------------------------------------------------------------
146 function scribe_add() {
147 $STD_DEBUG
148 #For each item listed add it
149 if ! [ -d $CODEX_ROOT ] ; then
150 message "${MESSAGE_COLOR}Main codex directory not present." \
151 "Creating ${FILE_COLOR}$CODEX_ROOT${MESSAGE_COLOR}.${DEFAULT_COLOR}"
152 mkdir -p $CODEX_ROOT
153 fi
154
155 local grimoire from
156 while [ -n "$1" ] ; do
157 grimoire="$1"
158 if [ "$2" == "from" ] ; then
159 from=$3
160 shift 3
161 else
162 from=""
163 shift 1
164 fi
165
166 if codex_find_grimoire $grimoire >/dev/null; then
167 error_message "${PROBLEM_COLOR}There already exists a grimoire with" \
168 "the name ${SPELL_COLOR}$grimoire${PROBLEM_COLOR}!" \
169 "Refusing to add.${DEFAULT_COLOR}"
170 continue
171 fi
172
173 # avoid deleting $grimoire if it is a dir #13742
174 if [[ -d $grimoire ]]; then
175 error_message "${PROBLEM_COLOR}The grimoire ${FILE_COLOR}$grimoire" \
176 "${PROBLEM_COLOR} is an existing directory!" \
177 "Refusing to add!${DEFAULT_COLOR}"
178 continue
179 fi
180
181 local grim_name="$grimoire"
182 # derive a full grimoire name
183 grimoire=$(codex_canonicalize_grimoire_name $grimoire)
184 local grim_dir
185 smgl_dirname "$grimoire" grim_dir
186
187 if [[ -z $from ]]; then
188 message "${MESSAGE_COLOR}Adding grimoire ${SPELL_COLOR}$grim_name" \
189 "${MESSAGE_COLOR}to ${FILE_COLOR}$grim_dir${DEFAULT_COLOR}"
190 else
191 message "${MESSAGE_COLOR}Adding grimoire ${SPELL_COLOR}$grim_name" \
192 "${MESSAGE_COLOR}to ${FILE_COLOR}$grim_dir ${MESSAGE_COLOR}from" \
193 "${FILE_COLOR}$from${DEFAULT_COLOR}"
194 fi
195 scribe_add_update_worker "$grimoire" "$from" add
196 done
197 }
198
199 #---------------------------------------------------------------------
200 ## scribe_add_worker
201 ##
202 ## downloads a grimoire, unpacks it and adds it to the codex listing
203 ## if location is not given the default is used
204 ##
205 ## @param grimoire
206 ## @param location to download from (optional), if empty use $CODEX_URL
207 ##
208 #---------------------------------------------------------------------
209 function scribe_add_update_worker() {
210 $STD_DEBUG
211 local grimoire=$1
212 local from=$2
213 local add_or_update=$3
214
215 if [ -z $grimoire ] ; then
216 error_message "${PROBLEM_COLOR}Empty grimoire name! Please" \
217 "contact the sorcery team if you see this.${DEFAULT_COLOR}"
218 return 1
219 fi
220
221 if [[ $add_or_update == update ]] ; then
222 if ! test -d $grimoire ; then
223 error_message "${FILE_COLOR}$grimoire ${PROBLEM_COLOR}is not a directory!" \
224 "Refusing to update!${DEFAULT_COLOR}"
225 return 1
226 fi
227 fi
228
229 local grim_dir grim_name grim_target
230 smgl_dirname "$grimoire" grim_dir
231 smgl_basename "$grimoire" grim_name
232 pushd $grim_dir &> /dev/null
233
234 # get the url, if one was specified sanity check it
235 if [ -n "$from" ]; then
236 if ! url_is_valid "$from"; then
237 #if not valid, use default
238 error_message "${PROBLEM_COLOR}Error: ${FILE_COLOR}$from" \
239 "${PROBLEM_COLOR}is not a recognized url." \
240 "Using the default.${DEFAULT_COLOR}"
241 from=""
242 else
243 smgl_basename "$from" grim_target
244 fi
245 fi
246
247 local prefix
248 if [ -z "$from" ]; then
249 #from is empty - use the default
250 prefix=$(url_get_prefix $CODEX_URL)
251 if [[ $? != 0 ]]; then
252 error_message "${PROBLEM_COLOR}Failed to get the \$CODEX_URL prefix!" \
253 "${DEFAULT_COLOR}"
254 popd &>/dev/null
255 return 1
256 fi
257
258 local tree_prefixes="rsync svn svn_http svn_https svn_ssh cvs smgl_tla"
259 tree_prefixes="$tree_prefixes dir git git_http hg_http bzr"
260 if list_find "$tree_prefixes" "$prefix"; then
261 grim_target=$grim_name
262 else
263 grim_target="$grim_name.tar.bz2"
264 fi
265 from="$CODEX_URL/$grim_target"
266 fi
267
268 local prefix=$(url_get_prefix $from)
269 from=$(sanitize_rsync_url $prefix $from)
270
271
272 # do some cleanup before downloading
273 if [[ $add_or_update == add ]] ; then
274 if test -d $grimoire ; then
275 message "${MESSAGE_COLOR}Found an old grimoire directory," \
276 "removing it...${DEFAULT_COLOR}"
277 rm -rf $grimoire
278 fi
279 fi
280 test -f $grim_target && rm -f $grim_target
281
282 # download it
283 local scribe_target scribe_type
284 url_download "$grim_target" "$from" "" scribe_target scribe_type
285
286 #check the success of the download
287 if [ $? != 0 ]; then
288 scribe_download_fail_error_msg
289 popd &>/dev/null
290 return 1
291 fi
292
293 # do result specific actions
294 local rc
295 if [[ "$scribe_type" == file ]] ; then
296
297 gpg_verify_grimoire $PWD/$scribe_target $(smgl_dirname $from)
298 rc=$?
299 gpg_user_query $rc $(smgl_basename $from) grimoire || return 1
300
301 [[ $add_or_update == update ]] && mv $grim_name temp_$grim_name.old
302
303 if unpackage_grimoire_tarball "$scribe_target" "$grimoire" "$grim_name"
304 then
305 rm $scribe_target
306 if [[ $add_or_update == update ]] && [ -d temp_$grim_name.old ]; then
307 rm -rf temp_$grim_name.old
308 fi
309 else
310 # restore from backup
311 [[ $add_or_update == update ]] && mv -f temp_$grim_name.old $grim_name
312 popd &>/dev/null; return 1
313 fi
314 elif [[ "$scribe_type" == tree ]]; then
315 if ! scribe_validate_tree_common "$scribe_target" "$grim_name" "$grimoire"
316 then
317 popd &>/dev/null; return 1
318 fi
319 else
320 error_message "${PROBLEM_COLOR}Unknown download type" \
321 "${FILE_COLOR}$scribe_type ${PROBLEM_COLOR}," \
322 "file a bug if you see this.${DEFAULT_COLOR}"
323 return 1
324 fi
325 popd &>/dev/null
326
327 #success! create a GRIMOIRE file that stores where it was downloaded from
328 echo "FROM_URL=$from" > $grimoire/GRIMOIRE &&
329 chmod +x $grimoire/GRIMOIRE &&
330
331 if [[ $add_or_update == add ]] ; then
332 codex_add_grimoire $grimoire 0 &&
333 scribe_reindex $grimoire
334 message "${MESSAGE_COLOR}Grimoire ${FILE_COLOR}\"$grimoire\"" \
335 "${MESSAGE_COLOR}successfully added to your codex.${DEFAULT_COLOR}"
336 else
337 scribe_reindex $grimoire
338 message "${SPELL_COLOR}$grim_name ${MESSAGE_COLOR}updated!${DEFAULT_COLOR}"
339 echo
340 grimoire_history $grimoire
341 fi
342
343 return 0
344 }
345 #---------------------------------------------------------------------
346 ## scribe_fix
347 ##
348 ## frontend to metadata fixing
349 ##
350 ## @param grimoire names, if none all grimoires
351 ##
352 #---------------------------------------------------------------------
353 function scribe_fix() {
354 local grim grimoire grimoires
355 if [[ $@ ]] ; then
356 grimoires=$@
357 else
358 grimoires=`codex_get_all_grimoires`
359 fi
360 for grim in $grimoires; do
361
362 if ! grimoire=$(codex_find_grimoire $grim) ; then
363 error_message "${PROBLEM_COLOR}Grimoire ${SPELL_COLOR}$grim" \
364 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
365 return 1
366 fi
367
368 if ! [ -e $grimoire/GRIMOIRE ]; then
369 message "${MESSAGE_COLOR}No Metadata found for Grimoire" \
370 "${SPELL_COLOR}$grim${DEFAULT_COLOR}"
371 if scribe_fix_metadata $grimoire; then
372 message "${FILE_COLOR}$grimoire ${MESSAGE_COLOR}fixed.${DEFAULT_COLOR}"
373 else
374 error_message "${FILE_COLOR}$grimoire" \
375 "${PROBLEM_COLOR}not fixed!${DEFAULT_COLOR}"
376 fi
377 elif query "Metadata for $grimoire found. Fix anyway?" n; then
378 if scribe_fix_metadata $grimoire 1; then
379 message "${FILE_COLOR}$grimoire ${MESSAGE_COLOR}fixed.${DEFAULT_COLOR}"
380 else
381 error_message "${FILE_COLOR}$grimoire ${PROBLEM_COLOR}not fixed!${DEFAULT_COLOR}"
382 fi
383 else
384 message "${FILE_COLOR}$grimoire ${MESSAGE_COLOR}ignored${DEFAULT_COLOR}"
385 fi
386 done
387 }
388
389 #---------------------------------------------------------------------
390 ## scribe_fix_metadata
391 ##
392 ## fixes the metadata on a grimoire based on user input
393 ##
394 ## @param grimoire name
395 ## @param force, if one fix without prompting the user
396 ##
397 #---------------------------------------------------------------------
398 function scribe_fix_metadata() {
399 local URL grimoire_dir grimoire_name
400
401 if ! grimoire_dir=$(codex_find_grimoire $1) ; then
402 error_message "${PROBLEM_COLOR}Grimoire ${FILE_COLOR}$1 ${PROBLEM_COLOR}" \
403 "not found, this may be a sorcery bug...${DEFAULT_COLOR}"
404 return 1
405 fi
406 smgl_basename "$1" grimoire_name
407
408 if query "Repair Grimoire:$1's Metadata?" n || [ "$2" == "1" ] ; then
409 message "${MESSAGE_COLOR}Enter url to pull grimoire from${DEFAULT_COLOR}"
410 read -p "[ $CODEX_URL/$grimoire_name.tar.bz2 ]: " URL
411 URL=${URL:-$CODEX_URL/$grimoire_name.tar.bz2}
412 message "${MESSAGE_COLOR}Setting Metadata to: ${FILE_COLOR}$URL${DEFAULT_COLOR}"
413 message "${MESSAGE_COLOR}If this is incorrect, run" \
414 "${DEFAULT_COLOR}\"scribe fix $1\" ${MESSAGE_COLOR}and correct${DEFAULT_COLOR}"
415 echo "FROM_URL=$URL" > $grimoire_dir/GRIMOIRE
416 chmod +x $grimoire_dir/GRIMOIRE
417 return 0
418 fi
419 return 1
420 }
421
422 #---------------------------------------------------------------------
423 ## scribe_index
424 ##
425 ## Display installed grimoires
426 ##
427 #---------------------------------------------------------------------
428 function scribe_index() {
429 local idx grimoire grimoire_name
430
431 echo ""
432 echo "Codex Listing"
433 echo "-------------"
434 echo ""
435
436 #for each grimoire
437 let idx=0
438 for grimoire in $(codex_get_all_grimoires); do
439 smgl_basename "$grimoire" grimoire_name
440 echo -n " [$idx] : $grimoire_name : $grimoire"
441 if [[ -f $grimoire/VERSION ]]; then
442 echo " : $(head -c 16 $grimoire/VERSION | head -n 1)"
443 else
444 echo
445 fi
446 let idx+=1
447 done
448 echo ""
449 }
450
451 #---------------------------------------------------------------------
452 ## scribe_localize
453 ##
454 ## Set grimoires "local" so scribe update ignores them
455 ##
456 ## @param Names of grimoires to localize
457 ##
458 #---------------------------------------------------------------------
459 function scribe_localize() {
460 local grimoire path
461 for grimoire in $@; do
462 scribe_localize_sub yes &&
463 message "${MESSAGE_COLOR}Made ${FILE_COLOR}$path" \
464 "${MESSAGE_COLOR}local${DEFAULT_COLOR}"
465 done
466 }
467
468 #---------------------------------------------------------------------
469 ## scribe_localize_sub
470 ##
471 ## Adjust grimoires localization state
472 ##
473 ## @param Names of grimoires to (un)localize
474 ## @param yes/no state of grimoire localization
475 ##
476 #---------------------------------------------------------------------
477 function scribe_localize_sub() {
478 path=$(codex_find_grimoire $grimoire)
479 if [ -z "$path" ]; then
480 error_message "${PROBLEM_COLOR}No such grimoire:" \
481 "${FILE_COLOR}$grimoire${DEFAULT_COLOR}"
482 continue
483 fi
484 touch "$path/GRIMOIRE" &&
485 modify_config "$path/GRIMOIRE" "CODEX_IS_LOCAL" "$1"
486 }
487
488 #---------------------------------------------------------------------
489 ## scribe_reindex
490 ##
491 ## Update the spell index for grimoires
492 ##
493 ## @param grimoire names, if none all grimoires
494 ##
495 #---------------------------------------------------------------------
496 function scribe_reindex() {
497 local paths=""
498 local grimoire grimoires grim
499 if [[ "$@" ]] ; then
500 grimoires="$@"
501 else
502 grimoires=`codex_get_all_grimoires`
503 fi
504
505 for grim in $grimoires; do
506 if ! grimoire=$(codex_find_grimoire $grim) ; then
507 error_message "${PROBLEM_COLOR}Grimoire ${FILE_COLOR}$grim" \
508 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
509 return 1
510 fi
511 paths="$paths $grimoire"
512 done
513 debug "scribe" "reindex: paths = \"$paths\""
514
515 message -n "${MESSAGE_COLOR}Reindexing spell list... ${DEFAULT_COLOR}"
516 codex_create_cache $paths
517 message "${MESSAGE_COLOR}done.${DEFAULT_COLOR}"
518 }
519
520 #---------------------------------------------------------------------
521 ## scribe_reindex_keyword
522 ##
523 ## Recreate the keyword index, this is slow in comparison to
524 ## normal reindexing.
525 ##
526 ## @param grimoire names, if none all grimoires
527 ##
528 #---------------------------------------------------------------------
529 function scribe_reindex_keyword() {
530 local paths=""
531 local grimoire grimoires grim
532 if [[ "$@" ]] ; then
533 grimoires="$@"
534 else
535 grimoires=`codex_get_all_grimoires`
536 fi
537
538 for grim in $grimoires; do
539 if ! grimoire=$(codex_find_grimoire $grim) ; then
540 error_message "${PROBLEM_COLOR}Grimoire ${FILE_COLOR}$grim" \
541 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
542 return 1
543 fi
544 message -n "${MESSAGE_COLOR}Reindexing keywords for" \
545 "${FILE_COLOR}$grim ${MESSAGE_COLOR}... ${DEFAULT_COLOR}"
546 codex_create_keyword_cache "$grimoire"
547 message "${MESSAGE_COLOR}done.${DEFAULT_COLOR}"
548 done
549 }
550
551 #---------------------------------------------------------------------
552 ## scribe_reindex_version
553 ##
554 ## Recreate the version index
555 ##
556 ## @param grimoire names, if none all grimoires
557 ##
558 ## TODO: merge scribe_reindex_* functions?
559 #---------------------------------------------------------------------
560 function scribe_reindex_version() {
561 local paths=""
562 local grimoire grimoires grim
563 if [[ $@ ]] ; then
564 grimoires="$@"
565 else
566 grimoires=$(codex_get_all_grimoires)
567 fi
568
569 for grim in $grimoires; do
570 if ! grimoire=$(codex_find_grimoire $grim) ; then
571 error_message "${PROBLEM_COLOR}Grimoire ${FILE_COLOR}$grim" \
572 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
573 return 1
574 fi
575 message -n "${MESSAGE_COLOR}Reindexing versions for" \
576 "${FILE_COLOR}$grim${MESSAGE_COLOR} ... ${DEFAULT_COLOR}"
577 codex_create_version_cache "$grimoire"
578 message "${MESSAGE_COLOR}done.${DEFAULT_COLOR}"
579 done
580
581 }
582 #---------------------------------------------------------------------
583 ## scribe_remove
584 ##
585 ## remove a grimoire from the codex
586 ##
587 ## @param grimoires to remove
588 ##
589 #---------------------------------------------------------------------
590 function scribe_remove() {
591 #remove all listed grimoires
592 local grimoire grim
593 for grim in $@; do
594 # if the grimoire name starts with / they may have given a
595 # full path, the [[ ]] actually doesnt expand /* to $(ls /)
596 if ! grimoire=$(codex_find_grimoire $grim) ; then
597 error_message "${PROBLEM_COLOR}Grimoire ${FILE_COLOR}$grim" \
598 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
599 return 1
600 fi
601
602 message "${MESSAGE_COLOR}Deleting grimoire ${FILE_COLOR}$grimoire" \
603 "${MESSAGE_COLOR}directory${DEFAULT_COLOR}"
604 rm -rf $grimoire &&
605 message "${MESSAGE_COLOR}Removing grimoire ${FILE_COLOR}$grimoire" \
606 "${MESSAGE_COLOR}from codex${DEFAULT_COLOR}" &&
607 codex_remove_grimoire $grimoire ||
608 { error_message "${PROBLEM_COLOR}An error occured trying to remove" \
609 "${FILE_COLOR}$grimoire${PROBLEM_COLOR}," \
610 "I wonder why?${DEFAULT_COLOR}"
611 return 1
612 }
613 done
614 }
615
616 #---------------------------------------------------------------------
617 ## scribe_set
618 ##
619 ## Set grimoire1 before grimoire2, do this by removing grimoire1,
620 ## then finding the position of grimoire2 and then use codex_add_grimoire
621 ## on grimore1 with overwrite off
622 ##
623 ## @param grimoire1
624 ## @param grimoire2
625 ##
626 #---------------------------------------------------------------------
627 function scribe_set(){
628 local grim1=$1 grimoire1
629 local grim2=$2 grimoire2
630 local idx1 idx2
631 if [ $grim1 == $grim2 ] ; then
632 error_message "${SPELL_COLOR}$grim1 ${PROBLEM_COLOR}IS" \
633 "${SPELL_COLOR}$grim2${PROBLEM_COLOR}," \
634 "can't set a grimoire to itself!${DEFAULT_COLOR}"
635 return 1
636 fi
637 if ! codex_find_grimoire $grim1 grimoire1 idx1 ; then
638 error_message "${PROBLEM_COLOR}Grimoire ${SPELL_COLOR}$grim1" \
639 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
640
641 return 1
642 fi
643 if ! codex_find_grimoire $grim2 grimoire2 idx2 ; then
644 error_message "${PROBLEM_COLOR}Grimoire ${SPELL_COLOR}$grim2" \
645 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
646 return 1
647 fi
648 if [ $idx1 -eq $idx2 ] ; then
649 error_message "${PROBLEM_COLOR}This shouldn't happen, but if it" \
650 "does contact the sorcery team.${DEFAULT_COLOR}"
651 return 1
652 elif [ $idx1 -lt $idx2 ] ; then
653 let idx2-- # grim1 is before grim2, by removing grim1, the position
654 # decrease by 1
655 fi
656
657 message "${MESSAGE_COLOR}Setting ${SPELL_COLOR}$grim1" \
658 "${MESSAGE_COLOR}before ${SPELL_COLOR}$grim2${DEFAULT_COLOR}"
659 codex_remove_grimoire $grimoire1
660 codex_add_grimoire $grimoire1 $idx2
661 }
662
663 #---------------------------------------------------------------------
664 ## scribe_swap
665 ##
666 ## switch grimoire1 and grimoire2 in the grimoire ordering
667 ## do this by finding their positions, using the overwrite feature of
668 ## codex_add_grimoire
669 ##
670 ## @param grimoire1
671 ## @param grimoire2
672 ##
673 #---------------------------------------------------------------------
674 function scribe_swap() {
675 local grim1=$1 grimoire1
676 local grim2=$2 grimoire2
677 local idx1 idx2
678 if ! codex_find_grimoire $grim1 grimoire1 idx1 ; then
679 error_message "${PROBLEM_COLOR}Grimoire ${SPELL_COLOR}$grim1" \
680 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
681 return 1
682 fi
683 if ! codex_find_grimoire $grim2 grimoire2 idx2 ; then
684 error_message "${PROBLEM_COLOR}Grimoire ${SPELL_COLOR}$grim2" \
685 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
686 return 1
687 fi
688 message -n "${MESSAGE_COLOR}Swapping "
689 message "${SPELL_COLOR}$grim1 ${MESSAGE_COLOR}with" \
690 "${SPELL_COLOR}$grim2 ${DEFAULT_COLOR}"
691 codex_add_grimoire $grimoire1 $idx2 overwrite
692 codex_add_grimoire $grimoire2 $idx1 overwrite
693 }
694
695 #---------------------------------------------------------------------
696 ## scribe_update
697 ##
698 ## updates all installed grimoires, or just those passed in as params
699 ##
700 ## @param grimoire names, if none all grimoires
701 ##
702 #---------------------------------------------------------------------
703 function scribe_update() {
704 local grimoires grimoire grim from rc
705 rc=0
706 if [[ $@ ]] ; then
707 while [ -n "$1" ] ; do
708 grim="$1"
709 if ! grimoire=$(codex_find_grimoire $grim) ; then
710 error_message "${PROBLEM_COLOR}Grimoire ${SPELL_COLOR}$grim" \
711 "${PROBLEM_COLOR}not found!${DEFAULT_COLOR}"
712 if [[ "$2" == "from" ]] ; then shift 3 ; else shift 1 ; fi
713 let rc++
714 continue
715 fi
716
717 if ! [ -e $grimoire/GRIMOIRE ] && ! scribe_fix_metadata $grim; then
718 error_message "${SPELL_COLOR}$grim ${PROBLEM_COLOR}has invalid metadata." \
719 "Not Updating!${DEFAULT_COLOR}"
720 if [[ "$2" == "from" ]] ; then shift 3 ; else shift 1 ; fi
721 let rc++
722 continue
723 fi
724
725 if codex_is_local $grimoire; then
726 message "${SPELL_COLOR}$grim${MESSAGE_COLOR} is marked" \
727 "as local. Won't update.${DEFAULT_COLOR}"
728 if [[ "$2" == "from" ]] ; then shift 3 ; else shift 1 ; fi
729 continue
730 fi
731
732 . $grimoire/GRIMOIRE
733 # get a url if one exists
734 if [ "$2" == "from" ] ; then
735 from=$3
736 shift 3
737 else
738 from=$FROM_URL
739 shift 1
740 fi
741
742 message "${MESSAGE_COLOR}Updating grimoire ${SPELL_COLOR}$grim${MESSAGE_COLOR}" \
743 "from ${FILE_COLOR}$from${DEFAULT_COLOR}"
744 scribe_add_update_worker "$grimoire" "$from" update ||
745 let rc++
746 done
747 else
748 #for each grimoire
749 for grimoire in $(codex_get_all_grimoires); do
750 smgl_basename "$grimoire" grim
751 if ! [ -e $grimoire/GRIMOIRE ] && ! scribe_fix_metadata $grimoire; then
752 #no metadata found. dont auto-update
753 error_message "${SPELL_COLOR}$grim ${PROBLEM_COLOR}has invalid metadata." \
754 "Not Updating!${DEFAULT_COLOR}"
755 continue
756 fi
757
758 if codex_is_local $grimoire; then
759 error_message "${SPELL_COLOR}$grim${MESSAGE_COLOR} is marked as local. Won't update.${DEFAULT_COLOR}"
760 continue
761 fi
762
763 #include metadata
764 . $grimoire/GRIMOIRE
765 message "${MESSAGE_COLOR}Updating grimoire ${SPELL_COLOR}$grim " \
766 "${MESSAGE_COLOR}from ${FILE_COLOR}$FROM_URL${DEFAULT_COLOR}"
767 scribe_add_update_worker "$grimoire" "$FROM_URL" update ||
768 let rc++
769 done
770 fi
771 tablet_import_repair_files $TABLET_PATH
772 return $rc
773 }
774
775 #---------------------------------------------------------------------
776 ## scribe_localize
777 ##
778 ## Removes a grimoire's "local" state so scribe update will update them
779 ##
780 ## @param Names of grimoires to unlocalize
781 ##
782 #---------------------------------------------------------------------
783 function scribe_unlocalize() {
784 local grimoire path
785 for grimoire in $@; do
786 scribe_localize_sub $grimiore no &&
787 message "${MESSAGE_COLOR}Made ${FILE_COLOR}$path" \
788 "${MESSAGE_COLOR}unlocal${DEFAULT_COLOR}"
789 done
790 }
791
792 #---------------------------------------------------------------------
793 ## find_function
794 ##
795 ## take the command line and figure out what the user wants to do
796 ##
797 ## @param command line args
798 ##
799 #---------------------------------------------------------------------
800 function find_function() {
801 case $1 in
802 a|ad|add) FUNCTION="add" ;;
803 f|fi|fix) FUNCTION="fix" ;;
804 i|in|ind|inde|index) FUNCTION="index";;
805 l|loc|local|localize) FUNCTION="localize";;
806 reindex-keyword) FUNCTION="reindex-keyword";;
807 reindex-version) FUNCTION="reindex-version";;
808 rei|reind|reinde|reindex) FUNCTION="reindex";;
809 rm|rem|remo|remov|remove) FUNCTION="remove" ;;
810 se|set) FUNCTION="set";;
811 sw|swa|swap) FUNCTION="swap";;
812 un|unloc|unlocal|unlocalize) FUNCTION="unlocalize";;
813 u|up|upd|upda|updat|update) FUNCTION="update" ;;
814 *) help">help">help ;;
815 esac
816 }
817
818 #---------------------------------------------------------------------
819 ## main">main">main">main">main
820 ##
821 ## start the ride.
822 #---------------------------------------------------------------------
823 function main">main">main">main">main() {
824 #move to the tmp folder in case we create junk
825 cd /tmp
826
827 #check out what it is we are doing
828 local FUNCTION
829 find_function $*
830 shift 1
831
832 #now that we have a function, do it.
833 case $FUNCTION in
834 add) scribe_add $@ ;;
835 fix) scribe_fix $@ ;;
836 index) scribe_index $@ ;;
837 localize) scribe_localize $@ ;;
838 reindex) scribe_reindex $@ ;;
839 reindex-keyword) scribe_reindex_keyword $@ ;;
840 reindex-version) scribe_reindex_version $@ ;;
841 remove) scribe_remove $@ ;;
842 set) scribe_set $@ ;;
843 swap) scribe_swap $@ ;;
844 unlocalize) scribe_unlocalize $@ ;;
845 update) scribe_update $@ ;;
846 *) help">help">help ;;
847 esac
848 }
849
850 . /etc/sorcery/config
851
852 # validate the parameters before potentially su-ing
853 find_function $*
854
855 #check if root. If not, become root
856 if [ "$UID" == 0 ] ; then
857 if [[ $NICE != "0" ]] ; then
858 renice $NICE -p $$ >/dev/null
859 fi
860 mk_tmp_dirs scribe
861 main">main">main">main">main $@
862 rc=$?
863 cleanup_tmp_dir $TMP_DIR
864 exit $rc
865 elif [[ $1 == -h ]] || [[ $1 == --help ]] ; then
866 help">help">help
867 elif [[ $1 == index ]] ; then
868 scribe_index # this requires no access privaledges so special case it
869 else
870 echo "Enter the root password, please." 1>&2
871 PARAMS=$(consolidate_params "$@")
872 exec su -c "scribe $PARAMS" root
873 fi
874
875 #---------------------------------------------------------------------
876 ##=back
877 ##
878 ##=head1 LICENSE
879 ##
880 ## This software is free software; you can redistribute it and/or modify
881 ## it under the terms of the GNU General Public License as published by
882 ## the Free Software Foundation; either version 2 of the License, or
883 ## (at your option) any later version.
884 ##
885 ## This software is distributed in the hope that it will be useful,
886 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
887 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
888 ## GNU General Public License for more details.
889 ##
890 ## You should have received a copy of the GNU General Public License
891 ## along with this software; if not, write to the Free Software
892 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
893 ##
894 #---------------------------------------------------------------------