# -*- coding: utf-8 -*- """upload_docs Implements a Distutils 'upload_docs' subcommand (upload documentation to PyPI's pythonhosted.org). """ import os import socket import zipfile import tempfile import sys import shutil from base64 import standard_b64encode from pkg_resources import iter_entry_points from distutils import log from distutils.errors import DistutilsOptionError try: from distutils.command.upload import upload except ImportError: from setuptools.command.upload import upload from setuptools.compat import httplib, urlparse, unicode, iteritems _IS_PYTHON3 = sys.version > '3' if _IS_PYTHON3: errors = 'surrogateescape' else: errors = 'strict' # This is not just a replacement for byte literals # but works as a general purpose encoder def b(s, encoding='utf-8'): if isinstance(s, unicode): return s.encode(encoding, errors) return s class upload_docs(upload): description = 'Upload documentation to PyPI' user_options = [ ('repository=', 'r', "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), ('show-response', None, 'display full response text from server'), ('upload-dir=', None, 'directory to upload'), ] boolean_options = upload.boolean_options def has_sphinx(self): if self.upload_dir is None: for ep in iter_entry_points('distutils.commands', 'build_sphinx'): return True sub_commands = [('build_sphinx', has_sphinx)] def initialize_options(self): upload.initialize_options(self) self.upload_dir = None self.target_dir = None def finalize_options(self): upload.finalize_options(self) if self.upload_dir is None: if self.has_sphinx(): build_sphinx = self.get_finalized_command('build_sphinx') self.target_dir = build_sphinx.builder_target_dir else: build = self.get_finalized_command('build') self.target_dir = os.path.join(build.build_base, 'docs') else: self.ensure_dirname('upload_dir') self.target_dir = self.upload_dir self.announce('Using upload directory %s' % self.target_dir) def create_zipfile(self, filename): zip_file = zipfile.ZipFile(filename, "w") try: self.mkpath(self.target_dir) # just in case for root, dirs, files in os.walk(self.target_dir): if root == self.target_dir and not files: raise DistutilsOptionError( "no files found in upload directory '%s'" % self.target_dir) for name in files: full = os.path.join(root, name) relative = root[len(self.target_dir):].lstrip(os.path.sep) dest = os.path.join(relative, name) zip_file.write(full, dest) finally: zip_file.close() def run(self): # Run sub commands for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) tmp_dir = tempfile.mkdtemp() name = self.distribution.metadata.get_name() zip_file = os.path.join(tmp_dir, "%s.zip" % name) try: self.create_zipfile(zip_file) self.upload_file(zip_file) finally: shutil.rmtree(tmp_dir) def upload_file(self, filename): f = open(filename, 'rb') content = f.read() f.close() meta = self.distribution.metadata data = { ':action': 'doc_upload', 'name': meta.get_name(), 'content': (os.path.basename(filename), content), } # set up the authentication credentials = b(self.username + ':' + self.password) credentials = standard_b64encode(credentials) if sys.version_info >= (3,): credentials = credentials.decode('ascii') auth = "Basic " + credentials # Build up the MIME payload for the POST data boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' sep_boundary = b('\n--') + b(boundary) end_boundary = sep_boundary + b('--') body = [] for key, values in iteritems(data): title = '\nContent-Disposition: form-data; name="%s"' % key # handle multiple entries for the same name if type(values) != type([]): values = [values] for value in values: if type(value) is tuple: title += '; filename="%s"' % value[0] value = value[1] else: value = b(value) body.append(sep_boundary) body.append(b(title)) body.append(b("\n\n")) body.append(value) if value and value[-1:] == b('\r'): body.append(b('\n')) # write an extra newline (lurve Macs) body.append(end_boundary) body.append(b("\n")) body = b('').join(body) self.announce("Submitting documentation to %s" % (self.repository), log.INFO) # build the Request # We can't use urllib2 since we need to send the Basic # auth right with the first request schema, netloc, url, params, query, fragments = \ urlparse(self.repository) assert not params and not query and not fragments if schema == 'http': conn = httplib.HTTPConnection(netloc) elif schema == 'https': conn = httplib.HTTPSConnection(netloc) else: raise AssertionError("unsupported schema "+schema) data = '' loglevel = log.INFO try: conn.connect() conn.putrequest("POST", url) conn.putheader('Content-type', 'multipart/form-data; boundary=%s'%boundary) conn.putheader('Content-length', str(len(body))) conn.putheader('Authorization', auth) conn.endheaders() conn.send(body) except socket.error: e = sys.exc_info()[1] self.announce(str(e), log.ERROR) return r = conn.getresponse() if r.status == 200: self.announce('Server response (%s): %s' % (r.status, r.reason), log.INFO) elif r.status == 301: location = r.getheader('Location') if location is None: location = 'https://pythonhosted.org/%s/' % meta.get_name() self.announce('Upload successful. Visit %s' % location, log.INFO) else: self.announce('Upload failed (%s): %s' % (r.status, r.reason), log.ERROR) if self.show_response: print('-'*75, r.read(), '-'*75)
Name | Type | Size | Permission | Actions |
---|---|---|---|---|
.__init__.pyo.40009 | File | 911 B | 0644 |
|
.alias.pyo.40009 | File | 3.16 KB | 0644 |
|
.bdist_egg.pyo.40009 | File | 18.18 KB | 0644 |
|
.bdist_rpm.pyo.40009 | File | 2.24 KB | 0644 |
|
.bdist_wininst.pyo.40009 | File | 2.33 KB | 0644 |
|
.build_py.pyo.40009 | File | 11.38 KB | 0644 |
|
.develop.pyo.40009 | File | 5.68 KB | 0644 |
|
.easy_install.pyo.40009 | File | 65.69 KB | 0644 |
|
.egg_info.pyo.40009 | File | 17.27 KB | 0644 |
|
.install.pyo.40009 | File | 3.67 KB | 0644 |
|
.install_egg_info.pyo.40009 | File | 4.56 KB | 0644 |
|
.install_scripts.pyo.40009 | File | 2.54 KB | 0644 |
|
.register.pyo.40009 | File | 692 B | 0644 |
|
.rotate.pyo.40009 | File | 2.88 KB | 0644 |
|
.saveopts.pyo.40009 | File | 1.2 KB | 0644 |
|
.sdist.pyo.40009 | File | 9.92 KB | 0644 |
|
.setopt.pyo.40009 | File | 5.91 KB | 0644 |
|
.test.pyo.40009 | File | 5.76 KB | 0644 |
|
__init__.py | File | 689 B | 0644 |
|
__init__.pyc | File | 911 B | 0644 |
|
__init__.pyo | File | 911 B | 0644 |
|
alias.py | File | 2.43 KB | 0644 |
|
alias.pyc | File | 3.16 KB | 0644 |
|
alias.pyo | File | 3.16 KB | 0644 |
|
bdist_egg.py | File | 18.28 KB | 0644 |
|
bdist_egg.pyc | File | 18.18 KB | 0644 |
|
bdist_egg.pyo | File | 18.18 KB | 0644 |
|
bdist_rpm.py | File | 1.98 KB | 0644 |
|
bdist_rpm.pyc | File | 2.24 KB | 0644 |
|
bdist_rpm.pyo | File | 2.24 KB | 0644 |
|
bdist_wininst.py | File | 2.23 KB | 0644 |
|
bdist_wininst.pyc | File | 2.33 KB | 0644 |
|
bdist_wininst.pyo | File | 2.33 KB | 0644 |
|
build_ext.py | File | 11.58 KB | 0644 |
|
build_ext.pyc | File | 10.08 KB | 0644 |
|
build_ext.pyo | File | 10.04 KB | 0644 |
|
build_py.py | File | 10.29 KB | 0644 |
|
build_py.pyc | File | 11.38 KB | 0644 |
|
build_py.pyo | File | 11.38 KB | 0644 |
|
develop.py | File | 6.3 KB | 0644 |
|
develop.pyc | File | 5.68 KB | 0644 |
|
develop.pyo | File | 5.68 KB | 0644 |
|
easy_install.py | File | 73.07 KB | 0755 |
|
easy_install.pyc | File | 65.69 KB | 0644 |
|
easy_install.pyo | File | 65.69 KB | 0644 |
|
egg_info.py | File | 15.42 KB | 0644 |
|
egg_info.pyc | File | 17.27 KB | 0644 |
|
egg_info.pyo | File | 17.27 KB | 0644 |
|
install.py | File | 3.97 KB | 0644 |
|
install.pyc | File | 3.67 KB | 0644 |
|
install.pyo | File | 3.67 KB | 0644 |
|
install_egg_info.py | File | 3.74 KB | 0644 |
|
install_egg_info.pyc | File | 4.56 KB | 0644 |
|
install_egg_info.pyo | File | 4.56 KB | 0644 |
|
install_lib.py | File | 2.43 KB | 0644 |
|
install_lib.pyc | File | 3.14 KB | 0644 |
|
install_lib.pyo | File | 3.1 KB | 0644 |
|
install_scripts.py | File | 2.02 KB | 0644 |
|
install_scripts.pyc | File | 2.54 KB | 0644 |
|
install_scripts.pyo | File | 2.54 KB | 0644 |
|
register.py | File | 277 B | 0644 |
|
register.pyc | File | 692 B | 0644 |
|
register.pyo | File | 692 B | 0644 |
|
rotate.py | File | 2.01 KB | 0644 |
|
rotate.pyc | File | 2.88 KB | 0644 |
|
rotate.pyo | File | 2.88 KB | 0644 |
|
saveopts.py | File | 705 B | 0644 |
|
saveopts.pyc | File | 1.2 KB | 0644 |
|
saveopts.pyo | File | 1.2 KB | 0644 |
|
sdist.py | File | 9.6 KB | 0644 |
|
sdist.pyc | File | 9.92 KB | 0644 |
|
sdist.pyo | File | 9.92 KB | 0644 |
|
setopt.py | File | 4.95 KB | 0644 |
|
setopt.pyc | File | 5.91 KB | 0644 |
|
setopt.pyo | File | 5.91 KB | 0644 |
|
test.py | File | 5.79 KB | 0644 |
|
test.pyc | File | 5.76 KB | 0644 |
|
test.pyo | File | 5.76 KB | 0644 |
|
upload.py | File | 6.57 KB | 0644 |
|
upload.pyc | File | 6.28 KB | 0644 |
|
upload.pyo | File | 6.26 KB | 0644 |
|
upload_docs.py | File | 6.81 KB | 0644 |
|
upload_docs.pyc | File | 7.01 KB | 0644 |
|
upload_docs.pyo | File | 6.98 KB | 0644 |
|