root / env / lib / python2.7 / site-packages / distribute-0.6.19-py2.7.egg / setuptools / command / upload_docs.py @ 1a305335
History | View | Annotate | Download (6.03 KB)
1 |
# -*- coding: utf-8 -*-
|
---|---|
2 |
"""upload_docs
|
3 |
|
4 |
Implements a Distutils 'upload_docs' subcommand (upload documentation to
|
5 |
PyPI's packages.python.org).
|
6 |
"""
|
7 |
|
8 |
import os |
9 |
import socket |
10 |
import zipfile |
11 |
import httplib |
12 |
import base64 |
13 |
import urlparse |
14 |
import tempfile |
15 |
import sys |
16 |
|
17 |
from distutils import log |
18 |
from distutils.errors import DistutilsOptionError |
19 |
|
20 |
try:
|
21 |
from distutils.command.upload import upload |
22 |
except ImportError: |
23 |
from setuptools.command.upload import upload |
24 |
|
25 |
_IS_PYTHON3 = sys.version > '3'
|
26 |
|
27 |
try:
|
28 |
bytes
|
29 |
except NameError: |
30 |
bytes = str
|
31 |
|
32 |
def b(str_or_bytes): |
33 |
"""Return bytes by either encoding the argument as ASCII or simply return
|
34 |
the argument as-is."""
|
35 |
if not isinstance(str_or_bytes, bytes): |
36 |
return str_or_bytes.encode('ascii') |
37 |
else:
|
38 |
return str_or_bytes
|
39 |
|
40 |
|
41 |
class upload_docs(upload): |
42 |
|
43 |
description = 'Upload documentation to PyPI'
|
44 |
|
45 |
user_options = [ |
46 |
('repository=', 'r', |
47 |
"url of repository [default: %s]" % upload.DEFAULT_REPOSITORY),
|
48 |
('show-response', None, |
49 |
'display full response text from server'),
|
50 |
('upload-dir=', None, 'directory to upload'), |
51 |
] |
52 |
boolean_options = upload.boolean_options |
53 |
|
54 |
def initialize_options(self): |
55 |
upload.initialize_options(self)
|
56 |
self.upload_dir = None |
57 |
|
58 |
def finalize_options(self): |
59 |
upload.finalize_options(self)
|
60 |
if self.upload_dir is None: |
61 |
build = self.get_finalized_command('build') |
62 |
self.upload_dir = os.path.join(build.build_base, 'docs') |
63 |
self.mkpath(self.upload_dir) |
64 |
self.ensure_dirname('upload_dir') |
65 |
self.announce('Using upload directory %s' % self.upload_dir) |
66 |
|
67 |
def create_zipfile(self): |
68 |
name = self.distribution.metadata.get_name()
|
69 |
tmp_dir = tempfile.mkdtemp() |
70 |
tmp_file = os.path.join(tmp_dir, "%s.zip" % name)
|
71 |
zip_file = zipfile.ZipFile(tmp_file, "w")
|
72 |
for root, dirs, files in os.walk(self.upload_dir): |
73 |
if root == self.upload_dir and not files: |
74 |
raise DistutilsOptionError(
|
75 |
"no files found in upload directory '%s'"
|
76 |
% self.upload_dir)
|
77 |
for name in files: |
78 |
full = os.path.join(root, name) |
79 |
relative = root[len(self.upload_dir):].lstrip(os.path.sep) |
80 |
dest = os.path.join(relative, name) |
81 |
zip_file.write(full, dest) |
82 |
zip_file.close() |
83 |
return tmp_file
|
84 |
|
85 |
def run(self): |
86 |
zip_file = self.create_zipfile()
|
87 |
self.upload_file(zip_file)
|
88 |
|
89 |
def upload_file(self, filename): |
90 |
content = open(filename, 'rb').read() |
91 |
meta = self.distribution.metadata
|
92 |
data = { |
93 |
':action': 'doc_upload', |
94 |
'name': meta.get_name(),
|
95 |
'content': (os.path.basename(filename), content),
|
96 |
} |
97 |
# set up the authentication
|
98 |
credentials = self.username + ':' + self.password |
99 |
if _IS_PYTHON3: # base64 only works with bytes in Python 3. |
100 |
encoded_creds = base64.encodebytes(credentials.encode('utf8'))
|
101 |
auth = bytes("Basic ") |
102 |
else:
|
103 |
encoded_creds = base64.encodestring(credentials) |
104 |
auth = "Basic "
|
105 |
auth += encoded_creds.strip() |
106 |
|
107 |
# Build up the MIME payload for the POST data
|
108 |
boundary = b('--------------GHSKFJDLGDS7543FJKLFHRE75642756743254')
|
109 |
sep_boundary = b('\n--') + boundary
|
110 |
end_boundary = sep_boundary + b('--')
|
111 |
body = [] |
112 |
for key, values in data.items(): |
113 |
# handle multiple entries for the same name
|
114 |
if type(values) != type([]): |
115 |
values = [values] |
116 |
for value in values: |
117 |
if type(value) is tuple: |
118 |
fn = b(';filename="%s"' % value[0]) |
119 |
value = value[1]
|
120 |
else:
|
121 |
fn = b("")
|
122 |
body.append(sep_boundary) |
123 |
body.append(b('\nContent-Disposition: form-data; name="%s"'%key))
|
124 |
body.append(fn) |
125 |
body.append(b("\n\n"))
|
126 |
body.append(b(value)) |
127 |
if value and value[-1] == b('\r'): |
128 |
body.append(b('\n')) # write an extra newline (lurve Macs) |
129 |
body.append(end_boundary) |
130 |
body.append(b("\n"))
|
131 |
body = b('').join(body)
|
132 |
|
133 |
self.announce("Submitting documentation to %s" % (self.repository), |
134 |
log.INFO) |
135 |
|
136 |
# build the Request
|
137 |
# We can't use urllib2 since we need to send the Basic
|
138 |
# auth right with the first request
|
139 |
schema, netloc, url, params, query, fragments = \ |
140 |
urlparse.urlparse(self.repository)
|
141 |
assert not params and not query and not fragments |
142 |
if schema == 'http': |
143 |
conn = httplib.HTTPConnection(netloc) |
144 |
elif schema == 'https': |
145 |
conn = httplib.HTTPSConnection(netloc) |
146 |
else:
|
147 |
raise AssertionError("unsupported schema "+schema) |
148 |
|
149 |
data = ''
|
150 |
loglevel = log.INFO |
151 |
try:
|
152 |
conn.connect() |
153 |
conn.putrequest("POST", url)
|
154 |
conn.putheader('Content-type',
|
155 |
'multipart/form-data; boundary=%s'%boundary)
|
156 |
conn.putheader('Content-length', str(len(body))) |
157 |
conn.putheader('Authorization', auth)
|
158 |
conn.endheaders() |
159 |
conn.send(body) |
160 |
except socket.error, e:
|
161 |
self.announce(str(e), log.ERROR) |
162 |
return
|
163 |
|
164 |
r = conn.getresponse() |
165 |
if r.status == 200: |
166 |
self.announce('Server response (%s): %s' % (r.status, r.reason), |
167 |
log.INFO) |
168 |
elif r.status == 301: |
169 |
location = r.getheader('Location')
|
170 |
if location is None: |
171 |
location = 'http://packages.python.org/%s/' % meta.get_name()
|
172 |
self.announce('Upload successful. Visit %s' % location, |
173 |
log.INFO) |
174 |
else:
|
175 |
self.announce('Upload failed (%s): %s' % (r.status, r.reason), |
176 |
log.ERROR) |
177 |
if self.show_response: |
178 |
print '-'*75, r.read(), '-'*75 |