Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sage
Path: blob/develop/build/sage_bootstrap/installcheck.py
4052 views
1
"""
2
Command-line script for checking an installed SPKG in an installation tree ($SAGE_LOCAL, $SAGE_VENV).
3
"""
4
5
# ****************************************************************************
6
# Copyright (C) 2017 Erik M. Bray <[email protected]>
7
# 2022 Matthias Koeppe
8
#
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation, either version 2 of the License, or
12
# (at your option) any later version.
13
# https://www.gnu.org/licenses/
14
# ****************************************************************************
15
from __future__ import print_function
16
17
import glob
18
import json
19
import os
20
import shutil
21
import subprocess
22
import sys
23
import argparse
24
import warnings
25
26
from .env import SAGE_ROOT
27
28
pth = os.path
29
PKGS = pth.join(SAGE_ROOT, 'build', 'pkgs')
30
"""Directory where all spkg sources are found."""
31
32
33
def check_lib_auditwheel(f, verbose=False):
34
from auditwheel.lddtree import lddtree
35
for lib, info in lddtree(f)["libs"].items():
36
if verbose:
37
print('- {0}: {1}'.format(lib, info["realpath"]), file=sys.stderr)
38
if info["realpath"] is None:
39
raise RuntimeError('Shared library {0} needed by {1} is not found'
40
.format(lib, f))
41
42
43
def installcheck(spkg_name, sage_local, verbose=False):
44
"""
45
Given a package name and path to an installation tree (SAGE_LOCAL or SAGE_VENV),
46
check the installation of the package in that tree.
47
"""
48
49
# The default path to this directory; however its value should be read
50
# from the environment if possible
51
spkg_inst = pth.join(sage_local, 'var', 'lib', 'sage', 'installed')
52
53
# Find all stamp files for the package; there should be only one, but if
54
# there is somehow more than one we'll work with the most recent one.
55
pattern = pth.join(spkg_inst, '{0}-*'.format(spkg_name))
56
stamp_files = sorted(glob.glob(pattern), key=pth.getmtime)
57
58
if stamp_files:
59
stamp_file = stamp_files[-1]
60
else:
61
stamp_file = None
62
63
spkg_meta = {}
64
if stamp_file:
65
try:
66
with open(stamp_file) as f:
67
spkg_meta = json.load(f)
68
except (OSError, ValueError):
69
pass
70
71
if 'files' not in spkg_meta:
72
if stamp_file:
73
print("Old-style or corrupt stamp file '{0}'"
74
.format(stamp_file), file=sys.stderr)
75
else:
76
print("Package '{0}' is currently not installed in '{1}'"
77
.format(spkg_name, sage_local), file=sys.stderr)
78
else:
79
files = spkg_meta['files']
80
81
for f in files:
82
f = os.path.join(sage_local, f)
83
if f.endswith(('.so', '.dylib')):
84
if verbose:
85
print("Checking shared library file '{0}'"
86
.format(f), file=sys.stderr)
87
if sys.platform == 'darwin':
88
try:
89
from delocate.libsana import _tree_libs_from_libraries, _filter_system_libs
90
except ImportError:
91
warnings.warn('delocate is not available, so nothing is actually checked')
92
else:
93
_tree_libs_from_libraries([f],
94
lib_filt_func=_filter_system_libs,
95
copy_filt_func=lambda path: True)
96
else:
97
try:
98
check_lib_auditwheel(f, verbose=False)
99
except ImportError:
100
warnings.warn('auditwheel is not available, so nothing is actually checked')
101
elif f.endswith('-any.whl'):
102
# pure Python wheel, nothing to check
103
pass
104
elif f.endswith('.whl'):
105
if verbose:
106
print("Checking wheel file '{0}'"
107
.format(f), file=sys.stderr)
108
if sys.platform == 'darwin':
109
try:
110
from delocate import wheel_libs
111
except ImportError:
112
warnings.warn('delocate is not available, so nothing is actually checked')
113
else:
114
wheel_libs(f)
115
else:
116
try:
117
from delocate.tmpdirs import TemporaryDirectory
118
from delocate.tools import zip2dir
119
except ImportError:
120
warnings.warn('delocate is not available, so nothing is actually checked')
121
else:
122
try:
123
with TemporaryDirectory() as tmpdir:
124
zip2dir(f, tmpdir)
125
for dirpath, dirnames, basenames in os.walk(tmpdir):
126
for base in basenames:
127
if base.endswith('.so'):
128
depending_path = os.path.realpath(os.path.join(dirpath, base))
129
check_lib_auditwheel(depending_path, verbose=False)
130
except ImportError:
131
warnings.warn('auditwheel is not available, so nothing is actually checked')
132
133
134
def dir_type(path):
135
"""
136
A custom argument 'type' for directory paths.
137
"""
138
139
if path and not pth.isdir(path):
140
raise argparse.ArgumentTypeError(
141
"'{0}' is not a directory".format(path))
142
143
return path
144
145
146
def spkg_type(pkg):
147
"""
148
A custom argument 'type' for spkgs--checks whether the given package name
149
is a known spkg.
150
"""
151
pkgbase = pth.join(PKGS, pkg)
152
153
if not pth.isdir(pkgbase):
154
raise argparse.ArgumentTypeError(
155
"'{0}' is not an spkg listed in '{1}'".format(pkg, PKGS))
156
157
return pkg
158
159
160
def make_parser():
161
"""Returns the command-line argument parser for sage-spkg-installcheck."""
162
163
doc_lines = __doc__.strip().splitlines()
164
165
parser = argparse.ArgumentParser(
166
description=doc_lines[0],
167
epilog='\n'.join(doc_lines[1:]).strip(),
168
formatter_class=argparse.RawDescriptionHelpFormatter)
169
170
parser.add_argument('spkg', type=spkg_type, help='the spkg to check')
171
parser.add_argument('sage_local', type=dir_type, nargs='?',
172
default=os.environ.get('SAGE_LOCAL'),
173
help='the path of the installation tree (default: the $SAGE_LOCAL '
174
'environment variable if set)')
175
parser.add_argument('-v', '--verbose', action='store_true',
176
help='verbose output showing all files removed')
177
parser.add_argument('--debug', action='store_true', help=argparse.SUPPRESS)
178
179
return parser
180
181
182
def run(argv=None):
183
parser = make_parser()
184
185
args = parser.parse_args(argv if argv is not None else sys.argv[1:])
186
187
if args.sage_local is None:
188
print('Error: An installation tree must be specified either at the command '
189
'line or in the $SAGE_LOCAL environment variable',
190
file=sys.stderr)
191
sys.exit(1)
192
193
try:
194
installcheck(args.spkg, args.sage_local,
195
verbose=args.verbose)
196
except Exception as exc:
197
print("Error during installcheck of '{0}': {1}".format(
198
args.spkg, exc), file=sys.stderr)
199
200
if args.debug:
201
raise
202
203
sys.exit(1)
204
205
206
if __name__ == '__main__':
207
run()
208
209