[Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.8, 1.9 easy_install.py, 1.16, 1.17

pje@users.sourceforge.net pje at users.sourceforge.net
Sun Jun 12 17:49:56 CEST 2005


Update of /cvsroot/python/python/nondist/sandbox/setuptools
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7441

Modified Files:
	EasyInstall.txt easy_install.py 
Log Message:
Restructure easy_install as a distutils "Command" object, so that it can
access the distutils configuration and logging infrastructure, and can
"inherit" options from a distutils setup script that wants to use it to
install its own dependencies.


Index: EasyInstall.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- EasyInstall.txt	12 Jun 2005 03:44:07 -0000	1.8
+++ EasyInstall.txt	12 Jun 2005 15:49:53 -0000	1.9
@@ -179,11 +179,39 @@
 Reference Manual
 ================
 
+Configuration Files
+-------------------
+
+(New in 0.4a2)
+
+You may specify default options for EasyInstall using the standard
+distutils configuration files, under the command heading ``easy_install``.
+EasyInstall will look first for a ``setup.cfg`` file in the current directory,
+then a ``~/.pydistutils.cfg`` or ``$HOME\\pydistutils.cfg`` (on Unix-like OSes
+and Windows, respectively), and finally a ``distutils.cfg`` file in the
+``distutils`` package directory.  Here's a simple example::
+
+    [easy_install]
+
+    # set the default location to install packages
+    install_dir = /home/me/lib/python
+    
+    # Notice that indentation can be used to continue an option
+    # value; this is especially useful for the "--find-links"
+    # option, which tells easy_install to use download links on
+    # these pages before consulting PyPI:
+    #
+    find_links = http://sqlobject.org/
+                 http://peak.telecommunity.com/dist/
+
+See also the current Python documentation on the `use and location of distutils
+configuration files <http://docs.python.org/inst/config-syntax.html>`_.
+
 
 Command-Line Options
 --------------------
 
-``--zip, -z``
+``--zip-ok, -z``
     Enable installing the package as a zip file. This can significantly
     increase Python's overall import performance if you're installing to
     ``site-packages`` and not using the ``--multi`` option, because Python
@@ -221,11 +249,13 @@
     which will put the latest installed version of the specified packages on
     ``sys.path`` for you. (For more advanced uses, like selecting specific
     versions and enabling optional dependencies, see the ``pkg_resources`` API
-    doc.) Note that if you install to a directory other than ``site-packages``,
+    doc.)
+
+    Note that if you install to a directory other than ``site-packages``,
     this option is automatically in effect, because ``.pth`` files can only be
     used in ``site-packages`` (at least in Python 2.3 and 2.4). So, if you use
-    the ``--install-dir`` or ``-i`` options, you must also use ``require()`` to
-    enable packages at runtime
+    the ``--install-dir`` or ``-d`` option (or they are set via configuration
+    file(s)) you must also use ``require()`` to enable packages at runtime.
 
 ``--install-dir=DIR, -d DIR``
     Set the installation directory. It is up to you to ensure that this
@@ -233,39 +263,53 @@
     ``pkg_resources.require()`` to enable the installed package(s) that you
     need.
 
-``--build-directory=DIR, -b DIR`` (New in 0.3a3)
-    Set the directory used to download, extract, and install the package.  The
-    directory is not cleared before or after installation, so the downloaded
-    packages and extracted contents will remain there afterwards, allowing you
-    to read any documentation, examples, scripts, etc. that may have been
-    included with the source distribution (if any).
-
-    This option can only be used when you are specifying a single installation
-    URL or filename, so that the installer will not be confused by the presence
-    of multiple ``setup.py`` files in the build directory.
+    (New in 0.4a2) If this option is not directly specified on the command line
+    or in a distutils configuration file, the distutils default installation
+    location is used.  Normally, this would be the ``site-packages`` directory,
+    but if you are using distutils configuration files, setting things like
+    ``--prefix`` or ``--install-lib``, then those settings are taken into
+    account when computing the default directory.
 
-``--scan-url=URL, -s URL`` (New in 0.4a1)
-    Scan the specified "download page" for direct links to downloadable eggs or
-    source distributions.  Any usable packages will be downloaded if they are
-    required by a command line argument.  For example, this::
+``--find-links=URL, -f URL`` (Option renamed in 0.4a2)
+    Scan the specified "download pages" for direct links to downloadable eggs
+    or source distributions.  Any usable packages will be downloaded if they
+    are required by a command line argument.  For example, this::
 
-        easy_install -s http://peak.telecommunity.com/dist PyProtocols
+        easy_install -f http://peak.telecommunity.com/dist PyProtocols
 
     will download and install the latest version of PyProtocols linked from
     the PEAK downloads page, but ignore the other download links on that page.
+    If all requested packages can be found using links on the specified
+    download pages, the Python Package Index will *not* be consulted.  You can
+    use ``file:`` URLs to reference a local filename.
 
-    You may use this option more than once, to list multiple download pages.
-    If all requested packages can be found using the specified download pages,
-    the Python Package Index will *not* be consulted.
+    You may specify multiple URLs with this option, separated by whitespace.
+    Note that on the command line, you will probably have to surround the URLs
+    with quotes, so that they are recognized as a single option value.  You can
+    also specify URLs in a configuration file; see `Configuration Files`_,
+    above; but note that this means the specified pages will be downloaded
+    every time you use EasyInstall (unless overridden on the command line) and
+    thus may make startup slower.
 
 ``--index-url=URL, -u URL`` (New in 0.4a1)
     Specifies the base URL of the Python Package Index.  The default is
     http://www.python.org/pypi if not specified.  When a package is requested
-    that is not locally available or linked from a ``--scan-url`` download
+    that is not locally available or linked from a ``--find-links`` download
     page, the package index will be searched for download pages for the needed
     package, and those download pages will be searched for links to download
     an egg or source distribution.
 
+``--build-directory=DIR, -b DIR`` (New in 0.3a3)
+    Set the directory used to download, extract, and install the package.  The
+    directory is not cleared before or after installation, so the downloaded
+    packages and extracted contents will remain there afterwards, allowing you
+    to read any documentation, examples, scripts, etc. that may have been
+    included with the source distribution (if any).
+
+    This option can only be used when you are specifying a single installation
+    URL or filename, so that the installer will not be confused by the presence
+    of multiple ``setup.py`` files in the build directory.
+
 
 Release Notes/Change History
 ============================
@@ -275,6 +319,11 @@
    time out or be missing a file.
 
 0.4a2
+ * Added support for setting options via distutils configuration files
+
+ * Renamed ``--scan-url/-s`` to ``--find-links/-f`` to free up ``-s`` for the
+   script installation directory option.
+
  * Use ``urllib2`` instead of ``urllib``, to allow use of ``https:`` URLs if
    Python includes SSL support.
 
@@ -292,6 +341,11 @@
    with an ``unpack_archive()`` API.  These were split out of EasyInstall to
    allow reuse by other tools and applications.
 
+ * ``setuptools.Command`` now supports reinitializing commands using keyword
+   arguments to set/reset options.  Also, ``Command`` subclasses can now set
+   their ``command_consumes_arguments`` attribute to ``True`` in order to
+   receive an ``args`` option containing the rest of the command line.
+
 0.4a1
  * Added ``--scan-url`` and ``--index-url`` options, to scan download pages
    and search PyPI for needed packages.

Index: easy_install.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/easy_install.py,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- easy_install.py	12 Jun 2005 03:44:07 -0000	1.16
+++ easy_install.py	12 Jun 2005 15:49:53 -0000	1.17
@@ -14,6 +14,7 @@
 
 import sys, os.path, zipimport, shutil, tempfile
 
+from setuptools import Command
 from setuptools.sandbox import run_setup
 from distutils.sysconfig import get_python_lib
 
@@ -22,6 +23,15 @@
 from pkg_resources import *
 
 
+def samefile(p1,p2):
+    if hasattr(os.path,'samefile') and (
+        os.path.exists(p1) and os.path.exists(p2)
+    ):
+        return os.path.samefile(p1,p2)
+    return (
+        os.path.normpath(os.path.normcase(p1)) ==
+        os.path.normpath(os.path.normcase(p2))
+    )
 
 
 
@@ -29,51 +39,123 @@
 
 
 
+class easy_install(Command):
+    """Manage a download/build/install process"""
 
+    description = "Find/get/install Python packages"
 
+    command_consumes_arguments = True
+    
+    user_options = [
+        ("zip-ok", "z", "install package as a zipfile"),
+        ("multi-version", "m", "make apps have to require() a version"),
+        ("install-dir=", "d", "install package to DIR"),
+        ("index-url=", "i", "base URL of Python Package Index"),
+        ("find-links=", "f", "additional URL(s) to search for packages"),
+        ("build-directory=", "b",
+            "download/extract/build in DIR; keep the results"),
+    ]
 
+    boolean_options = [ 'zip-ok', 'multi-version' ]
+    create_index = PackageIndex
+    
+    def initialize_options(self):
+        self.zip_ok = None
+        self.multi_version = None
+        self.install_dir = None
+        self.index_url = None
+        self.find_links = None
+        self.build_directory = None
+        self.args = None
 
+        # Options not specifiable via command line
+        self.package_index = None
+        self.pth_file = None
+
+    def alloc_tmp(self):
+        if self.build_directory is None:
+            return tempfile.mkdtemp(prefix="easy_install-")
+        tmpdir = os.path.realpath(self.build_directory)
+        if not os.path.isdir(tmpdir):
+            os.makedirs(tmpdir)
+        return tmpdir
+        
+    def finalize_options(self):
+        # Let install_lib get set by install_lib command, which in turn
+        # gets its info from the install command, and takes into account
+        # --prefix and --home and all that other crud.
+        #
+        self.set_undefined_options('install_lib',('install_dir','install_dir'))
+        site_packages = get_python_lib()       
+        instdir = self.install_dir
+
+        if instdir is None or samefile(site_packages,instdir):
+            instdir = site_packages
+            if self.pth_file is None:
+                self.pth_file = PthDistributions(
+                    os.path.join(instdir,'easy-install.pth')
+                )
+            self.install_dir = instdir    
+
+        elif self.multi_version is None:
+            self.multi_version = True
+
+        elif not self.multi_version:
+            # explicit false set from Python code; raise an error
+            raise RuntimeError(
+                "Can't do single-version installs outside site-packages"
+            )
+            
+        self.index_url = self.index_url or "http://www.python.org/pypi"
+        if self.package_index is None:
+            self.package_index = self.create_index(self.index_url)
+
+        if self.find_links is not None:
+            if isinstance(self.find_links, basestring):
+                self.find_links = self.find_links.split()
+            for link in self.find_links:
+                self.package_index.scan_url(link)
+
+        if not self.args:
+            parser.error("No urls, filenames, or requirements specified")
+        elif len(self.args)>1 and self.build_directory is not None:
+            parser.error("Build directory can only be set when using one URL")
+            
+    def run(self):
+        for spec in self.args:
+            self.easy_install(spec)
+
+
+    def easy_install(self, spec):       
+        tmpdir = self.alloc_tmp()
+        try:
+            print "Downloading", spec
+            download = self.package_index.download(spec, tmpdir)
+            if download is None:
+                raise RuntimeError(
+                    "Could not find distribution for %r" % spec
+                )
+
+            print "Installing", os.path.basename(download)
+            for dist in self.install_eggs(download, self.zip_ok, tmpdir):
+                self.package_index.add(dist)
+                print self.installation_report(dist)
+
+        finally:
+            if self.build_directory is None:
+                shutil.rmtree(tmpdir)
 
 
 
 
 
 
-class Installer:
-    """Manage a download/build/install process"""
 
-    pth_file = None
-    cleanup = False
 
-    def __init__(self, instdir=None, multi=None):
-        site_packages = get_python_lib()
-        if instdir is None or self.samefile(site_packages,instdir):
-            instdir = site_packages
-            self.pth_file = PthDistributions(
-                os.path.join(instdir,'easy-install.pth')
-            )
-        elif multi is None:
-            multi = True
 
-        elif not multi:
-            # explicit false, raise an error
-            raise RuntimeError(
-                "Can't do single-version installs outside site-packages"
-            )
 
-        self.instdir = instdir
-        self.multi = multi
 
 
-    def samefile(self,p1,p2):
-        if hasattr(os.path,'samefile') and (
-            os.path.exists(p1) and os.path.exists(p2)
-        ):
-            return os.path.samefile(p1,p2)
-        return (
-            os.path.normpath(os.path.normcase(p1)) ==
-            os.path.normpath(os.path.normcase(p2))
-        )
 
 
 
@@ -123,10 +205,10 @@
 
     def install_egg(self, egg_path, zip_ok, tmpdir):
 
-        destination = os.path.join(self.instdir, os.path.basename(egg_path))
+        destination = os.path.join(self.install_dir,os.path.basename(egg_path))
         ensure_directory(destination)
 
-        if not self.samefile(egg_path, destination):
+        if not samefile(egg_path, destination):
             if os.path.isdir(destination):
                 shutil.rmtree(destination)
             elif os.path.isfile(destination):
@@ -166,7 +248,7 @@
         """Helpful installation message for display to package users"""
 
         msg = "Installed %(eggloc)s to %(instdir)s"
-        if self.multi:
+        if self.multi_version:
             msg += """
 
 Because this distribution was installed --multi-version or --install-dir,
@@ -178,7 +260,7 @@
     pkg_resources.require("%(name)s==%(version)s")  # this exact version
     pkg_resources.require("%(name)s>=%(version)s")  # this version or higher
 """
-        if not self.samefile(get_python_lib(),self.instdir):
+        if not samefile(get_python_lib(),self.install_dir):
             msg += """
 
 Note also that the installation directory must be on sys.path at runtime for
@@ -186,7 +268,7 @@
 PYTHONPATH, or by being added to sys.path by your code.)
 """
         eggloc = os.path.basename(dist.path)
-        instdir = os.path.realpath(self.instdir)
+        instdir = os.path.realpath(self.install_dir)
         name = dist.name
         version = dist.version
         return msg % locals()
@@ -196,7 +278,7 @@
             remove = self.pth_file.remove
             for d in self.pth_file.get(dist.key,()):    # drop old entries
                 remove(d)
-            if not self.multi:
+            if not self.multi_version:
                 self.pth_file.add(dist) # add new entry
             self.pth_file.save()
 
@@ -244,40 +326,32 @@
 
 
 
-def main(argv, installer_type=Installer, index_type=PackageIndex):
+def main(argv, cmds={'easy_install':easy_install}):
+    from setuptools import setup
+    try:
+        setup(cmdclass = cmds, script_args = ['easy_install']+argv)
+    except RuntimeError, v:
+        print >>sys.stderr,"error:",v
+        sys.exit(1)
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
+
+
+
+
+
+
 
-    from optparse import OptionParser
 
-    parser = OptionParser(usage = "usage: %prog [options] url [url...]")
-    parser.add_option("-d", "--install-dir", dest="instdir", default=None,
-                      help="install package to DIR", metavar="DIR")
 
-    parser.add_option("-z", "--zip",
-                      action="store_true", dest="zip_ok", default=False,
-                      help="install package as a zipfile")
 
-    parser.add_option("-m", "--multi-version",
-                      action="store_true", dest="multi", default=None,
-                      help="make apps have to require() a version")
 
-    parser.add_option("-b", "--build-directory", dest="tmpdir", metavar="DIR",
-                      default=None,
-                      help="download/extract/build in DIR; keep the results")
 
-    parser.add_option("-u", "--index-url", dest="index_url", metavar="URL",
-                      default="http://www.python.org/pypi",
-                      help="base URL of Python Package Index")
 
-    parser.add_option("-s", "--scan-url", dest="scan_urls", metavar="URL",
-                      action="append",
-                      help="additional URL(s) to search for packages")
 
-    (options, args) = parser.parse_args()
 
-    if not args:
-        parser.error("No urls, filenames, or requirements specified")
-    elif len(args)>1 and options.tmpdir is not None:
-        parser.error("Build directory can only be set when using one URL")
 
 
 
@@ -285,44 +359,11 @@
 
 
 
-    def alloc_tmp():
-        if options.tmpdir is None:
-            return tempfile.mkdtemp(prefix="easy_install-")
-        elif not os.path.isdir(options.tmpdir):
-            os.makedirs(options.tmpdir)
-        return os.path.realpath(options.tmpdir)
 
-    try:
-        index = index_type(options.index_url)
-        inst = installer_type(options.instdir, options.multi)
 
-        if options.scan_urls:
-            for url in options.scan_urls:
-                index.scan_url(url)
 
-        for spec in args:
-            tmpdir = alloc_tmp()
-            try:
-                print "Downloading", spec
-                download = index.download(spec, tmpdir)
-                if download is None:
-                    raise RuntimeError(
-                        "Could not find distribution for %r" % spec
-                    )
 
-                print "Installing", os.path.basename(download)
-                for dist in inst.install_eggs(download,options.zip_ok, tmpdir):
-                    index.add(dist)
-                    print inst.installation_report(dist)
 
-            finally:
-                if options.tmpdir is None:
-                    shutil.rmtree(tmpdir)
 
-    except RuntimeError, v:
-        print >>sys.stderr,"error:",v
-        sys.exit(1)
 
-if __name__ == '__main__':
-    main(sys.argv[1:])
 



More information about the Python-checkins mailing list