build: separate package identity from storage paths
This commit is contained in:
@@ -60,6 +60,25 @@ fn slurp(path: *u8) (*u8, u64) = {
|
||||
return buf.ptr, nz;
|
||||
};
|
||||
|
||||
fn exportownermatches(buf: *u8, n: u64, path: *u8) bool = {
|
||||
let prefix: str = "//ww:module ";
|
||||
let pn: u64 = cstrlen(path);
|
||||
let poff: u64 = prefix.len: u64;
|
||||
let need: u64 = poff + pn + 1u64;
|
||||
if (n < need) { return false; };
|
||||
let i: u64 = 0u64;
|
||||
for (i < poff) {
|
||||
if (buf[i] != prefix.ptr[i]) { return false; };
|
||||
i += 1u64;
|
||||
};
|
||||
i = 0u64;
|
||||
for (i < pn) {
|
||||
if (buf[poff + i] != path[i]) { return false; };
|
||||
i += 1u64;
|
||||
};
|
||||
return buf[need - 1u64] == 10u8;
|
||||
};
|
||||
|
||||
export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let src: *u8 = nil;
|
||||
let out: *u8 = nil;
|
||||
@@ -204,6 +223,17 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
os.write(2, nl.ptr, nl.len: u64);
|
||||
return 1;
|
||||
};
|
||||
if (!exportownermatches(ibuf, ilen, importpaths[importi])) {
|
||||
let pre: str = "w6c: import ";
|
||||
let mid: str = ": export owner mismatch in ";
|
||||
let nl: str = "\n";
|
||||
os.write(2, pre.ptr, pre.len: u64);
|
||||
os.write(2, importpaths[importi], cstrlen(importpaths[importi]));
|
||||
os.write(2, mid.ptr, mid.len: u64);
|
||||
os.write(2, importfiles[importi], cstrlen(importfiles[importi]));
|
||||
os.write(2, nl.ptr, nl.len: u64);
|
||||
return 1;
|
||||
};
|
||||
let il: lex;
|
||||
lexinit(&il, strings.dup(pathstr(importfiles[importi])), ibuf, ilen);
|
||||
let ips: parser;
|
||||
|
||||
@@ -1017,6 +1017,9 @@ fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
|
||||
pkg = file.nmod;
|
||||
};
|
||||
};
|
||||
if (file.nmod.len > 0) {
|
||||
wputs(fd, "//ww:module "); wputs(fd, file.nmod); wputs(fd, "\n");
|
||||
};
|
||||
wputs(fd, "package ");
|
||||
wputs(fd, pkg);
|
||||
wputs(fd, ";\n");
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
package main;
|
||||
|
||||
import crypto.sha256;
|
||||
import hash;
|
||||
import os;
|
||||
import os.exec;
|
||||
import rt;
|
||||
@@ -137,8 +139,9 @@ fn selfdirinto(dst: *u8, dstsz: u64, argv0: *u8) void = {
|
||||
};
|
||||
|
||||
fn joinpath(dir: *u8, name: *u8) *u8 = {
|
||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
buf.len = os.PATH_MAX;
|
||||
let need: u64 = cstrlen(dir) + 1u64 + cstrlen(name) + 1u64;
|
||||
let buf: []u8 = alloc([], need)!;
|
||||
buf.len = need: i32;
|
||||
let off: u64 = cstrinto(buf.ptr, 0u64, dir);
|
||||
off = byteinto(buf.ptr, off, 47u8);
|
||||
off = cstrinto(buf.ptr, off, name);
|
||||
@@ -147,8 +150,9 @@ fn joinpath(dir: *u8, name: *u8) *u8 = {
|
||||
};
|
||||
|
||||
fn joinpathlit(dir: *u8, name: str) *u8 = {
|
||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
buf.len = os.PATH_MAX;
|
||||
let need: u64 = cstrlen(dir) + 1u64 + name.len: u64 + 1u64;
|
||||
let buf: []u8 = alloc([], need)!;
|
||||
buf.len = need: i32;
|
||||
let off: u64 = cstrinto(buf.ptr, 0u64, dir);
|
||||
off = byteinto(buf.ptr, off, 47u8);
|
||||
off = strinto(buf.ptr, off, name);
|
||||
@@ -495,7 +499,6 @@ def SEP_ROLE_GENERATED_MAIN: i32 = 2;
|
||||
def SEP_TEST_SUPPORT_MODULE: str = "__wwtest";
|
||||
def SEP_MAXPRODUCT: i32 = 256;
|
||||
def SEP_MAXCONTEXT: i32 = 257;
|
||||
def SEP_ARTIFACT_MAX: i32 = 1024;
|
||||
|
||||
// Classify a selected directory entry: 1 production, 2 test, 0 skipped,
|
||||
// -1 @test outside *_test.ww, -2 non-regular source.
|
||||
@@ -558,11 +561,6 @@ fn dirpackagename(path: *u8) *u8 = {
|
||||
cerr(": error: invalid or missing package clause\n");
|
||||
return nil;
|
||||
};
|
||||
if (imports.nmod.len >= 256) {
|
||||
cerrpos(imports.file, imports.line, imports.col);
|
||||
cerr(": error: package name is too long\n");
|
||||
return nil;
|
||||
};
|
||||
return arenadupcstr(imports.nmod.ptr, imports.nmod.len: u64);
|
||||
};
|
||||
|
||||
@@ -759,8 +757,9 @@ fn makestem(stem: *u8, src: *u8) void = {
|
||||
};
|
||||
|
||||
fn appendlit(stem: *u8, suffix: str) *u8 = {
|
||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
buf.len = os.PATH_MAX;
|
||||
let need: u64 = cstrlen(stem) + suffix.len: u64 + 1u64;
|
||||
let buf: []u8 = alloc([], need)!;
|
||||
buf.len = need: i32;
|
||||
let off: u64 = cstrinto(buf.ptr, 0u64, stem);
|
||||
off = strinto(buf.ptr, off, suffix);
|
||||
cstrseal(buf.ptr, off);
|
||||
@@ -804,6 +803,8 @@ type seppkg = struct {
|
||||
entry: *u8, // resolved package dir (or file, file root), NUL-term
|
||||
canon: *u8, // canonical location; never package identity
|
||||
artifact: *u8, // stable non-importable variant artifact key
|
||||
storage: *u8, // internal storage basename; never package identity
|
||||
storagehashed: bool,
|
||||
name: *u8, // validated declared name; directory packages only
|
||||
testpackage: *u8,
|
||||
sources: **u8, // owned, byte-sorted selected paths; dirs only
|
||||
@@ -930,10 +931,7 @@ fn sepcommandcompilermarker(g: *sepgraph, pi: i32) bool = {
|
||||
// identity. The compiler path is derived from that base and the semantic
|
||||
// variant; root/product/artifact state never participates.
|
||||
fn sepbindimportbase(g: *sepgraph, pi: i32, base: *u8) i32 = {
|
||||
if (base == nil || base[0u64] == 0u8 || cstrlen(base) >= 256u64) {
|
||||
cerr("ww: package path is too long (limit 255 bytes)\n");
|
||||
return -1;
|
||||
};
|
||||
if (base == nil || base[0u64] == 0u8) { return -1; };
|
||||
if (!reservedimportpath(base) && !sepimportbasevalid(base)) {
|
||||
cerr("ww: invalid package path "); cerr(pathstr(base)); cerr("\n");
|
||||
return -1;
|
||||
@@ -992,10 +990,6 @@ fn sepbindimportbase(g: *sepgraph, pi: i32, base: *u8) i32 = {
|
||||
fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
||||
isdir: i32, variant: i32, testpackage: *u8, role: i32,
|
||||
artifact: *u8, root: bool) i32 = {
|
||||
if (cstrlen(path) >= 256u64) {
|
||||
cerr("ww: package path is too long (limit 255 bytes)\n");
|
||||
return -1;
|
||||
};
|
||||
let canon: *u8 = nil;
|
||||
if (isdir != 0) {
|
||||
canon = canonicaldir(pathstr(entry));
|
||||
@@ -1004,10 +998,6 @@ fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
||||
cerr(pathstr(entry)); cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
if (cstrlen(canon) >= 1024u64) {
|
||||
cerr("ww: canonical package path is too long\n");
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
let incoming: *u8 = nil;
|
||||
if (isdir != 0 && path[0u64] != 0u8) {
|
||||
@@ -1094,6 +1084,8 @@ fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
||||
g.pkg[g.n].entry = arenadupcstr(entry, elen);
|
||||
g.pkg[g.n].canon = canon;
|
||||
g.pkg[g.n].artifact = nil;
|
||||
g.pkg[g.n].storage = nil;
|
||||
g.pkg[g.n].storagehashed = false;
|
||||
g.pkg[g.n].name = nil;
|
||||
g.pkg[g.n].testpackage = nil;
|
||||
if (testpackage != nil) {
|
||||
@@ -1186,17 +1178,12 @@ fn sepgraphfree(g: *sepgraph) void = {
|
||||
|
||||
fn sepcontextfor(g: *sepgraph, root: *u8, incs: *u8,
|
||||
toolsrcdir: *u8) i32 = {
|
||||
let cap: u64 = (os.PATH_MAX: u64) * 2u64;
|
||||
let need: u64 = cstrlen(root) + 1u64 + cstrlen(toolsrcdir) + 1u64;
|
||||
if (incs != nil && incs[0u64] != 0u8) {
|
||||
need += cstrlen(incs) + 1u64;
|
||||
};
|
||||
if (need > cap) {
|
||||
cerr("ww: package import search path is too long\n");
|
||||
return -1;
|
||||
};
|
||||
let search: []u8 = alloc([], cap)!;
|
||||
search.len = cap: i32;
|
||||
let search: []u8 = alloc([], need)!;
|
||||
search.len = need: i32;
|
||||
let off: u64 = cstrinto(search.ptr, 0u64, root);
|
||||
off = byteinto(search.ptr, off, 58u8);
|
||||
if (incs != nil && incs[0u64] != 0u8) {
|
||||
@@ -1221,59 +1208,142 @@ fn sepcontextfor(g: *sepgraph, root: *u8, incs: *u8,
|
||||
return result;
|
||||
};
|
||||
|
||||
// Build one artifact path. Test roots use distinct names even though both
|
||||
// compiler units reset to the bare executable namespace.
|
||||
def SEP_NAME_MAX: u64 = 255u64;
|
||||
|
||||
fn sepstoragedigest(p: *seppkg) *u8 = {
|
||||
let state: sha256.state = sha256.sha256();
|
||||
let h: *hash.hash = (&state): *hash.hash;
|
||||
hash.write(h, strings.toutf8("ww-package-storage-v2:"));
|
||||
let tag: [4]u8;
|
||||
tag[0] = ('0': i32 + p.variant): u8;
|
||||
tag[1] = ':': u8;
|
||||
tag[2] = ('0': i32 + p.role): u8;
|
||||
tag[3] = ':': u8;
|
||||
hash.write(h, tag[0:4]);
|
||||
hash.write(h, strings.toutf8(pathstr(p.path)));
|
||||
let zero: [1]u8;
|
||||
zero[0] = 0u8;
|
||||
hash.write(h, zero[0:1]);
|
||||
hash.write(h, strings.toutf8(pathstr(p.canon)));
|
||||
let digest: [32]u8;
|
||||
hash.sum(h, digest[0:32]);
|
||||
let need: u64 = "__wwpkg.v".len: u64 + 1u64 + ".r".len: u64
|
||||
+ 1u64 + ".h".len: u64 + 64u64 + 1u64;
|
||||
let out: []u8 = alloc([], need)!;
|
||||
out.len = need: i32;
|
||||
let off: u64 = strinto(out.ptr, 0u64, "__wwpkg.v");
|
||||
off = byteinto(out.ptr, off, tag[0]);
|
||||
off = strinto(out.ptr, off, ".r");
|
||||
off = byteinto(out.ptr, off, tag[2]);
|
||||
off = strinto(out.ptr, off, ".h");
|
||||
let hex: str = "0123456789abcdef";
|
||||
let i: i32 = 0;
|
||||
for (i < 32) {
|
||||
let high: i32 = (digest[i] / 16u8): i32;
|
||||
let low: i32 = (digest[i] % 16u8): i32;
|
||||
off = byteinto(out.ptr, off, hex[high]);
|
||||
off = byteinto(out.ptr, off, hex[low]);
|
||||
i += 1;
|
||||
};
|
||||
cstrseal(out.ptr, off);
|
||||
return out.ptr;
|
||||
};
|
||||
|
||||
fn seplegacyartifact(p: *seppkg) *u8 = {
|
||||
if (p.artifact != nil && p.artifact[0u64] != 0u8) { return p.artifact; };
|
||||
if (p.path != nil && p.path[0u64] != 0u8) { return p.path; };
|
||||
return "__root\0".ptr;
|
||||
};
|
||||
|
||||
fn sepvalidatestoragepath(p: *seppkg, scratch: *u8) i32 = {
|
||||
let need: u64 = cstrlen(scratch) + 1u64 + cstrlen(p.storage)
|
||||
+ ".unit.new".len: u64 + 1u64;
|
||||
if (cstrlen(p.storage) + ".unit.new".len: u64 > SEP_NAME_MAX
|
||||
|| need > os.PATH_MAX: u64) {
|
||||
cerr("ww: package artifact path is too long\n");
|
||||
return -1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
fn sepassignstorage(p: *seppkg, scratch: *u8) i32 = {
|
||||
let base: *u8 = seplegacyartifact(p);
|
||||
let need: u64 = cstrlen(scratch) + 1u64 + cstrlen(base)
|
||||
+ ".unit.new".len: u64 + 1u64;
|
||||
if (cstrlen(base) + ".unit.new".len: u64 <= SEP_NAME_MAX
|
||||
&& need <= os.PATH_MAX: u64) {
|
||||
p.storage = arenadupcstr(base, cstrlen(base));
|
||||
p.storagehashed = false;
|
||||
} else {
|
||||
p.storage = sepstoragedigest(p);
|
||||
p.storagehashed = true;
|
||||
};
|
||||
return sepvalidatestoragepath(p, scratch);
|
||||
};
|
||||
|
||||
fn sepfname(g: *sepgraph, pi: i32, scratch: *u8, suffix: str) *u8 = {
|
||||
let buf: []u8 = alloc([], SEP_ARTIFACT_MAX: u64)!;
|
||||
buf.len = SEP_ARTIFACT_MAX;
|
||||
let need: u64 = cstrlen(scratch) + 1u64
|
||||
+ cstrlen(g.pkg[pi].storage) + suffix.len: u64 + 1u64;
|
||||
let buf: []u8 = alloc([], need)!;
|
||||
buf.len = need: i32;
|
||||
let off: u64 = cstrinto(buf.ptr, 0u64, scratch);
|
||||
off = byteinto(buf.ptr, off, 47u8); // '/'
|
||||
if (g.pkg[pi].artifact != nil) {
|
||||
off = cstrinto(buf.ptr, off, g.pkg[pi].artifact);
|
||||
} else { if (g.pkg[pi].path[0u64] != 0u8) {
|
||||
off = cstrinto(buf.ptr, off, g.pkg[pi].path);
|
||||
} else {
|
||||
off = strinto(buf.ptr, off, "__root");
|
||||
}; };
|
||||
off = cstrinto(buf.ptr, off, g.pkg[pi].storage);
|
||||
off = strinto(buf.ptr, off, suffix);
|
||||
cstrseal(buf.ptr, off);
|
||||
return buf.ptr;
|
||||
};
|
||||
|
||||
// sepfname uses SEP_ARTIFACT_MAX storage. Validate the longest suffix once
|
||||
// before opening files so two action identities can never alias by truncation.
|
||||
fn sepvalidateartifactpaths(g: *sepgraph, scratch: *u8) i32 = {
|
||||
let i: i32 = 0;
|
||||
for (i < g.n) {
|
||||
if (g.pkg[i].failed || !g.pkg[i].loaded) { i += 1; continue; };
|
||||
let base: *u8 = g.pkg[i].artifact;
|
||||
if (base == nil) {
|
||||
base = g.pkg[i].path;
|
||||
if (base[0u64] == 0u8) { base = "__root\0".ptr; };
|
||||
};
|
||||
let need: u64 = cstrlen(scratch) + 1u64 + cstrlen(base)
|
||||
+ ".unit.new".len: u64 + 1u64;
|
||||
if (need > SEP_ARTIFACT_MAX: u64) {
|
||||
cerr("ww: package artifact path is too long\n");
|
||||
return -1;
|
||||
};
|
||||
let j: i32 = i + 1;
|
||||
for (j < g.n) {
|
||||
if (g.pkg[j].failed || !g.pkg[j].loaded) { j += 1; continue; };
|
||||
let other: *u8 = g.pkg[j].artifact;
|
||||
if (other == nil) {
|
||||
other = g.pkg[j].path;
|
||||
if (other[0u64] == 0u8) { other = "__root\0".ptr; };
|
||||
};
|
||||
if (cstreq(base, other)) {
|
||||
cerr("ww: package actions share artifact identity ");
|
||||
cerr(pathstr(base)); cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
j += 1;
|
||||
};
|
||||
if (g.pkg[i].storage == nil
|
||||
&& sepassignstorage(&g.pkg[i], scratch) < 0) { return -1; };
|
||||
i += 1;
|
||||
};
|
||||
let changed: bool = true;
|
||||
for (changed) {
|
||||
changed = false;
|
||||
i = 0;
|
||||
for (i < g.n && !changed) {
|
||||
if (g.pkg[i].failed || !g.pkg[i].loaded) { i += 1; continue; };
|
||||
let j: i32 = i + 1;
|
||||
for (j < g.n) {
|
||||
if (g.pkg[j].failed || !g.pkg[j].loaded
|
||||
|| !cstreq(g.pkg[i].storage, g.pkg[j].storage)) {
|
||||
j += 1; continue;
|
||||
};
|
||||
if (!g.pkg[i].storagehashed || !g.pkg[j].storagehashed) {
|
||||
if (!g.pkg[i].storagehashed) {
|
||||
g.pkg[i].storage = sepstoragedigest(&g.pkg[i]);
|
||||
g.pkg[i].storagehashed = true;
|
||||
if (sepvalidatestoragepath(&g.pkg[i], scratch) < 0) {
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
if (!g.pkg[j].storagehashed) {
|
||||
g.pkg[j].storage = sepstoragedigest(&g.pkg[j]);
|
||||
g.pkg[j].storagehashed = true;
|
||||
if (sepvalidatestoragepath(&g.pkg[j], scratch) < 0) {
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
changed = true;
|
||||
j = g.n;
|
||||
} else {
|
||||
cerr("ww: package storage collision for ");
|
||||
cerr(pathstr(g.pkg[i].path)); cerr(" in ");
|
||||
cerr(pathstr(g.pkg[i].canon)); cerr(" and ");
|
||||
cerr(pathstr(g.pkg[j].path)); cerr(" in ");
|
||||
cerr(pathstr(g.pkg[j].canon)); cerr(" at ");
|
||||
cerr(pathstr(g.pkg[i].storage)); cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -1384,11 +1454,6 @@ fn sepscanfile(g: *sepgraph, pi: i32, file: *u8, searchpath: *u8,
|
||||
&& (ownedsource != 0 || g.pkg[pi].name == nil)) {
|
||||
let declared: *u8 = imports.nmod.ptr;
|
||||
let declaredn: u64 = imports.nmod.len: u64;
|
||||
if (declaredn >= 256u64) {
|
||||
cerrpos(imports.file, imports.line, imports.col);
|
||||
cerr(": error: package name is too long\n");
|
||||
return -1;
|
||||
};
|
||||
if (g.pkg[pi].name == nil) {
|
||||
g.pkg[pi].name = arenadupcstr(declared, declaredn);
|
||||
} else { if (bytecmp(g.pkg[pi].name, cstrlen(g.pkg[pi].name),
|
||||
@@ -1465,11 +1530,6 @@ fn sepscanfile(g: *sepgraph, pi: i32, file: *u8, searchpath: *u8,
|
||||
cerr(u.usepath); cerr(" is reserved\n");
|
||||
return -1;
|
||||
};
|
||||
if (idn >= 256u64) {
|
||||
cerrpos(u.file, u.line, u.col);
|
||||
cerr(": error: import path is too long (limit 255 bytes)\n");
|
||||
return -1;
|
||||
};
|
||||
let externalproduction: bool = false;
|
||||
let ipath: *u8 = nil;
|
||||
if (g.pkg[pi].variant == SEP_VARIANT_EXTERNAL
|
||||
@@ -1638,6 +1698,8 @@ fn sepaddgeneratedmain(g: *sepgraph, product: *sepproduct, ordinal: i32,
|
||||
let variantartifact: *u8 = g.pkg[variant].artifact;
|
||||
if (variantartifact == nil) { variantartifact = g.pkg[variant].path; };
|
||||
p.artifact = appendlit(variantartifact, "-main");
|
||||
p.storage = nil;
|
||||
p.storagehashed = false;
|
||||
p.name = arenadupcstr("main\0".ptr, 4u64);
|
||||
p.testpackage = nil;
|
||||
p.sources = nil;
|
||||
@@ -1888,10 +1950,7 @@ fn sepreverseimportbase(g: *sepgraph, p: *seppkg, context: i32,
|
||||
if (rel != nil) {
|
||||
let converted: i32 = sepimportpathfromrelative(rel,
|
||||
out, outsz);
|
||||
if (converted < 0) {
|
||||
cerr("ww: package path is too long (limit 255 bytes)\n");
|
||||
return -1;
|
||||
};
|
||||
if (converted < 0) { return -1; };
|
||||
if (converted > 0 && reservedimportpath(out)) {
|
||||
converted = 0;
|
||||
};
|
||||
@@ -1981,12 +2040,14 @@ fn sepfinalizedirectoryidentities(g: *sepgraph) i32 = {
|
||||
let ci: i32 = 0;
|
||||
for (ci < g.ncontext) {
|
||||
if (p.contextstate[ci] == 2u8) {
|
||||
let candidate: [256]u8;
|
||||
let candidatesz: u64 = cstrlen(p.canon) + 1u64;
|
||||
let candidate: []u8 = alloc([], candidatesz)!;
|
||||
candidate.len = candidatesz: i32;
|
||||
let found: i32 = sepreverseimportbase(g, p, ci,
|
||||
&candidate[0], 256u64);
|
||||
candidate.ptr, candidatesz);
|
||||
if (found < 0) { return -1; };
|
||||
if (found > 0 && sepbindimportbase(g, pi,
|
||||
&candidate[0]) < 0) { return -1; };
|
||||
candidate.ptr) < 0) { return -1; };
|
||||
};
|
||||
ci += 1;
|
||||
};
|
||||
@@ -2014,10 +2075,7 @@ fn sepfinalizedirectoryidentities(g: *sepgraph) i32 = {
|
||||
};
|
||||
if (base == nil) {
|
||||
base = seplocalimportbase(p);
|
||||
if (base == nil || cstrlen(base) >= 256u64) {
|
||||
cerr("ww: local package identity is too long (limit 255 bytes)\n");
|
||||
return -1;
|
||||
};
|
||||
if (base == nil) { return -1; };
|
||||
};
|
||||
if (sepbindimportbase(g, pi, base) < 0) { return -1; };
|
||||
};
|
||||
@@ -2353,6 +2411,70 @@ fn filesizenonzero(path: *u8) bool = {
|
||||
return ok;
|
||||
};
|
||||
|
||||
fn sepvalidateunitowner(g: *sepgraph, pi: i32, scratch: *u8) i32 = {
|
||||
let unit: *u8 = sepfname(g, pi, scratch, ".unit.ww");
|
||||
let fi: os.filestat;
|
||||
match (os.lstat(&fi, pathstr(unit))) {
|
||||
case let e: os.oserror => {
|
||||
if ((e: i64) == -2i64) { return 0; };
|
||||
cerr("ww: package storage owner mismatch at ");
|
||||
cerr(pathstr(g.pkg[pi].storage)); cerr(" for ");
|
||||
if (g.pkg[pi].path[0u64] == 0u8) { cerr("(root)"); }
|
||||
else { cerr(pathstr(g.pkg[pi].path)); };
|
||||
cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
case void => void;
|
||||
};
|
||||
let typ: u32 = (fi.mode: u32) & 61440u32;
|
||||
if (typ != os.mode.REG: u32) {
|
||||
cerr("ww: package storage owner mismatch at ");
|
||||
cerr(pathstr(g.pkg[pi].storage)); cerr(" for ");
|
||||
if (g.pkg[pi].path[0u64] == 0u8) { cerr("(root)"); }
|
||||
else { cerr(pathstr(g.pkg[pi].path)); };
|
||||
cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
let buf: *u8;
|
||||
let n: u64;
|
||||
buf, n = slurp(unit);
|
||||
let prefix: str = "//ww:module-reset";
|
||||
let pathn: u64 = cstrlen(g.pkg[pi].path);
|
||||
let want: u64 = prefix.len: u64 + 1u64;
|
||||
if (pathn > 0u64) { want += 1u64 + pathn; };
|
||||
let matches: bool = buf != nil && n >= want
|
||||
&& bytecmp(buf, prefix.len: u64, prefix.ptr,
|
||||
prefix.len: u64) == 0;
|
||||
if (matches) {
|
||||
let off: u64 = prefix.len: u64;
|
||||
if (pathn == 0u64) {
|
||||
matches = buf[off] == ('\n': u8);
|
||||
} else {
|
||||
matches = buf[off] == (' ': u8)
|
||||
&& bytecmp(buf + off + 1u64, pathn,
|
||||
g.pkg[pi].path, pathn) == 0
|
||||
&& buf[off + 1u64 + pathn] == ('\n': u8);
|
||||
};
|
||||
};
|
||||
if (matches) { return 1; };
|
||||
cerr("ww: package storage owner mismatch at ");
|
||||
cerr(pathstr(g.pkg[pi].storage)); cerr(" for ");
|
||||
if (pathn == 0u64) { cerr("(root)"); }
|
||||
else { cerr(pathstr(g.pkg[pi].path)); };
|
||||
cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
|
||||
fn sepvalidateworkdirowners(g: *sepgraph, scratch: *u8) i32 = {
|
||||
let i: i32 = 0;
|
||||
for (i < g.n) {
|
||||
if (!g.pkg[i].failed && g.pkg[i].loaded
|
||||
&& sepvalidateunitowner(g, i, scratch) < 0) { return -1; };
|
||||
i += 1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Byte equality of two files; absence or IO error is inequality.
|
||||
fn fileequal(a: *u8, b: *u8) bool = {
|
||||
let fa: i32 = os.open(pathstr(a), os.flag.RDONLY, 0i32);
|
||||
@@ -2423,14 +2545,14 @@ fn copyfileatomic(src: *u8, dst: *u8) i32 = {
|
||||
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
||||
if (istest != 0) {
|
||||
if (emitasm != 0) {
|
||||
return "ww workdir fmt 9 mode test asm 1\n";
|
||||
return "ww workdir fmt 11 mode test asm 1\n";
|
||||
};
|
||||
return "ww workdir fmt 9 mode test asm 0\n";
|
||||
return "ww workdir fmt 11 mode test asm 0\n";
|
||||
};
|
||||
if (emitasm != 0) {
|
||||
return "ww workdir fmt 8 mode build asm 1\n";
|
||||
return "ww workdir fmt 10 mode build asm 1\n";
|
||||
};
|
||||
return "ww workdir fmt 8 mode build asm 0\n";
|
||||
return "ww workdir fmt 10 mode build asm 0\n";
|
||||
};
|
||||
|
||||
fn stampmatches(path: *u8, want: str) bool = {
|
||||
@@ -2595,20 +2717,18 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
};
|
||||
};
|
||||
|
||||
let stem: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
stem.len = os.PATH_MAX;
|
||||
let stem: *u8 = nil;
|
||||
if (entryisdir != 0) {
|
||||
let dlen: u64 = cstrlen(srcd.ptr);
|
||||
let bo: u64 = basenameoff(srcd.ptr, dlen);
|
||||
let off: u64 = cstrinto(stem.ptr, 0u64, srcd.ptr);
|
||||
stem[off] = 47u8; off += 1u64; // '/'
|
||||
let i: u64 = bo;
|
||||
for (i < dlen) { stem[off] = srcd[i]; off += 1u64; i += 1u64; };
|
||||
cstrseal(stem.ptr, off);
|
||||
stem = joinpath(srcd.ptr, srcd.ptr + bo);
|
||||
} else {
|
||||
makestem(stem.ptr, src);
|
||||
let stembuf: []u8 = alloc([], cstrlen(src) + 1u64)!;
|
||||
stembuf.len = (cstrlen(src) + 1u64): i32;
|
||||
makestem(stembuf.ptr, src);
|
||||
stem = stembuf.ptr;
|
||||
};
|
||||
let effstem: *u8 = stem.ptr;
|
||||
let effstem: *u8 = stem;
|
||||
if (objstem != nil) { effstem = objstem; };
|
||||
let warm: bool = false;
|
||||
if (workdir != nil) {
|
||||
@@ -2675,7 +2795,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
if (!fileequal(toola, a6)) { staleall = true; };
|
||||
};
|
||||
};
|
||||
if (staleall && invalidateworkdirunits(scratch) != 0) { return 1; };
|
||||
};
|
||||
|
||||
let rtpaths: []*u8 = alloc([], 2u64)!;
|
||||
@@ -2882,6 +3001,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
};
|
||||
};
|
||||
if (sepvalidateartifactpaths(g, scratch) < 0) { return 1; };
|
||||
if (warm && sepvalidateworkdirowners(g, scratch) < 0) { return 1; };
|
||||
if (warm && staleall && invalidateworkdirunits(scratch) != 0) { return 1; };
|
||||
let rootpackage: bool = packageonly != 0;
|
||||
if (rootpackage && !g.pkg[products[0].root].failed
|
||||
&& cstreqlit(g.pkg[products[0].root].name, "main")) {
|
||||
@@ -3534,8 +3655,14 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let workdir: *u8 = nil; // -w persistent package-artifact workdir
|
||||
let emitasm: i32 = 0;
|
||||
let packageonly: i32 = 0;
|
||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
||||
let inccap: u64 = 1u64;
|
||||
let capi: i32 = start;
|
||||
for (capi < argc) {
|
||||
inccap += cstrlen(argv[capi]) + 1u64;
|
||||
capi += 1;
|
||||
};
|
||||
let incs: []u8 = alloc([], inccap)!;
|
||||
incs.len = inccap: i32;
|
||||
let incoff: u64 = 0u64;
|
||||
cstrseal(incs.ptr, 0u64);
|
||||
|
||||
@@ -3739,8 +3866,14 @@ fn makedrivertmp(buf: *u8, prefix: str) void = {
|
||||
fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let src: *u8 = nil;
|
||||
let passstart: i32 = -1; // first argv idx to pass through to program
|
||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
||||
let inccap: u64 = 1u64;
|
||||
let capi: i32 = start;
|
||||
for (capi < argc) {
|
||||
inccap += cstrlen(argv[capi]) + 1u64;
|
||||
capi += 1;
|
||||
};
|
||||
let incs: []u8 = alloc([], inccap)!;
|
||||
incs.len = inccap: i32;
|
||||
let incoff: u64 = 0u64;
|
||||
cstrseal(incs.ptr, 0u64);
|
||||
|
||||
@@ -4038,8 +4171,14 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
// to the test binary as argv[1] (single-file/module only; dir-mode
|
||||
// rejects). cstage twin: do_test `pattern`.
|
||||
let patarg: *u8 = nil;
|
||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
||||
let inccap: u64 = 1u64;
|
||||
let capi: i32 = start;
|
||||
for (capi < argc) {
|
||||
inccap += cstrlen(argv[capi]) + 1u64;
|
||||
capi += 1;
|
||||
};
|
||||
let incs: []u8 = alloc([], inccap)!;
|
||||
incs.len = inccap: i32;
|
||||
let incoff: u64 = 0u64;
|
||||
cstrseal(incs.ptr, 0u64);
|
||||
|
||||
@@ -4093,7 +4232,7 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
if ((!cstreqlit(kind, "production")
|
||||
&& !cstreqlit(kind, "same")
|
||||
&& !cstreqlit(kind, "external"))
|
||||
|| pn == 0u64 || pn >= 256u64
|
||||
|| pn == 0u64
|
||||
|| dir[0u64] == 0u8 || output[0u64] == 0u8
|
||||
|| status[0u64] == 0u8
|
||||
|| (cstreqlit(kind, "external")
|
||||
|
||||
Reference in New Issue
Block a user