blob: fa56aa63f6453898d2d7407b50cab0586c50b249 [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"
13 of the Packaging. A useful analogy for command classes is to think of
14 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):
60 raise TypeError("dist must be a Distribution instance")
61 if self.__class__ is Command:
62 raise RuntimeError("Command is an abstract class")
63
64 self.distribution = dist
65 self.initialize_options()
66
67 # Per-command versions of the global flags, so that the user can
68 # customize Packaging' behaviour command-by-command and let some
69 # commands fall back on the Distribution's behaviour. None means
70 # "not defined, check self.distribution's copy", while 0 or 1 mean
71 # false and true (duh). Note that this means figuring out the real
72 # value of each flag is a touch complicated -- hence "self._dry_run"
73 # will be handled by a property, below.
74 # XXX This needs to be fixed. [I changed it to a property--does that
75 # "fix" it?]
76 self._dry_run = None
77
78 # Some commands define a 'self.force' option to ignore file
79 # timestamps, but methods defined *here* assume that
80 # 'self.force' exists for all commands. So define it here
81 # just to be safe.
82 self.force = None
83
84 # The 'help' flag is just used for command line parsing, so
85 # none of that complicated bureaucracy is needed.
86 self.help = False
87
88 # 'finalized' records whether or not 'finalize_options()' has been
89 # called. 'finalize_options()' itself should not pay attention to
90 # this flag: it is the business of 'ensure_finalized()', which
91 # always calls 'finalize_options()', to respect/update it.
92 self.finalized = False
93
94 # XXX A more explicit way to customize dry_run would be better.
95 @property
96 def dry_run(self):
97 if self._dry_run is None:
98 return getattr(self.distribution, 'dry_run')
99 else:
100 return self._dry_run
101
102 def ensure_finalized(self):
103 if not self.finalized:
104 self.finalize_options()
105 self.finalized = True
106
107 # Subclasses must define:
108 # initialize_options()
109 # provide default values for all options; may be customized by
110 # setup script, by options from config file(s), or by command-line
111 # options
112 # finalize_options()
113 # decide on the final values for all options; this is called
114 # after all possible intervention from the outside world
115 # (command line, option file, etc.) has been processed
116 # run()
117 # run the command: do whatever it is we're here to do,
118 # controlled by the command's various option values
119
120 def initialize_options(self):
121 """Set default values for all the options that this command
122 supports. Note that these defaults may be overridden by other
123 commands, by the setup script, by config files, or by the
124 command line. Thus, this is not the place to code dependencies
125 between options; generally, 'initialize_options()' implementations
126 are just a bunch of "self.foo = None" assignments.
127
128 This method must be implemented by all command classes.
129 """
130 raise RuntimeError(
131 "abstract method -- subclass %s must override" % self.__class__)
132
133 def finalize_options(self):
134 """Set final values for all the options that this command supports.
135 This is always called as late as possible, ie. after any option
136 assignments from the command line or from other commands have been
137 done. Thus, this is the place to code option dependencies: if
138 'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as
139 long as 'foo' still has the same value it was assigned in
140 'initialize_options()'.
141
142 This method must be implemented by all command classes.
143 """
144 raise RuntimeError(
145 "abstract method -- subclass %s must override" % self.__class__)
146
147 def dump_options(self, header=None, indent=""):
148 if header is None:
149 header = "command options for '%s':" % self.get_command_name()
150 logger.info(indent + header)
151 indent = indent + " "
152 negative_opt = getattr(self, 'negative_opt', ())
153 for option, _, _ in self.user_options:
154 if option in negative_opt:
155 continue
156 option = option.replace('-', '_')
157 if option[-1] == "=":
158 option = option[:-1]
159 value = getattr(self, option)
160 logger.info(indent + "%s = %s", option, value)
161
162 def run(self):
163 """A command's raison d'etre: carry out the action it exists to
164 perform, controlled by the options initialized in
165 'initialize_options()', customized by other commands, the setup
166 script, the command line and config files, and finalized in
167 'finalize_options()'. All terminal output and filesystem
168 interaction should be done by 'run()'.
169
170 This method must be implemented by all command classes.
171 """
172 raise RuntimeError(
173 "abstract method -- subclass %s must override" % self.__class__)
174
175 # -- External interface --------------------------------------------
176 # (called by outsiders)
177
178 def get_source_files(self):
179 """Return the list of files that are used as inputs to this command,
180 i.e. the files used to generate the output files. The result is used
181 by the `sdist` command in determining the set of default files.
182
183 Command classes should implement this method if they operate on files
184 from the source tree.
185 """
186 return []
187
188 def get_outputs(self):
189 """Return the list of files that would be produced if this command
190 were actually run. Not affected by the "dry-run" flag or whether
191 any other commands have been run.
192
193 Command classes should implement this method if they produce any
194 output files that get consumed by another command. e.g., `build_ext`
195 returns the list of built extension modules, but not any temporary
196 files used in the compilation process.
197 """
198 return []
199
200 # -- Option validation methods -------------------------------------
201 # (these are very handy in writing the 'finalize_options()' method)
202 #
203 # NB. the general philosophy here is to ensure that a particular option
204 # value meets certain type and value constraints. If not, we try to
205 # force it into conformance (eg. if we expect a list but have a string,
206 # split the string on comma and/or whitespace). If we can't force the
207 # option into conformance, raise PackagingOptionError. Thus, command
208 # classes need do nothing more than (eg.)
209 # self.ensure_string_list('foo')
210 # and they can be guaranteed that thereafter, self.foo will be
211 # a list of strings.
212
213 def _ensure_stringlike(self, option, what, default=None):
214 val = getattr(self, option)
215 if val is None:
216 setattr(self, option, default)
217 return default
218 elif not isinstance(val, str):
219 raise PackagingOptionError("'%s' must be a %s (got `%s`)" %
220 (option, what, val))
221 return val
222
223 def ensure_string(self, option, default=None):
224 """Ensure that 'option' is a string; if not defined, set it to
225 'default'.
226 """
227 self._ensure_stringlike(option, "string", default)
228
229 def ensure_string_list(self, option):
230 r"""Ensure that 'option' is a list of strings. If 'option' is
231 currently a string, we split it either on /,\s*/ or /\s+/, so
232 "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
233 ["foo", "bar", "baz"].
234 """
235 val = getattr(self, option)
236 if val is None:
237 return
238 elif isinstance(val, str):
239 setattr(self, option, re.split(r',\s*|\s+', val))
240 else:
241 if isinstance(val, list):
242 # checks if all elements are str
243 ok = True
244 for element in val:
245 if not isinstance(element, str):
246 ok = False
247 break
248 else:
249 ok = False
250
251 if not ok:
252 raise PackagingOptionError(
253 "'%s' must be a list of strings (got %r)" % (option, val))
254
255 def _ensure_tested_string(self, option, tester,
256 what, error_fmt, default=None):
257 val = self._ensure_stringlike(option, what, default)
258 if val is not None and not tester(val):
259 raise PackagingOptionError(
260 ("error in '%s' option: " + error_fmt) % (option, val))
261
262 def ensure_filename(self, option):
263 """Ensure that 'option' is the name of an existing file."""
264 self._ensure_tested_string(option, os.path.isfile,
265 "filename",
266 "'%s' does not exist or is not a file")
267
268 def ensure_dirname(self, option):
269 self._ensure_tested_string(option, os.path.isdir,
270 "directory name",
271 "'%s' does not exist or is not a directory")
272
273 # -- Convenience methods for commands ------------------------------
274
275 @classmethod
276 def get_command_name(cls):
277 if hasattr(cls, 'command_name'):
278 return cls.command_name
279 else:
280 return cls.__name__
281
282 def set_undefined_options(self, src_cmd, *options):
283 """Set values of undefined options from another command.
284
285 Undefined options are options set to None, which is the convention
286 used to indicate that an option has not been changed between
287 'initialize_options()' and 'finalize_options()'. This method is
288 usually called from 'finalize_options()' for options that depend on
289 some other command rather than another option of the same command,
290 typically subcommands.
291
292 The 'src_cmd' argument is the other command from which option values
293 will be taken (a command object will be created for it if necessary);
294 the remaining positional arguments are strings that give the name of
295 the option to set. If the name is different on the source and target
296 command, you can pass a tuple with '(name_on_source, name_on_dest)' so
297 that 'self.name_on_dest' will be set from 'src_cmd.name_on_source'.
298 """
299 src_cmd_obj = self.distribution.get_command_obj(src_cmd)
300 src_cmd_obj.ensure_finalized()
301 for obj in options:
302 if isinstance(obj, tuple):
303 src_option, dst_option = obj
304 else:
305 src_option, dst_option = obj, obj
306 if getattr(self, dst_option) is None:
307 setattr(self, dst_option,
308 getattr(src_cmd_obj, src_option))
309
310 def get_finalized_command(self, command, create=True):
311 """Wrapper around Distribution's 'get_command_obj()' method: find
312 (create if necessary and 'create' is true) the command object for
313 'command', call its 'ensure_finalized()' method, and return the
314 finalized command object.
315 """
316 cmd_obj = self.distribution.get_command_obj(command, create)
317 cmd_obj.ensure_finalized()
318 return cmd_obj
319
320 def get_reinitialized_command(self, command, reinit_subcommands=False):
321 return self.distribution.get_reinitialized_command(
322 command, reinit_subcommands)
323
324 def run_command(self, command):
325 """Run some other command: uses the 'run_command()' method of
326 Distribution, which creates and finalizes the command object if
327 necessary and then invokes its 'run()' method.
328 """
329 self.distribution.run_command(command)
330
331 def get_sub_commands(self):
332 """Determine the sub-commands that are relevant in the current
333 distribution (ie., that need to be run). This is based on the
334 'sub_commands' class attribute: each tuple in that list may include
335 a method that we call to determine if the subcommand needs to be
336 run for the current distribution. Return a list of command names.
337 """
338 commands = []
339 for sub_command in self.sub_commands:
340 if len(sub_command) == 2:
341 cmd_name, method = sub_command
342 if method is None or method(self):
343 commands.append(cmd_name)
344 else:
345 commands.append(sub_command)
346 return commands
347
348 # -- External world manipulation -----------------------------------
349
350 def execute(self, func, args, msg=None, level=1):
351 util.execute(func, args, msg, dry_run=self.dry_run)
352
353 def mkpath(self, name, mode=0o777, dry_run=None, verbose=0):
354 if dry_run is None:
355 dry_run = self.dry_run
356 name = os.path.normpath(name)
357 if os.path.isdir(name) or name == '':
358 return
359 if dry_run:
360 head = ''
361 for part in name.split(os.sep):
362 logger.info("created directory %s%s", head, part)
363 head += part + os.sep
364 return
365 os.makedirs(name, mode)
366
367 def copy_file(self, infile, outfile,
368 preserve_mode=True, preserve_times=True, link=None, level=1):
369 """Copy a file respecting verbose, dry-run and force flags. (The
370 former two default to whatever is in the Distribution object, and
371 the latter defaults to false for commands that don't define it.)"""
372 if self.dry_run:
373 # XXX add a comment
374 return
375 if os.path.isdir(outfile):
376 outfile = os.path.join(outfile, os.path.split(infile)[-1])
377 copyfile(infile, outfile)
378 return outfile, None # XXX
379
380 def copy_tree(self, infile, outfile, preserve_mode=True,
381 preserve_times=True, preserve_symlinks=False, level=1):
382 """Copy an entire directory tree respecting verbose, dry-run,
383 and force flags.
384 """
385 if self.dry_run:
386 return # see if we want to display something
387
388
389 return util.copy_tree(infile, outfile, preserve_mode, preserve_times,
390 preserve_symlinks, not self.force, dry_run=self.dry_run)
391
392 def move_file(self, src, dst, level=1):
393 """Move a file respecting the dry-run flag."""
394 if self.dry_run:
395 return # XXX log ?
396 return move(src, dst)
397
398 def spawn(self, cmd, search_path=True, level=1):
399 """Spawn an external command respecting dry-run flag."""
400 from packaging.util import spawn
401 spawn(cmd, search_path, dry_run=self.dry_run)
402
403 def make_archive(self, base_name, format, root_dir=None, base_dir=None,
404 owner=None, group=None):
405 return make_archive(base_name, format, root_dir,
406 base_dir, dry_run=self.dry_run,
407 owner=owner, group=group)
408
409 def make_file(self, infiles, outfile, func, args,
410 exec_msg=None, skip_msg=None, level=1):
411 """Special case of 'execute()' for operations that process one or
412 more input files and generate one output file. Works just like
413 'execute()', except the operation is skipped and a different
414 message printed if 'outfile' already exists and is newer than all
415 files listed in 'infiles'. If the command defined 'self.force',
416 and it is true, then the command is unconditionally run -- does no
417 timestamp checks.
418 """
419 if skip_msg is None:
420 skip_msg = "skipping %s (inputs unchanged)" % outfile
421
422 # Allow 'infiles' to be a single string
423 if isinstance(infiles, str):
424 infiles = (infiles,)
425 elif not isinstance(infiles, (list, tuple)):
426 raise TypeError(
427 "'infiles' must be a string, or a list or tuple of strings")
428
429 if exec_msg is None:
430 exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles))
431
432 # If 'outfile' must be regenerated (either because it doesn't
433 # exist, is out-of-date, or the 'force' flag is true) then
434 # perform the action that presumably regenerates it
435 if self.force or util.newer_group(infiles, outfile):
436 self.execute(func, args, exec_msg, level)
437
438 # Otherwise, print the "skip" message
439 else:
440 logger.debug(skip_msg)