• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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