summaryrefslogtreecommitdiffstats
path: root/src/tools/ifcodegen/relaxfreeze.py
blob: 706933155f2fda551098927a7a49a3666045f440 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/usr/bin/env python3
# Copyright (C) 2024 The Qt Company Ltd.,
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
"""Make relaxed requirements out of frozen requirements and constraints."""

import argparse
import re


def trim_line(line):
    """Chop comment from end of line and trim white spaces from both sides."""
    commentpos = line.find('#')
    if commentpos >= 0:
        line = line[:commentpos]
    return line.strip()


def get_pkg_name(requirement):
    """Extract package name from a requirement line."""
    match = re.search('[ ><=~[;]', requirement)
    if match:
        return requirement[:match.start()].strip()
    return requirement.strip()


def relax_frozen(frozen_file, constraints_file, relaxed_file, kept_pkgs):
    """Process input files, relax the frozen requirements and write results."""
    if not kept_pkgs:
        kept_pkgs = []
    requirements = {}
    constraints = {}

    for line in frozen_file:
        trim = trim_line(line)
        pkg = get_pkg_name(trim)
        if pkg:
            requirements[pkg] = trim

    for line in constraints_file:
        trim = trim_line(line)
        pkg = get_pkg_name(trim)
        if pkg and pkg in requirements:
            constraints[pkg] = trim
            if pkg not in kept_pkgs:
                requirements[pkg] = trim

    to_remove = []
    for pkg in requirements:
        if pkg not in constraints and pkg not in kept_pkgs:
            to_remove.append(pkg)

    for pkg in to_remove:
        del requirements[pkg]

    for (pkg, requirement) in requirements.items():
        relaxed_file.write(f'{requirement}\n')


def main():
    """Give help on usage and set up input and output files."""
    parser = argparse.ArgumentParser(
        description='''Merges a relaxed requirements file from a frozen
            requirements file and a constraints file by putting all the
            packages found in both into the output file by using the
            constraints instead of specific version numbers. However, specific
            packages can be fixed to the versions in the frozen file.''',
        epilog='''Copyright (C) 2024 The Qt Company Ltd.''')
    parser.add_argument(
        'frozenfile',
        type=argparse.FileType('r'),
        help='''Requirements file created by pip freeze having fixed version
            specifications''')
    parser.add_argument(
        'constraintsfile',
        type=argparse.FileType('r'),
        help='''File of constraints in requirements format from which relaxed
            version requirements will be used by default''')
    parser.add_argument(
        'relaxedfile',
        type=argparse.FileType('w'),
        help='The relaxed output file created in requirements format')
    parser.add_argument(
        '--keep',
        nargs='*',
        metavar='kept packages',
        dest='keep',
        help='Package names in the frozen file to be kept as fixed versions')
    args = parser.parse_args()
    relax_frozen(args.frozenfile, args.constraintsfile, args.relaxedfile,
                 args.keep)


if __name__ == '__main__':
    main()