summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mdbp/build_schema.json2
-rw-r--r--mdbp/common.py27
-rw-r--r--mdbp/mmdebstrap.py55
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",