ww: protect public install outputs
This commit is contained in:
@@ -39,9 +39,13 @@ type pkggroup = struct {
|
||||
bin: str,
|
||||
buildok: str,
|
||||
runoutput: str,
|
||||
installoutput: str,
|
||||
state: i32,
|
||||
runstartfailed: bool,
|
||||
runres: exec.result,
|
||||
publicbin: bool,
|
||||
installattempted: bool,
|
||||
installres: exec.result,
|
||||
};
|
||||
|
||||
type pkgplan = struct {
|
||||
@@ -64,6 +68,7 @@ type pkgplan = struct {
|
||||
outputcollisionbase: str,
|
||||
outputcollisiondir: str,
|
||||
suppressbuildreports: bool,
|
||||
deferpublish: bool,
|
||||
};
|
||||
|
||||
def PKG_COUNT_MAX: i32 = 2147483647;
|
||||
@@ -1373,16 +1378,23 @@ fn pkgsetplanpaths(p: *pkgplan, groups: []pkggroup, root: str, index: i32,
|
||||
pkgfailpath(g.root, "cannot create product temporary path");
|
||||
return false;
|
||||
};
|
||||
g.publicbin = false;
|
||||
g.installattempted = false;
|
||||
if (buildonly) {
|
||||
if (outputdir && strings.compare(g.pkg, "main") == 0
|
||||
&& !p.outputpatherror && !p.emitasm) {
|
||||
if (!pkgjoinpath(outname, g.basename, &g.bin)) { return false; };
|
||||
} else if (outname.len != 0 && !outputdir) { g.bin = outname; }
|
||||
g.publicbin = true;
|
||||
} else if (outname.len != 0 && !outputdir) {
|
||||
g.bin = outname;
|
||||
g.publicbin = true;
|
||||
}
|
||||
else if (!pkgstring(&g.bin, g.root, "/package.build")) { return false; };
|
||||
} else {
|
||||
if (!pkgstring(&g.bin, g.root, "/package.test")) { return false; };
|
||||
};
|
||||
if (!pkgstring(&g.runoutput, g.root, "/test.output")
|
||||
|| !pkgstring(&g.installoutput, g.root, "/install.output")
|
||||
|| !pkgstring(&g.buildok, g.root, "/build.ok")) { return false; };
|
||||
i += 1;
|
||||
};
|
||||
@@ -1484,7 +1496,8 @@ fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
|
||||
for (i < p.end) {
|
||||
let g: *pkggroup = &groups[i];
|
||||
append(ba, "--ww-package-test");
|
||||
if (p.buildonly) { append(ba, "build"); }
|
||||
if (p.buildonly && g.publicbin) { append(ba, "build-public"); }
|
||||
else if (p.buildonly) { append(ba, "build"); }
|
||||
else { append(ba, "test"); };
|
||||
append(ba, g.pkg);
|
||||
if (g.prodpkg.len != 0) { append(ba, g.prodpkg); }
|
||||
@@ -1495,7 +1508,7 @@ fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
|
||||
else { append(ba, "-"); };
|
||||
append(ba, g.dir);
|
||||
append(ba, g.bin);
|
||||
if (g.publish.len != 0) { append(ba, g.publish); }
|
||||
if (g.publish.len != 0 && !p.deferpublish) { append(ba, g.publish); }
|
||||
else { append(ba, "-"); };
|
||||
append(ba, g.buildok);
|
||||
i += 1;
|
||||
@@ -1591,6 +1604,31 @@ fn pkgstartrun(g: *pkggroup, filters: []str, timeoutarg: str,
|
||||
return true;
|
||||
};
|
||||
|
||||
// Pinned builderTest orders a retained running test as build -> run ->
|
||||
// BuildInstallFunc. Re-enter the selected stage driver for the final action so
|
||||
// build and test share one overwrite predicate instead of copying object magic
|
||||
// into the coordinator.
|
||||
fn pkginstalloutput(g: *pkggroup, builder: str) void = {
|
||||
let ia: []str = [builder, "test", "--ww-install-test-output",
|
||||
g.bin, g.publish];
|
||||
let env: []str = os.getenvs();
|
||||
let icmd: exec.command;
|
||||
icmd.path = builder;
|
||||
icmd.argv = ia;
|
||||
icmd.env = env;
|
||||
icmd.dir = "";
|
||||
icmd.stdoutpath = g.installoutput;
|
||||
icmd.stderrpath = g.installoutput;
|
||||
icmd.deadline.sec = 0i64;
|
||||
icmd.deadline.nsec = 0i64;
|
||||
icmd.grace = 0i64: time.duration;
|
||||
let h: exec.process;
|
||||
g.installattempted = true;
|
||||
exec.start(&h, &icmd);
|
||||
for (!exec.poll(&h)) { time.sleep(pkgpoll, time.clock.monotonic); };
|
||||
g.installres = h.result;
|
||||
};
|
||||
|
||||
fn pkgproductbuilt(g: *pkggroup, buildonly: bool) bool = {
|
||||
if (buildonly || g.notests) { return pkgisreg(g.buildok); };
|
||||
return pkgisreg(g.buildok) && pkgisreg(g.bin);
|
||||
@@ -1602,6 +1640,35 @@ fn pkgrunok(g: *pkggroup) bool = {
|
||||
&& g.runres.code == 0;
|
||||
};
|
||||
|
||||
fn pkginstallok(g: *pkggroup) bool = {
|
||||
return g.installres.errno == 0 && g.installres.cleanuperrno == 0
|
||||
&& g.installres.termination == exec.termination.EXIT
|
||||
&& g.installres.code == 0;
|
||||
};
|
||||
|
||||
fn pkgemitinstall(g: *pkggroup) bool = {
|
||||
if (!g.installattempted) { return true; };
|
||||
let output: str;
|
||||
if (!pkgread(g.installoutput, &output)) {
|
||||
pkgfailpath(g.root, "cannot read install capture");
|
||||
return false;
|
||||
};
|
||||
if (output.len != 0) {
|
||||
pkgput(os.STDERR_FILENO, output);
|
||||
if (output[output.len - 1] != '\n') {
|
||||
pkgput(os.STDERR_FILENO, "\n");
|
||||
};
|
||||
};
|
||||
if (!pkginstallok(g)) {
|
||||
if (output.len == 0) {
|
||||
pkgreportcommand(os.STDERR_FILENO, "install", g,
|
||||
&g.installres);
|
||||
};
|
||||
return false;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
fn pkgemitgroup(g: *pkggroup, compileonly: bool) bool = {
|
||||
if (g.notests) {
|
||||
pkgput(os.STDOUT_FILENO, "? ");
|
||||
@@ -1653,8 +1720,9 @@ fn pkgemitplan(p: *pkgplan, groups: []pkggroup,
|
||||
failed += 1;
|
||||
} else if (buildonly) {
|
||||
void;
|
||||
} else if (!pkgemitgroup(&groups[i], compileonly)) {
|
||||
failed += 1;
|
||||
} else {
|
||||
if (!pkgemitgroup(&groups[i], compileonly)) { failed += 1; };
|
||||
if (!compileonly && !pkgemitinstall(&groups[i])) { failed += 1; };
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
@@ -2385,11 +2453,12 @@ export fn packagecommand(args: []str) int = {
|
||||
plan.outputcollisiondir = outputcollisiondir;
|
||||
plan.suppressbuildreports = buildonly
|
||||
&& (outputdir || defaultoutputdir.len != 0);
|
||||
plan.deferpublish = !buildonly && !compileonly && testretain && !testnull;
|
||||
append(plans, plan);
|
||||
let createdir: str = "";
|
||||
if (buildonly && outputdir) {
|
||||
createdir = outname;
|
||||
} else if (!buildonly && testretain && !testnull) {
|
||||
} else if (!buildonly && compileonly && testretain && !testnull) {
|
||||
i = 0;
|
||||
for (i < groups.len) {
|
||||
if (groups[i].publish.len != 0) {
|
||||
@@ -2550,6 +2619,22 @@ export fn packagecommand(args: []str) int = {
|
||||
if (active > 0) { time.sleep(pkgpoll, time.clock.monotonic); };
|
||||
};
|
||||
|
||||
// A failed, signalled, timed-out, or unstartable run propagates to its Go
|
||||
// install action, so it preserves any prior retained binary. Successful
|
||||
// products install independently after their private execution.
|
||||
if (!compileonly) {
|
||||
i = 0;
|
||||
for (i < groups.len) {
|
||||
let g: *pkggroup = &groups[i];
|
||||
if (g.publish.len != 0 && !g.notests
|
||||
&& pkgproductbuilt(g, buildonly) && !g.runstartfailed
|
||||
&& pkgrunok(g)) {
|
||||
pkginstalloutput(g, builder);
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
i = 0;
|
||||
for (i < plans.len) {
|
||||
failed += pkgemitplan(&plans[i], groups, compileonly, buildonly);
|
||||
|
||||
Reference in New Issue
Block a user