ww: canonicalize directory package identities
This commit is contained in:
@@ -38,6 +38,8 @@ type pkggroup = struct {
|
||||
|
||||
type pkgplan = struct {
|
||||
dir: str,
|
||||
sourceroot: str,
|
||||
identity: str,
|
||||
root: str,
|
||||
workdir: str,
|
||||
buildout: str,
|
||||
@@ -438,6 +440,24 @@ fn pkgmakedir(path: str) bool = {
|
||||
return os.mkdir(path, 448i32) == 0;
|
||||
};
|
||||
|
||||
// Resolve a directory to the kernel's symlink-free absolute spelling. The
|
||||
// coordinator is single-threaded while planning, so the temporary cwd change
|
||||
// cannot race a child process launch.
|
||||
fn pkgcanonicaldir(path: str, out: *str) bool = {
|
||||
let before: []u8 = alloc([], os.PATH_MAX: u64)!;
|
||||
before.len = os.PATH_MAX;
|
||||
let bn: i64 = os.getcwd(before.ptr, before.len: u64);
|
||||
if (bn <= 1i64 || bn > before.len: i64) { return false; };
|
||||
if (os.chdir(path) != 0) { return false; };
|
||||
let after: []u8 = alloc([], os.PATH_MAX: u64)!;
|
||||
after.len = os.PATH_MAX;
|
||||
let an: i64 = os.getcwd(after.ptr, after.len: u64);
|
||||
let restored: i32 = os.chdir(strings.frombytes(before[0:(bn - 1i64): i32]));
|
||||
if (restored != 0 || an <= 1i64 || an > after.len: i64) { return false; };
|
||||
*out = strings.dup(strings.frombytes(after[0:(an - 1i64): i32]));
|
||||
return true;
|
||||
};
|
||||
|
||||
// The coordinator removes only its minted temp root; validating the opened
|
||||
// inode keeps a replaced path from carrying cleanup outside that ownership.
|
||||
fn pkgremoveall(path: str) bool = {
|
||||
@@ -519,9 +539,8 @@ fn pkgworkescape(s: str) str = {
|
||||
return strings.frombytes(out);
|
||||
};
|
||||
|
||||
fn pkgworkkey(dir: str, pkg: str) str = {
|
||||
return strings.concat("d_", pkgworkescape(dir), "_p_",
|
||||
pkgworkescape(pkg));
|
||||
fn pkgworkkey(dir: str) str = {
|
||||
return strings.concat("d_", pkgworkescape(dir));
|
||||
};
|
||||
|
||||
fn pkgsetplanpaths(p: *pkgplan, groups: []pkggroup, root: str, index: i32,
|
||||
@@ -531,10 +550,10 @@ fn pkgsetplanpaths(p: *pkgplan, groups: []pkggroup, root: str, index: i32,
|
||||
if (!pkgmakedir(p.root)) { return false; };
|
||||
p.workdir = "";
|
||||
if (workroot.len != 0) {
|
||||
// The request root and first byte-sorted product name make one stable
|
||||
// escaped key for the command-scoped driver workdir.
|
||||
// Canonical request-directory identity makes equivalent spellings and
|
||||
// product reorderings select one command-scoped driver workdir.
|
||||
p.workdir = strings.concat(workroot, "/",
|
||||
pkgworkkey(p.dir, groups[p.start].pkg));
|
||||
pkgworkkey(p.sourceroot));
|
||||
match (os.mkdirs(p.workdir, 448)) {
|
||||
case void => void;
|
||||
case let e: os.oserror => return false;
|
||||
@@ -601,10 +620,14 @@ fn pkgreportcommand(kind: str, g: *pkggroup, r: *exec.result) void = {
|
||||
fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
|
||||
h: *exec.process) void = {
|
||||
let ba: []str = alloc([],
|
||||
(8 + (p.end - p.start) * 6 + includes.len * 2): u64)!;
|
||||
(12 + (p.end - p.start) * 6 + includes.len * 2): u64)!;
|
||||
append(ba, builder);
|
||||
append(ba, "test");
|
||||
append(ba, "-c");
|
||||
if (p.identity.len != 0) {
|
||||
append(ba, "--ww-root-identity");
|
||||
append(ba, p.identity);
|
||||
};
|
||||
let i: i32 = p.start;
|
||||
for (i < p.end) {
|
||||
let g: *pkggroup = &groups[i];
|
||||
@@ -619,6 +642,10 @@ fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
|
||||
append(ba, g.buildok);
|
||||
i += 1;
|
||||
};
|
||||
// Recursive descendants derive full identities relative to the canonical
|
||||
// discovery root using the driver's ordinary ordered import lookup.
|
||||
append(ba, "-I");
|
||||
append(ba, p.sourceroot);
|
||||
let ii: i32 = 0;
|
||||
for (ii < includes.len) {
|
||||
append(ba, "-I");
|
||||
@@ -745,6 +772,7 @@ export fn packagecommand(args: []str) int = {
|
||||
let timeoutarg: str = "";
|
||||
let outname: str = "";
|
||||
let workroot: str = "";
|
||||
let requestidentity: str = "";
|
||||
let builder: str = pkgdefaultbuilder();
|
||||
let i: i32 = 0;
|
||||
for (i < args.len) {
|
||||
@@ -819,6 +847,16 @@ export fn packagecommand(args: []str) int = {
|
||||
i += 2;
|
||||
continue;
|
||||
};
|
||||
if (strings.compare(a, "--ww-root-identity") == 0) {
|
||||
if (i + 1 >= args.len || args[i + 1].len == 0
|
||||
|| requestidentity.len != 0) {
|
||||
pkgusage();
|
||||
return 2;
|
||||
};
|
||||
requestidentity = args[i + 1];
|
||||
i += 2;
|
||||
continue;
|
||||
};
|
||||
if (a.len != 0 && a[0] == '-') { pkgusage(); return 2; };
|
||||
append(roots, a);
|
||||
i += 1;
|
||||
@@ -872,6 +910,11 @@ export fn packagecommand(args: []str) int = {
|
||||
pkgfailpath(discoverroot, "directory contains no WW package sources");
|
||||
return 1;
|
||||
};
|
||||
let canonicalroot: str;
|
||||
if (!pkgcanonicaldir(discoverroot, &canonicalroot)) {
|
||||
pkgfailpath(discoverroot, "cannot canonicalize package directory");
|
||||
return 1;
|
||||
};
|
||||
|
||||
let srcs: []pkgsource = alloc([], ds.paths.len: u64)!;
|
||||
i = 0;
|
||||
@@ -985,6 +1028,8 @@ export fn packagecommand(args: []str) int = {
|
||||
let plans: []pkgplan = alloc([], 1u64)!;
|
||||
let plan: pkgplan;
|
||||
plan.dir = discoverroot;
|
||||
plan.sourceroot = canonicalroot;
|
||||
plan.identity = requestidentity;
|
||||
plan.start = 0;
|
||||
plan.end = groups.len;
|
||||
plan.state = PKGQUEUED;
|
||||
|
||||
Reference in New Issue
Block a user