-
Notifications
You must be signed in to change notification settings - Fork 4
/
treefile-expander.py
executable file
·179 lines (153 loc) · 5.87 KB
/
treefile-expander.py
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/bin/python3
# Author: Patrick Uiterwijk <[email protected]>
# This code is released under CC0
# Do whatever you want with it
#
# This script takes an rpm-ostree tree file, and expands
# all of the @groups in it.
import os
import libcomps
import librepo
import sys
import json
import tempfile
import hawkey
# TODO: Make these arguments... sometime
DEBUG_BROKEN = False
SKIP_OPTIONAL = True
if len(sys.argv) != 2:
print('Run as: python treefile-expander.py <treefile>.json.in')
sys.exit(1)
in_filename = sys.argv[1]
out_filename = sys.argv[1].replace('.in', '')
if os.path.exists(out_filename):
print('%s exists' % out_filename)
sys.exit(1)
contents = {}
with open(in_filename, 'r') as f:
lines = [line for line in f.readlines() if not line.strip().startswith('#')]
contents = json.loads(''.join(lines))
def dl_callback(data, total_to_download, downloaded):
PROGRESSBAR_LEN = 50
"""Progress callback"""
if total_to_download <= 0:
return
completed = int(downloaded / (total_to_download / PROGRESSBAR_LEN))
print("[%s%s] %8s/%8s (%s)\r" %
('#'*completed,
'-'*(PROGRESSBAR_LEN-completed),
int(downloaded),
int(total_to_download),
data),)
sys.stdout.flush()
def include_package(pkg):
if pkg.type == libcomps.PACKAGE_TYPE_OPTIONAL and SKIP_OPTIONAL:
# Could be set to True if you want optionals
return False
return True
def is_broken(sack, pkg):
return not bool(hawkey.Query(sack).filter(name=pkg.name))
tempdir = './temp'
with tempfile.TemporaryDirectory('treefile_') as tempdir:
repos = {}
print('Grabbing repo data')
for repo in contents['repos']:
print('Grabbing %s' % repo)
with open('%s.repo' % repo, 'r') as repodata:
os.mkdir('%s/%s' % (tempdir, repo))
h = librepo.Handle()
h.setopt(librepo.LRO_DESTDIR, '%s/%s' % (tempdir, repo))
r = librepo.Result()
got_link = False
for line in repodata.readlines():
if not line.startswith('#'):
if line.startswith('baseurl'):
url = line.split('=')[1].strip()
url = url.replace('$basearch', 'x86_64')
h.setopt(librepo.LRO_URLS, [url])
got_link = True
elif line.startswith('mirrorlist'):
url = line.split('=')[1].strip()
url = url.replace('$basearch', 'x86_64')
h.setopt(librepo.LRO_LRO_MIRRORLIST, url)
got_link = True
if not got_link:
print('Unable to find link')
sys.exit(1)
h.setopt(librepo.LRO_REPOTYPE, librepo.LR_YUMREPO)
h.setopt(librepo.LRO_CHECKSUM, True)
h.setopt(librepo.LRO_PROGRESSCB, dl_callback)
h.setopt(librepo.LRO_YUMDLIST, ["group", "primary"])
h.setopt(librepo.LRO_INTERRUPTIBLE, True)
h.perform(r)
repo_info = r.getinfo(librepo.LRR_YUM_REPO)
# Get primary
primary_sack = hawkey.Sack()
hk_repo = hawkey.Repo(repo)
hk_repo.repomd_fn = repo_info['repomd']
hk_repo.primary_fn = repo_info['primary']
primary_sack.load_repo(hk_repo, load_filelists=False)
# Get comps
comps = libcomps.Comps()
if 'group' in repo_info:
ret = comps.fromxml_f(repo_info['group'])
if ret == -1:
print('Error parsing')
break
repos[repo] = (comps, primary_sack)
expanded = 0
in_packages = contents['packages']
out_packages = set()
for package in in_packages:
if package.startswith('@'):
# Evaluate
package = package[1:]
expanded += 1
found = False
for repo in repos:
comp, sack = repos[repo]
try:
group = comp.groups[package]
found = True
added_packages = 0
broken_packages = 0
skipped_packages = 0
for pkg in group.packages:
if include_package(pkg):
if is_broken(sack, pkg):
if DEBUG_BROKEN:
print('Broken: %s' % pkg.name)
broken_packages += 1
else:
added_packages += 1
out_packages.add(pkg.name)
else:
skipped_packages = 1
print('Group %s was expanded to %d (skipped %d, broken %d)'
% (package,
added_packages,
skipped_packages,
broken_packages))
except KeyError:
# Seems this group was not in this file
pass
if not found:
print('Group %s could not be expanded' % package)
sys.exit(1)
elif package.startswith('-'):
# Remove this package
package = package[1:]
if not package in out_packages:
print('Unable to remove %s' % package)
else:
out_packages.remove(package)
print('Package %s removed' % package)
else:
out_packages.add(package)
contents['packages'] = sorted(list(out_packages))
with open(out_filename, 'w') as f:
f.write(json.dumps(contents,
sort_keys=True,
indent=4,
separators=(',', ': ')))
print('Wrote %s after expanding %d groups' % (out_filename, expanded))