Mercurial > repos > bcclaywell > argo_navis
comparison venv/lib/python2.7/site-packages/setuptools/command/upload_docs.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d67268158946 |
---|---|
1 # -*- coding: utf-8 -*- | |
2 """upload_docs | |
3 | |
4 Implements a Distutils 'upload_docs' subcommand (upload documentation to | |
5 PyPI's pythonhosted.org). | |
6 """ | |
7 | |
8 from base64 import standard_b64encode | |
9 from distutils import log | |
10 from distutils.errors import DistutilsOptionError | |
11 from distutils.command.upload import upload | |
12 import os | |
13 import socket | |
14 import zipfile | |
15 import tempfile | |
16 import sys | |
17 import shutil | |
18 | |
19 from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3 | |
20 from pkg_resources import iter_entry_points | |
21 | |
22 | |
23 errors = 'surrogateescape' if PY3 else 'strict' | |
24 | |
25 | |
26 # This is not just a replacement for byte literals | |
27 # but works as a general purpose encoder | |
28 def b(s, encoding='utf-8'): | |
29 if isinstance(s, unicode): | |
30 return s.encode(encoding, errors) | |
31 return s | |
32 | |
33 | |
34 class upload_docs(upload): | |
35 description = 'Upload documentation to PyPI' | |
36 | |
37 user_options = [ | |
38 ('repository=', 'r', | |
39 "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), | |
40 ('show-response', None, | |
41 'display full response text from server'), | |
42 ('upload-dir=', None, 'directory to upload'), | |
43 ] | |
44 boolean_options = upload.boolean_options | |
45 | |
46 def has_sphinx(self): | |
47 if self.upload_dir is None: | |
48 for ep in iter_entry_points('distutils.commands', 'build_sphinx'): | |
49 return True | |
50 | |
51 sub_commands = [('build_sphinx', has_sphinx)] | |
52 | |
53 def initialize_options(self): | |
54 upload.initialize_options(self) | |
55 self.upload_dir = None | |
56 self.target_dir = None | |
57 | |
58 def finalize_options(self): | |
59 upload.finalize_options(self) | |
60 if self.upload_dir is None: | |
61 if self.has_sphinx(): | |
62 build_sphinx = self.get_finalized_command('build_sphinx') | |
63 self.target_dir = build_sphinx.builder_target_dir | |
64 else: | |
65 build = self.get_finalized_command('build') | |
66 self.target_dir = os.path.join(build.build_base, 'docs') | |
67 else: | |
68 self.ensure_dirname('upload_dir') | |
69 self.target_dir = self.upload_dir | |
70 self.announce('Using upload directory %s' % self.target_dir) | |
71 | |
72 def create_zipfile(self, filename): | |
73 zip_file = zipfile.ZipFile(filename, "w") | |
74 try: | |
75 self.mkpath(self.target_dir) # just in case | |
76 for root, dirs, files in os.walk(self.target_dir): | |
77 if root == self.target_dir and not files: | |
78 raise DistutilsOptionError( | |
79 "no files found in upload directory '%s'" | |
80 % self.target_dir) | |
81 for name in files: | |
82 full = os.path.join(root, name) | |
83 relative = root[len(self.target_dir):].lstrip(os.path.sep) | |
84 dest = os.path.join(relative, name) | |
85 zip_file.write(full, dest) | |
86 finally: | |
87 zip_file.close() | |
88 | |
89 def run(self): | |
90 # Run sub commands | |
91 for cmd_name in self.get_sub_commands(): | |
92 self.run_command(cmd_name) | |
93 | |
94 tmp_dir = tempfile.mkdtemp() | |
95 name = self.distribution.metadata.get_name() | |
96 zip_file = os.path.join(tmp_dir, "%s.zip" % name) | |
97 try: | |
98 self.create_zipfile(zip_file) | |
99 self.upload_file(zip_file) | |
100 finally: | |
101 shutil.rmtree(tmp_dir) | |
102 | |
103 def upload_file(self, filename): | |
104 f = open(filename, 'rb') | |
105 content = f.read() | |
106 f.close() | |
107 meta = self.distribution.metadata | |
108 data = { | |
109 ':action': 'doc_upload', | |
110 'name': meta.get_name(), | |
111 'content': (os.path.basename(filename), content), | |
112 } | |
113 # set up the authentication | |
114 credentials = b(self.username + ':' + self.password) | |
115 credentials = standard_b64encode(credentials) | |
116 if PY3: | |
117 credentials = credentials.decode('ascii') | |
118 auth = "Basic " + credentials | |
119 | |
120 # Build up the MIME payload for the POST data | |
121 boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' | |
122 sep_boundary = b('\n--') + b(boundary) | |
123 end_boundary = sep_boundary + b('--') | |
124 body = [] | |
125 for key, values in iteritems(data): | |
126 title = '\nContent-Disposition: form-data; name="%s"' % key | |
127 # handle multiple entries for the same name | |
128 if not isinstance(values, list): | |
129 values = [values] | |
130 for value in values: | |
131 if type(value) is tuple: | |
132 title += '; filename="%s"' % value[0] | |
133 value = value[1] | |
134 else: | |
135 value = b(value) | |
136 body.append(sep_boundary) | |
137 body.append(b(title)) | |
138 body.append(b("\n\n")) | |
139 body.append(value) | |
140 if value and value[-1:] == b('\r'): | |
141 body.append(b('\n')) # write an extra newline (lurve Macs) | |
142 body.append(end_boundary) | |
143 body.append(b("\n")) | |
144 body = b('').join(body) | |
145 | |
146 self.announce("Submitting documentation to %s" % (self.repository), | |
147 log.INFO) | |
148 | |
149 # build the Request | |
150 # We can't use urllib2 since we need to send the Basic | |
151 # auth right with the first request | |
152 schema, netloc, url, params, query, fragments = \ | |
153 urlparse(self.repository) | |
154 assert not params and not query and not fragments | |
155 if schema == 'http': | |
156 conn = httplib.HTTPConnection(netloc) | |
157 elif schema == 'https': | |
158 conn = httplib.HTTPSConnection(netloc) | |
159 else: | |
160 raise AssertionError("unsupported schema " + schema) | |
161 | |
162 data = '' | |
163 try: | |
164 conn.connect() | |
165 conn.putrequest("POST", url) | |
166 content_type = 'multipart/form-data; boundary=%s' % boundary | |
167 conn.putheader('Content-type', content_type) | |
168 conn.putheader('Content-length', str(len(body))) | |
169 conn.putheader('Authorization', auth) | |
170 conn.endheaders() | |
171 conn.send(body) | |
172 except socket.error as e: | |
173 self.announce(str(e), log.ERROR) | |
174 return | |
175 | |
176 r = conn.getresponse() | |
177 if r.status == 200: | |
178 self.announce('Server response (%s): %s' % (r.status, r.reason), | |
179 log.INFO) | |
180 elif r.status == 301: | |
181 location = r.getheader('Location') | |
182 if location is None: | |
183 location = 'https://pythonhosted.org/%s/' % meta.get_name() | |
184 self.announce('Upload successful. Visit %s' % location, | |
185 log.INFO) | |
186 else: | |
187 self.announce('Upload failed (%s): %s' % (r.status, r.reason), | |
188 log.ERROR) | |
189 if self.show_response: | |
190 print('-' * 75, r.read(), '-' * 75) |