Skip to content

Commit 0df697a

Browse files
author
Release Manager
committed
gh-37350: `sage -package dependencies` <!-- ^^^^^ Please provide a concise, informative and self-explanatory title. Don't put issue numbers in there, do this in the PR body below. For example, instead of "Fixes #1234" use "Introduce new method to calculate 1+1" --> <!-- Describe your changes here in detail --> We add a new command `sage --package dependencies`. Like the command `sage --package properties` introduced in #37018, it can be used to eliminate direct references to `build/pkgs/` from various scripts and reduce code duplication in reading SPKG metadata. Here we only make such changes in `sage-spkg-info`. The only user-visible change is that the listed dependencies are now sorted alphabetically; this hides [subtle nuances that may be expressed in the sort order of some `dependencies` files](https://github.com/sagem ath/sage/pull/36878#issuecomment-1876426258). - Closes #33860 Split out from: - #36740 <!-- Why is this change required? What problem does it solve? --> <!-- If this PR resolves an open issue, please link to it here. For example "Fixes #12345". --> <!-- If your change requires a documentation PR, please link it appropriately. --> ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> <!-- If your change requires a documentation PR, please link it appropriately --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> <!-- Feel free to remove irrelevant items. --> - [x] The title is concise, informative, and self-explanatory. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation accordingly. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on - #12345: short description why this is a dependency - #34567: ... --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> URL: #37350 Reported by: Matthias Köppe Reviewer(s): Kwankyu Lee, Matthias Köppe
2 parents fba0587 + cce885f commit 0df697a

File tree

6 files changed

+180
-31
lines changed

6 files changed

+180
-31
lines changed

build/bin/sage-spkg-info

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,21 @@ if [ -n "$OUTPUT_RST" ]; then
1616
issue () { echo ":issue:\`$1\`"; }
1717
code () { echo "\`\`$*\`\`"; }
1818
tab () { echo ".. tab:: $1"; }
19+
FORMAT=rst
1920
else
2021
ref () { echo "$1"; }
2122
spkg () { echo "$1"; }
2223
issue () { echo "https://github.com/sagemath/sage/issues/$1"; }
2324
code () { echo "$1"; }
2425
tab () { echo "$1:"; }
26+
FORMAT=plain
2527
fi
26-
PKG_SCRIPTS="$SAGE_ROOT/build/pkgs/$PKG_BASE"
28+
if ! props=$(sage-package properties --format=shell $PKG_BASE 2> /dev/null); then
29+
echo >&2 "sage-spkg-info: unknown package $PKG_BASE"
30+
exit 1
31+
fi
32+
eval "$props"
33+
eval PKG_SCRIPTS=\$path_$PKG_BASE
2734
for ext in rst txt; do
2835
SPKG_FILE="$PKG_SCRIPTS/SPKG.$ext"
2936
if [ -f "$SPKG_FILE" ]; then
@@ -44,30 +51,7 @@ echo
4451
echo "Dependencies"
4552
echo "------------"
4653
echo
47-
dep=
48-
for dep_file in dependencies dependencies_order_only; do
49-
if [ -r "$PKG_SCRIPTS/$dep_file" ] ; then
50-
for dep in $(sed 's/^ *//; s/ *#.*//; q' "$PKG_SCRIPTS/$dep_file"); do
51-
case "$dep" in
52-
# Do not use order-only syntax, too much information
53-
\|) ;;
54-
# Suppress dependencies on source file of the form $(SAGE_ROOT)/..., $(SAGE_SRC)/...
55-
\$\(SAGE_*) ;;
56-
# Suppress FORCE
57-
FORCE) ;;
58-
# Dependencies like $(BLAS)
59-
\$\(*) echo "- $dep";;
60-
# Looks like a package
61-
*) if [ -r "$SAGE_ROOT/build/pkgs/$dep/SPKG.rst" ]; then
62-
# This RST label is set in src/doc/bootstrap
63-
echo "- $(spkg $dep)"
64-
else
65-
echo "- $dep"
66-
fi;;
67-
esac
68-
done
69-
fi
70-
done
54+
sage-package dependencies --format=$FORMAT $PKG_BASE
7155
echo
7256
echo "Version Information"
7357
echo "-------------------"

build/pkgs/giac/dependencies

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
readline libpng $(MP_LIBRARY) mpfr mpfi ntl gsl pari glpk curl cliquer ecm $(findstring libnauty,$(OPTIONAL_INSTALLED_PACKAGES))
1+
readline libpng $(MP_LIBRARY) mpfr mpfi ntl gsl pari glpk curl cliquer ecm
22

33
----------
44
All lines of this file are ignored except the first.

build/pkgs/giac/dependencies_optional

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
libnauty

build/sage_bootstrap/app.py

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ def properties(self, *package_classes, **kwds):
9494
pc = PackageClass(*package_classes)
9595
for package_name in pc.names:
9696
package = Package(package_name)
97-
if format == 'plain':
98-
print("{0}:".format(package_name))
97+
if len(pc.names) > 1:
98+
if format == 'plain':
99+
print("{0}:".format(package_name))
99100
for p in props:
100101
value = getattr(package, p)
101102
if value is None:
@@ -108,6 +109,79 @@ def properties(self, *package_classes, **kwds):
108109
else:
109110
print("{0}_{1}='{2}'".format(p, package_name, value))
110111

112+
def dependencies(self, *package_classes, **kwds):
113+
"""
114+
Find the dependencies given package names
115+
116+
$ sage --package dependencies maxima --runtime --order-only --format=shell
117+
order_only_deps_maxima='info'
118+
runtime_deps_maxima='ecl'
119+
"""
120+
types = kwds.pop('types', None)
121+
format = kwds.pop('format', 'plain')
122+
log.debug('Looking up dependencies')
123+
pc = PackageClass(*package_classes)
124+
if format in ['plain', 'rst']:
125+
if types is None:
126+
typesets = [['order_only', 'runtime']]
127+
else:
128+
typesets = [[t] for t in types]
129+
elif format == 'shell':
130+
if types is None:
131+
types = ['order_only', 'optional', 'runtime', 'check']
132+
typesets = [[t] for t in types]
133+
else:
134+
raise ValueError('format must be one of "plain", "rst", and "shell"')
135+
136+
for package_name in pc.names:
137+
package = Package(package_name)
138+
if len(pc.names) > 1:
139+
if format == 'plain':
140+
print("{0}:".format(package_name))
141+
indent1 = " "
142+
elif format == 'rst':
143+
print("\n{0}\n{1}\n".format(package_name, "~" * len(package_name)))
144+
indent1 = ""
145+
else:
146+
indent1 = ""
147+
148+
for typeset in typesets:
149+
if len(typesets) > 1:
150+
if format == 'plain':
151+
print(indent1 + "{0}: ".format('/'.join(typeset)))
152+
indent2 = indent1 + " "
153+
elif format == 'rst':
154+
print("\n" + indent1 + ".. tab:: {0}\n".format('/'.join(typeset)))
155+
indent2 = indent1 + " "
156+
else:
157+
indent2 = indent1
158+
159+
deps = []
160+
for t in typeset:
161+
deps.extend(getattr(package, 'dependencies_' + t))
162+
deps = sorted(set(deps))
163+
164+
if format in ['plain', 'rst']:
165+
for dep in deps:
166+
if '/' in dep:
167+
# Suppress dependencies on source files, e.g. of the form $(SAGE_ROOT)/..., $(SAGE_SRC)/...
168+
continue
169+
if dep == 'FORCE':
170+
# Suppress FORCE
171+
continue
172+
if dep.startswith('$('):
173+
# Dependencies like $(BLAS)
174+
print(indent2 + "- {0}".format(dep))
175+
elif format == 'rst' and Package(dep).has_file('SPKG.rst'):
176+
# This RST label is set in src/doc/bootstrap
177+
print(indent2 + "- :ref:`spkg_{0}`".format(dep))
178+
else:
179+
print(indent2 + "- {0}".format(dep))
180+
elif format == 'shell':
181+
# We single-quote the values because dependencies
182+
# may contain Makefile variable substitutions
183+
print("{0}_deps_{1}='{2}'".format(t, package_name, ' '.join(deps)))
184+
111185
def name(self, tarball_filename):
112186
"""
113187
Find the package name given a tarball filename

build/sage_bootstrap/cmdline.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,36 @@
9999
"""
100100

101101

102+
epilog_dependencies = \
103+
"""
104+
Print the list of packages that are dependencies of given package.
105+
By default, list a summary of the build, order-only, and runtime
106+
dependencies.
107+
108+
EXAMPLE:
109+
110+
$ sage --package dependencies maxima openblas
111+
maxima:
112+
- ecl
113+
- info
114+
openblas:
115+
- gfortran
116+
$ sage --package dependencies maxima --runtime
117+
- ecl
118+
119+
$ sage --package dependencies maxima openblas --runtime --order-only
120+
maxima:
121+
order_only:
122+
- info
123+
runtime:
124+
- ecl
125+
openblas:
126+
order_only:
127+
runtime:
128+
- gfortran
129+
"""
130+
131+
102132
epilog_name = \
103133
"""
104134
Find the package name given a tarball filename
@@ -286,6 +316,31 @@ def make_parser():
286316
'--format', type=str, default='plain',
287317
help='output format (one of plain and shell; default: plain)')
288318

319+
parser_dependencies = subparsers.add_parser(
320+
'dependencies', epilog=epilog_dependencies,
321+
formatter_class=argparse.RawDescriptionHelpFormatter,
322+
help='Print the list of packages that are dependencies of given packages')
323+
parser_dependencies.add_argument(
324+
'package_class', metavar='[package_name|:package_type:]',
325+
type=str, nargs='+',
326+
help=('package name or designator for all packages of a given type '
327+
'(one of :all:, :standard:, :optional:, and :experimental:)'))
328+
parser_dependencies.add_argument(
329+
'--order-only', action='store_true',
330+
help='list the order-only build dependencies')
331+
parser_dependencies.add_argument(
332+
'--optional', action='store_true',
333+
help='list the optional build dependencies')
334+
parser_dependencies.add_argument(
335+
'--runtime', action='store_true',
336+
help='list the runtime dependencies')
337+
parser_dependencies.add_argument(
338+
'--check', action='store_true',
339+
help='list the check dependencies')
340+
parser_dependencies.add_argument(
341+
'--format', type=str, default='plain',
342+
help='output format (one of plain, rst, and shell; default: plain)')
343+
289344
parser_name = subparsers.add_parser(
290345
'name', epilog=epilog_name,
291346
formatter_class=argparse.RawDescriptionHelpFormatter,
@@ -435,6 +490,19 @@ def run():
435490
exclude_dependencies=args.exclude_dependencies)
436491
elif args.subcommand == 'properties':
437492
app.properties(*args.package_class, format=args.format)
493+
elif args.subcommand == 'dependencies':
494+
types = []
495+
if args.order_only:
496+
types.append('order_only')
497+
if args.optional:
498+
types.append('optional')
499+
if args.runtime:
500+
types.append('runtime')
501+
if args.check:
502+
types.append('check')
503+
if not types:
504+
types = None
505+
app.dependencies(*args.package_class, types=types, format=args.format)
438506
elif args.subcommand == 'name':
439507
app.name(args.tarball_filename)
440508
elif args.subcommand == 'tarball':

build/sage_bootstrap/package.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,23 @@ def dependencies_order_only(self):
380380
"""
381381
return self.__dependencies.partition('|')[2].strip().split() + self.__dependencies_order_only.strip().split()
382382

383+
@property
384+
def dependencies_optional(self):
385+
"""
386+
Return a list of strings, the package names of the optional build dependencies
387+
"""
388+
return self.__dependencies_optional.strip().split()
389+
390+
@property
391+
def dependencies_runtime(self):
392+
"""
393+
Return a list of strings, the package names of the runtime dependencies
394+
"""
395+
# after a '|', we have order-only build dependencies
396+
return self.__dependencies.partition('|')[0].strip().split()
397+
398+
dependencies = dependencies_runtime
399+
383400
@property
384401
def dependencies_check(self):
385402
"""
@@ -503,17 +520,22 @@ def _init_install_requires(self):
503520
def _init_dependencies(self):
504521
try:
505522
with open(os.path.join(self.path, 'dependencies')) as f:
506-
self.__dependencies = f.readline().strip()
523+
self.__dependencies = f.readline().partition('#')[0].strip()
507524
except IOError:
508525
self.__dependencies = ''
509526
try:
510527
with open(os.path.join(self.path, 'dependencies_check')) as f:
511-
self.__dependencies_check = f.readline().strip()
528+
self.__dependencies_check = f.readline().partition('#')[0].strip()
512529
except IOError:
513530
self.__dependencies_check = ''
531+
try:
532+
with open(os.path.join(self.path, 'dependencies_optional')) as f:
533+
self.__dependencies_optional = f.readline().partition('#')[0].strip()
534+
except IOError:
535+
self.__dependencies_optional = ''
514536
try:
515537
with open(os.path.join(self.path, 'dependencies_order_only')) as f:
516-
self.__dependencies_order_only = f.readline()
538+
self.__dependencies_order_only = f.readline().partition('#')[0].strip()
517539
except IOError:
518540
self.__dependencies_order_only = ''
519541

0 commit comments

Comments
 (0)