diff options
author | Helmut Grohne <helmut@subdivi.de> | 2021-07-06 13:51:41 +0200 |
---|---|---|
committer | Helmut Grohne <helmut@subdivi.de> | 2021-07-06 13:51:41 +0200 |
commit | 58e77f47adf737c27e87e185adfe437dfebed6df (patch) | |
tree | 74ba8c2856e15dd210232e4cc4c4c2876810c80d /mdbp | |
parent | 2e9f3bddc0c9c7fd3411a2e41f49d048c93ba52e (diff) | |
download | mdbp-58e77f47adf737c27e87e185adfe437dfebed6df.tar.gz |
mmdebstrap and sbuild shall agree on what build_path means
While mmdebstrap would extract the package precisely to the build_path,
sbuild would create a subdirectory <source>-<upstream_version> inside
the build_path. Changing sbuild to do the mmdebstrap behaviour looks
next to impossible, so this commit changes mmdebstrap to behave like
sbuild.
pbuilder also allows changing the build_path in principle. The
documented BUILDDIR variable works quite similar to the sbuild option
--build-path. pbuilder also allows changing the sub directory using the
undocumented BUILDSUBDIR variable. That's another reason to do it like
sbuild.
Diffstat (limited to 'mdbp')
-rw-r--r-- | mdbp/build_schema.json | 2 | ||||
-rw-r--r-- | mdbp/common.py | 27 | ||||
-rw-r--r-- | mdbp/mmdebstrap.py | 55 |
3 files changed, 48 insertions, 36 deletions
diff --git a/mdbp/build_schema.json b/mdbp/build_schema.json index 0f7e9bc..e083654 100644 --- a/mdbp/build_schema.json +++ b/mdbp/build_schema.json @@ -112,7 +112,7 @@ }, "build_path": { "type": "string", - "description": "the path inside the chroot to peform the build" + "description": "Specify the path inside the chroot to peform the build. This excludes the final directory dpkg-source extracts to." }, "lintian": { "type": "object", diff --git a/mdbp/common.py b/mdbp/common.py index 719a8b6..5c67f58 100644 --- a/mdbp/common.py +++ b/mdbp/common.py @@ -118,6 +118,11 @@ def download(uri: str, checksums: typing.Dict[str, str], dest.unlink() raise +def parse_dsc(dscpath: pathlib.Path) -> debian.deb822.Dsc: + """Parse a dsc file.""" + with dscpath.open("r") as dscf: + return debian.deb822.Dsc(dscf) + def download_dsc(buildinput: JsonObject, destdir: pathlib.Path) -> pathlib.Path: """Download the .input.source_package_url including referenced components @@ -130,12 +135,11 @@ def download_dsc(buildinput: JsonObject, assert isinstance(dscpath, pathlib.Path) download(dscuri, buildinput.get("checksums", {}), dscpath) files: typing.Dict[str, typing.Dict[str, str]] = {} - with dscpath.open("r") as dscf: - for key, value in debian.deb822.Dsc(dscf).items(): - if key.lower().startswith("checksums-"): - for entry in value: - algo = key[10:].lower() - files.setdefault(entry["name"], dict())[algo] = entry[algo] + for key, value in parse_dsc(dscpath).items(): + if key.lower().startswith("checksums-"): + for entry in value: + algo = key[10:].lower() + files.setdefault(entry["name"], dict())[algo] = entry[algo] for name, checksums in files.items(): download(urllib.parse.urljoin(dscuri, name), checksums, destdir / name) return dscpath @@ -155,11 +159,12 @@ def get_dsc(build: JsonObject) -> typing.Iterator[pathlib.Path]: else: yield pathlib.Path(dscpath) -def get_dsc_files(dscpath: pathlib.Path) -> typing.List[pathlib.Path]: - """Get the component names referenced by the .dsc file.""" - with dscpath.open("r") as dscf: - dsc = debian.deb822.Dsc(dscf) - return [dscpath.parent / item["name"] for item in dsc["Files"]] +def get_dsc_files(dscpath: pathlib.Path, + dscobj: typing.Optional[debian.deb822.Dsc] = None) -> \ + typing.List[pathlib.Path]: + """Get the component names referenced by the .dsc.""" + return [dscpath.parent / item["name"] + for item in (dscobj or parse_dsc(dscpath))["Files"]] def make_option(optname: str, value: typing.Optional[str]) -> typing.List[str]: """Construct a valued option if a value is given.""" diff --git a/mdbp/mmdebstrap.py b/mdbp/mmdebstrap.py index c864bce..9858b65 100644 --- a/mdbp/mmdebstrap.py +++ b/mdbp/mmdebstrap.py @@ -16,8 +16,10 @@ import subprocess import sys import typing +import debian.debian_support + from .common import buildjson, clean_dir, compute_env, download_dsc, \ - get_dsc_files, json_load, profile_option + get_dsc_files, json_load, parse_dsc, profile_option libc = ctypes.CDLL(ctypes.util.find_library("c")) def unshare_network() -> None: @@ -59,19 +61,25 @@ def native_architecture() -> str: return subprocess.check_output(["dpkg", "--print-architecture"], encoding="ascii").strip() +def build_subdir(dsc: debian.deb822.Dsc) -> str: + """Compute the subdirectory that dpkg-source normally extracts to.""" + ver = debian.debian_support.BaseVersion(dsc["Version"]).upstream_version + assert ver is not None # please mypy + return "%s-%s" % (dsc["Source"], ver) + def hook_main(buildjsonfilename: str, chrootname: str) -> None: """The entry point for the --hook-helper invocation run from mmdebstrap.""" build = json_load(pathlib.Path(buildjsonfilename).open("r")) chroot = pathlib.Path(chrootname) - buildpath = pathlib.PurePath(build.get("build_path", "/build/build")) - fullbuildpath = chroot / buildpath.relative_to("/") + builddir = pathlib.PurePath(build.get("build_path", "/build")) + fullbuilddir = chroot / builddir.relative_to("/") if "source_package_path" in build["input"]: - dscpath = fullbuildpath.parent / \ + dscpath = fullbuilddir / \ pathlib.PurePath(build["input"]["source_package_path"]).name elif "source_package_url" in build["input"]: - dscpath = download_dsc(build["input"], fullbuildpath.parent) + dscpath = download_dsc(build["input"], fullbuilddir) priv_drop(["chown", "-R", "build:build", "."], - chroot=chroot, chdir=buildpath.parent) + chroot=chroot, chdir=builddir) apt_get = ["apt-get", "--yes", "-oAPT::Keep-Downloaded-Packages=false"] if "sourcename" in build["input"]: sourcename = build["input"]["sourcename"] @@ -79,13 +87,13 @@ def hook_main(buildjsonfilename: str, chrootname: str) -> None: sourcename += "=" + build["input"]["version"] priv_drop([*apt_get, "--only-source", "--download-only", "source", sourcename], - chroot=chroot, chdir=buildpath.parent, setuid="build") - [dscpath] = fullbuildpath.parent.glob(build["input"]["sourcename"] + - "_*.dsc") - priv_drop(["dpkg-source", "--no-check", "--extract", dscpath.name, - buildpath.name], - setuid="build", chroot=chroot, chdir=buildpath.parent) - for path in [*get_dsc_files(dscpath), dscpath]: + chroot=chroot, chdir=builddir, setuid="build") + [dscpath] = fullbuilddir.glob(build["input"]["sourcename"] + "_*.dsc") + dsc = parse_dsc(dscpath) + subdir = build_subdir(dsc) + priv_drop(["dpkg-source", "--no-check", "--extract", dscpath.name, subdir], + setuid="build", chroot=chroot, chdir=builddir) + for path in [*get_dsc_files(dscpath, dsc), dscpath]: path.unlink() hostarch = build.get("host_architecture") or \ build.get("build_architecture") or \ @@ -96,7 +104,7 @@ def hook_main(buildjsonfilename: str, chrootname: str) -> None: *profile_option(build, "--build-profiles"), "./"] try: - priv_drop(cmd, chroot=chroot, chdir=buildpath) + priv_drop(cmd, chroot=chroot, chdir=builddir / subdir) except subprocess.CalledProcessError: if build.get("bd-uninstallable-explainer") != "apt" or \ not build["output"].get("log", True): @@ -105,20 +113,20 @@ def hook_main(buildjsonfilename: str, chrootname: str) -> None: '-oDebug::pkgDepCache::Marker=1', '-oDebug::pkgDepCache::AutoInstall=1', '-oDebug::BuildDeps=1'] - priv_drop(cmd, chroot=chroot, chdir=buildpath) + priv_drop(cmd, chroot=chroot, chdir=builddir / subdir) priv_drop(["dpkg-buildpackage", "-uc", "--host-arch=" + hostarch, "--build=" + build.get("type", "binary"), *profile_option(build, "--build-profiles=")], chroot=chroot, setuid="build", privnet=not build.get("network") in ("enable", "try-enable"), - chdir=buildpath, env=compute_env(build)) - shutil.rmtree(fullbuildpath) + chdir=builddir / subdir, env=compute_env(build)) + shutil.rmtree(fullbuilddir / subdir) if build.get("lintian", {}).get("run"): priv_drop([*apt_get, "install", "lintian"], chroot=chroot) priv_drop(["lintian", *build["lintian"].get("options", ()), "%s_%s.changes" % (dscpath.stem, hostarch)], - chroot=chroot, setuid="build", chdir=buildpath.parent) - clean_dir(fullbuildpath.parent, build["output"].get("artifacts", ["*"])) + chroot=chroot, setuid="build", chdir=builddir) + clean_dir(fullbuilddir, build["output"].get("artifacts", ["*"])) class RawStoreAction(argparse.Action): """An action that stores the raw value in addition to the type-parsed @@ -168,7 +176,7 @@ def main() -> None: "libc-dev:" + hostarch, "libstdc++-dev:" + hostarch, "fakeroot")) - buildpath = pathlib.PurePath(build.get("build_path", "/build/build")) + builddir = build.get("build_path", "/build") enablelog = build["output"].get("log", True) cmd = [ @@ -182,18 +190,17 @@ def main() -> None: '--essential-hook=echo man-db man-db/auto-update boolean false | ' \ 'chroot "$1" debconf-set-selections', '--customize-hook=chroot "$1" useradd --user-group --create-home ' - '--home-dir %s build --skel /nonexistent' % - shlex.quote(str(buildpath.parent)), + '--home-dir %s build --skel /nonexistent' % shlex.quote(builddir), *(["--customize-hook=copy-in " + shlex.join([ build["input"]["source_package_path"], *map(str, get_dsc_files(pathlib.Path( build["input"]["source_package_path"]))), - str(buildpath.parent)])] + builddir])] if "source_package_path" in build["input"] else ()), '--customize-hook=mdbp-mmdebstrap --hook-helper %s "$1"' % shlex.quote(args.raw_buildjson), *(["--customize-hook=sync-out " + - shlex.join([str(buildpath.parent), build["output"]["directory"]])] + shlex.join([builddir, build["output"]["directory"]])] if build["output"].get("artifacts", ["*"]) else ()), build["distribution"], "/dev/null", |