deb: stage the pointed-at tree, not its parent
The staged tree was the parent of the tree the caller pointed at, so building a tree sitting in a busy directory dragged every sibling into the chroot: a /tmp checkout copied the whole host /tmp (snap sockets, other jobs' scratch), and the build user's chown -R then failed per foreign-owned file, or aborted the build outright. Stage the tree itself: its content is the merge point of the build root, the overlay lower is the tree and the record's upper stacks on top. The package resolution treats the staged root as the package when it carries debian/, keeping the pattern search for nested layouts. The .debs, the upload metadata and the dose3 scratch follow dh_builddeb's .. (the package directory's parent) instead of assuming the build root, and the host-tree snapshot covers the tree only. Records staged the old way self-heal: their snapshots carry parent-relative paths, so the next incremental run's sync wipes the stale upper entries and rebuilds once. Siblings are no longer visible to debian/rules — dpkg packaging never crosses that boundary, and pkh test already staged the tree alone.
This commit is contained in:
+56
-56
@@ -605,13 +605,14 @@ async fn build_binary_package_impl(
|
||||
// the upperdir) and re-mount it, so the previous attempt's build
|
||||
// artifacts (object files) are visible to make; a cold staging
|
||||
// (no snapshot, or no overlay support) stages a fresh copy.
|
||||
let parent_dir = host_tree
|
||||
.parent()
|
||||
.ok_or("Cannot find parent directory")?
|
||||
.to_path_buf();
|
||||
//
|
||||
// The staged tree is the pointed-at tree itself — its content is
|
||||
// the merge point of the build root — never its parent: siblings
|
||||
// stay on the host, so a tree sitting in a busy directory does
|
||||
// not drag it into the chroot.
|
||||
let mut build_resume = false;
|
||||
if let Some(s) = &session {
|
||||
build_resume = session::sync_upper_for_resume(s, &parent_dir)?;
|
||||
build_resume = session::sync_upper_for_resume(s, &host_tree)?;
|
||||
if build_resume {
|
||||
log::info!(
|
||||
"Reusing the build artifacts of the previous attempt (incremental build)"
|
||||
@@ -627,7 +628,7 @@ async fn build_binary_package_impl(
|
||||
// host-deleted files into the build. Still environment-
|
||||
// resumable, just not artifact-resumable.
|
||||
let staging = match build_ctx.ensure_available_with_overlay(
|
||||
&parent_dir,
|
||||
&host_tree,
|
||||
&build_root,
|
||||
&s.upper_dir(),
|
||||
&s.work_dir(),
|
||||
@@ -640,7 +641,7 @@ async fn build_binary_package_impl(
|
||||
e
|
||||
);
|
||||
s.wipe_staged_tree()?;
|
||||
let path = build_ctx.ensure_available(&parent_dir, &build_root)?;
|
||||
let path = build_ctx.ensure_available(&host_tree, &build_root)?;
|
||||
build_resume = false;
|
||||
crate::context::OverlayStaging {
|
||||
path,
|
||||
@@ -655,10 +656,10 @@ async fn build_binary_package_impl(
|
||||
}
|
||||
staging.path
|
||||
} else {
|
||||
build_ctx.ensure_available(&parent_dir, &build_root)?
|
||||
build_ctx.ensure_available(&host_tree, &build_root)?
|
||||
};
|
||||
// The staged parent (build root + workspace name) is where the
|
||||
// build steps and the artifact collection work.
|
||||
// The staged tree (build root + tree name) is where the build
|
||||
// steps and the artifact collection work.
|
||||
let build_root = staged_path.to_string_lossy().into_owned();
|
||||
|
||||
if let Some(s) = &session {
|
||||
@@ -667,11 +668,11 @@ async fn build_binary_package_impl(
|
||||
|
||||
// Resolve the package directory inside the staging area. The tree
|
||||
// the caller pointed at is authoritative (its changelog defined the
|
||||
// package/version/series above), so its staged copy wins; the
|
||||
// name-pattern search only runs as a fallback.
|
||||
// package/version/series above), so its staged content wins; the
|
||||
// name-pattern search only runs when the tree holds a layout
|
||||
// instead (a nested checkout, a version-suffixed unpack).
|
||||
let package_dir = resolve_package_directory(
|
||||
Path::new(&build_root),
|
||||
cwd,
|
||||
&package,
|
||||
&version,
|
||||
series,
|
||||
@@ -691,7 +692,6 @@ async fn build_binary_package_impl(
|
||||
series,
|
||||
pocket.as_deref(),
|
||||
mirror.as_deref(),
|
||||
&build_root,
|
||||
&package_dir,
|
||||
cross,
|
||||
ppa,
|
||||
@@ -713,9 +713,14 @@ async fn build_binary_package_impl(
|
||||
};
|
||||
|
||||
// Retrieve the produced artifacts (binary packages plus the upload
|
||||
// metadata) to the parent directory.
|
||||
// metadata) to the parent directory: the .debs land next to the
|
||||
// tree, on the host, whatever the staging scope is.
|
||||
enter_phase(view, Phase::RetrievingArtifacts, &mut profiler);
|
||||
let total_debs = remote_files.len();
|
||||
let parent_dir = host_tree
|
||||
.parent()
|
||||
.ok_or("Cannot find parent directory")?
|
||||
.to_path_buf();
|
||||
|
||||
let mut artifacts = Vec::with_capacity(total_debs);
|
||||
for (idx, remote_file) in remote_files.iter().enumerate() {
|
||||
@@ -903,32 +908,26 @@ fn resolve_record_in(
|
||||
|
||||
/// Resolve the package directory for a build inside the staged build root.
|
||||
///
|
||||
/// The tree the caller pointed at is authoritative: `cwd`'s changelog
|
||||
/// already defined the package, version and series for this build, so its
|
||||
/// staged copy is used outright when it carries a `debian/` tree. The
|
||||
/// name-pattern search ([`find_package_directory`], including the quirks
|
||||
/// overrides) only runs when that copy cannot be resolved — a default `.`
|
||||
/// cwd has no basename, and the pointed-at tree may live outside the staged
|
||||
/// parent. Embedded callers are the motivation: their working directory
|
||||
/// names (`tree`, `checkout`, ...) match none of the search patterns.
|
||||
/// The staged tree is the merge point of the build root: its content is
|
||||
/// the content of the tree the caller pointed at — whose changelog already
|
||||
/// defined the package, version and series — so the package directory is
|
||||
/// the root itself when the tree carries a `debian/` directory. Otherwise
|
||||
/// the tree holds a layout to search (a nested checkout, a
|
||||
/// version-suffixed unpack): [`find_package_directory`], including the
|
||||
/// quirks overrides.
|
||||
pub(crate) fn resolve_package_directory(
|
||||
build_root: &Path,
|
||||
cwd: &Path,
|
||||
package: &str,
|
||||
version: &str,
|
||||
series: &str,
|
||||
ctx: &context::Context,
|
||||
) -> Result<PathBuf, Box<dyn Error>> {
|
||||
if let Some(tree_name) = cwd.file_name() {
|
||||
let staged_tree = build_root.join(tree_name);
|
||||
if ctx.is_dir(&staged_tree)? && ctx.exists(&staged_tree.join("debian"))? {
|
||||
log::debug!(
|
||||
"Using the staged copy of {} at {}",
|
||||
cwd.display(),
|
||||
staged_tree.display()
|
||||
);
|
||||
return Ok(staged_tree);
|
||||
}
|
||||
if ctx.is_dir(build_root)? && ctx.exists(&build_root.join("debian"))? {
|
||||
log::debug!(
|
||||
"Using the staged copy of the tree at {}",
|
||||
build_root.display()
|
||||
);
|
||||
return Ok(build_root.to_path_buf());
|
||||
}
|
||||
find_package_directory(build_root, package, version, series, ctx)
|
||||
}
|
||||
@@ -1209,10 +1208,11 @@ mod tests {
|
||||
#[test]
|
||||
fn find_package_directory_lists_staged_directories_through_the_context() {
|
||||
let chroot = tempfile::tempdir().unwrap();
|
||||
// Staged parent holding a single tree whose name matches none of
|
||||
// the search patterns (the embedded-caller layout: <job>/tree)
|
||||
let staged_parent = chroot.path().join("tmp/pkh-build-1/j-42");
|
||||
std::fs::create_dir_all(staged_parent.join("tree/debian")).unwrap();
|
||||
// Staged tree holding a single nested checkout whose name matches
|
||||
// none of the search patterns (the embedded-caller layout:
|
||||
// <job>/tree)
|
||||
let staged_tree = chroot.path().join("tmp/pkh-build-1/j-42");
|
||||
std::fs::create_dir_all(staged_tree.join("tree/debian")).unwrap();
|
||||
|
||||
let ctx = unshare_test_context(chroot.path());
|
||||
let err = find_package_directory(
|
||||
@@ -1231,43 +1231,43 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// An explicit cwd must resolve to its staged copy even when its name
|
||||
/// matches none of the search patterns: the pointed-at tree is what the
|
||||
/// parsed changelog came from.
|
||||
/// The staged tree is the merge point of the build root: when the
|
||||
/// pointed-at tree is itself the package, its content sits at the
|
||||
/// root and resolves outright — even when the tree name matches none
|
||||
/// of the search patterns (the embedded-caller layout: <job>/tree).
|
||||
#[test]
|
||||
fn resolve_package_directory_prefers_the_pointed_tree() {
|
||||
let chroot = tempfile::tempdir().unwrap();
|
||||
let staged_parent = chroot.path().join("tmp/pkh-build-1/j-42");
|
||||
std::fs::create_dir_all(staged_parent.join("tree/debian/source")).unwrap();
|
||||
let staged_tree = chroot.path().join("tmp/pkh-build-1/tree");
|
||||
std::fs::create_dir_all(staged_tree.join("debian/source")).unwrap();
|
||||
|
||||
let ctx = unshare_test_context(chroot.path());
|
||||
let resolved = resolve_package_directory(
|
||||
Path::new("/tmp/pkh-build-1/j-42"),
|
||||
Path::new("/work/jobs/j-42/tree"),
|
||||
Path::new("/tmp/pkh-build-1/tree"),
|
||||
"bc",
|
||||
"1.07.1-1ubuntu1",
|
||||
"questing",
|
||||
&ctx,
|
||||
)
|
||||
.expect("the staged copy of the pointed-at tree must resolve");
|
||||
.expect("the staged tree must resolve to the build root");
|
||||
|
||||
assert_eq!(resolved, PathBuf::from("/tmp/pkh-build-1/j-42/tree"));
|
||||
assert_eq!(resolved, PathBuf::from("/tmp/pkh-build-1/tree"));
|
||||
}
|
||||
|
||||
/// When the pointed-at tree is not in the staging area under its own
|
||||
/// name, resolution falls back to the name-pattern search.
|
||||
/// When the staged tree holds a layout instead of the package itself
|
||||
/// (no debian/ at its root), resolution falls back to the
|
||||
/// name-pattern search over the staged content.
|
||||
#[test]
|
||||
fn resolve_package_directory_falls_back_to_the_name_search() {
|
||||
let chroot = tempfile::tempdir().unwrap();
|
||||
let staged_parent = chroot.path().join("tmp/pkh-build-1/j-42");
|
||||
// Staged copy of a pulled tree: <pkg>/<pkg>-<origversion>
|
||||
std::fs::create_dir_all(staged_parent.join("bc/bc-1.07.1/debian")).unwrap();
|
||||
let staged_tree = chroot.path().join("tmp/pkh-build-1/checkout");
|
||||
// A pulled-tree layout inside the pointed-at tree:
|
||||
// <pkg>/<pkg>-<origversion>
|
||||
std::fs::create_dir_all(staged_tree.join("bc/bc-1.07.1/debian")).unwrap();
|
||||
|
||||
let ctx = unshare_test_context(chroot.path());
|
||||
let resolved = resolve_package_directory(
|
||||
Path::new("/tmp/pkh-build-1/j-42"),
|
||||
// A tree never staged under that name
|
||||
Path::new("/work/other/checkout"),
|
||||
Path::new("/tmp/pkh-build-1/checkout"),
|
||||
"bc",
|
||||
"1.07.1-1ubuntu1",
|
||||
"questing",
|
||||
@@ -1277,7 +1277,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
resolved,
|
||||
PathBuf::from("/tmp/pkh-build-1/j-42/bc/bc-1.07.1")
|
||||
PathBuf::from("/tmp/pkh-build-1/checkout/bc/bc-1.07.1")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user