Commit 197c1c33 authored by Stefan H. Holek's avatar Stefan H. Holek

Miscellaneous updates to the upload_docs command.

a) upload_docs now runs build_sphinx to generate documentation.
b) The temporary ZIP file is properly disposed of.
c) Auth credentials now work under Python 3. Fixes #326.

hg record cannot split hunks, thus the large commit.

--HG--
branch : distribute
extra : rebase_source : 76d81880a2aaeb5b94a1d2388cb838068e4f64e3
parent 9d66fb61
...@@ -9,10 +9,13 @@ import os ...@@ -9,10 +9,13 @@ import os
import socket import socket
import zipfile import zipfile
import httplib import httplib
import base64
import urlparse import urlparse
import tempfile import tempfile
import sys import sys
import shutil
from base64 import standard_b64encode
from pkg_resources import iter_entry_points
from distutils import log from distutils import log
from distutils.errors import DistutilsOptionError from distutils.errors import DistutilsOptionError
...@@ -22,20 +25,18 @@ try: ...@@ -22,20 +25,18 @@ try:
except ImportError: except ImportError:
from setuptools.command.upload import upload from setuptools.command.upload import upload
_IS_PYTHON3 = sys.version > '3' if sys.version_info >= (3,):
errors = 'surrogateescape'
else:
errors = 'strict'
try:
bytes # This is not just a replacement for byte literals
except NameError: # but works as a general purpose encoder
bytes = str def b(s, encoding='utf-8'):
if isinstance(s, unicode):
def b(str_or_bytes): return s.encode(encoding, errors)
"""Return bytes by either encoding the argument as ASCII or simply return return s
the argument as-is."""
if not isinstance(str_or_bytes, bytes):
return str_or_bytes.encode('ascii')
else:
return str_or_bytes
class upload_docs(upload): class upload_docs(upload):
...@@ -51,40 +52,62 @@ class upload_docs(upload): ...@@ -51,40 +52,62 @@ class upload_docs(upload):
] ]
boolean_options = upload.boolean_options 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): def initialize_options(self):
upload.initialize_options(self) upload.initialize_options(self)
self.upload_dir = None self.upload_dir = None
self.target_dir = None
def finalize_options(self): def finalize_options(self):
upload.finalize_options(self) upload.finalize_options(self)
if self.upload_dir is None: 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') build = self.get_finalized_command('build')
self.upload_dir = os.path.join(build.build_base, 'docs') self.target_dir = os.path.join(build.build_base, 'docs')
self.mkpath(self.upload_dir) else:
self.ensure_dirname('upload_dir') self.ensure_dirname('upload_dir')
self.announce('Using upload directory %s' % self.upload_dir) self.target_dir = self.upload_dir
self.announce('Using upload directory %s' % self.target_dir)
def create_zipfile(self): def create_zipfile(self, filename):
name = self.distribution.metadata.get_name() zip_file = zipfile.ZipFile(filename, "w")
tmp_dir = tempfile.mkdtemp() try:
tmp_file = os.path.join(tmp_dir, "%s.zip" % name) self.mkpath(self.target_dir) # just in case
zip_file = zipfile.ZipFile(tmp_file, "w") for root, dirs, files in os.walk(self.target_dir):
for root, dirs, files in os.walk(self.upload_dir): if root == self.target_dir and not files:
if root == self.upload_dir and not files:
raise DistutilsOptionError( raise DistutilsOptionError(
"no files found in upload directory '%s'" "no files found in upload directory '%s'"
% self.upload_dir) % self.target_dir)
for name in files: for name in files:
full = os.path.join(root, name) full = os.path.join(root, name)
relative = root[len(self.upload_dir):].lstrip(os.path.sep) relative = root[len(self.target_dir):].lstrip(os.path.sep)
dest = os.path.join(relative, name) dest = os.path.join(relative, name)
zip_file.write(full, dest) zip_file.write(full, dest)
finally:
zip_file.close() zip_file.close()
return tmp_file
def run(self): def run(self):
zip_file = self.create_zipfile() # 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) self.upload_file(zip_file)
finally:
shutil.rmtree(tmp_dir)
def upload_file(self, filename): def upload_file(self, filename):
content = open(filename, 'rb').read() content = open(filename, 'rb').read()
...@@ -95,36 +118,33 @@ class upload_docs(upload): ...@@ -95,36 +118,33 @@ class upload_docs(upload):
'content': (os.path.basename(filename), content), 'content': (os.path.basename(filename), content),
} }
# set up the authentication # set up the authentication
credentials = self.username + ':' + self.password credentials = b(self.username + ':' + self.password)
if _IS_PYTHON3: # base64 only works with bytes in Python 3. credentials = standard_b64encode(credentials)
encoded_creds = base64.encodebytes(credentials.encode('utf8')) if sys.version_info >= (3,):
auth = bytes("Basic ") credentials = credentials.decode('ascii')
else: auth = "Basic " + credentials
encoded_creds = base64.encodestring(credentials)
auth = "Basic "
auth += encoded_creds.strip()
# Build up the MIME payload for the POST data # Build up the MIME payload for the POST data
boundary = b('--------------GHSKFJDLGDS7543FJKLFHRE75642756743254') boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
sep_boundary = b('\n--') + boundary sep_boundary = b('\n--') + b(boundary)
end_boundary = sep_boundary + b('--') end_boundary = sep_boundary + b('--')
body = [] body = []
for key, values in data.items(): for key, values in data.iteritems():
title = '\nContent-Disposition: form-data; name="%s"' % key
# handle multiple entries for the same name # handle multiple entries for the same name
if type(values) != type([]): if type(values) != type([]):
values = [values] values = [values]
for value in values: for value in values:
if type(value) is tuple: if type(value) is tuple:
fn = b(';filename="%s"' % value[0]) title += '; filename="%s"' % value[0]
value = value[1] value = value[1]
else: else:
fn = b("") value = b(value)
body.append(sep_boundary) body.append(sep_boundary)
body.append(b('\nContent-Disposition: form-data; name="%s"'%key)) body.append(b(title))
body.append(fn)
body.append(b("\n\n")) body.append(b("\n\n"))
body.append(b(value)) body.append(value)
if value and value[-1] == b('\r'): if value and value[-1:] == b('\r'):
body.append(b('\n')) # write an extra newline (lurve Macs) body.append(b('\n')) # write an extra newline (lurve Macs)
body.append(end_boundary) body.append(end_boundary)
body.append(b("\n")) body.append(b("\n"))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment