forked from openstack/requirements
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcap.py
More file actions
executable file
·138 lines (115 loc) · 4.02 KB
/
cap.py
File metadata and controls
executable file
·138 lines (115 loc) · 4.02 KB
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#! /usr/bin/env python
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import argparse
import re
import packaging.requirements
overrides = dict()
# List of overrides needed. Ignore version in pip-freeze and use the one here
# instead. Example:
# suds 0.4.1 isn't pip installable but is in distribution packages
# overrides['suds'] = 'suds==0.4'
# apt package of libvirt-python is lower then our minimum requirement
# overrides['libvirt-python'] = None
def cap(requirements, frozen):
"""Cap requirements to version in freeze.
Go through every package in requirements and try to cap.
Input: two arrays of lines.
Output: Array of new lines.
"""
output = []
for line in requirements:
try:
req = packaging.requirements.Requirement(line)
specifier = str(req.specifier)
if any(op in specifier for op in ['==', '~=', '<']):
# if already capped, continue
output.append(line)
continue
except ValueError:
# line was a comment, continue
output.append(line)
continue
if req.project_name in overrides:
new_line = overrides[req.project_name]
if new_line:
output.append(overrides[req.project_name])
else:
output.append(line)
continue
# add cap
new_cap = cap_requirement(req.project_name, frozen)
if new_cap:
output.append(pin(line, new_cap))
else:
output.append(line)
return output
def pin(line, new_cap):
"""Add new cap into existing line
Don't use packaging.requirements so we can preserve the comments.
"""
end = None
use_comma = False
parts = line.split(' #')
if len(split(parts[0].strip())) > 1:
use_comma = True
if "#" in line:
# if comment
end = parts[1]
# cap to new max version
if end:
new_end = "<=%s #%s" % (new_cap, end)
else:
new_end = "<=%s" % new_cap
if use_comma is True:
return "%s,%s" % (parts[0].strip(), new_end)
else:
return "%s%s" % (parts[0].strip(), new_end)
def split(line):
return re.split('[><=]', line)
def cap_requirement(requirement, frozen):
# Find current version of requirement in freeze
specifier = frozen.get(requirement, None)
if specifier:
return split(str(specifier))[-1]
return None
def freeze(lines):
"""Parse lines from freeze file into a dict.
Where k:v is project_name:specifier.
"""
freeze = dict()
for line in lines:
try:
req = packaging.requirements.Requirement(line)
freeze[req.project_name] = req.specifier
except ValueError:
# not a valid requirement, can be a comment, blank line etc
continue
return freeze
def main():
parser = argparse.ArgumentParser(
description="Take the output of "
"'pip freeze' and use the installed versions to "
"caps requirements.")
parser.add_argument('requirements', help='requirements file input')
parser.add_argument(
'freeze',
help='output of pip freeze, taken from a full tempest job')
args = parser.parse_args()
with open(args.requirements) as f:
requirements = [line.strip() for line in f.readlines()]
with open(args.freeze) as f:
frozen = freeze([line.strip() for line in f.readlines()])
for line in cap(requirements, frozen):
print(line)
if __name__ == '__main__':
main()