From 28be66133d8dd95ddb28800b8e50b16f56b084fc Mon Sep 17 00:00:00 2001 From: pje Date: Mon, 22 Mar 2004 01:20:58 +0000 Subject: 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. git-svn-id: svn://svn.eby-sarna.com/svnroot/wsgiref@245 571e12c6-e1fa-0310-aee7-ff1267fa46bd --- setuptools/command/depends.py | 86 ++++++++++++++++++++++++++++++++++++++++++- setuptools/dist.py | 41 +++++++++++++++++++++ setuptools/tests/__init__.py | 42 ++++++++++----------- 3 files changed, 146 insertions(+), 23 deletions(-) diff --git a/setuptools/command/depends.py b/setuptools/command/depends.py index 8917c83..9d9c9f4 100644 --- a/setuptools/command/depends.py +++ b/setuptools/command/depends.py @@ -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): + + + + + + + diff --git a/setuptools/dist.py b/setuptools/dist.py index cd3af26..cb5a906 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -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 diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py index 913c65b..66b1264 100644 --- a/setuptools/tests/__init__.py +++ b/setuptools/tests/__init__.py @@ -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}, + } + ) -- cgit v1.2.1