Jannis Leidel avatar Jannis Leidel committed d9fc6bd

Initial commit with working version

Comments (0)

Files changed (3)

+Copyright (c) 2009, Jannis Leidel
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of the author nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+from setuptools import setup
+
+setup(
+    name="Sphinx-PyPI-upload",
+    version='0.1',
+    author="Jannis Leidel",
+    author_email="jannis@leidel.info",
+    url="http://bitbucket.org/jezdez/sphinx-pypi-upload/",
+    download_url="http://bitbucket.org/jezdez/sphinx-pypi-upload/downloads/",
+    description="setuptools commands to help uploading of Sphinx documentation to PyPI",
+    license="BSD",
+    classifiers=[
+        "Topic :: Documentation",
+        "Framework :: Setuptools Plugin",
+        "Development Status :: 4 - Beta",
+        "Programming Language :: Python",
+        "Intended Audience :: Developers",
+        "Operating System :: OS Independent",
+        'License :: OSI Approved :: BSD License',
+        "Topic :: Software Development :: Documentation",
+        "Topic :: Software Development :: Libraries :: Python Modules",
+    ],
+    platforms='any',
+    py_modules=["sphinx_pypi_upload"],
+    entry_points = {
+        "distutils.commands": [
+            "upload_sphinx = sphinx_pypi_upload:upload",
+        ]
+    }
+)

sphinx_pypi_upload.py

+# -*- coding: utf-8 -*-
+"""
+    sphinx_pypi_upload
+    ~~~~~~~~~~~~~~~~~~
+
+    setuptools commands to help uploading of Sphinx documentation to PyPI
+
+    :author: Jannis Leidel
+    :contact: jannis@leidel.info
+    :copyright: Copyright 2009, Jannis Leidel.
+    :license: BSD, see LICENSE for details.
+"""
+
+import sys
+import os
+import socket
+import zipfile
+import httplib
+import base64
+import urlparse
+import tempfile
+import cStringIO as StringIO
+
+from distutils import log
+from distutils.core import PyPIRCCommand
+from distutils.errors import DistutilsOptionError
+
+class UploadDoc(PyPIRCCommand):
+    """Distutils command to upload Sphinx documentation."""
+
+    description = 'Upload Sphinx documentation to PyPI'
+    user_options = PyPIRCCommand.user_options + [
+        ('upload-dir=', None, 'directory to upload'),
+        ]
+    boolean_options = PyPIRCCommand.boolean_options + ['sign']
+
+    def initialize_options(self):
+        PyPIRCCommand.initialize_options(self)
+        self.upload_dir = None
+        self.username = ''
+        self.password = ''
+        self.show_response = 0
+        self.sign = False
+        self.identity = None
+
+    def finalize_options(self):
+        PyPIRCCommand.finalize_options(self)
+        if self.upload_dir is None:
+            build = self.get_finalized_command('build')
+            self.upload_dir = os.path.join(build.build_base, 'sphinx')
+            self.mkpath(self.upload_dir)
+        self.ensure_dirname('upload_dir')
+        self.announce('Using upload directory %s' % self.upload_dir)
+        config = self._read_pypirc()
+        if config != {}:
+            self.username = config['username']
+            self.password = config['password']
+            self.repository = config['repository']
+            self.realm = config['realm']
+
+    def create_zipfile(self):
+        name = self.distribution.metadata.get_name()
+        tmp_dir = tempfile.mkdtemp()
+        tmp_file = os.path.join(tmp_dir, "%s.zip" % name)
+        zip_file = zipfile.ZipFile(tmp_file, "w")
+        for root, dirs, files in os.walk(self.upload_dir):
+            if not files:
+                raise DistutilsOptionError, \
+                      "no files found in upload directory '%s'" % self.upload_dir
+            for name in files:
+                full = os.path.join(root, name)
+                relative = root[len(self.upload_dir):].lstrip(os.path.sep)
+                dest = os.path.join(relative, name)
+                zip_file.write(full, dest)
+        zip_file.close()
+        return tmp_file
+
+    def upload_file(self, filename):
+        content = open(filename,'rb').read()
+        meta = self.distribution.metadata
+        data = {
+            ':action': 'doc_upload',
+            'name': meta.get_name(),
+            'content': (os.path.basename(filename),content),
+        }
+        # 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 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.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(str(e), log.ERROR)
+            return
+
+        response = http.getresponse()
+        if response.status == 200:
+            self.announce('Server response (%s): %s' % (response.status, response.reason),
+                          log.INFO)
+        elif response.status == 301:
+            location = response.getheader('Location')
+            if location is None:
+                location = 'http://packages.python.org/%s/' % meta.get_name()
+            self.announce('Upload successful. Visit %s' % location,
+                          log.INFO)
+        else:
+            self.announce('Upload failed (%s): %s' % (response.status, response.reason),
+                          log.ERROR)
+        if self.show_response:
+            print '-'*75, response.read(), '-'*75
+
+    def run(self):
+        zip_file = self.create_zipfile()
+        self.upload_file(zip_file)
+        os.remove(zip_file)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.