Merge lp:~brian-murray/ubuntu-archive-tools/nbs-alt-deps into lp:ubuntu-archive-tools

Proposed by Brian Murray
Status: Merged
Merged at revision: 1233
Proposed branch: lp:~brian-murray/ubuntu-archive-tools/nbs-alt-deps
Merge into: lp:ubuntu-archive-tools
Diff against target: 284 lines (+122/-44)
4 files modified
checkrdepends (+1/-31)
cron.NBS (+1/-1)
nbs-report (+65/-12)
utils.py (+55/-0)
To merge this branch: bzr merge lp:~brian-murray/ubuntu-archive-tools/nbs-alt-deps
Reviewer Review Type Date Requested Status
Steve Langasek Approve
Review via email: mp+371474@code.launchpad.net

Description of the change

This modifies the NBS report so that it is aware of packages which have a dependency on a package which is NBS but that dependency also has an alternate (ORed) dependency that is satisfied by another package in the archive.

This is done by reading the Sources.gz and Packages.gz files again to see if the dependency has an alternate one and checking to see if the alternate is also NBS.

The read_tag_file function was moved out of checkrdepends and into utils.py and it is now utilized by nbs-report. The cron.NBS file was also modified so that the archive base directory is passed to nbs-report.

To post a comment you must log in.
Revision history for this message
Brian Murray (brian-murray) wrote :

The output of the updated report can be found here:

https://people.canonical.com/~brian/tmp/nbs.html

Revision history for this message
Steve Langasek (vorlon) :
review: Needs Information
1231. By Brian Murray

make changes based on reviewer feedback

Revision history for this message
Brian Murray (brian-murray) wrote :

I've answered your questions and made a change or two to the code.

Revision history for this message
Steve Langasek (vorlon) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'checkrdepends'
2--- checkrdepends 2019-04-20 00:28:29 +0000
3+++ checkrdepends 2019-08-19 23:21:28 +0000
4@@ -17,14 +17,12 @@
5 from __future__ import print_function
6
7 from collections import defaultdict
8-import gzip
9 import optparse
10 import os
11 import re
12 import sys
13-import tempfile
14
15-import apt_pkg
16+from utils import read_tag_file
17
18
19 default_base = '/home/ubuntu-archive/mirror/ubuntu'
20@@ -65,34 +63,6 @@
21 return ('arm64', 'armhf', 'ppc64el', 's390x')
22
23
24-def read_tag_file(path):
25- tmp = tempfile.NamedTemporaryFile(prefix='checkrdepends.', delete=False)
26- try:
27- compressed = gzip.open(path)
28- try:
29- tmp.write(compressed.read())
30- finally:
31- compressed.close()
32- tmp.close()
33- with open(tmp.name) as uncompressed:
34- tag_file = apt_pkg.TagFile(uncompressed)
35- prev_name = None
36- prev_stanza = None
37- for stanza in tag_file:
38- try:
39- name = stanza['package']
40- except KeyError:
41- continue
42- if name != prev_name and prev_stanza is not None:
43- yield prev_stanza
44- prev_name = name
45- prev_stanza = stanza
46- if prev_stanza is not None:
47- yield prev_stanza
48- finally:
49- os.unlink(tmp.name)
50-
51-
52 def read_sources(path):
53 ret = {
54 'binary': {},
55
56=== modified file 'cron.NBS'
57--- cron.NBS 2019-04-20 00:28:29 +0000
58+++ cron.NBS 2019-08-19 23:21:28 +0000
59@@ -42,6 +42,6 @@
60
61 rsync -a --delete "$D/" "$OUTDIR/"
62
63-nbs-report -d "$DISTRIBUTION" -s "$RELEASE" --csv "${OUTFILE%.html}.csv" \
64+nbs-report -B "$MIRROR/$DISTRIBUTION" -d "$DISTRIBUTION" -s "$RELEASE" --csv "${OUTFILE%.html}.csv" \
65 "$OUTDIR/" >"$OUTFILE.new" && \
66 mv "$OUTFILE.new" "$OUTFILE"
67
68=== modified file 'nbs-report'
69--- nbs-report 2019-04-20 00:28:29 +0000
70+++ nbs-report 2019-08-19 23:21:28 +0000
71@@ -2,6 +2,7 @@
72
73 # Copyright (C) 2011, 2012 Canonical Ltd.
74 # Author: Martin Pitt <martin.pitt@ubuntu.com>
75+# Author: Brian Murray <brian@ubuntu.com>
76
77 # This program is free software: you can redistribute it and/or modify
78 # it under the terms of the GNU General Public License as published by
79@@ -28,6 +29,10 @@
80 import time
81
82 from charts import make_chart, make_chart_header
83+from utils import read_tag_file
84+
85+default_base = '/home/ubuntu-archive/mirror/ubuntu'
86+rdeps_with_alternates = []
87
88
89 def parse_checkrdepends_file(path, pkgmap):
90@@ -48,8 +53,8 @@
91 pkgmap.setdefault(rdep, (cur_component, []))[1].append(cur_arch)
92
93
94-def _pkg_removable(pkg, nbs, checked_v):
95- '''Recursively check if pakcage is removable.
96+def _pkg_removable(options, pkg, nbs, checked_v):
97+ '''Recursively check if package is removable.
98
99 checked_v is the working set of already checked vertices, to avoid infinite
100 loops.
101@@ -58,14 +63,56 @@
102 for rdep in nbs.get(pkg, []):
103 if rdep in checked_v:
104 continue
105- #checked_v.add(rdep)
106- if not rdep in nbs:
107+ global rdeps_with_alternates
108+ # utilize a copy of the arches as nbs will be modified
109+ arches = list(nbs[pkg][rdep][1])
110+ for arch in arches:
111+ alternate_available = False
112+ if arch == 'build':
113+ ptype = 'source'
114+ file = 'Sources'
115+ else:
116+ ptype = 'binary-%s' % arch
117+ file = 'Packages'
118+ stanzas = read_tag_file('%s/dists/%s/%s/%s/%s.gz' %
119+ (options.archive_base, options.suite,
120+ nbs[pkg][rdep][0], ptype, file), rdep)
121+ for stanza in stanzas:
122+ if 'binary' in ptype:
123+ fields = ('Pre-Depends', 'Depends', 'Recommends')
124+ else:
125+ fields = ('Build-Depends', 'Build-Depends-Indep')
126+ for field in fields:
127+ if field not in stanza:
128+ continue
129+ if '|' not in stanza[field]:
130+ continue
131+ for or_dep in stanza[field].split(','):
132+ if '|' not in or_dep:
133+ continue
134+ alternatives = [dep.strip()
135+ for dep in or_dep.split('|')]
136+ if pkg not in alternatives:
137+ continue
138+ for dep in alternatives:
139+ if dep == pkg:
140+ continue
141+ if dep not in nbs:
142+ alternate_available = True
143+ break
144+ if alternate_available:
145+ nbs[pkg][rdep][1].remove(arch)
146+
147+ if len(nbs[pkg][rdep][1]) == 0:
148+ rdeps_with_alternates.append(rdep)
149+
150+ if rdep not in nbs and rdep not in rdeps_with_alternates:
151 try:
152 checked_v.remove(rdep)
153 except KeyError:
154 pass
155 return False
156- if not _pkg_removable(rdep, nbs, checked_v):
157+ if not _pkg_removable(options, rdep, nbs, checked_v):
158 try:
159 checked_v.remove(rdep)
160 except KeyError:
161@@ -74,7 +121,7 @@
162 return True
163
164
165-def get_removables(nbs):
166+def get_removables(options, nbs):
167 '''Get set of removable packages.
168
169 This includes packages with no rdepends and disconnected subgraphs, i. e.
170@@ -86,10 +133,9 @@
171 if p in removable:
172 continue
173 checked_v = set()
174- if _pkg_removable(p, nbs, checked_v):
175- # we can add the entire cluster here, not just p; avoids
176- # re-checking the other vertices in that cluster
177- removable.update(checked_v)
178+ if _pkg_removable(options, p, nbs, checked_v):
179+ # we only add packages which are nbs to removable
180+ removable.update([p for p in checked_v if p in nbs])
181
182 return removable
183
184@@ -97,6 +143,7 @@
185 def html_report(options, nbs, removables):
186 '''Generate HTML report from NBS map.'''
187
188+ global rdeps_with_alternates
189 print('''\
190 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
191 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
192@@ -148,9 +195,11 @@
193 cls = 'removable'
194 else:
195 cls = 'normal'
196- print('<tr><th colspan="4"><span class="%s">%s</span></td></tr>' %
197+ print('<tr><th colspan="4"><span class="%s">%s</span></th></tr>\n' %
198 (cls, pkg), end="")
199 for rdep in sorted(nbsmap):
200+ if rdep in rdeps_with_alternates:
201+ continue
202 (component, arches) = nbsmap[rdep]
203
204 if component in ('main', 'restricted'):
205@@ -208,6 +257,10 @@
206 parser = OptionParser(
207 usage="%prog <checkrdepends output directory>",
208 description="Generate an HTML report of current NBS binary packages.")
209+ parser.add_option('-B', '--archive-base', dest='archive_base',
210+ help=('archive base directory (default: %s)' %
211+ default_base),
212+ default=default_base)
213 parser.add_option('-d', '--distribution', default='ubuntu')
214 parser.add_option('-s', '--suite', default='eoan')
215 parser.add_option(
216@@ -246,7 +299,7 @@
217 # rd.replace('-', '').replace('.', '')), file=dot)
218 # print('}', file=dot)
219
220- removables = get_removables(nbs)
221+ removables = get_removables(options, nbs)
222
223 html_report(options, nbs, removables)
224
225
226=== added file 'utils.py'
227--- utils.py 1970-01-01 00:00:00 +0000
228+++ utils.py 2019-08-19 23:21:28 +0000
229@@ -0,0 +1,55 @@
230+#!/usr/bin/python
231+
232+# Copyright (C) 2019 Canonical Ltd.
233+# Author: Brian Murray <brian.murray@canonical.com>
234+
235+# This program is free software: you can redistribute it and/or modify
236+# it under the terms of the GNU General Public License as published by
237+# the Free Software Foundation; version 3 of the License.
238+#
239+# This program is distributed in the hope that it will be useful,
240+# but WITHOUT ANY WARRANTY; without even the implied warranty of
241+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
242+# GNU General Public License for more details.
243+#
244+# You should have received a copy of the GNU General Public License
245+# along with this program. If not, see <http://www.gnu.org/licenses/>.
246+
247+"""Portions of archive related code that is re-used by various tools."""
248+
249+import gzip
250+import os
251+import tempfile
252+
253+import apt_pkg
254+
255+
256+def read_tag_file(path, pkg=None):
257+ tmp = tempfile.NamedTemporaryFile(prefix='checkrdepends.', delete=False)
258+ try:
259+ compressed = gzip.open(path)
260+ try:
261+ tmp.write(compressed.read())
262+ finally:
263+ compressed.close()
264+ tmp.close()
265+ with open(tmp.name) as uncompressed:
266+ tag_file = apt_pkg.TagFile(uncompressed)
267+ prev_name = None
268+ prev_stanza = None
269+ for stanza in tag_file:
270+ try:
271+ name = stanza['package']
272+ except KeyError:
273+ continue
274+ if pkg:
275+ if name != pkg:
276+ continue
277+ if name != prev_name and prev_stanza is not None:
278+ yield prev_stanza
279+ prev_name = name
280+ prev_stanza = stanza
281+ if prev_stanza is not None:
282+ yield prev_stanza
283+ finally:
284+ os.unlink(tmp.name)

Subscribers

People subscribed via source and target branches