diff options
Diffstat (limited to 'setuptools')
| -rw-r--r-- | setuptools/__init__.py | 2 | ||||
| -rwxr-xr-x | setuptools/command/alias.py | 4 | ||||
| -rw-r--r-- | setuptools/command/bdist_egg.py | 6 | ||||
| -rw-r--r-- | setuptools/command/build_ext.py | 18 | ||||
| -rwxr-xr-x | setuptools/command/easy_install.py | 14 | ||||
| -rwxr-xr-x | setuptools/command/egg_info.py | 22 | ||||
| -rwxr-xr-x | setuptools/command/sdist.py | 83 | ||||
| -rw-r--r-- | setuptools/depends.py | 2 | ||||
| -rw-r--r-- | setuptools/dist.py | 53 | ||||
| -rwxr-xr-x | setuptools/package_index.py | 62 | ||||
| -rwxr-xr-x | setuptools/sandbox.py | 75 |
11 files changed, 232 insertions, 109 deletions
diff --git a/setuptools/__init__.py b/setuptools/__init__.py index 56cbf767..a9f6544d 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -7,7 +7,7 @@ from distutils.core import Command as _Command from distutils.util import convert_path import os.path -__version__ = '0.6c9' +__version__ = '0.6c10' __all__ = [ 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require', 'find_packages' diff --git a/setuptools/command/alias.py b/setuptools/command/alias.py index f5368b29..40c00b55 100755 --- a/setuptools/command/alias.py +++ b/setuptools/command/alias.py @@ -9,7 +9,7 @@ def shquote(arg): """Quote an argument for later parsing by shlex.split()""" for c in '"', "'", "\\", "#": if c in arg: return repr(arg) - if arg.split()<>[arg]: + if arg.split()!=[arg]: return repr(arg) return arg @@ -33,7 +33,7 @@ class alias(option_base): def finalize_options(self): option_base.finalize_options(self) - if self.remove and len(self.args)<>1: + if self.remove and len(self.args)!=1: raise DistutilsOptionError( "Must specify exactly one argument (the alias name) when " "using --remove" diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index 9e852a3f..7e5a3799 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -165,12 +165,13 @@ class bdist_egg(Command): def run(self): # Generate metadata first self.run_command("egg_info") - # We run install_lib before install_data, because some data hacks # pull their data path from the install_lib command. log.info("installing library code to %s" % self.bdist_dir) instcmd = self.get_finalized_command('install') old_root = instcmd.root; instcmd.root = None + if self.distribution.has_c_libraries() and not self.skip_build: + self.run_command('build_clib') cmd = self.call_command('install_lib', warn_dir=0) instcmd.root = old_root @@ -190,7 +191,6 @@ class bdist_egg(Command): to_compile.extend(self.make_init_files()) if to_compile: cmd.byte_compile(to_compile) - if self.distribution.data_files: self.do_install_data() @@ -398,7 +398,7 @@ def write_safety_flag(egg_dir, safe): for flag,fn in safety_flags.items(): fn = os.path.join(egg_dir, fn) if os.path.exists(fn): - if safe is None or bool(safe)<>flag: + if safe is None or bool(safe)!=flag: os.unlink(fn) elif safe is not None and bool(safe)==flag: f=open(fn,'wb'); f.write('\n'); f.close() diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py index c0aaa8e8..f6f3355d 100644 --- a/setuptools/command/build_ext.py +++ b/setuptools/command/build_ext.py @@ -82,15 +82,15 @@ class build_ext(_build_ext): def get_ext_filename(self, fullname): filename = _build_ext.get_ext_filename(self,fullname) - ext = self.ext_map[fullname] - if isinstance(ext,Library): - fn, ext = os.path.splitext(filename) - return self.shlib_compiler.library_filename(fn,libtype) - elif use_stubs and ext._links_to_dynamic: - d,fn = os.path.split(filename) - return os.path.join(d,'dl-'+fn) - else: - return filename + if fullname in self.ext_map: + ext = self.ext_map[fullname] + if isinstance(ext,Library): + fn, ext = os.path.splitext(filename) + return self.shlib_compiler.library_filename(fn,libtype) + elif use_stubs and ext._links_to_dynamic: + d,fn = os.path.split(filename) + return os.path.join(d,'dl-'+fn) + return filename def initialize_options(self): _build_ext.initialize_options(self) diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index f06b6ddd..a5a23ad4 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -204,7 +204,7 @@ class easy_install(Command): self.outputs = [] def run(self): - if self.verbose<>self.distribution.verbose: + if self.verbose!=self.distribution.verbose: log.set_verbosity(self.verbose) try: for spec in self.args: @@ -252,7 +252,7 @@ class easy_install(Command): # Is it a configured, PYTHONPATH, implicit, or explicit site dir? is_site_dir = instdir in self.all_site_dirs - if not is_site_dir: + if not is_site_dir and not self.multi_version: # No? Then directly test whether it does .pth file processing is_site_dir = self.check_pth_processing() else: @@ -430,9 +430,9 @@ Please make the appropriate changes for your system and try again. self.check_editable(spec) dist = self.package_index.fetch_distribution( - spec, tmpdir, self.upgrade, self.editable, not self.always_copy + spec, tmpdir, self.upgrade, self.editable, not self.always_copy, + self.local_index ) - if dist is None: msg = "Could not find suitable distribution for %r" % spec if self.always_copy: @@ -722,7 +722,7 @@ Please make the appropriate changes for your system and try again. f = open(pkg_inf,'w') f.write('Metadata-Version: 1.0\n') for k,v in cfg.items('metadata'): - if k<>'target_version': + if k!='target_version': f.write('%s: %s\n' % (k.replace('_','-').title(), v)) f.close() script_dir = os.path.join(egg_info,'scripts') @@ -988,7 +988,6 @@ See the setuptools documentation for the "develop" command for more info. def pf(src,dst): if dst.endswith('.py') and not src.startswith('EGG-INFO/'): to_compile.append(dst) - to_chmod.append(dst) elif dst.endswith('.dll') or dst.endswith('.so'): to_chmod.append(dst) self.unpack_progress(src,dst) @@ -1023,6 +1022,7 @@ See the setuptools documentation for the "develop" command for more info. + def no_default_version_msg(self): return """bad install directory or PYTHONPATH @@ -1286,7 +1286,7 @@ def get_exe_prefixes(exe_filename): if parts[1].endswith('.egg-info'): prefixes.insert(0,('/'.join(parts[:2]), 'EGG-INFO/')) break - if len(parts)<>2 or not name.endswith('.pth'): + if len(parts)!=2 or not name.endswith('.pth'): continue if name.endswith('-nspkg.pth'): continue diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 9741e26a..5a8b2db8 100755 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -217,18 +217,21 @@ class egg_info(Command): data = f.read() f.close() - if data.startswith('9') or data.startswith('8'): + if data.startswith('<?xml'): + dirurl = urlre.search(data).group(1) # get repository URL + localrev = max([int(m.group(1)) for m in revre.finditer(data)]+[0]) + else: + try: svnver = int(data.splitlines()[0]) + except: svnver=-1 + if data<8: + log.warn("unrecognized .svn/entries format; skipping %s", base) + dirs[:] = [] + continue + data = map(str.splitlines,data.split('\n\x0c\n')) del data[0][0] # get rid of the '8' or '9' dirurl = data[0][3] localrev = max([int(d[9]) for d in data if len(d)>9 and d[9]]+[0]) - elif data.startswith('<?xml'): - dirurl = urlre.search(data).group(1) # get repository URL - localrev = max([int(m.group(1)) for m in revre.finditer(data)]+[0]) - else: - log.warn("unrecognized .svn/entries format; skipping %s", base) - dirs[:] = [] - continue if base==os.curdir: base_url = dirurl+'/' # save the root url elif not dirurl.startswith(base_url): @@ -241,9 +244,6 @@ class egg_info(Command): - - - def find_sources(self): """Generate SOURCES.txt manifest file""" manifest_filename = os.path.join(self.egg_info,"SOURCES.txt") diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 5bd5ebd4..d5121de5 100755 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -1,6 +1,7 @@ from distutils.command.sdist import sdist as _sdist from distutils.util import convert_path from distutils import log +from glob import glob import os, re, sys, pkg_resources entities = [ @@ -38,7 +39,6 @@ def joinpath(prefix,suffix): - def walk_revctrl(dirname=''): """Find all files under revision control""" for ep in pkg_resources.iter_entry_points('setuptools.file_finders'): @@ -86,17 +86,21 @@ def entries_finder(dirname, filename): f = open(filename,'rU') data = f.read() f.close() - if data.startswith('9') or data.startswith('8'): # subversion 1.5/1.4 + if data.startswith('<?xml'): + for match in entries_pattern.finditer(data): + yield joinpath(dirname,unescape(match.group(1))) + else: + svnver=-1 + try: svnver = int(data.splitlines()[0]) + except: pass + if svnver<8: + log.warn("unrecognized .svn/entries format in %s", dirname) + return for record in map(str.splitlines, data.split('\n\x0c\n')[1:]): if not record or len(record)>=6 and record[5]=="delete": continue # skip deleted yield joinpath(dirname, record[0]) - elif data.startswith('<?xml'): - for match in entries_pattern.finditer(data): - yield joinpath(dirname,unescape(match.group(1))) - else: - log.warn("unrecognized .svn/entries format in %s", dirname) - + finders = [ (convert_path('CVS/Entries'), @@ -117,10 +121,6 @@ finders = [ - - - - class sdist(_sdist): """Smart sdist that finds anything supported by revision control""" @@ -162,6 +162,56 @@ class sdist(_sdist): sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close() raise + # Cribbed from old distutils code, to work around new distutils code + # that tries to do some of the same stuff as we do, in a way that makes + # us loop. + + def add_defaults (self): + standards = [('README', 'README.txt'), self.distribution.script_name] + + for fn in standards: + if type(fn) is tuple: + alts = fn + got_it = 0 + for fn in alts: + if os.path.exists(fn): + got_it = 1 + self.filelist.append(fn) + break + + if not got_it: + self.warn("standard file not found: should have one of " + + string.join(alts, ', ')) + else: + if os.path.exists(fn): + self.filelist.append(fn) + else: + self.warn("standard file '%s' not found" % fn) + + optional = ['test/test*.py', 'setup.cfg'] + + for pattern in optional: + files = filter(os.path.isfile, glob(pattern)) + if files: + self.filelist.extend(files) + + if self.distribution.has_pure_modules(): + build_py = self.get_finalized_command('build_py') + self.filelist.extend(build_py.get_source_files()) + + if self.distribution.has_ext_modules(): + build_ext = self.get_finalized_command('build_ext') + self.filelist.extend(build_ext.get_source_files()) + + if self.distribution.has_c_libraries(): + build_clib = self.get_finalized_command('build_clib') + self.filelist.extend(build_clib.get_source_files()) + + if self.distribution.has_scripts(): + build_scripts = self.get_finalized_command('build_scripts') + self.filelist.extend(build_scripts.get_source_files()) + + def check_readme(self): alts = ("README", "README.txt") for f in alts: @@ -193,13 +243,4 @@ class sdist(_sdist): - - - - - - - - - # diff --git a/setuptools/depends.py b/setuptools/depends.py index 4b7b3437..5fdf2d7e 100644 --- a/setuptools/depends.py +++ b/setuptools/depends.py @@ -36,7 +36,7 @@ class Require: def version_ok(self,version): """Is 'version' sufficiently up-to-date?""" return self.attribute is None or self.format is None or \ - str(version)<>"unknown" and version >= self.requested_version + str(version)!="unknown" and version >= self.requested_version def get_version(self, paths=None, default="unknown"): diff --git a/setuptools/dist.py b/setuptools/dist.py index 30ff35e3..c1218ef2 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -8,7 +8,7 @@ from setuptools.command.install_lib import install_lib from distutils.errors import DistutilsOptionError, DistutilsPlatformError from distutils.errors import DistutilsSetupError import setuptools, pkg_resources, distutils.core, distutils.dist, distutils.cmd -import os, distutils.log +import os, distutils.log, re def _get_unpatched(cls): """Protect against re-patching the distutils if reloaded @@ -61,8 +61,8 @@ def check_nsp(dist, attr, value): parent = '.'.join(nsp.split('.')[:-1]) if parent not in value: distutils.log.warn( - "%r is declared as a package namespace, but %r is not:" - " please correct this in setup.py", nsp, parent + "WARNING: %r is declared as a package namespace, but %r" + " is not: please correct this in setup.py", nsp, parent ) def check_extras(dist, attr, value): @@ -121,6 +121,47 @@ def check_package_data(dist, attr, value): "wildcard patterns" ) +def check_packages(dist, attr, value): + for pkgname in value: + if not re.match(r'\w+(\.\w+)*', pkgname): + distutils.log.warn( + "WARNING: %r not a valid package name; please use only" + ".-separated package names in setup.py", pkgname + ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + class Distribution(_Distribution): """Distribution with support for features, tests, and package data @@ -415,19 +456,19 @@ class Distribution(_Distribution): if self.packages: self.packages = [ p for p in self.packages - if p<>package and not p.startswith(pfx) + if p!=package and not p.startswith(pfx) ] if self.py_modules: self.py_modules = [ p for p in self.py_modules - if p<>package and not p.startswith(pfx) + if p!=package and not p.startswith(pfx) ] if self.ext_modules: self.ext_modules = [ p for p in self.ext_modules - if p.name<>package and not p.name.startswith(pfx) + if p.name!=package and not p.name.startswith(pfx) ] diff --git a/setuptools/package_index.py b/setuptools/package_index.py index da3fed12..70b75a6f 100755 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -1,5 +1,6 @@ """PyPI and direct package downloading""" import sys, os.path, re, urlparse, urllib2, shutil, random, socket, cStringIO +import httplib from pkg_resources import * from distutils import log from distutils.errors import DistutilsError @@ -8,7 +9,6 @@ try: except ImportError: from md5 import md5 from fnmatch import translate - EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$') HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I) # this is here to fix emacs' cruddy broken syntax highlighting @@ -42,6 +42,8 @@ def parse_bdist_wininst(name): def egg_info_for_url(url): scheme, server, path, parameters, query, fragment = urlparse.urlparse(url) base = urllib2.unquote(path.split('/')[-1]) + if server=='sourceforge.net' and base=='download': # XXX Yuck + base = urllib2.unquote(path.split('/')[-2]) if '#' in base: base, fragment = base.split('#',1) return base,fragment @@ -64,14 +66,12 @@ def distros_for_location(location, basename, metadata=None): if basename.endswith('.egg') and '-' in basename: # only one, unambiguous interpretation return [Distribution.from_location(location, basename, metadata)] - if basename.endswith('.exe'): win_base, py_ver = parse_bdist_wininst(basename) if win_base is not None: return interpret_distro_name( location, win_base, metadata, py_ver, BINARY_DIST, "win32" ) - # Try source distro extensions (.zip, .tgz, etc.) # for ext in EXTENSIONS: @@ -186,10 +186,10 @@ class PackageIndex(Environment): return self.info("Reading %s", url) + self.fetched_urls[url] = True # prevent multiple fetch attempts f = self.open_url(url, "Download error: %s -- Some packages may not be found!") if f is None: return - self.fetched_urls[url] = self.fetched_urls[f.url] = True - + self.fetched_urls[f.url] = True if 'html' not in f.headers.get('content-type', '').lower(): f.close() # not html, we can't process it return @@ -329,7 +329,7 @@ class PackageIndex(Environment): def check_md5(self, cs, info, filename, tfp): if re.match('md5=[0-9a-f]{32}$', info): self.debug("Validating md5 checksum for %s", filename) - if cs.hexdigest()<>info[4:]: + if cs.hexdigest()!=info[4:]: tfp.close() os.unlink(filename) raise DistutilsError( @@ -409,7 +409,8 @@ class PackageIndex(Environment): def fetch_distribution(self, - requirement, tmpdir, force_scan=False, source=False, develop_ok=False + requirement, tmpdir, force_scan=False, source=False, develop_ok=False, + local_index=None, ): """Obtain a distribution suitable for fulfilling `requirement` @@ -427,15 +428,15 @@ class PackageIndex(Environment): set, development and system eggs (i.e., those using the ``.egg-info`` format) will be ignored. """ - # process a Requirement self.info("Searching for %s", requirement) skipped = {} + dist = None - def find(req): + def find(env, req): # Find a matching distribution; may be called more than once - for dist in self[req.key]: + for dist in env[req.key]: if dist.precedence==DEVELOP_DIST and not develop_ok: if dist not in skipped: @@ -444,23 +445,25 @@ class PackageIndex(Environment): continue if dist in req and (dist.precedence<=SOURCE_DIST or not source): - self.info("Best match: %s", dist) - return dist.clone( - location=self.download(dist.location, tmpdir) - ) + return dist + + if force_scan: self.prescan() self.find_packages(requirement) + dist = find(self, requirement) + + if local_index is not None: + dist = dist or find(local_index, requirement) - dist = find(requirement) if dist is None and self.to_scan is not None: self.prescan() - dist = find(requirement) + dist = find(self, requirement) if dist is None and not force_scan: self.find_packages(requirement) - dist = find(requirement) + dist = find(self, requirement) if dist is None: self.warn( @@ -468,7 +471,9 @@ class PackageIndex(Environment): (source and "a source distribution of " or ""), requirement, ) - return dist + self.info("Best match: %s", dist) + return dist.clone(location=self.download(dist.location, tmpdir)) + def fetch(self, requirement, tmpdir, force_scan=False, source=False): """Obtain a file suitable for fulfilling `requirement` @@ -485,11 +490,6 @@ class PackageIndex(Environment): - - - - - def gen_setup(self, filename, fragment, tmpdir): match = EGG_FRAGMENT.match(fragment) dists = match and [d for d in @@ -573,17 +573,19 @@ class PackageIndex(Environment): def open_url(self, url, warning=None): - if url.startswith('file:'): - return local_open(url) + if url.startswith('file:'): return local_open(url) try: return open_with_auth(url) except urllib2.HTTPError, v: return v except urllib2.URLError, v: - if warning: self.warn(warning, v.reason) - else: - raise DistutilsError("Download error for %s: %s" - % (url, v.reason)) + reason = v.reason + except httplib.HTTPException, v: + reason = "%s: %s" % (v.__doc__ or v.__class__.__name__, v) + if warning: + self.warn(warning, reason) + else: + raise DistutilsError("Download error for %s: %s" % (url, reason)) def _download_url(self, scheme, url, tmpdir): # Determine download filename @@ -611,8 +613,6 @@ class PackageIndex(Environment): self.url_ok(url, True) # raises error if not allowed return self._attempt_download(url, filename) - - def scan_url(self, url): self.process_url(url, True) diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py index 4db0dbdb..00eb0124 100755 --- a/setuptools/sandbox.py +++ b/setuptools/sandbox.py @@ -1,14 +1,46 @@ -import os, sys, __builtin__, tempfile, operator +import os, sys, __builtin__, tempfile, operator, pkg_resources _os = sys.modules[os.name] _open = open +_file = file + from distutils.errors import DistutilsError +from pkg_resources import working_set + __all__ = [ "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup", ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + def run_setup(setup_script, args): """Run a distutils setup script, sandboxed in its directory""" - old_dir = os.getcwd() save_argv = sys.argv[:] save_path = sys.path[:] @@ -16,13 +48,16 @@ def run_setup(setup_script, args): temp_dir = os.path.join(setup_dir,'temp') if not os.path.isdir(temp_dir): os.makedirs(temp_dir) save_tmp = tempfile.tempdir - + save_modules = sys.modules.copy() + pr_state = pkg_resources.__getstate__() try: - tempfile.tempdir = temp_dir - os.chdir(setup_dir) + tempfile.tempdir = temp_dir; os.chdir(setup_dir) try: sys.argv[:] = [setup_script]+list(args) sys.path.insert(0, setup_dir) + # reset to include setup dir, w/clean callback list + working_set.__init__() + working_set.callbacks.append(lambda dist:dist.activate()) DirectorySandbox(setup_dir).run( lambda: execfile( "setup.py", @@ -34,11 +69,17 @@ def run_setup(setup_script, args): raise # Normal exit, just return finally: + pkg_resources.__setstate__(pr_state) + sys.modules.update(save_modules) + for key in list(sys.modules): + if key not in save_modules: del sys.modules[key] os.chdir(old_dir) sys.path[:] = save_path sys.argv[:] = save_argv tempfile.tempdir = save_tmp + + class AbstractSandbox: """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts""" @@ -58,15 +99,16 @@ class AbstractSandbox: """Run 'func' under os sandboxing""" try: self._copy(self) - __builtin__.open = __builtin__.file = self._open + __builtin__.file = self._file + __builtin__.open = self._open self._active = True return func() finally: self._active = False - __builtin__.open = __builtin__.file = _open + __builtin__.open = _file + __builtin__.file = _open self._copy(_os) - def _mk_dual_path_wrapper(name): original = getattr(_os,name) def wrap(self,src,dst,*args,**kw): @@ -75,7 +117,6 @@ class AbstractSandbox: return original(src,dst,*args,**kw) return wrap - for name in ["rename", "link", "symlink"]: if hasattr(_os,name): locals()[name] = _mk_dual_path_wrapper(name) @@ -88,7 +129,8 @@ class AbstractSandbox: return original(path,*args,**kw) return wrap - _open = _mk_single_path_wrapper('file', _open) + _open = _mk_single_path_wrapper('open', _open) + _file = _mk_single_path_wrapper('file', _file) for name in [ "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat", @@ -96,7 +138,6 @@ class AbstractSandbox: ]: if hasattr(_os,name): locals()[name] = _mk_single_path_wrapper(name) - def _mk_single_with_return(name): original = getattr(_os,name) def wrap(self,path,*args,**kw): @@ -187,22 +228,22 @@ class DirectorySandbox(AbstractSandbox): self._violation(operation, src, dst, *args, **kw) return (src,dst) + def _file(self, path, mode='r', *args, **kw): + if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): + self._violation("file", path, mode, *args, **kw) + return _file(path,mode,*args,**kw) + def open(self, file, flags, mode=0777): """Called for low-level os.open()""" if flags & WRITE_FLAGS and not self._ok(file): self._violation("os.open", file, flags, mode) return _os.open(file,flags,mode) - WRITE_FLAGS = reduce( - operator.or_, - [getattr(_os, a, 0) for a in + operator.or_, [getattr(_os, a, 0) for a in "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()] ) - - - class SandboxViolation(DistutilsError): """A setup script attempted to modify the filesystem outside the sandbox""" |
