Merge ~fourdollars/pc-enablement/+git/oem-scripts:master into ~oem-solutions-engineers/pc-enablement/+git/oem-scripts:master
- Git
- lp:~fourdollars/pc-enablement/+git/oem-scripts
- master
- Merge into master
Status: | Merged |
---|---|
Merged at revision: | 4baba105b3d1677c97b10f86131c904283b1f810 |
Proposed branch: | ~fourdollars/pc-enablement/+git/oem-scripts:master |
Merge into: | ~oem-solutions-engineers/pc-enablement/+git/oem-scripts:master |
Diff against target: |
321 lines (+200/-18) 8 files modified
debian/changelog (+13/-0) debian/tests/pkg-list (+4/-0) oem-meta-packages (+151/-0) oem_scripts/LaunchpadLogin.py (+1/-1) pkg-list (+28/-17) setup.py (+1/-0) tests/test_flake8 (+1/-0) tests/test_pep8 (+1/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Yuan-Chen Cheng (community) | Approve | ||
Review via email: mp+394863@code.launchpad.net |
Commit message
Description of the change
linux-image-
$ pkg-list --apt-dir /tmp/apt.W1fko1dluV linux-oem --exclude /tmp/apt.
amd64-microcode 3.20191021.
intel-microcode 3.20201110.
iucode-tool 2.3.1-1
linux-firmware 1.173.19
linux-headers-
linux-headers-oem 4.15.0.1104.108
linux-image-oem 4.15.0.1104.108
linux-oem 4.15.0.1104.108
linux-oem-
$ pkg-list --apt-dir /tmp/apt.W1fko1dluV linux-oem --exclude /tmp/apt.
<ERROR> linux-image-
$ run-autopkgtest lxc focal -t pkg-list -C
...
pkg-list PASS
autopkgtest-
$ grep ERROR autopkgtest-
<ERROR> python3:any is unavailable.
It is usual to see some Debian package still unavailable in proposed channel.
Alex Tu (alextu) wrote : | # |
Alex Tu (alextu) wrote : | # |
LGTM.
Shih-Yuan Lee (fourdollars) wrote : | # |
$ cat autopkgtest-
mir-bug-
autopkgtest-
autopkgtest-
pkg-somerville-meta PASS
pkg-sutton-meta PASS
pkg-stella-meta PASS
launchpad-api PASS
get-private-ppa PASS
jq-lp PASS
mir-bug PASS
run-autopkgtest PASS
bug-bind PASS
pkg-list PASS
setup-apt-dir PASS
git-url-
autopkgtest-
Shih-Yuan Lee (fourdollars) wrote : | # |
$ ./oem-meta-packages subscribe
<INFO> Using oem-scripts login
<INFO> Loading KWallet
<INFO> Loading SecretService
<INFO> Loading Windows
<INFO> Loading chainer
<INFO> Loading macOS
<INFO> Checking the subscriptions for oem-somerville-
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-somerville-
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-somerville-
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-somerville-
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-somerville-
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-somerville-
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-somerville-
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-qemu-meta...
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/
<INFO> Checking the subscriptions for oem-sutton.
<INFO> ubuntu/oem-sutto...
Yuan-Chen Cheng (ycheng-twn) wrote : | # |
for change related to pkg-list, they are LGTM.
Yuan-Chen Cheng (ycheng-twn) wrote : | # |
note: talk in the f2f with $4, I think there could be some other better place to do what oem-meta-packages is doing.
However, he can't think any other script fits. Give so, approve it.
Preview Diff
1 | diff --git a/debian/changelog b/debian/changelog |
2 | index 4545eb5..20ad464 100644 |
3 | --- a/debian/changelog |
4 | +++ b/debian/changelog |
5 | @@ -1,3 +1,16 @@ |
6 | +oem-scripts (0.71) UNRELEASED; urgency=medium |
7 | + |
8 | + * pkg-list: Add an option '--fail-unavailable' to return unavailable error. |
9 | + * pkg-list: Refine the checking for depends. |
10 | + * oem-meta-packages, |
11 | + oem_scripts/LaunchpadLogin.py, |
12 | + setup.py, |
13 | + tests/test_flake8, |
14 | + tests/test_pep8: Add oem-meta-packages to subscribe the bugs of oem meta |
15 | + packages. |
16 | + |
17 | + -- Shih-Yuan Lee (FourDollars) <sylee@canonical.com> Fri, 04 Dec 2020 14:50:37 +0800 |
18 | + |
19 | oem-scripts (0.70) focal; urgency=medium |
20 | |
21 | * mir-bug, |
22 | diff --git a/debian/tests/pkg-list b/debian/tests/pkg-list |
23 | index ae02e8d..92dfe33 100644 |
24 | --- a/debian/tests/pkg-list |
25 | +++ b/debian/tests/pkg-list |
26 | @@ -1,9 +1,13 @@ |
27 | #!/bin/bash |
28 | |
29 | +echo "=== Enable focal proposed channel ===" |
30 | APTDIR=$(setup-apt-dir.sh -c focal -m http://uk.archive.ubuntu.com/ubuntu -p | tail -n1) |
31 | |
32 | echo "=== ubuntu-desktop --recommends ===" |
33 | pkg-list --apt-dir "$APTDIR" ubuntu-desktop --recommends | tee ubuntu-desktop.list |
34 | +if ! pkg-list --apt-dir "$APTDIR" ubuntu-desktop --recommends --fail-unavailable; then |
35 | + echo "It is usual to see some Debian package still unavailable in proposed channel." |
36 | +fi |
37 | |
38 | echo "=== dkms ===" |
39 | pkg-list --apt-dir "$APTDIR" dkms --exclude ubuntu-desktop.list | tee dkms.list |
40 | diff --git a/oem-meta-packages b/oem-meta-packages |
41 | new file mode 100755 |
42 | index 0000000..2deb366 |
43 | --- /dev/null |
44 | +++ b/oem-meta-packages |
45 | @@ -0,0 +1,151 @@ |
46 | +#!/usr/bin/env python3 |
47 | +# -*- coding: utf-8 -*- |
48 | +# Copyright (C) 2020 Canonical Ltd. |
49 | +# Author: Shih-Yuan Lee (FourDollars) <sylee@canonical.com> |
50 | +# |
51 | +# This program is free software; you can redistribute it and/or modify |
52 | +# it under the terms of the GNU General Public License as published by |
53 | +# the Free Software Foundation; either version 3 of the License, or |
54 | +# (at your option) any later version. |
55 | +# |
56 | +# This program is distributed in the hope that it will be useful, |
57 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
58 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
59 | +# GNU General Public License for more details. |
60 | +# |
61 | +# You should have received a copy of the GNU General Public License |
62 | +# along with this program; if not, write to the Free Software |
63 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
64 | + |
65 | +import argparse |
66 | +import difflib |
67 | +import lazr |
68 | +import os |
69 | +import types |
70 | + |
71 | +from apt import apt_pkg |
72 | +from logging import info, warning, error, debug # , critical |
73 | +from oem_scripts.LaunchpadLogin import LaunchpadLogin |
74 | +from oem_scripts.logging import setup_logging |
75 | + |
76 | +parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, |
77 | + epilog=""" |
78 | +Make all bugs of all oem meta packages be subscribed by oem-solutions-engineers. |
79 | + (search current apt source for package lists) |
80 | + |
81 | +Check "To all bugs in oem-qemu-meta in Ubuntu:" on https://launchpad.net/ubuntu/+source/oem-qemu-meta/+subscribe for example. |
82 | + |
83 | +examples: |
84 | + oem-meta-packages subscribe""") |
85 | + |
86 | +parser.add_argument("-d", "--debug", |
87 | + help="print debug messages", action="store_true") |
88 | +parser.add_argument("-q", "--quiet", |
89 | + help="Don't print info messages", action="store_true") |
90 | +parser.add_argument("-v", "--verbose", action="store_true", |
91 | + help="print verbose messages") |
92 | +parser.add_argument("--apt-dir", |
93 | + type=str, |
94 | + help="specify the dir for apt") |
95 | + |
96 | +subparsers = parser.add_subparsers(dest="subcommand") |
97 | + |
98 | +subscribe = subparsers.add_parser('subscribe', help='[-h] [--yes]') |
99 | +subscribe.add_argument("--yes", |
100 | + help="Say yes for all prompts.", action="store_true") |
101 | + |
102 | +unsubscribe = subparsers.add_parser('unsubscribe', help='[-h] [--yes] pkgName') |
103 | +unsubscribe.add_argument("pkgName", type=str, |
104 | + help="Specify the package name to unsubscribe.") |
105 | +unsubscribe.add_argument("--yes", |
106 | + help="Say yes for all prompts.", action="store_true") |
107 | + |
108 | +args = parser.parse_args() |
109 | + |
110 | +setup_logging(debug=args.debug, quiet=args.quiet) |
111 | + |
112 | +if args.subcommand: |
113 | + login = LaunchpadLogin() |
114 | + lp = login.lp |
115 | + |
116 | +if args.apt_dir: |
117 | + apt_pkg.init_config() |
118 | + if args.debug: |
119 | + old = apt_pkg.config.dump() |
120 | + apt_pkg.config.set("Dir", args.apt_dir) |
121 | + apt_pkg.config.set("Dir::State::status", os.path.join(args.apt_dir, "var/lib/dpkg/status")) |
122 | + if args.debug: |
123 | + new = apt_pkg.config.dump() |
124 | + d = difflib.Differ() |
125 | + diff = d.compare(old.split('\n'), new.split('\n')) |
126 | + for line in diff: |
127 | + debug(line.strip()) |
128 | + apt_pkg.init_system() |
129 | + |
130 | + |
131 | +def yes_or_ask(yes: bool, message: str) -> bool: |
132 | + if yes: |
133 | + print(f"> \033[1;34m{message}\033[1;0m (y/n) y") |
134 | + return True |
135 | + while True: |
136 | + res = input(f"> \033[1;34m{message}\033[1;0m (y/n) ").lower() |
137 | + if res not in {"y", "n"}: |
138 | + continue |
139 | + if res == 'y': |
140 | + return True |
141 | + else: |
142 | + return False |
143 | + |
144 | + |
145 | +def _debug_obj(pkg) -> None: |
146 | + |
147 | + if not args.debug: |
148 | + return |
149 | + |
150 | + debug(dir(pkg)) |
151 | + |
152 | + for attr in dir(pkg): |
153 | + if not attr.startswith('__'): |
154 | + if not isinstance(pkg.__getattribute__(attr), types.BuiltinFunctionType): |
155 | + debug(f"{attr}: {pkg.__getattribute__(attr)}") |
156 | + |
157 | + |
158 | +cache = apt_pkg.Cache(progress=None) |
159 | + |
160 | +if args.subcommand == 'subscribe': |
161 | + for pkg in cache.packages: |
162 | + name = pkg.name |
163 | + if not name.startswith('oem-') or not name.endswith('-meta'): |
164 | + continue |
165 | + info(f"Checking the subscriptions for {name}...") |
166 | + source = lp.distributions['ubuntu'].getSourcePackage(name=name) |
167 | + if 'oem-solutions-engineers' in map(lambda x: x.subscriber.name, source.getSubscriptions()): |
168 | + info(f"ubuntu/{name} has subscribed oem-solutions-engineers.") |
169 | + continue |
170 | + warning(f"ubuntu/{name} didn't subscribe oem-solutions-engineers yet.") |
171 | + if yes_or_ask(args.yes, f"Would you like to subscribe 'oem-solutions-engineers' for ubuntu/{name}?"): |
172 | + try: |
173 | + # When a person is subscribed to a source package, one actually subscribe all bugs for it. |
174 | + source.addBugSubscription(subscriber=lp.people['oem-solutions-engineers']) |
175 | + except lazr.restfulclient.errors.Unauthorized as e: |
176 | + error(f"{lp.me.name} does not have permission to subscribe oem-solutions-engineers.") |
177 | + if args.verbose: |
178 | + print(e) |
179 | + exit(1) |
180 | +elif args.subcommand == 'unsubscribe': |
181 | + source = lp.distributions['ubuntu'].getSourcePackage(name=args.pkgName) |
182 | + subscriptions = source.getSubscriptions() |
183 | + for subscription in subscriptions: |
184 | + if subscription.subscriber.name == 'oem-solutions-engineers': |
185 | + info(f"ubuntu/{args.pkgName} has subscribed oem-solutions-engineers.") |
186 | + if yes_or_ask(args.yes, f"Would you like to unsubscribe 'oem-solutions-engineers' for ubuntu/{args.pkgName}?"): |
187 | + try: |
188 | + source.removeBugSubscription(subscriber=lp.people['oem-solutions-engineers']) |
189 | + except lazr.restfulclient.errors.Unauthorized as e: |
190 | + error(f"{lp.me.name} does not have permission to unsubscribe oem-solutions-engineers.") |
191 | + if args.verbose: |
192 | + print(e) |
193 | + exit(1) |
194 | + exit(0) |
195 | +else: |
196 | + parser.print_help() |
197 | diff --git a/oem_scripts/LaunchpadLogin.py b/oem_scripts/LaunchpadLogin.py |
198 | index 25c314f..0583ad2 100644 |
199 | --- a/oem_scripts/LaunchpadLogin.py |
200 | +++ b/oem_scripts/LaunchpadLogin.py |
201 | @@ -67,7 +67,7 @@ class LaunchpadLogin(): |
202 | logging.info("Using anonymously login") |
203 | self.lp = Launchpad.login_anonymously(application_name, service_root) |
204 | elif ":" in launchpad_token: |
205 | - oauth_token, oauth_token_secret, oauth_consumer_key = launchpad_token.split(":") |
206 | + oauth_token, oauth_token_secret, oauth_consumer_key = launchpad_token.split(":", maxsplit=2) |
207 | self.lp = Launchpad.login(oauth_consumer_key, |
208 | oauth_token, |
209 | oauth_token_secret, |
210 | diff --git a/pkg-list b/pkg-list |
211 | index ac844db..42351d5 100755 |
212 | --- a/pkg-list |
213 | +++ b/pkg-list |
214 | @@ -25,7 +25,7 @@ import sys |
215 | import types |
216 | |
217 | from apt import apt_pkg |
218 | -from logging import debug, error, critical # info, warning |
219 | +from logging import debug, error, critical, info # , warning |
220 | from urllib.parse import urljoin |
221 | |
222 | |
223 | @@ -59,6 +59,9 @@ parser.add_argument("--suggests", |
224 | parser.add_argument("--non-installed", |
225 | action="store_true", |
226 | help="only get non-installed packages per check current running environments") |
227 | +parser.add_argument("--fail-unavailable", |
228 | + action="store_true", |
229 | + help="Return error when any package is unavailable.") |
230 | parser.add_argument("--exclude", |
231 | metavar='pkg.list', |
232 | type=argparse.FileType('r', encoding='UTF-8'), |
233 | @@ -133,9 +136,18 @@ def get_depends(pkg_name: str, depends_list: list, recommends: bool, suggests: b |
234 | |
235 | pkg = cache[pkg_name] |
236 | |
237 | + info(f"check {pkg_name}") |
238 | _debug_pkg(pkg) |
239 | |
240 | + if args.fail_unavailable and not pkg.has_versions: |
241 | + error(f"{pkg_name} is unavailable.") |
242 | + exit(1) |
243 | + |
244 | for version in pkg.version_list: |
245 | + if pkg_name in map(lambda x: x[0], depends_list): |
246 | + continue |
247 | + info(f"version {version.ver_str}") |
248 | + _debug_pkg(version) |
249 | url = None |
250 | |
251 | if not version.downloadable: |
252 | @@ -160,22 +172,21 @@ def get_depends(pkg_name: str, depends_list: list, recommends: bool, suggests: b |
253 | item = (pkg_name, version.ver_str, url, record.hashes.find("MD5Sum"), record.hashes.find("SHA1"), record.hashes.find("SHA256")) |
254 | depends_list.append(item) |
255 | |
256 | - if 'Depends' not in version.depends_list_str: |
257 | - continue |
258 | - |
259 | - for depends in version.depends_list_str['Depends']: |
260 | - (name, ver, _) = depends[0] |
261 | - get_depends(name, depends_list, recommends=recommends, suggests=suggests, non_installed=non_installed) |
262 | - |
263 | - if recommends and 'Recommends' in version.depends_list_str: |
264 | - for depends in version.depends_list_str['Recommends']: |
265 | - (name, ver, _) = depends[0] |
266 | - get_depends(name, depends_list, recommends=recommends, suggests=suggests, non_installed=non_installed) |
267 | - |
268 | - if suggests and 'Suggests' in version.depends_list_str: |
269 | - for depends in version.depends_list_str['Suggests']: |
270 | - (name, ver, _) = depends[0] |
271 | - get_depends(name, depends_list, recommends=recommends, suggests=suggests, non_installed=non_installed) |
272 | + for target in ('PreDepends', 'Depends', 'Recommends', 'Suggests'): |
273 | + if target == 'Recommends' and not recommends: |
274 | + continue |
275 | + if target == 'Suggests' and not suggests: |
276 | + continue |
277 | + if target not in version.depends_list_str: |
278 | + continue |
279 | + for depends in version.depends_list_str[target]: |
280 | + for depend in depends: |
281 | + (name, ver, _) = depend |
282 | + pkg = cache[name] |
283 | + if name in map(lambda x: x[0], depends_list): |
284 | + continue |
285 | + info(f"{pkg_name} {target} {name}") |
286 | + get_depends(name, depends_list, recommends=recommends, suggests=suggests, non_installed=non_installed) |
287 | |
288 | |
289 | if args.apt_dir: |
290 | diff --git a/setup.py b/setup.py |
291 | index c598ec5..7984690 100644 |
292 | --- a/setup.py |
293 | +++ b/setup.py |
294 | @@ -45,6 +45,7 @@ Also there is a meta package oem-dev-tools that installs all scripts''', |
295 | 'lp-bug', |
296 | 'live-build-image-chroot.sh', |
297 | 'oem-getiso', |
298 | + 'oem-meta-packages', |
299 | 'pkg-list', |
300 | 'pkg-oem-meta', |
301 | 'rename-everything.py', |
302 | diff --git a/tests/test_flake8 b/tests/test_flake8 |
303 | index 069a89d..c4b8daa 100755 |
304 | --- a/tests/test_flake8 |
305 | +++ b/tests/test_flake8 |
306 | @@ -3,4 +3,5 @@ |
307 | flake8 --ignore E501 \ |
308 | lp-bug \ |
309 | mir-bug \ |
310 | + oem-meta-packages \ |
311 | pkg-list |
312 | diff --git a/tests/test_pep8 b/tests/test_pep8 |
313 | index 22fdd7e..e09071e 100755 |
314 | --- a/tests/test_pep8 |
315 | +++ b/tests/test_pep8 |
316 | @@ -11,4 +11,5 @@ pep8 --ignore=E501 \ |
317 | lp-bug \ |
318 | mir-bug \ |
319 | oem-getiso \ |
320 | + oem-meta-packages \ |
321 | pkg-list |
I'm thinking of the possibility of a unit test for pkg-list to capture all scenario of this script like what I did in pc-sanity package [1].
So, that we have confidence that any change would not impact expected behavior and the new scenarios could also be reviewed and verified easily through unit tests.
[1] https:/ /git.launchpad. net/plainbox- provider- pc-sanity/ tree/test