Commit 2e83526e authored by PJ Eby's avatar PJ Eby

Compute command line that should be passed to child setup scripts.

Warn user if unsupported options are supplied, and cancel unless
'depends -i' (aka '--ignore-extra-args') was used.

--HG--
branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4040880
parent 7ce55cab
......@@ -4,8 +4,6 @@ To-Do
* install_deps command (install runtime dependencies)
* compute child command line, abort if user specified incompatible options
* OPEN ISSUE: should parent install command include child install's files?
* Dependency class
......
......@@ -22,13 +22,54 @@ class depends(Command):
('install_lib','install_dir'), # where modules are installed
]
# Command options that can be safely passed to dependencies' setup scripts
safe_opts = {
'install': [
'prefix','exec-prefix','home','install-base','install-platbase',
'root','optimize','force','verbose','quiet'
],
'build': ['compiler','debug','force','verbose','quiet'],
}
# Options with string arguments that are *not* directories or files, and
# so should *not* have absolute-path fixups applied.
non_fs_opts = {'build':['compiler'] }
def initialize_options(self):
self.temp = None
self.temp = None; self.ignore_extra_args = None
def finalize_options(self):
self.set_undefined_options('build',('build_temp', 'temp'))
self.set_search_path()
self.set_subcommand_args()
def set_subcommand_args(self):
safe = {'install':[]} # ensure we at least perform an install
unsafe = {}
copts = self.distribution.get_cmdline_options()
if 'depends' in copts:
del copts['depends']
for cmd,opts in copts.items():
safe_opts = self.safe_opts.get(cmd,())
non_fs_opts = self.non_fs_opts.get(cmd,())
for opt,val in opts.items():
if opt in safe_opts:
cmdline = safe.setdefault(cmd,[])
if val is not None and opt not in non_fs_opts:
val = os.path.abspath(val)
else:
cmdline = unsafe.setdefault(cmd,[])
cmdline.append('--'+opt)
if val is not None:
cmdline.append(val)
self.safe_options = safe
self.unsafe_options = unsafe
def set_search_path(self):
"""Determine paths to check for installed dependencies"""
......@@ -41,21 +82,55 @@ class depends(Command):
def run(self):
self.announce("checking for installed dependencies")
needed = [
dep for dep in self.distribution.requires if self.is_needed(dep)
]
if not needed:
self.announce("all dependencies are present and up-to-date")
return
argv = [sys.executable,'setup.py']
for cmd,line in self.safe_options.items():
argv.append(cmd); argv.extend(line)
self.announce(
"dependencies will be installed using:\n "+' '.join(argv)+'\n'
)
# Alert for unsupported commands/options, unless '-i' was used
if self.unsafe_options:
self.warn_unsafe_options_used()
if not self.ignore_extra_args:
raise SystemExit(
"Unsupported options for building dependencies; please"
" add 'depends -i'\nto your command line if you want to"
" force the build to proceed.\nOtherwise, you will need"
" to omit the unsupported options,\nor install the"
" dependencies manually."
)
# Alert the user to missing items
fmt = "\t%s\t%s\n"
items = [fmt % (dep.full_name(),dep.homepage) for dep in needed]
items.insert(0,"Please install the following packages first:\n")
items.insert(0,"Please install the following packages *first*:\n")
items.append('')
raise SystemExit('\n'.join(items)) # dump msg to stderr and exit
def warn_unsafe_options_used(self):
lines = []; write = lines.append
write("the following command options are not supported for building")
write("dependencies, and will be IGNORED:")
for cmd,line in self.unsafe_options.items():
write('\t%s %s' % (cmd,' '.join(line)))
write('')
self.warn('\n'.join(lines))
def is_needed(self,dep):
"""Does the specified dependency need to be installed/updated?"""
......@@ -80,3 +155,10 @@ class depends(Command):
......@@ -285,6 +285,47 @@ class Distribution(_Distribution):
def get_cmdline_options(self):
"""Return a '{cmd: {opt:val}}' map of all command-line options
Option names are all long, but do not include the leading '--', and
contain dashes rather than underscores. If the option doesn't take
an argument (e.g. '--quiet'), the 'val' is 'None'.
Note that options provided by config files are intentionally excluded.
"""
d = {}
for cmd,opts in self.command_options.items():
for opt,(src,val) in opts.items():
if src != "command line":
continue
opt = opt.replace('_','-')
if val==0:
cmdobj = self.get_command_obj(cmd)
neg_opt = self.negative_opt.copy()
neg_opt.update(getattr(cmdobj,'negative_opt',{}))
for neg,pos in neg_opt.items():
if pos==opt:
opt=neg
val=None
break
else:
raise AssertionError("Shouldn't be able to get here")
elif val==1:
val = None
d.setdefault(cmd,{})[opt] = val
return d
class Feature:
"""A subset of the distribution that can be excluded if unneeded/wanted
......
......@@ -127,7 +127,10 @@ class DependsTests(TestCase):
dist = makeSetup(
extra_path='spam',
script_args=['install','--install-lib',path1]
script_args=[
'install','--install-lib',path1, '--prefix',path2,
'build','--compiler=mingw32',
]
)
cmd = dist.get_command_obj('depends')
......@@ -136,16 +139,13 @@ class DependsTests(TestCase):
self.assertEqual(cmd.temp, dist.get_command_obj('build').build_temp)
self.assertEqual(cmd.search_path, [path2,path1]+sys.path)
self.assertEqual(cmd.unsafe_options,
{'install':['--install-lib',path1]}
)
self.assertEqual(cmd.safe_options, {
'build':['--compiler','mingw32'],
'install':['--prefix',os.path.abspath(path2)]
})
......@@ -172,6 +172,10 @@ class DistroTests(TestCase):
packages=['a', 'a.b', 'a.b.c', 'b', 'c'],
py_modules=['b.d','x'],
ext_modules = (self.e1, self.e2),
script_args = [
'build', '-q', 'build_ext', '-i',
'install', '--prefix=/usr/lib', '--install-lib','/test'
],
package_dir = {},
)
......@@ -199,10 +203,6 @@ class DistroTests(TestCase):
def testIncludeExclude(self):
# remove an extension
self.dist.exclude(ext_modules=[self.e1])
......@@ -271,12 +271,12 @@ class DistroTests(TestCase):
self.dist.exclude, package_dir=['q']
)
def testCmdLineOpts(self):
self.assertEqual(self.dist.get_cmdline_options(),
{ 'install':{'prefix':'/usr/lib', 'install-lib':'/test'},
'build': {'quiet':None}, 'build_ext':{'inplace':None},
}
)
......
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