1"""distutils.core 2 3The only module that needs to be imported to use the Distutils; provides 4the 'setup' function (which is to be called from the setup script). Also 5indirectly provides the Distribution and Command classes, although they are 6really defined in distutils.dist and distutils.cmd. 7""" 8 9__revision__ = "$Id$" 10 11import sys 12import os 13 14from distutils.debug import DEBUG 15from distutils.errors import (DistutilsSetupError, DistutilsArgError, 16 DistutilsError, CCompilerError) 17 18# Mainly import these so setup scripts can "from distutils.core import" them. 19from distutils.dist import Distribution 20from distutils.cmd import Command 21from distutils.config import PyPIRCCommand 22from distutils.extension import Extension 23 24# This is a barebones help message generated displayed when the user 25# runs the setup script with no arguments at all. More useful help 26# is generated with various --help options: global help, list commands, 27# and per-command help. 28USAGE = """\ 29usage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] 30 or: %(script)s --help [cmd1 cmd2 ...] 31 or: %(script)s --help-commands 32 or: %(script)s cmd --help 33""" 34 35def gen_usage(script_name): 36 script = os.path.basename(script_name) 37 return USAGE % {'script': script} 38 39 40# Some mild magic to control the behaviour of 'setup()' from 'run_setup()'. 41_setup_stop_after = None 42_setup_distribution = None 43 44# Legal keyword arguments for the setup() function 45setup_keywords = ('distclass', 'script_name', 'script_args', 'options', 46 'name', 'version', 'author', 'author_email', 47 'maintainer', 'maintainer_email', 'url', 'license', 48 'description', 'long_description', 'keywords', 49 'platforms', 'classifiers', 'download_url', 50 'requires', 'provides', 'obsoletes', 51 ) 52 53# Legal keyword arguments for the Extension constructor 54extension_keywords = ('name', 'sources', 'include_dirs', 55 'define_macros', 'undef_macros', 56 'library_dirs', 'libraries', 'runtime_library_dirs', 57 'extra_objects', 'extra_compile_args', 'extra_link_args', 58 'swig_opts', 'export_symbols', 'depends', 'language') 59 60def setup(**attrs): 61 """The gateway to the Distutils: do everything your setup script needs 62 to do, in a highly flexible and user-driven way. Briefly: create a 63 Distribution instance; find and parse config files; parse the command 64 line; run each Distutils command found there, customized by the options 65 supplied to 'setup()' (as keyword arguments), in config files, and on 66 the command line. 67 68 The Distribution instance might be an instance of a class supplied via 69 the 'distclass' keyword argument to 'setup'; if no such class is 70 supplied, then the Distribution class (in dist.py) is instantiated. 71 All other arguments to 'setup' (except for 'cmdclass') are used to set 72 attributes of the Distribution instance. 73 74 The 'cmdclass' argument, if supplied, is a dictionary mapping command 75 names to command classes. Each command encountered on the command line 76 will be turned into a command class, which is in turn instantiated; any 77 class found in 'cmdclass' is used in place of the default, which is 78 (for command 'foo_bar') class 'foo_bar' in module 79 'distutils.command.foo_bar'. The command class must provide a 80 'user_options' attribute which is a list of option specifiers for 81 'distutils.fancy_getopt'. Any command-line options between the current 82 and the next command are used to set attributes of the current command 83 object. 84 85 When the entire command-line has been successfully parsed, calls the 86 'run()' method on each command object in turn. This method will be 87 driven entirely by the Distribution object (which each command object 88 has a reference to, thanks to its constructor), and the 89 command-specific options that became attributes of each command 90 object. 91 """ 92 93 global _setup_stop_after, _setup_distribution 94 95 # Determine the distribution class -- either caller-supplied or 96 # our Distribution (see below). 97 klass = attrs.get('distclass') 98 if klass: 99 del attrs['distclass'] 100 else: 101 klass = Distribution 102 103 if 'script_name' not in attrs: 104 attrs['script_name'] = os.path.basename(sys.argv[0]) 105 if 'script_args' not in attrs: 106 attrs['script_args'] = sys.argv[1:] 107 108 # Create the Distribution instance, using the remaining arguments 109 # (ie. everything except distclass) to initialize it 110 try: 111 _setup_distribution = dist = klass(attrs) 112 except DistutilsSetupError, msg: 113 if 'name' in attrs: 114 raise SystemExit, "error in %s setup command: %s" % \ 115 (attrs['name'], msg) 116 else: 117 raise SystemExit, "error in setup command: %s" % msg 118 119 if _setup_stop_after == "init": 120 return dist 121 122 # Find and parse the config file(s): they will override options from 123 # the setup script, but be overridden by the command line. 124 dist.parse_config_files() 125 126 if DEBUG: 127 print "options (after parsing config files):" 128 dist.dump_option_dicts() 129 130 if _setup_stop_after == "config": 131 return dist 132 133 # Parse the command line and override config files; any 134 # command-line errors are the end user's fault, so turn them into 135 # SystemExit to suppress tracebacks. 136 try: 137 ok = dist.parse_command_line() 138 except DistutilsArgError, msg: 139 raise SystemExit, gen_usage(dist.script_name) + "\nerror: %s" % msg 140 141 if DEBUG: 142 print "options (after parsing command line):" 143 dist.dump_option_dicts() 144 145 if _setup_stop_after == "commandline": 146 return dist 147 148 # And finally, run all the commands found on the command line. 149 if ok: 150 try: 151 dist.run_commands() 152 except KeyboardInterrupt: 153 raise SystemExit, "interrupted" 154 except (IOError, os.error), exc: 155 if DEBUG: 156 sys.stderr.write("error: %s\n" % (exc,)) 157 raise 158 else: 159 raise SystemExit, "error: %s" % (exc,) 160 161 except (DistutilsError, 162 CCompilerError), msg: 163 if DEBUG: 164 raise 165 else: 166 raise SystemExit, "error: " + str(msg) 167 168 return dist 169 170 171def run_setup(script_name, script_args=None, stop_after="run"): 172 """Run a setup script in a somewhat controlled environment, and 173 return the Distribution instance that drives things. This is useful 174 if you need to find out the distribution meta-data (passed as 175 keyword args from 'script' to 'setup()', or the contents of the 176 config files or command-line. 177 178 'script_name' is a file that will be run with 'execfile()'; 179 'sys.argv[0]' will be replaced with 'script' for the duration of the 180 call. 'script_args' is a list of strings; if supplied, 181 'sys.argv[1:]' will be replaced by 'script_args' for the duration of 182 the call. 183 184 'stop_after' tells 'setup()' when to stop processing; possible 185 values: 186 init 187 stop after the Distribution instance has been created and 188 populated with the keyword arguments to 'setup()' 189 config 190 stop after config files have been parsed (and their data 191 stored in the Distribution instance) 192 commandline 193 stop after the command-line ('sys.argv[1:]' or 'script_args') 194 have been parsed (and the data stored in the Distribution) 195 run [default] 196 stop after all commands have been run (the same as if 'setup()' 197 had been called in the usual way 198 199 Returns the Distribution instance, which provides all information 200 used to drive the Distutils. 201 """ 202 if stop_after not in ('init', 'config', 'commandline', 'run'): 203 raise ValueError, "invalid value for 'stop_after': %r" % (stop_after,) 204 205 global _setup_stop_after, _setup_distribution 206 _setup_stop_after = stop_after 207 208 save_argv = sys.argv 209 g = {'__file__': script_name} 210 l = {} 211 try: 212 try: 213 sys.argv[0] = script_name 214 if script_args is not None: 215 sys.argv[1:] = script_args 216 f = open(script_name) 217 try: 218 exec f.read() in g, l 219 finally: 220 f.close() 221 finally: 222 sys.argv = save_argv 223 _setup_stop_after = None 224 except SystemExit: 225 # Hmm, should we do something if exiting with a non-zero code 226 # (ie. error)? 227 pass 228 except: 229 raise 230 231 if _setup_distribution is None: 232 raise RuntimeError, \ 233 ("'distutils.core.setup()' was never called -- " 234 "perhaps '%s' is not a Distutils setup script?") % \ 235 script_name 236 237 # I wonder if the setup script's namespace -- g and l -- would be of 238 # any interest to callers? 239 return _setup_distribution 240