aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPJ Eby <distutils-sig@python.org>2006-09-22 00:09:06 +0000
committerPJ Eby <distutils-sig@python.org>2006-09-22 00:09:06 +0000
commitae347c1ed3e39fb2c00b8b9fc8aedcf507313c20 (patch)
tree2d8a9c2f40a70b768050625aa200b49d3325ebd2
parent4ef57c26cbeee3f3afd21f86877bbdcadf0f69c1 (diff)
downloadexternal_python_setuptools-ae347c1ed3e39fb2c00b8b9fc8aedcf507313c20.tar.gz
external_python_setuptools-ae347c1ed3e39fb2c00b8b9fc8aedcf507313c20.tar.bz2
external_python_setuptools-ae347c1ed3e39fb2c00b8b9fc8aedcf507313c20.zip
Add support for "eggsecutable" headers: a /bin/sh script that is prepended
to an .egg file to allow it to be run as a script on Unix-ish platforms. (This is mainly so that setuptools itself can have a single-file installer on Unix, without doing multiple downloads, dealing with firewalls, etc.) (Backport from trunk) --HG-- branch : setuptools-0.6 extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/branches/setuptools-0.6%4051969
-rwxr-xr-xsetup.py10
-rwxr-xr-xsetuptools.egg-info/entry_points.txt5
-rwxr-xr-xsetuptools.txt43
-rw-r--r--setuptools/command/bdist_egg.py57
-rwxr-xr-xsetuptools/command/easy_install.py8
5 files changed, 105 insertions, 18 deletions
diff --git a/setup.py b/setup.py
index 4aa44c51..c7168682 100755
--- a/setup.py
+++ b/setup.py
@@ -84,10 +84,13 @@ setup(
"easy_install = setuptools.command.easy_install:main",
"easy_install-%s = setuptools.command.easy_install:main"
% sys.version[:3]
- ],
+ ],
"setuptools.file_finders":
- ["svn_cvs = setuptools.command.sdist:_default_revctrl"]
+ ["svn_cvs = setuptools.command.sdist:_default_revctrl"],
+
+ "setuptools.installation":
+ ['eggsecutable = setuptools.command.easy_install:bootstrap'],
},
classifiers = [f.strip() for f in """
@@ -118,6 +121,3 @@ setup(
-
-
-
diff --git a/setuptools.egg-info/entry_points.txt b/setuptools.egg-info/entry_points.txt
index 4156edb5..fb9081c8 100755
--- a/setuptools.egg-info/entry_points.txt
+++ b/setuptools.egg-info/entry_points.txt
@@ -30,6 +30,9 @@ depends.txt = setuptools.command.egg_info:warn_depends_obsolete
easy_install = setuptools.command.easy_install:main
easy_install-2.4 = setuptools.command.easy_install:main
+[setuptools.installation]
+eggsecutable = setuptools.command.easy_install:bootstrap
+
[distutils.commands]
bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
rotate = setuptools.command.rotate:rotate
@@ -44,10 +47,10 @@ install_egg_info = setuptools.command.install_egg_info:install_egg_info
alias = setuptools.command.alias:alias
easy_install = setuptools.command.easy_install:easy_install
install_scripts = setuptools.command.install_scripts:install_scripts
+bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
bdist_egg = setuptools.command.bdist_egg:bdist_egg
install = setuptools.command.install:install
test = setuptools.command.test:test
install_lib = setuptools.command.install_lib:install_lib
build_ext = setuptools.command.build_ext:build_ext
sdist = setuptools.command.sdist:sdist
-
diff --git a/setuptools.txt b/setuptools.txt
index 43e0e610..26874c88 100755
--- a/setuptools.txt
+++ b/setuptools.txt
@@ -498,6 +498,43 @@ on "entry points" in general, see the section below on `Dynamic Discovery of
Services and Plugins`_.
+"Eggsecutable" Scripts
+----------------------
+
+Occasionally, there are situations where it's desirable to make an ``.egg``
+file directly executable. You can do this by including an entry point such
+as the following::
+
+ setup(
+ # other arguments here...
+ entry_points = {
+ 'setuptools.installation': [
+ 'eggsecutable = my_package.some_module:main_func',
+ ]
+ }
+ )
+
+Any eggs built from the above setup script will include a short excecutable
+prelude that imports and calls ``main_func()`` from ``my_package.some_module``.
+The prelude can be run on Unix-like platforms (including Mac and Linux) by
+invoking the egg with ``/bin/sh``, or by enabling execute permissions on the
+``.egg`` file. For the executable prelude to run, the appropriate version of
+Python must be available via the ``PATH`` environment variable, under its
+"long" name. That is, if the egg is built for Python 2.3, there must be a
+``python2.3`` executable present in a directory on ``PATH``.
+
+This feature is primarily intended to support bootstrapping the installation of
+setuptools itself on non-Windows platforms, but may also be useful for other
+projects as well.
+
+IMPORTANT NOTE: Eggs with an "eggsecutable" header cannot be renamed, or
+invoked via symlinks. They *must* be invoked using their original filename, in
+order to ensure that, once running, ``pkg_resources`` will know what project
+and version is in use. The header script will check this and exit with an
+error if the ``.egg`` file has been renamed or is invoked via a symlink that
+changes its base name.
+
+
Declaring Dependencies
======================
@@ -2567,6 +2604,12 @@ Release Notes/Change History
* Fix ``upload`` command not uploading files built by ``bdist_rpm`` or
``bdist_wininst`` under Python 2.3 and 2.4.
+ * Add support for "eggsecutable" headers: a ``#!/bin/sh`` script that is
+ prepended to an ``.egg`` file to allow it to be run as a script on Unix-ish
+ platforms. (This is mainly so that setuptools itself can have a single-file
+ installer on Unix, without doing multiple downloads, dealing with firewalls,
+ etc.)
+
0.6c3
* Fixed breakages caused by Subversion 1.4's new "working copy" format
diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py
index 981a1f9b..1f768e82 100644
--- a/setuptools/command/bdist_egg.py
+++ b/setuptools/command/bdist_egg.py
@@ -8,7 +8,9 @@ from setuptools import Command
from distutils.dir_util import remove_tree, mkpath
from distutils.sysconfig import get_python_version, get_python_lib
from distutils import log
+from distutils.errors import DistutilsSetupError
from pkg_resources import get_build_platform, Distribution, ensure_directory
+from pkg_resources import EntryPoint
from types import CodeType
from setuptools.extension import Library
@@ -37,8 +39,6 @@ def write_stub(resource, pyfile):
# stub __init__.py for packages distributed without one
NS_PKG_STUB = '__import__("pkg_resources").declare_namespace(__name__)'
-
-
class bdist_egg(Command):
description = "create an \"egg\" distribution"
@@ -233,7 +233,7 @@ class bdist_egg(Command):
# Make the archive
make_zipfile(self.egg_output, archive_root, verbose=self.verbose,
- dry_run=self.dry_run)
+ dry_run=self.dry_run, mode=self.gen_header())
if not self.keep_temp:
remove_tree(self.bdist_dir, dry_run=self.dry_run)
@@ -285,6 +285,47 @@ class bdist_egg(Command):
return init_files
+ def gen_header(self):
+ epm = EntryPoint.parse_map(self.distribution.entry_points or '')
+ ep = epm.get('setuptools.installation',{}).get('eggsecutable')
+ if ep is None:
+ return 'w' # not an eggsecutable, do it the usual way.
+
+ if not ep.attrs or ep.extras:
+ raise DistutilsSetupError(
+ "eggsecutable entry point (%r) cannot have 'extras' "
+ "or refer to a module" % (ep,)
+ )
+
+ pyver = sys.version[:3]
+ pkg = ep.module_name
+ full = '.'.join(ep.attrs)
+ base = ep.attrs[0]
+ basename = os.path.basename(self.egg_output)
+
+ header = (
+ "#!/bin/sh\n"
+ 'if [[ `basename $0` = "%(basename)s" ]]\n'
+ 'then exec python%(pyver)s -c "'
+ "import sys, os; sys.path.insert(0, os.path.abspath('$0')); "
+ "from %(pkg)s import %(base)s; sys.exit(%(full)s())"
+ '" "$@"\n'
+ 'else\n'
+ ' echo $0 is not the correct name for this egg file.\n'
+ ' echo Please rename it back to %(basename)s and try again.\n'
+ ' exec false\n'
+ 'fi\n'
+
+ ) % locals()
+
+ if not self.dry_run:
+ f = open(self.egg_output, 'w')
+ f.write(header)
+ f.close()
+ return 'a'
+
+
+
def copy_metadata_to(self, target_dir):
prefix = os.path.join(self.egg_info,'')
for path in self.ei_cmd.filelist.files:
@@ -415,7 +456,9 @@ INSTALL_DIRECTORY_ATTRS = [
'install_lib', 'install_dir', 'install_data', 'install_base'
]
-def make_zipfile (zip_filename, base_dir, verbose=0, dry_run=0, compress=None):
+def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
+ mode='w'
+):
"""Create a zip file from all the files under 'base_dir'. The output
zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
Python module (if available) or the InfoZIP "zip" utility (if installed
@@ -426,7 +469,7 @@ def make_zipfile (zip_filename, base_dir, verbose=0, dry_run=0, compress=None):
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
- def visit (z, dirname, names):
+ def visit(z, dirname, names):
for name in names:
path = os.path.normpath(os.path.join(dirname, name))
if os.path.isfile(path):
@@ -440,12 +483,10 @@ def make_zipfile (zip_filename, base_dir, verbose=0, dry_run=0, compress=None):
compression = [zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED][bool(compress)]
if not dry_run:
- z = zipfile.ZipFile(zip_filename, "w", compression=compression)
+ z = zipfile.ZipFile(zip_filename, mode, compression=compression)
os.path.walk(base_dir, visit, z)
z.close()
else:
os.path.walk(base_dir, visit, None)
-
return zip_filename
-
#
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index 147dfc43..b049ce58 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -1550,10 +1550,10 @@ def rmtree(path, ignore_errors=False, onerror=auto_chmod):
except os.error:
onerror(os.rmdir, path, sys.exc_info())
-
-
-
-
+def bootstrap():
+ # This function is called when setuptools*.egg is run using /bin/sh
+ import setuptools; argv0 = os.path.dirname(setuptools.__path__[0])
+ sys.argv[0] = argv0; sys.argv.append(argv0); main()
def main(argv=None, **kw):