diff options
Diffstat (limited to 'setuptools')
-rw-r--r-- | setuptools/__init__.py | 2 | ||||
-rwxr-xr-x | setuptools/command/sdist.py | 41 | ||||
-rwxr-xr-x | setuptools/command/upload.py | 171 | ||||
-rwxr-xr-x | setuptools/package_index.py | 24 |
4 files changed, 225 insertions, 13 deletions
diff --git a/setuptools/__init__.py b/setuptools/__init__.py index 5247f25b..89c4e7a9 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -8,7 +8,7 @@ from distutils.core import Command as _Command from distutils.util import convert_path import os.path -__version__ = '0.5a6' +__version__ = '0.5a7' __all__ = [ 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require', diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index b39df36f..3891526d 100755 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -63,8 +63,34 @@ def walk_revctrl(dirname='', memo=None): for item in walk_revctrl(path, memo): yield item + + + + + + + + + + + + + + + + + class sdist(_sdist): """Smart sdist that finds anything supported by revision control""" + + def run(self): + _sdist.run(self) + dist_files = getattr(self.distribution,'dist_files',[]) + for file in self.archive_files: + data = ('sdist', '', file) + if data not in dist_files: + dist_files.append(data) + def finalize_options(self): _sdist.finalize_options(self) if not os.path.isfile(self.template): @@ -80,3 +106,18 @@ class sdist(_sdist): + + + + + + + + + + + + + + + diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py new file mode 100755 index 00000000..bad01577 --- /dev/null +++ b/setuptools/command/upload.py @@ -0,0 +1,171 @@ +"""distutils.command.upload + +Implements the Distutils 'upload' subcommand (upload package to PyPI).""" + +from distutils.errors import * +from distutils.core import Command +from distutils.spawn import spawn +from distutils import log +from md5 import md5 +import os +import socket +import platform +import ConfigParser +import httplib +import base64 +import urlparse +import cStringIO as StringIO + +class upload(Command): + + description = "upload binary package to PyPI" + + DEFAULT_REPOSITORY = 'http://www.python.org/pypi' + + user_options = [ + ('repository=', 'r', + "url of repository [default: %s]" % DEFAULT_REPOSITORY), + ('show-response', None, + 'display full response text from server'), + ('sign', 's', + 'sign files to upload using gpg'), + ] + boolean_options = ['show-response', 'sign'] + + def initialize_options(self): + self.username = '' + self.password = '' + self.repository = '' + self.show_response = 0 + self.sign = False + + def finalize_options(self): + if os.environ.has_key('HOME'): + rc = os.path.join(os.environ['HOME'], '.pypirc') + if os.path.exists(rc): + self.announce('Using PyPI login from %s' % rc) + config = ConfigParser.ConfigParser({ + 'username':'', + 'password':'', + 'repository':''}) + config.read(rc) + if not self.repository: + self.repository = config.get('server-login', 'repository') + if not self.username: + self.username = config.get('server-login', 'username') + if not self.password: + self.password = config.get('server-login', 'password') + if not self.repository: + self.repository = self.DEFAULT_REPOSITORY + + def run(self): + if not self.distribution.dist_files: + raise DistutilsOptionError("No dist file created in earlier command") + for command, pyversion, filename in self.distribution.dist_files: + self.upload_file(command, pyversion, filename) + + def upload_file(self, command, pyversion, filename): + # Sign if requested + if self.sign: + spawn(("gpg", "--detach-sign", "-a", filename), + dry_run=self.dry_run) + + # Fill in the data + content = open(filename,'rb').read() + basename = os.path.basename(filename) + if basename.endswith('.egg'): + basename += '.zip' + if command=='bdist_egg': + command='sdist' + data = { + ':action':'file_upload', + 'protcol_version':'1', + 'name':self.distribution.get_name(), + 'version':self.distribution.get_version(), + 'content':(basename,content), + 'filetype':command, + 'pyversion':pyversion, + 'md5_digest':md5(content).hexdigest(), + } + comment = '' + if command == 'bdist_rpm': + dist, version, id = platform.dist() + if dist: + comment = 'built for %s %s' % (dist, version) + elif command == 'bdist_dumb': + comment = 'built for %s' % platform.platform(terse=1) + data['comment'] = comment + + if self.sign: + data['gpg_signature'] = (os.path.basename(filename) + ".asc", + open(filename+".asc").read()) + + # set up the authentication + auth = "Basic " + base64.encodestring(self.username + ":" + self.password).strip() + + # Build up the MIME payload for the POST data + boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = '\n--' + boundary + end_boundary = sep_boundary + '--' + body = StringIO.StringIO() + for key, value in data.items(): + # handle multiple entries for the same name + if type(value) != type([]): + value = [value] + for value in value: + if type(value) is tuple: + fn = ';filename="%s"' % value[0] + value = value[1] + else: + fn = "" + value = str(value) + body.write(sep_boundary) + body.write('\nContent-Disposition: form-data; name="%s"'%key) + body.write(fn) + body.write("\n\n") + body.write(value) + if value and value[-1] == '\r': + body.write('\n') # write an extra newline (lurve Macs) + body.write(end_boundary) + body.write("\n") + body = body.getvalue() + + self.announce("Submitting %s to %s" % (filename, 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.urlparse(self.repository) + assert not params and not query and not fragments + if schema == 'http': + http = httplib.HTTPConnection(netloc) + elif schema == 'https': + http = httplib.HTTPSConnection(netloc) + else: + raise AssertionError, "unsupported schema "+schema + + data = '' + loglevel = log.INFO + try: + http.connect() + http.putrequest("POST", url) + http.putheader('Content-type', + 'multipart/form-data; boundary=%s'%boundary) + http.putheader('Content-length', str(len(body))) + http.putheader('Authorization', auth) + http.endheaders() + http.send(body) + except socket.error, e: + self.announce(e.msg, log.ERROR) + return + + r = http.getresponse() + if r.status == 200: + self.announce('Server response (%s): %s' % (r.status, r.reason), + log.INFO) + else: + self.announce('Upload failed (%s): %s' % (r.status, r.reason), + log.ERROR) + if self.show_response: + print '-'*75, r.read(), '-'*75 diff --git a/setuptools/package_index.py b/setuptools/package_index.py index 78962eee..0a8ccddc 100755 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -44,7 +44,9 @@ def distros_for_url(url, metadata=None): path = urlparse.urlparse(url)[2] base = urllib2.unquote(path.split('/')[-1]) - + if base.endswith('.egg.zip'): + base = base[:-4] # strip the .zip + if base.endswith('.egg'): dist = Distribution.from_filename(base, metadata) dist.path = url @@ -58,10 +60,10 @@ def distros_for_url(url, metadata=None): ) # Try source distro extensions (.zip, .tgz, etc.) - # + # for ext in EXTENSIONS: if base.endswith(ext): - base = base[:-len(ext)] + base = base[:-len(ext)] return interpret_distro_name(url, base, metadata) return [] # no extension matched @@ -78,8 +80,6 @@ def distros_for_url(url, metadata=None): - - def interpret_distro_name(url, base, metadata, py_version=None, distro_type=SOURCE_DIST, platform=None ): @@ -139,7 +139,7 @@ class PackageIndex(AvailableDistributions): dists = list(distros_for_url(url)) if dists: self.debug("Found link: %s", url) - if dists or not retrieve or url in self.fetched_urls: + if dists or not retrieve or url in self.fetched_urls: for dist in dists: self.add(dist) # don't need the actual page @@ -164,7 +164,7 @@ class PackageIndex(AvailableDistributions): def process_index(self,url,page): """Process the contents of a PyPI page""" - + def scan(link): # Process a URL to see if it's for a package page if link.startswith(self.index_url): @@ -226,7 +226,7 @@ class PackageIndex(AvailableDistributions): for dist in self.get(requirement.key, ()): if dist in requirement: return dist - self.debug("%s does not match %s", requirement, dist) + self.debug("%s does not match %s", requirement, dist) return super(PackageIndex, self).obtain(requirement,installer) @@ -388,6 +388,9 @@ class PackageIndex(AvailableDistributions): else: name = "__downloaded__" # default if URL has no path contents + if name.endswith('.egg.zip'): + name = name[:-4] # strip the extra .zip before download + filename = os.path.join(tmpdir,name) # Download the file @@ -405,9 +408,6 @@ class PackageIndex(AvailableDistributions): self.process_url(url, True) - - - def _download_html(self, url, headers, filename, tmpdir): # Check for a sourceforge URL sf_url = url.startswith('http://prdownloads.') @@ -445,7 +445,7 @@ class PackageIndex(AvailableDistributions): def info(self, msg, *args): log.info(msg, *args) - + def warn(self, msg, *args): log.warn(msg, *args) |