diff --git a/build/bin/sage-spkg-info b/build/bin/sage-spkg-info index b7b91a63339..2df0895c31f 100755 --- a/build/bin/sage-spkg-info +++ b/build/bin/sage-spkg-info @@ -16,14 +16,21 @@ if [ -n "$OUTPUT_RST" ]; then issue () { echo ":issue:\`$1\`"; } code () { echo "\`\`$*\`\`"; } tab () { echo ".. tab:: $1"; } + FORMAT=rst else ref () { echo "$1"; } spkg () { echo "$1"; } issue () { echo "https://github.com/sagemath/sage/issues/$1"; } code () { echo "$1"; } tab () { echo "$1:"; } + FORMAT=plain fi -PKG_SCRIPTS="$SAGE_ROOT/build/pkgs/$PKG_BASE" +if ! props=$(sage-package properties --format=shell $PKG_BASE 2> /dev/null); then + echo >&2 "sage-spkg-info: unknown package $PKG_BASE" + exit 1 +fi +eval "$props" +eval PKG_SCRIPTS=\$path_$PKG_BASE for ext in rst txt; do SPKG_FILE="$PKG_SCRIPTS/SPKG.$ext" if [ -f "$SPKG_FILE" ]; then @@ -44,30 +51,7 @@ echo echo "Dependencies" echo "------------" echo -dep= -for dep_file in dependencies dependencies_order_only; do - if [ -r "$PKG_SCRIPTS/$dep_file" ] ; then - for dep in $(sed 's/^ *//; s/ *#.*//; q' "$PKG_SCRIPTS/$dep_file"); do - case "$dep" in - # Do not use order-only syntax, too much information - \|) ;; - # Suppress dependencies on source file of the form $(SAGE_ROOT)/..., $(SAGE_SRC)/... - \$\(SAGE_*) ;; - # Suppress FORCE - FORCE) ;; - # Dependencies like $(BLAS) - \$\(*) echo "- $dep";; - # Looks like a package - *) if [ -r "$SAGE_ROOT/build/pkgs/$dep/SPKG.rst" ]; then - # This RST label is set in src/doc/bootstrap - echo "- $(spkg $dep)" - else - echo "- $dep" - fi;; - esac - done - fi -done +sage-package dependencies --format=$FORMAT $PKG_BASE echo echo "Version Information" echo "-------------------" diff --git a/build/pkgs/giac/dependencies b/build/pkgs/giac/dependencies index a051202507e..d10806b4284 100644 --- a/build/pkgs/giac/dependencies +++ b/build/pkgs/giac/dependencies @@ -1,4 +1,4 @@ -readline libpng $(MP_LIBRARY) mpfr mpfi ntl gsl pari glpk curl cliquer ecm $(findstring libnauty,$(OPTIONAL_INSTALLED_PACKAGES)) +readline libpng $(MP_LIBRARY) mpfr mpfi ntl gsl pari glpk curl cliquer ecm ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/giac/dependencies_optional b/build/pkgs/giac/dependencies_optional new file mode 100644 index 00000000000..e9ef822c0f6 --- /dev/null +++ b/build/pkgs/giac/dependencies_optional @@ -0,0 +1 @@ +libnauty diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index 488b9b9edbd..978753352e5 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -94,8 +94,9 @@ def properties(self, *package_classes, **kwds): pc = PackageClass(*package_classes) for package_name in pc.names: package = Package(package_name) - if format == 'plain': - print("{0}:".format(package_name)) + if len(pc.names) > 1: + if format == 'plain': + print("{0}:".format(package_name)) for p in props: value = getattr(package, p) if value is None: @@ -108,6 +109,79 @@ def properties(self, *package_classes, **kwds): else: print("{0}_{1}='{2}'".format(p, package_name, value)) + def dependencies(self, *package_classes, **kwds): + """ + Find the dependencies given package names + + $ sage --package dependencies maxima --runtime --order-only --format=shell + order_only_deps_maxima='info' + runtime_deps_maxima='ecl' + """ + types = kwds.pop('types', None) + format = kwds.pop('format', 'plain') + log.debug('Looking up dependencies') + pc = PackageClass(*package_classes) + if format in ['plain', 'rst']: + if types is None: + typesets = [['order_only', 'runtime']] + else: + typesets = [[t] for t in types] + elif format == 'shell': + if types is None: + types = ['order_only', 'optional', 'runtime', 'check'] + typesets = [[t] for t in types] + else: + raise ValueError('format must be one of "plain", "rst", and "shell"') + + for package_name in pc.names: + package = Package(package_name) + if len(pc.names) > 1: + if format == 'plain': + print("{0}:".format(package_name)) + indent1 = " " + elif format == 'rst': + print("\n{0}\n{1}\n".format(package_name, "~" * len(package_name))) + indent1 = "" + else: + indent1 = "" + + for typeset in typesets: + if len(typesets) > 1: + if format == 'plain': + print(indent1 + "{0}: ".format('/'.join(typeset))) + indent2 = indent1 + " " + elif format == 'rst': + print("\n" + indent1 + ".. tab:: {0}\n".format('/'.join(typeset))) + indent2 = indent1 + " " + else: + indent2 = indent1 + + deps = [] + for t in typeset: + deps.extend(getattr(package, 'dependencies_' + t)) + deps = sorted(set(deps)) + + if format in ['plain', 'rst']: + for dep in deps: + if '/' in dep: + # Suppress dependencies on source files, e.g. of the form $(SAGE_ROOT)/..., $(SAGE_SRC)/... + continue + if dep == 'FORCE': + # Suppress FORCE + continue + if dep.startswith('$('): + # Dependencies like $(BLAS) + print(indent2 + "- {0}".format(dep)) + elif format == 'rst' and Package(dep).has_file('SPKG.rst'): + # This RST label is set in src/doc/bootstrap + print(indent2 + "- :ref:`spkg_{0}`".format(dep)) + else: + print(indent2 + "- {0}".format(dep)) + elif format == 'shell': + # We single-quote the values because dependencies + # may contain Makefile variable substitutions + print("{0}_deps_{1}='{2}'".format(t, package_name, ' '.join(deps))) + 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 f11c26adb28..7575d0d3706 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -99,6 +99,36 @@ """ +epilog_dependencies = \ +""" +Print the list of packages that are dependencies of given package. +By default, list a summary of the build, order-only, and runtime +dependencies. + +EXAMPLE: + + $ sage --package dependencies maxima openblas + maxima: + - ecl + - info + openblas: + - gfortran + $ sage --package dependencies maxima --runtime + - ecl + + $ sage --package dependencies maxima openblas --runtime --order-only + maxima: + order_only: + - info + runtime: + - ecl + openblas: + order_only: + runtime: + - gfortran +""" + + epilog_name = \ """ Find the package name given a tarball filename @@ -286,6 +316,31 @@ def make_parser(): '--format', type=str, default='plain', help='output format (one of plain and shell; default: plain)') + parser_dependencies = subparsers.add_parser( + 'dependencies', epilog=epilog_dependencies, + formatter_class=argparse.RawDescriptionHelpFormatter, + help='Print the list of packages that are dependencies of given packages') + parser_dependencies.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_dependencies.add_argument( + '--order-only', action='store_true', + help='list the order-only build dependencies') + parser_dependencies.add_argument( + '--optional', action='store_true', + help='list the optional build dependencies') + parser_dependencies.add_argument( + '--runtime', action='store_true', + help='list the runtime dependencies') + parser_dependencies.add_argument( + '--check', action='store_true', + help='list the check dependencies') + parser_dependencies.add_argument( + '--format', type=str, default='plain', + help='output format (one of plain, rst, and shell; default: plain)') + parser_name = subparsers.add_parser( 'name', epilog=epilog_name, formatter_class=argparse.RawDescriptionHelpFormatter, @@ -435,6 +490,19 @@ def run(): exclude_dependencies=args.exclude_dependencies) elif args.subcommand == 'properties': app.properties(*args.package_class, format=args.format) + elif args.subcommand == 'dependencies': + types = [] + if args.order_only: + types.append('order_only') + if args.optional: + types.append('optional') + if args.runtime: + types.append('runtime') + if args.check: + types.append('check') + if not types: + types = None + app.dependencies(*args.package_class, types=types, 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 ca0357b278b..8c76f71a8ea 100644 --- a/build/sage_bootstrap/package.py +++ b/build/sage_bootstrap/package.py @@ -380,6 +380,23 @@ def dependencies_order_only(self): """ return self.__dependencies.partition('|')[2].strip().split() + self.__dependencies_order_only.strip().split() + @property + def dependencies_optional(self): + """ + Return a list of strings, the package names of the optional build dependencies + """ + return self.__dependencies_optional.strip().split() + + @property + def dependencies_runtime(self): + """ + Return a list of strings, the package names of the runtime dependencies + """ + # after a '|', we have order-only build dependencies + return self.__dependencies.partition('|')[0].strip().split() + + dependencies = dependencies_runtime + @property def dependencies_check(self): """ @@ -503,17 +520,22 @@ def _init_install_requires(self): def _init_dependencies(self): try: with open(os.path.join(self.path, 'dependencies')) as f: - self.__dependencies = f.readline().strip() + self.__dependencies = f.readline().partition('#')[0].strip() except IOError: self.__dependencies = '' try: with open(os.path.join(self.path, 'dependencies_check')) as f: - self.__dependencies_check = f.readline().strip() + self.__dependencies_check = f.readline().partition('#')[0].strip() except IOError: self.__dependencies_check = '' + try: + with open(os.path.join(self.path, 'dependencies_optional')) as f: + self.__dependencies_optional = f.readline().partition('#')[0].strip() + except IOError: + self.__dependencies_optional = '' try: with open(os.path.join(self.path, 'dependencies_order_only')) as f: - self.__dependencies_order_only = f.readline() + self.__dependencies_order_only = f.readline().partition('#')[0].strip() except IOError: self.__dependencies_order_only = ''