Commits

Jason R. Coombs  committed ccdf276 Merge

Merge with default

  • Participants
  • Parent commits e8ff1af, 9e4eb30
  • Branches fix-issue-227

Comments (0)

Files changed (35)

 a7cf5ae137f1646adf86ce5d6b5d8b7bd6eab69f 0.6.20
 c4a375336d552129aef174486018ed09c212d684 0.6.20
 de44acab3cfce1f5bc811d6c0fa1a88ca0e9533f 0.6.21
+1a1ab844f03e10528ae693ad3cb45064e08f49e5 0.6.23
+1a1ab844f03e10528ae693ad3cb45064e08f49e5 0.6.23
+9406c5dac8429216f1a264e6f692fdc534476acd 0.6.23
+7fd7b6e30a0effa082baed1c4103a0efa56be98c 0.6.24
+6124053afb5c98f11e146ae62049b4c232d50dc5 0.6.25
 =======
 
 ------
-0.6.22
+0.6.26
 ------
 
+* Issue #183: Symlinked files are now extracted from source distributions.
+
+------
+0.6.25
+------
+
+* Issue #258: Workaround a cache issue
+* Issue #260: distribute_setup.py now accepts the --user parameter for
+  Python 2.6 and later.
+* Issue #262: package_index.open_with_auth no longer throws LookupError
+  on Python 3.
+* Issue #269: AttributeError when an exception occurs reading Manifest.in
+  on late releases of Python.
+* Issue #272: Prevent TypeError when namespace package names are unicode
+  and single-install-externally-managed is used. Also fixes PIP issue
+  449.
+* Issue #273: Legacy script launchers now install with Python2/3 support.
+
+------
+0.6.24
+------
+
+* Issue #249: Added options to exclude 2to3 fixers
+
+------
+0.6.23
+------
+
+* Issue #244: Fixed a test
+* Issue #243: Fixed a test
+* Issue #239: Fixed a test
+* Issue #240: Fixed a test
+* Issue #241: Fixed a test
+* Issue #237: Fixed a test
+* Issue #238: easy_install now uses 64bit executable wrappers on 64bit Python
+* Issue #208: Fixed parsed_versions, it now honors post-releases as noted in the documentation
+* Issue #207: Windows cli and gui wrappers pass CTRL-C to child python process
+* Issue #227: easy_install now passes its arguments to setup.py bdist_egg
 * Issue #225: Fixed a NameError on Python 2.5, 2.4
 
 ------

File DEVGUIDE.txt

 
 Grab the code at bitbucket::
 
-    $ hg clone https://tarek@bitbucket.org/tarek/distribute distribute
+    $ hg clone https://bitbucket.org/tarek/distribute
 
-If you want to work in the 0.6 branch, you have to switch to it::
+If you want to contribute changes, we recommend you fork the repository on
+bitbucket, commit the changes to your repository, and then make a pull request
+on bitbucket. If you make some changes, don't forget to:
 
-    $ hg update 0.6-maintenance
-
-    $ hg branch
-    0.6-maintenance
-
-If you make some changes, don't forget to:
-
-- backport it to the 0.7 branch
 - add a note in CHANGES.txt
 
-And remember that 0.6 is only bug fixes, and the APIs should
-be fully backward compatible with Setuptools.
+And remember that 0.6 (the only development line) is only bug fixes, and the
+APIs should be fully backward compatible with Setuptools.
 
 You can run the tests via::
 
 
 Download the source tarball, uncompress it, then run the install command::
 
-    $ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.22.tar.gz
-    $ tar -xzvf distribute-0.6.22.tar.gz
-    $ cd distribute-0.6.22
+    $ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.26.tar.gz
+    $ tar -xzvf distribute-0.6.26.tar.gz
+    $ cd distribute-0.6.26
     $ python setup.py install
 
 ---------------------------

File distribute.egg-info/entry_points.txt

 
 [console_scripts]
 easy_install = setuptools.command.easy_install:main
-easy_install-2.6 = setuptools.command.easy_install:main
+easy_install-2.7 = setuptools.command.easy_install:main
 
 [setuptools.file_finders]
 svn_cvs = setuptools.command.sdist:_default_revctrl
 dependency_links = setuptools.dist:assert_string_list
 entry_points = setuptools.dist:check_entry_points
 extras_require = setuptools.dist:check_extras
+use_2to3_exclude_fixers = setuptools.dist:assert_string_list
 package_data = setuptools.dist:check_package_data
 install_requires = setuptools.dist:check_requirements
 use_2to3 = setuptools.dist:assert_bool

File distribute_setup.py

             args = [quote(arg) for arg in args]
         return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
 
-DEFAULT_VERSION = "0.6.22"
+DEFAULT_VERSION = "0.6.26"
 DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
 SETUPTOOLS_FAKED_VERSION = "0.6c11"
 
 """ % SETUPTOOLS_FAKED_VERSION
 
 
-def _install(tarball):
+def _install(tarball, install_args=()):
     # extracting the tarball
     tmpdir = tempfile.mkdtemp()
     log.warn('Extracting in %s', tmpdir)
 
         # installing
         log.warn('Installing Distribute')
-        if not _python_cmd('setup.py', 'install'):
+        if not _python_cmd('setup.py', 'install', *install_args):
             log.warn('Something went wrong during the installation.')
             log.warn('See the error message above.')
     finally:
             else:
                 self._dbg(1, "tarfile: %s" % e)
 
+def _build_install_args(argv):
+    install_args = []
+    user_install = '--user' in argv
+    if user_install and sys.version_info < (2,6):
+        log.warn("--user requires Python 2.6 or later")
+        raise SystemExit(1)
+    if user_install:
+        install_args.append('--user')
+    return install_args
 
 def main(argv, version=DEFAULT_VERSION):
     """Install or upgrade setuptools and EasyInstall"""
     tarball = download_setuptools()
-    _install(tarball)
+    _install(tarball, _build_install_args(argv))
 
 
 if __name__ == '__main__':

File docs/conf.py

 # built documents.
 #
 # The short X.Y version.
-version = '0.6.17'
+version = '0.6.26'
 # The full version, including alpha/beta/rc tags.
-release = '0.6.17'
+release = '0.6.26'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

File docs/easy_install.txt

     judgment and force an installation directory to be treated as if it
     supported ``.pth`` files.
 
-    (If you want to *make* a non-``PYTHONPATH`` directory support ``.pth``
-    files, please see the `Administrator Installation`_ section below.)
-
 ``--no-deps, -N``  (New in 0.6a6)
     Don't install any dependencies.  This is intended as a convenience for
     tools that wrap eggs in a platform-specific packaging system.  (We don't
 Custom Installation Locations
 -----------------------------
 
-EasyInstall manages what packages are active using Python ``.pth`` files, which
-are normally only usable in Python's main ``site-packages`` directory.  On some
-platforms (such as Mac OS X), there are additional ``site-packages``
-directories that you can use besides the main one, but usually there is only
-one directory on the system where you can install packages without extra steps.
+By default, EasyInstall installs python packages into Python's main ``site-packages`` directory,
+and manages them using a custom ``.pth`` file in that same directory.
 
-There are many reasons, however, why you might want to install packages
-somewhere other than the ``site-packages`` directory.  For example, you might
-not have write access to that directory.  You may be working with unstable
-versions of packages that you don't want to install system-wide.  And so on.
+Very often though, a user or developer wants ``easy_install`` to install and manage python packages
+in an alternative location, usually for one of 3 reasons:
 
-The following sections describe various approaches to custom installation; feel
-free to choose which one best suits your system and needs.
+1. They don't have access to write to the main Python site-packages directory.
 
-`Administrator Installation`_
-    This approach is for when you have write access to ``site-packages`` (or
-    another directory where ``.pth`` files are processed), but don't want to
-    install packages there.  This can also be used by a system administrator
-    to enable each user having their own private directories that EasyInstall
-    will use to install packages.
+2. They want a user-specific stash of packages, that is not visible to other users.
 
-`Mac OS X "User" Installation`_
-    This approach produces a result similar to an administrator installation
-    that gives each user their own private package directory, but on Mac OS X
-    the hard part has already been done for you.  This is probably the best
-    approach for Mac OS X users.
+3. They want to isolate a set of packages to a specific python application, usually to minimize
+   the possibility of version conflicts.
 
-`Creating a "Virtual" Python`_
-    This approach is for when you don't have "root" or access to write to the
-    ``site-packages`` directory, and would like to be able to set up one or
-    more "virtual python" executables for your projects.  This approach
-    gives you the benefits of multiple Python installations, but without having
-    to actually install Python more than once and use up lots of disk space.
-    (Only the Python executable is copied; the libraries will be symlinked
-    from the systemwide Python.)
+Historically, there have been many approaches to achieve custom installation.
+The following section lists only the easiest and most relevant approaches [1]_.
 
-    If you don't already have any ``PYTHONPATH`` customization or
-    special distutils configuration, and you can't use either of the preceding
-    approaches, this is probably the best one for you.
+`Use the "--user" option`_
 
-`"Traditional" PYTHONPATH-based Installation`_
-    If you already have a custom ``PYTHONPATH``, and/or a custom distutils
-    configuration, and don't want to change any of your existing setup, you may
-    be interested in this approach.  (If you're using a custom ``.pth`` file to
-    point to your custom installation location, however, you should use
-    `Administrator Installation`_ to enable ``.pth`` processing in the custom
-    location instead, as that is easier and more flexible than this approach.)
+`Use the "--user" option and customize "PYTHONUSERBASE"`_
 
+`Use "virtualenv"`_
 
-Administrator Installation
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. [1] There are older ways to achieve custom installation using various ``easy_install`` and ``setup.py install`` options, combined with ``PYTHONPATH`` and/or ``PYTHONUSERBASE`` alterations, but all of these are effectively deprecated by the User scheme brought in by `PEP-370`_ in Python 2.6.
 
-If you have root access to your machine, you can easily configure it to allow
-each user to have their own directory where Python packages can be installed
-and managed by EasyInstall.
+.. _PEP-370: http://www.python.org/dev/peps/pep-0370/
 
-First, create an ``altinstall.pth`` file in Python's ``site-packages``
-directory,  containing the following line (substituting the correct Python
-version)::
 
-    import os, site; site.addsitedir(os.path.expanduser('~/lib/python2.3'))
+Use the "--user" option
+~~~~~~~~~~~~~~~~~~~~~~~
+With Python 2.6 came the User scheme for installation, which means that all
+python distributions support an alternative install location that is specific to a user [2]_ [3]_.
+The Default location for each OS is explained in the python documentation
+for the ``site.USER_BASE`` variable.  This mode of installation can be turned on by
+specifying the ``--user`` option to ``setup.py install`` or ``easy_install``.
+This approach serves the need to have a user-specific stash of packages.
 
-This will automatically add each user's ``~/lib/python2.X`` directory to
-``sys.path`` (if it exists), *and* it will process any ``.pth`` files in that
-directory -- which is what makes it usable with EasyInstall.
+.. [2] Prior to Python2.6, Mac OS X offered a form of the User scheme. That is now subsumed into the User scheme introduced in Python 2.6.
+.. [3] Prior to the User scheme, there was the Home scheme, which is still available, but requires more effort than the User scheme to get packages recognized.
 
-The next step is to create or modify ``distutils.cfg`` in the ``distutils``
-directory of your Python library.  The correct directory will be something like
-``/usr/lib/python2.X/distutils`` on most Posix systems and something like
-``C:\\Python2X\Lib\distutils`` on Windows machines.  Add the following lines
-to the file, substituting the correct Python version if necessary:
+Use the "--user" option and customize "PYTHONUSERBASE"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The User scheme install location can be customized by setting the ``PYTHONUSERBASE`` environment
+variable, which updates the value of ``site.USER_BASE``.  To isolate packages to a specific
+application, simply set the OS environment of that application to a specific value of
+``PYTHONUSERBASE``, that contains just those packages.
 
-.. code-block:: ini
+Use "virtualenv"
+~~~~~~~~~~~~~~~~
+"virtualenv" is a 3rd-party python package that effectively "clones" a python installation, thereby
+creating an isolated location to intall packages.  The evolution of "virtualenv" started before the existence
+of the User installation scheme.  "virtualenv" provides a version of ``easy_install`` that is
+scoped to the cloned python install and is used in the normal way. "virtualenv" does offer various features
+that the User installation scheme alone does not provide, e.g. the ability to hide the main python site-packages.
 
-    [install]
-    install_lib = ~/lib/python2.3
-
-    # This next line is optional but often quite useful; it directs EasyInstall
-    # and the distutils to install scripts in the user's "bin" directory.  For
-    # Mac OS X framework Python builds, you should use /usr/local/bin instead,
-    # because neither ~/bin nor the default script installation location are on
-    # the system PATH.
-    #
-    install_scripts = ~/bin
-
-This will configure the distutils and EasyInstall to install packages to the
-user's home directory by default.
-
-Of course, you aren't limited to using a ``~/lib/python2.X`` directory with
-this approach.  You can substitute a specific systemwide directory if you like.
-You can also edit ``~/.pydistutils.cfg`` (or ``~/pydistutils.cfg`` on Windows)
-instead of changing the master ``distutils.cfg`` file.  The true keys of this
-approach are simply that:
-
-1. any custom installation directory must be added to ``sys.path`` using a
-   ``site.addsitedir()`` call from a working ``.pth`` file or
-   ``sitecustomize.py``.
-
-2. The active distutils configuration file(s) or ``easy_install`` command line
-   should include the custom directory in the ``--site-dirs`` option, so that
-   EasyInstall knows that ``.pth`` files will work in that location.  (This is
-   because Python does not keep track of what directories are or aren't enabled
-   for ``.pth`` processing, in any way that EasyInstall can find out.)
-
-As long as both of these things have been done, your custom installation
-location is good to go.
-
-
-Mac OS X "User" Installation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are on a Mac OS X machine, you should just use the
-``~/Library/Python/2.x/site-packages`` directory as your custom installation
-location, because it is already configured to process ``.pth`` files, and
-EasyInstall already knows this.
-
-Before installing EasyInstall/setuptools, just create a ``~/.pydistutils.cfg``
-file with the following contents (or add this to the existing contents):
-
-.. code-block:: ini
-
-    [install]
-    install_lib = ~/Library/Python/$py_version_short/site-packages
-    install_scripts = ~/bin
-
-This will tell the distutils and EasyInstall to always install packages in
-your personal ``site-packages`` directory, and scripts to ``~/bin``.  (Note: do
-*not* replace ``$py_version_short`` with an actual Python version in the
-configuration file!  The distutils will substitute the correct value at
-runtime, so that the above configuration file should work correctly no matter
-what Python version you use, now or in the future.)
-
-Once you have done this, you can follow the normal `installation instructions`_
-and use ``easy_install`` without any other special options or steps.
-
-(Note, however, that ``~/bin`` is not in the default ``PATH``, so you may have
-to refer to scripts by their full location.  You may want to modify your shell
-startup script (likely ``.bashrc`` or ``.profile``) or your
-``~/.MacOSX/environment.plist`` to include ``~/bin`` in your ``PATH``.
-
-
-Creating a "Virtual" Python
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are on a Linux, BSD, Cygwin, or other similar Unix-like operating
-system, but don't have root access, you can create your own "virtual"
-Python installation, which uses its own library directories and some symlinks
-to the site-wide Python.
-
-Please refer to the `virtualenv`_ documentation for creating such an
-environment.
+Please refer to the `virtualenv`_ documentation for more details.
 
 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
 
 
-"Traditional" ``PYTHONPATH``-based Installation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This installation method is not as robust or as flexible as `creating a
-"virtual" python`_ installation, as it uses various tricks to fool Python into
-processing ``.pth`` files where it normally wouldn't.  We suggest you at least
-consider using one of the other approaches, as they will generally result in
-a cleaner, more usable Python configuration.  However, if for some reason you
-can't or won't use one of the other approaches, here's how to do it.
-
-Assuming that you want to install packages in a directory called ``~/py-lib``,
-and scripts in ``~/bin``, here's what you need to do:
-
-First, edit ``~/.pydistutils.cfg`` to include these settings, if you don't
-already have them:
-
-.. code-block:: ini
-
-    [install]
-    install_lib = ~/py-lib
-    install_scripts = ~/bin
-
-Be sure to do this *before* you try to run the ``distribute_setup.py``
-installation script.  Then, follow the standard `installation instructions`_,
-but make sure that ``~/py-lib`` is listed in your ``PYTHONPATH`` environment
-variable.
-
-Your library installation directory *must* be in listed in ``PYTHONPATH``,
-not only when you install packages with EasyInstall, but also when you use
-any packages that are installed using EasyInstall.  You will probably want to
-edit your ``~/.profile`` or other configuration file(s) to ensure that it is
-set, if you haven't already got this set up on your machine.
-
 
 Package Index "API"
 -------------------

File docs/python3.txt

 
 Distribute will convert all Python files, and also all doctests in Python
 files. However, if you have doctests located in separate text files, these
-will not automatically be converted. By adding them to the 
-``convert_2to3_doctests`` keyword parameter Distrubute will convert them as 
-well. 
+will not automatically be converted. By adding them to the
+``convert_2to3_doctests`` keyword parameter Distrubute will convert them as
+well.
 
 By default, the conversion uses all fixers in the ``lib2to3.fixers`` package.
-To use additional fixes, the parameter ``use_2to3_fixers`` can be set
-to a list of names of packages containing fixers.
+To use additional fixers, the parameter ``use_2to3_fixers`` can be set
+to a list of names of packages containing fixers. To exclude fixers, the
+parameter ``use_2to3_exclude_fixers`` can be set to fixer names to be
+skipped.
 
 A typical setup.py can look something like this::
 
     from setuptools import setup
-    
+
     setup(
         name='your.module',
         version = '1.0',
         test_suite = 'your.module.tests',
         use_2to3 = True,
         convert_2to3_doctests = ['src/your/module/README.txt'],
-        use_2to3_fixers = ['your.fixers']
+        use_2to3_fixers = ['your.fixers'],
+        use_2to3_exclude_fixers = ['lib2to3.fixes.fix_import'],
     )
 
 Differential conversion
 Note that a file will only be copied and converted during the build process
 if the source file has been changed. If you add a file to the doctests
 that should be converted, it will not be converted the next time you run
-the tests, since it hasn't been modified. You need to remove it from the 
+the tests, since it hasn't been modified. You need to remove it from the
 build directory. Also if you run the build, install or test commands before
 adding the use_2to3 parameter, you will have to remove the build directory
-before you run the test command, as the files otherwise will seem updated, 
+before you run the test command, as the files otherwise will seem updated,
 and no conversion will happen.
 
 In general, if code doesn't seem to be converted, deleting the build directory
 Advanced features
 =================
 
-If certain fixers are to be suppressed, this again can be overridden with the
-list ``setuptools.command.build_py.build_py.fixer_names``, which at some
-point contains the list of all fixer class names. For an example of how this
-can be done, see the `jaraco.util <https://bitbucket.org/jaraco/jaraco.util>`_
-project.
-
 If you don't want to run the 2to3 conversion on the doctests in Python files,
 you can turn that off by setting ``setuptools.use_2to3_on_doctests = False``.
 
 As a result it will warn about the unknown keyword parameters if you use
 setuptools instead of Distribute under Python 2. This is not an error, and
 install process will continue as normal, but if you want to get rid of that
-error this is easy. Simply conditionally add the new parameters into an extra 
+error this is easy. Simply conditionally add the new parameters into an extra
 dict and pass that dict into setup()::
 
     from setuptools import setup
     import sys
-    
+
     extra = {}
     if sys.version_info >= (3,):
         extra['use_2to3'] = True
         extra['convert_2to3_doctests'] = ['src/your/module/README.txt']
         extra['use_2to3_fixers'] = ['your.fixers']
-    
+
     setup(
         name='your.module',
         version = '1.0',
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <unistd.h>
+#include <string.h>
+#include <windows.h>
+#include <tchar.h>
 #include <fcntl.h>
-#include "windows.h"
+
+int child_pid=0;
 
 int fail(char *format, char *data) {
     /* Print error message to stderr and return 2 */
     return 2;
 }
 
-
-
-
-
 char *quoted(char *data) {
     int i, ln = strlen(data), nb;
 
     /* Return the absolute filename for spawnv */
     result = calloc(MAX_PATH, sizeof(char));
     strncpy(result, exename, MAX_PATH);
-    /*if (result) GetModuleFileName(hPython, result, MAX_PATH);
+    /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
 
     FreeLibrary(hPython); */
     return result;
     } while (1);
 }
 
+void pass_control_to_child(DWORD control_type) {
+    /*
+     * distribute-issue207
+     * passes the control event to child process (Python)
+     */
+    if (!child_pid) {
+        return;
+    }
+    GenerateConsoleCtrlEvent(child_pid,0);
+}
 
+BOOL control_handler(DWORD control_type) {
+    /* 
+     * distribute-issue207
+     * control event handler callback function
+     */
+    switch (control_type) {
+        case CTRL_C_EVENT:
+            pass_control_to_child(0);
+            break;
+    }
+    return TRUE;
+}
 
+int create_and_wait_for_subprocess(char* command) {
+    /*
+     * distribute-issue207
+     * launches child process (Python)
+     */
+    DWORD return_value = 0;
+    LPSTR commandline = command;
+    STARTUPINFOA s_info;
+    PROCESS_INFORMATION p_info;
+    ZeroMemory(&p_info, sizeof(p_info));
+    ZeroMemory(&s_info, sizeof(s_info));
+    s_info.cb = sizeof(STARTUPINFO);
+    // set-up control handler callback funciotn
+    SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
+    if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
+        fprintf(stderr, "failed to create process.\n");
+        return 0;
+    }   
+    child_pid = p_info.dwProcessId;
+    // wait for Python to exit
+    WaitForSingleObject(p_info.hProcess, INFINITE);
+    if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
+        fprintf(stderr, "failed to get exit code from process.\n");
+        return 0;
+    }
+    return return_value;
+}
+
+char* join_executable_and_args(char *executable, char **args, int argc)
+{
+    /*
+     * distribute-issue207
+     * CreateProcess needs a long string of the executable and command-line arguments,
+     * so we need to convert it from the args that was built
+     */
+    int len,counter;
+    char* cmdline;
+    
+    len=strlen(executable)+2;
+    for (counter=1; counter<argc; counter++) {
+        len+=strlen(args[counter])+1;
+    }
+
+    cmdline = (char*)calloc(len, sizeof(char));
+    sprintf(cmdline, "%s", executable);
+    len=strlen(executable);
+    for (counter=1; counter<argc; counter++) {
+        sprintf(cmdline+len, " %s", args[counter]);
+        len+=strlen(args[counter])+1;
+    }
+    return cmdline;
+}
 
 int run(int argc, char **argv, int is_gui) {
 
 
     char **newargs, **newargsp, **parsedargs; /* argument array for exec */
     char *ptr, *end;    /* working pointers for string manipulation */
+    char *cmdline;
     int i, parsedargc;              /* loop counter */
 
     /* compute script name from our .exe name*/
-    GetModuleFileName(NULL, script, sizeof(script));
+    GetModuleFileNameA(NULL, script, sizeof(script));
     end = script + strlen(script);
     while( end>script && *end != '.')
         *end-- = '\0';
         return fail("Could not exec %s", ptr);   /* shouldn't get here! */
     }
 
-    /* We *do* need to wait for a CLI to finish, so use spawn */
-    return spawnv(P_WAIT, ptr, (const char * const *)(newargs));
+    /*
+     * distribute-issue207: using CreateProcessA instead of spawnv
+     */
+    cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
+    return create_and_wait_for_subprocess(cmdline);
 }
 
-
 int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
     return run(__argc, __argv, GUI);
 }
 
+int main(int argc, char** argv) {
+    return run(argc, argv, GUI);
+}
+

File pkg_resources.py

         """
         seen = {}
         for item in self.entries:
+            if item not in self.entry_keys:
+                # workaround a cache issue
+                continue
+
             for key in self.entry_keys[item]:
                 if key not in seen:
                     seen[key]=1
 def _parse_version_parts(s):
     for part in component_re.split(s):
         part = replace(part,part)
-        if not part or part=='.':
+        if part in ['', '.']:
             continue
         if part[:1] in '0123456789':
             yield part.zfill(8)    # pad for numeric comparison
     parts = []
     for part in _parse_version_parts(s.lower()):
         if part.startswith('*'):
-            if part<'*final':   # remove '-' before a prerelease tag
-                while parts and parts[-1]=='*final-': parts.pop()
             # remove trailing zeros from each series of numeric parts
             while parts and parts[-1]=='00000000':
                 parts.pop()
+#!/usr/bin/env python
+
+"""
+Script to fully automate the release process. Requires Python 2.6+
+with sphinx installed and the 'hg' command on the path.
+"""
+
+from __future__ import print_function
+
+import subprocess
+import shutil
+import os
+import sys
+
+VERSION = '0.6.26'
+
+def get_next_version():
+	digits = map(int, VERSION.split('.'))
+	digits[-1] += 1
+	return '.'.join(map(str, digits))
+
+NEXT_VERSION = get_next_version()
+
+files_with_versions = ('docs/conf.py', 'setup.py', 'release.py',
+	'README.txt', 'distribute_setup.py')
+
+def bump_versions():
+	list(map(bump_version, files_with_versions))
+
+def bump_version(filename):
+	with open(filename, 'rb') as f:
+		lines = [line.replace(VERSION, NEXT_VERSION) for line in f]
+	with open(filename, 'wb') as f:
+		f.writelines(lines)
+
+def do_release():
+	assert all(map(os.path.exists, files_with_versions)), (
+		"Expected file(s) missing")
+	res = raw_input('Have you read through the SCM changelog and '
+		'confirmed the changelog is current for releasing {VERSION}? '
+		.format(**globals()))
+	if not res.lower().startswith('y'):
+		print("Please do that")
+		raise SystemExit(1)
+
+	res = raw_input('Have you or has someone verified that the tests '
+		'pass on this revision? ')
+	if not res.lower().startswith('y'):
+		print("Please do that")
+		raise SystemExit(2)
+
+	subprocess.check_call(['hg', 'tag', VERSION])
+
+	subprocess.check_call(['hg', 'update', VERSION])
+
+	build_docs()
+	if os.path.isdir('./dist'):
+		shutil.rmtree('./dist')
+	subprocess.check_call([sys.executable, 'setup.py',
+		'-q', 'egg_info', '-RD', '-b', '', 'sdist', 'register',
+		'upload', 'upload_docs'])
+	upload_bootstrap_script()
+
+	# update to the tip for the next operation
+	subprocess.check_call(['hg', 'update'])
+
+	# we just tagged the current version, bump for the next release.
+	bump_versions()
+	subprocess.check_call(['hg', 'ci', '-m',
+		'Bumped to {NEXT_VERSION} in preparation for next '
+		'release.'.format(**globals())])
+
+	# push the changes
+	subprocess.check_call(['hg', 'push'])
+
+	# TODO: update bitbucket milestones and versions
+
+def build_docs():
+	if os.path.isdir('docs/build'):
+		shutil.rmtree('docs/build')
+	subprocess.check_call([
+		'sphinx-build',
+		'-b', 'html',
+		'-d', 'build/doctrees',
+		'.',
+		'build/html',
+		],
+		cwd='docs')
+
+def upload_bootstrap_script():
+	scp_command = 'pscp' if sys.platform.startswith('win') else 'scp'
+	try:
+		subprocess.check_call([scp_command, 'distribute_setup.py',
+			'pypi@ziade.org:python-distribute.org/'])
+	except:
+		print("Unable to upload bootstrap script. Ask Tarek to do it.")
+
+if __name__ == '__main__':
+	do_release()

File release.sh

-#!/bin/sh
-export VERSION="0.6.22"
-
-# tagging
-hg tag $VERSION
-hg ci -m "bumped revision"
-
-# creating the releases
-rm -rf ./dist
-
-# now preparing the source release, pushing it and its doc
-python2.6 setup.py -q egg_info -RDb '' sdist register upload
-cd docs/
-make html
-cd ..
-python2.6 setup.py upload_docs
-
-# pushing the bootstrap script
-scp distribute_setup.py ziade.org:websites/python-distribute.org/
-
-# starting the new dev
-hg push
-

File setup.cfg

File contents unchanged.
 exec(open(init_path).read(), d)
 
 SETUP_COMMANDS = d['__all__']
-VERSION = "0.6.22"
+VERSION = "0.6.26"
 
 from setuptools import setup, find_packages
 from setuptools.command.build_py import build_py as _build_py
             "test_loader            = setuptools.dist:check_importable",
             "use_2to3               = setuptools.dist:assert_bool",
             "convert_2to3_doctests  = setuptools.dist:assert_string_list",
-            "use_2to3_fixers = setuptools.dist:assert_string_list",
+            "use_2to3_fixers        = setuptools.dist:assert_string_list",
+            "use_2to3_exclude_fixers = setuptools.dist:assert_string_list",
         ],
 
         "egg_info.writers": [

File setuptools/archive_util.py

     try:
         tarobj.chown = lambda *args: None   # don't do any chowning!
         for member in tarobj:
-            if member.isfile() or member.isdir():
-                name = member.name
-                # don't extract absolute paths or ones with .. in them
-                if not name.startswith('/') and '..' not in name:
-                    dst = os.path.join(extract_dir, *name.split('/'))                
-                    dst = progress_filter(name, dst)
-                    if dst:
-                        if dst.endswith(os.sep):
-                            dst = dst[:-1]
-                        try:
-                            tarobj._extract_member(member,dst)  # XXX Ugh
-                        except tarfile.ExtractError:
-                            pass    # chown/chmod/mkfifo/mknode/makedev failed
+            name = member.name
+            # don't extract absolute paths or ones with .. in them
+            if not name.startswith('/') and '..' not in name:
+                prelim_dst = os.path.join(extract_dir, *name.split('/'))
+                final_dst = progress_filter(name, prelim_dst)
+                # If progress_filter returns None, then we do not extract
+                # this file
+                # TODO: Do we really need to limit to just these file types?
+                # tarobj.extract() will handle all files on all platforms,
+                # turning file types that aren't allowed on that platform into
+                # regular files.
+                if final_dst and (member.isfile() or member.isdir() or
+                        member.islnk() or member.issym()):
+                    tarobj.extract(member, extract_dir)
+                    if final_dst != prelim_dst:
+                        shutil.move(prelim_dst, final_dst)
         return True
     finally:
         tarobj.close()

File setuptools/cli-32.exe

Binary file added.

File setuptools/cli-64.exe

Binary file added.

File setuptools/cli.exe

Binary file modified.

File setuptools/command/__init__.py

 
 from distutils.command.bdist import bdist
 
-
 if 'egg' not in bdist.format_commands:
     bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
     bdist.format_commands.append('egg')

File setuptools/command/build_py.py

             if not files:
                 return
             log.info("Fixing "+" ".join(files))
-            if not self.fixer_names:
-                self.fixer_names = []
-                for p in setuptools.lib2to3_fixer_packages:
-                    self.fixer_names.extend(get_fixers_from_package(p))
-                if self.distribution.use_2to3_fixers is not None:
-                    for p in self.distribution.use_2to3_fixers:
-                        self.fixer_names.extend(get_fixers_from_package(p))
+            self.__build_fixer_names()
+            self.__exclude_fixers()
             if doctests:
                 if setuptools.run_2to3_on_doctests:
                     r = DistutilsRefactoringTool(self.fixer_names)
             else:
                 _Mixin2to3.run_2to3(self, files)
 
+        def __build_fixer_names(self):
+            if self.fixer_names: return
+            self.fixer_names = []
+            for p in setuptools.lib2to3_fixer_packages:
+                self.fixer_names.extend(get_fixers_from_package(p))
+            if self.distribution.use_2to3_fixers is not None:
+                for p in self.distribution.use_2to3_fixers:
+                    self.fixer_names.extend(get_fixers_from_package(p))
+
+        def __exclude_fixers(self):
+            excluded_fixers = getattr(self, 'exclude_fixers', [])
+            if self.distribution.use_2to3_exclude_fixers is not None:
+                excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers)
+            for fixer_name in excluded_fixers:
+                if fixer_name not in self.fixer_names:
+                    log.warn("Excluded fixer %s not found", fixer_name)
+                    continue
+                self.fixer_names.remove(fixer_name)
+
 except ImportError:
     class Mixin2to3:
         def run_2to3(self, files, doctests=True):

File setuptools/command/easy_install.py

 import site
 HAS_USER_SITE = not sys.version < "2.6" and site.ENABLE_USER_SITE
 
+import struct
+def is_64bit():
+    return struct.calcsize("P") == 8
+
 def samefile(p1,p2):
     if hasattr(os.path,'samefile') and (
         os.path.exists(p1) and os.path.exists(p2)
         spec = str(dist.as_requirement())
         is_script = is_python_script(script_text, script_name)
 
-        if is_script and dev_path:
-            script_text = get_script_header(script_text) + (
-                "# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r\n"
-                "__requires__ = %(spec)r\n"
-                "from pkg_resources import require; require(%(spec)r)\n"
-                "del require\n"
-                "__file__ = %(dev_path)r\n"
-                "execfile(__file__)\n"
-            ) % locals()
-        elif is_script:
-            script_text = get_script_header(script_text) + (
-                "# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r\n"
-                "__requires__ = %(spec)r\n"
-                "import pkg_resources\n"
-                "pkg_resources.run_script(%(spec)r, %(script_name)r)\n"
-            ) % locals()
+        def get_template(filename):
+            """
+            There are a couple of template scripts in the package. This
+            function loads one of them and prepares it for use.
+
+            These templates use triple-quotes to escape variable
+            substitutions so the scripts get the 2to3 treatment when build
+            on Python 3. The templates cannot use triple-quotes naturally.
+            """
+            raw_bytes = resource_string('setuptools', template_name)
+            template_str = raw_bytes.decode('utf-8')
+            clean_template = template_str.replace('"""', '')
+            return clean_template
+
+        if is_script:
+            template_name = 'script template.py'
+            if dev_path:
+                template_name = template_name.replace('.py', ' (dev).py')
+            script_text = (get_script_header(script_text) +
+                get_template(template_name) % locals())
         self.write_script(script_name, _to_ascii(script_text), 'b')
 
     def write_script(self, script_name, contents, mode="t", blockers=()):
                     ext, launcher = '-script.py', 'cli.exe'
                     old = ['.py','.pyc','.pyo']
                     new_header = re.sub('(?i)pythonw.exe','python.exe',header)
-
+                if is_64bit():
+                    launcher = launcher.replace(".", "-64.")
+                else:
+                    launcher = launcher.replace(".", "-32.")
                 if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
                     hdr = new_header
                 else:

File setuptools/command/install_egg_info.py

         if not self.dry_run:
             f = open(filename,'wt')
             for pkg in nsp:
+                # ensure pkg is not a unicode string under Python 2.7
+                pkg = str(pkg)
                 pth = tuple(pkg.split('.'))
                 trailer = '\n'
                 if '.' in pkg:

File setuptools/command/register.py

File contents unchanged.

File setuptools/command/sdist.py

             build_scripts = self.get_finalized_command('build_scripts')
             self.filelist.extend(build_scripts.get_source_files())
 
-    def read_template(self):
+    def __read_template_hack(self):
+        # This grody hack closes the template file (MANIFEST.in) if an
+        #  exception occurs during read_template.
+        # Doing so prevents an error when easy_install attempts to delete the
+        #  file.
         try:
             _sdist.read_template(self)
         except:
-            # grody hack to close the template file (MANIFEST.in)
-            # this prevents easy_install's attempt at deleting the file from
-            # dying and thus masking the real error
             sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
             raise
+    # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle
+    #  has been fixed, so only override the method if we're using an earlier
+    #  Python.
+    if (
+            sys.version_info < (2,7,2)
+            or (3,0) <= sys.version_info < (3,1,4)
+            or (3,2) <= sys.version_info < (3,2,1)
+        ):
+        read_template = __read_template_hack
 
     def check_readme(self):
         alts = ("README", "README.txt")

File setuptools/command/upload.py

                           log.ERROR)
         if self.show_response:
             print '-'*75, r.read(), '-'*75
+

File setuptools/extension.py

-from distutils.core import Extension as _Extension
+import sys
+import distutils.core
+import distutils.extension
+
 from setuptools.dist import _get_unpatched
-_Extension = _get_unpatched(_Extension)
 
-# Prefer Cython to Pyrex
-pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
-for pyrex_impl in pyrex_impls:
-	try:
-		# from (pyrex_impl) import build_ext
-		build_ext = __import__(pyrex_impl, fromlist=['build_ext']).build_ext
-		break
-	except:
-		pass
-have_pyrex = 'build_ext' in globals()
+_Extension = _get_unpatched(distutils.core.Extension)
+
+def have_pyrex():
+    """
+    Return True if Cython or Pyrex can be imported.
+    """
+    pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
+    for pyrex_impl in pyrex_impls:
+        try:
+            # from (pyrex_impl) import build_ext
+            __import__(pyrex_impl, fromlist=['build_ext']).build_ext
+            return True
+        except Exception:
+            pass
+    return False
 
 
 class Extension(_Extension):
     """Extension that uses '.c' files in place of '.pyx' files"""
 
-    if not have_pyrex:
-        # convert .pyx extensions to .c 
-        def __init__(self,*args,**kw):
-            _Extension.__init__(self,*args,**kw)
-            sources = []
-            for s in self.sources:
-                if s.endswith('.pyx'):
-                    sources.append(s[:-3]+'c')
-                else:
-                    sources.append(s)
-            self.sources = sources
+    def __init__(self, *args, **kw):
+        _Extension.__init__(self, *args, **kw)
+        if not have_pyrex():
+            self._convert_pyx_sources_to_c()
+
+    def _convert_pyx_sources_to_c(self):
+        "convert .pyx extensions to .c"
+        def pyx_to_c(source):
+            if source.endswith('.pyx'):
+                source = source[:-4] + '.c'
+            return source
+        self.sources = map(pyx_to_c, self.sources)
 
 class Library(Extension):
     """Just like a regular Extension, but built as a library instead"""
 
-import sys, distutils.core, distutils.extension
 distutils.core.Extension = Extension
 distutils.extension.Extension = Extension
 if 'distutils.command.build_ext' in sys.modules:
     sys.modules['distutils.command.build_ext'].Extension = Extension
-

File setuptools/gui-32.exe

Binary file added.

File setuptools/gui-64.exe

Binary file added.

File setuptools/gui.exe

Binary file modified.

File setuptools/package_index.py

 """PyPI and direct package downloading"""
 import sys, os.path, re, urlparse, urllib, urllib2, shutil, random, socket, cStringIO
+import base64
 import httplib
 from pkg_resources import *
 from distutils import log
         return _socket_timeout
     return _socket_timeout
 
+def _encode_auth(auth):
+    """
+    A function compatible with Python 2.3-3.3 that will encode
+    auth from a URL suitable for an HTTP header.
+    >>> _encode_auth('username%3Apassword')
+    u'dXNlcm5hbWU6cGFzc3dvcmQ='
+    """
+    auth_s = urllib2.unquote(auth)
+    # convert to bytes
+    auth_bytes = auth_s.encode()
+    # use the legacy interface for Python 2.3 support
+    encoded_bytes = base64.encodestring(auth_bytes)
+    # convert back to a string
+    encoded = encoded_bytes.decode()
+    # strip the trailing carriage return
+    return encoded.rstrip()
 
 def open_with_auth(url):
     """Open a urllib2 request, handling HTTP authentication"""
         auth = None
 
     if auth:
-        auth = "Basic " + urllib2.unquote(auth).encode('base64').strip()
+        auth = "Basic " + _encode_auth(auth)
         new_url = urlparse.urlunparse((scheme,host,path,params,query,frag))
         request = urllib2.Request(new_url)
         request.add_header("Authorization", auth)

File setuptools/script template (dev).py

+# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
+__requires__ = """%(spec)r"""
+from pkg_resources import require; require("""%(spec)r""")
+del require
+__file__ = """%(dev_path)r"""
+execfile(__file__)

File setuptools/script template.py

+# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
+__requires__ = """%(spec)r"""
+import pkg_resources
+pkg_resources.run_script("""%(spec)r""", """%(script_name)r""")

File setuptools/tests/test_easy_install.py

 
         old_platform = sys.platform
         try:
-            name, script = get_script_args(dist).next()
+            name, script = [i for i in get_script_args(dist).next()][0:2]
         finally:
             sys.platform = old_platform
 
         self.assert_(pth.dirty)
 
     def test_add_from_site_is_ignored(self):
-        pth = PthDistributions('does-not_exist', ['/test/location/does-not-have-to-exist'])
+        if os.name != 'nt':
+            location = '/test/location/does-not-have-to-exist'
+        else:
+            location = 'c:\\does_not_exist'
+        pth = PthDistributions('does-not_exist', [location, ])
         self.assert_(not pth.dirty)
-        pth.add(PRDistribution('/test/location/does-not-have-to-exist'))
+        pth.add(PRDistribution(location))
         self.assert_(not pth.dirty)
 
 
 
         sys.path.append(target)
         old_ppath = os.environ.get('PYTHONPATH')
-        os.environ['PYTHONPATH'] = ':'.join(sys.path)
+        os.environ['PYTHONPATH'] = os.path.pathsep.join(sys.path)
         try:
             dist = Distribution()
             dist.script_name = 'setup.py'
             self.assertEquals(res.location, new_location)
         finally:
             sys.path.remove(target)
-            shutil.rmtree(new_location)
-            shutil.rmtree(target)
+            for basedir in [new_location, target, ]:
+                if not os.path.exists(basedir) or not os.path.isdir(basedir):
+                    continue
+                try:
+                    shutil.rmtree(basedir)
+                except:
+                    pass
             if old_ppath is not None:
                 os.environ['PYTHONPATH'] = old_ppath
             else:

File setuptools/tests/test_resources.py

 except NameError:
     from sets import ImmutableSet as frozenset
 
+def safe_repr(obj, short=False):
+    """ copied from Python2.7"""
+    try:
+        result = repr(obj)
+    except Exception:
+        result = object.__repr__(obj)
+    if not short or len(result) < _MAX_LENGTH:
+        return result
+    return result[:_MAX_LENGTH] + ' [truncated]...'
+
 class Metadata(EmptyProvider):
     """Mock object to return metadata as if from an on-disk distribution"""
 
             p1, p2 = parse_version(s1),parse_version(s2)
             self.assertEqual(p1,p2, (s1,s2,p1,p2))
 
-        c('1.2-rc1', '1.2rc1')
         c('0.4', '0.4.0')
         c('0.4.0.0', '0.4.0')
         c('0.4.0-0', '0.4-0')
         c('0pl1', '0.0pl1')
         c('0pre1', '0.0c1')
         c('0.0.0preview1', '0c1')
-        c('0.0c1', '0-rc1')
+        c('0.0c1', '0rc1')
         c('1.2a1', '1.2.a.1'); c('1.2...a', '1.2a')
 
     def testVersionOrdering(self):
             self.assert_(p1<p2, (s1,s2,p1,p2))
 
         c('2.1','2.1.1')
+        c('2.1.0','2.10')
         c('2a1','2b0')
+        c('2b1','2c0')
         c('2a1','2.1')
         c('2.3a1', '2.3')
         c('2.1-1', '2.1-2')
         c('2.1-1', '2.1.1')
+        c('2.1', '2.1.1-1')
         c('2.1', '2.1pl4')
         c('2.1a0-20040501', '2.1')
         c('1.1', '02.1')
         c('0.4', '4.0')
         c('0.0.4', '0.4.0')
         c('0pl1', '0.4pl1')
-        c('2.1.0-rc1','2.1.0')
         c('2.1dev','2.1a0')
+        c('2.1.0rc1','2.1.0')
+        c('2.1.0','2.1.0-rc0')
+        c('2.1.0','2.1.0-a')
+        c('2.1.0','2.1.0-alpha')
+        c('2.1.0','2.1.0-foo')
+        c('1.0','1.0-1')
+        c('1.0-1','1.0.1')
+        c('1.0a','1.0b')
+        c('1.0dev','1.0rc1')
+        c('1.0pre','1.0')
+        c('1.0pre','1.0')
+        c('1.0a','1.0-a')
+        c('1.0rc1','1.0-rc1')
 
         torture ="""
         0.80.1-3 0.80.1-2 0.80.1-1 0.79.9999+0.80.0pre4-1
         pkg_resources._namespace_packages = self._ns_pkgs.copy()
         sys.path = self._prev_sys_path[:]
 
+    def _assertIn(self, member, container):
+        """ assertIn and assertTrue does not exist in Python2.3"""
+        if member not in container:
+            standardMsg = '%s not found in %s' % (safe_repr(member),
+                                                  safe_repr(container))
+            self.fail(self._formatMessage(msg, standardMsg))
+
     def test_two_levels_deep(self):
         """
         Test nested namespace packages
             pkg2_init.write(ns_str)
             pkg2_init.close()
         import pkg1
-        self.assertTrue("pkg1" in pkg_resources._namespace_packages.keys())
+        self._assertIn("pkg1", pkg_resources._namespace_packages.keys())
         try:
             import pkg1.pkg2
         except ImportError, e:
             self.fail("Distribute tried to import the parent namespace package")
         # check the _namespace_packages dict
-        self.assertTrue("pkg1.pkg2" in pkg_resources._namespace_packages.keys())
+        self._assertIn("pkg1.pkg2", pkg_resources._namespace_packages.keys())
         self.assertEqual(pkg_resources._namespace_packages["pkg1"], ["pkg1.pkg2"])
         # check the __path__ attribute contains both paths
         self.assertEqual(pkg1.pkg2.__path__, [