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