~james-w/lpdistutils/trunk

« back to all changes in this revision

Viewing changes to lpdistutils/lpupload.py

  • Committer: James Westby
  • Date: 2010-07-16 19:41:26 UTC
  • Revision ID: james.westby@canonical.com-20100716194126-ksd6ritft85pnmt5
Hack something vaguely working.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""distutils.command.upload
 
2
 
 
3
Implements the Distutils 'upload' subcommand (upload package to PyPI)."""
 
4
 
 
5
import datetime
 
6
from distutils.errors import DistutilsOptionError
 
7
from distutils.spawn import spawn
 
8
import os
 
9
import platform
 
10
import sys
 
11
import subprocess
 
12
import tempfile
 
13
 
 
14
from lpdistutils import LPCommand
 
15
 
 
16
 
 
17
class lpupload(LPCommand):
 
18
 
 
19
    description = "upload files to Launchpad"
 
20
    user_options = LPCommand.user_options + [
 
21
        ('sign', 's',
 
22
         'sign files to upload using gpg'),
 
23
        ('identity=', 'i', 'GPG identity used to sign files'),
 
24
        ]
 
25
    boolean_options = LPCommand.boolean_options + ['sign']
 
26
 
 
27
    def initialize_options(self):
 
28
        LPCommand.initialize_options(self)
 
29
        self.sign = False
 
30
        self.identity = None
 
31
 
 
32
    def finalize_options(self):
 
33
        LPCommand.finalize_options(self)
 
34
        if self.identity and not self.sign:
 
35
            raise DistutilsOptionError(
 
36
                "Must use --sign for --identity to have meaning"
 
37
            )
 
38
 
 
39
    def run(self):
 
40
        if not self.distribution.dist_files:
 
41
            raise DistutilsOptionError("No dist file created in earlier command")
 
42
        for command, pyversion, filename in self.distribution.dist_files:
 
43
            self.upload_file(command, pyversion, filename)
 
44
 
 
45
    def create_release(self, project, version):
 
46
        print "Release %s could not be found for project. Create it? (Y/n)" % version
 
47
        answer = sys.stdin.readline().strip().lower()
 
48
        if not answer.startswith('y'):
 
49
            sys.exit(0)
 
50
        milestone = None
 
51
        if len(project.series) != 1:
 
52
            eligble_series = []
 
53
            found = False
 
54
            for s in project.series:
 
55
                for m in s.all_milestones:
 
56
                    if m.name == version:
 
57
                        milestone = m
 
58
                        series = s
 
59
                        found = True
 
60
                        break
 
61
                if found:
 
62
                    break
 
63
            if series is None:
 
64
                print "Select a series to upload to:"
 
65
                for i, series in enumerate(project.series):
 
66
                    print "%d: %s" % (i+1, series.name)
 
67
                answer = int(sys.stdin.readline().strip())
 
68
                if answer < 1 or answer > len(series):
 
69
                    sys.exit(0)
 
70
                series = project.series[answer-1]
 
71
        else:
 
72
            series = project.series[0]
 
73
 
 
74
        release_date = datetime.date.today().strftime('%Y-%m-%d')
 
75
        if milestone is None:
 
76
            milestone = series.newMilestone(name=version,
 
77
                    date_targeted=release_date)
 
78
        return milestone.createProductRelease(date_released=release_date)
 
79
 
 
80
    def edit_file(self, prefix, description):
 
81
        (fd, f) = tempfile.mkstemp(prefix=prefix+'.')
 
82
        os.write(fd, '\n\n#------\n# Please enter the %s here. Lines which start with "#" are ignored.\n' %
 
83
                description)
 
84
        os.close(fd)
 
85
        subprocess.call(['sensible-editor', f])
 
86
        content = ''
 
87
        for l in open(f):
 
88
            if l.startswith('#'):
 
89
                continue
 
90
            content += l
 
91
 
 
92
        return content.strip()
 
93
 
 
94
    def upload_file(self, command, pyversion, filename):
 
95
        # Sign if requested
 
96
        if self.sign:
 
97
            gpg_args = ["gpg", "--detach-sign", "-a", filename]
 
98
            if self.identity:
 
99
                gpg_args[2:2] = ["--local-user", self.identity]
 
100
            spawn(gpg_args)
 
101
 
 
102
        # Fill in the data
 
103
        f = open(filename,'rb')
 
104
        content = f.read()
 
105
        f.close()
 
106
        basename = os.path.basename(filename)
 
107
        description = command + " (%s)" % str(pyversion)
 
108
        if command=='bdist_egg' and self.distribution.has_ext_modules():
 
109
            description += " (built on %s)" % platform.platform(terse=1)
 
110
        if command == 'bdist_rpm':
 
111
            dist, version, id = platform.dist()
 
112
            if dist:
 
113
                description += ' (built for %s %s)' % (dist, version)
 
114
        elif command == 'bdist_dumb':
 
115
            description += ' (built for %s)' % platform.platform(terse=1)
 
116
 
 
117
        lpinfo = self.get_lpinfo()
 
118
        name = lpinfo.get_name()
 
119
        if name is None:
 
120
            name = self.distribution.get_name()
 
121
        version = self.distribution.metadata.version
 
122
 
 
123
        lp = self.get_lp()
 
124
        try:
 
125
            project = lp.projects[name]
 
126
        except KeyError:
 
127
            raise KeyError("Project %s not found." % name)
 
128
 
 
129
        release = None
 
130
        for rel in project.releases:
 
131
            if rel.version == version:
 
132
                release = rel
 
133
                break
 
134
        if release is None:
 
135
            release = self.create_release(project, version)
 
136
 
 
137
        kwargs = {}
 
138
        sig_filename = filename + ".asc"
 
139
        if self.sign:
 
140
            kwargs["signature_filename"] = os.path.basename(sig_filename)
 
141
            kwargs["signature_content"] = open(sig_filename).read()
 
142
 
 
143
        release.add_file(filename=basename, description=description,
 
144
                file_content=content, file_type="Code Release Tarball",
 
145
                content_type='application/x-gzip', **kwargs)
 
146
 
 
147
        changelog = self.edit_file('changelog', 'changelog')
 
148
        if changelog:
 
149
            release.changelog = changelog
 
150
        release_notes = self.edit_file('releasenotes', 'release notes')
 
151
        if release_notes:
 
152
            release.release_notes = release_notes
 
153
 
 
154
        release.lp_save()