/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	#---------------------------------------------------------------------