|
|
|
@ -1,70 +1,75 @@ |
|
|
|
#!/usr/bin/env python3 |
|
|
|
|
|
|
|
import re |
|
|
|
from os.path import join |
|
|
|
from subprocess import check_call, check_output |
|
|
|
from sys import argv |
|
|
|
from sys import argv, stdout |
|
|
|
from tempfile import TemporaryDirectory |
|
|
|
|
|
|
|
|
|
|
|
def print_packages(packages, heading): |
|
|
|
print(f'{heading}:') |
|
|
|
print(' ', end='') |
|
|
|
print('\n '.join(packages)) |
|
|
|
|
|
|
|
|
|
|
|
# would be nice if there was a cleaner way to get this, but I've not found a |
|
|
|
# more reliable one. |
|
|
|
with open('setup.py') as fh: |
|
|
|
match = re.search(r"name='(?P<pkg>[\w-]+)',", fh.read()) |
|
|
|
if not match: |
|
|
|
raise Exception('failed to determine our package name') |
|
|
|
our_package_name = match.group('pkg') |
|
|
|
print(f'our_package_name: {our_package_name}') |
|
|
|
|
|
|
|
with TemporaryDirectory() as tmpdir: |
|
|
|
check_call(['python3', '-m', 'venv', tmpdir]) |
|
|
|
|
|
|
|
def install_and_list(target): |
|
|
|
check_call([join(tmpdir, 'bin', 'pip'), 'install', target]) |
|
|
|
frozen = ( |
|
|
|
check_output([join(tmpdir, 'bin', 'pip'), 'freeze']) |
|
|
|
.decode('utf-8') |
|
|
|
.strip() |
|
|
|
.split('\n') |
|
|
|
) |
|
|
|
# file bit skips ourself |
|
|
|
return set(p.split('=', 1)[0] for p in frozen if 'file' not in p) |
|
|
|
|
|
|
|
# base needs |
|
|
|
check_call([join(tmpdir, 'bin', 'pip'), 'install', '.']) |
|
|
|
frozen = check_output([join(tmpdir, 'bin', 'pip'), 'freeze']) |
|
|
|
frozen = set(frozen.decode('utf-8').strip().split('\n')) |
|
|
|
frozen = install_and_list('.') |
|
|
|
# dev needs |
|
|
|
dev_frozen = install_and_list('.[dev]') - frozen |
|
|
|
# docs needs |
|
|
|
docs_frozen = install_and_list('.[docs]') - dev_frozen - frozen |
|
|
|
|
|
|
|
# dev additions |
|
|
|
check_call([join(tmpdir, 'bin', 'pip'), 'install', '.[dev]']) |
|
|
|
dev_frozen = check_output([join(tmpdir, 'bin', 'pip'), 'freeze']) |
|
|
|
dev_frozen = set(dev_frozen.decode('utf-8').strip().split('\n')) - frozen |
|
|
|
|
|
|
|
# pip installs the module itself along with deps so we need to get that out of |
|
|
|
# our list by finding the thing that was file installed during dev |
|
|
|
frozen = sorted([p for p in frozen if not p.startswith(our_package_name)]) |
|
|
|
dev_frozen = sorted( |
|
|
|
[p for p in dev_frozen if not p.startswith(our_package_name)] |
|
|
|
) |
|
|
|
# find the installed version for each package |
|
|
|
versions = {} |
|
|
|
for pv in ( |
|
|
|
check_output([join(tmpdir, 'bin', 'pip'), 'freeze']) |
|
|
|
.decode('utf-8') |
|
|
|
.strip() |
|
|
|
.split('\n') |
|
|
|
): |
|
|
|
if 'file' in pv: |
|
|
|
# skip ourself |
|
|
|
continue |
|
|
|
p, v = pv.split('==') |
|
|
|
versions[p] = (v,) |
|
|
|
|
|
|
|
# special handling for click until python 3.9 is gone due to it dropping |
|
|
|
# support for active versions early |
|
|
|
i = [i for i, r in enumerate(dev_frozen) if r.startswith('click==')][0] |
|
|
|
dev_frozen = ( |
|
|
|
dev_frozen[:i] |
|
|
|
+ [ |
|
|
|
"click==8.1.8; python_version<'3.10'", |
|
|
|
f"{dev_frozen[i]}; python_version>='3.10'", |
|
|
|
] |
|
|
|
+ dev_frozen[i + 1 :] |
|
|
|
versions['click'] = ( |
|
|
|
"8.1.8; python_version<'3.10'", |
|
|
|
f"{versions['click'][0]}; python_version>='3.10'", |
|
|
|
) |
|
|
|
|
|
|
|
print_packages(frozen, 'frozen') |
|
|
|
print_packages(dev_frozen, 'dev_frozen') |
|
|
|
|
|
|
|
script = argv[0] |
|
|
|
def write_packages(fh, packages, header, prefix=''): |
|
|
|
fh.write(header) |
|
|
|
for p in sorted(packages): |
|
|
|
for v in versions[p]: |
|
|
|
fh.write(prefix) |
|
|
|
fh.write(p) |
|
|
|
fh.write('==') |
|
|
|
fh.write(v) |
|
|
|
fh.write('\n') |
|
|
|
|
|
|
|
|
|
|
|
write_packages(stdout, frozen, header='base\n', prefix=' ') |
|
|
|
write_packages(stdout, dev_frozen, header='dev\n', prefix=' ') |
|
|
|
write_packages(stdout, docs_frozen, header='docs\n', prefix=' ') |
|
|
|
|
|
|
|
header = f'# DO NOT EDIT THIS FILE DIRECTLY - use {argv[0]} to update\n' |
|
|
|
|
|
|
|
with open('requirements.txt', 'w') as fh: |
|
|
|
fh.write(f'# DO NOT EDIT THIS FILE DIRECTLY - use {script} to update\n') |
|
|
|
fh.write('\n'.join(frozen)) |
|
|
|
fh.write('\n') |
|
|
|
write_packages(fh, frozen, header=header) |
|
|
|
|
|
|
|
with open('requirements-dev.txt', 'w') as fh: |
|
|
|
fh.write(f'# DO NOT EDIT THIS FILE DIRECTLY - use {script} to update\n') |
|
|
|
fh.write('\n'.join(dev_frozen)) |
|
|
|
fh.write('\n') |
|
|
|
write_packages(fh, dev_frozen, header=header) |
|
|
|
|
|
|
|
with open('requirements-docs.txt', 'w') as fh: |
|
|
|
write_packages(fh, docs_frozen, header=header) |