Rev 5910: Create a helper tool for uploading packages to Launchpad. in http://bazaar.launchpad.net/~jameinel/bzr/integration

John Arbash Meinel john at arbash-meinel.com
Mon May 23 15:00:32 UTC 2011


At http://bazaar.launchpad.net/~jameinel/bzr/integration

------------------------------------------------------------
revno: 5910
revision-id: john at arbash-meinel.com-20110523150018-1r1e2ldhnc06ooi4
parent: pqm at pqm.ubuntu.com-20110522135417-n76kmfgwmhygrj7g
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: integration
timestamp: Mon 2011-05-23 17:00:18 +0200
message:
  Create a helper tool for uploading packages to Launchpad.
-------------- next part --------------
=== added file 'tools/upload_to_launchpad.py'
--- a/tools/upload_to_launchpad.py	1970-01-01 00:00:00 +0000
+++ b/tools/upload_to_launchpad.py	2011-05-23 15:00:18 +0000
@@ -0,0 +1,178 @@
+# Copyright (C) 2005-2011 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""A tool for uploading tarballs and installers of bzr to Launchpad."""
+
+import os
+import pprint
+import re
+import subprocess
+import sys
+
+_bzr_version_re = re.compile(
+    r'bzr-(?P<major>\d)\.(?P<minor>\d)'
+    r'((?P<micro>(\.|b)\d))?'
+    r'(-(?P<build>\d))?'
+    r'(\.win32-py(?P<py_version>2\.\d))?')
+
+
+def determine_bzr_version(name):
+    """Extra the version information from the string."""
+    m = _bzr_version_re.match(name)
+    if not m:
+        return None
+    return m.groupdict()
+
+
+def add_build_num(name, version_dict, build):
+    """There isn't a build number, add it."""
+    version_bits = '%s.%s' % (version_dict['major'], version_dict['minor'])
+    if version_dict['micro'] is not None:
+        # 'micro' is 'b1' or '.3' etc.
+        version_bits += version_dict['micro']
+    return name.replace(version_bits, '%s-%d' % (version_bits, build))
+
+
+def find_sig_name(name):
+    """See if a signature exists for this entry."""
+    for ext in ('.asc', '.sig'):
+        sig_name = name + ext
+        if os.path.isfile(sig_name):
+            return sig_name
+    return None
+
+
+def get_sig_name(name):
+    """Find a signature file for this entry, or create one."""
+    sig_name = find_sig_name(name)
+    if sig_name is not None:
+        return sig_name
+    # If we got here, there is no signature yet
+    ret = subprocess.call(['gpg', '--detach-sig', '--armor', name])
+    if ret == 0:
+        return name + '.asc'
+    raise RuntimeError("failed to sign %s" % (name,))
+
+
+def get_description(version_dict):
+    """Get the description of this version."""
+    py_version = version_dict['py_version']
+    if py_version is None:
+        return "Windows Standalone Installer"
+    else:
+        return "Windows Python %s Installer" % (py_version,)
+
+
+def get_upload_url(opts, version_info):
+    """Get the URL we are posting to."""
+    var = dict(version_info)
+    if version_info['micro'] is None:
+        var['micro'] = ''
+    base = ('https://launchpad.net/bzr'
+            '/%(major)s.%(minor)s'
+            '/%(major)s.%(minor)s%(micro)s'
+            '/+adddownloadfile')
+    return base % var
+
+
+def get_curl_command(opts, filename, sig_filename, version_info):
+    """Populate the CURL command to upload this content."""
+    description = get_description(version_info)
+    # We may also do field.contenttype=CODETARBALL
+    url = get_upload_url(opts, version_info),
+    command = ['curl',
+               '--form-string', 'field.description=%s' % (description,),
+               '--form-string', 'field.filecontent.used=1',
+               '--form', 'field.filecontent=@%s' % (filename,),
+               '--form-string', 'field.signature.used=1',
+               '--form', 'field.signature=@%s' % (sig_filename,),
+               '--form-string', 'field.contenttype=INSTALLER',
+               '--form-string', 'field.actions.add=Upload',
+               '--referer', url,
+               url,
+              ]
+    if opts.user:
+        command.insert(1, '--user')
+        command.insert(2, opts.user)
+    if opts.ignore_ssl:
+        command.insert(-1, '--insecure')
+    return command
+
+
+def main(args):
+    import optparse
+    p = optparse.OptionParser(usage='%prog [options]')
+    p.add_option('--verbose', '-v', action='store_true', help='Be chatty')
+    p.add_option('--build', default=None, type=int,
+                 help='Files that are missing a build id will be renamed'
+                      ' to match this build num')
+    p.add_option('--user', default=None, type=str,
+                 help='Set the Launchpad username you are uploading as.')
+    p.add_option('--ignore-ssl', default=False, action='store_true',
+                 help='Ignore SSL certificates')
+    p.add_option('--dry-run', default=False, action='store_true',
+                 help='Don\'t actually run curl')
+
+    (opts, args) = p.parse_args(args)
+    files_to_upload = []
+    for arg in args:
+        if arg.endswith('.asc') or arg.endswith('.sig'):
+            sys.stderr.write('Ignoring signature file: %s\n' % (arg,))
+            continue
+        version = determine_bzr_version(arg)
+        if version is None:
+            sys.stderr.write('Unknown bzr version for %s\n' % (arg,))
+            continue
+        if version['build'] is None and opts.build is not None:
+            build_name = add_build_num(arg, version, opts.build)
+            os.rename(arg, build_name)
+            sig_name = find_sig_name(arg)
+            if sig_name is not None:
+                build_sig_name = add_build_num(sig_name, version, opts.build)
+                os.rename(sig_name, build_sig_name)
+            arg = build_name
+        sig_name = get_sig_name(arg)
+        files_to_upload.append((arg, sig_name, version))
+    # Now sort them
+    def sort_key(info):
+        version = info[-1]
+        py_version = version['py_version']
+        if py_version is None:
+            # We want these to sort last
+            py_version = '\xff\xff\xff\xff\xff\xff'
+        return (version['major'], version['minor'], version['micro'],
+                py_version)
+    files_to_upload.sort(key=sort_key)
+    for f_name, sig_name, version in files_to_upload:
+        curl = get_curl_command(opts, f_name, sig_name, version)
+        if opts.verbose:
+            pprint.pprint(curl)
+        else:
+            sys.stderr.write('Uploading %s' % (f_name,))
+        # We have curl write to a PIPE so that we get progress output, and then
+        # we turn around and write the actual content back out again for the
+        # user to see errors. On success, stdout is empty.
+        if not opts.dry_run:
+            p = subprocess.Popen(curl, stdout=subprocess.PIPE)
+            stdout, _ = p.communicate()
+            sys.stdout.write(stdout)
+            if p.returncode != 0:
+                sys.stderr.write('failed to upload for %s:\n' % (f_name,))
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
+



More information about the bazaar-commits mailing list