Generated libbe/_version.py was not UTF-8 aware.
[be.git] / release.py
index 0d84127f2e2a3a28fbc6174e734598cc9dc50c8a..9e80599d6ea14b776e6a2a6e53446f493622f53b 100755 (executable)
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 #
-# Copyright (C) 2009-2010 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2009-2011 Chris Ball <cjb@laptop.org>
+#                         W. Trevor King <wking@drexel.edu>
 #
 # This file is part of Bugs Everywhere.
 #
@@ -24,7 +25,6 @@ import string
 import sys
 
 from libbe.util.subproc import Pipe, invoke
-from libbe.util.encoding import set_file_contents
 from update_copyright import update_authors, update_files
 
 
@@ -60,35 +60,32 @@ def validate_tag(tag):
 def pending_changes():
     """Use `git diff`s output to detect change.
     """
-    p = Pipe([['git', 'diff', 'HEAD']])
-    assert p.status == 0, p.statuses
-    if len(p.stdout) == 0:
+    status,stdout,stderr = invoke(['git', 'diff', 'HEAD'])
+    if len(stdout) == 0:
         return False
     return True
 
 def set_release_version(tag):
     print "set libbe.version._VERSION = '%s'" % tag
-    p = Pipe([['sed', '-i', "s/^# *_VERSION *=.*/_VERSION = '%s'/" % tag,
-               os.path.join('libbe', 'version.py')]])
-    assert p.status == 0, p.statuses
+    invoke(['sed', '-i', "s/^# *_VERSION *=.*/_VERSION = '%s'/" % tag,
+            os.path.join('libbe', 'version.py')])
 
-def remove_makefile_libbe_version_dependencies():
-    print "set Makefile LIBBE_VERSION :="
-    p = Pipe([['sed', '-i', "s/^LIBBE_VERSION *:=.*/LIBBE_VERSION :=/",
-               'Makefile']])
-    assert p.status == 0, p.statuses
+def remove_makefile_libbe_version_dependencies(filename):
+    print "set %s LIBBE_VERSION :=" % filename
+    invoke(['sed', '-i', "s/^LIBBE_VERSION *:=.*/LIBBE_VERSION :=/",
+            filename])
 
 def commit(commit_message):
     print 'commit current status:', commit_message
-    p = Pipe([['git', 'commit', '-m', commit_message]])
-    assert p.status == 0, p.statuses
+    invoke(['git', 'commit', '-a', '-m', commit_message])
 
 def tag(tag):
     print 'tag current revision', tag
-    p = Pipe([['git', 'tag', tag]])
-    assert p.status == 0, p.statuses
+    invoke(['git', 'tag', tag])
 
 def export(target_dir):
+    if not target_dir.endswith(os.path.sep):
+        target_dir += os.path.sep
     print 'export current revision to', target_dir
     p = Pipe([['git', 'archive', '--prefix', target_dir, 'HEAD'],
               ['tar', '-xv']])
@@ -96,54 +93,58 @@ def export(target_dir):
 
 def make_version():
     print 'generate libbe/_version.py'
-    p = Pipe([['make', os.path.join('libbe', '_version.py')]])
-    assert p.status == 0, p.statuses
+    invoke(['make', os.path.join('libbe', '_version.py')])
 
 def make_changelog(filename, tag):
     """Generate a ChangeLog from the git history.
 
-    Based on
-      http://stackoverflow.com/questions/2976665/git-changelog-day-by-day
+    Not the most ChangeLog-esque format, but iterating through commits
+    by hand is just too slow.
     """
     print 'generate ChangeLog file', filename, 'up to tag', tag
-    p = invoke(['git', 'log', '--no-merges', '--format="%cd"', '--date=short',
-                '%s..%s' % (INITIAL_COMMIT, tag)])
-    days = sorted(set(p.stdout.split('\n')), reverse=True)
-    log = []
-    next = None
-    for day in days:
-        args = ['git', 'log', '--no-merges', '--format=" * s"', '--since', day]
-        if next != None:
-            args.extend(['--until', next])
-        p = invoke(args)
-        log.extend(['', day, p.stdout])
-        next = day
-    set_file_contents(filename, '\n'.join(log), encoding='utf-8')
-
-def set_vcs_name(filename, vcs_name='None'):
+    invoke(['git', 'log', '--no-merges',
+            '%s..%s' % (INITIAL_COMMIT, tag)],
+           stdout=open(filename, 'w')),
+
+def set_vcs_name(be_dir, vcs_name='None'):
     """Exported directory is not a git repository, so set vcs_name to
     something that will work.
       vcs_name: new_vcs_name
     """
-    print 'set vcs_name in', filename, 'to', vcs_name
-    p = Pipe([['sed', '-i', "s/^vcs_name:.*/vcs_name: %s/" % vcs_name,
-               filename]])
-    assert p.status == 0, p.statuses
+    for directory in os.listdir(be_dir):
+        if not os.path.isdir(os.path.join(be_dir, directory)):
+            continue
+        filename = os.path.join(be_dir, directory, 'settings')
+        if os.path.exists(filename):
+            print 'set vcs_name in', filename, 'to', vcs_name
+            invoke(['sed', '-i', "s/^vcs_name:.*/vcs_name: %s/" % vcs_name,
+                    filename])
+
+def make_id_cache():
+    """Generate .be/id-cache so users won't need to.
+    """
+    invoke(['./be', 'list'])
 
 def create_tarball(tag):
     release_name='be-%s' % tag
     export_dir = release_name
     export(export_dir)
     make_version()
+    remove_makefile_libbe_version_dependencies(
+        os.path.join(export_dir, 'Makefile'))
     print 'copy libbe/_version.py to %s/libbe/_version.py' % export_dir
     shutil.copy(os.path.join('libbe', '_version.py'),
                 os.path.join(export_dir, 'libbe', '_version.py'))
     make_changelog(os.path.join(export_dir, 'ChangeLog'), tag)
-    set_vcs_name(os.path.join(export_dir, '.be', 'settings'))
+    make_id_cache()
+    print 'copy .be/id-cache to %s/.be/id-cache' % export_dir
+    shutil.copy(os.path.join('.be', 'id-cache'),
+                os.path.join(export_dir, '.be', 'id-cache'))
+    set_vcs_name(os.path.join(export_dir, '.be'))
+    os.remove(os.path.join(export_dir, 'update_copyright.py'))
     tarball_file = '%s.tar.gz' % release_name
     print 'create tarball', tarball_file
-    p = Pipe([['tar', '-czf', tarball_file, export_dir]])
-    assert p.status == 0, p.statuses
+    invoke(['tar', '-czf', tarball_file, export_dir])
     print 'remove', export_dir
     shutil.rmtree(export_dir)
 
@@ -159,9 +160,9 @@ Create a git tag and a release tarball from the current revision.
 For example
   %prog 1.0.0
 
-You may wish to test this out in a dummy branch first to make sure it
-works as expected to avoid the tedium of unwinding the version-bump
-commit if it fails.
+If you don't like what got committed, you can undo the release with
+  $ git tag -d 1.0.0
+  $ git reset --hard HEAD^
 """
     p = optparse.OptionParser(usage)
     p.add_option('--test', dest='test', default=False,
@@ -173,15 +174,16 @@ commit if it fails.
         sys.exit(0)
 
     assert len(args) == 1, '%d (!= 1) arguments: %s' % (len(args), args)
-    tag = args[0]
-    validate_tag(tag)
+    _tag = args[0]
+    validate_tag(_tag)
 
     if pending_changes() == True:
         print "Handle pending changes before releasing."
         sys.exit(1)
-    set_release_version(tag)
+    set_release_version(_tag)
+    print "Update copyright information..."
     update_authors()
     update_files()
-    commit("Bumped to version %s" % tag)
-    tag(tag)
-    create_tarball(tag)
+    commit("Bumped to version %s" % _tag)
+    tag(_tag)
+    create_tarball(_tag)