blob: 25e6a72f2cd234f1823182b0282fbc147beb0ceb [file] [log] [blame]
Tarek Ziade1231a4e2011-05-19 13:07:25 +02001"""Base class for commands."""
2
3import os
4import re
5from shutil import copyfile, move, make_archive
6from packaging import util
7from packaging import logger
8from packaging.errors import PackagingOptionError
9
10
11class Command:
12 """Abstract base class for defining command classes, the "worker bees"
Éric Araujof8361622011-11-14 18:10:19 +010013 of Packaging. A useful analogy for command classes is to think of
Tarek Ziade1231a4e2011-05-19 13:07:25 +020014 them as subroutines with local variables called "options". The options
15 are "declared" in 'initialize_options()' and "defined" (given their
16 final values, aka "finalized") in 'finalize_options()', both of which
17 must be defined by every command class. The distinction between the
18 two is necessary because option values might come from the outside
19 world (command line, config file, ...), and any options dependent on
20 other options must be computed *after* these outside influences have
21 been processed -- hence 'finalize_options()'. The "body" of the
22 subroutine, where it does all its work based on the values of its
23 options, is the 'run()' method, which must also be implemented by every
24 command class.
25 """
26
27 # 'sub_commands' formalizes the notion of a "family" of commands,
28 # eg. "install_dist" as the parent with sub-commands "install_lib",
29 # "install_headers", etc. The parent of a family of commands
30 # defines 'sub_commands' as a class attribute; it's a list of
31 # (command_name : string, predicate : unbound_method | string | None)
32 # tuples, where 'predicate' is a method of the parent command that
33 # determines whether the corresponding command is applicable in the
34 # current situation. (Eg. we "install_headers" is only applicable if
35 # we have any C header files to install.) If 'predicate' is None,
36 # that command is always applicable.
37 #
38 # 'sub_commands' is usually defined at the *end* of a class, because
39 # predicates can be unbound methods, so they must already have been
40 # defined. The canonical example is the "install_dist" command.
41 sub_commands = []
42
43 # Pre and post command hooks are run just before or just after the command
44 # itself. They are simple functions that receive the command instance. They
45 # are specified as callable objects or dotted strings (for lazy loading).
46 pre_hook = None
47 post_hook = None
48
49 # -- Creation/initialization methods -------------------------------
50
51 def __init__(self, dist):
52 """Create and initialize a new Command object. Most importantly,
53 invokes the 'initialize_options()' method, which is the real
54 initializer and depends on the actual command being instantiated.
55 """
56 # late import because of mutual dependence between these classes
57 from packaging.dist import Distribution
58
59 if not isinstance(dist, Distribution):
Éric Araujo7b0908a2011-07-29 02:32:41 +020060 raise TypeError("dist must be an instance of Distribution, not %r"
61 % type(dist))
Tarek Ziade1231a4e2011-05-19 13:07:25 +020062 if self.__class__ is Command:
63 raise RuntimeError("Command is an abstract class")
64
65 self.distribution = dist
66 self.initialize_options()
67
68 # Per-command versions of the global flags, so that the user can
69 # customize Packaging' behaviour command-by-command and let some
70 # commands fall back on the Distribution's behaviour. None means
71 # "not defined, check self.distribution's copy", while 0 or 1 mean
72 # false and true (duh). Note that this means figuring out the real
73 # value of each flag is a touch complicated -- hence "self._dry_run"
74 # will be handled by a property, below.
75 # XXX This needs to be fixed. [I changed it to a property--does that
76 # "fix" it?]
77 self._dry_run = None
78
79 # Some commands define a 'self.force' option to ignore file
80 # timestamps, but methods defined *here* assume that
81 # 'self.force' exists for all commands. So define it here
82 # just to be safe.
83 self.force = None
84
85 # The 'help' flag is just used for command line parsing, so
86 # none of that complicated bureaucracy is needed.
87 self.help = False
88
89 # 'finalized' records whether or not 'finalize_options()' has been
90 # called. 'finalize_options()' itself should not pay attention to
91 # this flag: it is the business of 'ensure_finalized()', which
92 # always calls 'finalize_options()', to respect/update it.
93 self.finalized = False
94
95 # XXX A more explicit way to customize dry_run would be better.
96 @property
97 def dry_run(self):
98 if self._dry_run is None:
99 return getattr(self.distribution, 'dry_run')
100 else:
101 return self._dry_run
102
103 def ensure_finalized(self):
104 if not self.finalized:
105 self.finalize_options()
106 self.finalized = True
107
108 # Subclasses must define:
109 # initialize_options()
110 # provide default values for all options; may be customized by
111 # setup script, by options from config file(s), or by command-line
112 # options
113 # finalize_options()
114 # decide on the final values for all options; this is called
115 # after all possible intervention from the outside world
116 # (command line, option file, etc.) has been processed
117 # run()
118 # run the command: do whatever it is we're here to do,
119 # controlled by the command's various option values
120
121 def initialize_options(self):
122 """Set default values for all the options that this command
123 supports. Note that these defaults may be overridden by other
124 commands, by the setup script, by config files, or by the
125 command line. Thus, this is not the place to code dependencies
126 between options; generally, 'initialize_options()' implementations
127 are just a bunch of "self.foo = None" assignments.
128
129 This method must be implemented by all command classes.
130 """
131 raise RuntimeError(
132 "abstract method -- subclass %s must override" % self.__class__)
133
134 def finalize_options(self):
135 """Set final values for all the options that this command supports.
136 This is always called as late as possible, ie. after any option
137 assignments from the command line or from other commands have been
138 done. Thus, this is the place to code option dependencies: if
139 'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as
140 long as 'foo' still has the same value it was assigned in
141 'initialize_options()'.
142
143 This method must be implemented by all command classes.
144 """
145 raise RuntimeError(
146 "abstract method -- subclass %s must override" % self.__class__)
147
148 def dump_options(self, header=None, indent=""):
149 if header is None:
150 header = "command options for '%s':" % self.get_command_name()
151 logger.info(indent + header)
152 indent = indent + " "
153 negative_opt = getattr(self, 'negative_opt', ())
154 for option, _, _ in self.user_options:
155 if option in negative_opt:
156 continue
157 option = option.replace('-', '_')
158 if option[-1] == "=":
159 option = option[:-1]
160 value = getattr(self, option)
161 logger.info(indent + "%s = %s", option, value)
162
163 def run(self):
164 """A command's raison d'etre: carry out the action it exists to
165 perform, controlled by the options initialized in
166 'initialize_options()', customized by other commands, the setup
167 script, the command line and config files, and finalized in
168 'finalize_options()'. All terminal output and filesystem
169 interaction should be done by 'run()'.
170
171 This method must be implemented by all command classes.
172 """
173 raise RuntimeError(
174 "abstract method -- subclass %s must override" % self.__class__)
175
176 # -- External interface --------------------------------------------
177 # (called by outsiders)
178
179 def get_source_files(self):
180 """Return the list of files that are used as inputs to this command,
181 i.e. the files used to generate the output files. The result is used
182 by the `sdist` command in determining the set of default files.
183
184 Command classes should implement this method if they operate on files
185 from the source tree.
186 """
187 return []
188
189 def get_outputs(self):
190 """Return the list of files that would be produced if this command
191 were actually run. Not affected by the "dry-run" flag or whether
192 any other commands have been run.
193
194 Command classes should implement this method if they produce any
195 output files that get consumed by another command. e.g., `build_ext`
196 returns the list of built extension modules, but not any temporary
197 files used in the compilation process.
198 """
199 return []
200
201 # -- Option validation methods -------------------------------------
202 # (these are very handy in writing the 'finalize_options()' method)
203 #
204 # NB. the general philosophy here is to ensure that a particular option
205 # value meets certain type and value constraints. If not, we try to
206 # force it into conformance (eg. if we expect a list but have a string,
207 # split the string on comma and/or whitespace). If we can't force the
208 # option into conformance, raise PackagingOptionError. Thus, command
209 # classes need do nothing more than (eg.)
210 # self.ensure_string_list('foo')
211 # and they can be guaranteed that thereafter, self.foo will be
212 # a list of strings.
213
214 def _ensure_stringlike(self, option, what, default=None):
215 val = getattr(self, option)
216 if val is None:
217 setattr(self, option, default)
218 return default
219 elif not isinstance(val, str):
220 raise PackagingOptionError("'%s' must be a %s (got `%s`)" %
221 (option, what, val))
222 return val
223
224 def ensure_string(self, option, default=None):
225 """Ensure that 'option' is a string; if not defined, set it to
226 'default'.
227 """
228 self._ensure_stringlike(option, "string", default)
229
230 def ensure_string_list(self, option):
231 r"""Ensure that 'option' is a list of strings. If 'option' is
232 currently a string, we split it either on /,\s*/ or /\s+/, so
233 "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
234 ["foo", "bar", "baz"].
235 """
236 val = getattr(self, option)
237 if val is None:
238 return
239 elif isinstance(val, str):
240 setattr(self, option, re.split(r',\s*|\s+', val))
241 else:
242 if isinstance(val, list):
243 # checks if all elements are str
244 ok = True
245 for element in val:
246 if not isinstance(element, str):
247 ok = False
248 break
249 else:
250 ok = False
251
252 if not ok:
253 raise PackagingOptionError(
254 "'%s' must be a list of strings (got %r)" % (option, val))
255
256 def _ensure_tested_string(self, option, tester,
257 what, error_fmt, default=None):
258 val = self._ensure_stringlike(option, what, default)
259 if val is not None and not tester(val):
260 raise PackagingOptionError(
261 ("error in '%s' option: " + error_fmt) % (option, val))
262
263 def ensure_filename(self, option):
264 """Ensure that 'option' is the name of an existing file."""
265 self._ensure_tested_string(option, os.path.isfile,
266 "filename",
267 "'%s' does not exist or is not a file")
268
269 def ensure_dirname(self, option):
270 self._ensure_tested_string(option, os.path.isdir,
271 "directory name",
272 "'%s' does not exist or is not a directory")
273
274 # -- Convenience methods for commands ------------------------------
275
276 @classmethod
277 def get_command_name(cls):
278 if hasattr(cls, 'command_name'):
279 return cls.command_name
280 else:
281 return cls.__name__
282
283 def set_undefined_options(self, src_cmd, *options):
284 """Set values of undefined options from another command.
285
286 Undefined options are options set to None, which is the convention
287 used to indicate that an option has not been changed between
288 'initialize_options()' and 'finalize_options()'. This method is
289 usually called from 'finalize_options()' for options that depend on
290 some other command rather than another option of the same command,
291 typically subcommands.
292
293 The 'src_cmd' argument is the other command from which option values
294 will be taken (a command object will be created for it if necessary);
295 the remaining positional arguments are strings that give the name of
296 the option to set. If the name is different on the source and target
297 command, you can pass a tuple with '(name_on_source, name_on_dest)' so
298 that 'self.name_on_dest' will be set from 'src_cmd.name_on_source'.
299 """
300 src_cmd_obj = self.distribution.get_command_obj(src_cmd)
301 src_cmd_obj.ensure_finalized()
302 for obj in options:
303 if isinstance(obj, tuple):
304 src_option, dst_option = obj
305 else:
306 src_option, dst_option = obj, obj
307 if getattr(self, dst_option) is None:
308 setattr(self, dst_option,
309 getattr(src_cmd_obj, src_option))
310
311 def get_finalized_command(self, command, create=True):
312 """Wrapper around Distribution's 'get_command_obj()' method: find
313 (create if necessary and 'create' is true) the command object for
314 'command', call its 'ensure_finalized()' method, and return the
315 finalized command object.
316 """
317 cmd_obj = self.distribution.get_command_obj(command, create)
318 cmd_obj.ensure_finalized()
319 return cmd_obj
320
Éric Araujoa963e0d2011-11-06 06:54:05 +0100321 def reinitialize_command(self, command, reinit_subcommands=False):
322 return self.distribution.reinitialize_command(
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200323 command, reinit_subcommands)
324
325 def run_command(self, command):
326 """Run some other command: uses the 'run_command()' method of
327 Distribution, which creates and finalizes the command object if
328 necessary and then invokes its 'run()' method.
329 """
330 self.distribution.run_command(command)
331
332 def get_sub_commands(self):
333 """Determine the sub-commands that are relevant in the current
334 distribution (ie., that need to be run). This is based on the
335 'sub_commands' class attribute: each tuple in that list may include
336 a method that we call to determine if the subcommand needs to be
337 run for the current distribution. Return a list of command names.
338 """
339 commands = []
340 for sub_command in self.sub_commands:
341 if len(sub_command) == 2:
342 cmd_name, method = sub_command
343 if method is None or method(self):
344 commands.append(cmd_name)
345 else:
346 commands.append(sub_command)
347 return commands
348
349 # -- External world manipulation -----------------------------------
350
351 def execute(self, func, args, msg=None, level=1):
352 util.execute(func, args, msg, dry_run=self.dry_run)
353
Éric Araujo4d155462011-11-15 11:43:20 +0100354 def mkpath(self, name, mode=0o777, dry_run=None):
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200355 if dry_run is None:
356 dry_run = self.dry_run
357 name = os.path.normpath(name)
358 if os.path.isdir(name) or name == '':
359 return
360 if dry_run:
361 head = ''
362 for part in name.split(os.sep):
363 logger.info("created directory %s%s", head, part)
364 head += part + os.sep
365 return
366 os.makedirs(name, mode)
367
368 def copy_file(self, infile, outfile,
369 preserve_mode=True, preserve_times=True, link=None, level=1):
Éric Araujo4d155462011-11-15 11:43:20 +0100370 """Copy a file respecting dry-run and force flags.
371
372 (dry-run defaults to whatever is in the Distribution object, and
373 force to false for commands that don't define it.)
374 """
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200375 if self.dry_run:
376 # XXX add a comment
377 return
378 if os.path.isdir(outfile):
379 outfile = os.path.join(outfile, os.path.split(infile)[-1])
380 copyfile(infile, outfile)
381 return outfile, None # XXX
382
383 def copy_tree(self, infile, outfile, preserve_mode=True,
384 preserve_times=True, preserve_symlinks=False, level=1):
Éric Araujo4d155462011-11-15 11:43:20 +0100385 """Copy an entire directory tree respecting dry-run
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200386 and force flags.
387 """
388 if self.dry_run:
Éric Araujo4d155462011-11-15 11:43:20 +0100389 # XXX should not return but let copy_tree log and decide to execute
390 # or not based on its dry_run argument
391 return
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200392
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200393 return util.copy_tree(infile, outfile, preserve_mode, preserve_times,
394 preserve_symlinks, not self.force, dry_run=self.dry_run)
395
396 def move_file(self, src, dst, level=1):
397 """Move a file respecting the dry-run flag."""
398 if self.dry_run:
Éric Araujo4d155462011-11-15 11:43:20 +0100399 return # XXX same thing
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200400 return move(src, dst)
401
402 def spawn(self, cmd, search_path=True, level=1):
403 """Spawn an external command respecting dry-run flag."""
404 from packaging.util import spawn
405 spawn(cmd, search_path, dry_run=self.dry_run)
406
407 def make_archive(self, base_name, format, root_dir=None, base_dir=None,
408 owner=None, group=None):
409 return make_archive(base_name, format, root_dir,
410 base_dir, dry_run=self.dry_run,
411 owner=owner, group=group)
412
413 def make_file(self, infiles, outfile, func, args,
414 exec_msg=None, skip_msg=None, level=1):
415 """Special case of 'execute()' for operations that process one or
416 more input files and generate one output file. Works just like
417 'execute()', except the operation is skipped and a different
418 message printed if 'outfile' already exists and is newer than all
419 files listed in 'infiles'. If the command defined 'self.force',
420 and it is true, then the command is unconditionally run -- does no
421 timestamp checks.
422 """
423 if skip_msg is None:
424 skip_msg = "skipping %s (inputs unchanged)" % outfile
425
426 # Allow 'infiles' to be a single string
427 if isinstance(infiles, str):
428 infiles = (infiles,)
429 elif not isinstance(infiles, (list, tuple)):
430 raise TypeError(
431 "'infiles' must be a string, or a list or tuple of strings")
432
433 if exec_msg is None:
434 exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles))
435
436 # If 'outfile' must be regenerated (either because it doesn't
437 # exist, is out-of-date, or the 'force' flag is true) then
438 # perform the action that presumably regenerates it
439 if self.force or util.newer_group(infiles, outfile):
440 self.execute(func, args, exec_msg, level)
441
442 # Otherwise, print the "skip" message
443 else:
444 logger.debug(skip_msg)
Éric Araujof8361622011-11-14 18:10:19 +0100445
446 def byte_compile(self, files, prefix=None):
447 """Byte-compile files to pyc and/or pyo files.
448
449 This method requires that the calling class define compile and
450 optimize options, like build_py and install_lib. It also
451 automatically respects the force and dry-run options.
452
453 prefix, if given, is a string that will be stripped off the
454 filenames encoded in bytecode files.
455 """
456 if self.compile:
457 util.byte_compile(files, optimize=False, prefix=prefix,
458 force=self.force, dry_run=self.dry_run)
459 if self.optimize:
460 util.byte_compile(files, optimize=self.optimize, prefix=prefix,
461 force=self.force, dry_run=self.dry_run)