/var/lib/sorcery/modules/libqueue

     1	#!/bin/bash
     2	#---------------------------------------------------------------------
     3	##
     4	## @Synopsis Set of functions used by sorcery for queue generation
     5	##
     6	## @Copyright Original version Copyright 2001 by Kyle Sallee
     7	## @Copyright Additions/Corrections Copyright 2002-2008 by the Source Mage Team
     8	##
     9	#---------------------------------------------------------------------
    10	
    11	#---------------------------------------------------------------------
    12	##
    13	## Checks all installed spells for newer versions, and creates an
    14	## install queue.
    15	##
    16	#---------------------------------------------------------------------
    17	function update_install_queue()  {
    18	  local line spell curr_version curr_updated page_dir info curr_patchlevel
    19	  local curr_sec_patch count size
    20	  local tmp_queue=$TMP_DIR/install_queue
    21	  local recheck_queue=$TMP_DIR/recheck_queue
    22	  touch $tmp_queue
    23	
    24	  message  "${CHECK_COLOR}Generating the list of spells to update... ${DEFAULT_COLOR} "
    25	
    26	  update_install_queue_sub "$tmp_queue" "$recheck_queue" || return 1
    27	  if [[ -s $recheck_queue ]]; then
    28	    (
    29	      count=0
    30	      size=$(wc -l < $recheck_queue)
    31	      while read spell; do
    32	          let count++
    33	          progress_bar $count $size 50
    34	          explode "$(search_spell_status $SPELL_STATUS "$spell")" ":" "info"
    35	          curr_updated=${info[1]}
    36	          curr_version=${info[3]}
    37	          codex_set_current_spell_by_name $spell &&
    38	          does_spell_need_update_sub "$spell" "$curr_version" \
    39	                                    "$curr_updated" "$tmp_queue"
    40	      done < $recheck_queue
    41	      clear_line
    42	    )
    43	    rm $recheck_queue
    44	  fi
    45	  lock_file $INSTALL_QUEUE
    46	  rm  -f  $INSTALL_QUEUE
    47	  sort -u $tmp_queue > $INSTALL_QUEUE
    48	  unlock_file $INSTALL_QUEUE
    49	
    50	}
    51	
    52	#---------------------------------------------------------------------
    53	##
    54	## Finds all installed spells that need an update due to security
    55	## reasons and creates an install queue.
    56	##
    57	#---------------------------------------------------------------------
    58	function update_security_install_queue()  {
    59	  local line spell page_dir info curr_sec_patch=0
    60	  local tmp_queue=$TMP_DIR/install_queue
    61	  local recheck_queue=$TMP_DIR/recheck_queue
    62	  touch $tmp_queue
    63	
    64	  message  "${CHECK_COLOR}Generating the list of spells to update for" \
    65	           "security reasons... ${DEFAULT_COLOR} "
    66	
    67	  update_install_queue_sub "$tmp_queue" "$recheck_queue" security || return 1
    68	  if [[ -s $recheck_queue ]]; then
    69	    (
    70	      count=0
    71	      size=$(wc -l < $recheck_queue)
    72	      while read spell; do
    73	          let count++
    74	          progress_bar $count $size 50
    75	          if codex_set_current_spell_by_name $spell &&
    76	             tablet_find_spell_dir $spell page_dir; then
    77	            tablet_get_security_patch $page_dir curr_sec_patch &&
    78	            diff=$(( ${SECURITY_PATCH:-0} - $curr_sec_patch ))
    79	            if (( $diff > 0 )); then
    80	              echo $spell >> $tmp_queue
    81	              clear_line
    82	              if (( $diff > 1 )); then
    83	                message "$SPELL_COLOR$spell$DEFAULT_COLOR: Security update ($diff times!)."
    84	              else
    85	                message "$SPELL_COLOR$spell$DEFAULT_COLOR: Security update."
    86	              fi
    87	            fi
    88	          fi
    89	      done < $recheck_queue
    90	      clear_line
    91	    )
    92	    rm $recheck_queue
    93	  fi
    94	
    95	  lock_file $INSTALL_QUEUE
    96	  rm  -f  $INSTALL_QUEUE
    97	  sort -u $tmp_queue > $INSTALL_QUEUE
    98	  unlock_file $INSTALL_QUEUE
    99	
   100	}
   101	
   102	#---------------------------------------------------------------------
   103	## Find all spells that need to be updated due to security reasons.
   104	## Checks the version caches and compares them to the installed one.
   105	#---------------------------------------------------------------------
   106	function find_security_updates() {
   107	  local tmp_queue=$1
   108	  local recheck_queue=$2
   109	
   110	  awk -v i=$VERSION_STATUS -v verbose=$VERBOSE_QUEUING '
   111	    # decide what to print - just the spell or also the reason
   112	    function needs_update(                diff) {
   113	      if (verbose == "on") {
   114	        diff = factor[4] - $4
   115	        if (diff > 0) {
   116	          if (diff > 1) {
   117	            print $1, "Security update (" diff " times!)."
   118	          } else {
   119	            print $1, "Security update."
   120	          }
   121	        }
   122	      } else {
   123	        if ($4 < factor[4]) {
   124	          print $1
   125	        }
   126	      }
   127	    }
   128	
   129	    {
   130	      if ( ! ($1 in map)) {
   131	        map[$1]=$0;
   132	      }
   133	    }
   134	
   135	    END {
   136	      while (getline < i) {
   137	        if ($1 in map && ! match(map[$1],"multiversioned")) {
   138	          split(map[$1], factor);
   139	          needs_update();
   140	        } else {
   141	          # multiversioned spell - do it the old way
   142	          print $1 > "/dev/stderr";
   143	        }
   144	      }
   145	    } ' > $tmp_queue 2> $recheck_queue
   146	}
   147	
   148	#---------------------------------------------------------------------
   149	## Find all spells that need to be updated (for any reason).
   150	## Checks the version caches and compares them to the installed one.
   151	#---------------------------------------------------------------------
   152	function find_updates() {
   153	  local tmp_queue=$1
   154	  local recheck_queue=$2
   155	
   156	  awk -v i=$VERSION_STATUS -v verbose=$VERBOSE_QUEUING '
   157	    # decide what to print - just the spell or also the reason
   158	    function needs_update(               reasons, diff) {
   159	      if (verbose == "on") {
   160	        # check SECURITY_PATCH first since it is the most important
   161	        diff = factor[4] - $4
   162	        if (diff > 0) {
   163	          if (diff > 1) {
   164	            reasons = reasons " Security update (" diff " times!)."
   165	          } else {
   166	            reasons = reasons " Security update."
   167	          }
   168	        }
   169	        if ($2 != factor[2]) {
   170	          reasons = reasons " New version (" factor[2] ")."
   171	        }
   172	        if ($3 < factor[3] ) {
   173	          reasons = reasons " Spell update."
   174	        }
   175	        if ($5 < factor[5]) {
   176	          reasons = reasons " UPDATED changed."
   177	        }
   178	        if (reasons != "") {
   179	          print $1, reasons
   180	        }
   181	      } else {
   182	        if ($2 != factor[2] || $3 < factor[3] || $4 < factor[4] || $5 < factor[5]) {
   183	          print $1
   184	        }
   185	      }
   186	    }
   187	
   188	    {
   189	      if ( ! ($1 in map)) {
   190	        map[$1]=$0;
   191	      }
   192	    }
   193	
   194	    END {
   195	      while (getline < i) {
   196	        if ($1 in map && ! match(map[$1],"multiversioned")) {
   197	          split(map[$1], factor);
   198	          needs_update();
   199	        } else {
   200	          # multiversioned spell - do it the old way
   201	          print $1 > "/dev/stderr";
   202	        }
   203	      }
   204	    }' > $tmp_queue 2> $recheck_queue
   205	}
   206	
   207	#---------------------------------------------------------------------
   208	## Frontend routine to encapsulate whether or not a spell needs updating
   209	## Used by lazy dependency resolution
   210	#---------------------------------------------------------------------
   211	function does_spell_need_update() {
   212	  local spell=$1
   213	  local tmp_queue=$TMP_DIR/install_queue
   214	  local recheck_queue=$TMP_DIR/recheck_queue
   215	  local rc
   216	
   217	  VERBOSE_QUEUING=on
   218	  update_install_queue_sub "$tmp_queue" "$recheck_queue" single $spell
   219	  rc=$?
   220	  rm $tmp_queue $recheck_queue
   221	  return $rc
   222	}
   223	
   224	#---------------------------------------------------------------------
   225	## The slow way of determining if a spell needs to be updated. Doesn't
   226	## use the version cache and is also needed for checking multiversioned
   227	## spells.
   228	#---------------------------------------------------------------------
   229	function does_spell_need_update_sub() {
   230	  local spell=$1
   231	  local curr_version=$2
   232	  local curr_updated=$3
   233	  local tmp_queue=$4
   234	  local message="$SPELL_COLOR$spell$DEFAULT_COLOR:"
   235	
   236	  local curr_patchlevel=0
   237	  local curr_sec_patch=0
   238	  if tablet_find_spell_dir $spell page_dir; then
   239	    curr_updated=0
   240	    tablet_get_updated $page_dir curr_updated
   241	    tablet_get_patchlevel $page_dir curr_patchlevel
   242	    tablet_get_security_patch $page_dir curr_sec_patch
   243	  fi
   244	
   245	  local diff=$(( ${SECURITY_PATCH:-0} - $curr_sec_patch ))
   246	  if (( $diff > 0 )); then
   247	    if (( $diff > 1 )); then
   248	      message="$message Security update ($diff times!)."
   249	    else
   250	      message="$message Security update."
   251	    fi
   252	  fi
   253	  if [[ $VERSION != $curr_version ]]; then
   254	    message="$message New version ($VERSION)."
   255	  fi
   256	  if (( "${PATCHLEVEL:-0}" > "$curr_patchlevel" )); then
   257	    message="$message Spell update."
   258	  fi
   259	  if (( "${UPDATED:-0}" > "${curr_updated:-0}" )); then
   260	    message="$message UPDATED changed."
   261	  fi
   262	  if [[ $message == "$SPELL_COLOR$spell$DEFAULT_COLOR:" ]]; then
   263	    # no updates found
   264	    return 1
   265	  fi
   266	  if [[ $VERBOSE_QUEUING == on ]]; then
   267	    clear_line
   268	    message "$message"
   269	  fi
   270	  echo $spell >> $tmp_queue
   271	  return 0
   272	}
   273	
   274	#---------------------------------------------------------------------
   275	## Common code between update_install_queue,
   276	## update_security_install_queue and does_spell_need_update
   277	#---------------------------------------------------------------------
   278	function update_install_queue_sub()  {
   279	  local tmp_queue=$1
   280	  local recheck_queue=$2
   281	  local type=$3
   282	  local spell=$4
   283	  local rc
   284	
   285	  if [[ -z $OLD_QUEUING_METHOD ]]; then
   286	    tablet_check_version_cache $VERSION_STATUS || return 1
   287	    local grimoire
   288	    for grimoire in $(codex_get_all_grimoires); do
   289	      if [[ -f $grimoire/$VERSION_INDEX_FILE ]]; then
   290	        cat $grimoire/$VERSION_INDEX_FILE
   291	      else
   292	        # provide a dummy version index, treating all spells as multiversioned
   293	        sed -n "s|^\(\S*\) .*$|\1 multiversioned|p" $grimoire/$SPELL_INDEX_FILE
   294	      fi
   295	    done |
   296	    if [[ $type == security ]]; then
   297	      find_security_updates "$tmp_queue" "$recheck_queue"
   298	    else
   299	      find_updates "$tmp_queue" "$recheck_queue"
   300	    fi
   301	
   302	    if [[ $type == single ]]; then
   303	      if grep -q "^$spell " "$tmp_queue"; then
   304	        sed -i "/^$spell /!d" "$tmp_queue"
   305	      elif grep -q "^$spell$" "$recheck_queue"; then
   306	        update_install_queue_sub2 $spell
   307	        return $?
   308	      else
   309	        return 2
   310	      fi
   311	    else
   312	      for spell in $(get_all_spells_with_status held); do
   313	        sed -i "/^$spell\( \|$\)/d" $tmp_queue $recheck_queue
   314	      done
   315	    fi
   316	    if [[ $VERBOSE_QUEUING == on ]]; then
   317	      local message
   318	      while read spell message; do
   319	        message "$SPELL_COLOR$spell$DEFAULT_COLOR: $message"
   320	      done < $tmp_queue
   321	      sed -i 's,^\(\S*\)\s.*$,\1,' $tmp_queue
   322	    fi
   323	    return 0
   324	  else # use the old slow method
   325	    if [[ $type == single ]]; then
   326	      update_install_queue_sub2 $spell
   327	    else
   328	      get_all_spells_with_status installed > $recheck_queue
   329	    fi
   330	  fi
   331	}
   332	
   333	# FIXME: find a proper name
   334	#---------------------------------------------------------------------
   335	## Slow higher-level check if a spell needs to be updated
   336	#---------------------------------------------------------------------
   337	function update_install_queue_sub2()  {
   338	  local spell=$1
   339	  # this is in a subshell because the caller may not want to actually load
   340	  # the spell yet
   341	  (
   342	    line=$(search_spell_status $SPELL_STATUS $spell)
   343	    codex_set_current_spell_by_name  $spell
   344	    explode "$line" ":" "info"
   345	    does_spell_need_update_sub "$spell" "${info[3]}" "${info[1]}" /dev/null
   346	  )
   347	}
   348	
   349	#---------------------------------------------------------------------
   350	## @Stdout install queue
   351	##
   352	## List files in install queue, give user chance to modify it.
   353	##
   354	#---------------------------------------------------------------------
   355	function list_install_queue() {
   356	  if [[ -f $INSTALL_QUEUE ]]; then
   357	    lock_file $INSTALL_QUEUE
   358	
   359	    echo
   360	    message -n "The following spells will be updated:"
   361	    message "${SPELL_COLOR}"
   362	    column  $INSTALL_QUEUE
   363	    message "${DEFAULT_COLOR}"
   364	
   365	    query "Do you wish to edit$FILE_COLOR $INSTALL_QUEUE $DEFAULT_COLOR?" n &&
   366	    edit_file $INSTALL_QUEUE
   367	
   368	    if [[ -s $INSTALL_QUEUE ]]; then
   369	      SPELLS=$(< $INSTALL_QUEUE)
   370	    fi
   371	
   372	    unlock_file $INSTALL_QUEUE
   373	  else
   374	    message "${MESSAGE_COLOR}No spells listed in the queue.$DEFAULT_COLOR"
   375	  fi
   376	}
   377	
   378	#---------------------------------------------------------------------
   379	## @Stdout history
   380	##
   381	## Display the history of the install queue for review
   382	##
   383	#---------------------------------------------------------------------
   384	function install_queue_history() {
   385	  local spell
   386	  # we can't use read, since the loop needs a normal stdin
   387	  for spell in $(< $INSTALL_QUEUE); do
   388	    lock_file "$SPELL_STATUS"
   389	    local date=$(grep "^${spell}:" $SPELL_STATUS | cut -d':' -f2)
   390	    unlock_file "$SPELL_STATUS"
   391	    local datedash=$(echo "$date" | sed 's,^\(....\)\(..\)\(..\)$,\1-\2-\3,')
   392	
   393	    get_new_changes "Viewing history since last update ($datedash) for spell --  ${spell}  -- :" "$date" "$(codex_find_spell_by_name $spell)/HISTORY"
   394	
   395	    if query "Would you like to ${RED}remove $SPELL_COLOR$spell$QUERY_COLOR from the install queue?" n; then
   396	      pop_install_queue "$spell"
   397	      message "${QUERY_COLOR}The spell $SPELL_COLOR$spell$QUERY_COLOR was removed from $FILE_COLOR$INSTALL_QUEUE$DEFAULT_COLOR."
   398	    fi
   399	  done
   400	}
   401	
   402	#---------------------------------------------------------------------
   403	## @param queue filename
   404	## @param items to remove ...
   405	##
   406	## The first argument is the name of the file containing the queue.
   407	## If a second argument is given, any items in the queue that match
   408	## the second argument are removed from the queue.  Otherwise, the top
   409	## line of the queue is removed, and returned.
   410	##
   411	#---------------------------------------------------------------------
   412	function pop_queue() {
   413	  local item found
   414	  local exit_code=0
   415	
   416	  [[ -f $1 ]] || return 1
   417	
   418	  esc_str "$2" item
   419	  lock_start_transaction "$1" tQUEUE_FILE
   420	  if [[ -n $item ]]; then
   421	    grep -v "^$item\$" $1 > $tQUEUE_FILE
   422	  else
   423	    found=$(sed -n 1p $1)
   424	
   425	    if [[ -z $found ]]; then
   426	      exit_code=1
   427	    else
   428	      esc_str "$found" found
   429	      grep -v "^$found$" $1 > $tQUEUE_FILE
   430	      echo $found
   431	    fi
   432	  fi
   433	  lock_commit_transaction "$1"
   434	
   435	  return $exit_code
   436	}
   437	
   438	#---------------------------------------------------------------------
   439	## @param queue filename
   440	## @param item to add
   441	## The first argument is the name of the file containing the queue.
   442	## The second argument is an item to add to the end of the queue.  If
   443	## the item exists anywhere in the queue, the item is removed from the
   444	## queue before being added at the end.
   445	##
   446	#---------------------------------------------------------------------
   447	function push_queue() {
   448	  local t_file
   449	
   450	  pop_queue "$1" "$2"
   451	
   452	  lock_start_transaction "$1" t_file
   453	  echo "$2" >> "$t_file"
   454	  lock_commit_transaction "$1"
   455	}
   456	
   457	#---------------------------------------------------------------------
   458	## @param filename
   459	##
   460	## The first argument is the name of the file that installed correctly
   461	## and will be removed from the install file (this makes a failure of
   462	## the casting of the queue not have to recast completed spells).
   463	##
   464	#---------------------------------------------------------------------
   465	function pop_install_queue() {
   466	
   467	  pop_queue  $INSTALL_QUEUE  "$1"
   468	
   469	}
   470	
   471	#---------------------------------------------------------------------
   472	## @param spell
   473	##
   474	## Adds the given spell to the install queue and removes it from the
   475	## remove queue.
   476	##
   477	#---------------------------------------------------------------------
   478	function push_install_queue() {
   479	
   480	  pop_queue   $REMOVE_QUEUE    "$1"
   481	  pop_queue   $INSTALL_QUEUE   "$1"
   482	  !  spell_installed           "$1"  &&
   483	  push_queue  $INSTALL_QUEUE   "$1"
   484	
   485	}
   486	
   487	#---------------------------------------------------------------------
   488	## @param spell
   489	##
   490	## Adds the given spell to the remove queue and removes it from the
   491	## install queue.
   492	##
   493	#---------------------------------------------------------------------
   494	function push_remove_queue() {
   495	
   496	  pop_queue   $INSTALL_QUEUE  "$1"
   497	  pop_queue   $REMOVE_QUEUE   "$1"
   498	  spell_installed             "$1"  &&
   499	  push_queue  $REMOVE_QUEUE   "$1"
   500	
   501	}
   502	
   503	
   504	#---------------------------------------------------------------------
   505	##
   506	## This software is free software; you can redistribute it and/or modify
   507	## it under the terms of the GNU General Public License as published by
   508	## the Free Software Foundation; either version 2 of the License, or
   509	## (at your option) any later version.
   510	##
   511	## This software is distributed in the hope that it will be useful,
   512	## but WITHOUT ANY WARRANTY; without even the implied warranty of
   513	## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   514	## GNU General Public License for more details.
   515	##
   516	## You should have received a copy of the GNU General Public License
   517	## along with this software; if not, write to the Free Software
   518	## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   519	##
   520	#---------------------------------------------------------------------