17db96d56Sopenharmony_ci"""distutils.cmd 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciProvides the Command class, the base class for the command classes 47db96d56Sopenharmony_ciin the distutils.command package. 57db96d56Sopenharmony_ci""" 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ciimport sys, os, re 87db96d56Sopenharmony_cifrom distutils.errors import DistutilsOptionError 97db96d56Sopenharmony_cifrom distutils import util, dir_util, file_util, archive_util, dep_util 107db96d56Sopenharmony_cifrom distutils import log 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ciclass Command: 137db96d56Sopenharmony_ci """Abstract base class for defining command classes, the "worker bees" 147db96d56Sopenharmony_ci of the Distutils. A useful analogy for command classes is to think of 157db96d56Sopenharmony_ci them as subroutines with local variables called "options". The options 167db96d56Sopenharmony_ci are "declared" in 'initialize_options()' and "defined" (given their 177db96d56Sopenharmony_ci final values, aka "finalized") in 'finalize_options()', both of which 187db96d56Sopenharmony_ci must be defined by every command class. The distinction between the 197db96d56Sopenharmony_ci two is necessary because option values might come from the outside 207db96d56Sopenharmony_ci world (command line, config file, ...), and any options dependent on 217db96d56Sopenharmony_ci other options must be computed *after* these outside influences have 227db96d56Sopenharmony_ci been processed -- hence 'finalize_options()'. The "body" of the 237db96d56Sopenharmony_ci subroutine, where it does all its work based on the values of its 247db96d56Sopenharmony_ci options, is the 'run()' method, which must also be implemented by every 257db96d56Sopenharmony_ci command class. 267db96d56Sopenharmony_ci """ 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_ci # 'sub_commands' formalizes the notion of a "family" of commands, 297db96d56Sopenharmony_ci # eg. "install" as the parent with sub-commands "install_lib", 307db96d56Sopenharmony_ci # "install_headers", etc. The parent of a family of commands 317db96d56Sopenharmony_ci # defines 'sub_commands' as a class attribute; it's a list of 327db96d56Sopenharmony_ci # (command_name : string, predicate : unbound_method | string | None) 337db96d56Sopenharmony_ci # tuples, where 'predicate' is a method of the parent command that 347db96d56Sopenharmony_ci # determines whether the corresponding command is applicable in the 357db96d56Sopenharmony_ci # current situation. (Eg. we "install_headers" is only applicable if 367db96d56Sopenharmony_ci # we have any C header files to install.) If 'predicate' is None, 377db96d56Sopenharmony_ci # that command is always applicable. 387db96d56Sopenharmony_ci # 397db96d56Sopenharmony_ci # 'sub_commands' is usually defined at the *end* of a class, because 407db96d56Sopenharmony_ci # predicates can be unbound methods, so they must already have been 417db96d56Sopenharmony_ci # defined. The canonical example is the "install" command. 427db96d56Sopenharmony_ci sub_commands = [] 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ci # -- Creation/initialization methods ------------------------------- 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci def __init__(self, dist): 487db96d56Sopenharmony_ci """Create and initialize a new Command object. Most importantly, 497db96d56Sopenharmony_ci invokes the 'initialize_options()' method, which is the real 507db96d56Sopenharmony_ci initializer and depends on the actual command being 517db96d56Sopenharmony_ci instantiated. 527db96d56Sopenharmony_ci """ 537db96d56Sopenharmony_ci # late import because of mutual dependence between these classes 547db96d56Sopenharmony_ci from distutils.dist import Distribution 557db96d56Sopenharmony_ci 567db96d56Sopenharmony_ci if not isinstance(dist, Distribution): 577db96d56Sopenharmony_ci raise TypeError("dist must be a Distribution instance") 587db96d56Sopenharmony_ci if self.__class__ is Command: 597db96d56Sopenharmony_ci raise RuntimeError("Command is an abstract class") 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci self.distribution = dist 627db96d56Sopenharmony_ci self.initialize_options() 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_ci # Per-command versions of the global flags, so that the user can 657db96d56Sopenharmony_ci # customize Distutils' behaviour command-by-command and let some 667db96d56Sopenharmony_ci # commands fall back on the Distribution's behaviour. None means 677db96d56Sopenharmony_ci # "not defined, check self.distribution's copy", while 0 or 1 mean 687db96d56Sopenharmony_ci # false and true (duh). Note that this means figuring out the real 697db96d56Sopenharmony_ci # value of each flag is a touch complicated -- hence "self._dry_run" 707db96d56Sopenharmony_ci # will be handled by __getattr__, below. 717db96d56Sopenharmony_ci # XXX This needs to be fixed. 727db96d56Sopenharmony_ci self._dry_run = None 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci # verbose is largely ignored, but needs to be set for 757db96d56Sopenharmony_ci # backwards compatibility (I think)? 767db96d56Sopenharmony_ci self.verbose = dist.verbose 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci # Some commands define a 'self.force' option to ignore file 797db96d56Sopenharmony_ci # timestamps, but methods defined *here* assume that 807db96d56Sopenharmony_ci # 'self.force' exists for all commands. So define it here 817db96d56Sopenharmony_ci # just to be safe. 827db96d56Sopenharmony_ci self.force = None 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ci # The 'help' flag is just used for command-line parsing, so 857db96d56Sopenharmony_ci # none of that complicated bureaucracy is needed. 867db96d56Sopenharmony_ci self.help = 0 877db96d56Sopenharmony_ci 887db96d56Sopenharmony_ci # 'finalized' records whether or not 'finalize_options()' has been 897db96d56Sopenharmony_ci # called. 'finalize_options()' itself should not pay attention to 907db96d56Sopenharmony_ci # this flag: it is the business of 'ensure_finalized()', which 917db96d56Sopenharmony_ci # always calls 'finalize_options()', to respect/update it. 927db96d56Sopenharmony_ci self.finalized = 0 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ci # XXX A more explicit way to customize dry_run would be better. 957db96d56Sopenharmony_ci def __getattr__(self, attr): 967db96d56Sopenharmony_ci if attr == 'dry_run': 977db96d56Sopenharmony_ci myval = getattr(self, "_" + attr) 987db96d56Sopenharmony_ci if myval is None: 997db96d56Sopenharmony_ci return getattr(self.distribution, attr) 1007db96d56Sopenharmony_ci else: 1017db96d56Sopenharmony_ci return myval 1027db96d56Sopenharmony_ci else: 1037db96d56Sopenharmony_ci raise AttributeError(attr) 1047db96d56Sopenharmony_ci 1057db96d56Sopenharmony_ci def ensure_finalized(self): 1067db96d56Sopenharmony_ci if not self.finalized: 1077db96d56Sopenharmony_ci self.finalize_options() 1087db96d56Sopenharmony_ci self.finalized = 1 1097db96d56Sopenharmony_ci 1107db96d56Sopenharmony_ci # Subclasses must define: 1117db96d56Sopenharmony_ci # initialize_options() 1127db96d56Sopenharmony_ci # provide default values for all options; may be customized by 1137db96d56Sopenharmony_ci # setup script, by options from config file(s), or by command-line 1147db96d56Sopenharmony_ci # options 1157db96d56Sopenharmony_ci # finalize_options() 1167db96d56Sopenharmony_ci # decide on the final values for all options; this is called 1177db96d56Sopenharmony_ci # after all possible intervention from the outside world 1187db96d56Sopenharmony_ci # (command-line, option file, etc.) has been processed 1197db96d56Sopenharmony_ci # run() 1207db96d56Sopenharmony_ci # run the command: do whatever it is we're here to do, 1217db96d56Sopenharmony_ci # controlled by the command's various option values 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci def initialize_options(self): 1247db96d56Sopenharmony_ci """Set default values for all the options that this command 1257db96d56Sopenharmony_ci supports. Note that these defaults may be overridden by other 1267db96d56Sopenharmony_ci commands, by the setup script, by config files, or by the 1277db96d56Sopenharmony_ci command-line. Thus, this is not the place to code dependencies 1287db96d56Sopenharmony_ci between options; generally, 'initialize_options()' implementations 1297db96d56Sopenharmony_ci are just a bunch of "self.foo = None" assignments. 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci This method must be implemented by all command classes. 1327db96d56Sopenharmony_ci """ 1337db96d56Sopenharmony_ci raise RuntimeError("abstract method -- subclass %s must override" 1347db96d56Sopenharmony_ci % self.__class__) 1357db96d56Sopenharmony_ci 1367db96d56Sopenharmony_ci def finalize_options(self): 1377db96d56Sopenharmony_ci """Set final values for all the options that this command supports. 1387db96d56Sopenharmony_ci This is always called as late as possible, ie. after any option 1397db96d56Sopenharmony_ci assignments from the command-line or from other commands have been 1407db96d56Sopenharmony_ci done. Thus, this is the place to code option dependencies: if 1417db96d56Sopenharmony_ci 'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as 1427db96d56Sopenharmony_ci long as 'foo' still has the same value it was assigned in 1437db96d56Sopenharmony_ci 'initialize_options()'. 1447db96d56Sopenharmony_ci 1457db96d56Sopenharmony_ci This method must be implemented by all command classes. 1467db96d56Sopenharmony_ci """ 1477db96d56Sopenharmony_ci raise RuntimeError("abstract method -- subclass %s must override" 1487db96d56Sopenharmony_ci % self.__class__) 1497db96d56Sopenharmony_ci 1507db96d56Sopenharmony_ci 1517db96d56Sopenharmony_ci def dump_options(self, header=None, indent=""): 1527db96d56Sopenharmony_ci from distutils.fancy_getopt import longopt_xlate 1537db96d56Sopenharmony_ci if header is None: 1547db96d56Sopenharmony_ci header = "command options for '%s':" % self.get_command_name() 1557db96d56Sopenharmony_ci self.announce(indent + header, level=log.INFO) 1567db96d56Sopenharmony_ci indent = indent + " " 1577db96d56Sopenharmony_ci for (option, _, _) in self.user_options: 1587db96d56Sopenharmony_ci option = option.translate(longopt_xlate) 1597db96d56Sopenharmony_ci if option[-1] == "=": 1607db96d56Sopenharmony_ci option = option[:-1] 1617db96d56Sopenharmony_ci value = getattr(self, option) 1627db96d56Sopenharmony_ci self.announce(indent + "%s = %s" % (option, value), 1637db96d56Sopenharmony_ci level=log.INFO) 1647db96d56Sopenharmony_ci 1657db96d56Sopenharmony_ci def run(self): 1667db96d56Sopenharmony_ci """A command's raison d'etre: carry out the action it exists to 1677db96d56Sopenharmony_ci perform, controlled by the options initialized in 1687db96d56Sopenharmony_ci 'initialize_options()', customized by other commands, the setup 1697db96d56Sopenharmony_ci script, the command-line, and config files, and finalized in 1707db96d56Sopenharmony_ci 'finalize_options()'. All terminal output and filesystem 1717db96d56Sopenharmony_ci interaction should be done by 'run()'. 1727db96d56Sopenharmony_ci 1737db96d56Sopenharmony_ci This method must be implemented by all command classes. 1747db96d56Sopenharmony_ci """ 1757db96d56Sopenharmony_ci raise RuntimeError("abstract method -- subclass %s must override" 1767db96d56Sopenharmony_ci % self.__class__) 1777db96d56Sopenharmony_ci 1787db96d56Sopenharmony_ci def announce(self, msg, level=1): 1797db96d56Sopenharmony_ci """If the current verbosity level is of greater than or equal to 1807db96d56Sopenharmony_ci 'level' print 'msg' to stdout. 1817db96d56Sopenharmony_ci """ 1827db96d56Sopenharmony_ci log.log(level, msg) 1837db96d56Sopenharmony_ci 1847db96d56Sopenharmony_ci def debug_print(self, msg): 1857db96d56Sopenharmony_ci """Print 'msg' to stdout if the global DEBUG (taken from the 1867db96d56Sopenharmony_ci DISTUTILS_DEBUG environment variable) flag is true. 1877db96d56Sopenharmony_ci """ 1887db96d56Sopenharmony_ci from distutils.debug import DEBUG 1897db96d56Sopenharmony_ci if DEBUG: 1907db96d56Sopenharmony_ci print(msg) 1917db96d56Sopenharmony_ci sys.stdout.flush() 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_ci # -- Option validation methods ------------------------------------- 1957db96d56Sopenharmony_ci # (these are very handy in writing the 'finalize_options()' method) 1967db96d56Sopenharmony_ci # 1977db96d56Sopenharmony_ci # NB. the general philosophy here is to ensure that a particular option 1987db96d56Sopenharmony_ci # value meets certain type and value constraints. If not, we try to 1997db96d56Sopenharmony_ci # force it into conformance (eg. if we expect a list but have a string, 2007db96d56Sopenharmony_ci # split the string on comma and/or whitespace). If we can't force the 2017db96d56Sopenharmony_ci # option into conformance, raise DistutilsOptionError. Thus, command 2027db96d56Sopenharmony_ci # classes need do nothing more than (eg.) 2037db96d56Sopenharmony_ci # self.ensure_string_list('foo') 2047db96d56Sopenharmony_ci # and they can be guaranteed that thereafter, self.foo will be 2057db96d56Sopenharmony_ci # a list of strings. 2067db96d56Sopenharmony_ci 2077db96d56Sopenharmony_ci def _ensure_stringlike(self, option, what, default=None): 2087db96d56Sopenharmony_ci val = getattr(self, option) 2097db96d56Sopenharmony_ci if val is None: 2107db96d56Sopenharmony_ci setattr(self, option, default) 2117db96d56Sopenharmony_ci return default 2127db96d56Sopenharmony_ci elif not isinstance(val, str): 2137db96d56Sopenharmony_ci raise DistutilsOptionError("'%s' must be a %s (got `%s`)" 2147db96d56Sopenharmony_ci % (option, what, val)) 2157db96d56Sopenharmony_ci return val 2167db96d56Sopenharmony_ci 2177db96d56Sopenharmony_ci def ensure_string(self, option, default=None): 2187db96d56Sopenharmony_ci """Ensure that 'option' is a string; if not defined, set it to 2197db96d56Sopenharmony_ci 'default'. 2207db96d56Sopenharmony_ci """ 2217db96d56Sopenharmony_ci self._ensure_stringlike(option, "string", default) 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci def ensure_string_list(self, option): 2247db96d56Sopenharmony_ci r"""Ensure that 'option' is a list of strings. If 'option' is 2257db96d56Sopenharmony_ci currently a string, we split it either on /,\s*/ or /\s+/, so 2267db96d56Sopenharmony_ci "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become 2277db96d56Sopenharmony_ci ["foo", "bar", "baz"]. 2287db96d56Sopenharmony_ci """ 2297db96d56Sopenharmony_ci val = getattr(self, option) 2307db96d56Sopenharmony_ci if val is None: 2317db96d56Sopenharmony_ci return 2327db96d56Sopenharmony_ci elif isinstance(val, str): 2337db96d56Sopenharmony_ci setattr(self, option, re.split(r',\s*|\s+', val)) 2347db96d56Sopenharmony_ci else: 2357db96d56Sopenharmony_ci if isinstance(val, list): 2367db96d56Sopenharmony_ci ok = all(isinstance(v, str) for v in val) 2377db96d56Sopenharmony_ci else: 2387db96d56Sopenharmony_ci ok = False 2397db96d56Sopenharmony_ci if not ok: 2407db96d56Sopenharmony_ci raise DistutilsOptionError( 2417db96d56Sopenharmony_ci "'%s' must be a list of strings (got %r)" 2427db96d56Sopenharmony_ci % (option, val)) 2437db96d56Sopenharmony_ci 2447db96d56Sopenharmony_ci def _ensure_tested_string(self, option, tester, what, error_fmt, 2457db96d56Sopenharmony_ci default=None): 2467db96d56Sopenharmony_ci val = self._ensure_stringlike(option, what, default) 2477db96d56Sopenharmony_ci if val is not None and not tester(val): 2487db96d56Sopenharmony_ci raise DistutilsOptionError(("error in '%s' option: " + error_fmt) 2497db96d56Sopenharmony_ci % (option, val)) 2507db96d56Sopenharmony_ci 2517db96d56Sopenharmony_ci def ensure_filename(self, option): 2527db96d56Sopenharmony_ci """Ensure that 'option' is the name of an existing file.""" 2537db96d56Sopenharmony_ci self._ensure_tested_string(option, os.path.isfile, 2547db96d56Sopenharmony_ci "filename", 2557db96d56Sopenharmony_ci "'%s' does not exist or is not a file") 2567db96d56Sopenharmony_ci 2577db96d56Sopenharmony_ci def ensure_dirname(self, option): 2587db96d56Sopenharmony_ci self._ensure_tested_string(option, os.path.isdir, 2597db96d56Sopenharmony_ci "directory name", 2607db96d56Sopenharmony_ci "'%s' does not exist or is not a directory") 2617db96d56Sopenharmony_ci 2627db96d56Sopenharmony_ci 2637db96d56Sopenharmony_ci # -- Convenience methods for commands ------------------------------ 2647db96d56Sopenharmony_ci 2657db96d56Sopenharmony_ci def get_command_name(self): 2667db96d56Sopenharmony_ci if hasattr(self, 'command_name'): 2677db96d56Sopenharmony_ci return self.command_name 2687db96d56Sopenharmony_ci else: 2697db96d56Sopenharmony_ci return self.__class__.__name__ 2707db96d56Sopenharmony_ci 2717db96d56Sopenharmony_ci def set_undefined_options(self, src_cmd, *option_pairs): 2727db96d56Sopenharmony_ci """Set the values of any "undefined" options from corresponding 2737db96d56Sopenharmony_ci option values in some other command object. "Undefined" here means 2747db96d56Sopenharmony_ci "is None", which is the convention used to indicate that an option 2757db96d56Sopenharmony_ci has not been changed between 'initialize_options()' and 2767db96d56Sopenharmony_ci 'finalize_options()'. Usually called from 'finalize_options()' for 2777db96d56Sopenharmony_ci options that depend on some other command rather than another 2787db96d56Sopenharmony_ci option of the same command. 'src_cmd' is the other command from 2797db96d56Sopenharmony_ci which option values will be taken (a command object will be created 2807db96d56Sopenharmony_ci for it if necessary); the remaining arguments are 2817db96d56Sopenharmony_ci '(src_option,dst_option)' tuples which mean "take the value of 2827db96d56Sopenharmony_ci 'src_option' in the 'src_cmd' command object, and copy it to 2837db96d56Sopenharmony_ci 'dst_option' in the current command object". 2847db96d56Sopenharmony_ci """ 2857db96d56Sopenharmony_ci # Option_pairs: list of (src_option, dst_option) tuples 2867db96d56Sopenharmony_ci src_cmd_obj = self.distribution.get_command_obj(src_cmd) 2877db96d56Sopenharmony_ci src_cmd_obj.ensure_finalized() 2887db96d56Sopenharmony_ci for (src_option, dst_option) in option_pairs: 2897db96d56Sopenharmony_ci if getattr(self, dst_option) is None: 2907db96d56Sopenharmony_ci setattr(self, dst_option, getattr(src_cmd_obj, src_option)) 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci def get_finalized_command(self, command, create=1): 2937db96d56Sopenharmony_ci """Wrapper around Distribution's 'get_command_obj()' method: find 2947db96d56Sopenharmony_ci (create if necessary and 'create' is true) the command object for 2957db96d56Sopenharmony_ci 'command', call its 'ensure_finalized()' method, and return the 2967db96d56Sopenharmony_ci finalized command object. 2977db96d56Sopenharmony_ci """ 2987db96d56Sopenharmony_ci cmd_obj = self.distribution.get_command_obj(command, create) 2997db96d56Sopenharmony_ci cmd_obj.ensure_finalized() 3007db96d56Sopenharmony_ci return cmd_obj 3017db96d56Sopenharmony_ci 3027db96d56Sopenharmony_ci # XXX rename to 'get_reinitialized_command()'? (should do the 3037db96d56Sopenharmony_ci # same in dist.py, if so) 3047db96d56Sopenharmony_ci def reinitialize_command(self, command, reinit_subcommands=0): 3057db96d56Sopenharmony_ci return self.distribution.reinitialize_command(command, 3067db96d56Sopenharmony_ci reinit_subcommands) 3077db96d56Sopenharmony_ci 3087db96d56Sopenharmony_ci def run_command(self, command): 3097db96d56Sopenharmony_ci """Run some other command: uses the 'run_command()' method of 3107db96d56Sopenharmony_ci Distribution, which creates and finalizes the command object if 3117db96d56Sopenharmony_ci necessary and then invokes its 'run()' method. 3127db96d56Sopenharmony_ci """ 3137db96d56Sopenharmony_ci self.distribution.run_command(command) 3147db96d56Sopenharmony_ci 3157db96d56Sopenharmony_ci def get_sub_commands(self): 3167db96d56Sopenharmony_ci """Determine the sub-commands that are relevant in the current 3177db96d56Sopenharmony_ci distribution (ie., that need to be run). This is based on the 3187db96d56Sopenharmony_ci 'sub_commands' class attribute: each tuple in that list may include 3197db96d56Sopenharmony_ci a method that we call to determine if the subcommand needs to be 3207db96d56Sopenharmony_ci run for the current distribution. Return a list of command names. 3217db96d56Sopenharmony_ci """ 3227db96d56Sopenharmony_ci commands = [] 3237db96d56Sopenharmony_ci for (cmd_name, method) in self.sub_commands: 3247db96d56Sopenharmony_ci if method is None or method(self): 3257db96d56Sopenharmony_ci commands.append(cmd_name) 3267db96d56Sopenharmony_ci return commands 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ci 3297db96d56Sopenharmony_ci # -- External world manipulation ----------------------------------- 3307db96d56Sopenharmony_ci 3317db96d56Sopenharmony_ci def warn(self, msg): 3327db96d56Sopenharmony_ci log.warn("warning: %s: %s\n", self.get_command_name(), msg) 3337db96d56Sopenharmony_ci 3347db96d56Sopenharmony_ci def execute(self, func, args, msg=None, level=1): 3357db96d56Sopenharmony_ci util.execute(func, args, msg, dry_run=self.dry_run) 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_ci def mkpath(self, name, mode=0o777): 3387db96d56Sopenharmony_ci dir_util.mkpath(name, mode, dry_run=self.dry_run) 3397db96d56Sopenharmony_ci 3407db96d56Sopenharmony_ci def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, 3417db96d56Sopenharmony_ci link=None, level=1): 3427db96d56Sopenharmony_ci """Copy a file respecting verbose, dry-run and force flags. (The 3437db96d56Sopenharmony_ci former two default to whatever is in the Distribution object, and 3447db96d56Sopenharmony_ci the latter defaults to false for commands that don't define it.)""" 3457db96d56Sopenharmony_ci return file_util.copy_file(infile, outfile, preserve_mode, 3467db96d56Sopenharmony_ci preserve_times, not self.force, link, 3477db96d56Sopenharmony_ci dry_run=self.dry_run) 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ci def copy_tree(self, infile, outfile, preserve_mode=1, preserve_times=1, 3507db96d56Sopenharmony_ci preserve_symlinks=0, level=1): 3517db96d56Sopenharmony_ci """Copy an entire directory tree respecting verbose, dry-run, 3527db96d56Sopenharmony_ci and force flags. 3537db96d56Sopenharmony_ci """ 3547db96d56Sopenharmony_ci return dir_util.copy_tree(infile, outfile, preserve_mode, 3557db96d56Sopenharmony_ci preserve_times, preserve_symlinks, 3567db96d56Sopenharmony_ci not self.force, dry_run=self.dry_run) 3577db96d56Sopenharmony_ci 3587db96d56Sopenharmony_ci def move_file (self, src, dst, level=1): 3597db96d56Sopenharmony_ci """Move a file respecting dry-run flag.""" 3607db96d56Sopenharmony_ci return file_util.move_file(src, dst, dry_run=self.dry_run) 3617db96d56Sopenharmony_ci 3627db96d56Sopenharmony_ci def spawn(self, cmd, search_path=1, level=1): 3637db96d56Sopenharmony_ci """Spawn an external command respecting dry-run flag.""" 3647db96d56Sopenharmony_ci from distutils.spawn import spawn 3657db96d56Sopenharmony_ci spawn(cmd, search_path, dry_run=self.dry_run) 3667db96d56Sopenharmony_ci 3677db96d56Sopenharmony_ci def make_archive(self, base_name, format, root_dir=None, base_dir=None, 3687db96d56Sopenharmony_ci owner=None, group=None): 3697db96d56Sopenharmony_ci return archive_util.make_archive(base_name, format, root_dir, base_dir, 3707db96d56Sopenharmony_ci dry_run=self.dry_run, 3717db96d56Sopenharmony_ci owner=owner, group=group) 3727db96d56Sopenharmony_ci 3737db96d56Sopenharmony_ci def make_file(self, infiles, outfile, func, args, 3747db96d56Sopenharmony_ci exec_msg=None, skip_msg=None, level=1): 3757db96d56Sopenharmony_ci """Special case of 'execute()' for operations that process one or 3767db96d56Sopenharmony_ci more input files and generate one output file. Works just like 3777db96d56Sopenharmony_ci 'execute()', except the operation is skipped and a different 3787db96d56Sopenharmony_ci message printed if 'outfile' already exists and is newer than all 3797db96d56Sopenharmony_ci files listed in 'infiles'. If the command defined 'self.force', 3807db96d56Sopenharmony_ci and it is true, then the command is unconditionally run -- does no 3817db96d56Sopenharmony_ci timestamp checks. 3827db96d56Sopenharmony_ci """ 3837db96d56Sopenharmony_ci if skip_msg is None: 3847db96d56Sopenharmony_ci skip_msg = "skipping %s (inputs unchanged)" % outfile 3857db96d56Sopenharmony_ci 3867db96d56Sopenharmony_ci # Allow 'infiles' to be a single string 3877db96d56Sopenharmony_ci if isinstance(infiles, str): 3887db96d56Sopenharmony_ci infiles = (infiles,) 3897db96d56Sopenharmony_ci elif not isinstance(infiles, (list, tuple)): 3907db96d56Sopenharmony_ci raise TypeError( 3917db96d56Sopenharmony_ci "'infiles' must be a string, or a list or tuple of strings") 3927db96d56Sopenharmony_ci 3937db96d56Sopenharmony_ci if exec_msg is None: 3947db96d56Sopenharmony_ci exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles)) 3957db96d56Sopenharmony_ci 3967db96d56Sopenharmony_ci # If 'outfile' must be regenerated (either because it doesn't 3977db96d56Sopenharmony_ci # exist, is out-of-date, or the 'force' flag is true) then 3987db96d56Sopenharmony_ci # perform the action that presumably regenerates it 3997db96d56Sopenharmony_ci if self.force or dep_util.newer_group(infiles, outfile): 4007db96d56Sopenharmony_ci self.execute(func, args, exec_msg, level) 4017db96d56Sopenharmony_ci # Otherwise, print the "skip" message 4027db96d56Sopenharmony_ci else: 4037db96d56Sopenharmony_ci log.debug(skip_msg) 404