Skip to content

Commit 9b6aee8

Browse files
Simplify.
1 parent cc68b86 commit 9b6aee8

File tree

2 files changed

+79
-215
lines changed

2 files changed

+79
-215
lines changed

Lib/test/test_tools/test_freeze.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
"""Sanity-check tests for the "freeze" tool."""
22

3-
import os
4-
import os.path
5-
import subprocess
63
import sys
74
import textwrap
85
import unittest
@@ -22,13 +19,8 @@ def test_freeze_simple_script(self):
2219
print('running...')
2320
sys.exit(0)
2421
""")
25-
outdir, scriptfile, python = helper.prepare(
26-
script,
27-
outoftree=True,
28-
copy=True,
29-
verbose=False,
30-
)
22+
outdir, scriptfile, python = helper.prepare(script)
3123

32-
executable = helper.freeze(python, scriptfile, outdir, verbose=False)
24+
executable = helper.freeze(python, scriptfile, outdir)
3325
text = helper.run(executable)
3426
self.assertEqual(text, 'running...')

Tools/freeze/test/freeze.py

Lines changed: 77 additions & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
import shlex
55
import shutil
66
import subprocess
7-
import sys
87

98

109
TESTS_DIR = os.path.dirname(__file__)
1110
TOOL_ROOT = os.path.dirname(TESTS_DIR)
1211
SRCDIR = os.path.dirname(os.path.dirname(TOOL_ROOT))
1312

14-
CONFIGURE = os.path.join(SRCDIR, 'configure')
1513
MAKE = shutil.which('make')
1614
GIT = shutil.which('git')
1715
FREEZE = os.path.join(TOOL_ROOT, 'freeze.py')
@@ -22,20 +20,20 @@ class UnsupportedError(Exception):
2220
"""The operation isn't supported."""
2321

2422

25-
def _run_cmd(cmd, cwd=None, verbose=True, showcmd=True, showerr=True):
26-
if showcmd:
27-
print(f'# {" ".join(shlex.quote(a) for a in cmd)}')
28-
proc = subprocess.run(
23+
def _run_quiet(cmd, cwd=None):
24+
#print(f'# {" ".join(shlex.quote(a) for a in cmd)}')
25+
return subprocess.run(
2926
cmd,
3027
cwd=cwd,
31-
capture_output=not verbose,
28+
capture_output=True,
3229
text=True,
30+
check=True,
3331
)
34-
if proc.returncode != 0:
35-
if showerr:
36-
print(proc.stderr, file=sys.stderr)
37-
proc.check_returncode()
38-
return proc.stdout
32+
33+
34+
def _run_stdout(cmd, cwd=None):
35+
proc = _run_quiet(cmd, cwd)
36+
return proc.stdout.strip()
3937

4038

4139
def find_opt(args, name):
@@ -67,256 +65,130 @@ def ensure_opt(args, name, value):
6765
args[pos] = f'{opt}={value}'
6866

6967

70-
def git_copy_repo(newroot, remote=None, *, verbose=True):
68+
def git_copy_repo(newroot, oldroot):
7169
if not GIT:
7270
raise UnsupportedError('git')
73-
if not remote:
74-
remote = SRCDIR
71+
7572
if os.path.exists(newroot):
7673
print(f'updating copied repo {newroot}...')
7774
if newroot == SRCDIR:
7875
raise Exception('this probably isn\'t what you wanted')
79-
_run_cmd([GIT, 'clean', '-d', '-f'], newroot, verbose)
80-
_run_cmd([GIT, 'reset'], newroot, verbose)
81-
_run_cmd([GIT, 'checkout', '.'], newroot, verbose)
82-
_run_cmd([GIT, 'pull', '-f', remote], newroot, verbose)
76+
_run_quiet([GIT, 'clean', '-d', '-f'], newroot)
77+
_run_quiet([GIT, 'reset'], newroot)
78+
_run_quiet([GIT, 'checkout', '.'], newroot)
79+
_run_quiet([GIT, 'pull', '-f', oldroot], newroot)
8380
else:
8481
print(f'copying repo into {newroot}...')
85-
_run_cmd([GIT, 'clone', remote, newroot], verbose=verbose)
86-
if os.path.exists(remote):
87-
# Copy over any uncommited files.
88-
reporoot = remote
89-
text = _run_cmd([GIT, 'status', '-s'], reporoot, verbose, showcmd=False)
90-
for line in text.splitlines():
91-
_, _, relfile = line.strip().partition(' ')
92-
relfile = relfile.strip()
93-
isdir = relfile.endswith(os.path.sep)
94-
relfile = relfile.rstrip(os.path.sep)
95-
srcfile = os.path.join(reporoot, relfile)
96-
dstfile = os.path.join(newroot, relfile)
97-
os.makedirs(os.path.dirname(dstfile), exist_ok=True)
98-
if isdir:
99-
shutil.copytree(srcfile, dstfile, dirs_exist_ok=True)
100-
else:
101-
shutil.copy2(srcfile, dstfile)
82+
_run_quiet([GIT, 'clone', oldroot, newroot])
83+
84+
# Copy over any uncommited files.
85+
text = _run_stdout([GIT, 'status', '-s'], oldroot)
86+
for line in text.splitlines():
87+
_, _, relfile = line.strip().partition(' ')
88+
relfile = relfile.strip()
89+
isdir = relfile.endswith(os.path.sep)
90+
relfile = relfile.rstrip(os.path.sep)
91+
srcfile = os.path.join(oldroot, relfile)
92+
dstfile = os.path.join(newroot, relfile)
93+
os.makedirs(os.path.dirname(dstfile), exist_ok=True)
94+
if isdir:
95+
shutil.copytree(srcfile, dstfile, dirs_exist_ok=True)
96+
else:
97+
shutil.copy2(srcfile, dstfile)
10298

10399

104-
##################################
105-
# build queries
106-
107-
def get_makefile_var(builddir, name, *, fail=True):
100+
def get_makefile_var(builddir, name):
108101
regex = re.compile(rf'^{name} *=\s*(.*?)\s*$')
109102
filename = os.path.join(builddir, 'Makefile')
110103
try:
111104
infile = open(filename)
112105
except FileNotFoundError:
113-
if fail:
114-
raise # re-raise
115106
return None
116107
with infile:
117108
for line in infile:
118109
m = regex.match(line)
119110
if m:
120111
value, = m.groups()
121112
return value or ''
122-
if fail:
123-
raise KeyError(f'{name!r} not in Makefile', name=name)
124113
return None
125114

126115

127-
def get_config_var(build, name, *, fail=True):
128-
if os.path.isfile(build):
129-
python = build
130-
builddir = os.path.dirname(build)
131-
else:
132-
builddir = build
133-
python = os.path.join(builddir, 'python')
134-
116+
def get_config_var(builddir, name):
117+
python = os.path.join(builddir, 'python')
135118
if os.path.isfile(python):
119+
cmd = [python, '-c',
120+
f'import sysconfig; print(sysconfig.get_config_var("{name}"))']
136121
try:
137-
text = _run_cmd(
138-
[python, '-c',
139-
f'import sysconfig; print(sysconfig.get_config_var("{name}"))'],
140-
showcmd=False,
141-
showerr=False,
142-
verbose=False,
143-
)
144-
return text
122+
return _run_stdout(cmd)
145123
except subprocess.CalledProcessError:
146124
pass
147-
return get_makefile_var(builddir, name, fail=fail)
125+
return get_makefile_var(builddir, name)
148126

149127

150-
def get_configure_args(build, *, fail=True):
151-
text = get_config_var(build, 'CONFIG_ARGS', fail=fail)
152-
if not text:
153-
return None
154-
return shlex.split(text)
155-
128+
##################################
129+
# freezing
156130

157-
def get_prefix(build=None):
158-
if build and os.path.isfile(build):
159-
return _run_cmd(
160-
[build, '-c' 'import sys; print(sys.prefix)'],
161-
cwd=os.path.dirname(build),
162-
showcmd=False,
163-
)
164-
else:
165-
return get_makefile_var(build or '.', 'prefix', fail=False)
131+
def prepare(script=None, outdir=None):
132+
if not outdir:
133+
outdir = OUTDIR
134+
os.makedirs(outdir, exist_ok=True)
166135

136+
# Write the script to disk.
137+
if script:
138+
scriptfile = os.path.join(outdir, 'app.py')
139+
with open(scriptfile, 'w') as outfile:
140+
outfile.write(script)
167141

168-
##################################
169-
# building Python
170-
171-
def configure_python(builddir=None, prefix=None, cachefile=None, args=None, *,
172-
srcdir=None,
173-
inherit=False,
174-
verbose=True,
175-
):
176-
if not builddir:
177-
builddir = srcdir or SRCDIR
178-
if not srcdir:
179-
configure = os.path.join(builddir, 'configure')
180-
if not os.path.isfile(configure):
181-
srcdir = SRCDIR
182-
configure = CONFIGURE
183-
else:
184-
configure = os.path.join(srcdir, 'configure')
185-
186-
cmd = [configure]
187-
if inherit:
188-
oldargs = get_configure_args(builddir, fail=False)
189-
if oldargs:
190-
cmd.extend(oldargs)
191-
if cachefile:
192-
if args and find_opt(args, 'cache-file') >= 0:
193-
raise ValueError('unexpected --cache-file')
194-
ensure_opt(cmd, 'cache-file', os.path.abspath(cachefile))
195-
if prefix:
196-
if args and find_opt(args, 'prefix') >= 0:
197-
raise ValueError('unexpected --prefix')
198-
ensure_opt(cmd, 'prefix', os.path.abspath(prefix))
199-
if args:
200-
cmd.extend(args)
142+
# Make a copy of the repo to avoid affecting the current build.
143+
srcdir = os.path.join(outdir, 'cpython')
144+
git_copy_repo(srcdir, SRCDIR)
201145

202-
print(f'configuring python in {builddir}...')
146+
# We use an out-of-tree build (instead of srcdir).
147+
builddir = os.path.join(outdir, 'python-build')
203148
os.makedirs(builddir, exist_ok=True)
204-
_run_cmd(cmd, builddir, verbose)
205-
return builddir
206149

150+
# Run configure.
151+
print(f'configuring python in {builddir}...')
152+
cmd = [
153+
os.path.join(srcdir, 'configure'),
154+
*shlex.split(get_config_var(builddir, 'CONFIG_ARGS') or ''),
155+
]
156+
ensure_opt(cmd, 'cache-file', os.path.join(outdir, 'python-config.cache'))
157+
prefix = os.path.join(outdir, 'python-installation')
158+
ensure_opt(cmd, 'prefix', prefix)
159+
_run_quiet(cmd, builddir)
207160

208-
def build_python(builddir, *, verbose=True):
209161
if not MAKE:
210162
raise UnsupportedError('make')
211163

212-
if not builddir:
213-
builddir = '.'
214-
164+
# Build python.
215165
print('building python...')
216-
srcdir = get_config_var(builddir, 'srcdir', fail=False) or SRCDIR
217-
if os.path.abspath(builddir) != srcdir:
218-
if os.path.exists(os.path.join(srcdir, 'Makefile')):
219-
_run_cmd([MAKE, '-C', srcdir, 'clean'], verbose=False)
220-
_run_cmd([MAKE, '-C', builddir, '-j8'], verbose=verbose)
221-
222-
return os.path.join(builddir, 'python')
223-
224-
225-
def install_python(builddir, *, verbose=True):
226-
if not MAKE:
227-
raise UnsupportedError('make')
228-
229-
if not builddir:
230-
builddir = '.'
231-
prefix = get_prefix(builddir)
166+
if os.path.exists(os.path.join(srcdir, 'Makefile')):
167+
# Out-of-tree builds require a clean srcdir.
168+
_run_quiet([MAKE, '-C', srcdir, 'clean'])
169+
_run_quiet([MAKE, '-C', builddir, '-j8'])
232170

171+
# Install the build.
233172
print(f'installing python into {prefix}...')
234-
_run_cmd([MAKE, '-C', builddir, '-j', 'install'], verbose=verbose)
235-
236-
if not prefix:
237-
return None
238-
return os.path.join(prefix, 'bin', 'python3')
239-
240-
241-
def ensure_python_installed(outdir, srcdir=None, *,
242-
outoftree=True,
243-
verbose=True,
244-
):
245-
cachefile = os.path.join(outdir, 'python-config.cache')
246-
prefix = os.path.join(outdir, 'python-installation')
247-
if outoftree:
248-
builddir = os.path.join(outdir, 'python-build')
249-
else:
250-
builddir = srcdir or SRCDIR
251-
configure_python(builddir, prefix, cachefile,
252-
srcdir=srcdir, inherit=True, verbose=verbose)
253-
build_python(builddir, verbose=verbose)
254-
return install_python(builddir, verbose=verbose)
173+
_run_quiet([MAKE, '-C', builddir, '-j8', 'install'])
174+
python = os.path.join(prefix, 'bin', 'python3')
255175

256-
257-
##################################
258-
# freezing
259-
260-
def prepare(script=None, outdir=None, *,
261-
outoftree=True,
262-
copy=False,
263-
verbose=True,
264-
):
265-
if not outdir:
266-
outdir = OUTDIR
267-
os.makedirs(outdir, exist_ok=True)
268-
if script:
269-
if script.splitlines()[0] == script and os.path.isfile(script):
270-
scriptfile = script
271-
else:
272-
scriptfile = os.path.join(outdir, 'app.py')
273-
with open(scriptfile, 'w') as outfile:
274-
outfile.write(script)
275-
else:
276-
scriptfile = None
277-
if copy:
278-
srcdir = os.path.join(outdir, 'cpython')
279-
git_copy_repo(srcdir, SRCDIR, verbose=verbose)
280-
else:
281-
srcdir = SRCDIR
282-
python = ensure_python_installed(outdir, srcdir,
283-
outoftree=outoftree, verbose=verbose)
284176
return outdir, scriptfile, python
285177

286178

287-
def freeze(python, scriptfile, outdir=None, *, verbose=True):
179+
def freeze(python, scriptfile, outdir):
288180
if not MAKE:
289181
raise UnsupportedError('make')
290182

291-
if not outdir:
292-
outdir = OUTDIR
293-
294183
print(f'freezing {scriptfile}...')
295184
os.makedirs(outdir, exist_ok=True)
296-
subprocess.run(
297-
[python, FREEZE, '-o', outdir, scriptfile],
298-
cwd=outdir,
299-
capture_output=not verbose,
300-
check=True,
301-
)
302-
303-
subprocess.run(
304-
[MAKE],
305-
cwd=os.path.dirname(scriptfile),
306-
capture_output=not verbose,
307-
check=True,
308-
)
185+
_run_quiet([python, FREEZE, '-o', outdir, scriptfile], outdir)
186+
_run_quiet([MAKE, '-C', os.path.dirname(scriptfile)])
309187

310188
name = os.path.basename(scriptfile).rpartition('.')[0]
311189
executable = os.path.join(outdir, name)
312190
return executable
313191

314192

315193
def run(executable):
316-
proc = subprocess.run(
317-
[executable],
318-
capture_output=True,
319-
text=True,
320-
check=True,
321-
)
322-
return proc.stdout.strip()
194+
return _run_stdout([executable])

0 commit comments

Comments
 (0)