diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index 6e7469425bce..f2dd4380e617 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -277,7 +277,7 @@ pub const Location = union(enum) { /// URL, or a directory, in which case it should be treated as an /// already-unpacked directory (but still needs to be copied into the /// global package cache and have inclusion rules applied). - path_or_url: []const u8, + local_or_remote: Remote, pub const Remote = struct { url: []const u8, @@ -342,27 +342,26 @@ pub fn run(f: *Fetch) RunError!void { return queueJobsForDeps(f); }, .remote => |remote| remote, - .path_or_url => |path_or_url| { - if (fs.cwd().openDir(path_or_url, .{ .iterate = true })) |dir| { + .local_or_remote => |remote| blk: { + // Here, remote.url could be either a local path or an url. Try the path first. + if (fs.cwd().openDir(remote.url, .{ .iterate = true })) |dir| { var resource: Resource = .{ .dir = dir }; - return f.runResource(path_or_url, &resource, null); + return f.runResource(remote.url, &resource, remote.hash); } else |dir_err| { const file_err = if (dir_err == error.NotDir) e: { - if (fs.cwd().openFile(path_or_url, .{})) |file| { + if (fs.cwd().openFile(remote.url, .{})) |file| { var resource: Resource = .{ .file = file }; - return f.runResource(path_or_url, &resource, null); + return f.runResource(remote.url, &resource, remote.hash); } else |err| break :e err; } else dir_err; - const uri = std.Uri.parse(path_or_url) catch |uri_err| { + _ = std.Uri.parse(remote.url) catch |uri_err| { return f.fail(0, try eb.printString( "'{s}' could not be recognized as a file path ({s}) or an URL ({s})", - .{ path_or_url, @errorName(file_err), @errorName(uri_err) }, + .{ remote.url, @errorName(file_err), @errorName(uri_err) }, )); }; - var server_header_buffer: [header_buffer_size]u8 = undefined; - var resource = try f.initResource(uri, &server_header_buffer); - return f.runResource(try uri.path.toRawMaybeAlloc(arena), &resource, null); + break :blk remote; } }, }; diff --git a/src/main.zig b/src/main.zig index 0d833e550521..82fe62b9f45d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6968,10 +6968,10 @@ fn parseRcIncludes(arg: []const u8) Compilation.RcIncludes { } const usage_fetch = - \\Usage: zig fetch [options] - \\Usage: zig fetch [options] + \\Usage: zig fetch [options] [hash] + \\Usage: zig fetch [options] [hash] \\ - \\ Copy a package into the global cache and print its hash. + \\ Copy a package into the global cache, print, and optionally verify its hash. \\ \\Options: \\ -h, --help Print this help and exit @@ -6995,6 +6995,7 @@ fn cmdFetch( const work_around_btrfs_bug = native_os == .linux and EnvVar.ZIG_BTRFS_WORKAROUND.isSet(); var opt_path_or_url: ?[]const u8 = null; + var opt_hash: ?Package.Manifest.MultiHashHexDigest = null; var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena); var debug_hash: bool = false; var save: union(enum) { @@ -7029,11 +7030,16 @@ fn cmdFetch( } else { fatal("unrecognized parameter: '{s}'", .{arg}); } - } else if (opt_path_or_url != null) { - fatal("unexpected extra parameter: '{s}'", .{arg}); - } else { + } else if (opt_path_or_url == null) { opt_path_or_url = arg; - } + } else if (opt_hash == null) { + if (arg.len != Package.Manifest.multihash_hex_digest_len) { + fatal("wrong hash size. expected: {d}, found: {d}", .{ + Package.Manifest.multihash_hex_digest_len, arg, + }); + } + opt_hash = arg[0..Package.Manifest.multihash_hex_digest_len].*; + } else fatal("unexpected extra parameter: '{s}'", .{arg}); } } @@ -7075,7 +7081,10 @@ fn cmdFetch( var fetch: Package.Fetch = .{ .arena = std.heap.ArenaAllocator.init(gpa), - .location = .{ .path_or_url = path_or_url }, + .location = .{ .local_or_remote = .{ + .url = path_or_url, + .hash = opt_hash, + } }, .location_tok = 0, .hash_tok = 0, .name_tok = 0, @@ -7112,7 +7121,7 @@ fn cmdFetch( process.exit(1); } - const hex_digest = Package.Manifest.hexDigest(fetch.actual_hash); + const hex_digest = opt_hash orelse Package.Manifest.hexDigest(fetch.actual_hash); root_prog_node.end(); root_prog_node = .{ .index = .none };