Skip to content

Commit 8f6b1f2

Browse files
authored
zig fetch: resolve branch/tag names to commit SHA (#19941)
* Revert "Revert "Merge pull request #19349 from nolanderc/save-commit"" This reverts commit 6ca4ed5. * update to new URI changes, rework `--save` type * initialize `latest_commit` to null everywhere
1 parent 86d8688 commit 8f6b1f2

File tree

2 files changed

+63
-9
lines changed

2 files changed

+63
-9
lines changed

src/Package/Fetch.zig

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ omit_missing_hash_error: bool,
4444
/// which specifies inclusion rules. This is intended to be true for the first
4545
/// fetch task and false for the recursive dependencies.
4646
allow_missing_paths_field: bool,
47+
/// If true and URL points to a Git repository, will use the latest commit.
48+
use_latest_commit: bool,
4749

4850
// Above this are fields provided as inputs to `run`.
4951
// Below this are fields populated by `run`.
@@ -59,6 +61,10 @@ actual_hash: Manifest.Digest,
5961
has_build_zig: bool,
6062
/// Indicates whether the task aborted due to an out-of-memory condition.
6163
oom_flag: bool,
64+
/// If `use_latest_commit` was true, this will be set to the commit that was used.
65+
/// If the resource pointed to by the location is not a Git-repository, this
66+
/// will be left unchanged.
67+
latest_commit: ?git.Oid,
6268

6369
// This field is used by the CLI only, untouched by this file.
6470

@@ -699,6 +705,7 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
699705
.job_queue = f.job_queue,
700706
.omit_missing_hash_error = false,
701707
.allow_missing_paths_field = true,
708+
.use_latest_commit = false,
702709

703710
.package_root = undefined,
704711
.error_bundle = undefined,
@@ -707,6 +714,7 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
707714
.actual_hash = undefined,
708715
.has_build_zig = false,
709716
.oom_flag = false,
717+
.latest_commit = null,
710718

711719
.module = null,
712720
};
@@ -994,7 +1002,9 @@ fn initResource(f: *Fetch, uri: std.Uri, server_header_buffer: []u8) RunError!Re
9941002
}
9951003
return f.fail(f.location_tok, try eb.printString("ref not found: {s}", .{want_ref}));
9961004
};
997-
if (uri.fragment == null) {
1005+
if (f.use_latest_commit) {
1006+
f.latest_commit = want_oid;
1007+
} else if (uri.fragment == null) {
9981008
const notes_len = 1;
9991009
try eb.addRootErrorMessage(.{
10001010
.msg = try eb.addString("url field is missing an explicit ref"),

src/main.zig

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5097,6 +5097,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
50975097
.job_queue = &job_queue,
50985098
.omit_missing_hash_error = true,
50995099
.allow_missing_paths_field = false,
5100+
.use_latest_commit = false,
51005101

51015102
.package_root = undefined,
51025103
.error_bundle = undefined,
@@ -5105,6 +5106,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
51055106
.actual_hash = undefined,
51065107
.has_build_zig = true,
51075108
.oom_flag = false,
5109+
.latest_commit = null,
51085110

51095111
.module = build_mod,
51105112
};
@@ -6894,6 +6896,8 @@ const usage_fetch =
68946896
\\ --debug-hash Print verbose hash information to stdout
68956897
\\ --save Add the fetched package to build.zig.zon
68966898
\\ --save=[name] Add the fetched package to build.zig.zon as name
6899+
\\ --save-exact Add the fetched package to build.zig.zon, storing the URL verbatim
6900+
\\ --save-exact=[name] Add the fetched package to build.zig.zon as name, storing the URL verbatim
68976901
\\
68986902
;
68996903

@@ -6908,7 +6912,11 @@ fn cmdFetch(
69086912
var opt_path_or_url: ?[]const u8 = null;
69096913
var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
69106914
var debug_hash: bool = false;
6911-
var save: union(enum) { no, yes, name: []const u8 } = .no;
6915+
var save: union(enum) {
6916+
no,
6917+
yes: ?[]const u8,
6918+
exact: ?[]const u8,
6919+
} = .no;
69126920

69136921
{
69146922
var i: usize = 0;
@@ -6926,9 +6934,13 @@ fn cmdFetch(
69266934
} else if (mem.eql(u8, arg, "--debug-hash")) {
69276935
debug_hash = true;
69286936
} else if (mem.eql(u8, arg, "--save")) {
6929-
save = .yes;
6937+
save = .{ .yes = null };
69306938
} else if (mem.startsWith(u8, arg, "--save=")) {
6931-
save = .{ .name = arg["--save=".len..] };
6939+
save = .{ .yes = arg["--save=".len..] };
6940+
} else if (mem.eql(u8, arg, "--save-exact")) {
6941+
save = .{ .exact = null };
6942+
} else if (mem.startsWith(u8, arg, "--save-exact=")) {
6943+
save = .{ .exact = arg["--save=".len..] };
69326944
} else {
69336945
fatal("unrecognized parameter: '{s}'", .{arg});
69346946
}
@@ -6988,6 +7000,7 @@ fn cmdFetch(
69887000
.job_queue = &job_queue,
69897001
.omit_missing_hash_error = true,
69907002
.allow_missing_paths_field = false,
7003+
.use_latest_commit = true,
69917004

69927005
.package_root = undefined,
69937006
.error_bundle = undefined,
@@ -6996,6 +7009,7 @@ fn cmdFetch(
69967009
.actual_hash = undefined,
69977010
.has_build_zig = false,
69987011
.oom_flag = false,
7012+
.latest_commit = null,
69997013

70007014
.module = null,
70017015
};
@@ -7022,12 +7036,12 @@ fn cmdFetch(
70227036
try io.getStdOut().writeAll(hex_digest ++ "\n");
70237037
return cleanExit();
70247038
},
7025-
.yes => n: {
7039+
.yes, .exact => |name| name: {
7040+
if (name) |n| break :name n;
70267041
const fetched_manifest = fetch.manifest orelse
70277042
fatal("unable to determine name; fetched package has no build.zig.zon file", .{});
7028-
break :n fetched_manifest.name;
7043+
break :name fetched_manifest.name;
70297044
},
7030-
.name => |n| n,
70317045
};
70327046

70337047
const cwd_path = try process.getCwdAlloc(arena);
@@ -7052,13 +7066,43 @@ fn cmdFetch(
70527066
var fixups: Ast.Fixups = .{};
70537067
defer fixups.deinit(gpa);
70547068

7069+
var saved_path_or_url = path_or_url;
7070+
7071+
if (fetch.latest_commit) |*latest_commit| resolved: {
7072+
const latest_commit_hex = try std.fmt.allocPrint(arena, "{}", .{std.fmt.fmtSliceHexLower(latest_commit)});
7073+
7074+
var uri = try std.Uri.parse(path_or_url);
7075+
7076+
if (uri.fragment) |fragment| {
7077+
const target_ref = try fragment.toRawMaybeAlloc(arena);
7078+
7079+
// the refspec may already be fully resolved
7080+
if (std.mem.eql(u8, target_ref, latest_commit_hex)) break :resolved;
7081+
7082+
std.log.info("resolved ref '{s}' to commit {s}", .{ target_ref, latest_commit_hex });
7083+
7084+
// include the original refspec in a query parameter, could be used to check for updates
7085+
uri.query = .{ .percent_encoded = try std.fmt.allocPrint(arena, "ref={%}", .{fragment}) };
7086+
} else {
7087+
std.log.info("resolved to commit {s}", .{latest_commit_hex});
7088+
}
7089+
7090+
// replace the refspec with the resolved commit SHA
7091+
uri.fragment = .{ .raw = latest_commit_hex };
7092+
7093+
switch (save) {
7094+
.yes => saved_path_or_url = try std.fmt.allocPrint(arena, "{}", .{uri}),
7095+
.no, .exact => {}, // keep the original URL
7096+
}
7097+
}
7098+
70557099
const new_node_init = try std.fmt.allocPrint(arena,
70567100
\\.{{
70577101
\\ .url = "{}",
70587102
\\ .hash = "{}",
70597103
\\ }}
70607104
, .{
7061-
std.zig.fmtEscapes(path_or_url),
7105+
std.zig.fmtEscapes(saved_path_or_url),
70627106
std.zig.fmtEscapes(&hex_digest),
70637107
});
70647108

@@ -7078,7 +7122,7 @@ fn cmdFetch(
70787122
if (dep.hash) |h| {
70797123
switch (dep.location) {
70807124
.url => |u| {
7081-
if (mem.eql(u8, h, &hex_digest) and mem.eql(u8, u, path_or_url)) {
7125+
if (mem.eql(u8, h, &hex_digest) and mem.eql(u8, u, saved_path_or_url)) {
70827126
std.log.info("existing dependency named '{s}' is up-to-date", .{name});
70837127
process.exit(0);
70847128
}

0 commit comments

Comments
 (0)