mirror of
https://git.launchpad.net/ubuntu-dev-tools
synced 2026-01-03 13:33:26 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f5e9c8680 | ||
|
|
d35268b797 | ||
|
|
bf9ead2204 | ||
|
|
38988ed183 | ||
|
|
5e2f94cdb4 | ||
|
|
29914382cf | ||
|
|
addeb4f7fb | ||
|
|
ee87f312bf | ||
|
|
32530e356d | ||
|
|
38ef3c506e | ||
|
|
5fc7e15f96 | ||
|
|
f0326592bd | ||
|
|
aa439fec02 | ||
|
|
4bcfa0dd5a | ||
|
|
63b3d54264 | ||
|
|
654af1a613 | ||
|
|
524f590af2 | ||
|
|
4a2f194860 | ||
|
|
7b9aee4c0c | ||
|
|
45d317cc87 | ||
|
|
2e041ac1ff | ||
|
|
c8fe724560 | ||
|
|
768a517370 | ||
|
|
3d2ee5a1b7 | ||
|
|
1c81f0872d | ||
|
|
ef5e3d8066 | ||
|
|
816323ea5c | ||
|
|
41e7d2d714 | ||
|
|
7e82344d57 | ||
|
|
cf88f4b92f | ||
|
|
c6a4c10da2 | ||
|
|
dff0b269d2 |
@ -34,6 +34,7 @@ disable=fixme,locally-disabled,missing-docstring,useless-option-value,
|
||||
duplicate-code,
|
||||
too-many-instance-attributes,
|
||||
too-many-nested-blocks,
|
||||
too-many-positional-arguments,
|
||||
too-many-lines,
|
||||
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@ import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from typing import Any, NoReturn
|
||||
from urllib.parse import quote
|
||||
|
||||
try:
|
||||
@ -50,7 +51,7 @@ from ubuntutools.question import YesNoQuestion
|
||||
Logger = getLogger()
|
||||
|
||||
|
||||
def error(msg, *args):
|
||||
def error(msg: str, *args: Any) -> NoReturn:
|
||||
Logger.error(msg, *args)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
23
debian/changelog
vendored
23
debian/changelog
vendored
@ -1,3 +1,26 @@
|
||||
ubuntu-dev-tools (0.208) unstable; urgency=medium
|
||||
|
||||
[ Gianfranco Costamagna ]
|
||||
* ubuntu-build: consider amd64v3 as valid architecture
|
||||
|
||||
[ Sebastien Bacher ]
|
||||
* ubuntu-build: fix non batch mode errors.
|
||||
|
||||
[ Benjamin Drung ]
|
||||
* Format code with black and isort
|
||||
* ubuntutools/pullpkg.py: initialize vcscmd
|
||||
* make pylint and mypy happy
|
||||
* mark non-returning functions with typing.NoReturn
|
||||
* run-linters: add --errors-only mode and run this during package build
|
||||
* Drop Lintian overrides related to .pyc files
|
||||
* Drop obsolete Rules-Requires-Root: no
|
||||
* run mypy during package build
|
||||
* sponsor-patch: stop checking for bzr being present
|
||||
* Modernize SourcePackage._run_lintian()
|
||||
* requestsync: support pocket parameter in get_ubuntu_srcpkg (LP: #2115990)
|
||||
|
||||
-- Benjamin Drung <bdrung@debian.org> Wed, 03 Dec 2025 16:33:47 +0100
|
||||
|
||||
ubuntu-dev-tools (0.207) unstable; urgency=medium
|
||||
|
||||
* Team upload.
|
||||
|
||||
13
debian/control
vendored
13
debian/control
vendored
@ -8,16 +8,17 @@ Uploaders:
|
||||
Mattia Rizzolo <mattia@debian.org>,
|
||||
Simon Quigley <tsimonq2@debian.org>,
|
||||
Build-Depends:
|
||||
black <!nocheck>,
|
||||
dctrl-tools,
|
||||
debhelper-compat (= 13),
|
||||
devscripts (>= 2.11.0~),
|
||||
dh-make,
|
||||
dh-python,
|
||||
black <!nocheck>,
|
||||
dctrl-tools,
|
||||
devscripts (>= 2.11.0~),
|
||||
distro-info (>= 0.2~),
|
||||
flake8,
|
||||
isort <!nocheck>,
|
||||
lsb-release,
|
||||
mypy <!nocheck>,
|
||||
pylint <!nocheck>,
|
||||
python3-all,
|
||||
python3-apt,
|
||||
@ -30,9 +31,9 @@ Build-Depends:
|
||||
python3-pytest,
|
||||
python3-requests <!nocheck>,
|
||||
python3-setuptools,
|
||||
python3-typeshed <!nocheck>,
|
||||
python3-yaml <!nocheck>,
|
||||
Standards-Version: 4.7.2
|
||||
Rules-Requires-Root: no
|
||||
Vcs-Git: https://git.launchpad.net/ubuntu-dev-tools
|
||||
Vcs-Browser: https://git.launchpad.net/ubuntu-dev-tools
|
||||
Homepage: https://launchpad.net/ubuntu-dev-tools
|
||||
@ -40,12 +41,12 @@ Homepage: https://launchpad.net/ubuntu-dev-tools
|
||||
Package: ubuntu-dev-tools
|
||||
Architecture: all
|
||||
Depends:
|
||||
dpkg-dev,
|
||||
binutils,
|
||||
dctrl-tools,
|
||||
devscripts (>= 2.11.0~),
|
||||
diffstat,
|
||||
distro-info (>= 0.2~),
|
||||
dpkg-dev,
|
||||
dput,
|
||||
lsb-release,
|
||||
python3,
|
||||
@ -72,10 +73,10 @@ Recommends:
|
||||
genisoimage,
|
||||
lintian,
|
||||
patch,
|
||||
sbuild | pbuilder | cowbuilder,
|
||||
python3-dns,
|
||||
quilt,
|
||||
reportbug (>= 3.39ubuntu1),
|
||||
sbuild | pbuilder | cowbuilder,
|
||||
ubuntu-keyring | ubuntu-archive-keyring,
|
||||
Suggests:
|
||||
bzr | brz,
|
||||
|
||||
3
debian/rules
vendored
3
debian/rules
vendored
@ -3,10 +3,11 @@
|
||||
override_dh_auto_clean:
|
||||
dh_auto_clean
|
||||
rm -f .coverage
|
||||
rm -rf .tox
|
||||
rm -rf .mypy_cache .tox
|
||||
|
||||
override_dh_auto_test:
|
||||
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
|
||||
./run-linters --errors-only
|
||||
python3 -m pytest -v ubuntutools
|
||||
endif
|
||||
|
||||
|
||||
3
debian/source/lintian-overrides
vendored
3
debian/source/lintian-overrides
vendored
@ -1,3 +0,0 @@
|
||||
# pyc files are machine-generated; they're expected to have long lines and have unstated copyright
|
||||
source: file-without-copyright-information *.pyc [debian/copyright]
|
||||
source: very-long-line-length-in-source-file * > 512 [*.pyc:*]
|
||||
3
debian/tests/control
vendored
3
debian/tests/control
vendored
@ -4,4 +4,5 @@ Depends:
|
||||
python3-pytest,
|
||||
python3-setuptools,
|
||||
@,
|
||||
Restrictions: allow-stderr
|
||||
Restrictions:
|
||||
allow-stderr,
|
||||
|
||||
@ -43,7 +43,7 @@ operations.
|
||||
\fB\-a\fR ARCHITECTURE, \fB\-\-arch\fR=\fIARCHITECTURE\fR
|
||||
Rebuild or rescore a specific architecture. Valid
|
||||
architectures are:
|
||||
armhf, arm64, amd64, i386, powerpc, ppc64el, riscv64, s390x.
|
||||
armhf, arm64, amd64, amd64v3, i386, powerpc, ppc64el, riscv64, s390x.
|
||||
.TP
|
||||
Batch processing:
|
||||
.IP
|
||||
@ -66,7 +66,7 @@ Rescore builds to <priority>.
|
||||
\fB\-\-arch\fR=\fIARCHITECTURE\fR
|
||||
Affect only 'architecture' (can be used several
|
||||
times). Valid architectures are:
|
||||
arm64, amd64, i386, powerpc, ppc64el, riscv64, s390x.
|
||||
armhf, arm64, amd64, amd64v3, i386, powerpc, ppc64el, riscv64, s390x.
|
||||
.IP
|
||||
\fB\-A=\fIARCHIVE\fR
|
||||
Act on the named archive (ppa) instead of on the main Ubuntu archive.
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from typing import Any, NoReturn
|
||||
|
||||
from launchpadlib.errors import HTTPError
|
||||
from launchpadlib.launchpad import Launchpad
|
||||
@ -33,7 +34,7 @@ from ubuntutools.config import UDTConfig
|
||||
Logger = getLogger()
|
||||
|
||||
|
||||
def error_out(msg, *args):
|
||||
def error_out(msg: str, *args: Any) -> NoReturn:
|
||||
Logger.error(msg, *args)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
# pylint: enable=invalid-name
|
||||
|
||||
import sys
|
||||
from typing import NoReturn
|
||||
|
||||
from debian.changelog import Changelog
|
||||
|
||||
@ -30,7 +31,7 @@ from ubuntutools import getLogger
|
||||
Logger = getLogger()
|
||||
|
||||
|
||||
def usage(exit_code=1):
|
||||
def usage(exit_code: int = 1) -> NoReturn:
|
||||
Logger.info(
|
||||
"""Usage: merge-changelog <left changelog> <right changelog>
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
from typing import NoReturn
|
||||
|
||||
import debian.deb822
|
||||
from distro_info import DebianDistroInfo, DistroDataOutdated, UbuntuDistroInfo
|
||||
@ -411,7 +412,7 @@ class PbuilderDist:
|
||||
] + arguments
|
||||
|
||||
|
||||
def show_help(exit_code=0):
|
||||
def show_help(exit_code: int = 0) -> NoReturn:
|
||||
"""help() -> None
|
||||
|
||||
Print a help message for pbuilder-dist, and exit with the given code.
|
||||
|
||||
11
pm-helper
11
pm-helper
@ -22,6 +22,7 @@ from argparse import ArgumentParser
|
||||
import yaml
|
||||
from launchpadlib.launchpad import Launchpad
|
||||
|
||||
from ubuntutools.question import YesNoQuestion
|
||||
from ubuntutools.utils import get_url
|
||||
|
||||
# proposed-migration is only concerned with the devel series; unlike other
|
||||
@ -56,10 +57,8 @@ def claim_excuses_bug(launchpad, bug, package):
|
||||
if our_task.assignee:
|
||||
print(f"Currently assigned to {our_task.assignee.name}")
|
||||
|
||||
print("""Do you want to claim this bug? [yN] """, end="")
|
||||
sys.stdout.flush()
|
||||
response = sys.stdin.readline()
|
||||
if response.strip().lower().startswith("y"):
|
||||
answer = YesNoQuestion().ask("Do you want to claim this bug?", "no")
|
||||
if answer == "yes":
|
||||
our_task.assignee = launchpad.me
|
||||
our_task.lp_save()
|
||||
return True
|
||||
@ -131,7 +130,9 @@ def main():
|
||||
if not proposed_version:
|
||||
print(f"Package {args.package} not found in -proposed.")
|
||||
sys.exit(1)
|
||||
create_excuses_bug(args.launchpad, args.package, proposed_version)
|
||||
answer = YesNoQuestion().ask("Do you want to create a bug?", "no")
|
||||
if answer == "yes":
|
||||
create_excuses_bug(args.launchpad, args.package, proposed_version)
|
||||
except ValueError as e:
|
||||
sys.stderr.write(f"{e}\n")
|
||||
else:
|
||||
|
||||
@ -4,3 +4,7 @@ line-length = 99
|
||||
[tool.isort]
|
||||
line_length = 99
|
||||
profile = "black"
|
||||
|
||||
[tool.mypy]
|
||||
disallow_incomplete_defs = true
|
||||
ignore_missing_imports = true
|
||||
|
||||
@ -46,7 +46,7 @@ Logger = getLogger()
|
||||
#
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
# Our usage options.
|
||||
usage = "%(prog)s [options] <source package> [<target release> [base version]]"
|
||||
parser = argparse.ArgumentParser(usage=usage)
|
||||
@ -153,6 +153,7 @@ def main():
|
||||
import DNS # pylint: disable=import-outside-toplevel
|
||||
|
||||
DNS.DiscoverNameServers()
|
||||
# imported earlier, pylint: disable-next=possibly-used-before-assignment
|
||||
mxlist = DNS.mxlookup(bug_mail_domain)
|
||||
firstmx = mxlist[0]
|
||||
mailserver_host = firstmx[1]
|
||||
@ -214,6 +215,7 @@ def main():
|
||||
|
||||
if not args.release:
|
||||
if lpapi:
|
||||
# imported earlier, pylint: disable-next=possibly-used-before-assignment
|
||||
args.release = Distribution("ubuntu").getDevelopmentSeries().name
|
||||
else:
|
||||
ubu_info = UbuntuDistroInfo()
|
||||
@ -377,6 +379,7 @@ def main():
|
||||
# Map status to the values expected by LP API
|
||||
mapping = {"new": "New", "confirmed": "Confirmed"}
|
||||
# Post sync request using LP API
|
||||
# imported earlier, pylint: disable-next=possibly-used-before-assignment
|
||||
post_bug(srcpkg, subscribe, mapping[status], title, report)
|
||||
else:
|
||||
email_from = ubu_email(export=False)[1]
|
||||
|
||||
47
run-linters
47
run-linters
@ -4,16 +4,45 @@ set -eu
|
||||
# Copyright 2023, Canonical Ltd.
|
||||
# SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
PYTHON_SCRIPTS=$(grep -l -r '^#! */usr/bin/python3$' .)
|
||||
PYTHON_SCRIPTS=$(find . -maxdepth 1 -type f -exec grep -l '^#! */usr/bin/python3$' {} +)
|
||||
|
||||
echo "Running black..."
|
||||
black --check --diff . $PYTHON_SCRIPTS
|
||||
run_black() {
|
||||
echo "Running black..."
|
||||
black -C --check --diff . ${PYTHON_SCRIPTS}
|
||||
}
|
||||
|
||||
echo "Running isort..."
|
||||
isort --check-only --diff .
|
||||
run_isort() {
|
||||
echo "Running isort..."
|
||||
isort --check-only --diff .
|
||||
}
|
||||
|
||||
echo "Running flake8..."
|
||||
flake8 --max-line-length=99 --ignore=E203,W503 . $PYTHON_SCRIPTS
|
||||
run_flake8() {
|
||||
echo "Running flake8..."
|
||||
flake8 --max-line-length=99 --ignore=E203,W503 . $PYTHON_SCRIPTS
|
||||
}
|
||||
|
||||
echo "Running pylint..."
|
||||
pylint $(find * -name '*.py') $PYTHON_SCRIPTS
|
||||
run_mypy() {
|
||||
echo "Running mypy..."
|
||||
mypy .
|
||||
mypy --scripts-are-modules $PYTHON_SCRIPTS
|
||||
}
|
||||
|
||||
run_pylint() {
|
||||
echo "Running pylint..."
|
||||
pylint "$@" $(find * -name '*.py') $PYTHON_SCRIPTS
|
||||
}
|
||||
|
||||
if test "${1-}" = "--errors-only"; then
|
||||
# Run only linters that can detect real errors (ignore formatting)
|
||||
run_black || true
|
||||
run_isort || true
|
||||
run_flake8 || true
|
||||
run_mypy
|
||||
run_pylint --errors-only
|
||||
else
|
||||
run_black
|
||||
run_isort
|
||||
run_flake8
|
||||
run_mypy
|
||||
run_pylint
|
||||
fi
|
||||
|
||||
34
syncpackage
34
syncpackage
@ -22,6 +22,7 @@
|
||||
|
||||
import argparse
|
||||
import fnmatch
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
@ -49,7 +50,6 @@ from ubuntutools.requestsync.mail import get_debian_srcpkg as requestsync_mail_g
|
||||
from ubuntutools.version import Version
|
||||
|
||||
Logger = getLogger()
|
||||
cached_sync_blocklist = None
|
||||
|
||||
|
||||
def remove_signature(dscname):
|
||||
@ -436,6 +436,14 @@ def copy(src_pkg, release, bugs, sponsoree=None, simulate=False, force=False, ye
|
||||
close_bugs(bugs, src_pkg.source, src_pkg.version.full_version, changes, sponsoree)
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _fetch_sync_blocklist() -> str:
|
||||
url = "https://ubuntu-archive-team.ubuntu.com/sync-blocklist.txt"
|
||||
with urllib.request.urlopen(url) as f:
|
||||
sync_blocklist = f.read().decode("utf-8")
|
||||
return sync_blocklist
|
||||
|
||||
|
||||
def is_blocklisted(query):
|
||||
"""Determine if package "query" is in the sync blocklist
|
||||
Returns tuple of (blocklisted, comments)
|
||||
@ -456,24 +464,20 @@ def is_blocklisted(query):
|
||||
if diff.status == "Blacklisted always":
|
||||
blocklisted = "ALWAYS"
|
||||
|
||||
global cached_sync_blocklist
|
||||
if not cached_sync_blocklist:
|
||||
url = "https://ubuntu-archive-team.ubuntu.com/sync-blocklist.txt"
|
||||
try:
|
||||
with urllib.request.urlopen(url) as f:
|
||||
cached_sync_blocklist = f.read().decode("utf-8")
|
||||
except:
|
||||
print("WARNING: unable to download the sync blocklist. Erring on the side of caution.")
|
||||
return ("ALWAYS", "INTERNAL ERROR: Unable to fetch sync blocklist")
|
||||
try:
|
||||
sync_blocklist = _fetch_sync_blocklist()
|
||||
except OSError:
|
||||
print("WARNING: unable to download the sync blocklist. Erring on the side of caution.")
|
||||
return ("ALWAYS", "INTERNAL ERROR: Unable to fetch sync blocklist")
|
||||
|
||||
applicable_lines = []
|
||||
for line in cached_sync_blocklist.splitlines():
|
||||
for line in sync_blocklist.splitlines():
|
||||
if not line.strip():
|
||||
applicable_lines = []
|
||||
continue
|
||||
applicable_lines.append(line)
|
||||
try:
|
||||
line = line[:line.index("#")]
|
||||
line = line[: line.index("#")]
|
||||
except ValueError:
|
||||
pass
|
||||
source = line.strip()
|
||||
@ -523,7 +527,7 @@ def parse():
|
||||
"-y",
|
||||
"--yes",
|
||||
action="store_true",
|
||||
help="Automatically sync without prompting. Use with caution and care."
|
||||
help="Automatically sync without prompting. Use with caution and care.",
|
||||
)
|
||||
parser.add_argument("-d", "--distribution", help="Debian distribution to sync from.")
|
||||
parser.add_argument("-r", "--release", help="Specify target Ubuntu release.")
|
||||
@ -776,7 +780,9 @@ def main():
|
||||
continue
|
||||
|
||||
if args.lp:
|
||||
if not copy(src_pkg, args.release, args.bugs, sponsoree, args.simulate, args.force, args.yes):
|
||||
if not copy(
|
||||
src_pkg, args.release, args.bugs, sponsoree, args.simulate, args.force, args.yes
|
||||
):
|
||||
continue
|
||||
else:
|
||||
os.environ["DEB_VENDOR"] = "Ubuntu"
|
||||
|
||||
46
ubuntu-build
46
ubuntu-build
@ -87,17 +87,13 @@ def retry_builds(pkg, archs):
|
||||
return f"Retrying builds of '{pkg.source_package_name}':\n{msg}"
|
||||
|
||||
|
||||
def main():
|
||||
def parse_args(argv: list[str], valid_archs: set[str]) -> argparse.Namespace:
|
||||
"""Parse command line arguments and return namespace."""
|
||||
# Usage.
|
||||
usage = "%(prog)s <srcpackage> <release> <operation>\n\n"
|
||||
usage += "Where operation may be one of: rescore, retry, or status.\n"
|
||||
usage += "Only Launchpad Buildd Admins may rescore package builds."
|
||||
|
||||
# Valid architectures.
|
||||
valid_archs = set(
|
||||
["armhf", "arm64", "amd64", "i386", "powerpc", "ppc64el", "riscv64", "s390x"]
|
||||
)
|
||||
|
||||
# Prepare our option parser.
|
||||
parser = argparse.ArgumentParser(usage=usage)
|
||||
|
||||
@ -148,7 +144,23 @@ def main():
|
||||
parser.add_argument("packages", metavar="package", nargs="*", help=argparse.SUPPRESS)
|
||||
|
||||
# Parse our options.
|
||||
args = parser.parse_args()
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
if not args.batch:
|
||||
# Check we have the correct number of arguments.
|
||||
if len(args.packages) < 3:
|
||||
parser.error("Incorrect number of arguments.")
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
# Valid architectures.
|
||||
valid_archs = set(
|
||||
["armhf", "arm64", "amd64", "amd64v3", "i386", "powerpc", "ppc64el", "riscv64", "s390x"]
|
||||
)
|
||||
|
||||
args = parse_args(sys.argv[1:], valid_archs)
|
||||
|
||||
launchpad = Launchpad.login_with("ubuntu-dev-tools", "production", version="devel")
|
||||
ubuntu = launchpad.distributions["ubuntu"]
|
||||
@ -167,21 +179,13 @@ def main():
|
||||
Logger.error(error)
|
||||
sys.exit(1)
|
||||
else:
|
||||
# Check we have the correct number of arguments.
|
||||
if len(args.packages) < 3:
|
||||
parser.error("Incorrect number of arguments.")
|
||||
|
||||
try:
|
||||
package = str(args.packages[0]).lower()
|
||||
release = str(args.packages[1]).lower()
|
||||
operation = str(args.packages[2]).lower()
|
||||
except IndexError:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
package = str(args.packages[0]).lower()
|
||||
release = str(args.packages[1]).lower()
|
||||
operation = str(args.packages[2]).lower()
|
||||
|
||||
archive = launchpad.archives.getByReference(reference=args.archive)
|
||||
try:
|
||||
distroseries = ubuntu.getSeries(name_or_version=release)
|
||||
distroseries = ubuntu.getSeries(name_or_version=release.split("-")[0])
|
||||
except lazr.restfulclient.errors.NotFound as error:
|
||||
Logger.error(error)
|
||||
sys.exit(1)
|
||||
@ -234,11 +238,11 @@ def main():
|
||||
# are in place.
|
||||
if operation == "retry":
|
||||
necessary_privs = archive.checkUpload(
|
||||
component=sources.getComponent(),
|
||||
component=component,
|
||||
distroseries=distroseries,
|
||||
person=launchpad.me,
|
||||
pocket=pocket,
|
||||
sourcepackagename=sources.getPackageName(),
|
||||
sourcepackagename=sources.source_package_name,
|
||||
)
|
||||
if not necessary_privs:
|
||||
Logger.error(
|
||||
|
||||
@ -65,7 +65,7 @@ def main():
|
||||
err = True
|
||||
continue
|
||||
|
||||
Logger.info(prefix + version)
|
||||
Logger.info("%s%s", prefix, version)
|
||||
|
||||
if err:
|
||||
sys.exit(1)
|
||||
|
||||
@ -340,11 +340,9 @@ class SourcePackage(ABC):
|
||||
def _archive_servers(self):
|
||||
"Generator for mirror and master servers"
|
||||
# Always provide the mirrors first
|
||||
for server in self.mirrors:
|
||||
yield server
|
||||
yield from self.mirrors
|
||||
# Don't repeat servers that are in both mirrors and masters
|
||||
for server in set(self.masters) - set(self.mirrors):
|
||||
yield server
|
||||
yield from set(self.masters) - set(self.mirrors)
|
||||
|
||||
def _source_urls(self, name):
|
||||
"Generator of sources for name"
|
||||
@ -635,8 +633,7 @@ class DebianSourcePackage(SourcePackage):
|
||||
|
||||
def _source_urls(self, name):
|
||||
"Generator of sources for name"
|
||||
for url in super()._source_urls(name):
|
||||
yield url
|
||||
yield from super()._source_urls(name)
|
||||
if name in self.snapshot_files:
|
||||
yield self.snapshot_files[name]
|
||||
|
||||
@ -734,6 +731,7 @@ class PersonalPackageArchiveSourcePackage(UbuntuSourcePackage):
|
||||
|
||||
class UbuntuCloudArchiveSourcePackage(PersonalPackageArchiveSourcePackage):
|
||||
"Download / unpack an Ubuntu Cloud Archive source package"
|
||||
|
||||
TEAM = "ubuntu-cloud-archive"
|
||||
PROJECT = "cloud-archive"
|
||||
VALID_POCKETS = ["updates", "proposed", "staging"]
|
||||
@ -930,8 +928,8 @@ class UbuntuCloudArchiveSourcePackage(PersonalPackageArchiveSourcePackage):
|
||||
|
||||
|
||||
class _WebJSON:
|
||||
def getHostUrl(self): # pylint: disable=no-self-use
|
||||
raise Exception("Not implemented")
|
||||
def getHostUrl(self):
|
||||
raise NotImplementedError(f"{self.__class__.__name__}.getHostUrl() is not implemented")
|
||||
|
||||
def load(self, path=""):
|
||||
reader = codecs.getreader("utf-8")
|
||||
|
||||
@ -50,7 +50,7 @@ class UDTConfig:
|
||||
"KEYID": None,
|
||||
}
|
||||
# Populated from the configuration files:
|
||||
config = {}
|
||||
config: dict[str, str] = {}
|
||||
|
||||
def __init__(self, no_conf=False, prefix=None):
|
||||
self.no_conf = no_conf
|
||||
@ -61,7 +61,7 @@ class UDTConfig:
|
||||
self.config = self.parse_devscripts_config()
|
||||
|
||||
@staticmethod
|
||||
def parse_devscripts_config():
|
||||
def parse_devscripts_config() -> dict[str, str]:
|
||||
"""Read the devscripts configuration files, and return the values as a
|
||||
dictionary
|
||||
"""
|
||||
|
||||
@ -26,6 +26,7 @@ import logging
|
||||
import os
|
||||
import re
|
||||
from copy import copy
|
||||
from typing import Any
|
||||
from urllib.error import URLError
|
||||
from urllib.parse import urlparse
|
||||
|
||||
@ -139,7 +140,7 @@ class BaseWrapper(metaclass=MetaWrapper):
|
||||
A base class from which other wrapper classes are derived.
|
||||
"""
|
||||
|
||||
resource_type: str = None # it's a base class after all
|
||||
resource_type: str | tuple[str, str] = "" # it's a base class after all
|
||||
|
||||
def __new__(cls, data):
|
||||
if isinstance(data, str) and data.startswith(str(Launchpad._root_uri)):
|
||||
@ -667,20 +668,19 @@ class Archive(BaseWrapper):
|
||||
rversion = getattr(record, "binary_package_version", None)
|
||||
else:
|
||||
rversion = getattr(record, "source_package_version", None)
|
||||
skipmsg = f"Skipping version {rversion}: "
|
||||
|
||||
if record.pocket not in pockets:
|
||||
err_msg = f"pocket {record.pocket} not in ({','.join(pockets)})"
|
||||
Logger.debug(skipmsg + err_msg)
|
||||
Logger.debug("Skipping version %s: %s", rversion, err_msg)
|
||||
continue
|
||||
if record.status not in statuses:
|
||||
err_msg = f"status {record.status} not in ({','.join(statuses)})"
|
||||
Logger.debug(skipmsg + err_msg)
|
||||
Logger.debug("Skipping version %s: %s", rversion, err_msg)
|
||||
continue
|
||||
release = wrapper(record)
|
||||
if binary and archtag and archtag != release.arch:
|
||||
err_msg = f"arch {release.arch} does not match requested arch {archtag}"
|
||||
Logger.debug(skipmsg + err_msg)
|
||||
Logger.debug("Skipping version %s: %s", rversion, err_msg)
|
||||
continue
|
||||
# results are ordered so first is latest
|
||||
cache[index] = release
|
||||
@ -1502,7 +1502,7 @@ class Packageset(BaseWrapper): # pylint: disable=too-few-public-methods
|
||||
|
||||
resource_type = "packageset"
|
||||
_lp_packagesets = None
|
||||
_source_sets = {}
|
||||
_source_sets: dict[tuple[str, str | None, bool], Any] = {}
|
||||
|
||||
@classmethod
|
||||
def setsIncludingSource(cls, sourcepackagename, distroseries=None, direct_inclusion=False):
|
||||
|
||||
@ -471,6 +471,7 @@ class PullPkg:
|
||||
uri,
|
||||
)
|
||||
|
||||
vcscmd = ""
|
||||
if vcs == "Bazaar":
|
||||
vcscmd = " $ bzr branch " + uri
|
||||
elif vcs == "Git":
|
||||
|
||||
@ -62,8 +62,17 @@ def get_debian_srcpkg(name, release):
|
||||
return DebianSourcePackage(package=name, series=release).lp_spph
|
||||
|
||||
|
||||
def get_ubuntu_srcpkg(name, release):
|
||||
return UbuntuSourcePackage(package=name, series=release).lp_spph
|
||||
def get_ubuntu_srcpkg(name, release, pocket="Proposed"):
|
||||
srcpkg = UbuntuSourcePackage(package=name, series=release, pocket=pocket)
|
||||
try:
|
||||
return srcpkg.lp_spph
|
||||
except PackageNotFoundException:
|
||||
if pocket != "Release":
|
||||
parent_pocket = "Release"
|
||||
if pocket == "Updates":
|
||||
parent_pocket = "Proposed"
|
||||
return get_ubuntu_srcpkg(name, release, parent_pocket)
|
||||
raise
|
||||
|
||||
|
||||
def need_sponsorship(name, component, release):
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import sys
|
||||
from typing import NoReturn
|
||||
|
||||
from ubuntutools.question import Question, YesNoQuestion
|
||||
|
||||
@ -42,7 +43,7 @@ def ask_for_manual_fixing():
|
||||
user_abort()
|
||||
|
||||
|
||||
def user_abort():
|
||||
def user_abort() -> NoReturn:
|
||||
"""Print abort and quit the program."""
|
||||
|
||||
print("User abort.")
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
@ -407,22 +408,16 @@ class SourcePackage:
|
||||
|
||||
return True
|
||||
|
||||
def _run_lintian(self):
|
||||
def _run_lintian(self) -> str:
|
||||
"""Runs lintian on either the source or binary changes file.
|
||||
|
||||
Returns the filename of the created lintian output file.
|
||||
"""
|
||||
|
||||
# Determine whether to use the source or binary build for lintian
|
||||
package_and_version = f"{self._package}_{strip_epoch(self._version)}"
|
||||
if self._build_log:
|
||||
build_changes = (
|
||||
self._package
|
||||
+ "_"
|
||||
+ strip_epoch(self._version)
|
||||
+ "_"
|
||||
+ self._builder.get_architecture()
|
||||
+ ".changes"
|
||||
)
|
||||
build_changes = f"{package_and_version}_{self._builder.get_architecture()}.changes"
|
||||
changes_for_lintian = os.path.join(self._buildresult, build_changes)
|
||||
else:
|
||||
changes_for_lintian = self._changes_file
|
||||
@ -430,18 +425,12 @@ class SourcePackage:
|
||||
# Check lintian
|
||||
assert os.path.isfile(changes_for_lintian), f"{changes_for_lintian} does not exist."
|
||||
cmd = ["lintian", "-IE", "--pedantic", "-q", "--profile", "ubuntu", changes_for_lintian]
|
||||
lintian_filename = os.path.join(
|
||||
self._workdir, self._package + "_" + strip_epoch(self._version) + ".lintian"
|
||||
)
|
||||
Logger.debug("%s > %s", " ".join(cmd), lintian_filename)
|
||||
report = subprocess.check_output(cmd, encoding="utf-8")
|
||||
lintian_file = pathlib.Path(self._workdir) / f"{package_and_version}.lintian"
|
||||
Logger.debug("%s > %s", " ".join(cmd), lintian_file)
|
||||
with lintian_file.open("wb") as outfile:
|
||||
subprocess.run(cmd, stdout=outfile, check=True)
|
||||
|
||||
# write lintian report file
|
||||
lintian_file = open(lintian_filename, "w", encoding="utf-8")
|
||||
lintian_file.writelines(report)
|
||||
lintian_file.close()
|
||||
|
||||
return lintian_filename
|
||||
return str(lintian_file)
|
||||
|
||||
def sync(self, upload, series, bug_number, requester):
|
||||
"""Does a sync of the source package."""
|
||||
|
||||
@ -46,11 +46,9 @@ def is_command_available(command, check_sbin=False):
|
||||
def check_dependencies():
|
||||
"Do we have all the commands we need for full functionality?"
|
||||
missing = []
|
||||
for cmd in ("patch", "bzr", "quilt", "dput", "lintian"):
|
||||
for cmd in ("patch", "quilt", "dput", "lintian"):
|
||||
if not is_command_available(cmd):
|
||||
missing.append(cmd)
|
||||
if not is_command_available("bzr-buildpackage"):
|
||||
missing.append("bzr-builddeb")
|
||||
if not any(
|
||||
is_command_available(cmd, check_sbin=True) for cmd in ("pbuilder", "sbuild", "cowbuilder")
|
||||
):
|
||||
@ -212,14 +210,14 @@ def get_open_ubuntu_bug_task(launchpad, bug, branch=None):
|
||||
sys.exit(1)
|
||||
elif len(ubuntu_tasks) == 1:
|
||||
task = ubuntu_tasks[0]
|
||||
if len(ubuntu_tasks) > 1 and branch and branch[1] == "ubuntu":
|
||||
elif branch and branch[1] == "ubuntu":
|
||||
tasks = [t for t in ubuntu_tasks if t.get_series() == branch[2] and t.package == branch[3]]
|
||||
if len(tasks) > 1:
|
||||
# A bug targeted to the development series?
|
||||
tasks = [t for t in tasks if t.series is not None]
|
||||
assert len(tasks) == 1
|
||||
task = tasks[0]
|
||||
elif len(ubuntu_tasks) > 1:
|
||||
else:
|
||||
task_list = [t.get_short_info() for t in ubuntu_tasks]
|
||||
Logger.debug(
|
||||
"%i Ubuntu tasks exist for bug #%i.\n%s",
|
||||
|
||||
@ -60,7 +60,7 @@ class ExamplePackage:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
self._create(Path(tmpdir))
|
||||
|
||||
def _create(self, directory: Path):
|
||||
def _create(self, directory: Path) -> None:
|
||||
pkgdir = directory / self.dirname
|
||||
pkgdir.mkdir()
|
||||
(pkgdir / self.content_filename).write_text(self.content_text)
|
||||
|
||||
@ -28,6 +28,7 @@ class BinaryTests(unittest.TestCase):
|
||||
def test_keyring_installed(self):
|
||||
"""Smoke test for required lp api dependencies"""
|
||||
try:
|
||||
# pylint: disable-next=import-outside-toplevel,unused-import
|
||||
import keyring # noqa: F401
|
||||
except ModuleNotFoundError:
|
||||
raise ModuleNotFoundError("package python3-keyring is not installed")
|
||||
except ModuleNotFoundError as error:
|
||||
raise ModuleNotFoundError("package python3-keyring is not installed") from error
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
""" Tests for running_autopkgtests
|
||||
"""Tests for running_autopkgtests
|
||||
Tests using cached data from autopkgtest servers.
|
||||
|
||||
These tests only ensure code changes don't change parsing behavior
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user