fix docutils-test cleanup before installing new version
[docutils/kirr.git] / sandbox / infrastructure / release.sh
blobf3bd9b0594cc0a39108718c1b590c96fb0fed556
1 #!/bin/bash
3 # Author: Lea Wiemann
4 # Contact: LeWiemann@gmail.com
5 # Revision: $Revision$
6 # Date: $Date$
7 # Copyright: This script has been placed in the public domain.
9 # USAGE see: docutils/docs/dev/release.txt
11 set -e
13 function print_command()
15 # Print "$@", quoting parameters containing spaces.
16 echo -n $
17 for param in "$@"; do
18 echo "$param" | grep -Fq ' ' && echo -n " '$param'" || echo -n " $param"
19 done
22 function run()
24 # Print and run "$@".
25 print_command "$@"
26 echo
27 "$@"
30 function confirm()
32 # Print, let the user confirm and run "$@".
33 echo 'Press enter to run (or enter anything to skip):'
34 print_command "$@"
35 read
36 test "$REPLY" && echo Skipped. || "$@"
39 function svn_up()
41 if test $svn == svk; then
42 confirm svk sync "$depot"
44 confirm $svn up
47 function checkin()
49 # Parameters: log_message, file, file, file ...
50 log_message="$1"
51 shift
52 confirm $svn diff "$@"
53 confirm $svn ci -m "$log_prefix $log_message" "$@"
56 function set_ver()
58 # Parameters: old_version new_version
59 shopt -s extglob
60 echo Determining list of files to be changed...
61 # BUG ls lists directories but does not descend
62 files="docutils/__init__.py setup.py `$svn ls test/functional/expected/ | sed 's|^|test/functional/expected/|'`"
63 echo "Now I'll change the version number to $2 in the following files:"
64 echo $files
65 echo
66 echo 'Press enter to proceed (or enter anything to skip)...'
67 read
68 if [ ! "$REPLY" ]; then
69 echo 'Modifying files with ed...'
70 old_ver_regex="`echo "$1" | sed 's/\./\\\\./g'`"
71 # "ed" returns an error code if there has been no substitution, so
72 # we temporarily deactivate exit-on-error.
73 set +e
74 for F in $files; do
75 (echo ",s/$old_ver_regex/$2/g"; echo 'wq') | ed "$F"
76 done
77 set -e
79 echo
80 echo 'CAUTION: please look at the diffs carefully, for wrongly'
81 echo ' replaced embedded numbers.'
82 checkin "set version number to $2" $files
85 function usage()
87 echo 'Usage:'
88 echo
89 echo ' release.sh new_version svn_version[:branch_version] [stage]'
90 echo
91 echo 'The following things will be done:'
92 echo
93 echo '* Change version number to new_version. (stage 1)'
94 echo '* SVN-export, test, and release Docutils version new_version. (stage 2)'
95 echo '* Change version number to svn_version. (stage 3)'
96 echo
97 echo 'If stage is supplied (1, 2 or 3), only the specified stage will'
98 echo 'be executed. Otherwise, it defaults to executing all stages.'
99 echo
100 echo 'Before doing dangerous things, you will be asked to press enter.'
101 echo
102 echo 'A maintenance branch called docutils-new_version will be created'
103 echo 'if branch_version is given. The version number inside the'
104 echo 'maintenance branch will be set to branch_version.'
105 echo
106 echo 'Access ssh,scp and sftp access to shell/frs.sourceforge.net'
107 echo 'must be configured.'
108 exit 1
111 function initialize()
113 if [ "$#" -lt 2 ]; then
114 usage
116 echo 'Initializing...'
117 python_versions='2.3 2.4 2.5 2.6 2.7'
118 for py_ver in $python_versions; do
119 echo -n "Checking for Python $py_ver (python$py_ver)... "
120 if ! echo 'print "OK"' | python$py_ver; then
121 echo "Python $py_ver (python$py_ver) not found."
122 echo Aborting.
123 exit 1
125 done
126 echo -n 'Clearing $PYTHONPATH... '
127 export PYTHONPATH=
128 echo 'done'
129 echo -n 'Checking whether we are in a working copy... '
130 if [ -f HISTORY.txt ]; then
131 echo yes
132 else
133 echo "no (HISTORY.txt doesn't exist)"
134 echo 'Aborting.'
135 echo 'Please cd to a working copy before running this script.'
136 exit 1
138 echo -n 'Subversion binary to use: '
139 if [ -d .svn ]; then
140 svn=svn
141 else
142 svn=svk
144 echo $svn
145 working_copy="`pwd -P`"
146 echo "Working copy: $working_copy"
147 if test $svn = svk; then
148 depot_path="`svk info . | grep ^Depot\ Path: | sed 's/Depot Path: //'`"
149 depot="`echo "$depot_path" | sed 's|\(//[^/]\+/[^/]\+\).*|\1|'`"
150 echo "SVK depot: $depot"
151 mirrored_from="`svk info . | grep ^Mirrored\ From: | sed 's/Mirrored From: //;s/, Rev\. .*//'`"
152 svnurl="$mirrored_from`echo "$depot_path" | sed 's|//[^/]\+/[^/]\+||'`"
153 else
154 svnurl="`$svn info . | grep ^URL: | sed 's/URL: //'`"
156 if test -z "$svnurl"; then
157 echo 'Unable to detect Subversion URL. Aborting.'
158 exit 1
160 echo "Subversion URL: $svnurl"
161 if ! echo "$svnurl" | grep -q 'branches\|trunk'; then
162 echo 'Subversion URL contains neither "branches" nor "trunk".'
163 echo 'Aborting.'
164 exit 1
166 svnroot="`echo "$svnurl" | sed 's/\/\(branches\|trunk\).*//'`"
167 echo "Subversion root URL: $svnroot"
168 if test "$svnurl" = "$svnroot"; then
169 echo 'Error: Subversion URL and Subversion root URL are the same.'
170 exit 1
172 echo -n 'Detecting current Docutils version... '
173 old_ver="`python -c 'import docutils; print docutils.__version__'`"
174 echo "$old_ver"
175 new_ver="$1"
176 # log_prefix is for SVN logs.
177 log_prefix="Release $new_ver:"
178 echo "New version number (for releasing): $new_ver"
179 svn_ver="$2"
180 if echo "$svn_ver" | grep -q :; then
181 # Split at colon: svn_ver:branch_ver
182 branch_ver="${svn_ver#*:}"
183 svn_ver="${svn_ver%:*}"
184 else
185 branch_ver=
187 echo "New Subversion version number (after releasing): $svn_ver"
188 echo -n 'Create maintenance branch: '
189 if test "$branch_ver"; then
190 echo yes
191 echo "New version number on maintenance branch: $branch_ver"
192 else
193 echo no
195 if test "$branch_ver"; then
196 echo -n 'Checking that we have a full checkout... '
197 if echo "$working_copy" | grep -q 'branches\|trunk'; then
198 echo OK
199 else
200 echo 'no'
201 echo 'Working copy path contains neither "branches" nor "trunk".'
202 echo 'You need a full checkout in order to branch.'
203 echo 'Aborting.'
204 exit 1
206 wcroot="`echo "$working_copy" | sed 's/\/\(branches\|trunk\).*//'`"
207 echo "Working copy root: $wcroot"
209 tarball=docutils-"$new_ver".tar.gz
210 echo "Tarball name: $tarball"
211 echo 'Initialization completed.'
212 echo
215 function test_tarball()
217 # Assume we have the tarball in the current directory.
218 # Pass test number as first parameter.
219 echo 'Testing the release tarball.'
220 run mkdir tarball_test/
221 run cd tarball_test/
222 confirm tar xzvf "../$tarball"
223 echo
224 run cd docutils-"$new_ver"
225 echo 'Installing the distribution.'
226 # Extra files, with leading comma.
227 extras="`cd extras; for extrafile in *.py; do echo -n ",$extrafile{,c,o}"; done`"
228 confirm su -c '
229 for py_ver in '"$python_versions"'; do
230 echo "Deleting and installing Docutils on Python $py_ver."
231 echo "Press enter."
232 read
233 site_packages="/usr/local/lib/python$py_ver/site-packages"
234 echo "BUG prefers /usr/local too /usr"
235 if test ! -d "$site_packages"; then
236 site_packages="/usr/lib/python$py_ver/site-packages"
238 if test ! -d "$site_packages"; then
239 echo "Error: \"$site_packages\" does not exist."
240 exit 1
242 if test -e "$site_packages/docutils-test"; then
243 echo "Error: \"$site_packages/docutils-test\" exists."
244 echo "removing left over from previous releae. Ctrl-C to abort."
245 read
246 rm -rf $site_packages/docutils-test
248 rm -rfv /usr/{local,}lib/python$py_ver/site-packages/{docutils'"$extras"'}
249 python$py_ver setup.py install
250 echo
251 echo "Copying the test suite to the site-packages directory of Python $py_ver."
252 echo "Press enter."
253 read
254 cp -rv test "$site_packages/docutils-test"
255 done'
256 echo
257 echo 'Running the test suite as root with all Python versions.'
258 for py_ver in $python_versions; do
259 site_packages="/usr/local/lib/python$py_ver/site-packages"
260 if test ! -d "$site_packages"; then
261 site_packages="/usr/lib/python$py_ver/site-packages"
263 if test ! -d "$site_packages"; then
264 echo "Error: \"$site_packages\" does not exist."
265 exit 1
267 # BUG
268 echo "shell script exits if any test fails, maybe run in separate shell."
269 confirm su -c "python$py_ver -u \"$site_packages/docutils-test/alltests.py\""
270 done
271 run cd ../..
272 echo "Cleaning up..."
273 confirm su -c "rm -rf tarball_test"
274 confirm su -c '
275 for py_ver in '"$python_versions"'; do
276 rm -rfv /usr{/local,}/lib/python$py_ver/site-packages/docutils{-test,}
277 done'
278 echo
281 function upload_tarball()
283 # Assume we have the tarball in the working area.
284 run cd "$working_area"
285 mkdir $new_ver
286 cp docutils-$new_ver.tar.gz $new_ver
287 cp docutils/RELEASE-NOTES.txt $new_ver
288 # README.txt would be displayed automatically on sf.
289 cp docutils/RELEASE-NOTES.txt $new_ver/README.txt
290 # BUG user grubert hardcoded
291 # short path "/home/frs/project/docutils/docutils/" also exists
292 scp -r $new_ver grubert,docutils@frs.sourceforge.net:/home/frs/project/d/do/docutils/docutils/
293 echo 'Upload completed.'
296 function upload_htdocs()
298 # Assume we have the tarball in the working area.
299 run cd "$working_area"
300 echo "Upload htdocs for $new_ver"
301 run mkdir htdocs
302 run cd htdocs
303 confirm tar xzvf "../$tarball"
304 run cd docutils-"$new_ver"/tools/
305 # BUG no docutils installation left.
306 # BUG and it breaks on test/functional/input/standalone_rst_newlatex.txt:
307 # 1020: (SEVERE/4) Title level inconsistent
308 # because this is an include file.
309 # BUG --local .. still recurses into test
310 confirm ./buildhtml.py --local ..
311 confirm ./buildhtml.py ../docs
312 run cd ..
313 echo '$ find -name test -type d -prune -o -name \*.css -print0 \
314 -o -name \*.html -print0 -o -name \*.txt -print0 \
315 | tar -cjvf docutils-docs.tar.bz2 -T - --null'
316 find -name test -type d -prune -o -name \*.css -print0 \
317 -o -name \*.html -print0 -o -name \*.txt -print0 \
318 | tar -cjvf docutils-docs.tar.bz2 -T - --null
319 echo 'Upload docs to SF.net...'
320 echo 'Press enter (or enter anything to skip).'
321 read
322 if [ ! "$REPLY" ]; then
323 mkdir $new_ver
324 cd $new_ver
325 tar xjvf ../docutils-docs.tar.bz2
326 cd ..
327 chmod -R g+rw $new_ver
328 scp -r -p -C $new_ver web.sourceforge.net:/home/groups/d/do/docutils/htdocs
332 function create_maintenance_branch()
334 echo 'Creating maintenance branch.'
335 branch_name="docutils-$new_ver"
336 echo "Branch name: $branch_name"
337 branch_url="$svnroot/branches/$branch_name"
338 echo "Branch URL: $branch_url"
339 confirm svn cp "$svnurl" "$branch_url" -m \
340 "$log_prefix created maintenance branch for version $new_ver"
341 cd "$wcroot"
342 svn_up
343 cd branches/"$branch_name"
344 set_ver "$new_ver" "$branch_ver"
347 function run_stage()
349 if [ ! "$1" ]; then
350 run_stage 1
351 echo
352 run_stage 2
353 echo
354 run_stage 3
355 else
356 echo "Press enter to run stage $1 (or enter anything to skip this stage)."
357 read
358 if [ ! "$REPLY" ]; then
359 cd "$working_copy"
360 if [ "$1" == 1 ]; then
361 stage_1
362 elif [ "$1" == 2 ]; then
363 stage_2
364 elif [ "$1" == 3 ]; then
365 stage_3
366 else
367 echo 'Invalid stage.'
368 echo
369 usage
371 echo
372 echo "Stage $1 completed."
373 else
374 echo "Skipped stage $1."
379 function stage_1()
381 svn_up
382 echo
383 # update __version_details__ string
384 (echo ",s/^__version_details__ = .*\$/__version_details__ = 'release'/";
385 echo wq) | ed docutils/__init__.py 2> /dev/null
386 set_ver "$old_ver" "$new_ver"
387 echo
388 history_files='HISTORY.txt RELEASE-NOTES.txt'
389 echo "Now updating the following files: $history_files"
390 old_string="Changes Since [0-9.]+"
391 new_string="Release $new_ver (`date --utc --iso-8601`)"
392 echo 'Press enter to replace "'"$old_string"'" with "'"$new_string"\",
393 echo 'or enter anything to skip.'
394 read
395 test "$REPLY" || python -c "for filename in '$history_files'.split():
396 import re
397 h = file(filename).read()
398 h = re.sub('$old_string\\n=+', '$new_string\\n' + '=' * len('$new_string'), h, count=1)
399 file(filename, 'w').write(h)"
400 checkin 'closed "Changes Since ..." section' $history_files
403 function stage_2()
405 echo 'Creating working area...'
406 working_area="`echo ~/tmp/docutils-release.$$`"
407 run mkdir -p "$working_area"
408 echo
409 echo 'Getting a fresh export.'
410 echo 'Press enter to proceed (or enter anything to skip)...'
411 read
412 if [ ! "$REPLY" ]; then
413 run cd "$working_area"
414 confirm svn export "$svnurl"
415 echo
416 echo 'Building the release tarball.'
417 run cd docutils
418 confirm ./setup.py sdist
419 run cd ..
420 echo 'Tarball built.'
421 run cp docutils/dist/"$tarball" .
422 confirm test_tarball
423 echo "Testing documentation and uploading htdocs of version $new_ver..."
424 confirm upload_htdocs
425 echo "Tagging current revision..."
426 confirm svn cp "$svnurl" "$svnroot/tags/docutils-$new_ver/" -m "$log_prefix tagging released revision"
427 echo "Uploading $tarball to SF.net."
428 confirm upload_tarball
429 echo 'Now go to https://sourceforge.net/project/admin/explorer.php?group_id=38414'
430 echo 'and follow the instructions at'
431 echo 'http://docutils.sf.net/docs/dev/release.html#file-release-system'
432 echo 'BUG find your way.'
433 echo
434 echo 'Then press enter.'
435 read
437 run cd $working_area
438 echo 'Downloading the tarball to verify its integrity.'
439 while true; do
440 # BUG path is wrong. project admin filemanager shows md5sum
441 confirm wget http://osdn.dl.sourceforge.net/sourceforge/docutils/"$tarball"
442 echo 'Was the download successful?'
443 echo 'If yes, press enter to continue, otherwise enter anything to repeat'
444 echo '(it is possible that the file will show up in a few minutes).'
445 read
446 test "$REPLY" || break
447 done
448 confirm test_tarball
449 echo 'Registering with PyPI...'
450 echo 'Press enter to proceed (or enter anything to skip)...'
451 read
452 if [ ! "$REPLY" ]; then
453 echo "Unpacking tarball..."
454 ls -l
456 run tar xzvf "$tarball"
457 run cd docutils-"$new_ver"
458 confirm ./setup.py register
462 function stage_3()
464 svn_up
465 echo
466 # update __version_details__ string
467 (echo ",s/^__version_details__ = .*\$/__version_details__ = 'repository'/";
468 echo wq) | ed docutils/__init__.py 2> /dev/null
469 checkin 'set __version_details__ to "repository"'
470 echo
471 history_files='HISTORY.txt RELEASE-NOTES.txt'
472 echo "Now updating the following files: $history_files"
473 add_string="Changes Since $new_ver"
474 before="Release "
475 echo 'Press enter to add "'"$add_string"'" section,'
476 echo 'or enter anything to skip.'
477 read
478 test "$REPLY" || python -c "for filename in '$history_files'.split():
479 import re
480 h = file(filename).read()
481 h = re.sub('\n$before', '\\n$add_string\\n' + '=' * len('$add_string') +
482 '\\n\\n\\n$before', h, count=1)
483 file(filename, 'w').write(h)"
484 checkin "added empty \"Changes Since $new_ver\" section" $history_files
485 echo
486 if test "$branch_ver"; then
487 create_maintenance_branch
488 cd "$working_copy"
490 set_ver "$new_ver" "$svn_ver"
491 echo
492 echo 'Please update the web page now (web/index.txt).'
493 echo 'cd into sandbox/infrastructure'
494 echo 'and call docutils-update.local (requires linux, macosx cp misses something)'
495 echo "Press enter when you're done."
496 read
499 initialize "$@"
500 run_stage "$3"
501 echo
502 echo 'Finished.'
503 echo 'Run alltests.py on svn version now.'
505 # Local Variables:
506 # indent-tabs-mode: nil
507 # End: