Home | History | Annotate | Download | only in distutils
      1 """distutils.core
      2 
      3 The only module that needs to be imported to use the Distutils; provides
      4 the 'setup' function (which is to be called from the setup script).  Also
      5 indirectly provides the Distribution and Command classes, although they are
      6 really defined in distutils.dist and distutils.cmd.
      7 """
      8 
      9 __revision__ = "$Id$"
     10 
     11 import sys
     12 import os
     13 
     14 from distutils.debug import DEBUG
     15 from distutils.errors import (DistutilsSetupError, DistutilsArgError,
     16                               DistutilsError, CCompilerError)
     17 
     18 # Mainly import these so setup scripts can "from distutils.core import" them.
     19 from distutils.dist import Distribution
     20 from distutils.cmd import Command
     21 from distutils.config import PyPIRCCommand
     22 from 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.
     28 USAGE = """\
     29 usage: %(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 
     35 def 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
     45 setup_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
     54 extension_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 
     60 def 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 
    171 def 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