OSDN Git Service

Fixed a bug that the last counter was invisible.
[portsreinstall/current.git] / lib / libprogram.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - Program control -
5 # Copyright (C) 2013-2018 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Variables =============
10 PROGRAM_DEPENDS=        # Processes on which the current process depends
11 PROGRAM_NUM_STEPS=      # [Used in _program_exec_restartable_loop_operation__routine] Total number of routine steps
12 PROGRAM_STEP_PROGRESS=  # [Used in _program_exec_restartable_loop_operation__routine] Current progress as the finished number of routine steps
13 PROGRAM_STEP_COUNTER=   # [Used in _program_exec_restartable_loop_operation__routine] Counter string indicating the current progress
14 PROGRAM_STAGETAG=       # [Used in _program_exec_restartable_loop_operation__routine] Current stage tag
15 PROGRAM_STEP_COUNTER_LAST_SKIPPED=no    # Whether the last iteration was skipped
16
17 # ============= Check completion of a stage =============
18 program_chk_stage_complete ()
19 {
20         local stagetag
21         stagetag=$1
22         [ -e "${DBDIR}/stage.complete/$stagetag" ]
23 }
24
25 # ============= Check completion of a loop in a stage =============
26 program_chk_stage_loop_complete ()
27 {
28         local stagetag
29         stagetag=$1
30         program_chk_stage_complete "$stagetag" && return
31         [ -e "${DBDIR}/stage.reinit_loop/$stagetag" ]
32 }
33
34 # ============= Check completion of a loop in a stage =============
35 program_chk_stage_loop_complete ()
36 {
37         local stagetag
38         stagetag=$1
39         program_chk_stage_complete "$stagetag" && return
40         [ -e "${DBDIR}/stage.reinit_loop/$stagetag" ]
41 }
42
43 # ============= Register completion of a stage =============
44 program_register_stage_complete ()
45 {
46         local stagetag
47         stagetag=$1
48         rm -f "${DBDIR}/stage.reinit_loop/$stagetag"
49         mkdir -p "${DBDIR}/stage.complete"
50         touch "${DBDIR}/stage.complete/$stagetag"
51 }
52
53 # ============= Reset the loop counter of a stage =============
54 program_reset_loop_for_stage ()
55 {
56         local stagetag
57         stagetag=$1
58         mkdir -p "${DBDIR}/stage.reinit_loop"
59         touch "${DBDIR}/stage.reinit_loop/$stagetag"
60 }
61
62 # ============= Deregister completion of a stage =============
63 program_deregister_stage_complete ()
64 {
65         local stagetag
66         stagetag=$1
67         program_reset_loop_for_stage "$stagetag"
68         rm -f "${DBDIR}/stage.complete/$stagetag"
69 }
70
71 # ============= Register stages on which a stage depends =============
72 program_register_stage_depends ()
73 {
74         local stagetag prefix_rpl
75         stagetag=$1
76         shift
77         mkdir -p "${DBDIR}/stage.depends"
78         prefix_rpl=`str_escape_replaceval "${DBDIR}/stage.depends/"`
79         while [ $# -gt 0 ]
80         do
81                 fileedit_add_a_line_if_new "$stagetag" "${DBDIR}/stage.depends/$1"
82                 shift
83         done
84 }
85
86 # ============= Reset stages which depend on a stage =============
87 program_reset_depending_stages ()
88 {
89         local stagetag prefix_rpl
90         stagetag=$1
91         [ -e "${DBDIR}/stage.depends/$stagetag" ] || return 0
92         while read stagetag_dependent
93         do
94                 program_deregister_stage_complete "$stagetag_dependent"
95         done < ${DBDIR}/stage.depends/$stagetag
96 }
97
98 # ============= Define the default operation for program_exec_and_record_completion =============
99 program_reset_exec_and_record_completion_operation ()
100 {
101         _program_exec_and_record_completion__operation ()
102         {
103                 echo "ERROR: [Internal] _program_exec_and_record_completion__operation is undefined." .&2
104                 exit 1
105         }
106         PROGRAM_DEPENDS=
107 }
108 program_reset_exec_and_record_completion_operation
109
110 # ============= Execute an operation and record its completion =============
111 program_exec_and_record_completion ()
112 {
113         local stagetag PROGRAM_IS_LOOP_TO_BE_INIT
114         stagetag=$1
115         shift
116         if ! program_chk_stage_complete "$stagetag"
117         then
118                 PROGRAM_STAGETAG=$stagetag
119                 program_register_stage_depends "$stagetag" $PROGRAM_DEPENDS
120                 _program_exec_and_record_completion__operation "$@"
121                 program_reset_depending_stages "$stagetag"
122                 program_register_stage_complete "$stagetag"
123         fi
124         program_reset_exec_and_record_completion_operation
125 }
126
127 # ============= Define the default operation for program_exec_and_record_completion =============
128 program_reset_exec_restartable_loop_operation ()
129 {
130         _program_exec_restartable_loop_operation__routine ()
131         {
132                 local item
133                 item=$1
134                 echo "ERROR: [Internal] _program_exec_restartable_loop_operation__routine is undefined." .&2
135                 exit 1
136         }
137 }
138 program_reset_exec_restartable_loop_operation
139
140 # ============= Execute a restartable loop operation =============
141 program_exec_restartable_loop_operation ()
142 {
143         local inputdb tmp_diff looplist nlines iline item
144         inputdb=$1
145         tmp_diff=${TMPDIR}/program_exec_restartable_loop_operation:diff
146         looplist=${DBDIR}/stage.loop_list/$inputdb
147         if fileedit_manipulate_new_lines "$looplist.prev" "$looplist" > $looplist.remain.new
148         then
149                 if [ -f "$looplist.remain" -a ! -e "${DBDIR}/stage.reinit_loop/$PROGRAM_STAGETAG" ]
150                 then
151                         sort -u "$looplist.remain" "$looplist.remain.new" > $looplist.remain.tmp
152                         mv "$looplist.remain.tmp" "$looplist.remain"
153                 fi
154                 cat "$looplist" 2> /dev/null > $looplist.tmp || :
155                 mv "$looplist.tmp" "$looplist.prev"
156         fi
157         if [ -f "$looplist.remain" -a ! -e "${DBDIR}/stage.reinit_loop/$PROGRAM_STAGETAG" ]
158         then
159                 message_restarted_process
160         else
161                 cat "$looplist" 2> /dev/null > $looplist.remain.tmp || :
162                 mv "$looplist.remain.tmp" "$looplist.remain"
163                 rm -f "${DBDIR}/stage.reinit_loop/$PROGRAM_STAGETAG"
164         fi
165         cp "$looplist.remain" "${TMPDIR}/$inputdb.input"
166         PROGRAM_NUM_STEPS=`cat "$looplist" 2> /dev/null | wc -l | tr -d ' '` || :
167         nlines=`wc -l < ${TMPDIR}/$inputdb.input`
168         PROGRAM_STEP_PROGRESS=$(($PROGRAM_NUM_STEPS-$nlines))
169         iline=1
170         PROGRAM_STEP_COUNTER_LAST_SKIPPED=no
171         while [ $iline -le $nlines ]
172         do
173                 item=`sed -n ${iline}p "${TMPDIR}/$inputdb.input"`
174                 iline=$(($iline+1))
175                 PROGRAM_STEP_PROGRESS=$(($PROGRAM_STEP_PROGRESS+1))
176                 PROGRAM_STEP_COUNTER="[$PROGRAM_STEP_PROGRESS/$PROGRAM_NUM_STEPS $(($PROGRAM_STEP_PROGRESS*100/$PROGRAM_NUM_STEPS))%]"
177                 if ! grep -q -Fx "$item" "$looplist.remain" 2> /dev/null
178                 then
179                         [ $iline -gt $nlines ] && PROGRAM_STEP_COUNTER_LAST_SKIPPED=yes
180                         continue
181                 fi
182                 _program_exec_restartable_loop_operation__routine "$item"
183                 fileedit_rm_a_line "$item" "$looplist.remain"
184         done
185         program_reset_exec_restartable_loop_operation
186 }