authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-15 18:39:10+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-15 20:20:58+02:00
logab4f45bf9a9fc0c028dd87eecefe4073c40ae24a
treeebcdaa05f20a1b42d553da711f3099eb5a09527d
parentb9ea8ac3d350a7461b110946bfc6dd02465d3eee
signature Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

Merge pull request '`--fork` fixes' (#37241) from fix-fork into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37241

2 files changed, 94 insertions(+), 22 deletions(-)

lib/compiler/Maker.zig+77-15
......@@ -1385,7 +1385,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
13851385 printPkgTree(.{
13861386 .writer = initStdoutWriter(io),
13871387 .mode = try .detect(io, .stdout(), NO_COLOR, CLICOLOR_FORCE),
1388 }, arena, &job_queue, &fetch) catch |err| switch (err) {
1388 }, arena, graph.global_cache_root, &job_queue, &fetch, &fork_set) catch |err| switch (err) {
13891389 error.WriteFailed => return stdout_writer_allocation.err.?,
13901390 else => |e| return e,
13911391 };
......@@ -1398,7 +1398,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
13981398 process.exit(0);
13991399 }
14001400
1401 try validateFingerprints(gpa, &job_queue);
1401 try validateFingerprints(gpa, &job_queue, &fork_set);
14021402
14031403 // Create the dependencies.zig file for configurer to
14041404 // obtain via `@import("@dependencies")`.
......@@ -1444,10 +1444,29 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
14441444 // The first one is a dummy package for the current project.
14451445 continue;
14461446 }
1447 if (!f.has_build_zig)
1448 continue;
1447 if (!f.has_build_zig) continue;
1448
1449 if (f.have_manifest) {
1450 const project_id: Package.ProjectId = .init(f.manifest.name, f.manifest.id);
1451 if (fork_set.getKeyPtrAdapted(project_id, @as(Fetch.JobQueue.Fork.Adapter, .{}))) |fork| {
1452 const path = try fork.path.toString(arena);
1453 const gop = deps_mod.deps.getOrPutAssumeCapacity(path);
1454 if (gop.found_existing) {
1455 assert(fork.uses > 1);
1456 f.cli_module = gop.value_ptr.*;
1457 } else {
1458 const m = try arena.create(CliModule);
1459 m.* = .{
1460 .root_path = try f.package_root.toString(arena),
1461 .name = path,
1462 };
1463 gop.value_ptr.* = m;
1464 f.cli_module = m;
1465 }
1466 continue;
1467 }
1468 }
14491469 const hash_slice = try arena.dupe(u8, hash.toSlice());
1450
14511470 const m = try arena.create(CliModule);
14521471 m.* = .{
14531472 .root_path = try f.package_root.toString(arena),
......@@ -1469,7 +1488,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
14691488 const man = &f.manifest;
14701489 const dep_names = man.dependencies.keys();
14711490 try mod.deps.ensureUnusedCapacity(arena, @intCast(dep_names.len));
1472 for (dep_names, man.dependencies.values()) |name, dep| {
1491 for (dep_names, man.dependencies.values()) |name, *dep| {
14731492 const dep_digest = Package.Fetch.depDigest(
14741493 f.package_root,
14751494 graph.global_cache_root,
......@@ -1749,7 +1768,11 @@ const ValidFingerprintTable = std.array_hash_map.Custom(
17491768
17501769/// Ensure that the dependency tree did not have any fingerprint matches with the same semantic version but
17511770/// differing package hashes.
1752fn validateFingerprints(gpa: Allocator, job_queue: *const Fetch.JobQueue) !void {
1771fn validateFingerprints(
1772 gpa: Allocator,
1773 job_queue: *const Fetch.JobQueue,
1774 fork_set: *const Package.Fetch.JobQueue.ForkSet,
1775) !void {
17531776 var any_errors = false;
17541777
17551778 var table: ValidFingerprintTable = .empty;
......@@ -1757,8 +1780,13 @@ fn validateFingerprints(gpa: Allocator, job_queue: *const Fetch.JobQueue) !void
17571780
17581781 for (job_queue.table.keys(), job_queue.table.values()) |pkg_hash, fetch| {
17591782 if (!fetch.have_manifest) continue;
1783
1784 // Forked packages are exempt since they overide multiple package hashes to have the forked contents.
1785 const project_id: Package.ProjectId = .init(fetch.manifest.name, fetch.manifest.id);
1786 if (fork_set.containsAdapted(project_id, @as(Fetch.JobQueue.Fork.Adapter, .{}))) continue;
1787
17601788 const gop = try table.getOrPut(gpa, .{
1761 .project_id = .init(fetch.manifest.name, fetch.manifest.id),
1789 .project_id = project_id,
17621790 .version = fetch.manifest.version,
17631791 });
17641792 if (gop.found_existing) {
......@@ -1795,8 +1823,10 @@ fn validateFingerprints(gpa: Allocator, job_queue: *const Fetch.JobQueue) !void
17951823fn printPkgTree(
17961824 terminal: Io.Terminal,
17971825 arena: Allocator,
1826 global_cache_root: Cache.Directory,
17981827 job_queue: *const Fetch.JobQueue,
17991828 root_fetch: *const Fetch,
1829 fork_set: *const Package.Fetch.JobQueue.ForkSet,
18001830) !void {
18011831 if (!root_fetch.have_manifest) return;
18021832 const names = root_fetch.manifest.dependencies.keys();
......@@ -1805,37 +1835,49 @@ fn printPkgTree(
18051835 .parent = null,
18061836 .last = i == names.len - 1,
18071837 };
1808 try printPkgTreeChild(terminal, arena, job_queue, &print_node, name, dep.hash);
1838 switch (dep.location) {
1839 .url => {
1840 const child_hash = if (dep.hash) |h| Package.Hash.fromSlice(h) else null;
1841 try printPkgTreeChild(terminal, arena, global_cache_root, job_queue, &print_node, name, child_hash, fork_set);
1842 },
1843 .path => {
1844 const child_hash = Package.Fetch.depDigest(root_fetch.package_root, global_cache_root, dep);
1845 try printPkgTreeChild(terminal, arena, global_cache_root, job_queue, &print_node, name, child_hash, fork_set);
1846 },
1847 }
18091848 }
18101849}
18111850
18121851fn printPkgTreeChild(
18131852 terminal: Io.Terminal,
18141853 arena: Allocator,
1854 global_cache_root: Cache.Directory,
18151855 job_queue: *const Fetch.JobQueue,
18161856 parent_print_node: *const PrintNode,
18171857 dep_name: []const u8,
1818 opt_hash: ?[]const u8,
1858 opt_pkg_hash: ?Package.Hash,
1859 fork_set: *const Package.Fetch.JobQueue.ForkSet,
18191860) !void {
18201861 const w = terminal.writer;
18211862 try parent_print_node.printPrefixedChild(w, terminal.mode);
18221863 try w.writeAll(dep_name);
18231864
1824 const hash = opt_hash orelse {
1865 const pkg_hash = opt_pkg_hash orelse {
18251866 try terminal.setColor(.red);
18261867 try w.writeAll(" (missing hash)\n");
18271868 try terminal.setColor(.reset);
18281869 return;
18291870 };
18301871 try terminal.setColor(.dim);
1831 try w.print(" {s}", .{hash});
1872 try w.print(" {s}", .{pkg_hash.toSlice()});
18321873 try terminal.setColor(.reset);
1833 const child_fetch = job_queue.table.get(.fromSlice(hash)) orelse {
1874 const child_fetch = job_queue.table.get(pkg_hash) orelse {
18341875 try terminal.setColor(.red);
18351876 try w.writeAll(" (fetch failed)\n");
18361877 try terminal.setColor(.reset);
18371878 return;
18381879 };
1880
18391881 switch (child_fetch.lazy_status) {
18401882 .eager, .available => {},
18411883 .unavailable => {
......@@ -1845,8 +1887,19 @@ fn printPkgTreeChild(
18451887 return;
18461888 },
18471889 }
1890 if (!child_fetch.have_manifest) {
1891 try w.writeByte('\n');
1892 return;
1893 }
1894
1895 const project_id: Package.ProjectId = .init(child_fetch.manifest.name, child_fetch.manifest.id);
1896 if (fork_set.getKeyPtrAdapted(project_id, @as(Fetch.JobQueue.Fork.Adapter, .{}))) |fork| {
1897 try terminal.setColor(.yellow);
1898 try w.print(" (fork: {f})", .{fork.path});
1899 try terminal.setColor(.reset);
1900 }
1901
18481902 try w.writeByte('\n');
1849 if (!child_fetch.have_manifest) return;
18501903
18511904 const names = child_fetch.manifest.dependencies.keys();
18521905 for (names, child_fetch.manifest.dependencies.values(), 0..) |name, *dep, i| {
......@@ -1854,7 +1907,16 @@ fn printPkgTreeChild(
18541907 .parent = parent_print_node,
18551908 .last = i == names.len - 1,
18561909 };
1857 try printPkgTreeChild(terminal, arena, job_queue, &print_node, name, dep.hash);
1910 switch (dep.location) {
1911 .url => {
1912 const child_hash = if (dep.hash) |h| Package.Hash.fromSlice(h) else null;
1913 try printPkgTreeChild(terminal, arena, global_cache_root, job_queue, &print_node, name, child_hash, fork_set);
1914 },
1915 .path => {
1916 const child_hash = Package.Fetch.depDigest(child_fetch.package_root, global_cache_root, dep);
1917 try printPkgTreeChild(terminal, arena, global_cache_root, job_queue, &print_node, name, child_hash, fork_set);
1918 },
1919 }
18581920 }
18591921}
18601922
lib/compiler/Maker/Fetch.zig+17-7
......@@ -289,11 +289,21 @@ pub const JobQueue = struct {
289289 \\
290290 , .{std.fmt.alt(fetch.package_root, .formatEscapeString)});
291291
292 if (fetch.has_build_zig) {
292 if (fetch.has_build_zig) b: {
293 if (fetch.have_manifest) {
294 const project_id: Package.ProjectId = .init(fetch.manifest.name, fetch.manifest.id);
295 if (jq.fork_set.getKeyPtrAdapted(project_id, @as(JobQueue.Fork.Adapter, .{}))) |fork| {
296 try w.print(
297 \\ pub const build_zig = @import({qf});
298 \\
299 , .{fork.path});
300 }
301 break :b;
302 }
293303 try w.print(
294 \\ pub const build_zig = @import("{f}");
304 \\ pub const build_zig = @import({q});
295305 \\
296 , .{std.zig.fmtString(hash_slice)});
306 , .{hash_slice});
297307 }
298308
299309 if (fetch.have_manifest) {
......@@ -302,7 +312,7 @@ pub const JobQueue = struct {
302312 \\ pub const deps: []const struct { []const u8, []const u8 } = &.{
303313 \\
304314 );
305 for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, dep| {
315 for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, *dep| {
306316 const h = depDigest(fetch.package_root, jq.global_cache, dep) orelse continue;
307317 try w.print(
308318 " .{{ \"{f}\", \"{f}\" }},\n",
......@@ -335,7 +345,7 @@ pub const JobQueue = struct {
335345 assert(root_fetch.have_manifest);
336346 const root_manifest = &root_fetch.manifest;
337347
338 for (root_manifest.dependencies.keys(), root_manifest.dependencies.values()) |name, dep| {
348 for (root_manifest.dependencies.keys(), root_manifest.dependencies.values()) |name, *dep| {
339349 const h = depDigest(root_fetch.package_root, jq.global_cache, dep) orelse continue;
340350 try w.print(
341351 " .{{ \"{f}\", \"{f}\" }},\n",
......@@ -595,7 +605,7 @@ pub fn run(f: *Fetch) RunError!void {
595605 if (remote.hash) |expected_hash| {
596606 const expected_project_id: Package.ProjectId = expected_hash.projectId();
597607 if (job_queue.fork_set.getKeyPtrAdapted(expected_project_id, @as(JobQueue.Fork.Adapter, .{}))) |fork| {
598 log.debug("using fork {f} for {s}", .{ fork.path, fork.manifest.name });
608 log.debug("using fork {f} for {s}", .{ fork.path, expected_hash.toSlice() });
599609 fork.uses += 1;
600610 f.package_root = fork.path;
601611 f.remote_package_root = f.package_root;
......@@ -2033,7 +2043,7 @@ const Filter = struct {
20332043 }
20342044};
20352045
2036pub fn depDigest(pkg_root: Path, cache_root: Directory, dep: Manifest.Dependency) ?Package.Hash {
2046pub fn depDigest(pkg_root: Path, cache_root: Directory, dep: *const Manifest.Dependency) ?Package.Hash {
20372047 if (dep.hash) |h| return .fromSlice(h);
20382048
20392049 switch (dep.location) {