/var/lib/sorcery/modules/libstate

     1	#!/bin/bash
     2	#---------------------------------------------------------------------
     3	## Handles storage of state information, incluing depends and package
     4	## files. Also handles looking information up about what is installed
     5	## and what depends on what.
     6	##
     7	## @Copyright Copyright (C) 2002 The Source Mage Team <http://www.sourcemage.org>
     8	#---------------------------------------------------------------------
     9	
    10	#---------------------------------------------------------------------
    11	##
    12	## Adds a dependency to the a depends database file.  Returns 1 if the
    13	## 3rd or 4th fields are not valid.
    14	##
    15	## @param  Depends status file
    16	## @param  Name of the "parent" spell
    17	## @param  Name of the spell the parent spell depends on
    18	## @param  "on" or "off" depending on whether the user installed the dependency
    19	## @param  Type of dependency (required or optional)
    20	## @param  option to pass to C<configure> if the dependency is installed
    21	## @param  option to pass to C<configure> if the dependency is not installed
    22	##
    23	## @Example add_depends kdelibs alsa-driver on optional --with-alsa --without-alsa
    24	##
    25	#---------------------------------------------------------------------
    26	function add_depends()
    27	{ # $1=depends file $2=spell, $3=depends, $4=on/off, $5=optional/required, $6=on arg, $7=off arg
    28	  debug "libstate" "add_depends() - $*"
    29	
    30	  #already here for some reason
    31	  search_depends_status_exact "$@" >/dev/null  && return 0
    32	
    33	  local depends_status=$1
    34	  shift
    35	
    36	  # ensure the info is valid (perhaps add check that spells exist?)
    37	  list_find "on off" "$3" || return 1
    38	  list_find "required optional runtime suggest" "$4" || return 1
    39	
    40	  # Allow add_depends to override previous ones for the same pair of spells
    41	  search_depends_status "$depends_status" "$1" "$2" >/dev/null &&
    42	  remove_depends_status "$depends_status" "$1" "$2"
    43	
    44	  local t_status
    45	#  lock_start_transaction "$depends_status" t_status
    46	  echo "$1:$2:$3:$4:$5:$6" >> "$depends_status"
    47	#  lock_commit_transaction "$depends_status"
    48	
    49	  return 0
    50	
    51	}
    52	
    53	#---------------------------------------------------------------------
    54	##
    55	## In case you want to search in all the fields of the $1
    56	##
    57	## Arguments can be regexp
    58	##
    59	## Prints out the matching line(s)
    60	## @Stdout the matching line(s)
    61	## @param depends file
    62	## @param spell
    63	## @param depends
    64	## @param on/off
    65	## @param optional/required
    66	## @param on arg
    67	## @param off arg
    68	##
    69	## @return 0 if entry was found
    70	## @return 1 if entry was not found
    71	## @return 2 on error
    72	##
    73	#---------------------------------------------------------------------
    74	function search_depends_status_exact()
    75	{ # $1=depends file $2=spell, $3=depends, $4=on/off, $5=optional/required, $6=on arg, $7=off arg
    76	
    77	  local depends_status=$1
    78	  shift
    79	
    80	  local a1 a2 a3 a4 a5 a6
    81	  esc_str "$1" a1; esc_str "$3" a3
    82	  esc_str "$4" a4; esc_str "$5" a5; esc_str "$6" a6
    83	  esc_provider_str "$2" a2
    84	  debug "libstate" "search_depends_status_exact: [$a1:$a2:$a3:$a4:$a5:$a6]"
    85	
    86	  lock_file "$depends_status"
    87	  grep "^$a1:$a2:$a3:$a4:$a5:$a6$" "$depends_status"
    88	  rc=$?
    89	  unlock_file "$depends_status"
    90	
    91	  return $rc
    92	}
    93	
    94	#---------------------------------------------------------------------
    95	##
    96	## Search depends status, dont do anything escaping.
    97	##
    98	## Arguments can be regexp
    99	##
   100	## Prints out the matching line(s)
   101	## @Stdout the matching line(s)
   102	## @param depends file
   103	## @param spell
   104	## @param depends
   105	## @param on/off (optional)
   106	## @param optional/required (optional)
   107	## @param on arg (optional)
   108	## @param off arg (optional)
   109	##
   110	#---------------------------------------------------------------------
   111	function search_depends_status_simple()
   112	{ # $1=depends file $2=spell, $3=depends, $4=on/off, $5=optional/required, $6=on arg, $7=off arg
   113	
   114	    local depends_status=$1
   115	    shift
   116	
   117	    local a1 a2 a3 a4 a5 a6
   118	    esc_str "$1" a1; esc_provider_str "$2" a2
   119	    a3=${3:-.*} ; a4=${4:-.*}
   120	    esc_str "$5" a5; esc_str "$6" a6
   121	    a5=${5:-.*} ; a6=${6:-.*}
   122	
   123	    lock_file "$depends_status"
   124	    grep "^$a1:$a2\(([^:]*)\)\?:$a3:$a4:$a5:$a6$" "$depends_status"
   125	    unlock_file "$depends_status"
   126	}
   127	
   128	
   129	#---------------------------------------------------------------------
   130	## @param depends file
   131	## @param spell
   132	## @param depends (optional)
   133	## @Stdout matching lines
   134	## In case you want to search by spell or dependency in $1
   135	##
   136	## Arguments can be regexp
   137	##
   138	## Prints out the matching line(s)
   139	##
   140	#---------------------------------------------------------------------
   141	function search_depends_status()
   142	{ # $1=depends file $2=spell, $3=(opt)depends
   143	
   144	  [[ -z $2 ]] && return 1
   145	  local depends_status=$1
   146	  shift
   147	
   148	  local spell
   149	  esc_str "$1" spell
   150	#  lock_file "$depends_status"
   151	  if [[ -z $2 ]]; then
   152	    grep "^$spell:" "$depends_status"
   153	  else
   154	    local depends
   155	    esc_provider_str "$2" depends
   156	    grep "^$spell:$depends:" "$depends_status"
   157	  fi
   158	#  unlock_file "$depends_status"
   159	}
   160	
   161	
   162	
   163	#---------------------------------------------------------------------
   164	##
   165	## @param depends file
   166	## @param spell
   167	## @param dependency spell
   168	## @Stdout list of options
   169	##
   170	## Returns a list of options for ./configure from $1
   171	## Primarily aimed at generating $OPTS contents
   172	##
   173	## Prints out one line of output
   174	#---------------------------------------------------------------------
   175	function get_depends_options()
   176	{ # $1=depends_status $2=spell
   177	
   178	  local depends_status=$1
   179	  shift
   180	
   181	  [ -z "$1" ] && {
   182	    message "${PROBLEM_COLOR}${1:-<null>} is not a spell name${DEFAULT_COLOR}"
   183	    return
   184	  }
   185	
   186	  local START
   187	  esc_str "$1" START
   188	  debug "libstate" "get_depends_options() - START=$START"
   189	  lock_file "$depends_status"
   190	  awk -F ':' -v start=$START "{ if (\$1 == start) if (\$3 == \"on\") OPTS = OPTS \" \" \$5; else OPTS = OPTS \" \" \$6; } END { print OPTS; }" $depends_status 2> /dev/null
   191	  unlock_file "$depends_status"
   192	}
   193	
   194	
   195	#---------------------------------------------------------------------
   196	##
   197	## Arguments can be regexp, and all but the spell are optional
   198	##
   199	## @param depends file
   200	## @param spell
   201	## @param depends
   202	## @param on/off
   203	## @param optional/required
   204	## @param on arg
   205	## @param off arg
   206	##
   207	#---------------------------------------------------------------------
   208	function remove_depends_status()
   209	{ # $1=depends file $2=spell, $3=(OPT)depends, $4=(OPT)on/off, $5=(OPT)optional/required, $6=(OPT)on arg, $7=(OPT)off arg
   210	
   211	   local depends_status=$1
   212	   shift
   213	
   214	    local a1 a2 a3 a4 a5 a6
   215	    # arguments 1 and 2 are spell names, which might have characters that
   216	    # look like regexps, 5 and 6 might like funny too
   217	    # contrast 3 and 4 which are "on", "off", "required" or "optional"
   218	    # if they are regexps its probably desired so dont escape those
   219	    esc_str "$1" a1; esc_str "$2" a2
   220	    a1=${a1:-.*}; a2=${a2:-.*}
   221	
   222	    a3=${3:-.*} ; a4=${4:-.*}
   223	
   224	    esc_str "$5" a5; esc_str "$6" a6
   225	    a5=${a5:-.*}; a6=${a6:-.*}
   226	    [[ "$a5" == "[none]" ]] && a5="\\[none\\]"
   227	
   228	    local t_status
   229	    lock_start_transaction "$depends_status" t_status
   230	    sedit "/^$a1:$a2:$a3:$a4:$a5:$a6$/D" "$t_status"
   231	    lock_commit_transaction "$depends_status"
   232	}
   233	
   234	#---------------------------------------------------------------------
   235	## Toggle optional and suggested dependencies on/off
   236	##
   237	## @param depends file
   238	## @param spell
   239	## @param dependency
   240	##
   241	#---------------------------------------------------------------------
   242	function toggle_depends_status() {
   243	  local depends_status=$1
   244	  shift
   245	
   246	  local spell dependency
   247	  esc_str "$1" spell; esc_str "$2" dependency
   248	
   249	  local t_status
   250	  lock_start_transaction "$depends_status" t_status
   251	  awk -F ':' -v OFS=':' \
   252	    '/^'$spell:$dependency':(on|off):(optional|suggest):/ \
   253	      { if ($3 == "on") $3 = "off"; else $3 = "on"; }
   254	    { print; }' $depends_status > $t_status
   255	  lock_commit_transaction "$depends_status"
   256	}
   257	
   258	#---------------------------------------------------------------------
   259	## Changes the $spell's provider of $feature to a $new one. Can also
   260	## toggle it to be enabled or disabled.
   261	##
   262	## @param depends file
   263	## @param spell
   264	## @param new provider
   265	## @param feature
   266	## @param on/off
   267	##
   268	#---------------------------------------------------------------------
   269	function change_spell_provider() {
   270	  local depends_status=$1
   271	  shift
   272	
   273	  local spell new_provider feature enabled
   274	  esc_str "$1" spell
   275	  esc_str "$2" new_provider
   276	  esc_str "$3" feature
   277	  enabled=$4
   278	
   279	  local t_status
   280	  lock_start_transaction "$depends_status" t_status
   281	  if [[ -z $enabled ]]; then
   282	    sed -i "s/^$spell:[^:]*($feature):/$spell:$new_provider($feature):/" $t_status
   283	  else
   284	    sed -i "s/^$spell:[^:]*($feature):[^:]*:/$spell:$new_provider($feature):$enabled:/" $t_status
   285	  fi
   286	  lock_commit_transaction "$depends_status"
   287	}
   288	
   289	#---------------------------------------------------------------------
   290	## Sets up the uncommitted depends file. If the name isn't
   291	## found in the hash table create it. If the file already exists
   292	## move it to the abandoned depends directory and start with a new one.
   293	## The uncommitted_hash hash table should be hash_export'ed to
   294	## make it through the call to make.
   295	##
   296	## @param spell
   297	## @param variable name to put the filename name in (pass by reference)
   298	##
   299	#---------------------------------------------------------------------
   300	function get_uncommitted_depends_file() {
   301	    local SPELL=$1
   302	    local temp_spell_depends
   303	    hash_get_ref "uncommitted_hash" $SPELL temp_spell_depends
   304	
   305	    if ! [[ $temp_spell_depends ]] ; then
   306	      temp_spell_depends="$UNCOMMITTED_DEPENDS/$SPELL"
   307	      hash_put "uncommitted_hash" "$SPELL" "$temp_spell_depends"
   308	
   309	      mkdir -p "$ABANDONED_DEPENDS"
   310	      mv "$temp_spell_depends" "$ABANDONED_DEPENDS" &>/dev/null
   311	      mv "$temp_spell_depends:*" "$ABANDONED_DEPENDS" &>/dev/null
   312	
   313	      mkdir -p "$UNCOMMITTED_DEPENDS"
   314	      touch "$temp_spell_depends"
   315	    fi
   316	    eval "$2=\"$temp_spell_depends\""
   317	}
   318	
   319	#---------------------------------------------------------------------
   320	## Get the uncommitted sub-depends file. Uses get_uncommitted_depends_file.
   321	## This file is intended for use by the sub-dependee.
   322	##
   323	## @param spell
   324	## @param variable name to put the filename in
   325	#---------------------------------------------------------------------
   326	function get_uncommitted_sub_depends_file() {
   327	  local SPELL=$1
   328	  local upvar=$2
   329	  local __tmp
   330	  get_uncommitted_depends_file "$SPELL" __tmp
   331	  # : cannot be in spell names, so we can take advantage of the namespace
   332	  __tmp=${__tmp}:s
   333	  # we can assume that the parent directory exists because
   334	  # get_uncommitted_depends_file creates it
   335	  touch "$__tmp"
   336	  eval "$2=\"$__tmp\""
   337	}
   338	
   339	#---------------------------------------------------------------------
   340	## Get the uncommitted sub-depends file. Uses get_uncommitted_depends_file
   341	## This file is intended for use by the requester.
   342	##
   343	## @param spell
   344	## @param variable name to put the filename in
   345	#---------------------------------------------------------------------
   346	function get_uncommitted_rsub_depends_file() {
   347	  local SPELL=$1
   348	  local upvar=$2
   349	  local __tmp
   350	  get_uncommitted_depends_file "$SPELL" __tmp
   351	  # : cannot be in spell names, so we can take advantage of the namespace
   352	  __tmp=${__tmp}:rs
   353	  # we can assume that the parent directory exists because
   354	  # get_uncommitted_depends_file creates it
   355	  touch "$__tmp"
   356	  eval "$2=\"$__tmp\""
   357	}
   358	
   359	#---------------------------------------------------------------------
   360	## Add a sub-dependency.
   361	##
   362	## @param sub-depends file
   363	## @param requester file
   364	## @param sub-dependee
   365	## @param sub-depends
   366	#---------------------------------------------------------------------
   367	function add_sub_depends() {
   368	  $STD_DEBUG
   369	  remove_sub_depends "$@" || return 1
   370	  local file=$1
   371	  shift
   372	
   373	  local t_file
   374	  lock_start_transaction "$file" t_file
   375	  echo "$1:$2:$3" >> "$t_file"
   376	  lock_commit_transaction "$file"
   377	}
   378	
   379	#---------------------------------------------------------------------
   380	## Search in sub-depends file.
   381	##
   382	## @param sub-depends file
   383	## @param requester file (optional)
   384	## @param sub-dependee (optional)
   385	## @param sub-depends (optional)
   386	#---------------------------------------------------------------------
   387	function search_sub_depends() {
   388	  $STD_DEBUG
   389	  local file=$1
   390	  shift
   391	  local a1 a2 a3
   392	  esc_str "$1" a1; esc_str "$2" a2; esc_str "$3" a3
   393	  a1=${a1:-.*}
   394	  a2=${a2:-.*}
   395	  a3=${a3:-.*}
   396	
   397	  lock_file "$file"
   398	  grep "^$a1:$a2:$a3$" "$file"
   399	  unlock_file "$file"
   400	}
   401	
   402	#---------------------------------------------------------------------
   403	## Remove a sub-depends.
   404	##
   405	## @param sub-depends file
   406	## @param requester
   407	## @param sub-dependee
   408	## @param sub-depends
   409	#---------------------------------------------------------------------
   410	function remove_sub_depends() {
   411	  $STD_DEBUG
   412	  local file=$1
   413	  shift
   414	
   415	  test -f $file || return
   416	
   417	  local a1 a2 a3
   418	  esc_str "$1" a1; esc_str "$2" a2; esc_str "$3" a3
   419	  a1=${a1:-.*}; a2=${a2:-.*}; a3=${a3:-.*}
   420	
   421	  local t_file
   422	  lock_start_transaction "$file" t_file
   423	  sedit "/^$a1:$a2:$a3$/D" "$t_file"
   424	  lock_commit_transaction "$file"
   425	}
   426	
   427	#---------------------------------------------------------------------
   428	## Default depends and default provider api
   429	## default depends examples:
   430	##
   431	## default xfree86 provider to ImageMagick is xfree86
   432	## ImageMagick:X11-LIBS:xfree86
   433	##
   434	## default answer to optional_depends graphviz for ImageMagick is "no"
   435	## ImageMagick:graphviz:off
   436	##
   437	##
   438	## default provider examples:
   439	## use xorg as X11-LIBS even if its optional
   440	## xorg:X11-LIBS:on
   441	##
   442	## use xfree86 as X11-LIBS unless the [none] option exists (and use that instead)
   443	## xfree86:X11-LIBS:off
   444	#---------------------------------------------------------------------
   445	
   446	#---------------------------------------------------------------------
   447	##
   448	## add default depends entry, if $3 is a spell $4 must be on/off
   449	## if $3 is a PROVIDER $4 must be a spell
   450	##
   451	## @param depends file
   452	## @param spell
   453	## @param depends/PROVIDER
   454	## @param on/off
   455	##
   456	#---------------------------------------------------------------------
   457	function add_default_depends() {
   458	        debug "libstate" "add_default_depends() - $*"
   459	
   460	        #already here
   461	        search_default_depends "$@" >/dev/null  && return 0
   462	
   463	        local file=$1
   464	        shift
   465	        # ensure the info is valid... (this is redundant if calling
   466	        # from sorcery, but that may not always be the case...
   467	        if [[ $3 != on ]] && [[ $3 != off ]] ; then
   468	          return 1
   469	        fi
   470	
   471	        { [[ ! $1 ]] && [[ ! $2 ]] ; } && return 1
   472	
   473	        if [[ $1 ]] && ! codex_does_spell_exist $1 &>/dev/null; then
   474	          return 1
   475	        fi
   476	
   477	        if [[ $2 ]] && ! codex_does_spell_exist $2; then
   478	          return 1
   479	        fi
   480	
   481	        lock_start_transaction "$file" tfile
   482	        remove_default_depends $tfile $1 $2
   483	        echo "$1:$2:$3" >> $tfile
   484	        lock_commit_transaction $file
   485	
   486	       return 0
   487	
   488	}
   489	
   490	#---------------------------------------------------------------------
   491	##
   492	## Arguments can be regexp, $2, $3 and $4 are optional
   493	## Caller must lock the file
   494	##
   495	## @param depends file
   496	## @param spell
   497	## @param depends/PROVIDER
   498	## @param on/off/spell
   499	##
   500	#---------------------------------------------------------------------
   501	function remove_default_depends() {
   502	
   503	        local file=$1
   504	        shift
   505	        test -e $file || return
   506	
   507	        local a1 a2 a3
   508	        esc_str "$1" a1; esc_str "$2" a2; esc_str "$3" a3
   509	
   510	        a3=${a3:-.*}
   511	
   512	        local t_file
   513	        lock_start_transaction "$file" t_file
   514	        sedit "/^$a1:$a2:$a3$/D" $t_file
   515	        lock_commit_transaction "$file"
   516	}
   517	
   518	#---------------------------------------------------------------------
   519	##
   520	## Arguments can be regexp, $2 $3 and $4 are optional
   521	##
   522	## @param depends file
   523	## @param spell
   524	## @param depends/PROVIDER
   525	## @param on/off/spell
   526	##
   527	#---------------------------------------------------------------------
   528	function search_default_depends() {
   529	
   530	        local default_depends=$1
   531	        shift
   532	        [[ -s $default_depends ]] || return
   533	
   534	        local a1 a2 a3
   535	        esc_str "$1" a1; esc_str "$2" a2; esc_str "$3" a3
   536	        a3=${a3:-.*}
   537	
   538	        debug "libstate" "search_default_depends: [$a1:$a2:$a3]"
   539	        lock_file "$default_depends"
   540	        grep "^$a1:$a2:$a3$" $default_depends
   541	        rc=$?
   542	        unlock_file "$default_depends"
   543	
   544	        return $rc
   545	}
   546	
   547	
   548	#---------------------------------------------------------------------
   549	##
   550	## Arguments can be regexp, $3 and $4 are optional
   551	##
   552	## @param depends file
   553	## @param spell
   554	## @param PROVIDER
   555	## @param on/off
   556	##
   557	#---------------------------------------------------------------------
   558	function add_default_provider() {
   559	  debug "libstate" "add_default_depends() - $*"
   560	
   561	  #already here
   562	  search_default_provider "$@" >/dev/null  && return 0
   563	
   564	  local file=$1
   565	  shift
   566	
   567	  #ensure the info is valid...
   568	  { [[ ! $1 ]] && [[ ! $2 ]] ; } && return 1
   569	  { [[ $3 != on ]] && [[ $3 != off ]] ; } && return 1
   570	
   571	  if [[ $1 ]] && ! codex_does_spell_exist $1 &>/dev/null ; then
   572	    return 1
   573	  fi
   574	  if [[ $2 ]] && ! codex_does_service_exist $2 &>/dev/null ; then
   575	    return 1
   576	  fi
   577	
   578	  lock_start_transaction "$file" tfile
   579	  remove_default_provider $tfile "" $2
   580	  echo "$1:$2:$3" >> $tfile
   581	  lock_commit_transaction $file
   582	
   583	  return 0
   584	}
   585	
   586	# these are the same, as their countparts but are here for completeness
   587	# and incase they do someday diverge
   588	function remove_default_provider() {
   589	  remove_default_depends "$@"
   590	}
   591	
   592	function search_default_provider() {
   593	  search_default_depends "$@"
   594	}
   595	
   596	#---------------------------------------------------------------------
   597	## @param cache file
   598	## @param spell name
   599	##
   600	## Removes the spell info from the passed file ($VERSION_STATUS)
   601	##
   602	#---------------------------------------------------------------------
   603	function remove_version_cache()  {
   604	  local file=$1
   605	  lock_start_transaction "$file" t_file
   606	  sed -i "/^$2 /d" $t_file
   607	  lock_commit_transaction $file
   608	}
   609	
   610	#---------------------------------------------------------------------
   611	## @param cache file
   612	## @param spell name
   613	## @param version
   614	## @param patchlevel
   615	## @param security patch
   616	## @param updated
   617	##
   618	## Given a spell and the factors that affect queuing, this function
   619	## adds the info to the passed file (usually $VERSION_STATUS)
   620	##
   621	#---------------------------------------------------------------------
   622	function add_version_cache()  {
   623	  local file=$1
   624	  shift
   625	  remove_version_cache "$file" $1
   626	
   627	  lock_start_transaction "$file" t_file
   628	  echo "$1 ${2:-0} ${3:-0} ${4:-0} ${5:-0}" >> $t_file
   629	  lock_commit_transaction $file
   630	}
   631	
   632	#---------------------------------------------------------------------
   633	##
   634	## Adds an entry to the SPELL_STATUS file
   635	##
   636	## Arguments may either be SPELL, ACTION, VERSIONS, or just
   637	## ACTION if there exists SPELL and VERSIONS variables already
   638	## set.
   639	## @param spell OR action
   640	## @param (if spell) action
   641	## @param (if spell) version
   642	##
   643	#---------------------------------------------------------------------
   644	function add_spell_status()
   645	{ #$1=spell, $2=action, $3=version, OR $1=action.
   646	
   647	  local spell action version date
   648	  if [ $# -eq 1 ] ; then
   649	    spell="$SPELL"
   650	    action="$1"
   651	    version="$VERSION"
   652	  else
   653	    spell=$1
   654	    action=$2
   655	    version=$3
   656	  fi
   657	  [[ $spell ]] && [[ $action ]] && [[ $version ]] || return 1
   658	  date=`date +%Y%m%d`
   659	  lock_start_transaction "$SPELL_STATUS" tSPELL_STATUS
   660	  echo "$spell:$date:$action:$version" >> $tSPELL_STATUS
   661	  lock_commit_transaction $SPELL_STATUS
   662	
   663	}
   664	
   665	#---------------------------------------------------------------------
   666	## @param spell name
   667	##
   668	## Given a spell, status (installed, held, etc), and version, add_spell
   669	## adds the spell to the /var/state/sorcery/packages file
   670	##
   671	#---------------------------------------------------------------------
   672	function add_spell()  {
   673	  remove_spell  $1
   674	  add_spell_status $1 $2 $3
   675	}
   676	
   677	#---------------------------------------------------------------------
   678	## @param spell status file
   679	## @param spell
   680	## @param version (optional)
   681	## @Stdout matching lines
   682	##
   683	## Arguments can be regexp
   684	##
   685	## Prints out the matching line(s)
   686	##
   687	#---------------------------------------------------------------------
   688	function search_spell_status() {
   689	  [[ -z $2 ]] && return 1
   690	  local spell_status=$1
   691	  shift
   692	
   693	  local spell
   694	  esc_str "$1" spell
   695	  lock_file "$spell_status"
   696	  if [[ -z $2 ]]; then
   697	    grep "^$spell:" $spell_status
   698	  else
   699	    local version
   700	    esc_str "$2" version
   701	    grep "^$spell:$version:" $spell_status
   702	  fi
   703	  unlock_file "$spell_status"
   704	}
   705	
   706	#---------------------------------------------------------------------
   707	##
   708	## @param spell ( [A-Za-z0-9_-] )
   709	## @param version (optional and may not contain spaces or colons; '.' and '*' have special meaning)
   710	## @param variable to set
   711	## @Stdout last matching line ( only one even if there are more )
   712	##
   713	## Searches the SPELL_STATUS file for a spell and optionally
   714	## a version.
   715	##
   716	## Prints out the matching spell's status
   717	## @return 1 only for critical problems ( missing SPELL_STATUS file )
   718	## @return 0 for all other cases ( even when spell is not found )
   719	##
   720	#---------------------------------------------------------------------
   721	function query_spell_status()
   722	{ #$1=spell, $2=(OPT)version
   723	
   724	  local return_var __status
   725	  [[ -e $SPELL_STATUS ]] || return 1
   726	
   727	  lock_file "$SPELL_STATUS"
   728	  if [[ -z $3 ]]; then
   729	    [[ -z $2 ]] && return 0
   730	    return_var="$2"
   731	    __status=$(awk -F: -v spell="$1" '{ if (spell == $1) status=$3 } END{print status}' "$SPELL_STATUS" 2>/dev/null)
   732	  else
   733	    return_var="$3"
   734	    __status=$(awk -F: -v spell="$1" -v version="$2" '{ if (spell == $1 && version == $4) status=$3 } END{print status}' "$SPELL_STATUS" 2>/dev/null)
   735	  fi
   736	  unlock_file "$SPELL_STATUS"
   737	
   738	  eval "$return_var=\"\$__status\""
   739	  return 0
   740	}
   741	
   742	#---------------------------------------------------------------------
   743	## @Type API
   744	## @param spell name
   745	##
   746	## @return 0 if the given spell's status is "installed"
   747	#---------------------------------------------------------------------
   748	function real_spell_installed() {
   749	  local status
   750	  query_spell_status "$1" status
   751	  [[ $status == installed ]]
   752	}
   753	
   754	
   755	#---------------------------------------------------------------------
   756	## @param spell name
   757	##
   758	## @return 0 if the given spell's status is "held"
   759	##
   760	#---------------------------------------------------------------------
   761	function real_spell_held()      {
   762	  local status
   763	  query_spell_status "$1" status
   764	  [[ $status == held ]]
   765	}
   766	
   767	#---------------------------------------------------------------------
   768	## @Type API
   769	## @param spell name
   770	##
   771	## @return 0 if the given spell's status is "installed" or "held"
   772	#---------------------------------------------------------------------
   773	function real_spell_ok() {
   774	  local status
   775	  query_spell_status "$1" status
   776	  [[ $status == installed ]] || [[ $status == held ]]
   777	}
   778	
   779	
   780	#---------------------------------------------------------------------
   781	## @Type API
   782	## @param Provider name
   783	##
   784	## @return 0 if any provider of $1 is installed
   785	#---------------------------------------------------------------------
   786	function real_provider_ok() {
   787	  for spell in $(search_depends_status_exact $DEPENDS_STATUS '.*' ".*($1)" \
   788	                 'on' '.*'  '.*' |cut -f2 -d:|cut -f1 -d\(|sort -u); do
   789	    spell_ok $spell && return 0
   790	  done
   791	  return 1
   792	}
   793	
   794	#---------------------------------------------------------------------
   795	## @Type API
   796	## @param Spell name
   797	## @param Provider name
   798	## @param If empty get the uncommited spell info, if anything else get info from the committed ($DEPENDS_STATUS) database. If the uncommited db doesnt exist (maybe we're not casting) use DEPENDS_STATUS
   799	##
   800	## @return 0 if a provider could be found 1 if not
   801	## @return 0 if a dependency from $1 on $2 is enabled, 1 otherwise.
   802	## @stdout the provider name(s)
   803	#---------------------------------------------------------------------
   804	function real_get_spell_provider() {
   805	  local dep_status
   806	  if [[ $3 ]] ; then
   807	    dep_status=$DEPENDS_STATUS
   808	  else
   809	    hash_get_ref uncommitted_hash $1 dep_status
   810	    [[ $dep_status ]] || dep_status=$DEPENDS_STATUS
   811	  fi
   812	  search_depends_status_exact $dep_status "$1" ".*($2)" \
   813	                 'on' '.*'  '.*' '.*' |cut -f2 -d:|cut -f1 -d\(|sort -u
   814	}
   815	
   816	#---------------------------------------------------------------------
   817	## @Type API
   818	## @param Spell name
   819	## @param Target spell name
   820	## @param If empty get the uncommited spell info, if anything else get info from the committed ($DEPENDS_STATUS) database. If the uncommited db doesnt exist (maybe we're not casting) use DEPENDS_STATUS
   821	##
   822	## @return 0 if a dependency from $1 on $2 is enabled, 1 otherwise.
   823	## @stdout the provider name(s)
   824	#---------------------------------------------------------------------
   825	function real_is_depends_enabled() {
   826	  local dep_status
   827	  if [[ $3 ]] ; then
   828	    dep_status=$DEPENDS_STATUS
   829	  else
   830	    hash_get_ref uncommitted_hash $1 dep_status
   831	    [[ $dep_status ]] || dep_status=$DEPENDS_STATUS
   832	  fi
   833	  [[ -n $(search_depends_status_simple $dep_status "$1" "$2" 'on' ) ]]
   834	}
   835	
   836	
   837	#---------------------------------------------------------------------
   838	## @param spell name
   839	##
   840	##  @return 0 if the given spell's status is "exiled"
   841	##
   842	#---------------------------------------------------------------------
   843	function real_spell_exiled()    {
   844	  local status
   845	  query_spell_status "$1" status
   846	  [[ $status == exiled ]]
   847	}
   848	
   849	
   850	#---------------------------------------------------------------------
   851	## @param spell to remove status of
   852	## Removes all specified offending entries in SPELL_STATUS
   853	##
   854	#---------------------------------------------------------------------
   855	function remove_spell_status()
   856	{ #$1=spell to remove status of
   857	
   858	  lock_start_transaction "$SPELL_STATUS" tSPELL_STATUS
   859	  grep  -v  "^$1:" $SPELL_STATUS  >  $tSPELL_STATUS
   860	  lock_commit_transaction $SPELL_STATUS
   861	
   862	}
   863	
   864	#---------------------------------------------------------------------
   865	## @param spell name
   866	##
   867	## Removes the given spell from the /var/state/sorcery/packages file.
   868	## if C<EXILE> is set, the spell is changed to "exiled" in the file.
   869	##
   870	#---------------------------------------------------------------------
   871	function remove_spell()  {
   872	  debug  "libsorcery" "Running remove_spell() on $1"
   873	  remove_spell_status $1
   874	  if  [  -n  "$EXILE"  ];  then
   875	    add_spell_status $1 "exiled" "0.0"
   876	  fi
   877	}
   878	
   879	
   880	#---------------------------------------------------------------------
   881	## @Stdout All spell stati
   882	## Just here to round out the SPELL_STATUS functions so that
   883	## SPELL_STATUS doesn't have to mentioned in libsorcery
   884	##
   885	#---------------------------------------------------------------------
   886	function all_spell_status()
   887	{
   888	  lock_file "$SPELL_STATUS"
   889	  cat $SPELL_STATUS
   890	  unlock_file "$SPELL_STATUS"
   891	}
   892	
   893	
   894	#---------------------------------------------------------------------
   895	## @param spells
   896	## sets <spells>'s status to held
   897	##
   898	#---------------------------------------------------------------------
   899	function set_held() {
   900	    local t_status
   901	    lock_start_transaction "$SPELL_STATUS" t_status
   902	    for to_hold in $@; do
   903	        sedit 's/\(^'$(esc_str $to_hold)':[^:]*:\)installed/\1held/' $t_status
   904	    done
   905	    lock_commit_transaction $SPELL_STATUS
   906	}
   907	
   908	
   909	#---------------------------------------------------------------------
   910	## @param spells
   911	## sets <spells>'s status to exiled
   912	##
   913	#---------------------------------------------------------------------
   914	function set_exiled() {
   915	    local TO_DISPELL=""
   916	    local TO_EXILE
   917	    local MY_STATUS
   918	
   919	    for TO_EXILE in $@; do
   920	        query_spell_status "$TO_EXILE" MY_STATUS
   921	        case "$MY_STATUS" in
   922	            "" )
   923	                add_spell_status $TO_EXILE exiled 0.0
   924	                message "Spell '$TO_EXILE' exiled."
   925	                ;;
   926	            "exiled" )
   927	                message "${MESSAGE_COLOR}Spell ${DEFAULT_COLOR}'$TO_EXILE'" \
   928	                    "${MESSAGE_COLOR}is allready exiled.${DEFAULT_COLOR}"
   929	                ;;
   930	            "installed" )
   931	                local ask="'$TO_EXILE' is installed."
   932	                ask="${ask} Do you want to dispel and exile it ?"
   933	                query "$ask" &&
   934	                TO_DISPELL="$TO_DISPELL $TO_EXILE"
   935	                ;;
   936	            * )
   937	                message "${PROBLEM_COLOR}Can't exile spell" \
   938	                    "${DEFAULT_COLOR}'$TO_EXILE'${PROBLEM_COLOR}" \
   939	                    "which has status '$MY_STATUS'${DEFAULT_COLOR}"
   940	                ;;
   941	        esac
   942	    done
   943	    if [ -n "$TO_DISPELL" ]; then
   944	        dispel -e $TO_DISPELL
   945	    fi
   946	}
   947	
   948	
   949	#---------------------------------------------------------------------
   950	## @param spells
   951	## resets <spells>'s 'exiled' status
   952	##
   953	#---------------------------------------------------------------------
   954	function set_unexiled() {
   955	    local MY_STATUS
   956	    local TO_UNEXILE
   957	    for TO_UNEXILE in $@; do
   958	        query_spell_status "$TO_UNEXILE" MY_STATUS
   959	        if [ x"$MY_STATUS" == x"exiled" ]; then
   960	            remove_spell $TO_UNEXILE
   961	        else
   962	            message "${MESSAGE_COLOR}Can't unexile spell${DEFAULT_COLOR}" \
   963	                "'$TO_UNEXILE'${MESSAGE_COLOR}, it's not exiled${DEFAULT_COLOR}"
   964	        fi
   965	    done
   966	}
   967	
   968	
   969	#---------------------------------------------------------------------
   970	## @param spells
   971	## sets <spells>'s status to installed
   972	##
   973	#---------------------------------------------------------------------
   974	function set_unheld() {
   975	    local t_status
   976	    lock_start_transaction "$SPELL_STATUS" t_status
   977	    for to_hold in $@; do
   978	        sedit 's/\(^'$(esc_str $to_hold)':[^:]*:\)held/\1installed/' $t_status
   979	    done
   980	    lock_commit_transaction $SPELL_STATUS
   981	}
   982	
   983	
   984	#---------------------------------------------------------------------
   985	## @param status (installed, held, exiled or ok[for the first two])
   986	## @Stdout spells
   987	## returns all spells that are in that status
   988	##
   989	#---------------------------------------------------------------------
   990	function get_all_spells_with_status() {
   991	  local status=$1
   992	  lock_file $SPELL_STATUS
   993	  if [[ $status != ok ]]; then
   994	    gawk -F: 'BEGIN { status="'$status'" }
   995	              ($3 == status) { print $1 }' $SPELL_STATUS
   996	  else
   997	    awk -F: '{ if ($3 == "installed" || $3 == "held") print $1 }' $SPELL_STATUS
   998	  fi
   999	  unlock_file $SPELL_STATUS
  1000	}
  1001	
  1002	
  1003	#---------------------------------------------------------------------
  1004	## @param variable
  1005	## @param value
  1006	## @param command (optional)
  1007	##
  1008	## Modifies (or adds) an entry in the local/config.
  1009	## If "command" is the third argument, a space will separate the
  1010	## variable and value rather than the equals sign.
  1011	##
  1012	#---------------------------------------------------------------------
  1013	function modify_local_config() {
  1014	    debug "libstate" "modify_local_config() - $*"
  1015	    modify_config $LOCAL_CONFIG "$@"
  1016	}
  1017	
  1018	
  1019	#---------------------------------------------------------------------
  1020	## @param Filename
  1021	## @param variable
  1022	## @param value
  1023	## @param command (optional)
  1024	##
  1025	## Modifies (or adds) an entry in the local/config.
  1026	## If "command" is the third argument, a space will separate the
  1027	## variable and value rather than the equals sign.
  1028	##
  1029	#---------------------------------------------------------------------
  1030	function modify_config()  {
  1031	
  1032	  debug "libstate" "modify_config() - $*"
  1033	  local FILE=$1
  1034	  shift;
  1035	
  1036	  if ! [[ $1 ]]; then
  1037	    debug "libstate" "modify_config() - Warning: No name given for config option."
  1038	    return 1
  1039	  fi
  1040	
  1041	  local TEMP separator EQUALS_COL VARIABLE
  1042	
  1043	  if ! test -f $FILE; then
  1044	    if ! test -d $(smgl_dirname $FILE); then
  1045	      if test -e $(smgl_dirname $FILE); then
  1046	        message "Trying to modify $FILE, but $(smgl_dirname $FILE) is not a directory"
  1047	        return 1
  1048	      fi
  1049	      mkdir -p $(smgl_dirname $FILE)
  1050	    fi &&
  1051	    touch $FILE || {
  1052	      message "Failed to create $FILE"
  1053	      return 1
  1054	    }
  1055	  fi
  1056	
  1057	  # remove previous reference
  1058	  lock_start_transaction "$FILE" tFILE
  1059	  grep  -v  "^[[:blank:]]*${1}${separator}" $FILE >  $tFILE
  1060	
  1061	  # justifying...
  1062	  EQUALS_COL=$((20-${#1}))
  1063	  [ $EQUALS_COL -lt 0  ] && EQUALS_COL=0
  1064	  TEMP=""
  1065	  for (( ; EQUALS_COL>0 ; EQUALS_COL-- )) ; do
  1066	    TEMP="$TEMP "
  1067	  done
  1068	
  1069	  debug "libstate" "modify_config() - entering new value $VARIABLE $seperator $@ into $tFILE"
  1070	  # put the new value and justification in
  1071	  # assign the value in a way that can be overriden from the environment #14454
  1072	  if [[ $3 == command ]]; then
  1073	    echo "${TEMP}${1} \"$2\""
  1074	  else
  1075	    echo "${TEMP}${1}=\"\${$1:-$2}\""
  1076	  fi >> $tFILE
  1077	
  1078	  lock_commit_transaction $FILE
  1079	
  1080	}
  1081	
  1082	#---------------------------------------------------------------------
  1083	## @param Filename
  1084	## @param variable
  1085	## @param command (optional)
  1086	##
  1087	## Removes an entry in the local/config.
  1088	## If "command" is the third argument, a space will separate the
  1089	## variable and value rather than the equals sign.
  1090	##
  1091	#---------------------------------------------------------------------
  1092	function remove_config()  {
  1093	
  1094	  debug "libstate" "remove_config() - $*"
  1095	  local FILE=$1
  1096	  shift;
  1097	
  1098	  if ! [[ $1 ]]; then
  1099	    debug "libstate" "remove_config() - Warning: No name given for config option."
  1100	    return 1
  1101	  fi
  1102	
  1103	  local separator
  1104	
  1105	  # what to use as separator?
  1106	  if [[ $2 == command ]]
  1107	  then separator=" "
  1108	  else separator="=" ; fi
  1109	
  1110	  # remove previous reference
  1111	  lock_start_transaction "$FILE" tFILE
  1112	  grep  -v  "^[[:blank:]]*${1}${separator}" $FILE >  $tFILE
  1113	  lock_commit_transaction $FILE
  1114	
  1115	}
  1116	
  1117	#---------------------------------------------------------------------
  1118	##
  1119	## This software is free software; you can redistribute it and/or modify
  1120	## it under the terms of the GNU General Public License as published by
  1121	## the Free Software Foundation; either version 2 of the License, or
  1122	## (at your option) any later version.
  1123	##
  1124	## This software is distributed in the hope that it will be useful,
  1125	## but WITHOUT ANY WARRANTY; without even the implied warranty of
  1126	## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1127	## GNU General Public License for more details.
  1128	##
  1129	## You should have received a copy of the GNU General Public License
  1130	## along with this software; if not, write to the Free Software
  1131	## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  1132	##
  1133	#---------------------------------------------------------------------
  1134	# vim: filetype=sh:tabstop=4:shiftwidth=4:expandtab