authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-04 17:40:54-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-05 16:50:41-08:00
logdf64a3a36815fce6cc8671d047e52795655b3b9b
tree7df6db2ef13dc4fee6a0691a383f0c829ec62a7b
parent64dc1cdad8faf1fd8330d4b0f9149817b5205abf

build: packages now require fingerprint

also the name must be an enum literal. delete some .tar.gz test data. Test data should be in text form when it can be, and this could definitely be.

6 files changed, 7 insertions(+), 163 deletions(-)

src/Package/Fetch.zig-132
......@@ -60,8 +60,6 @@ omit_missing_hash_error: bool,
6060/// which specifies inclusion rules. This is intended to be true for the first
6161/// fetch task and false for the recursive dependencies.
6262allow_missing_paths_field: bool,
63allow_missing_fingerprint: bool,
64allow_name_string: bool,
6563/// If true and URL points to a Git repository, will use the latest commit.
6664use_latest_commit: bool,
6765
......@@ -675,8 +673,6 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void {
675673
676674 f.manifest = try Manifest.parse(arena, ast.*, rng.interface(), .{
677675 .allow_missing_paths_field = f.allow_missing_paths_field,
678 .allow_missing_fingerprint = f.allow_missing_fingerprint,
679 .allow_name_string = f.allow_name_string,
680676 });
681677 const manifest = &f.manifest.?;
682678
......@@ -794,8 +790,6 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
794790 .job_queue = f.job_queue,
795791 .omit_missing_hash_error = false,
796792 .allow_missing_paths_field = true,
797 .allow_missing_fingerprint = true,
798 .allow_name_string = true,
799793 .use_latest_commit = false,
800794
801795 .package_root = undefined,
......@@ -2049,130 +2043,6 @@ const UnpackResult = struct {
20492043 }
20502044};
20512045
2052test "tarball with duplicate paths" {
2053 // This tarball has duplicate path 'dir1/file1' to simulate case sensitve
2054 // file system on any file sytstem.
2055 //
2056 // duplicate_paths/
2057 // duplicate_paths/dir1/
2058 // duplicate_paths/dir1/file1
2059 // duplicate_paths/dir1/file1
2060 // duplicate_paths/build.zig.zon
2061 // duplicate_paths/src/
2062 // duplicate_paths/src/main.zig
2063 // duplicate_paths/src/root.zig
2064 // duplicate_paths/build.zig
2065 //
2066
2067 const gpa = std.testing.allocator;
2068 const io = std.testing.io;
2069 var tmp = std.testing.tmpDir(.{});
2070 defer tmp.cleanup();
2071
2072 const tarball_name = "duplicate_paths.tar.gz";
2073 try saveEmbedFile(io, tarball_name, tmp.dir);
2074 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
2075 defer gpa.free(tarball_path);
2076
2077 // Run tarball fetch, expect to fail
2078 var fb: TestFetchBuilder = undefined;
2079 var fetch = try fb.build(gpa, io, tmp.dir, tarball_path);
2080 defer fb.deinit();
2081 try std.testing.expectError(error.FetchFailed, fetch.run());
2082
2083 try fb.expectFetchErrors(1,
2084 \\error: unable to unpack tarball
2085 \\ note: unable to create file 'dir1/file1': PathAlreadyExists
2086 \\
2087 );
2088}
2089
2090test "tarball with excluded duplicate paths" {
2091 // Same as previous tarball but has build.zig.zon wich excludes 'dir1'.
2092 //
2093 // .paths = .{
2094 // "build.zig",
2095 // "build.zig.zon",
2096 // "src",
2097 // }
2098 //
2099
2100 const gpa = std.testing.allocator;
2101 const io = std.testing.io;
2102 var tmp = std.testing.tmpDir(.{});
2103 defer tmp.cleanup();
2104
2105 const tarball_name = "duplicate_paths_excluded.tar.gz";
2106 try saveEmbedFile(io, tarball_name, tmp.dir);
2107 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
2108 defer gpa.free(tarball_path);
2109
2110 // Run tarball fetch, should succeed
2111 var fb: TestFetchBuilder = undefined;
2112 var fetch = try fb.build(gpa, io, tmp.dir, tarball_path);
2113 defer fb.deinit();
2114 try fetch.run();
2115
2116 const hex_digest = Package.multiHashHexDigest(fetch.computed_hash.digest);
2117 try std.testing.expectEqualStrings(
2118 "12200bafe035cbb453dd717741b66e9f9d1e6c674069d06121dafa1b2e62eb6b22da",
2119 &hex_digest,
2120 );
2121
2122 const expected_files: []const []const u8 = &.{
2123 "build.zig",
2124 "build.zig.zon",
2125 "src/main.zig",
2126 "src/root.zig",
2127 };
2128 try fb.expectPackageFiles(expected_files);
2129}
2130
2131test "tarball without root folder" {
2132 // Tarball with root folder. Manifest excludes dir1 and dir2.
2133 //
2134 // build.zig
2135 // build.zig.zon
2136 // dir1/
2137 // dir1/file2
2138 // dir1/file1
2139 // dir2/
2140 // dir2/file2
2141 // src/
2142 // src/main.zig
2143 //
2144
2145 const gpa = std.testing.allocator;
2146 const io = std.testing.io;
2147
2148 var tmp = std.testing.tmpDir(.{});
2149 defer tmp.cleanup();
2150
2151 const tarball_name = "no_root.tar.gz";
2152 try saveEmbedFile(io, tarball_name, tmp.dir);
2153 const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
2154 defer gpa.free(tarball_path);
2155
2156 // Run tarball fetch, should succeed
2157 var fb: TestFetchBuilder = undefined;
2158 var fetch = try fb.build(gpa, io, tmp.dir, tarball_path);
2159 defer fb.deinit();
2160 try fetch.run();
2161
2162 const hex_digest = Package.multiHashHexDigest(fetch.computed_hash.digest);
2163 try std.testing.expectEqualStrings(
2164 "12209f939bfdcb8b501a61bb4a43124dfa1b2848adc60eec1e4624c560357562b793",
2165 &hex_digest,
2166 );
2167
2168 const expected_files: []const []const u8 = &.{
2169 "build.zig",
2170 "build.zig.zon",
2171 "src/main.zig",
2172 };
2173 try fb.expectPackageFiles(expected_files);
2174}
2175
21762046test "set executable bit based on file content" {
21772047 if (!Io.File.Permissions.has_executable_bit) return error.SkipZigTest;
21782048 const gpa = std.testing.allocator;
......@@ -2288,8 +2158,6 @@ const TestFetchBuilder = struct {
22882158 .job_queue = &self.job_queue,
22892159 .omit_missing_hash_error = true,
22902160 .allow_missing_paths_field = false,
2291 .allow_missing_fingerprint = true, // so we can keep using the old testdata .tar.gz
2292 .allow_name_string = true, // so we can keep using the old testdata .tar.gz
22932161 .use_latest_commit = true,
22942162
22952163 .package_root = undefined,
src/Package/Fetch/testdata/duplicate_paths.tar.gz deleted
Binary files a/src/Package/Fetch/testdata/duplicate_paths.tar.gz and /dev/null differ
src/Package/Fetch/testdata/duplicate_paths_excluded.tar.gz deleted
Binary files a/src/Package/Fetch/testdata/duplicate_paths_excluded.tar.gz and /dev/null differ
src/Package/Fetch/testdata/no_root.tar.gz deleted
Binary files a/src/Package/Fetch/testdata/no_root.tar.gz and /dev/null differ
src/Package/Manifest.zig+7-27
......@@ -49,10 +49,6 @@ arena_state: std.heap.ArenaAllocator.State,
4949
5050pub const ParseOptions = struct {
5151 allow_missing_paths_field: bool = false,
52 /// Deprecated, to be removed after 0.14.0 is tagged.
53 allow_name_string: bool = true,
54 /// Deprecated, to be removed after 0.14.0 is tagged.
55 allow_missing_fingerprint: bool = true,
5652};
5753
5854pub const Error = Allocator.Error;
......@@ -77,8 +73,6 @@ pub fn parse(gpa: Allocator, ast: Ast, rng: std.Random, options: ParseOptions) E
7773 .dependencies_node = .none,
7874 .paths = .{},
7975 .allow_missing_paths_field = options.allow_missing_paths_field,
80 .allow_name_string = options.allow_name_string,
81 .allow_missing_fingerprint = options.allow_missing_fingerprint,
8276 .minimum_zig_version = null,
8377 .buf = .{},
8478 };
......@@ -151,8 +145,6 @@ const Parse = struct {
151145 dependencies_node: Ast.Node.OptionalIndex,
152146 paths: std.StringArrayHashMapUnmanaged(void),
153147 allow_missing_paths_field: bool,
154 allow_name_string: bool,
155 allow_missing_fingerprint: bool,
156148 minimum_zig_version: ?std.SemanticVersion,
157149
158150 const InnerError = error{ ParseFailure, OutOfMemory };
......@@ -221,12 +213,10 @@ const Parse = struct {
221213 });
222214 }
223215 p.id = n.id;
224 } else if (!p.allow_missing_fingerprint) {
216 } else {
225217 try appendError(p, main_token, "missing top-level 'fingerprint' field; suggested value: 0x{x}", .{
226218 Package.Fingerprint.generate(rng, p.name).int(),
227219 });
228 } else {
229 p.id = 0;
230220 }
231221 }
232222
......@@ -395,19 +385,6 @@ const Parse = struct {
395385 const ast = p.ast;
396386 const main_token = ast.nodeMainToken(node);
397387
398 if (p.allow_name_string and ast.nodeTag(node) == .string_literal) {
399 const name = try parseString(p, node);
400 if (!std.zig.isValidId(name))
401 return fail(p, main_token, "name must be a valid bare zig identifier (hint: switch from string to enum literal)", .{});
402
403 if (name.len > max_name_len)
404 return fail(p, main_token, "name '{f}' exceeds max length of {d}", .{
405 std.zig.fmtId(name), max_name_len,
406 });
407
408 return name;
409 }
410
411388 if (ast.nodeTag(node) != .enum_literal)
412389 return fail(p, main_token, "expected enum literal", .{});
413390
......@@ -606,7 +583,8 @@ test "basic" {
606583
607584 const example =
608585 \\.{
609 \\ .name = "foo",
586 \\ .name = .foo,
587 \\ .fingerprint = 0x8c736521490b23df,
610588 \\ .version = "3.2.1",
611589 \\ .paths = .{""},
612590 \\ .dependencies = .{
......@@ -656,7 +634,8 @@ test "minimum_zig_version" {
656634
657635 const example =
658636 \\.{
659 \\ .name = "foo",
637 \\ .name = .foo,
638 \\ .fingerprint = 0x8c736521490b23df,
660639 \\ .version = "3.2.1",
661640 \\ .paths = .{""},
662641 \\ .minimum_zig_version = "0.11.1",
......@@ -690,7 +669,8 @@ test "minimum_zig_version - invalid version" {
690669
691670 const example =
692671 \\.{
693 \\ .name = "foo",
672 \\ .name = .foo,
673 \\ .fingerprint = 0x8c736521490b23df,
694674 \\ .version = "3.2.1",
695675 \\ .minimum_zig_version = "X.11.1",
696676 \\ .paths = .{""},
src/main.zig-4
......@@ -5285,8 +5285,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8,
52855285 .job_queue = &job_queue,
52865286 .omit_missing_hash_error = true,
52875287 .allow_missing_paths_field = false,
5288 .allow_missing_fingerprint = false,
5289 .allow_name_string = false,
52905288 .use_latest_commit = false,
52915289
52925290 .package_root = undefined,
......@@ -7044,8 +7042,6 @@ fn cmdFetch(
70447042 .job_queue = &job_queue,
70457043 .omit_missing_hash_error = true,
70467044 .allow_missing_paths_field = false,
7047 .allow_missing_fingerprint = true,
7048 .allow_name_string = true,
70497045 .use_latest_commit = true,
70507046
70517047 .package_root = undefined,