diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-01-10 16:26:27 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-01-11 15:39:49 -0800 |
| commit | a0f2e6a29f4d5c084a248d24b25fae9f30707001 (patch) | |
| tree | 3c65602e4baebd6e11eb797d86039ac256993bcc /src | |
| parent | 876ab99f5c462e93296ef0b2f642ac2243acb31c (diff) | |
| download | zig-a0f2e6a29f4d5c084a248d24b25fae9f30707001.tar.gz zig-a0f2e6a29f4d5c084a248d24b25fae9f30707001.zip | |
Package: complete the package-fetching logic
Diffstat (limited to 'src')
| -rw-r--r-- | src/Package.zig | 145 | ||||
| -rw-r--r-- | src/main.zig | 7 |
2 files changed, 109 insertions, 43 deletions
diff --git a/src/Package.zig b/src/Package.zig index 321743412a..c3a7f645a6 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -6,6 +6,7 @@ const mem = std.mem; const Allocator = mem.Allocator; const assert = std.debug.assert; const Hash = std.crypto.hash.sha2.Sha256; +const log = std.log.scoped(.package); const Compilation = @import("Compilation.zig"); const Module = @import("Module.zig"); @@ -128,6 +129,9 @@ pub fn addAndAdopt(parent: *Package, gpa: Allocator, name: []const u8, child: *P return parent.add(gpa, name, child); } +pub const build_zig_basename = "build.zig"; +pub const ini_basename = build_zig_basename ++ ".ini"; + pub fn fetchAndAddDependencies( pkg: *Package, thread_pool: *ThreadPool, @@ -138,7 +142,7 @@ pub fn fetchAndAddDependencies( ) !void { const max_bytes = 10 * 1024 * 1024; const gpa = thread_pool.allocator; - const build_zig_ini = directory.handle.readFileAlloc(gpa, "build.zig.ini", max_bytes) catch |err| switch (err) { + const build_zig_ini = directory.handle.readFileAlloc(gpa, ini_basename, max_bytes) catch |err| switch (err) { error.FileNotFound => { // Handle the same as no dependencies. return; @@ -154,7 +158,7 @@ pub fn fetchAndAddDependencies( var line_it = mem.split(u8, dep, "\n"); var opt_id: ?[]const u8 = null; var opt_url: ?[]const u8 = null; - var expected_hash: ?[Hash.digest_length]u8 = null; + var expected_hash: ?[]const u8 = null; while (line_it.next()) |kv| { const eq_pos = mem.indexOfScalar(u8, kv, '=') orelse continue; const key = kv[0..eq_pos]; @@ -164,8 +168,7 @@ pub fn fetchAndAddDependencies( } else if (mem.eql(u8, key, "url")) { opt_url = value; } else if (mem.eql(u8, key, "hash")) { - @panic("TODO parse hex digits of value into expected_hash"); - //expected_hash = value; + expected_hash = value; } else { const loc = std.zig.findLineColumn(ini.bytes, @ptrToInt(key.ptr) - @ptrToInt(ini.bytes.ptr)); std.log.warn("{s}/{s}:{d}:{d} unrecognized key: '{s}'", .{ @@ -208,6 +211,8 @@ pub fn fetchAndAddDependencies( global_cache_directory, url, expected_hash, + ini, + directory, ); try sub_pkg.fetchAndAddDependencies( @@ -229,17 +234,48 @@ fn fetchAndUnpack( http_client: *std.http.Client, global_cache_directory: Compilation.Directory, url: []const u8, - expected_hash: ?[Hash.digest_length]u8, + expected_hash: ?[]const u8, + ini: std.Ini, + comp_directory: Compilation.Directory, ) !*Package { const gpa = http_client.allocator; + const s = fs.path.sep_str; // Check if the expected_hash is already present in the global package // cache, and thereby avoid both fetching and unpacking. - const s = fs.path.sep_str; - if (expected_hash) |h| { - const pkg_dir_sub_path = "p" ++ s ++ hexDigest(h); - _ = pkg_dir_sub_path; - @panic("TODO check the p dir for the package"); + if (expected_hash) |h| cached: { + if (h.len != 2 * Hash.digest_length) { + return reportError( + ini, + comp_directory, + h.ptr, + "wrong hash size. expected: {d}, found: {d}", + .{ Hash.digest_length, h.len }, + ); + } + const hex_digest = h[0 .. 2 * Hash.digest_length]; + const pkg_dir_sub_path = "p" ++ s ++ hex_digest; + var pkg_dir = global_cache_directory.handle.openDir(pkg_dir_sub_path, .{}) catch |err| switch (err) { + error.FileNotFound => break :cached, + else => |e| return e, + }; + errdefer pkg_dir.close(); + + const ptr = try gpa.create(Package); + errdefer gpa.destroy(ptr); + + const owned_src_path = try gpa.dupe(u8, build_zig_basename); + errdefer gpa.free(owned_src_path); + + ptr.* = .{ + .root_src_directory = .{ + .path = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path}), + .handle = pkg_dir, + }, + .root_src_directory_owned = true, + .root_src_path = owned_src_path, + }; + return ptr; } const uri = try std.Uri.parse(url); @@ -277,9 +313,13 @@ fn fetchAndUnpack( .strip_components = 1, }); } else { - // TODO: show the build.zig.ini file and line number - std.log.err("{s}: unknown package extension for path '{s}'", .{ url, uri.path }); - return error.UnknownPackageExtension; + return reportError( + ini, + comp_directory, + uri.path.ptr, + "unknown file extension for path '{s}'", + .{uri.path}, + ); } // TODO: delete files not included in the package prior to computing the package hash. @@ -287,24 +327,13 @@ fn fetchAndUnpack( // apply those rules directly to the filesystem right here. This ensures that files // not protected by the hash are not present on the file system. - const actual_hash = try computePackageHash(thread_pool, .{ .dir = tmp_directory.handle }); - - if (expected_hash) |h| { - if (!mem.eql(u8, &h, &actual_hash)) { - // TODO: show the build.zig.ini file and line number - std.log.err("{s}: hash mismatch: expected: {s}, actual: {s}", .{ - url, h, actual_hash, - }); - return error.PackageHashMismatch; - } - } - - break :a actual_hash; + break :a try computePackageHash(thread_pool, .{ .dir = tmp_directory.handle }); }; + const pkg_dir_sub_path = "p" ++ s ++ hexDigest(actual_hash); + { // Rename the temporary directory into the global package cache. - const pkg_dir_sub_path = "p" ++ s ++ hexDigest(actual_hash); var handled_missing_dir = false; while (true) { global_cache_directory.handle.rename(tmp_dir_sub_path, pkg_dir_sub_path) catch |err| switch (err) { @@ -316,27 +345,60 @@ fn fetchAndUnpack( }; continue; }, + error.PathAlreadyExists => { + // Package has been already downloaded and may already be in use on the system. + global_cache_directory.handle.deleteTree(tmp_dir_sub_path) catch |del_err| { + std.log.warn("unable to delete temp directory: {s}", .{@errorName(del_err)}); + }; + }, else => |e| return e, }; break; } } - if (expected_hash == null) { - // TODO: show the build.zig.ini file and line number - std.log.err("{s}: missing hash:\nhash={s}", .{ - url, std.fmt.fmtSliceHexLower(&actual_hash), - }); - return error.PackageDependencyMissingHash; + if (expected_hash) |h| { + const actual_hex = hexDigest(actual_hash); + if (!mem.eql(u8, h, &actual_hex)) { + return reportError( + ini, + comp_directory, + h.ptr, + "hash mismatch: expected: {s}, found: {s}", + .{ h, actual_hex }, + ); + } + } else { + return reportError( + ini, + comp_directory, + url.ptr, + "url field is missing corresponding hash field: hash={s}", + .{std.fmt.fmtSliceHexLower(&actual_hash)}, + ); } - @panic("TODO create package and set root_src_directory"); - //return create(gpa, root_src - //gpa: Allocator, - ///// Null indicates the current working directory - //root_src_dir_path: ?[]const u8, - ///// Relative to root_src_dir_path - //root_src_path: []const u8, + return createWithDir(gpa, global_cache_directory, pkg_dir_sub_path, build_zig_basename); +} + +fn reportError( + ini: std.Ini, + comp_directory: Compilation.Directory, + src_ptr: [*]const u8, + comptime fmt_string: []const u8, + fmt_args: anytype, +) error{PackageFetchFailed} { + const loc = std.zig.findLineColumn(ini.bytes, @ptrToInt(src_ptr) - @ptrToInt(ini.bytes.ptr)); + if (comp_directory.path) |p| { + std.debug.print("{s}{c}{s}:{d}:{d}: error: " ++ fmt_string ++ "\n", .{ + p, fs.path.sep, ini_basename, loc.line + 1, loc.column + 1, + } ++ fmt_args); + } else { + std.debug.print("{s}:{d}:{d}: error: " ++ fmt_string ++ "\n", .{ + ini_basename, loc.line + 1, loc.column + 1, + } ++ fmt_args); + } + return error.PackageFetchFailed; } const HashedFile = struct { @@ -389,9 +451,10 @@ fn computePackageHash( .hash = undefined, // to be populated by the worker .failure = undefined, // to be populated by the worker }; - wait_group.start(); try thread_pool.spawn(workerHashFile, .{ pkg_dir.dir, hashed_file, &wait_group }); + + try all_files.append(hashed_file); } } diff --git a/src/main.zig b/src/main.zig index d0052b518b..739f8093e1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4088,13 +4088,16 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi defer http_client.deinit(); try http_client.rescanRootCertificates(); - try main_pkg.fetchAndAddDependencies( + main_pkg.fetchAndAddDependencies( &thread_pool, &http_client, build_directory, global_cache_directory, local_cache_directory, - ); + ) catch |err| switch (err) { + error.PackageFetchFailed => process.exit(1), + else => |e| return e, + }; } const comp = Compilation.create(gpa, .{ |
