WARN but do not stop if a python version is not installed
[docutils.git] / sandbox / infrastructure / release.sh
blob235a5820a1135f3b4a5459a829eb0b76eb6b6040
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.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 "WARN: Python $py_ver (python$py_ver) not found."
123 done
124 echo -n 'Clearing $PYTHONPATH... '
125 export PYTHONPATH=
126 echo 'done'
127 echo -n 'Checking whether we are in a working copy... '
128 if [ -f HISTORY.txt ]; then
129 echo yes
130 else
131 echo "no (HISTORY.txt doesn't exist)"
132 echo 'Aborting.'
133 echo 'Please cd to a working copy before running this script.'
134 exit 1
136 echo -n 'Subversion binary to use: '
137 if [ -d .svn ]; then
138 svn=svn
139 else
140 svn=svk
142 echo $svn
143 working_copy="`pwd -P`"
144 echo "Working copy: $working_copy"
145 if test $svn = svk; then
146 depot_path="`svk info . | grep ^Depot\ Path: | sed 's/Depot Path: //'`"
147 depot="`echo "$depot_path" | sed 's|\(//[^/]\+/[^/]\+\).*|\1|'`"
148 echo "SVK depot: $depot"
149 mirrored_from="`svk info . | grep ^Mirrored\ From: | sed 's/Mirrored From: //;s/, Rev\. .*//'`"
150 svnurl="$mirrored_from`echo "$depot_path" | sed 's|//[^/]\+/[^/]\+||'`"
151 else
152 svnurl="`$svn info . | grep ^URL: | sed 's/URL: //'`"
154 if test -z "$svnurl"; then
155 echo 'Unable to detect Subversion URL. Aborting.'
156 exit 1
158 echo "Subversion URL: $svnurl"
159 if ! echo "$svnurl" | grep -q 'branches\|trunk'; then
160 echo 'Subversion URL contains neither "branches" nor "trunk".'
161 echo 'Aborting.'
162 exit 1
164 svnroot="`echo "$svnurl" | sed 's/\/\(branches\|trunk\).*//'`"
165 echo "Subversion root URL: $svnroot"
166 if test "$svnurl" = "$svnroot"; then
167 echo 'Error: Subversion URL and Subversion root URL are the same.'
168 exit 1
170 echo -n 'Detecting current Docutils version... '
171 old_ver="`python -c 'import docutils; print docutils.__version__'`"
172 echo "$old_ver"
173 new_ver="$1"
174 # log_prefix is for SVN logs.
175 log_prefix="Release $new_ver:"
176 echo "New version number (for releasing): $new_ver"
177 svn_ver="$2"
178 if echo "$svn_ver" | grep -q :; then
179 # Split at colon: svn_ver:branch_ver
180 branch_ver="${svn_ver#*:}"
181 svn_ver="${svn_ver%:*}"
182 else
183 branch_ver=
185 echo "New Subversion version number (after releasing): $svn_ver"
186 echo -n 'Create maintenance branch: '
187 if test "$branch_ver"; then
188 echo yes
189 echo "New version number on maintenance branch: $branch_ver"
190 else
191 echo no
193 if test "$branch_ver"; then
194 echo -n 'Checking that we have a full checkout... '
195 if echo "$working_copy" | grep -q 'branches\|trunk'; then
196 echo OK
197 else
198 echo 'no'
199 echo 'Working copy path contains neither "branches" nor "trunk".'
200 echo 'You need a full checkout in order to branch.'
201 echo 'Aborting.'
202 exit 1
204 wcroot="`echo "$working_copy" | sed 's/\/\(branches\|trunk\).*//'`"
205 echo "Working copy root: $wcroot"
207 tarball=docutils-"$new_ver".tar.gz
208 echo "Tarball name: $tarball"
209 echo 'Initialization completed.'
210 echo
213 function test_tarball()
215 # Assume we have the tarball in the current directory.
216 # Pass test number as first parameter.
217 echo 'Testing the release tarball.'
218 run mkdir tarball_test/
219 run cd tarball_test/
220 confirm tar xzvf "../$tarball"
221 echo
222 run cd docutils-"$new_ver"
223 echo 'Installing the distribution.'
224 # Extra files, with leading comma.
225 extras="`cd extras; for extrafile in *.py; do echo -n ",$extrafile{,c,o}"; done`"
226 confirm su -c '
227 for py_ver in '"$python_versions"'; do
228 echo "Deleting and installing Docutils on Python $py_ver."
229 echo "Press enter."
230 read
231 site_packages="/usr/local/lib/python$py_ver/site-packages"
232 echo "BUG prefers /usr/local too /usr"
233 if test ! -d "$site_packages"; then
234 site_packages="/usr/lib/python$py_ver/site-packages"
236 if test ! -d "$site_packages"; then
237 echo "Error: \"$site_packages\" does not exist."
238 exit 1
240 if test -e "$site_packages/docutils-test"; then
241 echo "Error: \"$site_packages/docutils-test\" exists."
242 echo "removing left over from previous release. Ctrl-C to abort."
243 read
244 rm -rf $site_packages/docutils-test
246 rm -rfv /usr/{local,}lib/python$py_ver/site-packages/{docutils'"$extras"'}
247 echo "TODO for python3 rm local build, but building takes a long time then "
248 python$py_ver setup.py install
249 echo
250 echo "Copying the test suite to the site-packages directory of Python $py_ver."
251 echo "TODO for python3 copy test3"
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 "WARNING 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 # BUG user grubert hardcoded
290 # short path "/home/frs/project/docutils/docutils/" also exists
291 scp -r $new_ver grubert,docutils@frs.sourceforge.net:/home/frs/project/d/do/docutils/docutils/
292 echo 'Upload completed.'
295 function upload_htdocs()
297 # Assume we have the tarball in the working area.
298 run cd "$working_area"
299 echo "Upload htdocs for $new_ver"
300 run mkdir htdocs
301 run cd htdocs
302 confirm tar xzvf "../$tarball"
303 run cd docutils-"$new_ver"/tools/
304 echo "BUG no docutils installation left."
305 echo "DO NOT let call but manually in $(pwd)"
306 confirm ./buildhtml.py --local ..
307 confirm ./buildhtml.py ../docs
308 run cd ..
309 echo '$ find -name test -type d -prune -o -name \*.css -print0 \
310 -o -name \*.html -print0 -o -name \*.txt -print0 \
311 | tar -cjvf docutils-docs.tar.bz2 -T - --null'
312 find -name test -type d -prune -o -name \*.css -print0 \
313 -o -name \*.html -print0 -o -name \*.txt -print0 \
314 | tar -cjvf docutils-docs.tar.bz2 -T - --null
315 echo 'Upload docs to SF.net...'
316 echo 'Press enter (or enter anything to skip).'
317 read
318 if [ ! "$REPLY" ]; then
319 mkdir $new_ver
320 cd $new_ver
321 tar xjvf ../docutils-docs.tar.bz2
322 cd ..
323 chmod -R g+rw $new_ver
324 scp -r -p -C $new_ver web.sourceforge.net:/home/groups/d/do/docutils/htdocs
328 function create_maintenance_branch()
330 echo 'Creating maintenance branch.'
331 branch_name="docutils-$new_ver"
332 echo "Branch name: $branch_name"
333 branch_url="$svnroot/branches/$branch_name"
334 echo "Branch URL: $branch_url"
335 confirm svn cp "$svnurl" "$branch_url" -m \
336 "$log_prefix created maintenance branch for version $new_ver"
337 cd "$wcroot"
338 svn_up
339 cd branches/"$branch_name"
340 set_ver "$new_ver" "$branch_ver"
343 function run_stage()
345 if [ ! "$1" ]; then
346 run_stage 1
347 echo
348 run_stage 2
349 echo
350 run_stage 3
351 else
352 echo "Press enter to run stage $1 (or enter anything to skip this stage)."
353 read
354 if [ ! "$REPLY" ]; then
355 cd "$working_copy"
356 if [ "$1" == 1 ]; then
357 stage_1
358 elif [ "$1" == 2 ]; then
359 stage_2
360 elif [ "$1" == 3 ]; then
361 stage_3
362 else
363 echo 'Invalid stage.'
364 echo
365 usage
367 echo
368 echo "Stage $1 completed."
369 else
370 echo "Skipped stage $1."
375 function stage_1()
377 svn_up
378 echo
379 # update __version_details__ string
380 (echo ",s/^__version_details__ = .*\$/__version_details__ = 'release'/";
381 echo wq) | ed docutils/__init__.py 2> /dev/null
382 set_ver "$old_ver" "$new_ver"
383 echo
384 history_files='HISTORY.txt RELEASE-NOTES.txt'
385 echo "Now updating the following files: $history_files"
386 old_string="Changes Since [0-9.]+"
387 new_string="Release $new_ver (`date --utc --iso-8601`)"
388 echo 'Press enter to replace "'"$old_string"'" with "'"$new_string"\",
389 echo 'or enter anything to skip.'
390 read
391 test "$REPLY" || python -c "for filename in '$history_files'.split():
392 import re
393 h = file(filename).read()
394 h = re.sub('$old_string\\n=+', '$new_string\\n' + '=' * len('$new_string'), h, count=1)
395 file(filename, 'w').write(h)"
396 checkin 'closed "Changes Since ..." section' $history_files
399 function stage_2()
401 echo 'Creating working area...'
402 working_area="`echo ~/tmp/docutils-release.$$`"
403 run mkdir -p "$working_area"
404 echo
405 echo 'Getting a fresh export.'
406 echo 'Press enter to proceed (or enter anything to skip)...'
407 read
408 if [ ! "$REPLY" ]; then
409 run cd "$working_area"
410 confirm svn export "$svnurl"
411 echo
412 echo 'Building the release tarball.'
413 run cd docutils
414 confirm ./setup.py sdist
415 run cd ..
416 echo 'Tarball built.'
417 run cp docutils/dist/"$tarball" .
418 echo 'BETTER run release-test.sh manually for each installed python version.'
419 confirm test_tarball
420 echo "Testing documentation and uploading htdocs of version $new_ver..."
421 confirm upload_htdocs
422 echo "Tagging current revision..."
423 confirm svn cp "$svnurl" "$svnroot/tags/docutils-$new_ver/" -m "$log_prefix tagging released revision"
424 echo "Uploading $tarball to SF.net."
425 confirm upload_tarball
426 echo 'Now go to https://sourceforge.net/projects/docutils/files/docutils'
427 echo 'and follow the instructions at'
428 echo 'http://docutils.sf.net/docs/dev/release.html#file-release-system'
429 echo
430 echo 'Then press enter.'
431 read
433 run cd $working_area
434 echo 'Downloading the tarball to verify its integrity.'
435 while true; do
436 # BUG path is wrong. project admin filemanager shows md5sum
437 confirm wget http://sourceforge.net/projects/docutils/files/"$tarball"
438 echo 'Was the download successful?'
439 echo 'If yes, press enter to continue, otherwise enter anything to repeat'
440 echo '(it is possible that the file will show up in a few minutes).'
441 read
442 test "$REPLY" || break
443 done
444 confirm test_tarball
445 echo 'Registering with PyPI...'
446 echo 'TODO upload to pypi or set download url for this release'
447 echo 'Press enter to proceed (or enter anything to skip)...'
448 read
449 if [ ! "$REPLY" ]; then
450 echo "Unpacking tarball..."
451 ls -l
453 run tar xzvf "$tarball"
454 run cd docutils-"$new_ver"
455 confirm ./setup.py register
459 function stage_3()
461 svn_up
462 echo
463 # update __version_details__ string
464 (echo ",s/^__version_details__ = .*\$/__version_details__ = 'repository'/";
465 echo wq) | ed docutils/__init__.py 2> /dev/null
466 checkin 'set __version_details__ to "repository"'
467 echo
468 history_files='HISTORY.txt RELEASE-NOTES.txt'
469 echo "Now updating the following files: $history_files"
470 add_string="Changes Since $new_ver"
471 before="Release "
472 echo 'Press enter to add "'"$add_string"'" section,'
473 echo 'or enter anything to skip.'
474 read
475 test "$REPLY" || python -c "for filename in '$history_files'.split():
476 import re
477 h = file(filename).read()
478 h = re.sub('\n$before', '\\n$add_string\\n' + '=' * len('$add_string') +
479 '\\n\\n\\n$before', h, count=1)
480 file(filename, 'w').write(h)"
481 checkin "added empty \"Changes Since $new_ver\" section" $history_files
482 echo
483 if test "$branch_ver"; then
484 create_maintenance_branch
485 cd "$working_copy"
487 set_ver "$new_ver" "$svn_ver"
488 echo
489 echo 'Please update the web page now (web/index.txt).'
490 echo 'cd into sandbox/infrastructure'
491 echo 'and call docutils-update.local (requires linux, macosx cp misses something)'
492 echo "Press enter when you're done."
493 read
496 initialize "$@"
497 run_stage "$3"
498 echo
499 echo 'Finished.'
500 echo 'Run alltests.py on svn version now.'
502 # Local Variables:
503 # indent-tabs-mode: nil
504 # End: