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