17db96d56Sopenharmony_ci"""distutils.dist 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciProvides the Distribution class, which represents the module distribution 47db96d56Sopenharmony_cibeing built/installed/distributed. 57db96d56Sopenharmony_ci""" 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ciimport sys 87db96d56Sopenharmony_ciimport os 97db96d56Sopenharmony_ciimport re 107db96d56Sopenharmony_cifrom email import message_from_file 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_citry: 137db96d56Sopenharmony_ci import warnings 147db96d56Sopenharmony_ciexcept ImportError: 157db96d56Sopenharmony_ci warnings = None 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_cifrom distutils.errors import * 187db96d56Sopenharmony_cifrom distutils.fancy_getopt import FancyGetopt, translate_longopt 197db96d56Sopenharmony_cifrom distutils.util import check_environ, strtobool, rfc822_escape 207db96d56Sopenharmony_cifrom distutils import log 217db96d56Sopenharmony_cifrom distutils.debug import DEBUG 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ci# Regex to define acceptable Distutils command names. This is not *quite* 247db96d56Sopenharmony_ci# the same as a Python NAME -- I don't allow leading underscores. The fact 257db96d56Sopenharmony_ci# that they're very similar is no coincidence; the default naming scheme is 267db96d56Sopenharmony_ci# to look for a Python module named after the command. 277db96d56Sopenharmony_cicommand_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$') 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_cidef _ensure_list(value, fieldname): 317db96d56Sopenharmony_ci if isinstance(value, str): 327db96d56Sopenharmony_ci # a string containing comma separated values is okay. It will 337db96d56Sopenharmony_ci # be converted to a list by Distribution.finalize_options(). 347db96d56Sopenharmony_ci pass 357db96d56Sopenharmony_ci elif not isinstance(value, list): 367db96d56Sopenharmony_ci # passing a tuple or an iterator perhaps, warn and convert 377db96d56Sopenharmony_ci typename = type(value).__name__ 387db96d56Sopenharmony_ci msg = f"Warning: '{fieldname}' should be a list, got type '{typename}'" 397db96d56Sopenharmony_ci log.log(log.WARN, msg) 407db96d56Sopenharmony_ci value = list(value) 417db96d56Sopenharmony_ci return value 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ciclass Distribution: 457db96d56Sopenharmony_ci """The core of the Distutils. Most of the work hiding behind 'setup' 467db96d56Sopenharmony_ci is really done within a Distribution instance, which farms the work out 477db96d56Sopenharmony_ci to the Distutils commands specified on the command line. 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ci Setup scripts will almost never instantiate Distribution directly, 507db96d56Sopenharmony_ci unless the 'setup()' function is totally inadequate to their needs. 517db96d56Sopenharmony_ci However, it is conceivable that a setup script might wish to subclass 527db96d56Sopenharmony_ci Distribution for some specialized purpose, and then pass the subclass 537db96d56Sopenharmony_ci to 'setup()' as the 'distclass' keyword argument. If so, it is 547db96d56Sopenharmony_ci necessary to respect the expectations that 'setup' has of Distribution. 557db96d56Sopenharmony_ci See the code for 'setup()', in core.py, for details. 567db96d56Sopenharmony_ci """ 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci # 'global_options' describes the command-line options that may be 597db96d56Sopenharmony_ci # supplied to the setup script prior to any actual commands. 607db96d56Sopenharmony_ci # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of 617db96d56Sopenharmony_ci # these global options. This list should be kept to a bare minimum, 627db96d56Sopenharmony_ci # since every global option is also valid as a command option -- and we 637db96d56Sopenharmony_ci # don't want to pollute the commands with too many options that they 647db96d56Sopenharmony_ci # have minimal control over. 657db96d56Sopenharmony_ci # The fourth entry for verbose means that it can be repeated. 667db96d56Sopenharmony_ci global_options = [ 677db96d56Sopenharmony_ci ('verbose', 'v', "run verbosely (default)", 1), 687db96d56Sopenharmony_ci ('quiet', 'q', "run quietly (turns verbosity off)"), 697db96d56Sopenharmony_ci ('dry-run', 'n', "don't actually do anything"), 707db96d56Sopenharmony_ci ('help', 'h', "show detailed help message"), 717db96d56Sopenharmony_ci ('no-user-cfg', None, 727db96d56Sopenharmony_ci 'ignore pydistutils.cfg in your home directory'), 737db96d56Sopenharmony_ci ] 747db96d56Sopenharmony_ci 757db96d56Sopenharmony_ci # 'common_usage' is a short (2-3 line) string describing the common 767db96d56Sopenharmony_ci # usage of the setup script. 777db96d56Sopenharmony_ci common_usage = """\ 787db96d56Sopenharmony_ciCommon commands: (see '--help-commands' for more) 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ci setup.py build will build the package underneath 'build/' 817db96d56Sopenharmony_ci setup.py install will install the package 827db96d56Sopenharmony_ci""" 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ci # options that are not propagated to the commands 857db96d56Sopenharmony_ci display_options = [ 867db96d56Sopenharmony_ci ('help-commands', None, 877db96d56Sopenharmony_ci "list all available commands"), 887db96d56Sopenharmony_ci ('name', None, 897db96d56Sopenharmony_ci "print package name"), 907db96d56Sopenharmony_ci ('version', 'V', 917db96d56Sopenharmony_ci "print package version"), 927db96d56Sopenharmony_ci ('fullname', None, 937db96d56Sopenharmony_ci "print <package name>-<version>"), 947db96d56Sopenharmony_ci ('author', None, 957db96d56Sopenharmony_ci "print the author's name"), 967db96d56Sopenharmony_ci ('author-email', None, 977db96d56Sopenharmony_ci "print the author's email address"), 987db96d56Sopenharmony_ci ('maintainer', None, 997db96d56Sopenharmony_ci "print the maintainer's name"), 1007db96d56Sopenharmony_ci ('maintainer-email', None, 1017db96d56Sopenharmony_ci "print the maintainer's email address"), 1027db96d56Sopenharmony_ci ('contact', None, 1037db96d56Sopenharmony_ci "print the maintainer's name if known, else the author's"), 1047db96d56Sopenharmony_ci ('contact-email', None, 1057db96d56Sopenharmony_ci "print the maintainer's email address if known, else the author's"), 1067db96d56Sopenharmony_ci ('url', None, 1077db96d56Sopenharmony_ci "print the URL for this package"), 1087db96d56Sopenharmony_ci ('license', None, 1097db96d56Sopenharmony_ci "print the license of the package"), 1107db96d56Sopenharmony_ci ('licence', None, 1117db96d56Sopenharmony_ci "alias for --license"), 1127db96d56Sopenharmony_ci ('description', None, 1137db96d56Sopenharmony_ci "print the package description"), 1147db96d56Sopenharmony_ci ('long-description', None, 1157db96d56Sopenharmony_ci "print the long package description"), 1167db96d56Sopenharmony_ci ('platforms', None, 1177db96d56Sopenharmony_ci "print the list of platforms"), 1187db96d56Sopenharmony_ci ('classifiers', None, 1197db96d56Sopenharmony_ci "print the list of classifiers"), 1207db96d56Sopenharmony_ci ('keywords', None, 1217db96d56Sopenharmony_ci "print the list of keywords"), 1227db96d56Sopenharmony_ci ('provides', None, 1237db96d56Sopenharmony_ci "print the list of packages/modules provided"), 1247db96d56Sopenharmony_ci ('requires', None, 1257db96d56Sopenharmony_ci "print the list of packages/modules required"), 1267db96d56Sopenharmony_ci ('obsoletes', None, 1277db96d56Sopenharmony_ci "print the list of packages/modules made obsolete") 1287db96d56Sopenharmony_ci ] 1297db96d56Sopenharmony_ci display_option_names = [translate_longopt(x[0]) for x in display_options] 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci # negative options are options that exclude other options 1327db96d56Sopenharmony_ci negative_opt = {'quiet': 'verbose'} 1337db96d56Sopenharmony_ci 1347db96d56Sopenharmony_ci # -- Creation/initialization methods ------------------------------- 1357db96d56Sopenharmony_ci 1367db96d56Sopenharmony_ci def __init__(self, attrs=None): 1377db96d56Sopenharmony_ci """Construct a new Distribution instance: initialize all the 1387db96d56Sopenharmony_ci attributes of a Distribution, and then use 'attrs' (a dictionary 1397db96d56Sopenharmony_ci mapping attribute names to values) to assign some of those 1407db96d56Sopenharmony_ci attributes their "real" values. (Any attributes not mentioned in 1417db96d56Sopenharmony_ci 'attrs' will be assigned to some null value: 0, None, an empty list 1427db96d56Sopenharmony_ci or dictionary, etc.) Most importantly, initialize the 1437db96d56Sopenharmony_ci 'command_obj' attribute to the empty dictionary; this will be 1447db96d56Sopenharmony_ci filled in with real command objects by 'parse_command_line()'. 1457db96d56Sopenharmony_ci """ 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci # Default values for our command-line options 1487db96d56Sopenharmony_ci self.verbose = 1 1497db96d56Sopenharmony_ci self.dry_run = 0 1507db96d56Sopenharmony_ci self.help = 0 1517db96d56Sopenharmony_ci for attr in self.display_option_names: 1527db96d56Sopenharmony_ci setattr(self, attr, 0) 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci # Store the distribution meta-data (name, version, author, and so 1557db96d56Sopenharmony_ci # forth) in a separate object -- we're getting to have enough 1567db96d56Sopenharmony_ci # information here (and enough command-line options) that it's 1577db96d56Sopenharmony_ci # worth it. Also delegate 'get_XXX()' methods to the 'metadata' 1587db96d56Sopenharmony_ci # object in a sneaky and underhanded (but efficient!) way. 1597db96d56Sopenharmony_ci self.metadata = DistributionMetadata() 1607db96d56Sopenharmony_ci for basename in self.metadata._METHOD_BASENAMES: 1617db96d56Sopenharmony_ci method_name = "get_" + basename 1627db96d56Sopenharmony_ci setattr(self, method_name, getattr(self.metadata, method_name)) 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci # 'cmdclass' maps command names to class objects, so we 1657db96d56Sopenharmony_ci # can 1) quickly figure out which class to instantiate when 1667db96d56Sopenharmony_ci # we need to create a new command object, and 2) have a way 1677db96d56Sopenharmony_ci # for the setup script to override command classes 1687db96d56Sopenharmony_ci self.cmdclass = {} 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci # 'command_packages' is a list of packages in which commands 1717db96d56Sopenharmony_ci # are searched for. The factory for command 'foo' is expected 1727db96d56Sopenharmony_ci # to be named 'foo' in the module 'foo' in one of the packages 1737db96d56Sopenharmony_ci # named here. This list is searched from the left; an error 1747db96d56Sopenharmony_ci # is raised if no named package provides the command being 1757db96d56Sopenharmony_ci # searched for. (Always access using get_command_packages().) 1767db96d56Sopenharmony_ci self.command_packages = None 1777db96d56Sopenharmony_ci 1787db96d56Sopenharmony_ci # 'script_name' and 'script_args' are usually set to sys.argv[0] 1797db96d56Sopenharmony_ci # and sys.argv[1:], but they can be overridden when the caller is 1807db96d56Sopenharmony_ci # not necessarily a setup script run from the command-line. 1817db96d56Sopenharmony_ci self.script_name = None 1827db96d56Sopenharmony_ci self.script_args = None 1837db96d56Sopenharmony_ci 1847db96d56Sopenharmony_ci # 'command_options' is where we store command options between 1857db96d56Sopenharmony_ci # parsing them (from config files, the command-line, etc.) and when 1867db96d56Sopenharmony_ci # they are actually needed -- ie. when the command in question is 1877db96d56Sopenharmony_ci # instantiated. It is a dictionary of dictionaries of 2-tuples: 1887db96d56Sopenharmony_ci # command_options = { command_name : { option : (source, value) } } 1897db96d56Sopenharmony_ci self.command_options = {} 1907db96d56Sopenharmony_ci 1917db96d56Sopenharmony_ci # 'dist_files' is the list of (command, pyversion, file) that 1927db96d56Sopenharmony_ci # have been created by any dist commands run so far. This is 1937db96d56Sopenharmony_ci # filled regardless of whether the run is dry or not. pyversion 1947db96d56Sopenharmony_ci # gives sysconfig.get_python_version() if the dist file is 1957db96d56Sopenharmony_ci # specific to a Python version, 'any' if it is good for all 1967db96d56Sopenharmony_ci # Python versions on the target platform, and '' for a source 1977db96d56Sopenharmony_ci # file. pyversion should not be used to specify minimum or 1987db96d56Sopenharmony_ci # maximum required Python versions; use the metainfo for that 1997db96d56Sopenharmony_ci # instead. 2007db96d56Sopenharmony_ci self.dist_files = [] 2017db96d56Sopenharmony_ci 2027db96d56Sopenharmony_ci # These options are really the business of various commands, rather 2037db96d56Sopenharmony_ci # than of the Distribution itself. We provide aliases for them in 2047db96d56Sopenharmony_ci # Distribution as a convenience to the developer. 2057db96d56Sopenharmony_ci self.packages = None 2067db96d56Sopenharmony_ci self.package_data = {} 2077db96d56Sopenharmony_ci self.package_dir = None 2087db96d56Sopenharmony_ci self.py_modules = None 2097db96d56Sopenharmony_ci self.libraries = None 2107db96d56Sopenharmony_ci self.headers = None 2117db96d56Sopenharmony_ci self.ext_modules = None 2127db96d56Sopenharmony_ci self.ext_package = None 2137db96d56Sopenharmony_ci self.include_dirs = None 2147db96d56Sopenharmony_ci self.extra_path = None 2157db96d56Sopenharmony_ci self.scripts = None 2167db96d56Sopenharmony_ci self.data_files = None 2177db96d56Sopenharmony_ci self.password = '' 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci # And now initialize bookkeeping stuff that can't be supplied by 2207db96d56Sopenharmony_ci # the caller at all. 'command_obj' maps command names to 2217db96d56Sopenharmony_ci # Command instances -- that's how we enforce that every command 2227db96d56Sopenharmony_ci # class is a singleton. 2237db96d56Sopenharmony_ci self.command_obj = {} 2247db96d56Sopenharmony_ci 2257db96d56Sopenharmony_ci # 'have_run' maps command names to boolean values; it keeps track 2267db96d56Sopenharmony_ci # of whether we have actually run a particular command, to make it 2277db96d56Sopenharmony_ci # cheap to "run" a command whenever we think we might need to -- if 2287db96d56Sopenharmony_ci # it's already been done, no need for expensive filesystem 2297db96d56Sopenharmony_ci # operations, we just check the 'have_run' dictionary and carry on. 2307db96d56Sopenharmony_ci # It's only safe to query 'have_run' for a command class that has 2317db96d56Sopenharmony_ci # been instantiated -- a false value will be inserted when the 2327db96d56Sopenharmony_ci # command object is created, and replaced with a true value when 2337db96d56Sopenharmony_ci # the command is successfully run. Thus it's probably best to use 2347db96d56Sopenharmony_ci # '.get()' rather than a straight lookup. 2357db96d56Sopenharmony_ci self.have_run = {} 2367db96d56Sopenharmony_ci 2377db96d56Sopenharmony_ci # Now we'll use the attrs dictionary (ultimately, keyword args from 2387db96d56Sopenharmony_ci # the setup script) to possibly override any or all of these 2397db96d56Sopenharmony_ci # distribution options. 2407db96d56Sopenharmony_ci 2417db96d56Sopenharmony_ci if attrs: 2427db96d56Sopenharmony_ci # Pull out the set of command options and work on them 2437db96d56Sopenharmony_ci # specifically. Note that this order guarantees that aliased 2447db96d56Sopenharmony_ci # command options will override any supplied redundantly 2457db96d56Sopenharmony_ci # through the general options dictionary. 2467db96d56Sopenharmony_ci options = attrs.get('options') 2477db96d56Sopenharmony_ci if options is not None: 2487db96d56Sopenharmony_ci del attrs['options'] 2497db96d56Sopenharmony_ci for (command, cmd_options) in options.items(): 2507db96d56Sopenharmony_ci opt_dict = self.get_option_dict(command) 2517db96d56Sopenharmony_ci for (opt, val) in cmd_options.items(): 2527db96d56Sopenharmony_ci opt_dict[opt] = ("setup script", val) 2537db96d56Sopenharmony_ci 2547db96d56Sopenharmony_ci if 'licence' in attrs: 2557db96d56Sopenharmony_ci attrs['license'] = attrs['licence'] 2567db96d56Sopenharmony_ci del attrs['licence'] 2577db96d56Sopenharmony_ci msg = "'licence' distribution option is deprecated; use 'license'" 2587db96d56Sopenharmony_ci if warnings is not None: 2597db96d56Sopenharmony_ci warnings.warn(msg) 2607db96d56Sopenharmony_ci else: 2617db96d56Sopenharmony_ci sys.stderr.write(msg + "\n") 2627db96d56Sopenharmony_ci 2637db96d56Sopenharmony_ci # Now work on the rest of the attributes. Any attribute that's 2647db96d56Sopenharmony_ci # not already defined is invalid! 2657db96d56Sopenharmony_ci for (key, val) in attrs.items(): 2667db96d56Sopenharmony_ci if hasattr(self.metadata, "set_" + key): 2677db96d56Sopenharmony_ci getattr(self.metadata, "set_" + key)(val) 2687db96d56Sopenharmony_ci elif hasattr(self.metadata, key): 2697db96d56Sopenharmony_ci setattr(self.metadata, key, val) 2707db96d56Sopenharmony_ci elif hasattr(self, key): 2717db96d56Sopenharmony_ci setattr(self, key, val) 2727db96d56Sopenharmony_ci else: 2737db96d56Sopenharmony_ci msg = "Unknown distribution option: %s" % repr(key) 2747db96d56Sopenharmony_ci warnings.warn(msg) 2757db96d56Sopenharmony_ci 2767db96d56Sopenharmony_ci # no-user-cfg is handled before other command line args 2777db96d56Sopenharmony_ci # because other args override the config files, and this 2787db96d56Sopenharmony_ci # one is needed before we can load the config files. 2797db96d56Sopenharmony_ci # If attrs['script_args'] wasn't passed, assume false. 2807db96d56Sopenharmony_ci # 2817db96d56Sopenharmony_ci # This also make sure we just look at the global options 2827db96d56Sopenharmony_ci self.want_user_cfg = True 2837db96d56Sopenharmony_ci 2847db96d56Sopenharmony_ci if self.script_args is not None: 2857db96d56Sopenharmony_ci for arg in self.script_args: 2867db96d56Sopenharmony_ci if not arg.startswith('-'): 2877db96d56Sopenharmony_ci break 2887db96d56Sopenharmony_ci if arg == '--no-user-cfg': 2897db96d56Sopenharmony_ci self.want_user_cfg = False 2907db96d56Sopenharmony_ci break 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci self.finalize_options() 2937db96d56Sopenharmony_ci 2947db96d56Sopenharmony_ci def get_option_dict(self, command): 2957db96d56Sopenharmony_ci """Get the option dictionary for a given command. If that 2967db96d56Sopenharmony_ci command's option dictionary hasn't been created yet, then create it 2977db96d56Sopenharmony_ci and return the new dictionary; otherwise, return the existing 2987db96d56Sopenharmony_ci option dictionary. 2997db96d56Sopenharmony_ci """ 3007db96d56Sopenharmony_ci dict = self.command_options.get(command) 3017db96d56Sopenharmony_ci if dict is None: 3027db96d56Sopenharmony_ci dict = self.command_options[command] = {} 3037db96d56Sopenharmony_ci return dict 3047db96d56Sopenharmony_ci 3057db96d56Sopenharmony_ci def dump_option_dicts(self, header=None, commands=None, indent=""): 3067db96d56Sopenharmony_ci from pprint import pformat 3077db96d56Sopenharmony_ci 3087db96d56Sopenharmony_ci if commands is None: # dump all command option dicts 3097db96d56Sopenharmony_ci commands = sorted(self.command_options.keys()) 3107db96d56Sopenharmony_ci 3117db96d56Sopenharmony_ci if header is not None: 3127db96d56Sopenharmony_ci self.announce(indent + header) 3137db96d56Sopenharmony_ci indent = indent + " " 3147db96d56Sopenharmony_ci 3157db96d56Sopenharmony_ci if not commands: 3167db96d56Sopenharmony_ci self.announce(indent + "no commands known yet") 3177db96d56Sopenharmony_ci return 3187db96d56Sopenharmony_ci 3197db96d56Sopenharmony_ci for cmd_name in commands: 3207db96d56Sopenharmony_ci opt_dict = self.command_options.get(cmd_name) 3217db96d56Sopenharmony_ci if opt_dict is None: 3227db96d56Sopenharmony_ci self.announce(indent + 3237db96d56Sopenharmony_ci "no option dict for '%s' command" % cmd_name) 3247db96d56Sopenharmony_ci else: 3257db96d56Sopenharmony_ci self.announce(indent + 3267db96d56Sopenharmony_ci "option dict for '%s' command:" % cmd_name) 3277db96d56Sopenharmony_ci out = pformat(opt_dict) 3287db96d56Sopenharmony_ci for line in out.split('\n'): 3297db96d56Sopenharmony_ci self.announce(indent + " " + line) 3307db96d56Sopenharmony_ci 3317db96d56Sopenharmony_ci # -- Config file finding/parsing methods --------------------------- 3327db96d56Sopenharmony_ci 3337db96d56Sopenharmony_ci def find_config_files(self): 3347db96d56Sopenharmony_ci """Find as many configuration files as should be processed for this 3357db96d56Sopenharmony_ci platform, and return a list of filenames in the order in which they 3367db96d56Sopenharmony_ci should be parsed. The filenames returned are guaranteed to exist 3377db96d56Sopenharmony_ci (modulo nasty race conditions). 3387db96d56Sopenharmony_ci 3397db96d56Sopenharmony_ci There are three possible config files: distutils.cfg in the 3407db96d56Sopenharmony_ci Distutils installation directory (ie. where the top-level 3417db96d56Sopenharmony_ci Distutils __inst__.py file lives), a file in the user's home 3427db96d56Sopenharmony_ci directory named .pydistutils.cfg on Unix and pydistutils.cfg 3437db96d56Sopenharmony_ci on Windows/Mac; and setup.cfg in the current directory. 3447db96d56Sopenharmony_ci 3457db96d56Sopenharmony_ci The file in the user's home directory can be disabled with the 3467db96d56Sopenharmony_ci --no-user-cfg option. 3477db96d56Sopenharmony_ci """ 3487db96d56Sopenharmony_ci files = [] 3497db96d56Sopenharmony_ci check_environ() 3507db96d56Sopenharmony_ci 3517db96d56Sopenharmony_ci # Where to look for the system-wide Distutils config file 3527db96d56Sopenharmony_ci sys_dir = os.path.dirname(sys.modules['distutils'].__file__) 3537db96d56Sopenharmony_ci 3547db96d56Sopenharmony_ci # Look for the system config file 3557db96d56Sopenharmony_ci sys_file = os.path.join(sys_dir, "distutils.cfg") 3567db96d56Sopenharmony_ci if os.path.isfile(sys_file): 3577db96d56Sopenharmony_ci files.append(sys_file) 3587db96d56Sopenharmony_ci 3597db96d56Sopenharmony_ci # What to call the per-user config file 3607db96d56Sopenharmony_ci if os.name == 'posix': 3617db96d56Sopenharmony_ci user_filename = ".pydistutils.cfg" 3627db96d56Sopenharmony_ci else: 3637db96d56Sopenharmony_ci user_filename = "pydistutils.cfg" 3647db96d56Sopenharmony_ci 3657db96d56Sopenharmony_ci # And look for the user config file 3667db96d56Sopenharmony_ci if self.want_user_cfg: 3677db96d56Sopenharmony_ci user_file = os.path.join(os.path.expanduser('~'), user_filename) 3687db96d56Sopenharmony_ci if os.path.isfile(user_file): 3697db96d56Sopenharmony_ci files.append(user_file) 3707db96d56Sopenharmony_ci 3717db96d56Sopenharmony_ci # All platforms support local setup.cfg 3727db96d56Sopenharmony_ci local_file = "setup.cfg" 3737db96d56Sopenharmony_ci if os.path.isfile(local_file): 3747db96d56Sopenharmony_ci files.append(local_file) 3757db96d56Sopenharmony_ci 3767db96d56Sopenharmony_ci if DEBUG: 3777db96d56Sopenharmony_ci self.announce("using config files: %s" % ', '.join(files)) 3787db96d56Sopenharmony_ci 3797db96d56Sopenharmony_ci return files 3807db96d56Sopenharmony_ci 3817db96d56Sopenharmony_ci def parse_config_files(self, filenames=None): 3827db96d56Sopenharmony_ci from configparser import ConfigParser 3837db96d56Sopenharmony_ci 3847db96d56Sopenharmony_ci # Ignore install directory options if we have a venv 3857db96d56Sopenharmony_ci if sys.prefix != sys.base_prefix: 3867db96d56Sopenharmony_ci ignore_options = [ 3877db96d56Sopenharmony_ci 'install-base', 'install-platbase', 'install-lib', 3887db96d56Sopenharmony_ci 'install-platlib', 'install-purelib', 'install-headers', 3897db96d56Sopenharmony_ci 'install-scripts', 'install-data', 'prefix', 'exec-prefix', 3907db96d56Sopenharmony_ci 'home', 'user', 'root'] 3917db96d56Sopenharmony_ci else: 3927db96d56Sopenharmony_ci ignore_options = [] 3937db96d56Sopenharmony_ci 3947db96d56Sopenharmony_ci ignore_options = frozenset(ignore_options) 3957db96d56Sopenharmony_ci 3967db96d56Sopenharmony_ci if filenames is None: 3977db96d56Sopenharmony_ci filenames = self.find_config_files() 3987db96d56Sopenharmony_ci 3997db96d56Sopenharmony_ci if DEBUG: 4007db96d56Sopenharmony_ci self.announce("Distribution.parse_config_files():") 4017db96d56Sopenharmony_ci 4027db96d56Sopenharmony_ci parser = ConfigParser() 4037db96d56Sopenharmony_ci for filename in filenames: 4047db96d56Sopenharmony_ci if DEBUG: 4057db96d56Sopenharmony_ci self.announce(" reading %s" % filename) 4067db96d56Sopenharmony_ci parser.read(filename) 4077db96d56Sopenharmony_ci for section in parser.sections(): 4087db96d56Sopenharmony_ci options = parser.options(section) 4097db96d56Sopenharmony_ci opt_dict = self.get_option_dict(section) 4107db96d56Sopenharmony_ci 4117db96d56Sopenharmony_ci for opt in options: 4127db96d56Sopenharmony_ci if opt != '__name__' and opt not in ignore_options: 4137db96d56Sopenharmony_ci val = parser.get(section,opt) 4147db96d56Sopenharmony_ci opt = opt.replace('-', '_') 4157db96d56Sopenharmony_ci opt_dict[opt] = (filename, val) 4167db96d56Sopenharmony_ci 4177db96d56Sopenharmony_ci # Make the ConfigParser forget everything (so we retain 4187db96d56Sopenharmony_ci # the original filenames that options come from) 4197db96d56Sopenharmony_ci parser.__init__() 4207db96d56Sopenharmony_ci 4217db96d56Sopenharmony_ci # If there was a "global" section in the config file, use it 4227db96d56Sopenharmony_ci # to set Distribution options. 4237db96d56Sopenharmony_ci 4247db96d56Sopenharmony_ci if 'global' in self.command_options: 4257db96d56Sopenharmony_ci for (opt, (src, val)) in self.command_options['global'].items(): 4267db96d56Sopenharmony_ci alias = self.negative_opt.get(opt) 4277db96d56Sopenharmony_ci try: 4287db96d56Sopenharmony_ci if alias: 4297db96d56Sopenharmony_ci setattr(self, alias, not strtobool(val)) 4307db96d56Sopenharmony_ci elif opt in ('verbose', 'dry_run'): # ugh! 4317db96d56Sopenharmony_ci setattr(self, opt, strtobool(val)) 4327db96d56Sopenharmony_ci else: 4337db96d56Sopenharmony_ci setattr(self, opt, val) 4347db96d56Sopenharmony_ci except ValueError as msg: 4357db96d56Sopenharmony_ci raise DistutilsOptionError(msg) 4367db96d56Sopenharmony_ci 4377db96d56Sopenharmony_ci # -- Command-line parsing methods ---------------------------------- 4387db96d56Sopenharmony_ci 4397db96d56Sopenharmony_ci def parse_command_line(self): 4407db96d56Sopenharmony_ci """Parse the setup script's command line, taken from the 4417db96d56Sopenharmony_ci 'script_args' instance attribute (which defaults to 'sys.argv[1:]' 4427db96d56Sopenharmony_ci -- see 'setup()' in core.py). This list is first processed for 4437db96d56Sopenharmony_ci "global options" -- options that set attributes of the Distribution 4447db96d56Sopenharmony_ci instance. Then, it is alternately scanned for Distutils commands 4457db96d56Sopenharmony_ci and options for that command. Each new command terminates the 4467db96d56Sopenharmony_ci options for the previous command. The allowed options for a 4477db96d56Sopenharmony_ci command are determined by the 'user_options' attribute of the 4487db96d56Sopenharmony_ci command class -- thus, we have to be able to load command classes 4497db96d56Sopenharmony_ci in order to parse the command line. Any error in that 'options' 4507db96d56Sopenharmony_ci attribute raises DistutilsGetoptError; any error on the 4517db96d56Sopenharmony_ci command-line raises DistutilsArgError. If no Distutils commands 4527db96d56Sopenharmony_ci were found on the command line, raises DistutilsArgError. Return 4537db96d56Sopenharmony_ci true if command-line was successfully parsed and we should carry 4547db96d56Sopenharmony_ci on with executing commands; false if no errors but we shouldn't 4557db96d56Sopenharmony_ci execute commands (currently, this only happens if user asks for 4567db96d56Sopenharmony_ci help). 4577db96d56Sopenharmony_ci """ 4587db96d56Sopenharmony_ci # 4597db96d56Sopenharmony_ci # We now have enough information to show the Macintosh dialog 4607db96d56Sopenharmony_ci # that allows the user to interactively specify the "command line". 4617db96d56Sopenharmony_ci # 4627db96d56Sopenharmony_ci toplevel_options = self._get_toplevel_options() 4637db96d56Sopenharmony_ci 4647db96d56Sopenharmony_ci # We have to parse the command line a bit at a time -- global 4657db96d56Sopenharmony_ci # options, then the first command, then its options, and so on -- 4667db96d56Sopenharmony_ci # because each command will be handled by a different class, and 4677db96d56Sopenharmony_ci # the options that are valid for a particular class aren't known 4687db96d56Sopenharmony_ci # until we have loaded the command class, which doesn't happen 4697db96d56Sopenharmony_ci # until we know what the command is. 4707db96d56Sopenharmony_ci 4717db96d56Sopenharmony_ci self.commands = [] 4727db96d56Sopenharmony_ci parser = FancyGetopt(toplevel_options + self.display_options) 4737db96d56Sopenharmony_ci parser.set_negative_aliases(self.negative_opt) 4747db96d56Sopenharmony_ci parser.set_aliases({'licence': 'license'}) 4757db96d56Sopenharmony_ci args = parser.getopt(args=self.script_args, object=self) 4767db96d56Sopenharmony_ci option_order = parser.get_option_order() 4777db96d56Sopenharmony_ci log.set_verbosity(self.verbose) 4787db96d56Sopenharmony_ci 4797db96d56Sopenharmony_ci # for display options we return immediately 4807db96d56Sopenharmony_ci if self.handle_display_options(option_order): 4817db96d56Sopenharmony_ci return 4827db96d56Sopenharmony_ci while args: 4837db96d56Sopenharmony_ci args = self._parse_command_opts(parser, args) 4847db96d56Sopenharmony_ci if args is None: # user asked for help (and got it) 4857db96d56Sopenharmony_ci return 4867db96d56Sopenharmony_ci 4877db96d56Sopenharmony_ci # Handle the cases of --help as a "global" option, ie. 4887db96d56Sopenharmony_ci # "setup.py --help" and "setup.py --help command ...". For the 4897db96d56Sopenharmony_ci # former, we show global options (--verbose, --dry-run, etc.) 4907db96d56Sopenharmony_ci # and display-only options (--name, --version, etc.); for the 4917db96d56Sopenharmony_ci # latter, we omit the display-only options and show help for 4927db96d56Sopenharmony_ci # each command listed on the command line. 4937db96d56Sopenharmony_ci if self.help: 4947db96d56Sopenharmony_ci self._show_help(parser, 4957db96d56Sopenharmony_ci display_options=len(self.commands) == 0, 4967db96d56Sopenharmony_ci commands=self.commands) 4977db96d56Sopenharmony_ci return 4987db96d56Sopenharmony_ci 4997db96d56Sopenharmony_ci # Oops, no commands found -- an end-user error 5007db96d56Sopenharmony_ci if not self.commands: 5017db96d56Sopenharmony_ci raise DistutilsArgError("no commands supplied") 5027db96d56Sopenharmony_ci 5037db96d56Sopenharmony_ci # All is well: return true 5047db96d56Sopenharmony_ci return True 5057db96d56Sopenharmony_ci 5067db96d56Sopenharmony_ci def _get_toplevel_options(self): 5077db96d56Sopenharmony_ci """Return the non-display options recognized at the top level. 5087db96d56Sopenharmony_ci 5097db96d56Sopenharmony_ci This includes options that are recognized *only* at the top 5107db96d56Sopenharmony_ci level as well as options recognized for commands. 5117db96d56Sopenharmony_ci """ 5127db96d56Sopenharmony_ci return self.global_options + [ 5137db96d56Sopenharmony_ci ("command-packages=", None, 5147db96d56Sopenharmony_ci "list of packages that provide distutils commands"), 5157db96d56Sopenharmony_ci ] 5167db96d56Sopenharmony_ci 5177db96d56Sopenharmony_ci def _parse_command_opts(self, parser, args): 5187db96d56Sopenharmony_ci """Parse the command-line options for a single command. 5197db96d56Sopenharmony_ci 'parser' must be a FancyGetopt instance; 'args' must be the list 5207db96d56Sopenharmony_ci of arguments, starting with the current command (whose options 5217db96d56Sopenharmony_ci we are about to parse). Returns a new version of 'args' with 5227db96d56Sopenharmony_ci the next command at the front of the list; will be the empty 5237db96d56Sopenharmony_ci list if there are no more commands on the command line. Returns 5247db96d56Sopenharmony_ci None if the user asked for help on this command. 5257db96d56Sopenharmony_ci """ 5267db96d56Sopenharmony_ci # late import because of mutual dependence between these modules 5277db96d56Sopenharmony_ci from distutils.cmd import Command 5287db96d56Sopenharmony_ci 5297db96d56Sopenharmony_ci # Pull the current command from the head of the command line 5307db96d56Sopenharmony_ci command = args[0] 5317db96d56Sopenharmony_ci if not command_re.match(command): 5327db96d56Sopenharmony_ci raise SystemExit("invalid command name '%s'" % command) 5337db96d56Sopenharmony_ci self.commands.append(command) 5347db96d56Sopenharmony_ci 5357db96d56Sopenharmony_ci # Dig up the command class that implements this command, so we 5367db96d56Sopenharmony_ci # 1) know that it's a valid command, and 2) know which options 5377db96d56Sopenharmony_ci # it takes. 5387db96d56Sopenharmony_ci try: 5397db96d56Sopenharmony_ci cmd_class = self.get_command_class(command) 5407db96d56Sopenharmony_ci except DistutilsModuleError as msg: 5417db96d56Sopenharmony_ci raise DistutilsArgError(msg) 5427db96d56Sopenharmony_ci 5437db96d56Sopenharmony_ci # Require that the command class be derived from Command -- want 5447db96d56Sopenharmony_ci # to be sure that the basic "command" interface is implemented. 5457db96d56Sopenharmony_ci if not issubclass(cmd_class, Command): 5467db96d56Sopenharmony_ci raise DistutilsClassError( 5477db96d56Sopenharmony_ci "command class %s must subclass Command" % cmd_class) 5487db96d56Sopenharmony_ci 5497db96d56Sopenharmony_ci # Also make sure that the command object provides a list of its 5507db96d56Sopenharmony_ci # known options. 5517db96d56Sopenharmony_ci if not (hasattr(cmd_class, 'user_options') and 5527db96d56Sopenharmony_ci isinstance(cmd_class.user_options, list)): 5537db96d56Sopenharmony_ci msg = ("command class %s must provide " 5547db96d56Sopenharmony_ci "'user_options' attribute (a list of tuples)") 5557db96d56Sopenharmony_ci raise DistutilsClassError(msg % cmd_class) 5567db96d56Sopenharmony_ci 5577db96d56Sopenharmony_ci # If the command class has a list of negative alias options, 5587db96d56Sopenharmony_ci # merge it in with the global negative aliases. 5597db96d56Sopenharmony_ci negative_opt = self.negative_opt 5607db96d56Sopenharmony_ci if hasattr(cmd_class, 'negative_opt'): 5617db96d56Sopenharmony_ci negative_opt = negative_opt.copy() 5627db96d56Sopenharmony_ci negative_opt.update(cmd_class.negative_opt) 5637db96d56Sopenharmony_ci 5647db96d56Sopenharmony_ci # Check for help_options in command class. They have a different 5657db96d56Sopenharmony_ci # format (tuple of four) so we need to preprocess them here. 5667db96d56Sopenharmony_ci if (hasattr(cmd_class, 'help_options') and 5677db96d56Sopenharmony_ci isinstance(cmd_class.help_options, list)): 5687db96d56Sopenharmony_ci help_options = fix_help_options(cmd_class.help_options) 5697db96d56Sopenharmony_ci else: 5707db96d56Sopenharmony_ci help_options = [] 5717db96d56Sopenharmony_ci 5727db96d56Sopenharmony_ci # All commands support the global options too, just by adding 5737db96d56Sopenharmony_ci # in 'global_options'. 5747db96d56Sopenharmony_ci parser.set_option_table(self.global_options + 5757db96d56Sopenharmony_ci cmd_class.user_options + 5767db96d56Sopenharmony_ci help_options) 5777db96d56Sopenharmony_ci parser.set_negative_aliases(negative_opt) 5787db96d56Sopenharmony_ci (args, opts) = parser.getopt(args[1:]) 5797db96d56Sopenharmony_ci if hasattr(opts, 'help') and opts.help: 5807db96d56Sopenharmony_ci self._show_help(parser, display_options=0, commands=[cmd_class]) 5817db96d56Sopenharmony_ci return 5827db96d56Sopenharmony_ci 5837db96d56Sopenharmony_ci if (hasattr(cmd_class, 'help_options') and 5847db96d56Sopenharmony_ci isinstance(cmd_class.help_options, list)): 5857db96d56Sopenharmony_ci help_option_found=0 5867db96d56Sopenharmony_ci for (help_option, short, desc, func) in cmd_class.help_options: 5877db96d56Sopenharmony_ci if hasattr(opts, parser.get_attr_name(help_option)): 5887db96d56Sopenharmony_ci help_option_found=1 5897db96d56Sopenharmony_ci if callable(func): 5907db96d56Sopenharmony_ci func() 5917db96d56Sopenharmony_ci else: 5927db96d56Sopenharmony_ci raise DistutilsClassError( 5937db96d56Sopenharmony_ci "invalid help function %r for help option '%s': " 5947db96d56Sopenharmony_ci "must be a callable object (function, etc.)" 5957db96d56Sopenharmony_ci % (func, help_option)) 5967db96d56Sopenharmony_ci 5977db96d56Sopenharmony_ci if help_option_found: 5987db96d56Sopenharmony_ci return 5997db96d56Sopenharmony_ci 6007db96d56Sopenharmony_ci # Put the options from the command-line into their official 6017db96d56Sopenharmony_ci # holding pen, the 'command_options' dictionary. 6027db96d56Sopenharmony_ci opt_dict = self.get_option_dict(command) 6037db96d56Sopenharmony_ci for (name, value) in vars(opts).items(): 6047db96d56Sopenharmony_ci opt_dict[name] = ("command line", value) 6057db96d56Sopenharmony_ci 6067db96d56Sopenharmony_ci return args 6077db96d56Sopenharmony_ci 6087db96d56Sopenharmony_ci def finalize_options(self): 6097db96d56Sopenharmony_ci """Set final values for all the options on the Distribution 6107db96d56Sopenharmony_ci instance, analogous to the .finalize_options() method of Command 6117db96d56Sopenharmony_ci objects. 6127db96d56Sopenharmony_ci """ 6137db96d56Sopenharmony_ci for attr in ('keywords', 'platforms'): 6147db96d56Sopenharmony_ci value = getattr(self.metadata, attr) 6157db96d56Sopenharmony_ci if value is None: 6167db96d56Sopenharmony_ci continue 6177db96d56Sopenharmony_ci if isinstance(value, str): 6187db96d56Sopenharmony_ci value = [elm.strip() for elm in value.split(',')] 6197db96d56Sopenharmony_ci setattr(self.metadata, attr, value) 6207db96d56Sopenharmony_ci 6217db96d56Sopenharmony_ci def _show_help(self, parser, global_options=1, display_options=1, 6227db96d56Sopenharmony_ci commands=[]): 6237db96d56Sopenharmony_ci """Show help for the setup script command-line in the form of 6247db96d56Sopenharmony_ci several lists of command-line options. 'parser' should be a 6257db96d56Sopenharmony_ci FancyGetopt instance; do not expect it to be returned in the 6267db96d56Sopenharmony_ci same state, as its option table will be reset to make it 6277db96d56Sopenharmony_ci generate the correct help text. 6287db96d56Sopenharmony_ci 6297db96d56Sopenharmony_ci If 'global_options' is true, lists the global options: 6307db96d56Sopenharmony_ci --verbose, --dry-run, etc. If 'display_options' is true, lists 6317db96d56Sopenharmony_ci the "display-only" options: --name, --version, etc. Finally, 6327db96d56Sopenharmony_ci lists per-command help for every command name or command class 6337db96d56Sopenharmony_ci in 'commands'. 6347db96d56Sopenharmony_ci """ 6357db96d56Sopenharmony_ci # late import because of mutual dependence between these modules 6367db96d56Sopenharmony_ci from distutils.core import gen_usage 6377db96d56Sopenharmony_ci from distutils.cmd import Command 6387db96d56Sopenharmony_ci 6397db96d56Sopenharmony_ci if global_options: 6407db96d56Sopenharmony_ci if display_options: 6417db96d56Sopenharmony_ci options = self._get_toplevel_options() 6427db96d56Sopenharmony_ci else: 6437db96d56Sopenharmony_ci options = self.global_options 6447db96d56Sopenharmony_ci parser.set_option_table(options) 6457db96d56Sopenharmony_ci parser.print_help(self.common_usage + "\nGlobal options:") 6467db96d56Sopenharmony_ci print('') 6477db96d56Sopenharmony_ci 6487db96d56Sopenharmony_ci if display_options: 6497db96d56Sopenharmony_ci parser.set_option_table(self.display_options) 6507db96d56Sopenharmony_ci parser.print_help( 6517db96d56Sopenharmony_ci "Information display options (just display " + 6527db96d56Sopenharmony_ci "information, ignore any commands)") 6537db96d56Sopenharmony_ci print('') 6547db96d56Sopenharmony_ci 6557db96d56Sopenharmony_ci for command in self.commands: 6567db96d56Sopenharmony_ci if isinstance(command, type) and issubclass(command, Command): 6577db96d56Sopenharmony_ci klass = command 6587db96d56Sopenharmony_ci else: 6597db96d56Sopenharmony_ci klass = self.get_command_class(command) 6607db96d56Sopenharmony_ci if (hasattr(klass, 'help_options') and 6617db96d56Sopenharmony_ci isinstance(klass.help_options, list)): 6627db96d56Sopenharmony_ci parser.set_option_table(klass.user_options + 6637db96d56Sopenharmony_ci fix_help_options(klass.help_options)) 6647db96d56Sopenharmony_ci else: 6657db96d56Sopenharmony_ci parser.set_option_table(klass.user_options) 6667db96d56Sopenharmony_ci parser.print_help("Options for '%s' command:" % klass.__name__) 6677db96d56Sopenharmony_ci print('') 6687db96d56Sopenharmony_ci 6697db96d56Sopenharmony_ci print(gen_usage(self.script_name)) 6707db96d56Sopenharmony_ci 6717db96d56Sopenharmony_ci def handle_display_options(self, option_order): 6727db96d56Sopenharmony_ci """If there were any non-global "display-only" options 6737db96d56Sopenharmony_ci (--help-commands or the metadata display options) on the command 6747db96d56Sopenharmony_ci line, display the requested info and return true; else return 6757db96d56Sopenharmony_ci false. 6767db96d56Sopenharmony_ci """ 6777db96d56Sopenharmony_ci from distutils.core import gen_usage 6787db96d56Sopenharmony_ci 6797db96d56Sopenharmony_ci # User just wants a list of commands -- we'll print it out and stop 6807db96d56Sopenharmony_ci # processing now (ie. if they ran "setup --help-commands foo bar", 6817db96d56Sopenharmony_ci # we ignore "foo bar"). 6827db96d56Sopenharmony_ci if self.help_commands: 6837db96d56Sopenharmony_ci self.print_commands() 6847db96d56Sopenharmony_ci print('') 6857db96d56Sopenharmony_ci print(gen_usage(self.script_name)) 6867db96d56Sopenharmony_ci return 1 6877db96d56Sopenharmony_ci 6887db96d56Sopenharmony_ci # If user supplied any of the "display metadata" options, then 6897db96d56Sopenharmony_ci # display that metadata in the order in which the user supplied the 6907db96d56Sopenharmony_ci # metadata options. 6917db96d56Sopenharmony_ci any_display_options = 0 6927db96d56Sopenharmony_ci is_display_option = {} 6937db96d56Sopenharmony_ci for option in self.display_options: 6947db96d56Sopenharmony_ci is_display_option[option[0]] = 1 6957db96d56Sopenharmony_ci 6967db96d56Sopenharmony_ci for (opt, val) in option_order: 6977db96d56Sopenharmony_ci if val and is_display_option.get(opt): 6987db96d56Sopenharmony_ci opt = translate_longopt(opt) 6997db96d56Sopenharmony_ci value = getattr(self.metadata, "get_"+opt)() 7007db96d56Sopenharmony_ci if opt in ['keywords', 'platforms']: 7017db96d56Sopenharmony_ci print(','.join(value)) 7027db96d56Sopenharmony_ci elif opt in ('classifiers', 'provides', 'requires', 7037db96d56Sopenharmony_ci 'obsoletes'): 7047db96d56Sopenharmony_ci print('\n'.join(value)) 7057db96d56Sopenharmony_ci else: 7067db96d56Sopenharmony_ci print(value) 7077db96d56Sopenharmony_ci any_display_options = 1 7087db96d56Sopenharmony_ci 7097db96d56Sopenharmony_ci return any_display_options 7107db96d56Sopenharmony_ci 7117db96d56Sopenharmony_ci def print_command_list(self, commands, header, max_length): 7127db96d56Sopenharmony_ci """Print a subset of the list of all commands -- used by 7137db96d56Sopenharmony_ci 'print_commands()'. 7147db96d56Sopenharmony_ci """ 7157db96d56Sopenharmony_ci print(header + ":") 7167db96d56Sopenharmony_ci 7177db96d56Sopenharmony_ci for cmd in commands: 7187db96d56Sopenharmony_ci klass = self.cmdclass.get(cmd) 7197db96d56Sopenharmony_ci if not klass: 7207db96d56Sopenharmony_ci klass = self.get_command_class(cmd) 7217db96d56Sopenharmony_ci try: 7227db96d56Sopenharmony_ci description = klass.description 7237db96d56Sopenharmony_ci except AttributeError: 7247db96d56Sopenharmony_ci description = "(no description available)" 7257db96d56Sopenharmony_ci 7267db96d56Sopenharmony_ci print(" %-*s %s" % (max_length, cmd, description)) 7277db96d56Sopenharmony_ci 7287db96d56Sopenharmony_ci def print_commands(self): 7297db96d56Sopenharmony_ci """Print out a help message listing all available commands with a 7307db96d56Sopenharmony_ci description of each. The list is divided into "standard commands" 7317db96d56Sopenharmony_ci (listed in distutils.command.__all__) and "extra commands" 7327db96d56Sopenharmony_ci (mentioned in self.cmdclass, but not a standard command). The 7337db96d56Sopenharmony_ci descriptions come from the command class attribute 7347db96d56Sopenharmony_ci 'description'. 7357db96d56Sopenharmony_ci """ 7367db96d56Sopenharmony_ci import distutils.command 7377db96d56Sopenharmony_ci std_commands = distutils.command.__all__ 7387db96d56Sopenharmony_ci is_std = {} 7397db96d56Sopenharmony_ci for cmd in std_commands: 7407db96d56Sopenharmony_ci is_std[cmd] = 1 7417db96d56Sopenharmony_ci 7427db96d56Sopenharmony_ci extra_commands = [] 7437db96d56Sopenharmony_ci for cmd in self.cmdclass.keys(): 7447db96d56Sopenharmony_ci if not is_std.get(cmd): 7457db96d56Sopenharmony_ci extra_commands.append(cmd) 7467db96d56Sopenharmony_ci 7477db96d56Sopenharmony_ci max_length = 0 7487db96d56Sopenharmony_ci for cmd in (std_commands + extra_commands): 7497db96d56Sopenharmony_ci if len(cmd) > max_length: 7507db96d56Sopenharmony_ci max_length = len(cmd) 7517db96d56Sopenharmony_ci 7527db96d56Sopenharmony_ci self.print_command_list(std_commands, 7537db96d56Sopenharmony_ci "Standard commands", 7547db96d56Sopenharmony_ci max_length) 7557db96d56Sopenharmony_ci if extra_commands: 7567db96d56Sopenharmony_ci print() 7577db96d56Sopenharmony_ci self.print_command_list(extra_commands, 7587db96d56Sopenharmony_ci "Extra commands", 7597db96d56Sopenharmony_ci max_length) 7607db96d56Sopenharmony_ci 7617db96d56Sopenharmony_ci def get_command_list(self): 7627db96d56Sopenharmony_ci """Get a list of (command, description) tuples. 7637db96d56Sopenharmony_ci The list is divided into "standard commands" (listed in 7647db96d56Sopenharmony_ci distutils.command.__all__) and "extra commands" (mentioned in 7657db96d56Sopenharmony_ci self.cmdclass, but not a standard command). The descriptions come 7667db96d56Sopenharmony_ci from the command class attribute 'description'. 7677db96d56Sopenharmony_ci """ 7687db96d56Sopenharmony_ci # Currently this is only used on Mac OS, for the Mac-only GUI 7697db96d56Sopenharmony_ci # Distutils interface (by Jack Jansen) 7707db96d56Sopenharmony_ci import distutils.command 7717db96d56Sopenharmony_ci std_commands = distutils.command.__all__ 7727db96d56Sopenharmony_ci is_std = {} 7737db96d56Sopenharmony_ci for cmd in std_commands: 7747db96d56Sopenharmony_ci is_std[cmd] = 1 7757db96d56Sopenharmony_ci 7767db96d56Sopenharmony_ci extra_commands = [] 7777db96d56Sopenharmony_ci for cmd in self.cmdclass.keys(): 7787db96d56Sopenharmony_ci if not is_std.get(cmd): 7797db96d56Sopenharmony_ci extra_commands.append(cmd) 7807db96d56Sopenharmony_ci 7817db96d56Sopenharmony_ci rv = [] 7827db96d56Sopenharmony_ci for cmd in (std_commands + extra_commands): 7837db96d56Sopenharmony_ci klass = self.cmdclass.get(cmd) 7847db96d56Sopenharmony_ci if not klass: 7857db96d56Sopenharmony_ci klass = self.get_command_class(cmd) 7867db96d56Sopenharmony_ci try: 7877db96d56Sopenharmony_ci description = klass.description 7887db96d56Sopenharmony_ci except AttributeError: 7897db96d56Sopenharmony_ci description = "(no description available)" 7907db96d56Sopenharmony_ci rv.append((cmd, description)) 7917db96d56Sopenharmony_ci return rv 7927db96d56Sopenharmony_ci 7937db96d56Sopenharmony_ci # -- Command class/object methods ---------------------------------- 7947db96d56Sopenharmony_ci 7957db96d56Sopenharmony_ci def get_command_packages(self): 7967db96d56Sopenharmony_ci """Return a list of packages from which commands are loaded.""" 7977db96d56Sopenharmony_ci pkgs = self.command_packages 7987db96d56Sopenharmony_ci if not isinstance(pkgs, list): 7997db96d56Sopenharmony_ci if pkgs is None: 8007db96d56Sopenharmony_ci pkgs = '' 8017db96d56Sopenharmony_ci pkgs = [pkg.strip() for pkg in pkgs.split(',') if pkg != ''] 8027db96d56Sopenharmony_ci if "distutils.command" not in pkgs: 8037db96d56Sopenharmony_ci pkgs.insert(0, "distutils.command") 8047db96d56Sopenharmony_ci self.command_packages = pkgs 8057db96d56Sopenharmony_ci return pkgs 8067db96d56Sopenharmony_ci 8077db96d56Sopenharmony_ci def get_command_class(self, command): 8087db96d56Sopenharmony_ci """Return the class that implements the Distutils command named by 8097db96d56Sopenharmony_ci 'command'. First we check the 'cmdclass' dictionary; if the 8107db96d56Sopenharmony_ci command is mentioned there, we fetch the class object from the 8117db96d56Sopenharmony_ci dictionary and return it. Otherwise we load the command module 8127db96d56Sopenharmony_ci ("distutils.command." + command) and fetch the command class from 8137db96d56Sopenharmony_ci the module. The loaded class is also stored in 'cmdclass' 8147db96d56Sopenharmony_ci to speed future calls to 'get_command_class()'. 8157db96d56Sopenharmony_ci 8167db96d56Sopenharmony_ci Raises DistutilsModuleError if the expected module could not be 8177db96d56Sopenharmony_ci found, or if that module does not define the expected class. 8187db96d56Sopenharmony_ci """ 8197db96d56Sopenharmony_ci klass = self.cmdclass.get(command) 8207db96d56Sopenharmony_ci if klass: 8217db96d56Sopenharmony_ci return klass 8227db96d56Sopenharmony_ci 8237db96d56Sopenharmony_ci for pkgname in self.get_command_packages(): 8247db96d56Sopenharmony_ci module_name = "%s.%s" % (pkgname, command) 8257db96d56Sopenharmony_ci klass_name = command 8267db96d56Sopenharmony_ci 8277db96d56Sopenharmony_ci try: 8287db96d56Sopenharmony_ci __import__(module_name) 8297db96d56Sopenharmony_ci module = sys.modules[module_name] 8307db96d56Sopenharmony_ci except ImportError: 8317db96d56Sopenharmony_ci continue 8327db96d56Sopenharmony_ci 8337db96d56Sopenharmony_ci try: 8347db96d56Sopenharmony_ci klass = getattr(module, klass_name) 8357db96d56Sopenharmony_ci except AttributeError: 8367db96d56Sopenharmony_ci raise DistutilsModuleError( 8377db96d56Sopenharmony_ci "invalid command '%s' (no class '%s' in module '%s')" 8387db96d56Sopenharmony_ci % (command, klass_name, module_name)) 8397db96d56Sopenharmony_ci 8407db96d56Sopenharmony_ci self.cmdclass[command] = klass 8417db96d56Sopenharmony_ci return klass 8427db96d56Sopenharmony_ci 8437db96d56Sopenharmony_ci raise DistutilsModuleError("invalid command '%s'" % command) 8447db96d56Sopenharmony_ci 8457db96d56Sopenharmony_ci def get_command_obj(self, command, create=1): 8467db96d56Sopenharmony_ci """Return the command object for 'command'. Normally this object 8477db96d56Sopenharmony_ci is cached on a previous call to 'get_command_obj()'; if no command 8487db96d56Sopenharmony_ci object for 'command' is in the cache, then we either create and 8497db96d56Sopenharmony_ci return it (if 'create' is true) or return None. 8507db96d56Sopenharmony_ci """ 8517db96d56Sopenharmony_ci cmd_obj = self.command_obj.get(command) 8527db96d56Sopenharmony_ci if not cmd_obj and create: 8537db96d56Sopenharmony_ci if DEBUG: 8547db96d56Sopenharmony_ci self.announce("Distribution.get_command_obj(): " 8557db96d56Sopenharmony_ci "creating '%s' command object" % command) 8567db96d56Sopenharmony_ci 8577db96d56Sopenharmony_ci klass = self.get_command_class(command) 8587db96d56Sopenharmony_ci cmd_obj = self.command_obj[command] = klass(self) 8597db96d56Sopenharmony_ci self.have_run[command] = 0 8607db96d56Sopenharmony_ci 8617db96d56Sopenharmony_ci # Set any options that were supplied in config files 8627db96d56Sopenharmony_ci # or on the command line. (NB. support for error 8637db96d56Sopenharmony_ci # reporting is lame here: any errors aren't reported 8647db96d56Sopenharmony_ci # until 'finalize_options()' is called, which means 8657db96d56Sopenharmony_ci # we won't report the source of the error.) 8667db96d56Sopenharmony_ci options = self.command_options.get(command) 8677db96d56Sopenharmony_ci if options: 8687db96d56Sopenharmony_ci self._set_command_options(cmd_obj, options) 8697db96d56Sopenharmony_ci 8707db96d56Sopenharmony_ci return cmd_obj 8717db96d56Sopenharmony_ci 8727db96d56Sopenharmony_ci def _set_command_options(self, command_obj, option_dict=None): 8737db96d56Sopenharmony_ci """Set the options for 'command_obj' from 'option_dict'. Basically 8747db96d56Sopenharmony_ci this means copying elements of a dictionary ('option_dict') to 8757db96d56Sopenharmony_ci attributes of an instance ('command'). 8767db96d56Sopenharmony_ci 8777db96d56Sopenharmony_ci 'command_obj' must be a Command instance. If 'option_dict' is not 8787db96d56Sopenharmony_ci supplied, uses the standard option dictionary for this command 8797db96d56Sopenharmony_ci (from 'self.command_options'). 8807db96d56Sopenharmony_ci """ 8817db96d56Sopenharmony_ci command_name = command_obj.get_command_name() 8827db96d56Sopenharmony_ci if option_dict is None: 8837db96d56Sopenharmony_ci option_dict = self.get_option_dict(command_name) 8847db96d56Sopenharmony_ci 8857db96d56Sopenharmony_ci if DEBUG: 8867db96d56Sopenharmony_ci self.announce(" setting options for '%s' command:" % command_name) 8877db96d56Sopenharmony_ci for (option, (source, value)) in option_dict.items(): 8887db96d56Sopenharmony_ci if DEBUG: 8897db96d56Sopenharmony_ci self.announce(" %s = %s (from %s)" % (option, value, 8907db96d56Sopenharmony_ci source)) 8917db96d56Sopenharmony_ci try: 8927db96d56Sopenharmony_ci bool_opts = [translate_longopt(o) 8937db96d56Sopenharmony_ci for o in command_obj.boolean_options] 8947db96d56Sopenharmony_ci except AttributeError: 8957db96d56Sopenharmony_ci bool_opts = [] 8967db96d56Sopenharmony_ci try: 8977db96d56Sopenharmony_ci neg_opt = command_obj.negative_opt 8987db96d56Sopenharmony_ci except AttributeError: 8997db96d56Sopenharmony_ci neg_opt = {} 9007db96d56Sopenharmony_ci 9017db96d56Sopenharmony_ci try: 9027db96d56Sopenharmony_ci is_string = isinstance(value, str) 9037db96d56Sopenharmony_ci if option in neg_opt and is_string: 9047db96d56Sopenharmony_ci setattr(command_obj, neg_opt[option], not strtobool(value)) 9057db96d56Sopenharmony_ci elif option in bool_opts and is_string: 9067db96d56Sopenharmony_ci setattr(command_obj, option, strtobool(value)) 9077db96d56Sopenharmony_ci elif hasattr(command_obj, option): 9087db96d56Sopenharmony_ci setattr(command_obj, option, value) 9097db96d56Sopenharmony_ci else: 9107db96d56Sopenharmony_ci raise DistutilsOptionError( 9117db96d56Sopenharmony_ci "error in %s: command '%s' has no such option '%s'" 9127db96d56Sopenharmony_ci % (source, command_name, option)) 9137db96d56Sopenharmony_ci except ValueError as msg: 9147db96d56Sopenharmony_ci raise DistutilsOptionError(msg) 9157db96d56Sopenharmony_ci 9167db96d56Sopenharmony_ci def reinitialize_command(self, command, reinit_subcommands=0): 9177db96d56Sopenharmony_ci """Reinitializes a command to the state it was in when first 9187db96d56Sopenharmony_ci returned by 'get_command_obj()': ie., initialized but not yet 9197db96d56Sopenharmony_ci finalized. This provides the opportunity to sneak option 9207db96d56Sopenharmony_ci values in programmatically, overriding or supplementing 9217db96d56Sopenharmony_ci user-supplied values from the config files and command line. 9227db96d56Sopenharmony_ci You'll have to re-finalize the command object (by calling 9237db96d56Sopenharmony_ci 'finalize_options()' or 'ensure_finalized()') before using it for 9247db96d56Sopenharmony_ci real. 9257db96d56Sopenharmony_ci 9267db96d56Sopenharmony_ci 'command' should be a command name (string) or command object. If 9277db96d56Sopenharmony_ci 'reinit_subcommands' is true, also reinitializes the command's 9287db96d56Sopenharmony_ci sub-commands, as declared by the 'sub_commands' class attribute (if 9297db96d56Sopenharmony_ci it has one). See the "install" command for an example. Only 9307db96d56Sopenharmony_ci reinitializes the sub-commands that actually matter, ie. those 9317db96d56Sopenharmony_ci whose test predicates return true. 9327db96d56Sopenharmony_ci 9337db96d56Sopenharmony_ci Returns the reinitialized command object. 9347db96d56Sopenharmony_ci """ 9357db96d56Sopenharmony_ci from distutils.cmd import Command 9367db96d56Sopenharmony_ci if not isinstance(command, Command): 9377db96d56Sopenharmony_ci command_name = command 9387db96d56Sopenharmony_ci command = self.get_command_obj(command_name) 9397db96d56Sopenharmony_ci else: 9407db96d56Sopenharmony_ci command_name = command.get_command_name() 9417db96d56Sopenharmony_ci 9427db96d56Sopenharmony_ci if not command.finalized: 9437db96d56Sopenharmony_ci return command 9447db96d56Sopenharmony_ci command.initialize_options() 9457db96d56Sopenharmony_ci command.finalized = 0 9467db96d56Sopenharmony_ci self.have_run[command_name] = 0 9477db96d56Sopenharmony_ci self._set_command_options(command) 9487db96d56Sopenharmony_ci 9497db96d56Sopenharmony_ci if reinit_subcommands: 9507db96d56Sopenharmony_ci for sub in command.get_sub_commands(): 9517db96d56Sopenharmony_ci self.reinitialize_command(sub, reinit_subcommands) 9527db96d56Sopenharmony_ci 9537db96d56Sopenharmony_ci return command 9547db96d56Sopenharmony_ci 9557db96d56Sopenharmony_ci # -- Methods that operate on the Distribution ---------------------- 9567db96d56Sopenharmony_ci 9577db96d56Sopenharmony_ci def announce(self, msg, level=log.INFO): 9587db96d56Sopenharmony_ci log.log(level, msg) 9597db96d56Sopenharmony_ci 9607db96d56Sopenharmony_ci def run_commands(self): 9617db96d56Sopenharmony_ci """Run each command that was seen on the setup script command line. 9627db96d56Sopenharmony_ci Uses the list of commands found and cache of command objects 9637db96d56Sopenharmony_ci created by 'get_command_obj()'. 9647db96d56Sopenharmony_ci """ 9657db96d56Sopenharmony_ci for cmd in self.commands: 9667db96d56Sopenharmony_ci self.run_command(cmd) 9677db96d56Sopenharmony_ci 9687db96d56Sopenharmony_ci # -- Methods that operate on its Commands -------------------------- 9697db96d56Sopenharmony_ci 9707db96d56Sopenharmony_ci def run_command(self, command): 9717db96d56Sopenharmony_ci """Do whatever it takes to run a command (including nothing at all, 9727db96d56Sopenharmony_ci if the command has already been run). Specifically: if we have 9737db96d56Sopenharmony_ci already created and run the command named by 'command', return 9747db96d56Sopenharmony_ci silently without doing anything. If the command named by 'command' 9757db96d56Sopenharmony_ci doesn't even have a command object yet, create one. Then invoke 9767db96d56Sopenharmony_ci 'run()' on that command object (or an existing one). 9777db96d56Sopenharmony_ci """ 9787db96d56Sopenharmony_ci # Already been here, done that? then return silently. 9797db96d56Sopenharmony_ci if self.have_run.get(command): 9807db96d56Sopenharmony_ci return 9817db96d56Sopenharmony_ci 9827db96d56Sopenharmony_ci log.info("running %s", command) 9837db96d56Sopenharmony_ci cmd_obj = self.get_command_obj(command) 9847db96d56Sopenharmony_ci cmd_obj.ensure_finalized() 9857db96d56Sopenharmony_ci cmd_obj.run() 9867db96d56Sopenharmony_ci self.have_run[command] = 1 9877db96d56Sopenharmony_ci 9887db96d56Sopenharmony_ci # -- Distribution query methods ------------------------------------ 9897db96d56Sopenharmony_ci 9907db96d56Sopenharmony_ci def has_pure_modules(self): 9917db96d56Sopenharmony_ci return len(self.packages or self.py_modules or []) > 0 9927db96d56Sopenharmony_ci 9937db96d56Sopenharmony_ci def has_ext_modules(self): 9947db96d56Sopenharmony_ci return self.ext_modules and len(self.ext_modules) > 0 9957db96d56Sopenharmony_ci 9967db96d56Sopenharmony_ci def has_c_libraries(self): 9977db96d56Sopenharmony_ci return self.libraries and len(self.libraries) > 0 9987db96d56Sopenharmony_ci 9997db96d56Sopenharmony_ci def has_modules(self): 10007db96d56Sopenharmony_ci return self.has_pure_modules() or self.has_ext_modules() 10017db96d56Sopenharmony_ci 10027db96d56Sopenharmony_ci def has_headers(self): 10037db96d56Sopenharmony_ci return self.headers and len(self.headers) > 0 10047db96d56Sopenharmony_ci 10057db96d56Sopenharmony_ci def has_scripts(self): 10067db96d56Sopenharmony_ci return self.scripts and len(self.scripts) > 0 10077db96d56Sopenharmony_ci 10087db96d56Sopenharmony_ci def has_data_files(self): 10097db96d56Sopenharmony_ci return self.data_files and len(self.data_files) > 0 10107db96d56Sopenharmony_ci 10117db96d56Sopenharmony_ci def is_pure(self): 10127db96d56Sopenharmony_ci return (self.has_pure_modules() and 10137db96d56Sopenharmony_ci not self.has_ext_modules() and 10147db96d56Sopenharmony_ci not self.has_c_libraries()) 10157db96d56Sopenharmony_ci 10167db96d56Sopenharmony_ci # -- Metadata query methods ---------------------------------------- 10177db96d56Sopenharmony_ci 10187db96d56Sopenharmony_ci # If you're looking for 'get_name()', 'get_version()', and so forth, 10197db96d56Sopenharmony_ci # they are defined in a sneaky way: the constructor binds self.get_XXX 10207db96d56Sopenharmony_ci # to self.metadata.get_XXX. The actual code is in the 10217db96d56Sopenharmony_ci # DistributionMetadata class, below. 10227db96d56Sopenharmony_ci 10237db96d56Sopenharmony_ciclass DistributionMetadata: 10247db96d56Sopenharmony_ci """Dummy class to hold the distribution meta-data: name, version, 10257db96d56Sopenharmony_ci author, and so forth. 10267db96d56Sopenharmony_ci """ 10277db96d56Sopenharmony_ci 10287db96d56Sopenharmony_ci _METHOD_BASENAMES = ("name", "version", "author", "author_email", 10297db96d56Sopenharmony_ci "maintainer", "maintainer_email", "url", 10307db96d56Sopenharmony_ci "license", "description", "long_description", 10317db96d56Sopenharmony_ci "keywords", "platforms", "fullname", "contact", 10327db96d56Sopenharmony_ci "contact_email", "classifiers", "download_url", 10337db96d56Sopenharmony_ci # PEP 314 10347db96d56Sopenharmony_ci "provides", "requires", "obsoletes", 10357db96d56Sopenharmony_ci ) 10367db96d56Sopenharmony_ci 10377db96d56Sopenharmony_ci def __init__(self, path=None): 10387db96d56Sopenharmony_ci if path is not None: 10397db96d56Sopenharmony_ci self.read_pkg_file(open(path)) 10407db96d56Sopenharmony_ci else: 10417db96d56Sopenharmony_ci self.name = None 10427db96d56Sopenharmony_ci self.version = None 10437db96d56Sopenharmony_ci self.author = None 10447db96d56Sopenharmony_ci self.author_email = None 10457db96d56Sopenharmony_ci self.maintainer = None 10467db96d56Sopenharmony_ci self.maintainer_email = None 10477db96d56Sopenharmony_ci self.url = None 10487db96d56Sopenharmony_ci self.license = None 10497db96d56Sopenharmony_ci self.description = None 10507db96d56Sopenharmony_ci self.long_description = None 10517db96d56Sopenharmony_ci self.keywords = None 10527db96d56Sopenharmony_ci self.platforms = None 10537db96d56Sopenharmony_ci self.classifiers = None 10547db96d56Sopenharmony_ci self.download_url = None 10557db96d56Sopenharmony_ci # PEP 314 10567db96d56Sopenharmony_ci self.provides = None 10577db96d56Sopenharmony_ci self.requires = None 10587db96d56Sopenharmony_ci self.obsoletes = None 10597db96d56Sopenharmony_ci 10607db96d56Sopenharmony_ci def read_pkg_file(self, file): 10617db96d56Sopenharmony_ci """Reads the metadata values from a file object.""" 10627db96d56Sopenharmony_ci msg = message_from_file(file) 10637db96d56Sopenharmony_ci 10647db96d56Sopenharmony_ci def _read_field(name): 10657db96d56Sopenharmony_ci value = msg[name] 10667db96d56Sopenharmony_ci if value == 'UNKNOWN': 10677db96d56Sopenharmony_ci return None 10687db96d56Sopenharmony_ci return value 10697db96d56Sopenharmony_ci 10707db96d56Sopenharmony_ci def _read_list(name): 10717db96d56Sopenharmony_ci values = msg.get_all(name, None) 10727db96d56Sopenharmony_ci if values == []: 10737db96d56Sopenharmony_ci return None 10747db96d56Sopenharmony_ci return values 10757db96d56Sopenharmony_ci 10767db96d56Sopenharmony_ci metadata_version = msg['metadata-version'] 10777db96d56Sopenharmony_ci self.name = _read_field('name') 10787db96d56Sopenharmony_ci self.version = _read_field('version') 10797db96d56Sopenharmony_ci self.description = _read_field('summary') 10807db96d56Sopenharmony_ci # we are filling author only. 10817db96d56Sopenharmony_ci self.author = _read_field('author') 10827db96d56Sopenharmony_ci self.maintainer = None 10837db96d56Sopenharmony_ci self.author_email = _read_field('author-email') 10847db96d56Sopenharmony_ci self.maintainer_email = None 10857db96d56Sopenharmony_ci self.url = _read_field('home-page') 10867db96d56Sopenharmony_ci self.license = _read_field('license') 10877db96d56Sopenharmony_ci 10887db96d56Sopenharmony_ci if 'download-url' in msg: 10897db96d56Sopenharmony_ci self.download_url = _read_field('download-url') 10907db96d56Sopenharmony_ci else: 10917db96d56Sopenharmony_ci self.download_url = None 10927db96d56Sopenharmony_ci 10937db96d56Sopenharmony_ci self.long_description = _read_field('description') 10947db96d56Sopenharmony_ci self.description = _read_field('summary') 10957db96d56Sopenharmony_ci 10967db96d56Sopenharmony_ci if 'keywords' in msg: 10977db96d56Sopenharmony_ci self.keywords = _read_field('keywords').split(',') 10987db96d56Sopenharmony_ci 10997db96d56Sopenharmony_ci self.platforms = _read_list('platform') 11007db96d56Sopenharmony_ci self.classifiers = _read_list('classifier') 11017db96d56Sopenharmony_ci 11027db96d56Sopenharmony_ci # PEP 314 - these fields only exist in 1.1 11037db96d56Sopenharmony_ci if metadata_version == '1.1': 11047db96d56Sopenharmony_ci self.requires = _read_list('requires') 11057db96d56Sopenharmony_ci self.provides = _read_list('provides') 11067db96d56Sopenharmony_ci self.obsoletes = _read_list('obsoletes') 11077db96d56Sopenharmony_ci else: 11087db96d56Sopenharmony_ci self.requires = None 11097db96d56Sopenharmony_ci self.provides = None 11107db96d56Sopenharmony_ci self.obsoletes = None 11117db96d56Sopenharmony_ci 11127db96d56Sopenharmony_ci def write_pkg_info(self, base_dir): 11137db96d56Sopenharmony_ci """Write the PKG-INFO file into the release tree. 11147db96d56Sopenharmony_ci """ 11157db96d56Sopenharmony_ci with open(os.path.join(base_dir, 'PKG-INFO'), 'w', 11167db96d56Sopenharmony_ci encoding='UTF-8') as pkg_info: 11177db96d56Sopenharmony_ci self.write_pkg_file(pkg_info) 11187db96d56Sopenharmony_ci 11197db96d56Sopenharmony_ci def write_pkg_file(self, file): 11207db96d56Sopenharmony_ci """Write the PKG-INFO format data to a file object. 11217db96d56Sopenharmony_ci """ 11227db96d56Sopenharmony_ci version = '1.0' 11237db96d56Sopenharmony_ci if (self.provides or self.requires or self.obsoletes or 11247db96d56Sopenharmony_ci self.classifiers or self.download_url): 11257db96d56Sopenharmony_ci version = '1.1' 11267db96d56Sopenharmony_ci 11277db96d56Sopenharmony_ci file.write('Metadata-Version: %s\n' % version) 11287db96d56Sopenharmony_ci file.write('Name: %s\n' % self.get_name()) 11297db96d56Sopenharmony_ci file.write('Version: %s\n' % self.get_version()) 11307db96d56Sopenharmony_ci file.write('Summary: %s\n' % self.get_description()) 11317db96d56Sopenharmony_ci file.write('Home-page: %s\n' % self.get_url()) 11327db96d56Sopenharmony_ci file.write('Author: %s\n' % self.get_contact()) 11337db96d56Sopenharmony_ci file.write('Author-email: %s\n' % self.get_contact_email()) 11347db96d56Sopenharmony_ci file.write('License: %s\n' % self.get_license()) 11357db96d56Sopenharmony_ci if self.download_url: 11367db96d56Sopenharmony_ci file.write('Download-URL: %s\n' % self.download_url) 11377db96d56Sopenharmony_ci 11387db96d56Sopenharmony_ci long_desc = rfc822_escape(self.get_long_description()) 11397db96d56Sopenharmony_ci file.write('Description: %s\n' % long_desc) 11407db96d56Sopenharmony_ci 11417db96d56Sopenharmony_ci keywords = ','.join(self.get_keywords()) 11427db96d56Sopenharmony_ci if keywords: 11437db96d56Sopenharmony_ci file.write('Keywords: %s\n' % keywords) 11447db96d56Sopenharmony_ci 11457db96d56Sopenharmony_ci self._write_list(file, 'Platform', self.get_platforms()) 11467db96d56Sopenharmony_ci self._write_list(file, 'Classifier', self.get_classifiers()) 11477db96d56Sopenharmony_ci 11487db96d56Sopenharmony_ci # PEP 314 11497db96d56Sopenharmony_ci self._write_list(file, 'Requires', self.get_requires()) 11507db96d56Sopenharmony_ci self._write_list(file, 'Provides', self.get_provides()) 11517db96d56Sopenharmony_ci self._write_list(file, 'Obsoletes', self.get_obsoletes()) 11527db96d56Sopenharmony_ci 11537db96d56Sopenharmony_ci def _write_list(self, file, name, values): 11547db96d56Sopenharmony_ci for value in values: 11557db96d56Sopenharmony_ci file.write('%s: %s\n' % (name, value)) 11567db96d56Sopenharmony_ci 11577db96d56Sopenharmony_ci # -- Metadata query methods ---------------------------------------- 11587db96d56Sopenharmony_ci 11597db96d56Sopenharmony_ci def get_name(self): 11607db96d56Sopenharmony_ci return self.name or "UNKNOWN" 11617db96d56Sopenharmony_ci 11627db96d56Sopenharmony_ci def get_version(self): 11637db96d56Sopenharmony_ci return self.version or "0.0.0" 11647db96d56Sopenharmony_ci 11657db96d56Sopenharmony_ci def get_fullname(self): 11667db96d56Sopenharmony_ci return "%s-%s" % (self.get_name(), self.get_version()) 11677db96d56Sopenharmony_ci 11687db96d56Sopenharmony_ci def get_author(self): 11697db96d56Sopenharmony_ci return self.author or "UNKNOWN" 11707db96d56Sopenharmony_ci 11717db96d56Sopenharmony_ci def get_author_email(self): 11727db96d56Sopenharmony_ci return self.author_email or "UNKNOWN" 11737db96d56Sopenharmony_ci 11747db96d56Sopenharmony_ci def get_maintainer(self): 11757db96d56Sopenharmony_ci return self.maintainer or "UNKNOWN" 11767db96d56Sopenharmony_ci 11777db96d56Sopenharmony_ci def get_maintainer_email(self): 11787db96d56Sopenharmony_ci return self.maintainer_email or "UNKNOWN" 11797db96d56Sopenharmony_ci 11807db96d56Sopenharmony_ci def get_contact(self): 11817db96d56Sopenharmony_ci return self.maintainer or self.author or "UNKNOWN" 11827db96d56Sopenharmony_ci 11837db96d56Sopenharmony_ci def get_contact_email(self): 11847db96d56Sopenharmony_ci return self.maintainer_email or self.author_email or "UNKNOWN" 11857db96d56Sopenharmony_ci 11867db96d56Sopenharmony_ci def get_url(self): 11877db96d56Sopenharmony_ci return self.url or "UNKNOWN" 11887db96d56Sopenharmony_ci 11897db96d56Sopenharmony_ci def get_license(self): 11907db96d56Sopenharmony_ci return self.license or "UNKNOWN" 11917db96d56Sopenharmony_ci get_licence = get_license 11927db96d56Sopenharmony_ci 11937db96d56Sopenharmony_ci def get_description(self): 11947db96d56Sopenharmony_ci return self.description or "UNKNOWN" 11957db96d56Sopenharmony_ci 11967db96d56Sopenharmony_ci def get_long_description(self): 11977db96d56Sopenharmony_ci return self.long_description or "UNKNOWN" 11987db96d56Sopenharmony_ci 11997db96d56Sopenharmony_ci def get_keywords(self): 12007db96d56Sopenharmony_ci return self.keywords or [] 12017db96d56Sopenharmony_ci 12027db96d56Sopenharmony_ci def set_keywords(self, value): 12037db96d56Sopenharmony_ci self.keywords = _ensure_list(value, 'keywords') 12047db96d56Sopenharmony_ci 12057db96d56Sopenharmony_ci def get_platforms(self): 12067db96d56Sopenharmony_ci return self.platforms or ["UNKNOWN"] 12077db96d56Sopenharmony_ci 12087db96d56Sopenharmony_ci def set_platforms(self, value): 12097db96d56Sopenharmony_ci self.platforms = _ensure_list(value, 'platforms') 12107db96d56Sopenharmony_ci 12117db96d56Sopenharmony_ci def get_classifiers(self): 12127db96d56Sopenharmony_ci return self.classifiers or [] 12137db96d56Sopenharmony_ci 12147db96d56Sopenharmony_ci def set_classifiers(self, value): 12157db96d56Sopenharmony_ci self.classifiers = _ensure_list(value, 'classifiers') 12167db96d56Sopenharmony_ci 12177db96d56Sopenharmony_ci def get_download_url(self): 12187db96d56Sopenharmony_ci return self.download_url or "UNKNOWN" 12197db96d56Sopenharmony_ci 12207db96d56Sopenharmony_ci # PEP 314 12217db96d56Sopenharmony_ci def get_requires(self): 12227db96d56Sopenharmony_ci return self.requires or [] 12237db96d56Sopenharmony_ci 12247db96d56Sopenharmony_ci def set_requires(self, value): 12257db96d56Sopenharmony_ci import distutils.versionpredicate 12267db96d56Sopenharmony_ci for v in value: 12277db96d56Sopenharmony_ci distutils.versionpredicate.VersionPredicate(v) 12287db96d56Sopenharmony_ci self.requires = list(value) 12297db96d56Sopenharmony_ci 12307db96d56Sopenharmony_ci def get_provides(self): 12317db96d56Sopenharmony_ci return self.provides or [] 12327db96d56Sopenharmony_ci 12337db96d56Sopenharmony_ci def set_provides(self, value): 12347db96d56Sopenharmony_ci value = [v.strip() for v in value] 12357db96d56Sopenharmony_ci for v in value: 12367db96d56Sopenharmony_ci import distutils.versionpredicate 12377db96d56Sopenharmony_ci distutils.versionpredicate.split_provision(v) 12387db96d56Sopenharmony_ci self.provides = value 12397db96d56Sopenharmony_ci 12407db96d56Sopenharmony_ci def get_obsoletes(self): 12417db96d56Sopenharmony_ci return self.obsoletes or [] 12427db96d56Sopenharmony_ci 12437db96d56Sopenharmony_ci def set_obsoletes(self, value): 12447db96d56Sopenharmony_ci import distutils.versionpredicate 12457db96d56Sopenharmony_ci for v in value: 12467db96d56Sopenharmony_ci distutils.versionpredicate.VersionPredicate(v) 12477db96d56Sopenharmony_ci self.obsoletes = list(value) 12487db96d56Sopenharmony_ci 12497db96d56Sopenharmony_cidef fix_help_options(options): 12507db96d56Sopenharmony_ci """Convert a 4-tuple 'help_options' list as found in various command 12517db96d56Sopenharmony_ci classes to the 3-tuple form required by FancyGetopt. 12527db96d56Sopenharmony_ci """ 12537db96d56Sopenharmony_ci new_options = [] 12547db96d56Sopenharmony_ci for help_tuple in options: 12557db96d56Sopenharmony_ci new_options.append(help_tuple[0:3]) 12567db96d56Sopenharmony_ci return new_options 1257