-
Notifications
You must be signed in to change notification settings - Fork 38
/
foswiki-upgrade-check
executable file
·283 lines (255 loc) · 10.4 KB
/
foswiki-upgrade-check
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#!/bin/bash
set -a
USAGE='foswiki-upgrade-check [options] install_dir old_release new_release
This allows you to check what a foswiki upgrade would do, and perform it
with interactive merging. Arguments are:
- install_dir your foswiki installation directory
- old_release a directory containing the distributed release for it
- new_release a directory containing the distributed new version
e.g:
foswiki-upgrade-check /www/fw /tmp/Foswiki-1.0.4 /tmp/Foswiki-1.0.5
By default it just list the files that conflicts and would need a merge.
This is useful, as it allows you to make a list of these files for later use
by -mfd or -nom. For instance, if you have a production foswiki on a distant
server that you can copy locally on your dev machine, you can:
foswiki-upgrade-check on prod, save output in a file V
foswiki-upgrade-check -y on a local copy on dev
make a tar on local of files listed in V, upload to prod
foswiki-upgrade-check -y -nom on prod, then untar your tar in prod
Options:
-v verbose: lists all operations that will be done
-a list all files that would be modified, not just the to merge ones.
-s do not merge, but show the diffs for all conflicts (use kdiff3)
-y yes, really "do it" performs the copy & merge
you must have write permission to the install_dir files.
Please make a BACKUP before!!!
If you do not want to make a full backup, you can backup the files
listed with the -a option that will be changed by the upgrade.
-r remove any files missing from the new release. (optional)
-l list all files of the installation that will be probed for upgrade
-kd3 use kdiff3 to perform interactive merges (default)
-xxd use xxdiff to perform interactive merges
-tkd use tkdiff to perform interactive merges
-mld use meld to perform interactive merges
-mfd DIR do not merge interactively, but instead in case of conflict take
file from DIR. Useful if DIR is a copy of your prod instance you
upgraded previously to test things and do not want to repeat manual
process and copy what you did there
-nom no merge, for all conflicts keep your files
PS: do not forget to fix files permissions after this, for instance by a
chown -R apache:apache ., chown -R www-data:www-data ., chmod -R a+rwX .
depending on your installation
PS: the "new_release" dir can also be the distributed "upgrade" package, but
it is advised to use the full release for the new version as otherwise small
discrepencies may appear on susequent upgrades
To upgrade a server with no graphical environment (remote), do:
* run foswiki-upgrade-check on the server to list the conflicting files.
take note of them for instance by a: (I O N are the installation, old and
new dirs respectively)
foswiki-upgrade-check $I $O $N >/tmp/fwu.list
Do a backup via:
cd $I; tar cfz /tmp/wiki-backup.tgz $(foswiki-upgrade-check -a $I $O $N)
* copy the server install on your local workstation, by
rsync -aHSx --delete --force SERVER:SRC/ DEST/
If your installation is big, you can copy only the useful files for this
upgrade by copying and untarring /tmp/fwi.tgz made on the server by:
tar cfz /tmp/fwi.tgz $(foswiki-upgrade-check -l $I $O $N)
* do the "foswiki-upgrade-check -y" locally (in DEST/) with your graphical
merge tool
* either re-upload your upgraded local copy to another place on the server
(lets say /tmp/fwu ), or better just the resolved conflicts:
rsync -aHSx --delete --force -R `cat /tmp/fwu.list` SERVER:/tmp/fwu/
if you copied /tmp/fwu.list from the server to your workstation
* on the server, perform the automatic merge with
foswiki-upgrade-check -y -mfd /tmp/fwu $I $O $N
v1.0 2009-04-26 published on http://foswiki.org/Support/HowDoIUpgradeSafelyACustomizedFoswikiInstallation
v1.1 2009-08-18 -nom was not working
v1.2 2009-09-22 -s option, kdiff3 merge is now automatic if no conflicts
detects case where file is new but different
avoid merging binary files, just copy over.
v1.3 2010-02-26 dir arguments can now be relative
v1.4 2010-03-28 -a and -l options to help backuping
v1.5 2010-09-23 -f option
v1.6 2011-01-07 -r option (remove missing files). Also prompt for optional merge.
v1.7 2011-02-16 Use jot if seq command does not exist (FreeBSD)
V1.8 2011-02-19 exclude commonly tailored files, Better handle files missing from old release
'
merge=merge_kdiff3
doit=false
dolist=false
listall=false
verbose=false
remove=false
mfd=
showdiff=
seqcmd=true
excluded=( WebHome.txt WebPreferences.txt WebStatistics.txt WebNotify.txt SitePreferences.txt AdminGroup.txt TrashAttachment.txt )
doseq () { if $seqcmd; then seq $@; else jot - $@; fi; }
function elementExists()
{
file=${1##*/}
if [ -z "$file" ]
then
return
fi
for exfile in ${excluded[@]}
do
if [ $exfile == $file ]
then
return 0
fi
done
return 1
}
# Determine if the seq command is useful, otherwise we use jot
if command -v seq &>/dev/null
then
seqcmd=true
else
seqcmd=false
fi
# Options processing
while test "_${1#-}" != "_$1" -a "_${1//-/}" != "_";do case "$1" in
-kd3) merge=merge_kdiff3;;
-tkd) merge=merge_tkdiff;;
-xxd) merge=merge_xxdiff;;
-mld) merge=merge_meld;;
-mfd) merge=merge_mfd; mfd=$2;shift;;
-nom) merge=merge_none;;
-s) showdiff=show_kdiff3;;
-a) dolist=true;;
-l) listall=true;;
-y) doit=true;;
-v) verbose=true;;
-r) remove=true;;
*) echo "$USAGE"; exit 1;
esac;shift; done; if test "_$1" = "_--";then shift; fi
if test $# != 3; then echo ERROR: 3 arguments needed; echo "$USAGE"; exit 1; fi
for d in "$@" $mfd; do
if test ! -e $d/lib/Foswiki.pm; then
echo ERROR: "$d" is not a foswiki directory; exit 1
fi
done
I="$1"; O="$2"; U="$3"
case "$I" in /*) : ;; *) I="$PWD/$I";; esac
case "$O" in /*) : ;; *) O="$PWD/$O";; esac
case "$U" in /*) : ;; *) U="$PWD/$U";; esac
V () { if $verbose; then echo "$@"; fi; }
doit () { if $doit; then "$@"; fi; }
dolist () { if ! $doit; then if $dolist; then echo $1; fi; fi; }
if $listall; then
cd $I; for d in "$O" "$U";do ( cd $d; find * -type f );done|sort|uniq \
| while read f; do if test -e "$f"; then echo "$f";fi;done
exit 0
fi
# merge args are is the file, merge into installation
merge_kdiff3 () { kdiff3 -m --auto $orig $I/$1 $U/$1 -o $I/$1; }
show_kdiff3 () { kdiff3 $orig $I/$1 $U/$1; }
merge_tkdiff () { tkdiff -a $orig -o $I/$1 $I/$1 $U/$1; }
merge_xxdiff () { xxdiff --show-merged-pane -O -m -M $I/$1 $I/$1 $orig $U/$1; }
merge_meld () { meld $orig $I/$1 $U/$1; }
merge_mfd () { cp $mfd/$1 $I/$1; }
merge_none () { :; }
is_binary () {
case "$1" in
*.gif|*.GIF|*.png|*.PNG|*.jpg|*.JPG|*.gz|*.GZ) return 0;;
*) return 1;;
esac
}
# I is the installed wiki,
# O the old distribution used to install it,
# U the new upgrade or full distrib
cd $U
file_list=( $(find * -type f) )
for element in $(doseq 0 $((${#file_list[@]} - 1))); do
i=${file_list[$element]}
if elementExists $i; then
echo "SKIPPING $U/$i - file is not normally updated"
continue
fi
#echo "Processing file $i "
if test -e $I/$i; then # File exists in installed Wiki
if ! cmp -s $i $I/$i; then # Installed not same as New
if cmp -s $O/$i $I/$i; then # Old same as installed
V $i LOCALLY_SAME, DIST_CHANGED, COPY
doit cp $U/$i $I/$i
dolist $i
elif cmp -s $i $O/$i; then
V $i LOCALLY_CHANGED, DIST_SAME. KEEP
else # Old file has changed
if test ! -e $O/$i; then
V $i NEW FILE, BUT DIFFERENT IN LOCAL AND UPGRADE
echo "WARNING: New file $U/$i conflicts with existing file $I/$i "
orig=/dev/null
else
V $i CONFLICT, MERGE
orig=$O/$i
fi
if $doit; then
if is_binary "$i"; then
echo "WARNING: copied $U/$i over your $I/$i . Revert if wrong"
doit cp $U/$i $I/$i
dolist $i
else
echo "How do you want to handle conflict: $U/$i ?"
select ans in "Merge files" "Keep original" "Use new file"
do
echo "Answer $ans "
case $ans in
"Merge files" ) echo "merge"; doit $merge $i; break;;
"Keep original" ) echo "keeping original"; break;;
"Use new file" ) echo "using new"; doit cp $U/$i $I/$i; break;;
esac
done
fi
elif test -n "$showdiff"; then
if is_binary "$i"; then ls -l $orig $I/$1 $U/$1
else $showdiff $i
fi
else echo $i
fi
fi
else
V $i SAME, IGNORE
fi
else
V $i NEW FILE, COPY
if $doit; then
dir=$I/$i; dir=${dir%/*}
if test ! -d $dir; then mkdir -p $dir; fi
cp $U/$i $I/$i
fi
fi
done
if $remove; then
cd $O
old_list=( $(find * -type f) )
for element in $(doseq 0 $((${#old_list[@]} - 1))); do
i=${old_list[$element]}
if test -e $I/$i; then
if test ! -e $U/$i; then
if ! cmp -s $i $I/$i; then
V $i LOCALLY_MODIFIED, DIST_REMOVED, REMOVE
if $doit; then
echo "Warning, file to be removed has been locally modified: $U/$i ?"
echo "How do you want to handle conflict: ?"
select ans in "Keep original" "Remove anyway"
do
echo "Answer $ans "
case $ans in
"Keep original" ) echo "keeping original"; break;;
"Remove anyway" ) echo "removing anyway"; doit rm -v $I/$i; break;;
esac
done
fi
else
V $i LOCALLY_PRESENT, DIST_REMOVED, REMOVE
doit rm -v $I/$i
if ! $doit; then
echo "$i (remove)"
fi
fi
fi
fi
done
fi