Statistics
| Branch: | Revision:

root / env / lib / python2.7 / site-packages / distribute-0.6.19-py2.7.egg / setuptools / command / upload.py @ 1a305335

History | View | Annotate | Download (6.52 KB)

1
"""distutils.command.upload
2

3
Implements the Distutils 'upload' subcommand (upload package to PyPI)."""
4

    
5
from distutils.errors import *
6
from distutils.core import Command
7
from distutils.spawn import spawn
8
from distutils import log
9
try:
10
    from hashlib import md5
11
except ImportError:
12
    from md5 import md5
13
import os
14
import socket
15
import platform
16
import ConfigParser
17
import httplib
18
import base64
19
import urlparse
20
import cStringIO as StringIO
21

    
22
class upload(Command):
23

    
24
    description = "upload binary package to PyPI"
25

    
26
    DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi'
27

    
28
    user_options = [
29
        ('repository=', 'r',
30
         "url of repository [default: %s]" % DEFAULT_REPOSITORY),
31
        ('show-response', None,
32
         'display full response text from server'),
33
        ('sign', 's',
34
         'sign files to upload using gpg'),
35
        ('identity=', 'i', 'GPG identity used to sign files'),
36
        ]
37
    boolean_options = ['show-response', 'sign']
38

    
39
    def initialize_options(self):
40
        self.username = ''
41
        self.password = ''
42
        self.repository = ''
43
        self.show_response = 0
44
        self.sign = False
45
        self.identity = None
46

    
47
    def finalize_options(self):
48
        if self.identity and not self.sign:
49
            raise DistutilsOptionError(
50
                "Must use --sign for --identity to have meaning"
51
            )
52
        if os.environ.has_key('HOME'):
53
            rc = os.path.join(os.environ['HOME'], '.pypirc')
54
            if os.path.exists(rc):
55
                self.announce('Using PyPI login from %s' % rc)
56
                config = ConfigParser.ConfigParser({
57
                        'username':'',
58
                        'password':'',
59
                        'repository':''})
60
                config.read(rc)
61
                if not self.repository:
62
                    self.repository = config.get('server-login', 'repository')
63
                if not self.username:
64
                    self.username = config.get('server-login', 'username')
65
                if not self.password:
66
                    self.password = config.get('server-login', 'password')
67
        if not self.repository:
68
            self.repository = self.DEFAULT_REPOSITORY
69

    
70
    def run(self):
71
        if not self.distribution.dist_files:
72
            raise DistutilsOptionError("No dist file created in earlier command")
73
        for command, pyversion, filename in self.distribution.dist_files:
74
            self.upload_file(command, pyversion, filename)
75

    
76
    def upload_file(self, command, pyversion, filename):
77
        # Sign if requested
78
        if self.sign:
79
            gpg_args = ["gpg", "--detach-sign", "-a", filename]
80
            if self.identity:
81
                gpg_args[2:2] = ["--local-user", self.identity]
82
            spawn(gpg_args,
83
                  dry_run=self.dry_run)
84

    
85
        # Fill in the data
86
        f = open(filename,'rb')
87
        content = f.read()
88
        f.close()
89
        basename = os.path.basename(filename)
90
        comment = ''
91
        if command=='bdist_egg' and self.distribution.has_ext_modules():
92
            comment = "built on %s" % platform.platform(terse=1)
93
        data = {
94
            ':action':'file_upload',
95
            'protcol_version':'1',
96
            'name':self.distribution.get_name(),
97
            'version':self.distribution.get_version(),
98
            'content':(basename,content),
99
            'filetype':command,
100
            'pyversion':pyversion,
101
            'md5_digest':md5(content).hexdigest(),
102
            }
103
        if command == 'bdist_rpm':
104
            dist, version, id = platform.dist()
105
            if dist:
106
                comment = 'built for %s %s' % (dist, version)
107
        elif command == 'bdist_dumb':
108
            comment = 'built for %s' % platform.platform(terse=1)
109
        data['comment'] = comment
110

    
111
        if self.sign:
112
            data['gpg_signature'] = (os.path.basename(filename) + ".asc",
113
                                     open(filename+".asc").read())
114

    
115
        # set up the authentication
116
        auth = "Basic " + base64.encodestring(self.username + ":" + self.password).strip()
117

    
118
        # Build up the MIME payload for the POST data
119
        boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
120
        sep_boundary = '\n--' + boundary
121
        end_boundary = sep_boundary + '--'
122
        body = StringIO.StringIO()
123
        for key, value in data.items():
124
            # handle multiple entries for the same name
125
            if type(value) != type([]):
126
                value = [value]
127
            for value in value:
128
                if type(value) is tuple:
129
                    fn = ';filename="%s"' % value[0]
130
                    value = value[1]
131
                else:
132
                    fn = ""
133
                value = str(value)
134
                body.write(sep_boundary)
135
                body.write('\nContent-Disposition: form-data; name="%s"'%key)
136
                body.write(fn)
137
                body.write("\n\n")
138
                body.write(value)
139
                if value and value[-1] == '\r':
140
                    body.write('\n')  # write an extra newline (lurve Macs)
141
        body.write(end_boundary)
142
        body.write("\n")
143
        body = body.getvalue()
144

    
145
        self.announce("Submitting %s to %s" % (filename, self.repository), log.INFO)
146

    
147
        # build the Request
148
        # We can't use urllib2 since we need to send the Basic
149
        # auth right with the first request
150
        schema, netloc, url, params, query, fragments = \
151
            urlparse.urlparse(self.repository)
152
        assert not params and not query and not fragments
153
        if schema == 'http':
154
            http = httplib.HTTPConnection(netloc)
155
        elif schema == 'https':
156
            http = httplib.HTTPSConnection(netloc)
157
        else:
158
            raise AssertionError, "unsupported schema "+schema
159

    
160
        data = ''
161
        loglevel = log.INFO
162
        try:
163
            http.connect()
164
            http.putrequest("POST", url)
165
            http.putheader('Content-type',
166
                           'multipart/form-data; boundary=%s'%boundary)
167
            http.putheader('Content-length', str(len(body)))
168
            http.putheader('Authorization', auth)
169
            http.endheaders()
170
            http.send(body)
171
        except socket.error, e:
172
            self.announce(str(e), log.ERROR)
173
            return
174

    
175
        r = http.getresponse()
176
        if r.status == 200:
177
            self.announce('Server response (%s): %s' % (r.status, r.reason),
178
                          log.INFO)
179
        else:
180
            self.announce('Upload failed (%s): %s' % (r.status, r.reason),
181
                          log.ERROR)
182
        if self.show_response:
183
            print '-'*75, r.read(), '-'*75