ajout de gestion de bdd pour...
|
1 |
#!/bin/bash |
2 | ||
ré-écriture complète
|
3 |
set -e |
4 | ||
5 |
declare -A data=( |
|
6 |
[/sim/description]=text |
|
7 |
[/sim/long-description]=text |
|
8 |
[/sim/author]=text |
|
9 |
[/sim/flight-model]=text |
|
10 |
[/sim/type]=text |
|
11 |
[/sim/model/path]=text |
|
12 |
) |
|
ajout de gestion de bdd pour...
|
13 |
fgaddon_url=https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft |
14 |
fgaddon_svn=https://svn.code.sf.net/p/flightgear/fgaddon/trunk/Aircraft |
|
many improvement
|
15 |
fgaddon_path=$HOME/.fgfs/flightgear-fgaddon/Aircraft |
ré-écriture complète
|
16 |
database=${DB:-$0.db} |
17 |
#locale=fr |
|
18 | ||
19 |
test -r "$0.conf" && source $0.conf && echo config red |
|
20 | ||
ajout de gestion de bdd pour...
|
21 | |
22 |
aircrafts=$(mktemp --dry-run /dev/shm/Aircraft-XXXXXXXXX) |
|
23 |
aircraft=$(mktemp --dry-run /dev/shm/aircraft-XXXXXXX) |
|
24 |
setxml=$(mktemp --dry-run /dev/shm/setxml-XXXXXXXX) |
|
25 |
in_ram_database=$(mktemp --dry-run /dev/shm/XXXXXXX) |
|
26 | ||
27 | ||
ré-écriture complète
|
28 |
function xmlgetnext () { |
29 |
local IFS='>' |
|
30 |
read -d '<' TAG VALUE |
|
31 |
# by design, the first TAG/VALUE pair is empty |
|
32 |
# to avoid infinite loops at end of file parsing we return an error |
|
33 |
# the next time we find an empty TAG |
|
34 |
if test -z "$TAG"; then |
|
35 |
test ${xmlgetnext_firstentry:-1} -eq 1 && xmlgetnext_firstentry=0 || return 1; |
|
36 |
fi |
|
37 |
# process $TAG only if necessary |
|
38 |
local _TAG=$(printf '%q' $TAG) |
|
39 |
if test ${_TAG:0:1} = '$'; then |
|
40 |
TAG=$(tr '\n' ' ' <<< $TAG | sed 's/ */ /g; s/ *$//') |
|
41 |
fi |
|
ajout de gestion de bdd pour...
|
42 |
} |
43 | ||
44 |
function sqlite_request () { |
|
ré-écriture complète
|
45 |
if ! sqlite3 "$in_ram_database" <<< "$1"; then |
46 |
register_state |
|
47 |
fi |
|
48 |
} |
|
49 | ||
50 |
function xmlremovecomments () { |
|
51 |
sed -ri 's/<(!--|script>)/\n&/;s/(<\/script|--)>/&\n/' $setxml |
|
52 |
sed -ri '/<(script>|!--).*(<\/script|--)>/d;/<(script>|!--)/,/(<\/script|--)>/d' $setxml |
|
53 |
} |
|
54 | ||
55 |
function trap_break () { |
|
56 |
trap '' INT |
|
57 |
echo "stop requested" |
|
58 |
register_state |
|
ajout de gestion de bdd pour...
|
59 |
} |
60 | ||
61 |
function trap_exit () { |
|
ré-écriture complète
|
62 |
trapped_rc=$? |
63 |
trap '' INT |
|
64 |
rm -f $aircrafts $aircraft $setxml |
|
65 |
if test ! -e $in_ram_database; then |
|
66 |
exit |
|
67 |
fi |
|
68 |
test $trapped_rc -ne 0 && register_state |
|
many improvements
|
69 |
echo "updating installation status" |
ré-écriture complète
|
70 |
for ac in $(sqlite_request 'select printf("%i:%s/%s", aircrafts.id, aircrafts.name, setxml.file) |
71 |
from aircrafts inner join setxml |
|
72 |
where aircrafts.id = setxml.variantof and setxml.installed != 0;'); do |
|
many improvements
|
73 |
ac_path=${ac#*:} |
many improvement
|
74 |
if test ! -e $fgaddon_path/$ac_path-set.xml; then |
75 |
sqlite_request "update setxml set installed = 0 where file = '${ac_path#*/}' and variantof = ${ac%:*}" |
|
76 |
fi |
|
77 |
done |
|
78 |
for ac in $fgaddon_path/*/*-set.xml; do |
|
79 |
ac=${ac/$fgaddon_path} |
|
80 |
sx=${ac##*/} |
|
81 |
ac=${ac%/*} |
|
82 |
if test -d $fgaddon_path/$ac/.svn; then |
|
83 |
install_type=1 |
|
84 |
elif test -d $fgaddon_path/$ac/.git; then |
|
85 |
install_type=2 |
|
86 |
else |
|
87 |
install_type=3 |
|
88 |
fi |
|
89 |
sqlite_request "update setxml set installed = $install_type |
|
90 |
where exists ( |
|
ré-écriture complète
|
91 |
select 1 |
92 |
from aircrafts |
|
93 |
where name = '${ac/\/}' and setxml.variantof = id |
|
many improvement
|
94 |
)" |
many improvements
|
95 |
done |
ré-écriture complète
|
96 |
missing_setxml=$(sqlite_request "select name from aircrafts where id not in (select variantof from setxml)") |
97 |
if test -n "$missing_setxml"; then |
|
98 |
echo "missing setxml config: $missing_setxml" |
|
99 |
fi |
|
ajout de gestion de bdd pour...
|
100 |
if test -r "$database" && md5sum $in_ram_database | sed "s,$in_ram_database,$database," | md5sum --status -c -; then |
101 |
rm -f $in_ram_database |
|
many improvements
|
102 |
echo "no changes in $database" |
ajout de gestion de bdd pour...
|
103 |
elif test -w "$database"; then |
complete rewrite (use svn in...
|
104 |
sqlite_request "vacuum" |
ajout de gestion de bdd pour...
|
105 |
mv -f $in_ram_database "$database" |
many improvements
|
106 |
echo "database $database updated" |
ajout de gestion de bdd pour...
|
107 |
elif ! test -e "$database"; then |
108 |
mv $in_ram_database "$database" |
|
many improvements
|
109 |
echo "database $database created" |
ajout de gestion de bdd pour...
|
110 |
else |
111 |
rm -f $in_ram_database |
|
many improvements
|
112 |
echo "nothing can be done with $database !" |
ajout de gestion de bdd pour...
|
113 |
fi |
114 |
} |
|
115 | ||
ré-écriture complète
|
116 |
function register_state () { |
117 |
set +x |
|
118 |
sqlite_request "drop table if exists recover_rev" |
|
119 |
sqlite_request "create table recover_rev ( |
|
120 |
revkey text, |
|
121 |
revision integer, |
|
122 |
revauthor text, |
|
123 |
revdate integer |
|
124 |
)" |
|
125 |
for revkey in ${!revision[@]}; do |
|
126 |
sqlite_request "insert into recover_rev values ( |
|
127 |
'$revkey', |
|
128 |
${revision[$revkey]:-0}, |
|
129 |
'${revauthor[$revkey]}', |
|
130 |
${revdate[$revkey]:-0} |
|
131 |
)" |
|
132 |
done |
|
133 |
sqlite_request "drop table if exists recover_setxmlmodified" |
|
134 |
sqlite_request "create table if not exists recover_setxmlmodified ( |
|
135 |
sx text |
|
136 |
)" |
|
137 |
for sx in ${!setxmlmodified[@]}; do |
|
138 |
sqlite_request "insert into recover_setxmlmodified values ( |
|
139 |
'$sx' |
|
140 |
)" |
|
141 |
done |
|
142 |
set +x |
|
143 |
exit |
|
144 |
} |
|
145 | ||
146 |
function update_database () { |
|
147 |
echo "[ ${#revision[@]} ] ${ac:1}" |
|
ajout de gestion de bdd pour...
|
148 | |
ré-écriture complète
|
149 |
dbupdate=$(sqlite_request "select revision from aircrafts where name is '${ac:1}'") |
ajout de gestion de bdd pour...
|
150 |
if test -z "$dbupdate"; then |
complete rewrite (use svn in...
|
151 |
sqlite_request "insert into aircrafts (name, revision, date, author) |
ré-écriture complète
|
152 |
values ('${ac:1}', ${revision[$ac]}, ${revdate[$ac]}, '${revauthor[$ac]}')" |
complete rewrite (use svn in...
|
153 |
elif test $dbupdate -lt ${revision[$ac]}; then |
154 |
sqlite_request "update aircrafts set |
|
155 |
revision = ${revision[$ac]}, |
|
156 |
author = '${revauthor[$ac]}', |
|
157 |
date = ${revdate[$ac]} |
|
ré-écriture complète
|
158 |
where name is '${ac:1}'" |
ajout de gestion de bdd pour...
|
159 |
fi |
ré-écriture complète
|
160 |
id=$(sqlite_request "select id from aircrafts where name is '${ac:1}'") |
ajout de gestion de bdd pour...
|
161 | |
ré-écriture complète
|
162 |
for sx in ${!setxmlmodified[@]}; do |
163 |
unset include include_rootpath |
|
164 |
[[ "$sx" =~ ^"${ac:1}/" ]] || continue |
|
165 |
for col in ${!data[@]}; do |
|
166 |
data[$col]= |
|
167 |
done |
|
168 |
sx=${sx#*/} |
|
remove -set.xml from filenam...
|
169 |
echo " -> $sx" |
ré-écriture complète
|
170 |
if ! svn export --quiet --force $fgaddon_svn/${ac:1}/$sx-set.xml $setxml; then |
171 |
register_state |
|
172 |
fi |
|
173 |
xmlremovecomments |
|
174 |
unset xmlgetnext_firstentry property |
|
complete rewrite (use svn in...
|
175 |
while xmlgetnext; do |
ré-écriture complète
|
176 |
case "${TAG:0:1}" in |
177 |
''|'?'|'!') |
|
178 |
continue;; |
|
179 |
/) |
|
180 |
property=${property%/*};; |
|
181 |
*) |
|
182 |
if test "${TAG: -1}" != '/'; then |
|
183 |
property+=/${TAG%% *} |
|
fix syntax mistake
|
184 |
fi;; |
ré-écriture complète
|
185 |
# property+=/${TAG%% *} |
186 |
# if test "${TAG: -1}" = '/'; then |
|
187 |
# _TAG=${TAG:0:-1} |
|
188 |
# test "${_TAG#* }" != "${_TAG}" && eval "${_TAG#* }" |
|
189 |
# property=${property%/*} |
|
190 |
# fi;; |
|
191 |
esac |
|
192 | ||
193 |
if [[ "$TAG" =~ ^"PropertyList include=" ]]; then |
|
194 |
include_rootpath=${include%/*} |
|
195 |
test $include = $include_rootpath && unset include_rootpath |
|
196 |
eval $(echo ${TAG#* }) |
|
197 |
[[ "$include" =~ ^Aircraft/Generic/ ]] && unset include include_rootpath && continue |
|
198 |
if [[ "$include" =~ ^'../' ]]; then |
|
199 |
if test -n "$include_rootpath"; then |
|
200 |
if [[ "$include_rootpath" =~ '/' ]]; then |
|
201 |
include_rootpath=${include_rootpath%/*} |
|
202 |
else |
|
203 |
unset include_rootpath |
|
204 |
fi |
|
205 |
else |
|
206 |
ac_save=$ac |
|
207 |
unset ac |
|
208 |
fi |
|
209 |
include=${include/\.\.\/} |
|
210 |
fi |
|
211 |
if ! svn cat $fgaddon_svn/${ac:1}/${include_rootpath:+$include_rootpath/}$include >> $setxml; then |
|
212 |
register_state |
|
213 |
fi |
|
214 |
xmlremovecomments |
|
215 |
fi |
|
216 | ||
217 |
if [[ "$property" = /PropertyList@($data_pattern) ]]; then |
|
218 |
eval "data[${property/\/PropertyList}]=\"${VALUE//\"/\\\"}\"" |
|
219 |
data[${property/\/PropertyList}]=$(tr '\n' ' ' <<< ${data[${property/\/PropertyList}]} | sed -r 's/^\s*//;s/\s+/ /g;s/\s*$//') |
|
many improvement
|
220 |
fi |
ajout de gestion de bdd pour...
|
221 | |
ré-écriture complète
|
222 |
if test -n "$_TAG"; then |
223 |
# _TAG non-null means xml props ends with / |
|
224 |
# need to go back of last property |
|
225 |
property=${property/%\/${_TAG%% *}} |
|
226 |
unset _TAG |
|
227 |
fi |
|
many improvement
|
228 | |
ré-écriture complète
|
229 |
# continue parsing (while loop) until everything's found |
230 |
for col in ${!data[@]}; do |
|
231 |
test -z "${data[$col]}" && continue 2 |
|
232 |
done |
|
233 |
break # everything's found |
|
234 |
done < $setxml |
|
ajout de gestion de bdd pour...
|
235 | |
ré-écriture complète
|
236 |
if eval "test -z \"$data_test_null\""; then |
237 |
echo "WARNING: no info found, skipping" |
|
238 |
continue |
|
complete rewrite (use svn in...
|
239 |
fi |
240 | ||
ajout de gestion de bdd pour...
|
241 |
known=$(sqlite_request "select variantof from setxml where file is '$sx'") |
242 |
if test -n "$known"; then |
|
ré-écriture complète
|
243 |
for col in ${!data[@]}; do |
244 |
dbvalue=$(sqlite_request "select '$col' |
|
245 |
from setxml |
|
246 |
where file is '$sx' and variantof = $known") |
|
247 |
if test "$dbvalue" != "${data[$col]}" -a -n "${data[$col]}"; then |
|
248 |
sqlite_request "update setxml |
|
249 |
set '$col' = '${data[$col]//\'/\'\'}' |
|
250 |
where file is '$sx' and variantof = $known" |
|
ajout de gestion de bdd pour...
|
251 |
fi |
252 |
done |
|
253 |
else |
|
ré-écriture complète
|
254 |
values="'$sx', $id, " |
255 |
for col in ${!data[@]}; do |
|
256 |
values+="'${data[$col]//\'/\'\'}', " |
|
257 |
done |
|
258 |
values+=0 |
|
259 |
sqlite_request "insert into setxml values ($values)" |
|
260 |
fi |
|
261 |
test -n "$ac_save" && ac=$ac_save |
|
262 |
unset setxmlmodified[${ac:1}/$sx] |
|
263 |
done |
|
264 |
unset revision[$ac] |
|
265 |
} |
|
266 | ||
267 |
function apply_revision () { |
|
268 |
for ac in "${!revision[@]}"; do |
|
269 |
update_database |
|
270 |
if test -d $fgaddon_path/${ac:1}/.svn \ |
|
271 |
&& test "$(svn info --show-item=url $fgaddon_path/${ac:1})" != "$fgaddon_svn/${ac:1}" \ |
|
272 |
|| test -d $fgaddon_path/${ac:1} -a ! -d $fgaddon_path/${ac:1}/.svn; then |
|
273 |
echo "INFO: local ${ac:1} installed out from repo" >&2 |
|
ajout de gestion de bdd pour...
|
274 |
fi |
275 |
done |
|
276 |
} |
|
277 | ||
ré-écriture complète
|
278 |
trap trap_break INT |
ajout de gestion de bdd pour...
|
279 |
trap trap_exit EXIT |
280 | ||
ré-écriture complète
|
281 |
stty -echoctl |
282 | ||
283 |
declare -A revision revauthor revdate setxmlmodified files revpath |
|
284 |
data_pattern=$(printf "%s|" ${!data[@]}) |
|
285 |
data_pattern=${data_pattern:0:-1} |
|
286 |
data_test_null=$(printf '${data[%s]}' ${!data[@]}) |
|
287 | ||
288 |
if test -e $database; then |
|
289 |
cp $database $in_ram_database |
|
290 |
sql_cols=$(sqlite_request "pragma table_info(setxml)" | awk -F'|' '{printf("%s %s ", $2, $3)}') |
|
291 |
script_cols="file text variantof integer " |
|
292 |
for col in ${!data[@]}; do |
|
293 |
script_cols+="$col ${data["$col"]} " |
|
294 |
done |
|
295 |
script_cols+="installed integer " # last space is important |
|
296 |
if test "$sql_cols" != "$script_cols"; then |
|
297 |
echo "ALERT: datbase version mismatch !" |
|
298 |
exit 1 |
|
299 |
fi |
|
300 |
if sqlite_request '.tables' | grep -q 'recover_' && test -z "$1"; then |
|
301 |
echo "recovering from previous saved state" |
|
302 |
eval $(sqlite_request "select printf('revision[%s]=%u;revauthor[%s]=%s;revdate[%s]=%u;', |
|
303 |
revkey, revision, |
|
304 |
revkey, revauthor, |
|
305 |
revkey, revdate) |
|
306 |
from recover_rev") |
|
307 |
eval $(sqlite_request "select printf('setxmlmodified[%s]=1;', sx) |
|
308 |
from recover_setxmlmodified") |
|
309 |
sqlite_request "drop table recover_rev" |
|
310 |
sqlite_request "drop table recover_setxmlmodified" |
|
311 |
apply_revision |
|
312 |
exit |
|
313 |
fi |
|
314 |
fi |
|
315 | ||
316 |
sqlite_request "create table if not exists aircrafts ( |
|
317 |
id integer primary key, |
|
318 |
name text, |
|
319 |
revision integer, |
|
320 |
date integer, |
|
321 |
author text)" |
|
ajout de gestion de bdd pour...
|
322 | |
ré-écriture complète
|
323 |
sqlite_request "create table if not exists setxml ( |
324 |
file text, |
|
325 |
variantof integer, |
|
326 |
$(for col in ${!data[@]}; do printf "'%s' %s, " $col ${data[$col]}; done) |
|
327 |
installed integer)" |
|
ajout de gestion de bdd pour...
|
328 | |
complete rewrite (use svn in...
|
329 |
latest_revision=$(sqlite_request "select max(revision) from aircrafts") |
330 | ||
ré-écriture complète
|
331 |
# for debugging purpose |
332 |
if test -n "$2"; then |
|
333 |
ac=_${1%/*} |
|
334 |
revision[$ac]=1 |
|
335 |
revdate[$ac]=0 |
|
336 |
revauthor[$ac]=foobar |
|
337 |
setxmlmodified[${ac:1}/${1#*/}]=1 |
|
338 |
set -x |
|
339 |
update_database |
|
340 |
set +x |
|
341 |
exit |
|
342 |
elif test -n "$1"; then |
|
343 |
ac=_${1%/*} |
|
344 |
eval $(sqlite_request "select printf('revision[_%s]=%s;revdate[_%s]=%i;revauthor[_%s]=%s;', |
|
345 |
name, revision, |
|
346 |
name, date, |
|
347 |
name, author) |
|
348 |
from aircrafts |
|
349 |
where name = '${ac:1}'") |
|
350 |
setxmlmodified[${ac:1}/${1#*/}]=1 |
|
351 |
if test -z "${revision[$ac]}"; then |
|
352 |
echo "aircraft ${ac:1} not found" |
|
353 |
rm $in_ram_database |
|
354 |
exit |
|
355 |
fi |
|
356 |
update_database |
|
357 |
exit |
|
358 |
fi |
|
359 | ||
complete rewrite (use svn in...
|
360 |
echo "downloading FGADDON history from revision ${latest_revision:-0}" |
361 |
svn log --revision ${latest_revision:-0}:HEAD --xml --verbose $fgaddon_svn > $aircrafts |
|
362 | ||
ré-écriture complète
|
363 |
total=$(grep -c '<logentry' $aircrafts) |
364 |
progress=0 |
|
365 | ||
366 |
echo parsing history |
|
367 | ||
complete rewrite (use svn in...
|
368 |
while xmlgetnext; do |
369 |
case "$TAG" in |
|
370 |
'logentry revision='*) |
|
371 |
eval $(echo ${TAG#* }) |
|
ré-écriture complète
|
372 |
for action in ${!revpath[@]}; do |
373 |
unset revpath[$action] |
|
374 |
done |
|
complete rewrite (use svn in...
|
375 |
;; |
376 |
'author') |
|
ré-écriture complète
|
377 |
revauthor=${VALUE//\'/\'\'} |
complete rewrite (use svn in...
|
378 |
;; |
379 |
'date') |
|
380 |
revdate=$(date +%s -d "$VALUE") |
|
381 |
;; |
|
382 |
'path '*) |
|
ré-écriture complète
|
383 |
TAG=${TAG#* } |
384 |
TAG=${TAG// /;} |
|
385 |
TAG=${TAG//-/_} |
|
386 |
eval $(echo ${TAG// /;}) |
|
387 |
path=(${VALUE//\// }) |
|
388 |
if test $kind = 'file' -a ${#path[@]} -gt 3; then |
|
389 |
revpath[$action]+="$VALUE " |
|
390 |
elif test $kind = 'dir' -a ${#path[@]} -eq 3 -a $action = 'D'; then |
|
391 |
files[_${path[2]}]=0 |
|
392 |
unset revision[_${path[2]}] revauthor[_${path[2]}] revdate[_${path[2]}] |
|
393 |
for sx in ${!setxmlmodified[@]}; do |
|
394 |
[[ "$sx" =~ "${path[2]}/" ]] && unset setxmlmodified[$sx] |
|
395 |
done |
|
396 |
fi |
|
complete rewrite (use svn in...
|
397 |
;; |
398 |
'/logentry') |
|
ré-écriture complète
|
399 |
for item in ${revpath[D]}; do |
400 |
path=(${item//\// }) |
|
401 |
[[ "${path[3]}" =~ "-set.xml" ]] && unset setxmlmodified[${path[2]}/${path[3]/-set.xml}] |
|
402 |
files[_${path[2]}]=$(( --files[_${path[2]}] )) |
|
403 |
if test ${files[_${path[2]}]} -le 0; then |
|
404 |
unset revision[_${path[2]}] revauthor[_${path[2]}] revdate[_${path[2]}] |
|
many improvement
|
405 |
fi |
complete rewrite (use svn in...
|
406 |
done |
ré-écriture complète
|
407 |
for action in A M R; do |
408 |
for item in ${revpath[$action]}; do |
|
409 |
path=(${item//\// }) |
|
410 |
revision[_${path[2]}]=$revision |
|
411 |
revauthor[_${path[2]}]=$revauthor |
|
412 |
revdate[_${path[2]}]=$revdate |
|
413 |
[[ "${path[3]}" =~ "-set.xml" ]] && setxmlmodified[${path[2]}/${path[3]/-set.xml}]=1 |
|
414 |
test $action = 'A' && files[_${path[2]}]=$(( ++files[_${path[2]}] )) |
|
415 |
done |
|
416 |
done |
|
417 |
newprogress=$((++logentry * 100 / $total)) |
|
418 |
if test $(( $newprogress - $progress )) -ge ${progress_granularity:-1}; then |
|
419 |
progress=$newprogress |
|
420 |
echo "$progress% (${#revision[@]})" |
|
421 |
fi |
|
422 |
;; |
|
423 |
'/log') |
|
424 |
apply_revision |
|
complete rewrite (use svn in...
|
425 |
break |
426 |
;; |
|
427 |
esac |
|
428 |
done < $aircrafts |