Added <release:update-version> feature
authorThomas Leonard <talex5@gmail.com>
Fri, 23 Aug 2013 09:33:33 +0000 (23 10:33 +0100)
committerThomas Leonard <talex5@gmail.com>
Fri, 23 Aug 2013 10:01:28 +0000 (23 11:01 +0100)
This is an easier way to update version numbers, and is more portable as
you don't need "sed". Just pass the file to update and a regular
expression matching the version assignment. The first match group will
be replaced with the version. Example:

  <release:update-version path='main.py'>^version = '(.*)'$</release:update-version>

Note: this is sets a "-post" version after the commit, which wasn't
previously possible.

release.py
tests/test-repo.tgz
tests/testrelease.py

index 2e9d258..e3f78fb 100644 (file)
@@ -1,7 +1,7 @@
 # Copyright (C) 2009, Thomas Leonard
 # See the README file for details, or visit http://0install.net.
 
-import os, subprocess, shutil, sys
+import os, subprocess, shutil, sys, re
 from xml.dom import minidom
 from zeroinstall import SafeException
 from zeroinstall.injector import model
@@ -135,6 +135,27 @@ legacy_warning = """*** Note: the upload functions of 0release
 ***   http://www.0install.net/support.html#lists
 """
 
+def do_version_substitutions(impl_dir, version_substitutions, new_version):
+       for (rel_path, subst) in version_substitutions:
+               assert not os.path.isabs(rel_path), rel_path
+               path = os.path.join(impl_dir, rel_path)
+               with open(path, 'rt') as stream:
+                       data = stream.read()
+
+               match = subst.search(data)
+               if match:
+                       orig = match.group(0)
+                       span = match.span(1)
+                       if match.lastindex != 1:
+                               raise SafeException("Regex '%s' must have exactly one matching () group" % subst.pattern)
+                       assert span[0] >= 0, "Version match group did not match (regexp=%s; match=%s)" % (subst.pattern, orig)
+                       new_data = data[:span[0]] + new_version + data[span[1]:]
+               else:
+                       raise SafeException("No matches for regex '%s' in '%s'" % (subst.pattern, path))
+
+               with open(path, 'wt') as stream:
+                       stream.write(new_data)
+
 def do_release(local_feed, options):
        if options.master_feed_file or options.archive_dir_public_url or options.archive_upload_command or options.master_feed_upload_command:
                print(legacy_warning)
@@ -164,6 +185,8 @@ def do_release(local_feed, options):
        for phase in valid_phases:
                phase_actions[phase] = []       # List of <release:action> elements
 
+       version_substitutions = []
+
        add_toplevel_dir = None
        release_management = local_feed.get_metadata(XMLNS_RELEASE, 'management')
        if len(release_management) == 1:
@@ -175,6 +198,8 @@ def do_release(local_feed, options):
                                if phase not in valid_phases:
                                        raise SafeException("Invalid action phase '%s' in local feed %s. Valid actions are:\n%s" % (phase, local_feed.local_path, '\n'.join(valid_phases)))
                                phase_actions[phase].append(x.content)
+                       elif x.uri == XMLNS_RELEASE and x.name == 'update-version':
+                               version_substitutions.append((x.getAttribute('path'), re.compile(x.content, re.MULTILINE)))
                        elif x.uri == XMLNS_RELEASE and x.name == 'add-toplevel-directory':
                                add_toplevel_dir = local_feed.get_name()
                        else:
@@ -212,6 +237,7 @@ def do_release(local_feed, options):
                status.save()
 
                working_copy = local_impl.id
+               do_version_substitutions(local_impl_dir, version_substitutions, release_version)
                run_hooks('commit-release', cwd = working_copy, env = {'RELEASE_VERSION': release_version})
 
                print "Releasing version", release_version
@@ -229,6 +255,7 @@ def do_release(local_feed, options):
        def set_to_snapshot(snapshot_version):
                assert snapshot_version.endswith('-post')
                support.publish(local_feed.local_path, set_released = '', set_version = snapshot_version)
+               do_version_substitutions(local_impl_dir, version_substitutions, snapshot_version)
                scm.commit('Start development series %s' % snapshot_version, branch = TMP_BRANCH_NAME, parent = TMP_BRANCH_NAME)
                status.new_snapshot_version = scm.get_head_revision()
                status.save()
dissimilarity index 100%
index 6ba25e7..f96493b 100644 (file)
Binary files a/tests/test-repo.tgz and b/tests/test-repo.tgz differ
index 30719fa..787216b 100755 (executable)
@@ -126,6 +126,8 @@ class TestRelease(unittest.TestCase):
 
                assert 'Prints "Hello World"' in file('0.1/changelog-0.1').read()
                assert 'Prints "Hello World"' not in file('0.2/changelog-0.2').read()
+               new_v = file('../hello/hello.py').read()
+               assert '0.2-post' in new_v, new_v
 
        def testUncommitted(self):
                support.check_call(['tar', 'xzf', test_repo_actions])