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 |