Commit 8e3f9d32 authored by Alex Grönholm's avatar Alex Grönholm

Fixed PEP 8 compliancy of the setuptools.command package

parent afea314a
...@@ -5,10 +5,11 @@ __all__ = [ ...@@ -5,10 +5,11 @@ __all__ = [
'register', 'bdist_wininst', 'upload_docs', 'register', 'bdist_wininst', 'upload_docs',
] ]
from setuptools.command import install_scripts from distutils.command.bdist import bdist
import sys import sys
from distutils.command.bdist import bdist from setuptools.command import install_scripts
if 'egg' not in bdist.format_commands: if 'egg' not in bdist.format_commands:
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file") bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
......
...@@ -2,10 +2,12 @@ from distutils.errors import DistutilsOptionError ...@@ -2,10 +2,12 @@ from distutils.errors import DistutilsOptionError
from setuptools.command.setopt import edit_config, option_base, config_file from setuptools.command.setopt import edit_config, option_base, config_file
def shquote(arg): def shquote(arg):
"""Quote an argument for later parsing by shlex.split()""" """Quote an argument for later parsing by shlex.split()"""
for c in '"', "'", "\\", "#": for c in '"', "'", "\\", "#":
if c in arg: return repr(arg) if c in arg:
return repr(arg)
if arg.split() != [arg]: if arg.split() != [arg]:
return repr(arg) return repr(arg)
return arg return arg
...@@ -18,7 +20,7 @@ class alias(option_base): ...@@ -18,7 +20,7 @@ class alias(option_base):
command_consumes_arguments = True command_consumes_arguments = True
user_options = [ user_options = [
('remove', 'r', 'remove (unset) the alias'), ('remove', 'r', 'remove (unset) the alias'),
] + option_base.user_options ] + option_base.user_options
boolean_options = option_base.boolean_options + ['remove'] boolean_options = option_base.boolean_options + ['remove']
...@@ -46,7 +48,7 @@ class alias(option_base): ...@@ -46,7 +48,7 @@ class alias(option_base):
print("setup.py alias", format_alias(alias, aliases)) print("setup.py alias", format_alias(alias, aliases))
return return
elif len(self.args)==1: elif len(self.args) == 1:
alias, = self.args alias, = self.args
if self.remove: if self.remove:
command = None command = None
...@@ -58,9 +60,9 @@ class alias(option_base): ...@@ -58,9 +60,9 @@ class alias(option_base):
return return
else: else:
alias = self.args[0] alias = self.args[0]
command = ' '.join(map(shquote,self.args[1:])) command = ' '.join(map(shquote, self.args[1:]))
edit_config(self.filename, {'aliases': {alias:command}}, self.dry_run) edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run)
def format_alias(name, aliases): def format_alias(name, aliases):
...@@ -73,4 +75,4 @@ def format_alias(name, aliases): ...@@ -73,4 +75,4 @@ def format_alias(name, aliases):
source = '' source = ''
else: else:
source = '--filename=%r' % source source = '--filename=%r' % source
return source+name+' '+command return source + name + ' ' + command
...@@ -3,29 +3,33 @@ ...@@ -3,29 +3,33 @@
Build .egg distributions""" Build .egg distributions"""
# This module should be kept compatible with Python 2.3 # This module should be kept compatible with Python 2.3
from distutils.errors import DistutilsSetupError
from distutils.dir_util import remove_tree, mkpath
from distutils import log
from types import CodeType
import sys import sys
import os import os
import marshal import marshal
import textwrap import textwrap
from pkg_resources import get_build_platform, Distribution, ensure_directory
from pkg_resources import EntryPoint
from setuptools.compat import basestring, next
from setuptools.extension import Library
from setuptools import Command from setuptools import Command
from distutils.dir_util import remove_tree, mkpath
try: try:
# Python 2.7 or >=3.2 # Python 2.7 or >=3.2
from sysconfig import get_path, get_python_version from sysconfig import get_path, get_python_version
def _get_purelib(): def _get_purelib():
return get_path("purelib") return get_path("purelib")
except ImportError: except ImportError:
from distutils.sysconfig import get_python_lib, get_python_version from distutils.sysconfig import get_python_lib, get_python_version
def _get_purelib(): def _get_purelib():
return get_python_lib(False) return get_python_lib(False)
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.compat import basestring, next
from setuptools.extension import Library
def strip_module(filename): def strip_module(filename):
if '.' in filename: if '.' in filename:
...@@ -34,6 +38,7 @@ def strip_module(filename): ...@@ -34,6 +38,7 @@ def strip_module(filename):
filename = filename[:-6] filename = filename[:-6]
return filename return filename
def write_stub(resource, pyfile): def write_stub(resource, pyfile):
_stub_template = textwrap.dedent(""" _stub_template = textwrap.dedent("""
def __bootstrap__(): def __bootstrap__():
...@@ -49,23 +54,22 @@ def write_stub(resource, pyfile): ...@@ -49,23 +54,22 @@ def write_stub(resource, pyfile):
class bdist_egg(Command): class bdist_egg(Command):
description = "create an \"egg\" distribution" description = "create an \"egg\" distribution"
user_options = [ user_options = [
('bdist-dir=', 'b', ('bdist-dir=', 'b',
"temporary directory for creating the distribution"), "temporary directory for creating the distribution"),
('plat-name=', 'p', "platform name to embed in generated filenames " ('plat-name=', 'p', "platform name to embed in generated filenames "
"(default: %s)" % get_build_platform()), "(default: %s)" % get_build_platform()),
('exclude-source-files', None, ('exclude-source-files', None,
"remove all .py files from the generated egg"), "remove all .py files from the generated egg"),
('keep-temp', 'k', ('keep-temp', 'k',
"keep the pseudo-installation tree around after " + "keep the pseudo-installation tree around after " +
"creating the distribution archive"), "creating the distribution archive"),
('dist-dir=', 'd', ('dist-dir=', 'd',
"directory to put final built distributions in"), "directory to put final built distributions in"),
('skip-build', None, ('skip-build', None,
"skip rebuilding everything (for testing/debugging)"), "skip rebuilding everything (for testing/debugging)"),
] ]
boolean_options = [ boolean_options = [
...@@ -92,7 +96,7 @@ class bdist_egg(Command): ...@@ -92,7 +96,7 @@ class bdist_egg(Command):
if self.plat_name is None: if self.plat_name is None:
self.plat_name = get_build_platform() self.plat_name = get_build_platform()
self.set_undefined_options('bdist',('dist_dir', 'dist_dir')) self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
if self.egg_output is None: if self.egg_output is None:
...@@ -103,25 +107,25 @@ class bdist_egg(Command): ...@@ -103,25 +107,25 @@ class bdist_egg(Command):
self.distribution.has_ext_modules() and self.plat_name self.distribution.has_ext_modules() and self.plat_name
).egg_name() ).egg_name()
self.egg_output = os.path.join(self.dist_dir, basename+'.egg') self.egg_output = os.path.join(self.dist_dir, basename + '.egg')
def do_install_data(self): def do_install_data(self):
# Hack for packages that install data to install's --install-lib # Hack for packages that install data to install's --install-lib
self.get_finalized_command('install').install_lib = self.bdist_dir self.get_finalized_command('install').install_lib = self.bdist_dir
site_packages = os.path.normcase(os.path.realpath(_get_purelib())) site_packages = os.path.normcase(os.path.realpath(_get_purelib()))
old, self.distribution.data_files = self.distribution.data_files,[] old, self.distribution.data_files = self.distribution.data_files, []
for item in old: for item in old:
if isinstance(item,tuple) and len(item)==2: if isinstance(item, tuple) and len(item) == 2:
if os.path.isabs(item[0]): if os.path.isabs(item[0]):
realpath = os.path.realpath(item[0]) realpath = os.path.realpath(item[0])
normalized = os.path.normcase(realpath) normalized = os.path.normcase(realpath)
if normalized==site_packages or normalized.startswith( if normalized == site_packages or normalized.startswith(
site_packages+os.sep site_packages + os.sep
): ):
item = realpath[len(site_packages)+1:], item[1] item = realpath[len(site_packages) + 1:], item[1]
# XXX else: raise ??? # XXX else: raise ???
self.distribution.data_files.append(item) self.distribution.data_files.append(item)
try: try:
...@@ -133,11 +137,11 @@ class bdist_egg(Command): ...@@ -133,11 +137,11 @@ class bdist_egg(Command):
def get_outputs(self): def get_outputs(self):
return [self.egg_output] return [self.egg_output]
def call_command(self,cmdname,**kw): def call_command(self, cmdname, **kw):
"""Invoke reinitialized command `cmdname` with keyword args""" """Invoke reinitialized command `cmdname` with keyword args"""
for dirname in INSTALL_DIRECTORY_ATTRS: for dirname in INSTALL_DIRECTORY_ATTRS:
kw.setdefault(dirname,self.bdist_dir) kw.setdefault(dirname, self.bdist_dir)
kw.setdefault('skip_build',self.skip_build) kw.setdefault('skip_build', self.skip_build)
kw.setdefault('dry_run', self.dry_run) kw.setdefault('dry_run', self.dry_run)
cmd = self.reinitialize_command(cmdname, **kw) cmd = self.reinitialize_command(cmdname, **kw)
self.run_command(cmdname) self.run_command(cmdname)
...@@ -160,15 +164,16 @@ class bdist_egg(Command): ...@@ -160,15 +164,16 @@ class bdist_egg(Command):
all_outputs, ext_outputs = self.get_ext_outputs() all_outputs, ext_outputs = self.get_ext_outputs()
self.stubs = [] self.stubs = []
to_compile = [] to_compile = []
for (p,ext_name) in enumerate(ext_outputs): for (p, ext_name) in enumerate(ext_outputs):
filename,ext = os.path.splitext(ext_name) filename, ext = os.path.splitext(ext_name)
pyfile = os.path.join(self.bdist_dir, strip_module(filename)+'.py') pyfile = os.path.join(self.bdist_dir, strip_module(filename) +
'.py')
self.stubs.append(pyfile) self.stubs.append(pyfile)
log.info("creating stub loader for %s" % ext_name) log.info("creating stub loader for %s" % ext_name)
if not self.dry_run: if not self.dry_run:
write_stub(os.path.basename(ext_name), pyfile) write_stub(os.path.basename(ext_name), pyfile)
to_compile.append(pyfile) to_compile.append(pyfile)
ext_outputs[p] = ext_name.replace(os.sep,'/') ext_outputs[p] = ext_name.replace(os.sep, '/')
if to_compile: if to_compile:
cmd.byte_compile(to_compile) cmd.byte_compile(to_compile)
...@@ -177,12 +182,13 @@ class bdist_egg(Command): ...@@ -177,12 +182,13 @@ class bdist_egg(Command):
# Make the EGG-INFO directory # Make the EGG-INFO directory
archive_root = self.bdist_dir archive_root = self.bdist_dir
egg_info = os.path.join(archive_root,'EGG-INFO') egg_info = os.path.join(archive_root, 'EGG-INFO')
self.mkpath(egg_info) self.mkpath(egg_info)
if self.distribution.scripts: if self.distribution.scripts:
script_dir = os.path.join(egg_info, 'scripts') script_dir = os.path.join(egg_info, 'scripts')
log.info("installing scripts to %s" % script_dir) log.info("installing scripts to %s" % script_dir)
self.call_command('install_scripts',install_dir=script_dir,no_ep=1) self.call_command('install_scripts', install_dir=script_dir,
no_ep=1)
self.copy_metadata_to(egg_info) self.copy_metadata_to(egg_info)
native_libs = os.path.join(egg_info, "native_libs.txt") native_libs = os.path.join(egg_info, "native_libs.txt")
...@@ -200,10 +206,10 @@ class bdist_egg(Command): ...@@ -200,10 +206,10 @@ class bdist_egg(Command):
os.unlink(native_libs) os.unlink(native_libs)
write_safety_flag( write_safety_flag(
os.path.join(archive_root,'EGG-INFO'), self.zip_safe() os.path.join(archive_root, 'EGG-INFO'), self.zip_safe()
) )
if os.path.exists(os.path.join(self.egg_info,'depends.txt')): if os.path.exists(os.path.join(self.egg_info, 'depends.txt')):
log.warn( log.warn(
"WARNING: 'depends.txt' will not be used by setuptools 0.6!\n" "WARNING: 'depends.txt' will not be used by setuptools 0.6!\n"
"Use the install_requires/extras_require setup() args instead." "Use the install_requires/extras_require setup() args instead."
...@@ -214,25 +220,25 @@ class bdist_egg(Command): ...@@ -214,25 +220,25 @@ class bdist_egg(Command):
# Make the archive # Make the archive
make_zipfile(self.egg_output, archive_root, verbose=self.verbose, make_zipfile(self.egg_output, archive_root, verbose=self.verbose,
dry_run=self.dry_run, mode=self.gen_header()) dry_run=self.dry_run, mode=self.gen_header())
if not self.keep_temp: if not self.keep_temp:
remove_tree(self.bdist_dir, dry_run=self.dry_run) remove_tree(self.bdist_dir, dry_run=self.dry_run)
# Add to 'Distribution.dist_files' so that the "upload" command works # Add to 'Distribution.dist_files' so that the "upload" command works
getattr(self.distribution,'dist_files',[]).append( getattr(self.distribution, 'dist_files', []).append(
('bdist_egg',get_python_version(),self.egg_output)) ('bdist_egg', get_python_version(), self.egg_output))
def zap_pyfiles(self): def zap_pyfiles(self):
log.info("Removing .py files from temporary directory") log.info("Removing .py files from temporary directory")
for base,dirs,files in walk_egg(self.bdist_dir): for base, dirs, files in walk_egg(self.bdist_dir):
for name in files: for name in files:
if name.endswith('.py'): if name.endswith('.py'):
path = os.path.join(base,name) path = os.path.join(base, name)
log.debug("Deleting %s", path) log.debug("Deleting %s", path)
os.unlink(path) os.unlink(path)
def zip_safe(self): def zip_safe(self):
safe = getattr(self.distribution,'zip_safe',None) safe = getattr(self.distribution, 'zip_safe', None)
if safe is not None: if safe is not None:
return safe return safe
log.warn("zip_safe flag not set; analyzing archive contents...") log.warn("zip_safe flag not set; analyzing archive contents...")
...@@ -240,7 +246,7 @@ class bdist_egg(Command): ...@@ -240,7 +246,7 @@ class bdist_egg(Command):
def gen_header(self): def gen_header(self):
epm = EntryPoint.parse_map(self.distribution.entry_points or '') epm = EntryPoint.parse_map(self.distribution.entry_points or '')
ep = epm.get('setuptools.installation',{}).get('eggsecutable') ep = epm.get('setuptools.installation', {}).get('eggsecutable')
if ep is None: if ep is None:
return 'w' # not an eggsecutable, do it the usual way. return 'w' # not an eggsecutable, do it the usual way.
...@@ -268,7 +274,6 @@ class bdist_egg(Command): ...@@ -268,7 +274,6 @@ class bdist_egg(Command):
' echo Please rename it back to %(basename)s and try again.\n' ' echo Please rename it back to %(basename)s and try again.\n'
' exec false\n' ' exec false\n'
'fi\n' 'fi\n'
) % locals() ) % locals()
if not self.dry_run: if not self.dry_run:
...@@ -283,7 +288,7 @@ class bdist_egg(Command): ...@@ -283,7 +288,7 @@ class bdist_egg(Command):
# normalize the path (so that a forward-slash in egg_info will # normalize the path (so that a forward-slash in egg_info will
# match using startswith below) # match using startswith below)
norm_egg_info = os.path.normpath(self.egg_info) norm_egg_info = os.path.normpath(self.egg_info)
prefix = os.path.join(norm_egg_info,'') prefix = os.path.join(norm_egg_info, '')
for path in self.ei_cmd.filelist.files: for path in self.ei_cmd.filelist.files:
if path.startswith(prefix): if path.startswith(prefix):
target = os.path.join(target_dir, path[len(prefix):]) target = os.path.join(target_dir, path[len(prefix):])
...@@ -296,23 +301,24 @@ class bdist_egg(Command): ...@@ -296,23 +301,24 @@ class bdist_egg(Command):
all_outputs = [] all_outputs = []
ext_outputs = [] ext_outputs = []
paths = {self.bdist_dir:''} paths = {self.bdist_dir: ''}
for base, dirs, files in os.walk(self.bdist_dir): for base, dirs, files in os.walk(self.bdist_dir):
for filename in files: for filename in files:
if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS: if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS:
all_outputs.append(paths[base]+filename) all_outputs.append(paths[base] + filename)
for filename in dirs: for filename in dirs:
paths[os.path.join(base,filename)] = paths[base]+filename+'/' paths[os.path.join(base, filename)] = (paths[base] +
filename + '/')
if self.distribution.has_ext_modules(): if self.distribution.has_ext_modules():
build_cmd = self.get_finalized_command('build_ext') build_cmd = self.get_finalized_command('build_ext')
for ext in build_cmd.extensions: for ext in build_cmd.extensions:
if isinstance(ext,Library): if isinstance(ext, Library):
continue continue
fullname = build_cmd.get_ext_fullname(ext.name) fullname = build_cmd.get_ext_fullname(ext.name)
filename = build_cmd.get_ext_filename(fullname) filename = build_cmd.get_ext_filename(fullname)
if not os.path.basename(filename).startswith('dl-'): if not os.path.basename(filename).startswith('dl-'):
if os.path.exists(os.path.join(self.bdist_dir,filename)): if os.path.exists(os.path.join(self.bdist_dir, filename)):
ext_outputs.append(filename) ext_outputs.append(filename)
return all_outputs, ext_outputs return all_outputs, ext_outputs
...@@ -324,19 +330,21 @@ NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split()) ...@@ -324,19 +330,21 @@ NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split())
def walk_egg(egg_dir): def walk_egg(egg_dir):
"""Walk an unpacked egg's contents, skipping the metadata directory""" """Walk an unpacked egg's contents, skipping the metadata directory"""
walker = os.walk(egg_dir) walker = os.walk(egg_dir)
base,dirs,files = next(walker) base, dirs, files = next(walker)
if 'EGG-INFO' in dirs: if 'EGG-INFO' in dirs:
dirs.remove('EGG-INFO') dirs.remove('EGG-INFO')
yield base,dirs,files yield base, dirs, files
for bdf in walker: for bdf in walker:
yield bdf yield bdf
def analyze_egg(egg_dir, stubs): def analyze_egg(egg_dir, stubs):
# check for existing flag in EGG-INFO # check for existing flag in EGG-INFO
for flag,fn in safety_flags.items(): for flag, fn in safety_flags.items():
if os.path.exists(os.path.join(egg_dir,'EGG-INFO',fn)): if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)):
return flag return flag
if not can_scan(): return False if not can_scan():
return False
safe = True safe = True
for base, dirs, files in walk_egg(egg_dir): for base, dirs, files in walk_egg(egg_dir):
for name in files: for name in files:
...@@ -347,36 +355,39 @@ def analyze_egg(egg_dir, stubs): ...@@ -347,36 +355,39 @@ def analyze_egg(egg_dir, stubs):
safe = scan_module(egg_dir, base, name, stubs) and safe safe = scan_module(egg_dir, base, name, stubs) and safe
return safe return safe
def write_safety_flag(egg_dir, safe): def write_safety_flag(egg_dir, safe):
# Write or remove zip safety flag file(s) # Write or remove zip safety flag file(s)
for flag,fn in safety_flags.items(): for flag, fn in safety_flags.items():
fn = os.path.join(egg_dir, fn) fn = os.path.join(egg_dir, fn)
if os.path.exists(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) os.unlink(fn)
elif safe is not None and bool(safe)==flag: elif safe is not None and bool(safe) == flag:
f = open(fn,'wt') f = open(fn, 'wt')
f.write('\n') f.write('\n')
f.close() f.close()
safety_flags = { safety_flags = {
True: 'zip-safe', True: 'zip-safe',
False: 'not-zip-safe', False: 'not-zip-safe',
} }
def scan_module(egg_dir, base, name, stubs): def scan_module(egg_dir, base, name, stubs):
"""Check whether module possibly uses unsafe-for-zipfile stuff""" """Check whether module possibly uses unsafe-for-zipfile stuff"""
filename = os.path.join(base,name) filename = os.path.join(base, name)
if filename[:-1] in stubs: if filename[:-1] in stubs:
return True # Extension module return True # Extension module
pkg = base[len(egg_dir)+1:].replace(os.sep,'.') pkg = base[len(egg_dir) + 1:].replace(os.sep, '.')
module = pkg+(pkg and '.' or '')+os.path.splitext(name)[0] module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0]
if sys.version_info < (3, 3): if sys.version_info < (3, 3):
skip = 8 # skip magic & date skip = 8 # skip magic & date
else: else:
skip = 12 # skip magic & date & file size skip = 12 # skip magic & date & file size
f = open(filename,'rb') f = open(filename, 'rb')
f.read(skip) f.read(skip)
code = marshal.load(f) code = marshal.load(f)
f.close() f.close()
...@@ -396,21 +407,24 @@ def scan_module(egg_dir, base, name, stubs): ...@@ -396,21 +407,24 @@ def scan_module(egg_dir, base, name, stubs):
log.warn("%s: module MAY be using inspect.%s", module, bad) log.warn("%s: module MAY be using inspect.%s", module, bad)
safe = False safe = False
if '__name__' in symbols and '__main__' in symbols and '.' not in module: if '__name__' in symbols and '__main__' in symbols and '.' not in module:
if sys.version[:3]=="2.4": # -m works w/zipfiles in 2.5 if sys.version[:3] == "2.4": # -m works w/zipfiles in 2.5
log.warn("%s: top-level module may be 'python -m' script", module) log.warn("%s: top-level module may be 'python -m' script", module)
safe = False safe = False
return safe return safe
def iter_symbols(code): def iter_symbols(code):
"""Yield names and strings used by `code` and its nested code objects""" """Yield names and strings used by `code` and its nested code objects"""
for name in code.co_names: yield name for name in code.co_names:
yield name
for const in code.co_consts: for const in code.co_consts:
if isinstance(const,basestring): if isinstance(const, basestring):
yield const yield const
elif isinstance(const,CodeType): elif isinstance(const, CodeType):
for name in iter_symbols(const): for name in iter_symbols(const):
yield name yield name
def can_scan(): def can_scan():
if not sys.platform.startswith('java') and sys.platform != 'cli': if not sys.platform.startswith('java') and sys.platform != 'cli':
# CPython, PyPy, etc. # CPython, PyPy, etc.
...@@ -426,8 +440,9 @@ INSTALL_DIRECTORY_ATTRS = [ ...@@ -426,8 +440,9 @@ INSTALL_DIRECTORY_ATTRS = [
'install_lib', 'install_dir', 'install_data', 'install_base' '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'): mode='w'):
"""Create a zip file from all the files under 'base_dir'. The output """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" zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
Python module (if available) or the InfoZIP "zip" utility (if installed Python module (if available) or the InfoZIP "zip" utility (if installed
...@@ -435,6 +450,7 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None, ...@@ -435,6 +450,7 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
raises DistutilsExecError. Returns the name of the output zip file. raises DistutilsExecError. Returns the name of the output zip file.
""" """
import zipfile import zipfile
mkpath(os.path.dirname(zip_filename), dry_run=dry_run) mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir) log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
...@@ -442,13 +458,14 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None, ...@@ -442,13 +458,14 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
for name in names: for name in names:
path = os.path.normpath(os.path.join(dirname, name)) path = os.path.normpath(os.path.join(dirname, name))
if os.path.isfile(path): if os.path.isfile(path):
p = path[len(base_dir)+1:] p = path[len(base_dir) + 1:]
if not dry_run: if not dry_run:
z.write(path, p) z.write(path, p)
log.debug("adding '%s'" % p) log.debug("adding '%s'" % p)
if compress is None: if compress is None:
compress = (sys.version>="2.4") # avoid 2.3 zipimport bug when 64 bits # avoid 2.3 zipimport bug when 64 bits
compress = (sys.version >= "2.4")
compression = [zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED][bool(compress)] compression = [zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED][bool(compress)]
if not dry_run: if not dry_run:
......
import distutils.command.bdist_rpm as orig import distutils.command.bdist_rpm as orig
class bdist_rpm(orig.bdist_rpm): class bdist_rpm(orig.bdist_rpm):
""" """
Override the default bdist_rpm behavior to do the following: Override the default bdist_rpm behavior to do the following:
...@@ -19,7 +20,7 @@ class bdist_rpm(orig.bdist_rpm): ...@@ -19,7 +20,7 @@ class bdist_rpm(orig.bdist_rpm):
def _make_spec_file(self): def _make_spec_file(self):
version = self.distribution.get_version() version = self.distribution.get_version()
rpmversion = version.replace('-','_') rpmversion = version.replace('-', '_')
spec = orig.bdist_rpm._make_spec_file(self) spec = orig.bdist_rpm._make_spec_file(self)
line23 = '%define version ' + version line23 = '%define version ' + version
line24 = '%define version ' + rpmversion line24 = '%define version ' + rpmversion
......
import distutils.command.bdist_wininst as orig import distutils.command.bdist_wininst as orig
class bdist_wininst(orig.bdist_wininst): class bdist_wininst(orig.bdist_wininst):
def reinitialize_command(self, command, reinit_subcommands=0): def reinitialize_command(self, command, reinit_subcommands=0):
""" """
......
from distutils.command.build_ext import build_ext as _du_build_ext from distutils.command.build_ext import build_ext as _du_build_ext
from distutils.file_util import copy_file
from distutils.ccompiler import new_compiler
from distutils.sysconfig import customize_compiler
from distutils.errors import DistutilsError
from distutils import log
import os
import sys
from setuptools.extension import Library
try: try:
# Attempt to use Pyrex for building extensions, if available # Attempt to use Pyrex for building extensions, if available
from Pyrex.Distutils.build_ext import build_ext as _build_ext from Pyrex.Distutils.build_ext import build_ext as _build_ext
except ImportError: except ImportError:
_build_ext = _du_build_ext _build_ext = _du_build_ext
import os
import sys
from distutils.file_util import copy_file
from setuptools.extension import Library
from distutils.ccompiler import new_compiler
from distutils.sysconfig import customize_compiler
try: try:
# Python 2.7 or >=3.2 # Python 2.7 or >=3.2
from sysconfig import _CONFIG_VARS from sysconfig import _CONFIG_VARS
except ImportError: except ImportError:
from distutils.sysconfig import get_config_var from distutils.sysconfig import get_config_var
get_config_var("LDSHARED") # make sure _config_vars is initialized get_config_var("LDSHARED") # make sure _config_vars is initialized
del get_config_var del get_config_var
from distutils.sysconfig import _config_vars as _CONFIG_VARS from distutils.sysconfig import _config_vars as _CONFIG_VARS
from distutils import log
from distutils.errors import DistutilsError
have_rtld = False have_rtld = False
use_stubs = False use_stubs = False
...@@ -31,11 +34,13 @@ if sys.platform == "darwin": ...@@ -31,11 +34,13 @@ if sys.platform == "darwin":
elif os.name != 'nt': elif os.name != 'nt':
try: try:
from dl import RTLD_NOW from dl import RTLD_NOW
have_rtld = True have_rtld = True
use_stubs = True use_stubs = True
except ImportError: except ImportError:
pass pass
def if_dl(s): def if_dl(s):
if have_rtld: if have_rtld:
return s return s
...@@ -59,8 +64,9 @@ class build_ext(_build_ext): ...@@ -59,8 +64,9 @@ class build_ext(_build_ext):
modpath = fullname.split('.') modpath = fullname.split('.')
package = '.'.join(modpath[:-1]) package = '.'.join(modpath[:-1])
package_dir = build_py.get_package_dir(package) package_dir = build_py.get_package_dir(package)
dest_filename = os.path.join(package_dir,os.path.basename(filename)) dest_filename = os.path.join(package_dir,
src_filename = os.path.join(self.build_lib,filename) os.path.basename(filename))
src_filename = os.path.join(self.build_lib, filename)
# Always copy, even if source is older than destination, to ensure # Always copy, even if source is older than destination, to ensure
# that the right extensions for the current Python/platform are # that the right extensions for the current Python/platform are
...@@ -72,7 +78,8 @@ class build_ext(_build_ext): ...@@ -72,7 +78,8 @@ class build_ext(_build_ext):
if ext._needs_stub: if ext._needs_stub:
self.write_stub(package_dir or os.curdir, ext, True) self.write_stub(package_dir or os.curdir, ext, True)
if _build_ext is not _du_build_ext and not hasattr(_build_ext,'pyrex_sources'): if _build_ext is not _du_build_ext and not hasattr(_build_ext,
'pyrex_sources'):
# Workaround for problems using some Pyrex versions w/SWIG and/or 2.4 # Workaround for problems using some Pyrex versions w/SWIG and/or 2.4
def swig_sources(self, sources, *otherargs): def swig_sources(self, sources, *otherargs):
# first do any Pyrex processing # first do any Pyrex processing
...@@ -81,15 +88,15 @@ class build_ext(_build_ext): ...@@ -81,15 +88,15 @@ class build_ext(_build_ext):
return _du_build_ext.swig_sources(self, sources, *otherargs) return _du_build_ext.swig_sources(self, sources, *otherargs)
def get_ext_filename(self, fullname): def get_ext_filename(self, fullname):
filename = _build_ext.get_ext_filename(self,fullname) filename = _build_ext.get_ext_filename(self, fullname)
if fullname in self.ext_map: if fullname in self.ext_map:
ext = self.ext_map[fullname] ext = self.ext_map[fullname]
if isinstance(ext,Library): if isinstance(ext, Library):
fn, ext = os.path.splitext(filename) fn, ext = os.path.splitext(filename)
return self.shlib_compiler.library_filename(fn,libtype) return self.shlib_compiler.library_filename(fn, libtype)
elif use_stubs and ext._links_to_dynamic: elif use_stubs and ext._links_to_dynamic:
d,fn = os.path.split(filename) d, fn = os.path.split(filename)
return os.path.join(d,'dl-'+fn) return os.path.join(d, 'dl-' + fn)
return filename return filename
def initialize_options(self): def initialize_options(self):
...@@ -103,7 +110,7 @@ class build_ext(_build_ext): ...@@ -103,7 +110,7 @@ class build_ext(_build_ext):
self.extensions = self.extensions or [] self.extensions = self.extensions or []
self.check_extensions_list(self.extensions) self.check_extensions_list(self.extensions)
self.shlibs = [ext for ext in self.extensions self.shlibs = [ext for ext in self.extensions
if isinstance(ext, Library)] if isinstance(ext, Library)]
if self.shlibs: if self.shlibs:
self.setup_shlib_compiler() self.setup_shlib_compiler()
for ext in self.extensions: for ext in self.extensions:
...@@ -118,9 +125,10 @@ class build_ext(_build_ext): ...@@ -118,9 +125,10 @@ class build_ext(_build_ext):
ltd = ext._links_to_dynamic = \ ltd = ext._links_to_dynamic = \
self.shlibs and self.links_to_dynamic(ext) or False self.shlibs and self.links_to_dynamic(ext) or False
ext._needs_stub = ltd and use_stubs and not isinstance(ext,Library) ext._needs_stub = ltd and use_stubs and not isinstance(ext,
Library)
filename = ext._file_name = self.get_ext_filename(fullname) filename = ext._file_name = self.get_ext_filename(fullname)
libdir = os.path.dirname(os.path.join(self.build_lib,filename)) libdir = os.path.dirname(os.path.join(self.build_lib, filename))
if ltd and libdir not in ext.library_dirs: if ltd and libdir not in ext.library_dirs:
ext.library_dirs.append(libdir) ext.library_dirs.append(libdir)
if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs: if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
...@@ -134,7 +142,8 @@ class build_ext(_build_ext): ...@@ -134,7 +142,8 @@ class build_ext(_build_ext):
tmp = _CONFIG_VARS.copy() tmp = _CONFIG_VARS.copy()
try: try:
# XXX Help! I don't have any idea whether these are right... # XXX Help! I don't have any idea whether these are right...
_CONFIG_VARS['LDSHARED'] = "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup" _CONFIG_VARS['LDSHARED'] = (
"gcc -Wl,-x -dynamiclib -undefined dynamic_lookup")
_CONFIG_VARS['CCSHARED'] = " -dynamiclib" _CONFIG_VARS['CCSHARED'] = " -dynamiclib"
_CONFIG_VARS['SO'] = ".dylib" _CONFIG_VARS['SO'] = ".dylib"
customize_compiler(compiler) customize_compiler(compiler)
...@@ -148,7 +157,7 @@ class build_ext(_build_ext): ...@@ -148,7 +157,7 @@ class build_ext(_build_ext):
compiler.set_include_dirs(self.include_dirs) compiler.set_include_dirs(self.include_dirs)
if self.define is not None: if self.define is not None:
# 'define' option is a list of (name,value) tuples # 'define' option is a list of (name,value) tuples
for (name,value) in self.define: for (name, value) in self.define:
compiler.define_macro(name, value) compiler.define_macro(name, value)
if self.undef is not None: if self.undef is not None:
for macro in self.undef: for macro in self.undef:
...@@ -166,16 +175,16 @@ class build_ext(_build_ext): ...@@ -166,16 +175,16 @@ class build_ext(_build_ext):
compiler.link_shared_object = link_shared_object.__get__(compiler) compiler.link_shared_object = link_shared_object.__get__(compiler)
def get_export_symbols(self, ext): def get_export_symbols(self, ext):
if isinstance(ext,Library): if isinstance(ext, Library):
return ext.export_symbols return ext.export_symbols
return _build_ext.get_export_symbols(self,ext) return _build_ext.get_export_symbols(self, ext)
def build_extension(self, ext): def build_extension(self, ext):
_compiler = self.compiler _compiler = self.compiler
try: try:
if isinstance(ext,Library): if isinstance(ext, Library):
self.compiler = self.shlib_compiler self.compiler = self.shlib_compiler
_build_ext.build_extension(self,ext) _build_ext.build_extension(self, ext)
if ext._needs_stub: if ext._needs_stub:
self.write_stub( self.write_stub(
self.get_finalized_command('build_py').build_lib, ext self.get_finalized_command('build_py').build_lib, ext
...@@ -189,9 +198,10 @@ class build_ext(_build_ext): ...@@ -189,9 +198,10 @@ class build_ext(_build_ext):
# XXX as dynamic, and not just using a locally-found version or a # XXX as dynamic, and not just using a locally-found version or a
# XXX static-compiled version # XXX static-compiled version
libnames = dict.fromkeys([lib._full_name for lib in self.shlibs]) libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])
pkg = '.'.join(ext._full_name.split('.')[:-1]+['']) pkg = '.'.join(ext._full_name.split('.')[:-1] + [''])
for libname in ext.libraries: for libname in ext.libraries:
if pkg+libname in libnames: return True if pkg + libname in libnames:
return True
return False return False
def get_outputs(self): def get_outputs(self):
...@@ -200,26 +210,29 @@ class build_ext(_build_ext): ...@@ -200,26 +210,29 @@ class build_ext(_build_ext):
for ext in self.extensions: for ext in self.extensions:
if ext._needs_stub: if ext._needs_stub:
base = os.path.join(self.build_lib, *ext._full_name.split('.')) base = os.path.join(self.build_lib, *ext._full_name.split('.'))
outputs.append(base+'.py') outputs.append(base + '.py')
outputs.append(base+'.pyc') outputs.append(base + '.pyc')
if optimize: if optimize:
outputs.append(base+'.pyo') outputs.append(base + '.pyo')
return outputs return outputs
def write_stub(self, output_dir, ext, compile=False): def write_stub(self, output_dir, ext, compile=False):
log.info("writing stub loader for %s to %s",ext._full_name, output_dir) log.info("writing stub loader for %s to %s", ext._full_name,
stub_file = os.path.join(output_dir, *ext._full_name.split('.'))+'.py' output_dir)
stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) +
'.py')
if compile and os.path.exists(stub_file): if compile and os.path.exists(stub_file):
raise DistutilsError(stub_file+" already exists! Please delete.") raise DistutilsError(stub_file + " already exists! Please delete.")
if not self.dry_run: if not self.dry_run:
f = open(stub_file,'w') f = open(stub_file, 'w')
f.write( f.write(
'\n'.join([ '\n'.join([
"def __bootstrap__():", "def __bootstrap__():",
" global __bootstrap__, __file__, __loader__", " global __bootstrap__, __file__, __loader__",
" import sys, os, pkg_resources, imp"+if_dl(", dl"), " import sys, os, pkg_resources, imp" + if_dl(", dl"),
" __file__ = pkg_resources.resource_filename(__name__,%r)" " __file__ = pkg_resources.resource_filename"
% os.path.basename(ext._file_name), "(__name__,%r)"
% os.path.basename(ext._file_name),
" del __bootstrap__", " del __bootstrap__",
" if '__loader__' in globals():", " if '__loader__' in globals():",
" del __loader__", " del __loader__",
...@@ -233,12 +246,13 @@ class build_ext(_build_ext): ...@@ -233,12 +246,13 @@ class build_ext(_build_ext):
if_dl(" sys.setdlopenflags(old_flags)"), if_dl(" sys.setdlopenflags(old_flags)"),
" os.chdir(old_dir)", " os.chdir(old_dir)",
"__bootstrap__()", "__bootstrap__()",
"" # terminal \n "" # terminal \n
]) ])
) )
f.close() f.close()
if compile: if compile:
from distutils.util import byte_compile from distutils.util import byte_compile
byte_compile([stub_file], optimize=0, byte_compile([stub_file], optimize=0,
force=True, dry_run=self.dry_run) force=True, dry_run=self.dry_run)
optimize = self.get_finalized_command('install_lib').optimize optimize = self.get_finalized_command('install_lib').optimize
...@@ -249,13 +263,14 @@ class build_ext(_build_ext): ...@@ -249,13 +263,14 @@ class build_ext(_build_ext):
os.unlink(stub_file) os.unlink(stub_file)
if use_stubs or os.name=='nt': if use_stubs or os.name == 'nt':
# Build shared libraries # Build shared libraries
# #
def link_shared_object(self, objects, output_libname, output_dir=None, def link_shared_object(
libraries=None, library_dirs=None, runtime_library_dirs=None, self, objects, output_libname, output_dir=None, libraries=None,
export_symbols=None, debug=0, extra_preargs=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None,
extra_postargs=None, build_temp=None, target_lang=None): debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
target_lang=None):
self.link( self.link(
self.SHARED_LIBRARY, objects, output_libname, self.SHARED_LIBRARY, objects, output_libname,
output_dir, libraries, library_dirs, runtime_library_dirs, output_dir, libraries, library_dirs, runtime_library_dirs,
...@@ -266,18 +281,19 @@ else: ...@@ -266,18 +281,19 @@ else:
# Build static libraries everywhere else # Build static libraries everywhere else
libtype = 'static' libtype = 'static'
def link_shared_object(self, objects, output_libname, output_dir=None, def link_shared_object(
libraries=None, library_dirs=None, runtime_library_dirs=None, self, objects, output_libname, output_dir=None, libraries=None,
export_symbols=None, debug=0, extra_preargs=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None,
extra_postargs=None, build_temp=None, target_lang=None): debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
target_lang=None):
# XXX we need to either disallow these attrs on Library instances, # XXX we need to either disallow these attrs on Library instances,
# or warn/abort here if set, or something... # or warn/abort here if set, or something...
#libraries=None, library_dirs=None, runtime_library_dirs=None, # libraries=None, library_dirs=None, runtime_library_dirs=None,
#export_symbols=None, extra_preargs=None, extra_postargs=None, # export_symbols=None, extra_preargs=None, extra_postargs=None,
#build_temp=None # build_temp=None
assert output_dir is None # distutils build_ext doesn't pass this assert output_dir is None # distutils build_ext doesn't pass this
output_dir,filename = os.path.split(output_libname) output_dir, filename = os.path.split(output_libname)
basename, ext = os.path.splitext(filename) basename, ext = os.path.splitext(filename)
if self.library_filename("x").startswith('lib'): if self.library_filename("x").startswith('lib'):
# strip 'lib' prefix; this is kludgy if some platform uses # strip 'lib' prefix; this is kludgy if some platform uses
......
from glob import glob
from distutils.util import convert_path
import distutils.command.build_py as orig
import os import os
import sys import sys
import fnmatch import fnmatch
import textwrap import textwrap
import distutils.command.build_py as orig
from distutils.util import convert_path
from glob import glob
try: try:
from setuptools.lib2to3_ex import Mixin2to3 from setuptools.lib2to3_ex import Mixin2to3
...@@ -13,6 +13,7 @@ except ImportError: ...@@ -13,6 +13,7 @@ except ImportError:
def run_2to3(self, files, doctests=True): def run_2to3(self, files, doctests=True):
"do nothing" "do nothing"
class build_py(orig.build_py, Mixin2to3): class build_py(orig.build_py, Mixin2to3):
"""Enhanced 'build_py' command that includes data files with packages """Enhanced 'build_py' command that includes data files with packages
...@@ -22,11 +23,14 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -22,11 +23,14 @@ class build_py(orig.build_py, Mixin2to3):
Also, this version of the 'build_py' command allows you to specify both Also, this version of the 'build_py' command allows you to specify both
'py_modules' and 'packages' in the same setup operation. 'py_modules' and 'packages' in the same setup operation.
""" """
def finalize_options(self): def finalize_options(self):
orig.build_py.finalize_options(self) orig.build_py.finalize_options(self)
self.package_data = self.distribution.package_data self.package_data = self.distribution.package_data
self.exclude_package_data = self.distribution.exclude_package_data or {} self.exclude_package_data = (self.distribution.exclude_package_data or
if 'data_files' in self.__dict__: del self.__dict__['data_files'] {})
if 'data_files' in self.__dict__:
del self.__dict__['data_files']
self.__updated_files = [] self.__updated_files = []
self.__doctests_2to3 = [] self.__doctests_2to3 = []
...@@ -51,13 +55,14 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -51,13 +55,14 @@ class build_py(orig.build_py, Mixin2to3):
self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0)) self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0))
def __getattr__(self, attr): def __getattr__(self, attr):
if attr=='data_files': # lazily compute data files if attr == 'data_files': # lazily compute data files
self.data_files = files = self._get_data_files() self.data_files = files = self._get_data_files()
return files return files
return orig.build_py.__getattr__(self,attr) return orig.build_py.__getattr__(self, attr)
def build_module(self, module, module_file, package): def build_module(self, module, module_file, package):
outfile, copied = orig.build_py.build_module(self, module, module_file, package) outfile, copied = orig.build_py.build_module(self, module, module_file,
package)
if copied: if copied:
self.__updated_files.append(outfile) self.__updated_files.append(outfile)
return outfile, copied return outfile, copied
...@@ -74,12 +79,12 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -74,12 +79,12 @@ class build_py(orig.build_py, Mixin2to3):
build_dir = os.path.join(*([self.build_lib] + package.split('.'))) build_dir = os.path.join(*([self.build_lib] + package.split('.')))
# Length of path to strip from found files # Length of path to strip from found files
plen = len(src_dir)+1 plen = len(src_dir) + 1
# Strip directory from globbed filenames # Strip directory from globbed filenames
filenames = [ filenames = [
file[plen:] for file in self.find_data_files(package, src_dir) file[plen:] for file in self.find_data_files(package, src_dir)
] ]
data.append((package, src_dir, build_dir, filenames)) data.append((package, src_dir, build_dir, filenames))
return data return data
...@@ -102,7 +107,8 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -102,7 +107,8 @@ class build_py(orig.build_py, Mixin2to3):
srcfile = os.path.join(src_dir, filename) srcfile = os.path.join(src_dir, filename)
outf, copied = self.copy_file(srcfile, target) outf, copied = self.copy_file(srcfile, target)
srcfile = os.path.abspath(srcfile) srcfile = os.path.abspath(srcfile)
if copied and srcfile in self.distribution.convert_2to3_doctests: if (copied and
srcfile in self.distribution.convert_2to3_doctests):
self.__doctests_2to3.append(outf) self.__doctests_2to3.append(outf)
def analyze_manifest(self): def analyze_manifest(self):
...@@ -117,21 +123,22 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -117,21 +123,22 @@ class build_py(orig.build_py, Mixin2to3):
self.run_command('egg_info') self.run_command('egg_info')
ei_cmd = self.get_finalized_command('egg_info') ei_cmd = self.get_finalized_command('egg_info')
for path in ei_cmd.filelist.files: for path in ei_cmd.filelist.files:
d,f = os.path.split(assert_relative(path)) d, f = os.path.split(assert_relative(path))
prev = None prev = None
oldf = f oldf = f
while d and d!=prev and d not in src_dirs: while d and d != prev and d not in src_dirs:
prev = d prev = d
d, df = os.path.split(d) d, df = os.path.split(d)
f = os.path.join(df, f) f = os.path.join(df, f)
if d in src_dirs: if d in src_dirs:
if path.endswith('.py') and f==oldf: if path.endswith('.py') and f == oldf:
continue # it's a module, not data continue # it's a module, not data
mf.setdefault(src_dirs[d],[]).append(path) mf.setdefault(src_dirs[d], []).append(path)
def get_data_files(self): pass # kludge 2.4 for lazy computation def get_data_files(self):
pass # kludge 2.4 for lazy computation
if sys.version<"2.4": # Python 2.4 already has this code if sys.version < "2.4": # Python 2.4 already has this code
def get_outputs(self, include_bytecode=1): def get_outputs(self, include_bytecode=1):
"""Return complete list of files copied to the build directory """Return complete list of files copied to the build directory
...@@ -142,9 +149,9 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -142,9 +149,9 @@ class build_py(orig.build_py, Mixin2to3):
""" """
return orig.build_py.get_outputs(self, include_bytecode) + [ return orig.build_py.get_outputs(self, include_bytecode) + [
os.path.join(build_dir, filename) os.path.join(build_dir, filename)
for package, src_dir, build_dir,filenames in self.data_files for package, src_dir, build_dir, filenames in self.data_files
for filename in filenames for filename in filenames
] ]
def check_package(self, package, package_dir): def check_package(self, package, package_dir):
"""Check namespace packages' __init__ for declare_namespace""" """Check namespace packages' __init__ for declare_namespace"""
...@@ -160,25 +167,26 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -160,25 +167,26 @@ class build_py(orig.build_py, Mixin2to3):
return init_py return init_py
for pkg in self.distribution.namespace_packages: for pkg in self.distribution.namespace_packages:
if pkg==package or pkg.startswith(package+'.'): if pkg == package or pkg.startswith(package + '.'):
break break
else: else:
return init_py return init_py
f = open(init_py,'rbU') f = open(init_py, 'rbU')
if 'declare_namespace'.encode() not in f.read(): if 'declare_namespace'.encode() not in f.read():
from distutils.errors import DistutilsError from distutils.errors import DistutilsError
raise DistutilsError( raise DistutilsError(
"Namespace package problem: %s is a namespace package, but its\n" "Namespace package problem: %s is a namespace package, but "
"__init__.py does not call declare_namespace()! Please fix it.\n" "its\n__init__.py does not call declare_namespace()! Please "
'(See the setuptools manual under "Namespace Packages" for ' 'fix it.\n(See the setuptools manual under '
"details.)\n" % (package,) '"Namespace Packages" for details.)\n"' % (package,)
) )
f.close() f.close()
return init_py return init_py
def initialize_options(self): def initialize_options(self):
self.packages_checked={} self.packages_checked = {}
orig.build_py.initialize_options(self) orig.build_py.initialize_options(self)
def get_package_dir(self, package): def get_package_dir(self, package):
...@@ -202,7 +210,7 @@ class build_py(orig.build_py, Mixin2to3): ...@@ -202,7 +210,7 @@ class build_py(orig.build_py, Mixin2to3):
seen = {} seen = {}
return [ return [
f for f in files if f not in bad f for f in files if f not in bad
and f not in seen and seen.setdefault(f,1) # ditch dupes and f not in seen and seen.setdefault(f, 1) # ditch dupes
] ]
...@@ -210,6 +218,7 @@ def assert_relative(path): ...@@ -210,6 +218,7 @@ def assert_relative(path):
if not os.path.isabs(path): if not os.path.isabs(path):
return path return path
from distutils.errors import DistutilsSetupError from distutils.errors import DistutilsSetupError
msg = textwrap.dedent(""" msg = textwrap.dedent("""
Error: setup script specifies an absolute path: Error: setup script specifies an absolute path:
......
import os
import glob
from distutils.util import convert_path from distutils.util import convert_path
from distutils import log from distutils import log
from distutils.errors import DistutilsError, DistutilsOptionError from distutils.errors import DistutilsError, DistutilsOptionError
import os
import glob
import setuptools
from pkg_resources import Distribution, PathMetadata, normalize_path from pkg_resources import Distribution, PathMetadata, normalize_path
from setuptools.command.easy_install import easy_install from setuptools.command.easy_install import easy_install
from setuptools.compat import PY3 from setuptools.compat import PY3
import setuptools
class develop(easy_install): class develop(easy_install):
"""Set up package for development""" """Set up package for development"""
...@@ -36,7 +37,7 @@ class develop(easy_install): ...@@ -36,7 +37,7 @@ class develop(easy_install):
self.egg_path = None self.egg_path = None
easy_install.initialize_options(self) easy_install.initialize_options(self)
self.setup_path = None self.setup_path = None
self.always_copy_from = '.' # always copy eggs installed in curdir self.always_copy_from = '.' # always copy eggs installed in curdir
def finalize_options(self): def finalize_options(self):
ei = self.get_finalized_command("egg_info") ei = self.get_finalized_command("egg_info")
...@@ -52,29 +53,31 @@ class develop(easy_install): ...@@ -52,29 +53,31 @@ class develop(easy_install):
# pick up setup-dir .egg files only: no .egg-info # pick up setup-dir .egg files only: no .egg-info
self.package_index.scan(glob.glob('*.egg')) self.package_index.scan(glob.glob('*.egg'))
self.egg_link = os.path.join(self.install_dir, ei.egg_name+'.egg-link') self.egg_link = os.path.join(self.install_dir, ei.egg_name +
'.egg-link')
self.egg_base = ei.egg_base self.egg_base = ei.egg_base
if self.egg_path is None: if self.egg_path is None:
self.egg_path = os.path.abspath(ei.egg_base) self.egg_path = os.path.abspath(ei.egg_base)
target = normalize_path(self.egg_base) target = normalize_path(self.egg_base)
egg_path = normalize_path(os.path.join(self.install_dir, self.egg_path)) egg_path = normalize_path(os.path.join(self.install_dir,
self.egg_path))
if egg_path != target: if egg_path != target:
raise DistutilsOptionError( raise DistutilsOptionError(
"--egg-path must be a relative path from the install" "--egg-path must be a relative path from the install"
" directory to "+target " directory to " + target
) )
# Make a distribution for the package's source # Make a distribution for the package's source
self.dist = Distribution( self.dist = Distribution(
target, target,
PathMetadata(target, os.path.abspath(ei.egg_info)), PathMetadata(target, os.path.abspath(ei.egg_info)),
project_name = ei.egg_name project_name=ei.egg_name
) )
p = self.egg_base.replace(os.sep,'/') p = self.egg_base.replace(os.sep, '/')
if p!= os.curdir: if p != os.curdir:
p = '../' * (p.count('/')+1) p = '../' * (p.count('/') + 1)
self.setup_path = p self.setup_path = p
p = normalize_path(os.path.join(self.install_dir, self.egg_path, p)) p = normalize_path(os.path.join(self.install_dir, self.egg_path, p))
if p != normalize_path(os.curdir): if p != normalize_path(os.curdir):
...@@ -103,7 +106,8 @@ class develop(easy_install): ...@@ -103,7 +106,8 @@ class develop(easy_install):
ei_cmd = self.get_finalized_command("egg_info") ei_cmd = self.get_finalized_command("egg_info")
self.egg_path = build_path self.egg_path = build_path
self.dist.location = build_path self.dist.location = build_path
self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info) # XXX # XXX
self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info)
else: else:
# Without 2to3 inplace works fine: # Without 2to3 inplace works fine:
self.run_command('egg_info') self.run_command('egg_info')
...@@ -120,7 +124,7 @@ class develop(easy_install): ...@@ -120,7 +124,7 @@ class develop(easy_install):
# create an .egg-link in the installation dir, pointing to our egg # create an .egg-link in the installation dir, pointing to our egg
log.info("Creating %s (link to %s)", self.egg_link, self.egg_base) log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
if not self.dry_run: if not self.dry_run:
f = open(self.egg_link,"w") f = open(self.egg_link, "w")
f.write(self.egg_path + "\n" + self.setup_path) f.write(self.egg_path + "\n" + self.setup_path)
f.close() f.close()
# postprocess the installed distro, fixing up .pth, installing scripts, # postprocess the installed distro, fixing up .pth, installing scripts,
...@@ -133,7 +137,8 @@ class develop(easy_install): ...@@ -133,7 +137,8 @@ class develop(easy_install):
egg_link_file = open(self.egg_link) egg_link_file = open(self.egg_link)
contents = [line.rstrip() for line in egg_link_file] contents = [line.rstrip() for line in egg_link_file]
egg_link_file.close() egg_link_file.close()
if contents not in ([self.egg_path], [self.egg_path, self.setup_path]): if contents not in ([self.egg_path],
[self.egg_path, self.setup_path]):
log.warn("Link points to %s: uninstall aborted", contents) log.warn("Link points to %s: uninstall aborted", contents)
return return
if not self.dry_run: if not self.dry_run:
...@@ -147,7 +152,7 @@ class develop(easy_install): ...@@ -147,7 +152,7 @@ class develop(easy_install):
def install_egg_scripts(self, dist): def install_egg_scripts(self, dist):
if dist is not self.dist: if dist is not self.dist:
# Installing a dependency, so fall back to normal behavior # Installing a dependency, so fall back to normal behavior
return easy_install.install_egg_scripts(self,dist) return easy_install.install_egg_scripts(self, dist)
# create wrapper scripts in the script dir, pointing to dist.scripts # create wrapper scripts in the script dir, pointing to dist.scripts
...@@ -158,7 +163,7 @@ class develop(easy_install): ...@@ -158,7 +163,7 @@ class develop(easy_install):
for script_name in self.distribution.scripts or []: for script_name in self.distribution.scripts or []:
script_path = os.path.abspath(convert_path(script_name)) script_path = os.path.abspath(convert_path(script_name))
script_name = os.path.basename(script_path) script_name = os.path.basename(script_path)
f = open(script_path,'rU') f = open(script_path, 'rU')
script_text = f.read() script_text = f.read()
f.close() f.close()
self.install_script(dist, script_name, script_text, script_path) self.install_script(dist, script_name, script_text, script_path)
...@@ -12,6 +12,14 @@ __ https://pythonhosted.org/setuptools/easy_install.html ...@@ -12,6 +12,14 @@ __ https://pythonhosted.org/setuptools/easy_install.html
""" """
from glob import glob
from distutils.util import get_platform
from distutils.util import convert_path, subst_vars
from distutils.errors import DistutilsArgError, DistutilsOptionError, \
DistutilsError, DistutilsPlatformError
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
from distutils import log, dir_util
from distutils.command.build_scripts import first_line_re
import sys import sys
import os import os
import zipimport import zipimport
...@@ -26,21 +34,10 @@ import textwrap ...@@ -26,21 +34,10 @@ import textwrap
import warnings import warnings
import site import site
import struct import struct
from glob import glob
from distutils import log, dir_util
from distutils.command.build_scripts import first_line_re
import pkg_resources
from setuptools import Command, _dont_write_bytecode from setuptools import Command, _dont_write_bytecode
from setuptools.sandbox import run_setup from setuptools.sandbox import run_setup
from setuptools.py31compat import get_path, get_config_vars from setuptools.py31compat import get_path, get_config_vars
from distutils.util import get_platform
from distutils.util import convert_path, subst_vars
from distutils.errors import DistutilsArgError, DistutilsOptionError, \
DistutilsError, DistutilsPlatformError
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
from setuptools.command import setopt from setuptools.command import setopt
from setuptools.archive_util import unpack_archive from setuptools.archive_util import unpack_archive
from setuptools.package_index import PackageIndex from setuptools.package_index import PackageIndex
...@@ -54,18 +51,22 @@ from pkg_resources import ( ...@@ -54,18 +51,22 @@ from pkg_resources import (
Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound, Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound,
VersionConflict, DEVELOP_DIST, VersionConflict, DEVELOP_DIST,
) )
import pkg_resources
sys_executable = os.environ.get('__PYVENV_LAUNCHER__', sys_executable = os.environ.get('__PYVENV_LAUNCHER__',
os.path.normpath(sys.executable)) os.path.normpath(sys.executable))
__all__ = [ __all__ = [
'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
'main', 'get_exe_prefixes', 'main', 'get_exe_prefixes',
] ]
def is_64bit(): def is_64bit():
return struct.calcsize("P") == 8 return struct.calcsize("P") == 8
def samefile(p1, p2): def samefile(p1, p2):
both_exist = os.path.exists(p1) and os.path.exists(p2) both_exist = os.path.exists(p1) and os.path.exists(p2)
use_samefile = hasattr(os.path, 'samefile') and both_exist use_samefile = hasattr(os.path, 'samefile') and both_exist
...@@ -75,9 +76,11 @@ def samefile(p1, p2): ...@@ -75,9 +76,11 @@ def samefile(p1, p2):
norm_p2 = os.path.normpath(os.path.normcase(p2)) norm_p2 = os.path.normpath(os.path.normcase(p2))
return norm_p1 == norm_p2 return norm_p1 == norm_p2
if PY2: if PY2:
def _to_ascii(s): def _to_ascii(s):
return s return s
def isascii(s): def isascii(s):
try: try:
unicode(s, 'ascii') unicode(s, 'ascii')
...@@ -87,6 +90,7 @@ if PY2: ...@@ -87,6 +90,7 @@ if PY2:
else: else:
def _to_ascii(s): def _to_ascii(s):
return s.encode('ascii') return s.encode('ascii')
def isascii(s): def isascii(s):
try: try:
s.encode('ascii') s.encode('ascii')
...@@ -94,6 +98,7 @@ else: ...@@ -94,6 +98,7 @@ else:
except UnicodeError: except UnicodeError:
return False return False
class easy_install(Command): class easy_install(Command):
"""Manage a download/build/install process""" """Manage a download/build/install process"""
description = "Find/get/install Python packages" description = "Find/get/install Python packages"
...@@ -111,22 +116,22 @@ class easy_install(Command): ...@@ -111,22 +116,22 @@ class easy_install(Command):
("index-url=", "i", "base URL of Python Package Index"), ("index-url=", "i", "base URL of Python Package Index"),
("find-links=", "f", "additional URL(s) to search for packages"), ("find-links=", "f", "additional URL(s) to search for packages"),
("build-directory=", "b", ("build-directory=", "b",
"download/extract/build in DIR; keep the results"), "download/extract/build in DIR; keep the results"),
('optimize=', 'O', ('optimize=', 'O',
"also compile with optimization: -O1 for \"python -O\", " "also compile with optimization: -O1 for \"python -O\", "
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
('record=', None, ('record=', None,
"filename in which to record list of installed files"), "filename in which to record list of installed files"),
('always-unzip', 'Z', "don't install as a zipfile, no matter what"), ('always-unzip', 'Z', "don't install as a zipfile, no matter what"),
('site-dirs=','S',"list of directories where .pth files work"), ('site-dirs=', 'S', "list of directories where .pth files work"),
('editable', 'e', "Install specified packages in editable form"), ('editable', 'e', "Install specified packages in editable form"),
('no-deps', 'N', "don't install dependencies"), ('no-deps', 'N', "don't install dependencies"),
('allow-hosts=', 'H', "pattern(s) that hostnames must match"), ('allow-hosts=', 'H', "pattern(s) that hostnames must match"),
('local-snapshots-ok', 'l', ('local-snapshots-ok', 'l',
"allow building eggs from local checkouts"), "allow building eggs from local checkouts"),
('version', None, "print version information and exit"), ('version', None, "print version information and exit"),
('no-find-links', None, ('no-find-links', None,
"Don't load find-links defined in packages being installed") "Don't load find-links defined in packages being installed")
] ]
boolean_options = [ boolean_options = [
'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy',
...@@ -160,10 +165,10 @@ class easy_install(Command): ...@@ -160,10 +165,10 @@ class easy_install(Command):
self.editable = self.no_deps = self.allow_hosts = None self.editable = self.no_deps = self.allow_hosts = None
self.root = self.prefix = self.no_report = None self.root = self.prefix = self.no_report = None
self.version = None self.version = None
self.install_purelib = None # for pure module distributions self.install_purelib = None # for pure module distributions
self.install_platlib = None # non-pure (dists w/ extensions) self.install_platlib = None # non-pure (dists w/ extensions)
self.install_headers = None # for C/C++ headers self.install_headers = None # for C/C++ headers
self.install_lib = None # set to either purelib or platlib self.install_lib = None # set to either purelib or platlib
self.install_scripts = None self.install_scripts = None
self.install_data = None self.install_data = None
self.install_base = None self.install_base = None
...@@ -198,7 +203,8 @@ class easy_install(Command): ...@@ -198,7 +203,8 @@ class easy_install(Command):
if os.path.exists(filename) or os.path.islink(filename): if os.path.exists(filename) or os.path.islink(filename):
log.info("Deleting %s", filename) log.info("Deleting %s", filename)
if not self.dry_run: if not self.dry_run:
if os.path.isdir(filename) and not os.path.islink(filename): if (os.path.isdir(filename) and
not os.path.islink(filename)):
rmtree(filename) rmtree(filename)
else: else:
os.unlink(filename) os.unlink(filename)
...@@ -231,7 +237,7 @@ class easy_install(Command): ...@@ -231,7 +237,7 @@ class easy_install(Command):
self.config_vars['usersite'] = self.install_usersite self.config_vars['usersite'] = self.install_usersite
# fix the install_dir if "--user" was used # fix the install_dir if "--user" was used
#XXX: duplicate of the code in the setup command # XXX: duplicate of the code in the setup command
if self.user and site.ENABLE_USER_SITE: if self.user and site.ENABLE_USER_SITE:
self.create_home_path() self.create_home_path()
if self.install_userbase is None: if self.install_userbase is None:
...@@ -246,7 +252,8 @@ class easy_install(Command): ...@@ -246,7 +252,8 @@ class easy_install(Command):
self.expand_basedirs() self.expand_basedirs()
self.expand_dirs() self.expand_dirs()
self._expand('install_dir','script_dir','build_directory','site_dirs') self._expand('install_dir', 'script_dir', 'build_directory',
'site_dirs')
# If a non-default installation directory was specified, default the # If a non-default installation directory was specified, default the
# script directory to match it. # script directory to match it.
if self.script_dir is None: if self.script_dir is None:
...@@ -258,12 +265,12 @@ class easy_install(Command): ...@@ -258,12 +265,12 @@ class easy_install(Command):
# Let install_dir get set by install_lib command, which in turn # Let install_dir get set by install_lib command, which in turn
# gets its info from the install command, and takes into account # gets its info from the install command, and takes into account
# --prefix and --home and all that other crud. # --prefix and --home and all that other crud.
self.set_undefined_options('install_lib', self.set_undefined_options(
('install_dir','install_dir') 'install_lib', ('install_dir', 'install_dir')
) )
# Likewise, set default script_dir from 'install_scripts.install_dir' # Likewise, set default script_dir from 'install_scripts.install_dir'
self.set_undefined_options('install_scripts', self.set_undefined_options(
('install_dir', 'script_dir') 'install_scripts', ('install_dir', 'script_dir')
) )
if self.user and self.install_purelib: if self.user and self.install_purelib:
...@@ -277,18 +284,20 @@ class easy_install(Command): ...@@ -277,18 +284,20 @@ class easy_install(Command):
self.all_site_dirs = get_site_dirs() self.all_site_dirs = get_site_dirs()
if self.site_dirs is not None: if self.site_dirs is not None:
site_dirs = [ site_dirs = [
os.path.expanduser(s.strip()) for s in self.site_dirs.split(',') os.path.expanduser(s.strip()) for s in
self.site_dirs.split(',')
] ]
for d in site_dirs: for d in site_dirs:
if not os.path.isdir(d): if not os.path.isdir(d):
log.warn("%s (in --site-dirs) does not exist", d) log.warn("%s (in --site-dirs) does not exist", d)
elif normalize_path(d) not in normpath: elif normalize_path(d) not in normpath:
raise DistutilsOptionError( raise DistutilsOptionError(
d+" (in --site-dirs) is not on sys.path" d + " (in --site-dirs) is not on sys.path"
) )
else: else:
self.all_site_dirs.append(normalize_path(d)) self.all_site_dirs.append(normalize_path(d))
if not self.editable: self.check_site_dir() if not self.editable:
self.check_site_dir()
self.index_url = self.index_url or "https://pypi.python.org/simple" self.index_url = self.index_url or "https://pypi.python.org/simple"
self.shadow_path = self.all_site_dirs[:] self.shadow_path = self.all_site_dirs[:]
for path_item in self.install_dir, normalize_path(self.script_dir): for path_item in self.install_dir, normalize_path(self.script_dir):
...@@ -301,9 +310,9 @@ class easy_install(Command): ...@@ -301,9 +310,9 @@ class easy_install(Command):
hosts = ['*'] hosts = ['*']
if self.package_index is None: if self.package_index is None:
self.package_index = self.create_index( self.package_index = self.create_index(
self.index_url, search_path = self.shadow_path, hosts=hosts, self.index_url, search_path=self.shadow_path, hosts=hosts,
) )
self.local_index = Environment(self.shadow_path+sys.path) self.local_index = Environment(self.shadow_path + sys.path)
if self.find_links is not None: if self.find_links is not None:
if isinstance(self.find_links, basestring): if isinstance(self.find_links, basestring):
...@@ -311,14 +320,15 @@ class easy_install(Command): ...@@ -311,14 +320,15 @@ class easy_install(Command):
else: else:
self.find_links = [] self.find_links = []
if self.local_snapshots_ok: if self.local_snapshots_ok:
self.package_index.scan_egg_links(self.shadow_path+sys.path) self.package_index.scan_egg_links(self.shadow_path + sys.path)
if not self.no_find_links: if not self.no_find_links:
self.package_index.add_find_links(self.find_links) self.package_index.add_find_links(self.find_links)
self.set_undefined_options('install_lib', ('optimize','optimize')) self.set_undefined_options('install_lib', ('optimize', 'optimize'))
if not isinstance(self.optimize,int): if not isinstance(self.optimize, int):
try: try:
self.optimize = int(self.optimize) self.optimize = int(self.optimize)
if not (0 <= self.optimize <= 2): raise ValueError if not (0 <= self.optimize <= 2):
raise ValueError
except ValueError: except ValueError:
raise DistutilsOptionError("--optimize must be 0, 1, or 2") raise DistutilsOptionError("--optimize must be 0, 1, or 2")
...@@ -350,7 +360,7 @@ class easy_install(Command): ...@@ -350,7 +360,7 @@ class easy_install(Command):
"""Calls `os.path.expanduser` on install dirs.""" """Calls `os.path.expanduser` on install dirs."""
self._expand_attrs(['install_purelib', 'install_platlib', self._expand_attrs(['install_purelib', 'install_platlib',
'install_lib', 'install_headers', 'install_lib', 'install_headers',
'install_scripts', 'install_data',]) 'install_scripts', 'install_data', ])
def run(self): def run(self):
if self.verbose != self.distribution.verbose: if self.verbose != self.distribution.verbose:
...@@ -360,11 +370,12 @@ class easy_install(Command): ...@@ -360,11 +370,12 @@ class easy_install(Command):
self.easy_install(spec, not self.no_deps) self.easy_install(spec, not self.no_deps)
if self.record: if self.record:
outputs = self.outputs outputs = self.outputs
if self.root: # strip any package prefix if self.root: # strip any package prefix
root_len = len(self.root) root_len = len(self.root)
for counter in range(len(outputs)): for counter in range(len(outputs)):
outputs[counter] = outputs[counter][root_len:] outputs[counter] = outputs[counter][root_len:]
from distutils import file_util from distutils import file_util
self.execute( self.execute(
file_util.write_file, (self.record, outputs), file_util.write_file, (self.record, outputs),
"writing list of installed files to '%s'" % "writing list of installed files to '%s'" %
...@@ -392,7 +403,7 @@ class easy_install(Command): ...@@ -392,7 +403,7 @@ class easy_install(Command):
"""Verify that self.install_dir is .pth-capable dir, if needed""" """Verify that self.install_dir is .pth-capable dir, if needed"""
instdir = normalize_path(self.install_dir) instdir = normalize_path(self.install_dir)
pth_file = os.path.join(instdir,'easy-install.pth') pth_file = os.path.join(instdir, 'easy-install.pth')
# Is it a configured, PYTHONPATH, implicit, or explicit site dir? # Is it a configured, PYTHONPATH, implicit, or explicit site dir?
is_site_dir = instdir in self.all_site_dirs is_site_dir = instdir in self.all_site_dirs
...@@ -402,13 +413,14 @@ class easy_install(Command): ...@@ -402,13 +413,14 @@ class easy_install(Command):
is_site_dir = self.check_pth_processing() is_site_dir = self.check_pth_processing()
else: else:
# make sure we can write to target dir # make sure we can write to target dir
testfile = self.pseudo_tempname()+'.write-test' testfile = self.pseudo_tempname() + '.write-test'
test_exists = os.path.exists(testfile) test_exists = os.path.exists(testfile)
try: try:
if test_exists: os.unlink(testfile) if test_exists:
open(testfile,'w').close() os.unlink(testfile)
open(testfile, 'w').close()
os.unlink(testfile) os.unlink(testfile)
except (OSError,IOError): except (OSError, IOError):
self.cant_write_to_target() self.cant_write_to_target()
if not is_site_dir and not self.multi_version: if not is_site_dir and not self.multi_version:
...@@ -421,13 +433,13 @@ class easy_install(Command): ...@@ -421,13 +433,13 @@ class easy_install(Command):
else: else:
self.pth_file = None self.pth_file = None
PYTHONPATH = os.environ.get('PYTHONPATH','').split(os.pathsep) PYTHONPATH = os.environ.get('PYTHONPATH', '').split(os.pathsep)
if instdir not in map(normalize_path, [_f for _f in PYTHONPATH if _f]): if instdir not in map(normalize_path, [_f for _f in PYTHONPATH if _f]):
# only PYTHONPATH dirs need a site.py, so pretend it's there # only PYTHONPATH dirs need a site.py, so pretend it's there
self.sitepy_installed = True self.sitepy_installed = True
elif self.multi_version and not os.path.exists(pth_file): elif self.multi_version and not os.path.exists(pth_file):
self.sitepy_installed = True # don't need site.py in this case self.sitepy_installed = True # don't need site.py in this case
self.pth_file = None # and don't create a .pth file self.pth_file = None # and don't create a .pth file
self.install_dir = instdir self.install_dir = instdir
def cant_write_to_target(self): def cant_write_to_target(self):
...@@ -473,32 +485,36 @@ Please make the appropriate changes for your system and try again. ...@@ -473,32 +485,36 @@ Please make the appropriate changes for your system and try again.
"""Empirically verify whether .pth files are supported in inst. dir""" """Empirically verify whether .pth files are supported in inst. dir"""
instdir = self.install_dir instdir = self.install_dir
log.info("Checking .pth file support in %s", instdir) log.info("Checking .pth file support in %s", instdir)
pth_file = self.pseudo_tempname()+".pth" pth_file = self.pseudo_tempname() + ".pth"
ok_file = pth_file+'.ok' ok_file = pth_file + '.ok'
ok_exists = os.path.exists(ok_file) ok_exists = os.path.exists(ok_file)
try: try:
if ok_exists: os.unlink(ok_file) if ok_exists:
os.unlink(ok_file)
dirname = os.path.dirname(ok_file) dirname = os.path.dirname(ok_file)
if not os.path.exists(dirname): if not os.path.exists(dirname):
os.makedirs(dirname) os.makedirs(dirname)
f = open(pth_file,'w') f = open(pth_file, 'w')
except (OSError,IOError): except (OSError, IOError):
self.cant_write_to_target() self.cant_write_to_target()
else: else:
try: try:
f.write("import os; f = open(%r, 'w'); f.write('OK'); f.close()\n" % (ok_file,)) f.write("import os; f = open(%r, 'w'); f.write('OK'); "
"f.close()\n" % (ok_file,))
f.close() f.close()
f=None f = None
executable = sys.executable executable = sys.executable
if os.name=='nt': if os.name == 'nt':
dirname,basename = os.path.split(executable) dirname, basename = os.path.split(executable)
alt = os.path.join(dirname,'pythonw.exe') alt = os.path.join(dirname, 'pythonw.exe')
if basename.lower()=='python.exe' and os.path.exists(alt): if (basename.lower() == 'python.exe' and
os.path.exists(alt)):
# use pythonw.exe to avoid opening a console window # use pythonw.exe to avoid opening a console window
executable = alt executable = alt
from distutils.spawn import spawn from distutils.spawn import spawn
spawn([executable,'-E','-c','pass'],0)
spawn([executable, '-E', '-c', 'pass'], 0)
if os.path.exists(ok_file): if os.path.exists(ok_file):
log.info( log.info(
...@@ -527,7 +543,7 @@ Please make the appropriate changes for your system and try again. ...@@ -527,7 +543,7 @@ Please make the appropriate changes for your system and try again.
continue continue
self.install_script( self.install_script(
dist, script_name, dist, script_name,
dist.get_metadata('scripts/'+script_name) dist.get_metadata('scripts/' + script_name)
) )
self.install_wrapper_scripts(dist) self.install_wrapper_scripts(dist)
...@@ -535,7 +551,7 @@ Please make the appropriate changes for your system and try again. ...@@ -535,7 +551,7 @@ Please make the appropriate changes for your system and try again.
if os.path.isdir(path): if os.path.isdir(path):
for base, dirs, files in os.walk(path): for base, dirs, files in os.walk(path):
for filename in files: for filename in files:
self.outputs.append(os.path.join(base,filename)) self.outputs.append(os.path.join(base, filename))
else: else:
self.outputs.append(path) self.outputs.append(path)
...@@ -547,7 +563,7 @@ Please make the appropriate changes for your system and try again. ...@@ -547,7 +563,7 @@ Please make the appropriate changes for your system and try again.
% (spec,) % (spec,)
) )
def check_editable(self,spec): def check_editable(self, spec):
if not self.editable: if not self.editable:
return return
...@@ -560,15 +576,17 @@ Please make the appropriate changes for your system and try again. ...@@ -560,15 +576,17 @@ Please make the appropriate changes for your system and try again.
def easy_install(self, spec, deps=False): def easy_install(self, spec, deps=False):
tmpdir = tempfile.mkdtemp(prefix="easy_install-") tmpdir = tempfile.mkdtemp(prefix="easy_install-")
download = None download = None
if not self.editable: self.install_site_py() if not self.editable:
self.install_site_py()
try: try:
if not isinstance(spec,Requirement): if not isinstance(spec, Requirement):
if URL_SCHEME(spec): if URL_SCHEME(spec):
# It's a url, download it to tmpdir and process # It's a url, download it to tmpdir and process
self.not_editable(spec) self.not_editable(spec)
download = self.package_index.download(spec, tmpdir) download = self.package_index.download(spec, tmpdir)
return self.install_item(None, download, tmpdir, deps, True) return self.install_item(None, download, tmpdir, deps,
True)
elif os.path.exists(spec): elif os.path.exists(spec):
# Existing file or directory, just process it directly # Existing file or directory, just process it directly
...@@ -579,15 +597,15 @@ Please make the appropriate changes for your system and try again. ...@@ -579,15 +597,15 @@ Please make the appropriate changes for your system and try again.
self.check_editable(spec) self.check_editable(spec)
dist = self.package_index.fetch_distribution( dist = self.package_index.fetch_distribution(
spec, tmpdir, self.upgrade, self.editable, not self.always_copy, spec, tmpdir, self.upgrade, self.editable,
self.local_index not self.always_copy, self.local_index
) )
if dist is None: if dist is None:
msg = "Could not find suitable distribution for %r" % spec msg = "Could not find suitable distribution for %r" % spec
if self.always_copy: if self.always_copy:
msg+=" (--always-copy skips system and development eggs)" msg += " (--always-copy skips system and development eggs)"
raise DistutilsError(msg) raise DistutilsError(msg)
elif dist.precedence==DEVELOP_DIST: elif dist.precedence == DEVELOP_DIST:
# .egg-info dists don't need installing, just process deps # .egg-info dists don't need installing, just process deps
self.process_distribution(spec, dist, deps, "Using") self.process_distribution(spec, dist, deps, "Using")
return dist return dist
...@@ -614,10 +632,10 @@ Please make the appropriate changes for your system and try again. ...@@ -614,10 +632,10 @@ Please make the appropriate changes for your system and try again.
# at this point, we know it's a local .egg, we just don't know if # at this point, we know it's a local .egg, we just don't know if
# it's already installed. # it's already installed.
for dist in self.local_index[spec.project_name]: for dist in self.local_index[spec.project_name]:
if dist.location==download: if dist.location == download:
break break
else: else:
install_needed = True # it's not in the local index install_needed = True # it's not in the local index
log.info("Processing %s", os.path.basename(download)) log.info("Processing %s", os.path.basename(download))
...@@ -704,17 +722,18 @@ Please make the appropriate changes for your system and try again. ...@@ -704,17 +722,18 @@ Please make the appropriate changes for your system and try again.
def maybe_move(self, spec, dist_filename, setup_base): def maybe_move(self, spec, dist_filename, setup_base):
dst = os.path.join(self.build_directory, spec.key) dst = os.path.join(self.build_directory, spec.key)
if os.path.exists(dst): if os.path.exists(dst):
msg = "%r already exists in %s; build directory %s will not be kept" msg = ("%r already exists in %s; build directory %s will not be "
"kept")
log.warn(msg, spec.key, self.build_directory, setup_base) log.warn(msg, spec.key, self.build_directory, setup_base)
return setup_base return setup_base
if os.path.isdir(dist_filename): if os.path.isdir(dist_filename):
setup_base = dist_filename setup_base = dist_filename
else: else:
if os.path.dirname(dist_filename)==setup_base: if os.path.dirname(dist_filename) == setup_base:
os.unlink(dist_filename) # get it out of the tmp dir os.unlink(dist_filename) # get it out of the tmp dir
contents = os.listdir(setup_base) contents = os.listdir(setup_base)
if len(contents)==1: if len(contents) == 1:
dist_filename = os.path.join(setup_base,contents[0]) dist_filename = os.path.join(setup_base, contents[0])
if os.path.isdir(dist_filename): if os.path.isdir(dist_filename):
# if the only thing there is a directory, move it instead # if the only thing there is a directory, move it instead
setup_base = dist_filename setup_base = dist_filename
...@@ -734,7 +753,7 @@ Please make the appropriate changes for your system and try again. ...@@ -734,7 +753,7 @@ Please make the appropriate changes for your system and try again.
if is_script: if is_script:
script_text = (get_script_header(script_text) + script_text = (get_script_header(script_text) +
self._load_template(dev_path) % locals()) self._load_template(dev_path) % locals())
self.write_script(script_name, _to_ascii(script_text), 'b') self.write_script(script_name, _to_ascii(script_text), 'b')
@staticmethod @staticmethod
...@@ -744,7 +763,7 @@ Please make the appropriate changes for your system and try again. ...@@ -744,7 +763,7 @@ Please make the appropriate changes for your system and try again.
function loads one of them and prepares it for use. function loads one of them and prepares it for use.
""" """
# See https://bitbucket.org/pypa/setuptools/issue/134 for info # See https://bitbucket.org/pypa/setuptools/issue/134 for info
# on script file naming and downstream issues with SVR4 # on script file naming and downstream issues with SVR4
name = 'script.tmpl' name = 'script.tmpl'
if dev_path: if dev_path:
name = name.replace('.tmpl', ' (dev).tmpl') name = name.replace('.tmpl', ' (dev).tmpl')
...@@ -754,8 +773,9 @@ Please make the appropriate changes for your system and try again. ...@@ -754,8 +773,9 @@ Please make the appropriate changes for your system and try again.
def write_script(self, script_name, contents, mode="t", blockers=()): def write_script(self, script_name, contents, mode="t", blockers=()):
"""Write an executable file to the scripts directory""" """Write an executable file to the scripts directory"""
self.delete_blockers( # clean up old .py/.pyw w/o a script self.delete_blockers( # clean up old .py/.pyw w/o a script
[os.path.join(self.script_dir,x) for x in blockers]) [os.path.join(self.script_dir, x) for x in blockers]
)
log.info("Installing %s script to %s", script_name, self.script_dir) log.info("Installing %s script to %s", script_name, self.script_dir)
target = os.path.join(self.script_dir, script_name) target = os.path.join(self.script_dir, script_name)
self.add_output(target) self.add_output(target)
...@@ -765,10 +785,10 @@ Please make the appropriate changes for your system and try again. ...@@ -765,10 +785,10 @@ Please make the appropriate changes for your system and try again.
ensure_directory(target) ensure_directory(target)
if os.path.exists(target): if os.path.exists(target):
os.unlink(target) os.unlink(target)
f = open(target,"w"+mode) f = open(target, "w" + mode)
f.write(contents) f.write(contents)
f.close() f.close()
chmod(target, 0o777-mask) chmod(target, 0o777 - mask)
def install_eggs(self, spec, dist_filename, tmpdir): def install_eggs(self, spec, dist_filename, tmpdir):
# .egg dirs or files are already built, so just return them # .egg dirs or files are already built, so just return them
...@@ -784,7 +804,7 @@ Please make the appropriate changes for your system and try again. ...@@ -784,7 +804,7 @@ Please make the appropriate changes for your system and try again.
elif os.path.isdir(dist_filename): elif os.path.isdir(dist_filename):
setup_base = os.path.abspath(dist_filename) setup_base = os.path.abspath(dist_filename)
if (setup_base.startswith(tmpdir) # something we downloaded if (setup_base.startswith(tmpdir) # something we downloaded
and self.build_directory and spec is not None): and self.build_directory and spec is not None):
setup_base = self.maybe_move(spec, dist_filename, setup_base) setup_base = self.maybe_move(spec, dist_filename, setup_base)
...@@ -795,11 +815,13 @@ Please make the appropriate changes for your system and try again. ...@@ -795,11 +815,13 @@ Please make the appropriate changes for your system and try again.
setups = glob(os.path.join(setup_base, '*', 'setup.py')) setups = glob(os.path.join(setup_base, '*', 'setup.py'))
if not setups: if not setups:
raise DistutilsError( raise DistutilsError(
"Couldn't find a setup script in %s" % os.path.abspath(dist_filename) "Couldn't find a setup script in %s" %
os.path.abspath(dist_filename)
) )
if len(setups)>1: if len(setups) > 1:
raise DistutilsError( raise DistutilsError(
"Multiple setup scripts in %s" % os.path.abspath(dist_filename) "Multiple setup scripts in %s" %
os.path.abspath(dist_filename)
) )
setup_script = setups[0] setup_script = setups[0]
...@@ -812,13 +834,15 @@ Please make the appropriate changes for your system and try again. ...@@ -812,13 +834,15 @@ Please make the appropriate changes for your system and try again.
def egg_distribution(self, egg_path): def egg_distribution(self, egg_path):
if os.path.isdir(egg_path): if os.path.isdir(egg_path):
metadata = PathMetadata(egg_path,os.path.join(egg_path,'EGG-INFO')) metadata = PathMetadata(egg_path, os.path.join(egg_path,
'EGG-INFO'))
else: else:
metadata = EggMetadata(zipimport.zipimporter(egg_path)) metadata = EggMetadata(zipimport.zipimporter(egg_path))
return Distribution.from_filename(egg_path,metadata=metadata) return Distribution.from_filename(egg_path, metadata=metadata)
def install_egg(self, egg_path, tmpdir): def install_egg(self, egg_path, tmpdir):
destination = os.path.join(self.install_dir,os.path.basename(egg_path)) destination = os.path.join(self.install_dir,
os.path.basename(egg_path))
destination = os.path.abspath(destination) destination = os.path.abspath(destination)
if not self.dry_run: if not self.dry_run:
ensure_directory(destination) ensure_directory(destination)
...@@ -828,28 +852,30 @@ Please make the appropriate changes for your system and try again. ...@@ -828,28 +852,30 @@ Please make the appropriate changes for your system and try again.
if os.path.isdir(destination) and not os.path.islink(destination): if os.path.isdir(destination) and not os.path.islink(destination):
dir_util.remove_tree(destination, dry_run=self.dry_run) dir_util.remove_tree(destination, dry_run=self.dry_run)
elif os.path.exists(destination): elif os.path.exists(destination):
self.execute(os.unlink,(destination,),"Removing "+destination) self.execute(os.unlink, (destination,), "Removing " +
destination)
try: try:
new_dist_is_zipped = False new_dist_is_zipped = False
if os.path.isdir(egg_path): if os.path.isdir(egg_path):
if egg_path.startswith(tmpdir): if egg_path.startswith(tmpdir):
f,m = shutil.move, "Moving" f, m = shutil.move, "Moving"
else: else:
f,m = shutil.copytree, "Copying" f, m = shutil.copytree, "Copying"
elif self.should_unzip(dist): elif self.should_unzip(dist):
self.mkpath(destination) self.mkpath(destination)
f,m = self.unpack_and_compile, "Extracting" f, m = self.unpack_and_compile, "Extracting"
else: else:
new_dist_is_zipped = True new_dist_is_zipped = True
if egg_path.startswith(tmpdir): if egg_path.startswith(tmpdir):
f,m = shutil.move, "Moving" f, m = shutil.move, "Moving"
else: else:
f,m = shutil.copy2, "Copying" f, m = shutil.copy2, "Copying"
self.execute(f, (egg_path, destination), self.execute(f, (egg_path, destination),
(m+" %s to %s") % (m + " %s to %s") %
(os.path.basename(egg_path),os.path.dirname(destination))) (os.path.basename(egg_path),
os.path.dirname(destination)))
update_dist_caches(destination, update_dist_caches(destination,
fix_zipimporter_caches=new_dist_is_zipped) fix_zipimporter_caches=new_dist_is_zipped)
except: except:
update_dist_caches(destination, fix_zipimporter_caches=False) update_dist_caches(destination, fix_zipimporter_caches=False)
raise raise
...@@ -867,30 +893,32 @@ Please make the appropriate changes for your system and try again. ...@@ -867,30 +893,32 @@ Please make the appropriate changes for your system and try again.
# Create a dummy distribution object until we build the real distro # Create a dummy distribution object until we build the real distro
dist = Distribution( dist = Distribution(
None, None,
project_name=cfg.get('metadata','name'), project_name=cfg.get('metadata', 'name'),
version=cfg.get('metadata','version'), platform=get_platform(), version=cfg.get('metadata', 'version'), platform=get_platform(),
) )
# Convert the .exe to an unpacked egg # Convert the .exe to an unpacked egg
egg_path = dist.location = os.path.join(tmpdir, dist.egg_name()+'.egg') egg_path = dist.location = os.path.join(tmpdir, dist.egg_name() +
'.egg')
egg_tmp = egg_path + '.tmp' egg_tmp = egg_path + '.tmp'
_egg_info = os.path.join(egg_tmp, 'EGG-INFO') _egg_info = os.path.join(egg_tmp, 'EGG-INFO')
pkg_inf = os.path.join(_egg_info, 'PKG-INFO') pkg_inf = os.path.join(_egg_info, 'PKG-INFO')
ensure_directory(pkg_inf) # make sure EGG-INFO dir exists ensure_directory(pkg_inf) # make sure EGG-INFO dir exists
dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX
self.exe_to_egg(dist_filename, egg_tmp) self.exe_to_egg(dist_filename, egg_tmp)
# Write EGG-INFO/PKG-INFO # Write EGG-INFO/PKG-INFO
if not os.path.exists(pkg_inf): if not os.path.exists(pkg_inf):
f = open(pkg_inf,'w') f = open(pkg_inf, 'w')
f.write('Metadata-Version: 1.0\n') f.write('Metadata-Version: 1.0\n')
for k,v in cfg.items('metadata'): 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.write('%s: %s\n' % (k.replace('_', '-').title(), v))
f.close() f.close()
script_dir = os.path.join(_egg_info,'scripts') script_dir = os.path.join(_egg_info, 'scripts')
self.delete_blockers( # delete entry-point scripts to avoid duping self.delete_blockers( # delete entry-point scripts to avoid duping
[os.path.join(script_dir,args[0]) for args in get_script_args(dist)] [os.path.join(script_dir, args[0]) for args in
get_script_args(dist)]
) )
# Build .egg file from tmpdir # Build .egg file from tmpdir
bdist_egg.make_zipfile( bdist_egg.make_zipfile(
...@@ -906,11 +934,12 @@ Please make the appropriate changes for your system and try again. ...@@ -906,11 +934,12 @@ Please make the appropriate changes for your system and try again.
to_compile = [] to_compile = []
native_libs = [] native_libs = []
top_level = {} top_level = {}
def process(src,dst):
def process(src, dst):
s = src.lower() s = src.lower()
for old,new in prefixes: for old, new in prefixes:
if s.startswith(old): if s.startswith(old):
src = new+src[len(old):] src = new + src[len(old):]
parts = src.split('/') parts = src.split('/')
dst = os.path.join(egg_tmp, *parts) dst = os.path.join(egg_tmp, *parts)
dl = dst.lower() dl = dst.lower()
...@@ -918,35 +947,37 @@ Please make the appropriate changes for your system and try again. ...@@ -918,35 +947,37 @@ Please make the appropriate changes for your system and try again.
parts[-1] = bdist_egg.strip_module(parts[-1]) parts[-1] = bdist_egg.strip_module(parts[-1])
top_level[os.path.splitext(parts[0])[0]] = 1 top_level[os.path.splitext(parts[0])[0]] = 1
native_libs.append(src) native_libs.append(src)
elif dl.endswith('.py') and old!='SCRIPTS/': elif dl.endswith('.py') and old != 'SCRIPTS/':
top_level[os.path.splitext(parts[0])[0]] = 1 top_level[os.path.splitext(parts[0])[0]] = 1
to_compile.append(dst) to_compile.append(dst)
return dst return dst
if not src.endswith('.pth'): if not src.endswith('.pth'):
log.warn("WARNING: can't process %s", src) log.warn("WARNING: can't process %s", src)
return None return None
# extract, tracking .pyd/.dll->native_libs and .py -> to_compile # extract, tracking .pyd/.dll->native_libs and .py -> to_compile
unpack_archive(dist_filename, egg_tmp, process) unpack_archive(dist_filename, egg_tmp, process)
stubs = [] stubs = []
for res in native_libs: for res in native_libs:
if res.lower().endswith('.pyd'): # create stubs for .pyd's if res.lower().endswith('.pyd'): # create stubs for .pyd's
parts = res.split('/') parts = res.split('/')
resource = parts[-1] resource = parts[-1]
parts[-1] = bdist_egg.strip_module(parts[-1])+'.py' parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py'
pyfile = os.path.join(egg_tmp, *parts) pyfile = os.path.join(egg_tmp, *parts)
to_compile.append(pyfile) to_compile.append(pyfile)
stubs.append(pyfile) stubs.append(pyfile)
bdist_egg.write_stub(resource, pyfile) bdist_egg.write_stub(resource, pyfile)
self.byte_compile(to_compile) # compile .py's self.byte_compile(to_compile) # compile .py's
bdist_egg.write_safety_flag(os.path.join(egg_tmp,'EGG-INFO'), bdist_egg.write_safety_flag(
os.path.join(egg_tmp, 'EGG-INFO'),
bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag
for name in 'top_level','native_libs': for name in 'top_level', 'native_libs':
if locals()[name]: if locals()[name]:
txt = os.path.join(egg_tmp, 'EGG-INFO', name+'.txt') txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt')
if not os.path.exists(txt): if not os.path.exists(txt):
f = open(txt,'w') f = open(txt, 'w')
f.write('\n'.join(locals()[name])+'\n') f.write('\n'.join(locals()[name]) + '\n')
f.close() f.close()
def installation_report(self, req, dist, what="Installed"): def installation_report(self, req, dist, what="Installed"):
...@@ -964,7 +995,7 @@ these examples, in order to select the desired version: ...@@ -964,7 +995,7 @@ these examples, in order to select the desired version:
pkg_resources.require("%(name)s==%(version)s") # this exact version pkg_resources.require("%(name)s==%(version)s") # this exact version
pkg_resources.require("%(name)s>=%(version)s") # this version or higher pkg_resources.require("%(name)s>=%(version)s") # this version or higher
""" """
if self.install_dir not in map(normalize_path,sys.path): if self.install_dir not in map(normalize_path, sys.path):
msg += """ msg += """
Note also that the installation directory must be on sys.path at runtime for Note also that the installation directory must be on sys.path at runtime for
...@@ -974,7 +1005,7 @@ PYTHONPATH, or by being added to sys.path by your code.) ...@@ -974,7 +1005,7 @@ PYTHONPATH, or by being added to sys.path by your code.)
eggloc = dist.location eggloc = dist.location
name = dist.project_name name = dist.project_name
version = dist.version version = dist.version
extras = '' # TODO: self.report_extras(req, dist) extras = '' # TODO: self.report_extras(req, dist)
return msg % locals() return msg % locals()
def report_editable(self, spec, setup_script): def report_editable(self, spec, setup_script):
...@@ -995,15 +1026,15 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -995,15 +1026,15 @@ See the setuptools documentation for the "develop" command for more info.
sys.modules.setdefault('distutils.command.egg_info', egg_info) sys.modules.setdefault('distutils.command.egg_info', egg_info)
args = list(args) args = list(args)
if self.verbose>2: if self.verbose > 2:
v = 'v' * (self.verbose - 1) v = 'v' * (self.verbose - 1)
args.insert(0,'-'+v) args.insert(0, '-' + v)
elif self.verbose<2: elif self.verbose < 2:
args.insert(0,'-q') args.insert(0, '-q')
if self.dry_run: if self.dry_run:
args.insert(0,'-n') args.insert(0, '-n')
log.info( log.info(
"Running %s %s", setup_script[len(setup_base)+1:], ' '.join(args) "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args)
) )
try: try:
run_setup(setup_script, args) run_setup(setup_script, args)
...@@ -1029,11 +1060,11 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1029,11 +1060,11 @@ See the setuptools documentation for the "develop" command for more info.
eggs.append(self.install_egg(dist.location, setup_base)) eggs.append(self.install_egg(dist.location, setup_base))
if not eggs and not self.dry_run: if not eggs and not self.dry_run:
log.warn("No eggs found in %s (setup script problem?)", log.warn("No eggs found in %s (setup script problem?)",
dist_dir) dist_dir)
return eggs return eggs
finally: finally:
rmtree(dist_dir) rmtree(dist_dir)
log.set_verbosity(self.verbose) # restore our log verbosity log.set_verbosity(self.verbose) # restore our log verbosity
def _set_fetcher_options(self, base): def _set_fetcher_options(self, base):
""" """
...@@ -1043,7 +1074,7 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1043,7 +1074,7 @@ See the setuptools documentation for the "develop" command for more info.
are available to that command as well. are available to that command as well.
""" """
# find the fetch options from easy_install and write them out # find the fetch options from easy_install and write them out
# to the setup.cfg file. # to the setup.cfg file.
ei_opts = self.distribution.get_option_dict('easy_install').copy() ei_opts = self.distribution.get_option_dict('easy_install').copy()
fetch_directives = ( fetch_directives = (
'find_links', 'site_dirs', 'index_url', 'optimize', 'find_links', 'site_dirs', 'index_url', 'optimize',
...@@ -1051,7 +1082,8 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1051,7 +1082,8 @@ See the setuptools documentation for the "develop" command for more info.
) )
fetch_options = {} fetch_options = {}
for key, val in ei_opts.items(): for key, val in ei_opts.items():
if key not in fetch_directives: continue if key not in fetch_directives:
continue
fetch_options[key.replace('_', '-')] = val[1] fetch_options[key.replace('_', '-')] = val[1]
# create a settings dictionary suitable for `edit_config` # create a settings dictionary suitable for `edit_config`
settings = dict(easy_install=fetch_options) settings = dict(easy_install=fetch_options)
...@@ -1062,7 +1094,7 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1062,7 +1094,7 @@ See the setuptools documentation for the "develop" command for more info.
if self.pth_file is None: if self.pth_file is None:
return return
for d in self.pth_file[dist.key]: # drop old entries for d in self.pth_file[dist.key]: # drop old entries
if self.multi_version or d.location != dist.location: if self.multi_version or d.location != dist.location:
log.info("Removing %s from easy-install.pth file", d) log.info("Removing %s from easy-install.pth file", d)
self.pth_file.remove(d) self.pth_file.remove(d)
...@@ -1077,7 +1109,7 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1077,7 +1109,7 @@ See the setuptools documentation for the "develop" command for more info.
) )
else: else:
log.info("Adding %s to easy-install.pth file", dist) log.info("Adding %s to easy-install.pth file", dist)
self.pth_file.add(dist) # add new entry self.pth_file.add(dist) # add new entry
if dist.location not in self.shadow_path: if dist.location not in self.shadow_path:
self.shadow_path.append(dist.location) self.shadow_path.append(dist.location)
...@@ -1085,19 +1117,20 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1085,19 +1117,20 @@ See the setuptools documentation for the "develop" command for more info.
self.pth_file.save() self.pth_file.save()
if dist.key=='setuptools': if dist.key == 'setuptools':
# Ensure that setuptools itself never becomes unavailable! # Ensure that setuptools itself never becomes unavailable!
# XXX should this check for latest version? # XXX should this check for latest version?
filename = os.path.join(self.install_dir,'setuptools.pth') filename = os.path.join(self.install_dir, 'setuptools.pth')
if os.path.islink(filename): os.unlink(filename) if os.path.islink(filename):
os.unlink(filename)
f = open(filename, 'wt') f = open(filename, 'wt')
f.write(self.pth_file.make_relative(dist.location)+'\n') f.write(self.pth_file.make_relative(dist.location) + '\n')
f.close() f.close()
def unpack_progress(self, src, dst): def unpack_progress(self, src, dst):
# Progress filter for unpacking # Progress filter for unpacking
log.debug("Unpacking %s to %s", src, dst) log.debug("Unpacking %s to %s", src, dst)
return dst # only unpack-and-compile skips files for dry run return dst # only unpack-and-compile skips files for dry run
def unpack_and_compile(self, egg_path, destination): def unpack_and_compile(self, egg_path, destination):
to_compile = [] to_compile = []
...@@ -1108,7 +1141,7 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1108,7 +1141,7 @@ See the setuptools documentation for the "develop" command for more info.
to_compile.append(dst) to_compile.append(dst)
elif dst.endswith('.dll') or dst.endswith('.so'): elif dst.endswith('.dll') or dst.endswith('.so'):
to_chmod.append(dst) to_chmod.append(dst)
self.unpack_progress(src,dst) self.unpack_progress(src, dst)
return not self.dry_run and dst or None return not self.dry_run and dst or None
unpack_archive(egg_path, destination, pf) unpack_archive(egg_path, destination, pf)
...@@ -1124,6 +1157,7 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1124,6 +1157,7 @@ See the setuptools documentation for the "develop" command for more info.
return return
from distutils.util import byte_compile from distutils.util import byte_compile
try: try:
# try to make the byte compile messages quieter # try to make the byte compile messages quieter
log.set_verbosity(self.verbose - 1) log.set_verbosity(self.verbose - 1)
...@@ -1135,7 +1169,7 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1135,7 +1169,7 @@ See the setuptools documentation for the "develop" command for more info.
dry_run=self.dry_run dry_run=self.dry_run
) )
finally: finally:
log.set_verbosity(self.verbose) # restore original verbosity log.set_verbosity(self.verbose) # restore original verbosity
def no_default_version_msg(self): def no_default_version_msg(self):
template = """bad install directory or PYTHONPATH template = """bad install directory or PYTHONPATH
...@@ -1166,7 +1200,7 @@ Here are some of your options for correcting the problem: ...@@ -1166,7 +1200,7 @@ Here are some of your options for correcting the problem:
https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations
Please make the appropriate changes for your system and try again.""" Please make the appropriate changes for your system and try again."""
return template % (self.install_dir, os.environ.get('PYTHONPATH','')) return template % (self.install_dir, os.environ.get('PYTHONPATH', ''))
def install_site_py(self): def install_site_py(self):
"""Make sure there's a site.py in the target dir, if needed""" """Make sure there's a site.py in the target dir, if needed"""
...@@ -1180,7 +1214,7 @@ Please make the appropriate changes for your system and try again.""" ...@@ -1180,7 +1214,7 @@ Please make the appropriate changes for your system and try again."""
if os.path.exists(sitepy): if os.path.exists(sitepy):
log.debug("Checking existing site.py in %s", self.install_dir) log.debug("Checking existing site.py in %s", self.install_dir)
f = open(sitepy,'rb') f = open(sitepy, 'rb')
current = f.read() current = f.read()
# we want str, not bytes # we want str, not bytes
if PY3: if PY3:
...@@ -1197,7 +1231,7 @@ Please make the appropriate changes for your system and try again.""" ...@@ -1197,7 +1231,7 @@ Please make the appropriate changes for your system and try again."""
log.info("Creating %s", sitepy) log.info("Creating %s", sitepy)
if not self.dry_run: if not self.dry_run:
ensure_directory(sitepy) ensure_directory(sitepy)
f = open(sitepy,'wb') f = open(sitepy, 'wb')
f.write(source) f.write(source)
f.close() f.close()
self.byte_compile([sitepy]) self.byte_compile([sitepy])
...@@ -1215,15 +1249,15 @@ Please make the appropriate changes for your system and try again.""" ...@@ -1215,15 +1249,15 @@ Please make the appropriate changes for your system and try again."""
os.makedirs(path, 0o700) os.makedirs(path, 0o700)
INSTALL_SCHEMES = dict( INSTALL_SCHEMES = dict(
posix = dict( posix=dict(
install_dir = '$base/lib/python$py_version_short/site-packages', install_dir='$base/lib/python$py_version_short/site-packages',
script_dir = '$base/bin', script_dir='$base/bin',
), ),
) )
DEFAULT_SCHEME = dict( DEFAULT_SCHEME = dict(
install_dir = '$base/Lib/site-packages', install_dir='$base/Lib/site-packages',
script_dir = '$base/Scripts', script_dir='$base/Scripts',
) )
def _expand(self, *attrs): def _expand(self, *attrs):
...@@ -1233,12 +1267,13 @@ Please make the appropriate changes for your system and try again.""" ...@@ -1233,12 +1267,13 @@ Please make the appropriate changes for your system and try again."""
# Set default install_dir/scripts from --prefix # Set default install_dir/scripts from --prefix
config_vars = config_vars.copy() config_vars = config_vars.copy()
config_vars['base'] = self.prefix config_vars['base'] = self.prefix
scheme = self.INSTALL_SCHEMES.get(os.name,self.DEFAULT_SCHEME) scheme = self.INSTALL_SCHEMES.get(os.name, self.DEFAULT_SCHEME)
for attr,val in scheme.items(): for attr, val in scheme.items():
if getattr(self,attr,None) is None: if getattr(self, attr, None) is None:
setattr(self,attr,val) setattr(self, attr, val)
from distutils.util import subst_vars from distutils.util import subst_vars
for attr in attrs: for attr in attrs:
val = getattr(self, attr) val = getattr(self, attr)
if val is not None: if val is not None:
...@@ -1247,6 +1282,7 @@ Please make the appropriate changes for your system and try again.""" ...@@ -1247,6 +1282,7 @@ Please make the appropriate changes for your system and try again."""
val = os.path.expanduser(val) val = os.path.expanduser(val)
setattr(self, attr, val) setattr(self, attr, val)
def get_site_dirs(): def get_site_dirs():
# return a list of 'site' dirs # return a list of 'site' dirs
sitedirs = [_f for _f in os.environ.get('PYTHONPATH', sitedirs = [_f for _f in os.environ.get('PYTHONPATH',
...@@ -1260,10 +1296,10 @@ def get_site_dirs(): ...@@ -1260,10 +1296,10 @@ def get_site_dirs():
sitedirs.append(os.path.join(prefix, "Lib", "site-packages")) sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
elif os.sep == '/': elif os.sep == '/':
sitedirs.extend([os.path.join(prefix, sitedirs.extend([os.path.join(prefix,
"lib", "lib",
"python" + sys.version[:3], "python" + sys.version[:3],
"site-packages"), "site-packages"),
os.path.join(prefix, "lib", "site-python")]) os.path.join(prefix, "lib", "site-python")])
else: else:
sitedirs.extend( sitedirs.extend(
[prefix, os.path.join(prefix, "lib", "site-packages")] [prefix, os.path.join(prefix, "lib", "site-packages")]
...@@ -1283,7 +1319,8 @@ def get_site_dirs(): ...@@ -1283,7 +1319,8 @@ def get_site_dirs():
'site-packages')) 'site-packages'))
lib_paths = get_path('purelib'), get_path('platlib') lib_paths = get_path('purelib'), get_path('platlib')
for site_lib in lib_paths: for site_lib in lib_paths:
if site_lib not in sitedirs: sitedirs.append(site_lib) if site_lib not in sitedirs:
sitedirs.append(site_lib)
if site.ENABLE_USER_SITE: if site.ENABLE_USER_SITE:
sitedirs.append(site.USER_SITE) sitedirs.append(site.USER_SITE)
...@@ -1314,12 +1351,12 @@ def expand_paths(inputs): ...@@ -1314,12 +1351,12 @@ def expand_paths(inputs):
if not name.endswith('.pth'): if not name.endswith('.pth'):
# We only care about the .pth files # We only care about the .pth files
continue continue
if name in ('easy-install.pth','setuptools.pth'): if name in ('easy-install.pth', 'setuptools.pth'):
# Ignore .pth files that we control # Ignore .pth files that we control
continue continue
# Read the .pth file # Read the .pth file
f = open(os.path.join(dirname,name)) f = open(os.path.join(dirname, name))
lines = list(yield_lines(f)) lines = list(yield_lines(f))
f.close() f.close()
...@@ -1339,7 +1376,7 @@ def extract_wininst_cfg(dist_filename): ...@@ -1339,7 +1376,7 @@ def extract_wininst_cfg(dist_filename):
Returns a ConfigParser.RawConfigParser, or None Returns a ConfigParser.RawConfigParser, or None
""" """
f = open(dist_filename,'rb') f = open(dist_filename, 'rb')
try: try:
endrec = zipfile._EndRecData(f) endrec = zipfile._EndRecData(f)
if endrec is None: if endrec is None:
...@@ -1348,21 +1385,23 @@ def extract_wininst_cfg(dist_filename): ...@@ -1348,21 +1385,23 @@ def extract_wininst_cfg(dist_filename):
prepended = (endrec[9] - endrec[5]) - endrec[6] prepended = (endrec[9] - endrec[5]) - endrec[6]
if prepended < 12: # no wininst data here if prepended < 12: # no wininst data here
return None return None
f.seek(prepended-12) f.seek(prepended - 12)
from setuptools.compat import StringIO, ConfigParser from setuptools.compat import StringIO, ConfigParser
import struct import struct
tag, cfglen, bmlen = struct.unpack("<iii",f.read(12))
tag, cfglen, bmlen = struct.unpack("<iii", f.read(12))
if tag not in (0x1234567A, 0x1234567B): if tag not in (0x1234567A, 0x1234567B):
return None # not a valid tag return None # not a valid tag
f.seek(prepended-(12+cfglen)) f.seek(prepended - (12 + cfglen))
cfg = ConfigParser.RawConfigParser({'version':'','target_version':''}) cfg = ConfigParser.RawConfigParser(
{'version': '', 'target_version': ''})
try: try:
part = f.read(cfglen) part = f.read(cfglen)
# part is in bytes, but we need to read up to the first null # part is in bytes, but we need to read up to the first null
# byte. # byte.
if sys.version_info >= (2,6): if sys.version_info >= (2, 6):
null_byte = bytes([0]) null_byte = bytes([0])
else: else:
null_byte = chr(0) null_byte = chr(0)
...@@ -1395,25 +1434,25 @@ def get_exe_prefixes(exe_filename): ...@@ -1395,25 +1434,25 @@ def get_exe_prefixes(exe_filename):
for info in z.infolist(): for info in z.infolist():
name = info.filename name = info.filename
parts = name.split('/') parts = name.split('/')
if len(parts)==3 and parts[2]=='PKG-INFO': if len(parts) == 3 and parts[2] == 'PKG-INFO':
if parts[1].endswith('.egg-info'): if parts[1].endswith('.egg-info'):
prefixes.insert(0,('/'.join(parts[:2]), 'EGG-INFO/')) prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/'))
break break
if len(parts) != 2 or not name.endswith('.pth'): if len(parts) != 2 or not name.endswith('.pth'):
continue continue
if name.endswith('-nspkg.pth'): if name.endswith('-nspkg.pth'):
continue continue
if parts[0].upper() in ('PURELIB','PLATLIB'): if parts[0].upper() in ('PURELIB', 'PLATLIB'):
contents = z.read(name) contents = z.read(name)
if PY3: if PY3:
contents = contents.decode() contents = contents.decode()
for pth in yield_lines(contents): for pth in yield_lines(contents):
pth = pth.strip().replace('\\','/') pth = pth.strip().replace('\\', '/')
if not pth.startswith('import'): if not pth.startswith('import'):
prefixes.append((('%s/%s/' % (parts[0],pth)), '')) prefixes.append((('%s/%s/' % (parts[0], pth)), ''))
finally: finally:
z.close() z.close()
prefixes = [(x.lower(),y) for x, y in prefixes] prefixes = [(x.lower(), y) for x, y in prefixes]
prefixes.sort() prefixes.sort()
prefixes.reverse() prefixes.reverse()
return prefixes return prefixes
...@@ -1427,6 +1466,7 @@ def parse_requirement_arg(spec): ...@@ -1427,6 +1466,7 @@ def parse_requirement_arg(spec):
"Not a URL, existing file, or requirement spec: %r" % (spec,) "Not a URL, existing file, or requirement spec: %r" % (spec,)
) )
class PthDistributions(Environment): class PthDistributions(Environment):
"""A .pth file with Distribution paths in it""" """A .pth file with Distribution paths in it"""
...@@ -1446,7 +1486,7 @@ class PthDistributions(Environment): ...@@ -1446,7 +1486,7 @@ class PthDistributions(Environment):
saw_import = False saw_import = False
seen = dict.fromkeys(self.sitedirs) seen = dict.fromkeys(self.sitedirs)
if os.path.isfile(self.filename): if os.path.isfile(self.filename):
f = open(self.filename,'rt') f = open(self.filename, 'rt')
for line in f: for line in f:
if line.startswith('import'): if line.startswith('import'):
saw_import = True saw_import = True
...@@ -1458,17 +1498,17 @@ class PthDistributions(Environment): ...@@ -1458,17 +1498,17 @@ class PthDistributions(Environment):
# skip non-existent paths, in case somebody deleted a package # skip non-existent paths, in case somebody deleted a package
# manually, and duplicate paths as well # manually, and duplicate paths as well
path = self.paths[-1] = normalize_path( path = self.paths[-1] = normalize_path(
os.path.join(self.basedir,path) os.path.join(self.basedir, path)
) )
if not os.path.exists(path) or path in seen: if not os.path.exists(path) or path in seen:
self.paths.pop() # skip it self.paths.pop() # skip it
self.dirty = True # we cleaned up, so we're dirty now :) self.dirty = True # we cleaned up, so we're dirty now :)
continue continue
seen[path] = 1 seen[path] = 1
f.close() f.close()
if self.paths and not saw_import: if self.paths and not saw_import:
self.dirty = True # ensure anything we touch has import wrappers self.dirty = True # ensure anything we touch has import wrappers
while self.paths and not self.paths[-1].strip(): while self.paths and not self.paths[-1].strip():
self.paths.pop() self.paths.pop()
...@@ -1477,7 +1517,7 @@ class PthDistributions(Environment): ...@@ -1477,7 +1517,7 @@ class PthDistributions(Environment):
if not self.dirty: if not self.dirty:
return return
data = '\n'.join(map(self.make_relative,self.paths)) data = '\n'.join(map(self.make_relative, self.paths))
if data: if data:
log.debug("Saving %s", self.filename) log.debug("Saving %s", self.filename)
data = ( data = (
...@@ -1491,7 +1531,7 @@ class PthDistributions(Environment): ...@@ -1491,7 +1531,7 @@ class PthDistributions(Environment):
if os.path.islink(self.filename): if os.path.islink(self.filename):
os.unlink(self.filename) os.unlink(self.filename)
f = open(self.filename,'wt') f = open(self.filename, 'wt')
f.write(data) f.write(data)
f.close() f.close()
...@@ -1504,9 +1544,9 @@ class PthDistributions(Environment): ...@@ -1504,9 +1544,9 @@ class PthDistributions(Environment):
def add(self, dist): def add(self, dist):
"""Add `dist` to the distribution map""" """Add `dist` to the distribution map"""
if (dist.location not in self.paths and ( if (dist.location not in self.paths and (
dist.location not in self.sitedirs or dist.location not in self.sitedirs or
dist.location == os.getcwd() # account for '.' being in PYTHONPATH dist.location == os.getcwd() # account for '.' being in PYTHONPATH
)): )):
self.paths.append(dist.location) self.paths.append(dist.location)
self.dirty = True self.dirty = True
Environment.add(self, dist) Environment.add(self, dist)
...@@ -1518,13 +1558,13 @@ class PthDistributions(Environment): ...@@ -1518,13 +1558,13 @@ class PthDistributions(Environment):
self.dirty = True self.dirty = True
Environment.remove(self, dist) Environment.remove(self, dist)
def make_relative(self,path): def make_relative(self, path):
npath, last = os.path.split(normalize_path(path)) npath, last = os.path.split(normalize_path(path))
baselen = len(self.basedir) baselen = len(self.basedir)
parts = [last] parts = [last]
sep = os.altsep=='/' and '/' or os.sep sep = os.altsep == '/' and '/' or os.sep
while len(npath)>=baselen: while len(npath) >= baselen:
if npath==self.basedir: if npath == self.basedir:
parts.append(os.curdir) parts.append(os.curdir)
parts.reverse() parts.reverse()
return sep.join(parts) return sep.join(parts)
...@@ -1548,12 +1588,13 @@ def _first_line_re(): ...@@ -1548,12 +1588,13 @@ def _first_line_re():
def get_script_header(script_text, executable=sys_executable, wininst=False): def get_script_header(script_text, executable=sys_executable, wininst=False):
"""Create a #! line, getting options (if any) from script_text""" """Create a #! line, getting options (if any) from script_text"""
first = (script_text+'\n').splitlines()[0] first = (script_text + '\n').splitlines()[0]
match = _first_line_re().match(first) match = _first_line_re().match(first)
options = '' options = ''
if match: if match:
options = match.group(1) or '' options = match.group(1) or ''
if options: options = ' '+options if options:
options = ' ' + options
if wininst: if wininst:
executable = "python.exe" executable = "python.exe"
else: else:
...@@ -1563,20 +1604,22 @@ def get_script_header(script_text, executable=sys_executable, wininst=False): ...@@ -1563,20 +1604,22 @@ def get_script_header(script_text, executable=sys_executable, wininst=False):
# Non-ascii path to sys.executable, use -x to prevent warnings # Non-ascii path to sys.executable, use -x to prevent warnings
if options: if options:
if options.strip().startswith('-'): if options.strip().startswith('-'):
options = ' -x'+options.strip()[1:] options = ' -x' + options.strip()[1:]
# else: punt, we can't do it, let the warning happen anyway # else: punt, we can't do it, let the warning happen anyway
else: else:
options = ' -x' options = ' -x'
executable = fix_jython_executable(executable, options) executable = fix_jython_executable(executable, options)
hdr = "#!%(executable)s%(options)s\n" % locals() hdr = "#!%(executable)s%(options)s\n" % locals()
return hdr return hdr
def auto_chmod(func, arg, exc): def auto_chmod(func, arg, exc):
if func is os.remove and os.name=='nt': if func is os.remove and os.name == 'nt':
chmod(arg, stat.S_IWRITE) chmod(arg, stat.S_IWRITE)
return func(arg) return func(arg)
et, ev, _ = sys.exc_info() et, ev, _ = sys.exc_info()
reraise(et, (ev[0], ev[1] + (" %s %s" % (func,arg)))) reraise(et, (ev[0], ev[1] + (" %s %s" % (func, arg))))
def update_dist_caches(dist_path, fix_zipimporter_caches): def update_dist_caches(dist_path, fix_zipimporter_caches):
""" """
...@@ -1630,7 +1673,7 @@ def update_dist_caches(dist_path, fix_zipimporter_caches): ...@@ -1630,7 +1673,7 @@ def update_dist_caches(dist_path, fix_zipimporter_caches):
# instances that we do not clear here, but might if ever given a reason to # instances that we do not clear here, but might if ever given a reason to
# do so: # do so:
# * Global setuptools pkg_resources.working_set (a.k.a. 'master working # * Global setuptools pkg_resources.working_set (a.k.a. 'master working
# set') may contain distributions which may in turn contain their # set') may contain distributions which may in turn contain their
# zipimport.zipimporter loaders. # zipimport.zipimporter loaders.
# * Several zipimport.zipimporter loaders held by local variables further # * Several zipimport.zipimporter loaders held by local variables further
# up the function call stack when running the setuptools installation. # up the function call stack when running the setuptools installation.
...@@ -1659,6 +1702,7 @@ def update_dist_caches(dist_path, fix_zipimporter_caches): ...@@ -1659,6 +1702,7 @@ def update_dist_caches(dist_path, fix_zipimporter_caches):
# this is really needed. # this is really needed.
_remove_and_clear_zip_directory_cache_data(normalized_path) _remove_and_clear_zip_directory_cache_data(normalized_path)
def _collect_zipimporter_cache_entries(normalized_path, cache): def _collect_zipimporter_cache_entries(normalized_path, cache):
""" """
Return zipimporter cache entry keys related to a given normalized path. Return zipimporter cache entry keys related to a given normalized path.
...@@ -1678,6 +1722,7 @@ def _collect_zipimporter_cache_entries(normalized_path, cache): ...@@ -1678,6 +1722,7 @@ def _collect_zipimporter_cache_entries(normalized_path, cache):
result.append(p) result.append(p)
return result return result
def _update_zipimporter_cache(normalized_path, cache, updater=None): def _update_zipimporter_cache(normalized_path, cache, updater=None):
""" """
Update zipimporter cache data for a given normalized path. Update zipimporter cache data for a given normalized path.
...@@ -1696,7 +1741,7 @@ def _update_zipimporter_cache(normalized_path, cache, updater=None): ...@@ -1696,7 +1741,7 @@ def _update_zipimporter_cache(normalized_path, cache, updater=None):
for p in _collect_zipimporter_cache_entries(normalized_path, cache): for p in _collect_zipimporter_cache_entries(normalized_path, cache):
# N.B. pypy's custom zipimport._zip_directory_cache implementation does # N.B. pypy's custom zipimport._zip_directory_cache implementation does
# not support the complete dict interface: # not support the complete dict interface:
# * Does not support item assignment, thus not allowing this function # * Does not support item assignment, thus not allowing this function
# to be used only for removing existing cache entries. # to be used only for removing existing cache entries.
# * Does not support the dict.pop() method, forcing us to use the # * Does not support the dict.pop() method, forcing us to use the
# get/del patterns instead. For more detailed information see the # get/del patterns instead. For more detailed information see the
...@@ -1709,14 +1754,17 @@ def _update_zipimporter_cache(normalized_path, cache, updater=None): ...@@ -1709,14 +1754,17 @@ def _update_zipimporter_cache(normalized_path, cache, updater=None):
if new_entry is not None: if new_entry is not None:
cache[p] = new_entry cache[p] = new_entry
def _uncache(normalized_path, cache): def _uncache(normalized_path, cache):
_update_zipimporter_cache(normalized_path, cache) _update_zipimporter_cache(normalized_path, cache)
def _remove_and_clear_zip_directory_cache_data(normalized_path): def _remove_and_clear_zip_directory_cache_data(normalized_path):
def clear_and_remove_cached_zip_archive_directory_data(path, old_entry): def clear_and_remove_cached_zip_archive_directory_data(path, old_entry):
old_entry.clear() old_entry.clear()
_update_zipimporter_cache(normalized_path,
zipimport._zip_directory_cache, _update_zipimporter_cache(
normalized_path, zipimport._zip_directory_cache,
updater=clear_and_remove_cached_zip_archive_directory_data) updater=clear_and_remove_cached_zip_archive_directory_data)
# PyPy Python implementation does not allow directly writing to the # PyPy Python implementation does not allow directly writing to the
...@@ -1728,7 +1776,7 @@ def _remove_and_clear_zip_directory_cache_data(normalized_path): ...@@ -1728,7 +1776,7 @@ def _remove_and_clear_zip_directory_cache_data(normalized_path):
# instead of being automatically corrected to use the new correct zip archive # instead of being automatically corrected to use the new correct zip archive
# directory information. # directory information.
if '__pypy__' in sys.builtin_module_names: if '__pypy__' in sys.builtin_module_names:
_replace_zip_directory_cache_data = \ _replace_zip_directory_cache_data = \
_remove_and_clear_zip_directory_cache_data _remove_and_clear_zip_directory_cache_data
else: else:
def _replace_zip_directory_cache_data(normalized_path): def _replace_zip_directory_cache_data(normalized_path):
...@@ -1744,10 +1792,12 @@ else: ...@@ -1744,10 +1792,12 @@ else:
zipimport.zipimporter(path) zipimport.zipimporter(path)
old_entry.update(zipimport._zip_directory_cache[path]) old_entry.update(zipimport._zip_directory_cache[path])
return old_entry return old_entry
_update_zipimporter_cache(normalized_path,
zipimport._zip_directory_cache, _update_zipimporter_cache(
normalized_path, zipimport._zip_directory_cache,
updater=replace_cached_zip_archive_directory_data) updater=replace_cached_zip_archive_directory_data)
def is_python(text, filename='<string>'): def is_python(text, filename='<string>'):
"Is this string a valid Python script?" "Is this string a valid Python script?"
try: try:
...@@ -1757,15 +1807,18 @@ def is_python(text, filename='<string>'): ...@@ -1757,15 +1807,18 @@ def is_python(text, filename='<string>'):
else: else:
return True return True
def is_sh(executable): def is_sh(executable):
"""Determine if the specified executable is a .sh (contains a #! line)""" """Determine if the specified executable is a .sh (contains a #! line)"""
try: try:
fp = open(executable) fp = open(executable)
magic = fp.read(2) magic = fp.read(2)
fp.close() fp.close()
except (OSError,IOError): return executable except (OSError, IOError):
return executable
return magic == '#!' return magic == '#!'
def nt_quote_arg(arg): def nt_quote_arg(arg):
"""Quote a command line argument according to Windows parsing rules""" """Quote a command line argument according to Windows parsing rules"""
...@@ -1782,7 +1835,7 @@ def nt_quote_arg(arg): ...@@ -1782,7 +1835,7 @@ def nt_quote_arg(arg):
nb += 1 nb += 1
elif c == '"': elif c == '"':
# double preceding backslashes, then add a \" # double preceding backslashes, then add a \"
result.append('\\' * (nb*2) + '\\"') result.append('\\' * (nb * 2) + '\\"')
nb = 0 nb = 0
else: else:
if nb: if nb:
...@@ -1794,29 +1847,33 @@ def nt_quote_arg(arg): ...@@ -1794,29 +1847,33 @@ def nt_quote_arg(arg):
result.append('\\' * nb) result.append('\\' * nb)
if needquote: if needquote:
result.append('\\' * nb) # double the trailing backslashes result.append('\\' * nb) # double the trailing backslashes
result.append('"') result.append('"')
return ''.join(result) return ''.join(result)
def is_python_script(script_text, filename): def is_python_script(script_text, filename):
"""Is this text, as a whole, a Python script? (as opposed to shell/bat/etc. """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.
""" """
if filename.endswith('.py') or filename.endswith('.pyw'): if filename.endswith('.py') or filename.endswith('.pyw'):
return True # extension says it's Python return True # extension says it's Python
if is_python(script_text, filename): if is_python(script_text, filename):
return True # it's syntactically valid Python return True # it's syntactically valid Python
if script_text.startswith('#!'): if script_text.startswith('#!'):
# It begins with a '#!' line, so check if 'python' is in it somewhere # It begins with a '#!' line, so check if 'python' is in it somewhere
return 'python' in script_text.splitlines()[0].lower() return 'python' in script_text.splitlines()[0].lower()
return False # Not any Python I can recognize return False # Not any Python I can recognize
try: try:
from os import chmod as _chmod from os import chmod as _chmod
except ImportError: except ImportError:
# Jython compatibility # Jython compatibility
def _chmod(*args): pass def _chmod(*args):
pass
def chmod(path, mode): def chmod(path, mode):
log.debug("changing mode of %s to %o", path, mode) log.debug("changing mode of %s to %o", path, mode)
...@@ -1826,10 +1883,12 @@ def chmod(path, mode): ...@@ -1826,10 +1883,12 @@ def chmod(path, mode):
e = sys.exc_info()[1] e = sys.exc_info()[1]
log.debug("chmod failed: %s", e) log.debug("chmod failed: %s", e)
def fix_jython_executable(executable, options): def fix_jython_executable(executable, options):
if sys.platform.startswith('java') and is_sh(executable): if sys.platform.startswith('java') and is_sh(executable):
# Workaround for Jython is not needed on Linux systems. # Workaround for Jython is not needed on Linux systems.
import java import java
if java.lang.System.getProperty("os.name") == "Linux": if java.lang.System.getProperty("os.name") == "Linux":
return executable return executable
...@@ -1878,19 +1937,19 @@ class ScriptWriter(object): ...@@ -1878,19 +1937,19 @@ class ScriptWriter(object):
for name, ep in dist.get_entry_map(group).items(): for name, ep in dist.get_entry_map(group).items():
script_text = gen_class.template % locals() script_text = gen_class.template % locals()
for res in gen_class._get_script_args(type_, name, header, for res in gen_class._get_script_args(type_, name, header,
script_text): script_text):
yield res yield res
@classmethod @classmethod
def get_writer(cls, force_windows): def get_writer(cls, force_windows):
if force_windows or sys.platform=='win32': if force_windows or sys.platform == 'win32':
return WindowsScriptWriter.get_writer() return WindowsScriptWriter.get_writer()
return cls return cls
@classmethod @classmethod
def _get_script_args(cls, type_, name, header, script_text): def _get_script_args(cls, type_, name, header, script_text):
# Simply write the stub with no extension. # Simply write the stub with no extension.
yield (name, header+script_text) yield (name, header + script_text)
class WindowsScriptWriter(ScriptWriter): class WindowsScriptWriter(ScriptWriter):
...@@ -1913,12 +1972,12 @@ class WindowsScriptWriter(ScriptWriter): ...@@ -1913,12 +1972,12 @@ class WindowsScriptWriter(ScriptWriter):
ext = dict(console='.pya', gui='.pyw')[type_] ext = dict(console='.pya', gui='.pyw')[type_]
if ext not in os.environ['PATHEXT'].lower().split(';'): if ext not in os.environ['PATHEXT'].lower().split(';'):
warnings.warn("%s not listed in PATHEXT; scripts will not be " warnings.warn("%s not listed in PATHEXT; scripts will not be "
"recognized as executables." % ext, UserWarning) "recognized as executables." % ext, UserWarning)
old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe'] old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe']
old.remove(ext) old.remove(ext)
header = cls._adjust_header(type_, header) header = cls._adjust_header(type_, header)
blockers = [name+x for x in old] blockers = [name + x for x in old]
yield name+ext, header+script_text, 't', blockers yield name + ext, header + script_text, 't', blockers
@staticmethod @staticmethod
def _adjust_header(type_, orig_header): def _adjust_header(type_, orig_header):
...@@ -1945,33 +2004,35 @@ class WindowsExecutableLauncherWriter(WindowsScriptWriter): ...@@ -1945,33 +2004,35 @@ class WindowsExecutableLauncherWriter(WindowsScriptWriter):
""" """
For Windows, add a .py extension and an .exe launcher For Windows, add a .py extension and an .exe launcher
""" """
if type_=='gui': if type_ == 'gui':
launcher_type = 'gui' launcher_type = 'gui'
ext = '-script.pyw' ext = '-script.pyw'
old = ['.pyw'] old = ['.pyw']
else: else:
launcher_type = 'cli' launcher_type = 'cli'
ext = '-script.py' ext = '-script.py'
old = ['.py','.pyc','.pyo'] old = ['.py', '.pyc', '.pyo']
hdr = cls._adjust_header(type_, header) hdr = cls._adjust_header(type_, header)
blockers = [name+x for x in old] blockers = [name + x for x in old]
yield (name+ext, hdr+script_text, 't', blockers) yield (name + ext, hdr + script_text, 't', blockers)
yield ( yield (
name+'.exe', get_win_launcher(launcher_type), name + '.exe', get_win_launcher(launcher_type),
'b' # write in binary mode 'b' # write in binary mode
) )
if not is_64bit(): if not is_64bit():
# install a manifest for the launcher to prevent Windows # install a manifest for the launcher to prevent Windows
# from detecting it as an installer (which it will for # from detecting it as an installer (which it will for
# launchers like easy_install.exe). Consider only # launchers like easy_install.exe). Consider only
# adding a manifest for launchers detected as installers. # adding a manifest for launchers detected as installers.
# See Distribute #143 for details. # See Distribute #143 for details.
m_name = name + '.exe.manifest' m_name = name + '.exe.manifest'
yield (m_name, load_launcher_manifest(name), 't') yield (m_name, load_launcher_manifest(name), 't')
# for backward-compatibility # for backward-compatibility
get_script_args = ScriptWriter.get_script_args get_script_args = ScriptWriter.get_script_args
def get_win_launcher(type): def get_win_launcher(type):
""" """
Load the Windows launcher (executable) suitable for launching a script. Load the Windows launcher (executable) suitable for launching a script.
...@@ -1981,7 +2042,7 @@ def get_win_launcher(type): ...@@ -1981,7 +2042,7 @@ def get_win_launcher(type):
Returns the executable as a byte string. Returns the executable as a byte string.
""" """
launcher_fn = '%s.exe' % type launcher_fn = '%s.exe' % type
if platform.machine().lower()=='arm': if platform.machine().lower() == 'arm':
launcher_fn = launcher_fn.replace(".", "-arm.") launcher_fn = launcher_fn.replace(".", "-arm.")
if is_64bit(): if is_64bit():
launcher_fn = launcher_fn.replace(".", "-64.") launcher_fn = launcher_fn.replace(".", "-64.")
...@@ -1989,6 +2050,7 @@ def get_win_launcher(type): ...@@ -1989,6 +2050,7 @@ def get_win_launcher(type):
launcher_fn = launcher_fn.replace(".", "-32.") launcher_fn = launcher_fn.replace(".", "-32.")
return resource_string('setuptools', launcher_fn) return resource_string('setuptools', launcher_fn)
def load_launcher_manifest(name): def load_launcher_manifest(name):
manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml') manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml')
if PY2: if PY2:
...@@ -1996,6 +2058,7 @@ def load_launcher_manifest(name): ...@@ -1996,6 +2058,7 @@ def load_launcher_manifest(name):
else: else:
return manifest.decode('utf-8') % vars() return manifest.decode('utf-8') % vars()
def rmtree(path, ignore_errors=False, onerror=auto_chmod): def rmtree(path, ignore_errors=False, onerror=auto_chmod):
"""Recursively delete a directory tree. """Recursively delete a directory tree.
...@@ -2031,19 +2094,23 @@ def rmtree(path, ignore_errors=False, onerror=auto_chmod): ...@@ -2031,19 +2094,23 @@ def rmtree(path, ignore_errors=False, onerror=auto_chmod):
except os.error: except os.error:
onerror(os.rmdir, path, sys.exc_info()) onerror(os.rmdir, path, sys.exc_info())
def current_umask(): def current_umask():
tmp = os.umask(0o022) tmp = os.umask(0o022)
os.umask(tmp) os.umask(tmp)
return tmp return tmp
def bootstrap(): def bootstrap():
# This function is called when setuptools*.egg is run using /bin/sh # This function is called when setuptools*.egg is run using /bin/sh
import setuptools import setuptools
argv0 = os.path.dirname(setuptools.__path__[0]) argv0 = os.path.dirname(setuptools.__path__[0])
sys.argv[0] = argv0 sys.argv[0] = argv0
sys.argv.append(argv0) sys.argv.append(argv0)
main() main()
def main(argv=None, **kw): def main(argv=None, **kw):
from setuptools import setup from setuptools import setup
from setuptools.dist import Distribution from setuptools.dist import Distribution
...@@ -2070,16 +2137,16 @@ usage: %(script)s [options] requirement_or_url ... ...@@ -2070,16 +2137,16 @@ usage: %(script)s [options] requirement_or_url ...
class DistributionWithoutHelpCommands(Distribution): class DistributionWithoutHelpCommands(Distribution):
common_usage = "" common_usage = ""
def _show_help(self,*args,**kw): def _show_help(self, *args, **kw):
with_ei_usage(lambda: Distribution._show_help(self,*args,**kw)) with_ei_usage(lambda: Distribution._show_help(self, *args, **kw))
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]
with_ei_usage(lambda: with_ei_usage(
setup( lambda: setup(
script_args = ['-q','easy_install', '-v']+argv, script_args=['-q', 'easy_install', '-v'] + argv,
script_name = sys.argv[0] or 'easy_install', script_name=sys.argv[0] or 'easy_install',
distclass=DistributionWithoutHelpCommands, **kw distclass=DistributionWithoutHelpCommands, **kw
) )
) )
...@@ -2,21 +2,22 @@ ...@@ -2,21 +2,22 @@
Create a distribution's .egg-info directory and contents""" Create a distribution's .egg-info directory and contents"""
from distutils.filelist import FileList as _FileList
from distutils.util import convert_path
from distutils import log
import distutils.errors
import os import os
import re import re
import sys import sys
from setuptools import Command from setuptools import Command
import distutils.errors
from distutils import log
from setuptools.command.sdist import sdist from setuptools.command.sdist import sdist
from setuptools.compat import basestring, PY3, StringIO from setuptools.compat import basestring, PY3, StringIO
from setuptools import svn_utils from setuptools import svn_utils
from distutils.util import convert_path
from distutils.filelist import FileList as _FileList
from pkg_resources import (parse_requirements, safe_name, parse_version,
safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
from setuptools.command.sdist import walk_revctrl from setuptools.command.sdist import walk_revctrl
from pkg_resources import (
parse_requirements, safe_name, parse_version,
safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
import setuptools.unicode_utils as unicode_utils import setuptools.unicode_utils as unicode_utils
...@@ -27,11 +28,11 @@ class egg_info(Command): ...@@ -27,11 +28,11 @@ class egg_info(Command):
('egg-base=', 'e', "directory containing .egg-info directories" ('egg-base=', 'e', "directory containing .egg-info directories"
" (default: top of the source tree)"), " (default: top of the source tree)"),
('tag-svn-revision', 'r', ('tag-svn-revision', 'r',
"Add subversion revision ID to version number"), "Add subversion revision ID to version number"),
('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
('tag-build=', 'b', "Specify explicit tag to add to version number"), ('tag-build=', 'b', "Specify explicit tag to add to version number"),
('no-svn-revision', 'R', ('no-svn-revision', 'R',
"Don't add subversion revision ID [default]"), "Don't add subversion revision ID [default]"),
('no-date', 'D', "Don't include date stamp [default]"), ('no-date', 'D', "Don't include date stamp [default]"),
] ]
...@@ -52,6 +53,7 @@ class egg_info(Command): ...@@ -52,6 +53,7 @@ class egg_info(Command):
def save_version_info(self, filename): def save_version_info(self, filename):
from setuptools.command.setopt import edit_config from setuptools.command.setopt import edit_config
values = dict( values = dict(
egg_info=dict( egg_info=dict(
tag_svn_revision=0, tag_svn_revision=0,
...@@ -68,23 +70,25 @@ class egg_info(Command): ...@@ -68,23 +70,25 @@ class egg_info(Command):
try: try:
list( list(
parse_requirements('%s==%s' % (self.egg_name,self.egg_version)) parse_requirements('%s==%s' % (self.egg_name,
self.egg_version))
) )
except ValueError: except ValueError:
raise distutils.errors.DistutilsOptionError( raise distutils.errors.DistutilsOptionError(
"Invalid distribution name or version syntax: %s-%s" % "Invalid distribution name or version syntax: %s-%s" %
(self.egg_name,self.egg_version) (self.egg_name, self.egg_version)
) )
if self.egg_base is None: if self.egg_base is None:
dirs = self.distribution.package_dir dirs = self.distribution.package_dir
self.egg_base = (dirs or {}).get('',os.curdir) self.egg_base = (dirs or {}).get('', os.curdir)
self.ensure_dirname('egg_base') self.ensure_dirname('egg_base')
self.egg_info = to_filename(self.egg_name)+'.egg-info' self.egg_info = to_filename(self.egg_name) + '.egg-info'
if self.egg_base != os.curdir: if self.egg_base != os.curdir:
self.egg_info = os.path.join(self.egg_base, self.egg_info) self.egg_info = os.path.join(self.egg_base, self.egg_info)
if '-' in self.egg_name: self.check_broken_egg_info() if '-' in self.egg_name:
self.check_broken_egg_info()
# Set package version for the benefit of dumber commands # Set package version for the benefit of dumber commands
# (e.g. sdist, bdist_wininst, etc.) # (e.g. sdist, bdist_wininst, etc.)
...@@ -96,7 +100,7 @@ class egg_info(Command): ...@@ -96,7 +100,7 @@ class egg_info(Command):
# to the version info # to the version info
# #
pd = self.distribution._patched_dist pd = self.distribution._patched_dist
if pd is not None and pd.key==self.egg_name.lower(): if pd is not None and pd.key == self.egg_name.lower():
pd._version = self.egg_version pd._version = self.egg_version
pd._parsed_version = parse_version(self.egg_version) pd._parsed_version = parse_version(self.egg_version)
self.distribution._patched_dist = None self.distribution._patched_dist = None
...@@ -154,7 +158,7 @@ class egg_info(Command): ...@@ -154,7 +158,7 @@ class egg_info(Command):
installer = self.distribution.fetch_build_egg installer = self.distribution.fetch_build_egg
for ep in iter_entry_points('egg_info.writers'): for ep in iter_entry_points('egg_info.writers'):
writer = ep.load(installer=installer) writer = ep.load(installer=installer)
writer(self, ep.name, os.path.join(self.egg_info,ep.name)) writer(self, ep.name, os.path.join(self.egg_info, ep.name))
# Get rid of native_libs.txt if it was put there by older bdist_egg # Get rid of native_libs.txt if it was put there by older bdist_egg
nl = os.path.join(self.egg_info, "native_libs.txt") nl = os.path.join(self.egg_info, "native_libs.txt")
...@@ -166,12 +170,14 @@ class egg_info(Command): ...@@ -166,12 +170,14 @@ class egg_info(Command):
def tags(self): def tags(self):
version = '' version = ''
if self.tag_build: if self.tag_build:
version+=self.tag_build version += self.tag_build
if self.tag_svn_revision and ( if self.tag_svn_revision and (
os.path.exists('.svn') or os.path.exists('PKG-INFO') os.path.exists('.svn') or os.path.exists('PKG-INFO')
): version += '-r%s' % self.get_svn_revision() ):
version += '-r%s' % self.get_svn_revision()
if self.tag_date: if self.tag_date:
import time import time
version += time.strftime("-%Y%m%d") version += time.strftime("-%Y%m%d")
return version return version
...@@ -181,32 +187,33 @@ class egg_info(Command): ...@@ -181,32 +187,33 @@ class egg_info(Command):
def find_sources(self): def find_sources(self):
"""Generate SOURCES.txt manifest file""" """Generate SOURCES.txt manifest file"""
manifest_filename = os.path.join(self.egg_info,"SOURCES.txt") manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
mm = manifest_maker(self.distribution) mm = manifest_maker(self.distribution)
mm.manifest = manifest_filename mm.manifest = manifest_filename
mm.run() mm.run()
self.filelist = mm.filelist self.filelist = mm.filelist
def check_broken_egg_info(self): def check_broken_egg_info(self):
bei = self.egg_name+'.egg-info' bei = self.egg_name + '.egg-info'
if self.egg_base != os.curdir: if self.egg_base != os.curdir:
bei = os.path.join(self.egg_base, bei) bei = os.path.join(self.egg_base, bei)
if os.path.exists(bei): if os.path.exists(bei):
log.warn( log.warn(
"-"*78+'\n' "-" * 78 + '\n'
"Note: Your current .egg-info directory has a '-' in its name;" "Note: Your current .egg-info directory has a '-' in its name;"
'\nthis will not work correctly with "setup.py develop".\n\n' '\nthis will not work correctly with "setup.py develop".\n\n'
'Please rename %s to %s to correct this problem.\n'+'-'*78, 'Please rename %s to %s to correct this problem.\n' + '-' * 78,
bei, self.egg_info bei, self.egg_info
) )
self.broken_egg_info = self.egg_info self.broken_egg_info = self.egg_info
self.egg_info = bei # make it work for now self.egg_info = bei # make it work for now
class FileList(_FileList): class FileList(_FileList):
"""File list that accepts only existing, platform-independent paths""" """File list that accepts only existing, platform-independent paths"""
def append(self, item): def append(self, item):
if item.endswith('\r'): # Fix older sdists built on Windows if item.endswith('\r'): # Fix older sdists built on Windows
item = item[:-1] item = item[:-1]
path = convert_path(item) path = convert_path(item)
...@@ -229,29 +236,28 @@ class FileList(_FileList): ...@@ -229,29 +236,28 @@ class FileList(_FileList):
def _safe_path(self, path): def _safe_path(self, path):
enc_warn = "'%s' not %s encodable -- skipping" enc_warn = "'%s' not %s encodable -- skipping"
#To avoid accidental trans-codings errors, first to unicode # To avoid accidental trans-codings errors, first to unicode
u_path = unicode_utils.filesys_decode(path) u_path = unicode_utils.filesys_decode(path)
if u_path is None: if u_path is None:
log.warn("'%s' in unexpected encoding -- skipping" % path) log.warn("'%s' in unexpected encoding -- skipping" % path)
return False return False
#Must ensure utf-8 encodability # Must ensure utf-8 encodability
utf8_path = unicode_utils.try_encode(u_path, "utf-8") utf8_path = unicode_utils.try_encode(u_path, "utf-8")
if utf8_path is None: if utf8_path is None:
log.warn(enc_warn, path, 'utf-8') log.warn(enc_warn, path, 'utf-8')
return False return False
try: try:
#accept is either way checks out # accept is either way checks out
if os.path.exists(u_path) or os.path.exists(utf8_path): if os.path.exists(u_path) or os.path.exists(utf8_path):
return True return True
#this will catch any encode errors decoding u_path # this will catch any encode errors decoding u_path
except UnicodeEncodeError: except UnicodeEncodeError:
log.warn(enc_warn, path, sys.getfilesystemencoding()) log.warn(enc_warn, path, sys.getfilesystemencoding())
class manifest_maker(sdist): class manifest_maker(sdist):
template = "MANIFEST.in" template = "MANIFEST.in"
def initialize_options(self): def initialize_options(self):
...@@ -266,7 +272,7 @@ class manifest_maker(sdist): ...@@ -266,7 +272,7 @@ class manifest_maker(sdist):
def run(self): def run(self):
self.filelist = FileList() self.filelist = FileList()
if not os.path.exists(self.manifest): if not os.path.exists(self.manifest):
self.write_manifest() # it must exist so it'll get in the list self.write_manifest() # it must exist so it'll get in the list
self.filelist.findall() self.filelist.findall()
self.add_defaults() self.add_defaults()
if os.path.exists(self.template): if os.path.exists(self.template):
...@@ -287,12 +293,12 @@ class manifest_maker(sdist): ...@@ -287,12 +293,12 @@ class manifest_maker(sdist):
""" """
self.filelist._repair() self.filelist._repair()
#Now _repairs should encodability, but not unicode # Now _repairs should encodability, but not unicode
files = [self._manifest_normalize(f) for f in self.filelist.files] files = [self._manifest_normalize(f) for f in self.filelist.files]
msg = "writing manifest file '%s'" % self.manifest msg = "writing manifest file '%s'" % self.manifest
self.execute(write_file, (self.manifest, files), msg) self.execute(write_file, (self.manifest, files), msg)
def warn(self, msg): # suppress missing-file warnings from sdist def warn(self, msg): # suppress missing-file warnings from sdist
if not msg.startswith("standard file not found:"): if not msg.startswith("standard file not found:"):
sdist.warn(self, msg) sdist.warn(self, msg)
...@@ -314,7 +320,8 @@ class manifest_maker(sdist): ...@@ -314,7 +320,8 @@ class manifest_maker(sdist):
self.filelist.exclude_pattern(None, prefix=build.build_base) self.filelist.exclude_pattern(None, prefix=build.build_base)
self.filelist.exclude_pattern(None, prefix=base_dir) self.filelist.exclude_pattern(None, prefix=base_dir)
sep = re.escape(os.sep) sep = re.escape(os.sep)
self.filelist.exclude_pattern(sep+r'(RCS|CVS|\.svn)'+sep, is_regex=1) self.filelist.exclude_pattern(sep + r'(RCS|CVS|\.svn)' + sep,
is_regex=1)
def write_file(filename, contents): def write_file(filename, contents):
...@@ -323,10 +330,10 @@ def write_file(filename, contents): ...@@ -323,10 +330,10 @@ def write_file(filename, contents):
""" """
contents = "\n".join(contents) contents = "\n".join(contents)
#assuming the contents has been vetted for utf-8 encoding # assuming the contents has been vetted for utf-8 encoding
contents = contents.encode("utf-8") contents = contents.encode("utf-8")
with open(filename, "wb") as f: # always write POSIX-style manifest with open(filename, "wb") as f: # always write POSIX-style manifest
f.write(contents) f.write(contents)
...@@ -343,10 +350,12 @@ def write_pkg_info(cmd, basename, filename): ...@@ -343,10 +350,12 @@ def write_pkg_info(cmd, basename, filename):
finally: finally:
metadata.name, metadata.version = oldname, oldver metadata.name, metadata.version = oldname, oldver
safe = getattr(cmd.distribution,'zip_safe',None) safe = getattr(cmd.distribution, 'zip_safe', None)
from setuptools.command import bdist_egg from setuptools.command import bdist_egg
bdist_egg.write_safety_flag(cmd.egg_info, safe) bdist_egg.write_safety_flag(cmd.egg_info, safe)
def warn_depends_obsolete(cmd, basename, filename): def warn_depends_obsolete(cmd, basename, filename):
if os.path.exists(filename): if os.path.exists(filename):
log.warn( log.warn(
...@@ -361,6 +370,7 @@ def _write_requirements(stream, reqs): ...@@ -361,6 +370,7 @@ def _write_requirements(stream, reqs):
lines = map(append_cr, lines) lines = map(append_cr, lines)
stream.writelines(lines) stream.writelines(lines)
def write_requirements(cmd, basename, filename): def write_requirements(cmd, basename, filename):
dist = cmd.distribution dist = cmd.distribution
data = StringIO() data = StringIO()
...@@ -371,48 +381,52 @@ def write_requirements(cmd, basename, filename): ...@@ -371,48 +381,52 @@ def write_requirements(cmd, basename, filename):
_write_requirements(data, extras_require[extra]) _write_requirements(data, extras_require[extra])
cmd.write_or_delete_file("requirements", filename, data.getvalue()) cmd.write_or_delete_file("requirements", filename, data.getvalue())
def write_toplevel_names(cmd, basename, filename): def write_toplevel_names(cmd, basename, filename):
pkgs = dict.fromkeys( pkgs = dict.fromkeys(
[ [
k.split('.',1)[0] k.split('.', 1)[0]
for k in cmd.distribution.iter_distribution_names() for k in cmd.distribution.iter_distribution_names()
] ]
) )
cmd.write_file("top-level names", filename, '\n'.join(pkgs)+'\n') cmd.write_file("top-level names", filename, '\n'.join(pkgs) + '\n')
def overwrite_arg(cmd, basename, filename): def overwrite_arg(cmd, basename, filename):
write_arg(cmd, basename, filename, True) write_arg(cmd, basename, filename, True)
def write_arg(cmd, basename, filename, force=False): def write_arg(cmd, basename, filename, force=False):
argname = os.path.splitext(basename)[0] argname = os.path.splitext(basename)[0]
value = getattr(cmd.distribution, argname, None) value = getattr(cmd.distribution, argname, None)
if value is not None: if value is not None:
value = '\n'.join(value)+'\n' value = '\n'.join(value) + '\n'
cmd.write_or_delete_file(argname, filename, value, force) cmd.write_or_delete_file(argname, filename, value, force)
def write_entries(cmd, basename, filename): def write_entries(cmd, basename, filename):
ep = cmd.distribution.entry_points ep = cmd.distribution.entry_points
if isinstance(ep,basestring) or ep is None: if isinstance(ep, basestring) or ep is None:
data = ep data = ep
elif ep is not None: elif ep is not None:
data = [] data = []
for section, contents in sorted(ep.items()): for section, contents in sorted(ep.items()):
if not isinstance(contents,basestring): if not isinstance(contents, basestring):
contents = EntryPoint.parse_group(section, contents) contents = EntryPoint.parse_group(section, contents)
contents = '\n'.join(sorted(map(str,contents.values()))) contents = '\n'.join(sorted(map(str, contents.values())))
data.append('[%s]\n%s\n\n' % (section,contents)) data.append('[%s]\n%s\n\n' % (section, contents))
data = ''.join(data) data = ''.join(data)
cmd.write_or_delete_file('entry points', filename, data, True) cmd.write_or_delete_file('entry points', filename, data, True)
def get_pkg_info_revision(): def get_pkg_info_revision():
# See if we can get a -r### off of PKG-INFO, in case this is an sdist of # See if we can get a -r### off of PKG-INFO, in case this is an sdist of
# a subversion revision # a subversion revision
# #
if os.path.exists('PKG-INFO'): if os.path.exists('PKG-INFO'):
f = open('PKG-INFO','rU') f = open('PKG-INFO', 'rU')
for line in f: for line in f:
match = re.match(r"Version:.*-r(\d+)\s*$", line) match = re.match(r"Version:.*-r(\d+)\s*$", line)
if match: if match:
......
import setuptools from distutils.errors import DistutilsArgError
import inspect import inspect
import glob import glob
import warnings import warnings
import platform import platform
import distutils.command.install as orig import distutils.command.install as orig
from distutils.errors import DistutilsArgError
import setuptools
# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for # Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for
# now. See https://bitbucket.org/pypa/setuptools/issue/199/ # now. See https://bitbucket.org/pypa/setuptools/issue/199/
_install = orig.install _install = orig.install
class install(orig.install): class install(orig.install):
"""Use easy_install to install the package, w/dependencies""" """Use easy_install to install the package, w/dependencies"""
user_options = orig.install.user_options + [ user_options = orig.install.user_options + [
('old-and-unmanageable', None, "Try not to use this!"), ('old-and-unmanageable', None, "Try not to use this!"),
('single-version-externally-managed', None, ('single-version-externally-managed', None,
"used by system package builders to create 'flat' eggs"), "used by system package builders to create 'flat' eggs"),
] ]
boolean_options = orig.install.boolean_options + [ boolean_options = orig.install.boolean_options + [
'old-and-unmanageable', 'single-version-externally-managed', 'old-and-unmanageable', 'single-version-externally-managed',
...@@ -115,7 +117,9 @@ class install(orig.install): ...@@ -115,7 +117,9 @@ class install(orig.install):
cmd.run() cmd.run()
setuptools.bootstrap_install_from = None setuptools.bootstrap_install_from = None
# XXX Python 3.1 doesn't see _nc if this is inside the class # XXX Python 3.1 doesn't see _nc if this is inside the class
install.sub_commands = [ install.sub_commands = (
cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] +
] + install.new_commands install.new_commands
)
from distutils import log, dir_util
import os
from setuptools import Command from setuptools import Command
from setuptools.archive_util import unpack_archive from setuptools.archive_util import unpack_archive
from distutils import log, dir_util import pkg_resources
import os, pkg_resources
class install_egg_info(Command): class install_egg_info(Command):
"""Install an .egg-info directory for the package""" """Install an .egg-info directory for the package"""
...@@ -16,11 +19,12 @@ class install_egg_info(Command): ...@@ -16,11 +19,12 @@ class install_egg_info(Command):
self.install_dir = None self.install_dir = None
def finalize_options(self): def finalize_options(self):
self.set_undefined_options('install_lib',('install_dir','install_dir')) self.set_undefined_options('install_lib',
('install_dir', 'install_dir'))
ei_cmd = self.get_finalized_command("egg_info") ei_cmd = self.get_finalized_command("egg_info")
basename = pkg_resources.Distribution( basename = pkg_resources.Distribution(
None, None, ei_cmd.egg_name, ei_cmd.egg_version None, None, ei_cmd.egg_name, ei_cmd.egg_version
).egg_name()+'.egg-info' ).egg_name() + '.egg-info'
self.source = ei_cmd.egg_info self.source = ei_cmd.egg_info
self.target = os.path.join(self.install_dir, basename) self.target = os.path.join(self.install_dir, basename)
self.outputs = [self.target] self.outputs = [self.target]
...@@ -31,11 +35,11 @@ class install_egg_info(Command): ...@@ -31,11 +35,11 @@ class install_egg_info(Command):
if os.path.isdir(self.target) and not os.path.islink(self.target): if os.path.isdir(self.target) and not os.path.islink(self.target):
dir_util.remove_tree(self.target, dry_run=self.dry_run) dir_util.remove_tree(self.target, dry_run=self.dry_run)
elif os.path.exists(self.target): elif os.path.exists(self.target):
self.execute(os.unlink,(self.target,),"Removing "+self.target) self.execute(os.unlink, (self.target,), "Removing " + self.target)
if not self.dry_run: if not self.dry_run:
pkg_resources.ensure_directory(self.target) pkg_resources.ensure_directory(self.target)
self.execute(self.copytree, (), self.execute(
"Copying %s to %s" % (self.source, self.target) self.copytree, (), "Copying %s to %s" % (self.source, self.target)
) )
self.install_namespaces() self.install_namespaces()
...@@ -44,50 +48,29 @@ class install_egg_info(Command): ...@@ -44,50 +48,29 @@ class install_egg_info(Command):
def copytree(self): def copytree(self):
# Copy the .egg-info tree to site-packages # Copy the .egg-info tree to site-packages
def skimmer(src,dst): def skimmer(src, dst):
# filter out source-control directories; note that 'src' is always # filter out source-control directories; note that 'src' is always
# a '/'-separated path, regardless of platform. 'dst' is a # a '/'-separated path, regardless of platform. 'dst' is a
# platform-specific path. # platform-specific path.
for skip in '.svn/','CVS/': for skip in '.svn/', 'CVS/':
if src.startswith(skip) or '/'+skip in src: if src.startswith(skip) or '/' + skip in src:
return None return None
self.outputs.append(dst) self.outputs.append(dst)
log.debug("Copying %s to %s", src, dst) log.debug("Copying %s to %s", src, dst)
return dst return dst
unpack_archive(self.source, self.target, skimmer)
unpack_archive(self.source, self.target, skimmer)
def install_namespaces(self): def install_namespaces(self):
nsp = self._get_all_ns_packages() nsp = self._get_all_ns_packages()
if not nsp: return if not nsp:
filename,ext = os.path.splitext(self.target) return
filename += '-nspkg.pth'; self.outputs.append(filename) filename, ext = os.path.splitext(self.target)
log.info("Installing %s",filename) filename += '-nspkg.pth'
self.outputs.append(filename)
log.info("Installing %s", filename)
if not self.dry_run: if not self.dry_run:
f = open(filename,'wt') f = open(filename, 'wt')
for pkg in nsp: for pkg in nsp:
# ensure pkg is not a unicode string under Python 2.7 # ensure pkg is not a unicode string under Python 2.7
pkg = str(pkg) pkg = str(pkg)
...@@ -101,10 +84,11 @@ class install_egg_info(Command): ...@@ -101,10 +84,11 @@ class install_egg_info(Command):
f.write( f.write(
"import sys,types,os; " "import sys,types,os; "
"p = os.path.join(sys._getframe(1).f_locals['sitedir'], " "p = os.path.join(sys._getframe(1).f_locals['sitedir'], "
"*%(pth)r); " "*%(pth)r); "
"ie = os.path.exists(os.path.join(p,'__init__.py')); " "ie = os.path.exists(os.path.join(p,'__init__.py')); "
"m = not ie and " "m = not ie and "
"sys.modules.setdefault(%(pkg)r,types.ModuleType(%(pkg)r)); " "sys.modules.setdefault(%(pkg)r,types.ModuleType"
"(%(pkg)r)); "
"mp = (m or []) and m.__dict__.setdefault('__path__',[]); " "mp = (m or []) and m.__dict__.setdefault('__path__',[]); "
"(p not in mp) and mp.append(p)%(trailer)s" "(p not in mp) and mp.append(p)%(trailer)s"
% locals() % locals()
...@@ -118,8 +102,6 @@ class install_egg_info(Command): ...@@ -118,8 +102,6 @@ class install_egg_info(Command):
while pkg: while pkg:
nsp['.'.join(pkg)] = 1 nsp['.'.join(pkg)] = 1
pkg.pop() pkg.pop()
nsp=list(nsp) nsp = list(nsp)
nsp.sort() # set up shorter names first nsp.sort() # set up shorter names first
return nsp return nsp
import distutils.command.install_lib as orig import distutils.command.install_lib as orig
import os import os
class install_lib(orig.install_lib): class install_lib(orig.install_lib):
"""Don't add compiled flags to filenames of non-Python files""" """Don't add compiled flags to filenames of non-Python files"""
...@@ -15,20 +16,20 @@ class install_lib(orig.install_lib): ...@@ -15,20 +16,20 @@ class install_lib(orig.install_lib):
exclude = {} exclude = {}
nsp = self.distribution.namespace_packages nsp = self.distribution.namespace_packages
svem = (nsp and self.get_finalized_command('install') svem = (nsp and self.get_finalized_command('install')
.single_version_externally_managed) .single_version_externally_managed)
if svem: if svem:
for pkg in nsp: for pkg in nsp:
parts = pkg.split('.') parts = pkg.split('.')
while parts: while parts:
pkgdir = os.path.join(self.install_dir, *parts) pkgdir = os.path.join(self.install_dir, *parts)
for f in '__init__.py', '__init__.pyc', '__init__.pyo': for f in '__init__.py', '__init__.pyc', '__init__.pyo':
exclude[os.path.join(pkgdir,f)] = 1 exclude[os.path.join(pkgdir, f)] = 1
parts.pop() parts.pop()
return exclude return exclude
def copy_tree( def copy_tree(
self, infile, outfile, self, infile, outfile,
preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1
): ):
assert preserve_mode and preserve_times and not preserve_symlinks assert preserve_mode and preserve_times and not preserve_symlinks
exclude = self.get_exclusions() exclude = self.get_exclusions()
...@@ -45,7 +46,8 @@ class install_lib(orig.install_lib): ...@@ -45,7 +46,8 @@ class install_lib(orig.install_lib):
def pf(src, dst): def pf(src, dst):
if dst in exclude: if dst in exclude:
log.warn("Skipping installation of %s (namespace package)",dst) log.warn("Skipping installation of %s (namespace package)",
dst)
return False return False
log.info("copying %s -> %s", src, os.path.dirname(dst)) log.info("copying %s -> %s", src, os.path.dirname(dst))
......
from distutils import log
import distutils.command.install_scripts as orig import distutils.command.install_scripts as orig
from pkg_resources import Distribution, PathMetadata, ensure_directory
import os import os
from distutils import log
from pkg_resources import Distribution, PathMetadata, ensure_directory
class install_scripts(orig.install_scripts): class install_scripts(orig.install_scripts):
"""Do normal script install, plus any egg_info wrapper scripts""" """Do normal script install, plus any egg_info wrapper scripts"""
...@@ -29,7 +31,7 @@ class install_scripts(orig.install_scripts): ...@@ -29,7 +31,7 @@ class install_scripts(orig.install_scripts):
ei_cmd.egg_name, ei_cmd.egg_version, ei_cmd.egg_name, ei_cmd.egg_version,
) )
bs_cmd = self.get_finalized_command('build_scripts') bs_cmd = self.get_finalized_command('build_scripts')
executable = getattr(bs_cmd,'executable',sys_executable) executable = getattr(bs_cmd, 'executable', sys_executable)
is_wininst = getattr( is_wininst = getattr(
self.get_finalized_command("bdist_wininst"), '_is_running', False self.get_finalized_command("bdist_wininst"), '_is_running', False
) )
...@@ -39,6 +41,7 @@ class install_scripts(orig.install_scripts): ...@@ -39,6 +41,7 @@ class install_scripts(orig.install_scripts):
def write_script(self, script_name, contents, mode="t", *ignored): def write_script(self, script_name, contents, mode="t", *ignored):
"""Write an executable file to the scripts directory""" """Write an executable file to the scripts directory"""
from setuptools.command.easy_install import chmod, current_umask from setuptools.command.easy_install import chmod, current_umask
log.info("Installing %s script to %s", script_name, self.install_dir) log.info("Installing %s script to %s", script_name, self.install_dir)
target = os.path.join(self.install_dir, script_name) target = os.path.join(self.install_dir, script_name)
self.outfiles.append(target) self.outfiles.append(target)
...@@ -46,7 +49,7 @@ class install_scripts(orig.install_scripts): ...@@ -46,7 +49,7 @@ class install_scripts(orig.install_scripts):
mask = current_umask() mask = current_umask()
if not self.dry_run: if not self.dry_run:
ensure_directory(target) ensure_directory(target)
f = open(target,"w"+mode) f = open(target, "w" + mode)
f.write(contents) f.write(contents)
f.close() f.close()
chmod(target, 0o777-mask) chmod(target, 0o777 - mask)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" <assemblyIdentity version="1.0.0.0"
processorArchitecture="X86" processorArchitecture="X86"
name="%(name)s" name="%(name)s"
type="win32"/> type="win32"/>
<!-- Identify the application security requirements. --> <!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security> <security>
<requestedPrivileges> <requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/> <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges> </requestedPrivileges>
</security> </security>
</trustInfo> </trustInfo>
</assembly> </assembly>
import distutils.command.register as orig import distutils.command.register as orig
class register(orig.register): class register(orig.register):
__doc__ = orig.register.__doc__ __doc__ = orig.register.__doc__
......
import os
from setuptools import Command
from setuptools.compat import basestring
from distutils.util import convert_path from distutils.util import convert_path
from distutils import log from distutils import log
from distutils.errors import DistutilsOptionError from distutils.errors import DistutilsOptionError
import os
from setuptools import Command
from setuptools.compat import basestring
class rotate(Command): class rotate(Command):
"""Delete older distributions""" """Delete older distributions"""
description = "delete older distributions, keeping N newest files" description = "delete older distributions, keeping N newest files"
user_options = [ user_options = [
('match=', 'm', "patterns to match (required)"), ('match=', 'm', "patterns to match (required)"),
('dist-dir=', 'd', "directory where the distributions are"), ('dist-dir=', 'd', "directory where the distributions are"),
('keep=', 'k', "number of matching distributions to keep"), ('keep=', 'k', "number of matching distributions to keep"),
] ]
boolean_options = [] boolean_options = []
...@@ -38,21 +40,22 @@ class rotate(Command): ...@@ -38,21 +40,22 @@ class rotate(Command):
self.match = [ self.match = [
convert_path(p.strip()) for p in self.match.split(',') convert_path(p.strip()) for p in self.match.split(',')
] ]
self.set_undefined_options('bdist',('dist_dir', 'dist_dir')) self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
def run(self): def run(self):
self.run_command("egg_info") self.run_command("egg_info")
from glob import glob from glob import glob
for pattern in self.match: for pattern in self.match:
pattern = self.distribution.get_name()+'*'+pattern pattern = self.distribution.get_name() + '*' + pattern
files = glob(os.path.join(self.dist_dir,pattern)) files = glob(os.path.join(self.dist_dir, pattern))
files = [(os.path.getmtime(f),f) for f in files] files = [(os.path.getmtime(f), f) for f in files]
files.sort() files.sort()
files.reverse() files.reverse()
log.info("%d file(s) matching %s", len(files), pattern) log.info("%d file(s) matching %s", len(files), pattern)
files = files[self.keep:] files = files[self.keep:]
for (t,f) in files: for (t, f) in files:
log.info("Deleting %s", f) log.info("Deleting %s", f)
if not self.dry_run: if not self.dry_run:
os.unlink(f) os.unlink(f)
import distutils, os
from setuptools import Command
from setuptools.command.setopt import edit_config, option_base from setuptools.command.setopt import edit_config, option_base
class saveopts(option_base): class saveopts(option_base):
"""Save command-line options to a file""" """Save command-line options to a file"""
...@@ -13,12 +12,11 @@ class saveopts(option_base): ...@@ -13,12 +12,11 @@ class saveopts(option_base):
for cmd in dist.command_options: for cmd in dist.command_options:
if cmd=='saveopts': if cmd == 'saveopts':
continue # don't save our own options! continue # don't save our own options!
for opt,(src,val) in dist.get_option_dict(cmd).items(): for opt, (src, val) in dist.get_option_dict(cmd).items():
if src=="command line": if src == "command line":
settings.setdefault(cmd,{})[opt] = val settings.setdefault(cmd, {})[opt] = val
edit_config(self.filename, settings, self.dry_run) edit_config(self.filename, settings, self.dry_run)
from glob import glob
from distutils.util import convert_path
from distutils import log
import distutils.command.sdist as orig
import os import os
import re import re
import sys import sys
from glob import glob
import pkg_resources
import distutils.command.sdist as orig
from distutils.util import convert_path
from distutils import log
from setuptools import svn_utils from setuptools import svn_utils
from setuptools.compat import PY3 from setuptools.compat import PY3
import pkg_resources
READMES = ('README', 'README.rst', 'README.txt') READMES = ('README', 'README.rst', 'README.txt')
...@@ -20,7 +20,7 @@ def walk_revctrl(dirname=''): ...@@ -20,7 +20,7 @@ def walk_revctrl(dirname=''):
yield item yield item
#TODO will need test case # TODO will need test case
class re_finder(object): class re_finder(object):
""" """
Finder that locates files based on entries in a file matched by a Finder that locates files based on entries in a file matched by a
...@@ -33,7 +33,7 @@ class re_finder(object): ...@@ -33,7 +33,7 @@ class re_finder(object):
self.entries_path = convert_path(path) self.entries_path = convert_path(path)
def _finder(self, dirname, filename): def _finder(self, dirname, filename):
f = open(filename,'rU') f = open(filename, 'rU')
try: try:
data = f.read() data = f.read()
finally: finally:
...@@ -51,12 +51,13 @@ class re_finder(object): ...@@ -51,12 +51,13 @@ class re_finder(object):
if not os.path.isfile(path): if not os.path.isfile(path):
# entries file doesn't exist # entries file doesn't exist
return return
for path in self._finder(dirname,path): for path in self._finder(dirname, path):
if os.path.isfile(path): if os.path.isfile(path):
yield path yield path
elif os.path.isdir(path): elif os.path.isdir(path):
for item in self.find(path): for item in self.find(path):
yield item yield item
__call__ = find __call__ = find
...@@ -85,7 +86,7 @@ class sdist(orig.sdist): ...@@ -85,7 +86,7 @@ class sdist(orig.sdist):
('dist-dir=', 'd', ('dist-dir=', 'd',
"directory to put the source distribution archive(s) in " "directory to put the source distribution archive(s) in "
"[default: dist]"), "[default: dist]"),
] ]
negative_opt = {} negative_opt = {}
...@@ -93,7 +94,7 @@ class sdist(orig.sdist): ...@@ -93,7 +94,7 @@ class sdist(orig.sdist):
self.run_command('egg_info') self.run_command('egg_info')
ei_cmd = self.get_finalized_command('egg_info') ei_cmd = self.get_finalized_command('egg_info')
self.filelist = ei_cmd.filelist self.filelist = ei_cmd.filelist
self.filelist.append(os.path.join(ei_cmd.egg_info,'SOURCES.txt')) self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))
self.check_readme() self.check_readme()
# Run sub commands # Run sub commands
...@@ -103,12 +104,13 @@ class sdist(orig.sdist): ...@@ -103,12 +104,13 @@ class sdist(orig.sdist):
# Call check_metadata only if no 'check' command # Call check_metadata only if no 'check' command
# (distutils <= 2.6) # (distutils <= 2.6)
import distutils.command import distutils.command
if 'check' not in distutils.command.__all__: if 'check' not in distutils.command.__all__:
self.check_metadata() self.check_metadata()
self.make_distribution() self.make_distribution()
dist_files = getattr(self.distribution,'dist_files',[]) dist_files = getattr(self.distribution, 'dist_files', [])
for file in self.archive_files: for file in self.archive_files:
data = ('sdist', '', file) data = ('sdist', '', file)
if data not in dist_files: if data not in dist_files:
...@@ -124,13 +126,14 @@ class sdist(orig.sdist): ...@@ -124,13 +126,14 @@ class sdist(orig.sdist):
except: except:
sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close() sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
raise raise
# Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle # 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 # has been fixed, so only override the method if we're using an earlier
# Python. # Python.
has_leaky_handle = ( has_leaky_handle = (
sys.version_info < (2,7,2) sys.version_info < (2, 7, 2)
or (3,0) <= sys.version_info < (3,1,4) or (3, 0) <= sys.version_info < (3, 1, 4)
or (3,2) <= sys.version_info < (3,2,1) or (3, 2) <= sys.version_info < (3, 2, 1)
) )
if has_leaky_handle: if has_leaky_handle:
read_template = __read_template_hack read_template = __read_template_hack
...@@ -194,7 +197,8 @@ class sdist(orig.sdist): ...@@ -194,7 +197,8 @@ class sdist(orig.sdist):
return return
else: else:
self.warn( self.warn(
"standard file not found: should have one of " +', '.join(READMES) "standard file not found: should have one of " +
', '.join(READMES)
) )
def make_release_tree(self, base_dir, files): def make_release_tree(self, base_dir, files):
...@@ -202,7 +206,7 @@ class sdist(orig.sdist): ...@@ -202,7 +206,7 @@ class sdist(orig.sdist):
# Save any egg_info command line options used to create this sdist # Save any egg_info command line options used to create this sdist
dest = os.path.join(base_dir, 'setup.cfg') dest = os.path.join(base_dir, 'setup.cfg')
if hasattr(os,'link') and os.path.exists(dest): if hasattr(os, 'link') and os.path.exists(dest):
# unlink and re-copy, since it might be hard-linked, and # unlink and re-copy, since it might be hard-linked, and
# we don't want to change the source version # we don't want to change the source version
os.unlink(dest) os.unlink(dest)
...@@ -220,7 +224,8 @@ class sdist(orig.sdist): ...@@ -220,7 +224,8 @@ class sdist(orig.sdist):
first_line = fp.readline() first_line = fp.readline()
finally: finally:
fp.close() fp.close()
return first_line != '# file GENERATED by distutils, do NOT edit\n'.encode() return (first_line !=
'# file GENERATED by distutils, do NOT edit\n'.encode())
def read_manifest(self): def read_manifest(self):
"""Read the manifest file (named by 'self.manifest') and use it to """Read the manifest file (named by 'self.manifest') and use it to
......
import os
import distutils
from setuptools import Command
from distutils.util import convert_path from distutils.util import convert_path
from distutils import log from distutils import log
from distutils.errors import DistutilsOptionError from distutils.errors import DistutilsOptionError
import distutils
import os
from setuptools import Command
__all__ = ['config_file', 'edit_config', 'option_base', 'setopt'] __all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
...@@ -13,19 +15,20 @@ def config_file(kind="local"): ...@@ -13,19 +15,20 @@ def config_file(kind="local"):
`kind` must be one of "local", "global", or "user" `kind` must be one of "local", "global", or "user"
""" """
if kind=='local': if kind == 'local':
return 'setup.cfg' return 'setup.cfg'
if kind=='global': if kind == 'global':
return os.path.join( return os.path.join(
os.path.dirname(distutils.__file__),'distutils.cfg' os.path.dirname(distutils.__file__), 'distutils.cfg'
) )
if kind=='user': if kind == 'user':
dot = os.name=='posix' and '.' or '' dot = os.name == 'posix' and '.' or ''
return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot)) return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot))
raise ValueError( raise ValueError(
"config_file() type must be 'local', 'global', or 'user'", kind "config_file() type must be 'local', 'global', or 'user'", kind
) )
def edit_config(filename, settings, dry_run=False): def edit_config(filename, settings, dry_run=False):
"""Edit a configuration file to include `settings` """Edit a configuration file to include `settings`
...@@ -35,6 +38,7 @@ def edit_config(filename, settings, dry_run=False): ...@@ -35,6 +38,7 @@ def edit_config(filename, settings, dry_run=False):
A setting of ``None`` means to delete that setting. A setting of ``None`` means to delete that setting.
""" """
from setuptools.compat import ConfigParser from setuptools.compat import ConfigParser
log.debug("Reading configuration from %s", filename) log.debug("Reading configuration from %s", filename)
opts = ConfigParser.RawConfigParser() opts = ConfigParser.RawConfigParser()
opts.read([filename]) opts.read([filename])
...@@ -46,39 +50,40 @@ def edit_config(filename, settings, dry_run=False): ...@@ -46,39 +50,40 @@ def edit_config(filename, settings, dry_run=False):
if not opts.has_section(section): if not opts.has_section(section):
log.debug("Adding new section [%s] to %s", section, filename) log.debug("Adding new section [%s] to %s", section, filename)
opts.add_section(section) opts.add_section(section)
for option,value in options.items(): for option, value in options.items():
if value is None: if value is None:
log.debug( log.debug(
"Deleting %s.%s from %s", "Deleting %s.%s from %s",
section, option, filename section, option, filename
) )
opts.remove_option(section,option) opts.remove_option(section, option)
if not opts.options(section): if not opts.options(section):
log.info("Deleting empty [%s] section from %s", log.info("Deleting empty [%s] section from %s",
section, filename) section, filename)
opts.remove_section(section) opts.remove_section(section)
else: else:
log.debug( log.debug(
"Setting %s.%s to %r in %s", "Setting %s.%s to %r in %s",
section, option, value, filename section, option, value, filename
) )
opts.set(section,option,value) opts.set(section, option, value)
log.info("Writing %s", filename) log.info("Writing %s", filename)
if not dry_run: if not dry_run:
with open(filename, 'w') as f: with open(filename, 'w') as f:
opts.write(f) opts.write(f)
class option_base(Command): class option_base(Command):
"""Abstract base class for commands that mess with config files""" """Abstract base class for commands that mess with config files"""
user_options = [ user_options = [
('global-config', 'g', ('global-config', 'g',
"save options to the site-wide distutils.cfg file"), "save options to the site-wide distutils.cfg file"),
('user-config', 'u', ('user-config', 'u',
"save options to the current user's pydistutils.cfg file"), "save options to the current user's pydistutils.cfg file"),
('filename=', 'f', ('filename=', 'f',
"configuration file to use (default=setup.cfg)"), "configuration file to use (default=setup.cfg)"),
] ]
boolean_options = [ boolean_options = [
...@@ -100,7 +105,7 @@ class option_base(Command): ...@@ -100,7 +105,7 @@ class option_base(Command):
filenames.append(self.filename) filenames.append(self.filename)
if not filenames: if not filenames:
filenames.append(config_file('local')) filenames.append(config_file('local'))
if len(filenames)>1: if len(filenames) > 1:
raise DistutilsOptionError( raise DistutilsOptionError(
"Must specify only one configuration file option", "Must specify only one configuration file option",
filenames filenames
...@@ -115,9 +120,9 @@ class setopt(option_base): ...@@ -115,9 +120,9 @@ class setopt(option_base):
user_options = [ user_options = [
('command=', 'c', 'command to set an option for'), ('command=', 'c', 'command to set an option for'),
('option=', 'o', 'option to set'), ('option=', 'o', 'option to set'),
('set-value=', 's', 'value of the option'), ('set-value=', 's', 'value of the option'),
('remove', 'r', 'remove (unset) the value'), ('remove', 'r', 'remove (unset) the value'),
] + option_base.user_options ] + option_base.user_options
boolean_options = option_base.boolean_options + ['remove'] boolean_options = option_base.boolean_options + ['remove']
...@@ -139,7 +144,7 @@ class setopt(option_base): ...@@ -139,7 +144,7 @@ class setopt(option_base):
def run(self): def run(self):
edit_config( edit_config(
self.filename, { self.filename, {
self.command: {self.option.replace('-','_'):self.set_value} self.command: {self.option.replace('-', '_'): self.set_value}
}, },
self.dry_run self.dry_run
) )
import unittest
from unittest import TestLoader
from setuptools import Command
from distutils.errors import DistutilsOptionError from distutils.errors import DistutilsOptionError
from unittest import TestLoader
import unittest
import sys import sys
from pkg_resources import (resource_listdir, resource_exists,
normalize_path, working_set, _namespace_packages, add_activation_listener,
require, EntryPoint)
from pkg_resources import (resource_listdir, resource_exists, normalize_path,
working_set, _namespace_packages,
add_activation_listener, require, EntryPoint)
from setuptools import Command
from setuptools.compat import PY3 from setuptools.compat import PY3
from setuptools.py31compat import unittest_main from setuptools.py31compat import unittest_main
class ScanningLoader(TestLoader): class ScanningLoader(TestLoader):
def loadTestsFromModule(self, module): def loadTestsFromModule(self, module):
"""Return a suite of all tests cases contained in the given module """Return a suite of all tests cases contained in the given module
...@@ -34,7 +32,7 @@ class ScanningLoader(TestLoader): ...@@ -34,7 +32,7 @@ class ScanningLoader(TestLoader):
submodule = module.__name__ + '.' + file[:-3] submodule = module.__name__ + '.' + file[:-3]
else: else:
if resource_exists(module.__name__, file + '/__init__.py'): if resource_exists(module.__name__, file + '/__init__.py'):
submodule = module.__name__+'.'+file submodule = module.__name__ + '.' + file
else: else:
continue continue
tests.append(self.loadTestsFromName(submodule)) tests.append(self.loadTestsFromName(submodule))
...@@ -42,19 +40,18 @@ class ScanningLoader(TestLoader): ...@@ -42,19 +40,18 @@ class ScanningLoader(TestLoader):
if len(tests) != 1: if len(tests) != 1:
return self.suiteClass(tests) return self.suiteClass(tests)
else: else:
return tests[0] # don't create a nested suite for only one return return tests[0] # don't create a nested suite for only one return
class test(Command): class test(Command):
"""Command to run unit tests after in-place build""" """Command to run unit tests after in-place build"""
description = "run unit tests after in-place build" description = "run unit tests after in-place build"
user_options = [ user_options = [
('test-module=','m', "Run 'test_suite' in specified module"), ('test-module=', 'm', "Run 'test_suite' in specified module"),
('test-suite=','s', ('test-suite=', 's',
"Test suite to run (e.g. 'some_module.test_suite')"), "Test suite to run (e.g. 'some_module.test_suite')"),
('test-runner=', 'r', "Test runner to use"), ('test-runner=', 'r', "Test runner to use"),
] ]
...@@ -79,7 +76,7 @@ class test(Command): ...@@ -79,7 +76,7 @@ class test(Command):
self.test_args = [self.test_suite] self.test_args = [self.test_suite]
if self.verbose: if self.verbose:
self.test_args.insert(0,'--verbose') self.test_args.insert(0, '--verbose')
if self.test_loader is None: if self.test_loader is None:
self.test_loader = getattr(self.distribution, 'test_loader', None) self.test_loader = getattr(self.distribution, 'test_loader', None)
if self.test_loader is None: if self.test_loader is None:
...@@ -132,7 +129,8 @@ class test(Command): ...@@ -132,7 +129,8 @@ class test(Command):
def run(self): def run(self):
if self.distribution.install_requires: if self.distribution.install_requires:
self.distribution.fetch_build_eggs(self.distribution.install_requires) self.distribution.fetch_build_eggs(
self.distribution.install_requires)
if self.distribution.tests_require: if self.distribution.tests_require:
self.distribution.fetch_build_eggs(self.distribution.tests_require) self.distribution.fetch_build_eggs(self.distribution.tests_require)
...@@ -161,7 +159,7 @@ class test(Command): ...@@ -161,7 +159,7 @@ class test(Command):
list(map(sys.modules.__delitem__, del_modules)) list(map(sys.modules.__delitem__, del_modules))
unittest_main( unittest_main(
None, None, [unittest.__file__]+self.test_args, None, None, [unittest.__file__] + self.test_args,
testLoader=self._resolve_as_ep(self.test_loader), testLoader=self._resolve_as_ep(self.test_loader),
testRunner=self._resolve_as_ep(self.test_runner), testRunner=self._resolve_as_ep(self.test_runner),
) )
......
...@@ -5,6 +5,10 @@ Implements a Distutils 'upload_docs' subcommand (upload documentation to ...@@ -5,6 +5,10 @@ Implements a Distutils 'upload_docs' subcommand (upload documentation to
PyPI's pythonhosted.org). PyPI's pythonhosted.org).
""" """
from base64 import standard_b64encode
from distutils import log
from distutils.errors import DistutilsOptionError
from distutils.command.upload import upload
import os import os
import socket import socket
import zipfile import zipfile
...@@ -12,14 +16,9 @@ import tempfile ...@@ -12,14 +16,9 @@ import tempfile
import sys import sys
import shutil import shutil
from base64 import standard_b64encode from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3
from pkg_resources import iter_entry_points from pkg_resources import iter_entry_points
from distutils import log
from distutils.errors import DistutilsOptionError
from distutils.command.upload import upload
from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3
errors = 'surrogateescape' if PY3 else 'strict' errors = 'surrogateescape' if PY3 else 'strict'
...@@ -33,7 +32,6 @@ def b(s, encoding='utf-8'): ...@@ -33,7 +32,6 @@ def b(s, encoding='utf-8'):
class upload_docs(upload): class upload_docs(upload):
description = 'Upload documentation to PyPI' description = 'Upload documentation to PyPI'
user_options = [ user_options = [
...@@ -42,7 +40,7 @@ class upload_docs(upload): ...@@ -42,7 +40,7 @@ class upload_docs(upload):
('show-response', None, ('show-response', None,
'display full response text from server'), 'display full response text from server'),
('upload-dir=', None, 'directory to upload'), ('upload-dir=', None, 'directory to upload'),
] ]
boolean_options = upload.boolean_options boolean_options = upload.boolean_options
def has_sphinx(self): def has_sphinx(self):
...@@ -159,7 +157,7 @@ class upload_docs(upload): ...@@ -159,7 +157,7 @@ class upload_docs(upload):
elif schema == 'https': elif schema == 'https':
conn = httplib.HTTPSConnection(netloc) conn = httplib.HTTPSConnection(netloc)
else: else:
raise AssertionError("unsupported schema "+schema) raise AssertionError("unsupported schema " + schema)
data = '' data = ''
try: try:
...@@ -190,4 +188,4 @@ class upload_docs(upload): ...@@ -190,4 +188,4 @@ class upload_docs(upload):
self.announce('Upload failed (%s): %s' % (r.status, r.reason), self.announce('Upload failed (%s): %s' % (r.status, r.reason),
log.ERROR) log.ERROR)
if self.show_response: if self.show_response:
print('-'*75, r.read(), '-'*75) print('-' * 75, r.read(), '-' * 75)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment