PageRenderTime 311ms CodeModel.GetById 151ms app.highlight 14ms RepoModel.GetById 141ms app.codeStats 0ms

/Lib/distutils/core.py

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