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