Skip to content

Commit 39f8435

Browse files
author
Release Manager
committed
sagemathgh-37018: `sage --package properties` <!-- ^^^^^ 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 sagemath#1234" use "Introduce new method to calculate 1+1" --> <!-- Describe your changes here in detail --> For example: ``` $ ./sage -package properties --format shell gap ecl git:sage_package_properties path_ecl='/Users/mkoeppe/s/sage/sage-rebasing/worktree- pristine/build/pkgs/ecl' version_with_patchlevel_ecl='21.2.1' type_ecl='standard' source_ecl='normal' trees_ecl='SAGE_LOCAL' path_gap='/Users/mkoeppe/s/sage/sage-rebasing/worktree- pristine/build/pkgs/gap' version_with_patchlevel_gap='4.12.2' type_gap='standard' source_gap='normal' trees_gap='SAGE_LOCAL' ``` The output is suitable as input for `eval` in Bourne shell. (The default output format is more human-friendly.) <!-- Why is this change required? What problem does it solve? --> Split out from: - sagemath#36740 where this new interface is used to eliminate direct references to `build/pkgs/` from various scripts and reduce code duplication and complexity in reading SPKG metadata. <!-- If this PR resolves an open issue, please link to it here. For example "Fixes sagemath#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 - sagemath#12345: short description why this is a dependency - sagemath#34567: ... --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> URL: sagemath#37018 Reported by: Matthias Köppe Reviewer(s): Kwankyu Lee
2 parents 821a0e0 + 8ff9e85 commit 39f8435

File tree

3 files changed

+118
-0
lines changed

3 files changed

+118
-0
lines changed

build/sage_bootstrap/app.py

+30
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,36 @@ def list_cls(self, *package_classes, **filters):
7777
for pkg_name in pc.names:
7878
print(pkg_name)
7979

80+
def properties(self, *package_classes, props=['path', 'version_with_patchlevel', 'type', 'source', 'trees'],
81+
format='plain'):
82+
"""
83+
Show the properties of given packages
84+
85+
$ sage --package properties --format shell maxima
86+
path_maxima='........./build/pkgs/maxima'
87+
version_with_patchlevel_maxima='5.46.0'
88+
type_maxima='standard'
89+
source_maxima='normal'
90+
trees_maxima='SAGE_LOCAL'
91+
"""
92+
log.debug('Looking up properties')
93+
pc = PackageClass(*package_classes)
94+
for package_name in pc.names:
95+
package = Package(package_name)
96+
if format == 'plain':
97+
print("{0}:".format(package_name))
98+
for p in props:
99+
value = getattr(package, p)
100+
if value is None:
101+
if p.startswith('version'):
102+
value = 'none'
103+
else:
104+
value = ''
105+
if format == 'plain':
106+
print(" {0:28} {1}".format(p + ":", value))
107+
else:
108+
print("{0}_{1}='{2}'".format(p, package_name, value))
109+
80110
def name(self, tarball_filename):
81111
"""
82112
Find the package name given a tarball filename

build/sage_bootstrap/cmdline.py

+31
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@
8383
"""
8484

8585

86+
epilog_properties = \
87+
"""
88+
Print properties of given package.
89+
90+
EXAMPLE:
91+
92+
$ sage --package properties maxima
93+
maxima:
94+
path: /.../build/pkgs/maxima
95+
version_with_patchlevel: 5.46.0
96+
type: standard
97+
source: normal
98+
trees: SAGE_LOCAL
99+
"""
100+
101+
86102
epilog_name = \
87103
"""
88104
Find the package name given a tarball filename
@@ -257,6 +273,19 @@ def make_parser():
257273
'--exclude-dependencies', action='store_true',
258274
help='exclude (ordinary) dependencies of the packages recursively')
259275

276+
parser_properties = subparsers.add_parser(
277+
'properties', epilog=epilog_properties,
278+
formatter_class=argparse.RawDescriptionHelpFormatter,
279+
help='Print properties of given packages')
280+
parser_properties.add_argument(
281+
'package_class', metavar='[package_name|:package_type:]',
282+
type=str, nargs='+',
283+
help=('package name or designator for all packages of a given type '
284+
'(one of :all:, :standard:, :optional:, and :experimental:)'))
285+
parser_properties.add_argument(
286+
'--format', type=str, default='plain',
287+
help='output format (one of plain and shell; default: plain)')
288+
260289
parser_name = subparsers.add_parser(
261290
'name', epilog=epilog_name,
262291
formatter_class=argparse.RawDescriptionHelpFormatter,
@@ -404,6 +433,8 @@ def run():
404433
exclude=args.exclude,
405434
include_dependencies=args.include_dependencies,
406435
exclude_dependencies=args.exclude_dependencies)
436+
elif args.subcommand == 'properties':
437+
app.properties(*args.package_class, format=args.format)
407438
elif args.subcommand == 'name':
408439
app.name(args.tarball_filename)
409440
elif args.subcommand == 'tarball':

build/sage_bootstrap/package.py

+57
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def __init__(self, package_name):
4848
self._init_type()
4949
self._init_install_requires()
5050
self._init_dependencies()
51+
self._init_trees()
5152

5253
def __repr__(self):
5354
return 'Package {0}'.format(self.name)
@@ -293,13 +294,62 @@ def patchlevel(self):
293294
"""
294295
return self.__patchlevel
295296

297+
@property
298+
def version_with_patchlevel(self):
299+
"""
300+
Return the version, including the Sage-specific patchlevel
301+
302+
OUTPUT:
303+
304+
String.
305+
"""
306+
v = self.version
307+
if v is None:
308+
return v
309+
p = self.patchlevel
310+
if p < 0:
311+
return v
312+
return "{0}.p{1}".format(v, p)
313+
296314
@property
297315
def type(self):
298316
"""
299317
Return the package type
300318
"""
301319
return self.__type
302320

321+
@property
322+
def source(self):
323+
"""
324+
Return the package source type
325+
"""
326+
if self.has_file('requirements.txt'):
327+
return 'pip'
328+
if self.tarball_filename:
329+
if self.tarball_filename.endswith('.whl'):
330+
return 'wheel'
331+
return 'normal'
332+
if self.has_file('spkg-install') or self.has_file('spkg-install.in'):
333+
return 'script'
334+
return 'none'
335+
336+
@property
337+
def trees(self):
338+
"""
339+
Return the installation trees for the package
340+
341+
OUTPUT:
342+
343+
A white-space-separated string of environment variable names
344+
"""
345+
if self.__trees is not None:
346+
return self.__trees
347+
if self.__install_requires is not None:
348+
return 'SAGE_VENV'
349+
if self.has_file('requirements.txt'):
350+
return 'SAGE_VENV'
351+
return 'SAGE_LOCAL'
352+
303353
@property
304354
def distribution_name(self):
305355
"""
@@ -466,3 +516,10 @@ def _init_dependencies(self):
466516
self.__dependencies_order_only = f.readline()
467517
except IOError:
468518
self.__dependencies_order_only = ''
519+
520+
def _init_trees(self):
521+
try:
522+
with open(os.path.join(self.path, 'trees.txt')) as f:
523+
self.__trees = f.readline().partition('#')[0].strip()
524+
except IOError:
525+
self.__trees = None

0 commit comments

Comments
 (0)