diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index 19ca74b6a68..488b9b9edbd 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -77,6 +77,37 @@ def list_cls(self, *package_classes, **filters): for pkg_name in pc.names: print(pkg_name) + def properties(self, *package_classes, **kwds): + """ + Show the properties of given packages + + $ sage --package properties --format shell maxima + path_maxima='........./build/pkgs/maxima' + version_with_patchlevel_maxima='5.46.0' + type_maxima='standard' + source_maxima='normal' + trees_maxima='SAGE_LOCAL' + """ + props = kwds.pop('props', ['path', 'version_with_patchlevel', 'type', 'source', 'trees']) + format = kwds.pop('format', 'plain') + log.debug('Looking up properties') + pc = PackageClass(*package_classes) + for package_name in pc.names: + package = Package(package_name) + if format == 'plain': + print("{0}:".format(package_name)) + for p in props: + value = getattr(package, p) + if value is None: + if p.startswith('version'): + value = 'none' + else: + value = '' + if format == 'plain': + print(" {0:28} {1}".format(p + ":", value)) + else: + print("{0}_{1}='{2}'".format(p, package_name, value)) + def name(self, tarball_filename): """ Find the package name given a tarball filename diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index e95e56cafb8..f11c26adb28 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -83,6 +83,22 @@ """ +epilog_properties = \ +""" +Print properties of given package. + +EXAMPLE: + + $ sage --package properties maxima + maxima: + path: /.../build/pkgs/maxima + version_with_patchlevel: 5.46.0 + type: standard + source: normal + trees: SAGE_LOCAL +""" + + epilog_name = \ """ Find the package name given a tarball filename @@ -257,6 +273,19 @@ def make_parser(): '--exclude-dependencies', action='store_true', help='exclude (ordinary) dependencies of the packages recursively') + parser_properties = subparsers.add_parser( + 'properties', epilog=epilog_properties, + formatter_class=argparse.RawDescriptionHelpFormatter, + help='Print properties of given packages') + parser_properties.add_argument( + 'package_class', metavar='[package_name|:package_type:]', + type=str, nargs='+', + help=('package name or designator for all packages of a given type ' + '(one of :all:, :standard:, :optional:, and :experimental:)')) + parser_properties.add_argument( + '--format', type=str, default='plain', + help='output format (one of plain and shell; default: plain)') + parser_name = subparsers.add_parser( 'name', epilog=epilog_name, formatter_class=argparse.RawDescriptionHelpFormatter, @@ -404,6 +433,8 @@ def run(): exclude=args.exclude, include_dependencies=args.include_dependencies, exclude_dependencies=args.exclude_dependencies) + elif args.subcommand == 'properties': + app.properties(*args.package_class, format=args.format) elif args.subcommand == 'name': app.name(args.tarball_filename) elif args.subcommand == 'tarball': diff --git a/build/sage_bootstrap/package.py b/build/sage_bootstrap/package.py index 9363138a457..ca0357b278b 100644 --- a/build/sage_bootstrap/package.py +++ b/build/sage_bootstrap/package.py @@ -48,6 +48,7 @@ def __init__(self, package_name): self._init_type() self._init_install_requires() self._init_dependencies() + self._init_trees() def __repr__(self): return 'Package {0}'.format(self.name) @@ -293,6 +294,23 @@ def patchlevel(self): """ return self.__patchlevel + @property + def version_with_patchlevel(self): + """ + Return the version, including the Sage-specific patchlevel + + OUTPUT: + + String. + """ + v = self.version + if v is None: + return v + p = self.patchlevel + if p < 0: + return v + return "{0}.p{1}".format(v, p) + @property def type(self): """ @@ -300,6 +318,38 @@ def type(self): """ return self.__type + @property + def source(self): + """ + Return the package source type + """ + if self.has_file('requirements.txt'): + return 'pip' + if self.tarball_filename: + if self.tarball_filename.endswith('.whl'): + return 'wheel' + return 'normal' + if self.has_file('spkg-install') or self.has_file('spkg-install.in'): + return 'script' + return 'none' + + @property + def trees(self): + """ + Return the installation trees for the package + + OUTPUT: + + A white-space-separated string of environment variable names + """ + if self.__trees is not None: + return self.__trees + if self.__install_requires is not None: + return 'SAGE_VENV' + if self.has_file('requirements.txt'): + return 'SAGE_VENV' + return 'SAGE_LOCAL' + @property def distribution_name(self): """ @@ -466,3 +516,10 @@ def _init_dependencies(self): self.__dependencies_order_only = f.readline() except IOError: self.__dependencies_order_only = '' + + def _init_trees(self): + try: + with open(os.path.join(self.path, 'trees.txt')) as f: + self.__trees = f.readline().partition('#')[0].strip() + except IOError: + self.__trees = None