Skip to content

Commit ba656e5

Browse files
committed
zig fetch: add --debug-hash argument
This argument causes zig to print verbose hashing information to stdout, which can be used to diff two different fetches and find out why the hashes do not equal each other.
1 parent f1a9344 commit ba656e5

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

src/Package/Fetch.zig

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ pub const JobQueue = struct {
8181
wait_group: WaitGroup = .{},
8282
global_cache: Cache.Directory,
8383
recursive: bool,
84+
/// Dumps hash information to stdout which can be used to troubleshoot why
85+
/// two hashes of the same package do not match.
86+
/// If this is true, `recursive` must be false.
87+
debug_hash: bool,
8488
work_around_btrfs_bug: bool,
8589

8690
pub const Table = std.AutoArrayHashMapUnmanaged(Manifest.MultiHashHexDigest, *Fetch);
@@ -1315,7 +1319,7 @@ fn computeHash(
13151319
const kind: HashedFile.Kind = switch (entry.kind) {
13161320
.directory => unreachable,
13171321
.file => .file,
1318-
.sym_link => .sym_link,
1322+
.sym_link => .link,
13191323
else => return f.fail(f.location_tok, try eb.printString(
13201324
"package contains '{s}' which has illegal file type '{s}'",
13211325
.{ entry.path, @tagName(entry.kind) },
@@ -1399,9 +1403,36 @@ fn computeHash(
13991403
}
14001404

14011405
if (any_failures) return error.FetchFailed;
1406+
1407+
if (f.job_queue.debug_hash) {
1408+
assert(!f.job_queue.recursive);
1409+
// Print something to stdout that can be text diffed to figure out why
1410+
// the package hash is different.
1411+
dumpHashInfo(all_files.items) catch |err| {
1412+
std.debug.print("unable to write to stdout: {s}\n", .{@errorName(err)});
1413+
std.process.exit(1);
1414+
};
1415+
}
1416+
14021417
return hasher.finalResult();
14031418
}
14041419

1420+
fn dumpHashInfo(all_files: []const *const HashedFile) !void {
1421+
const stdout = std.io.getStdOut();
1422+
var bw = std.io.bufferedWriter(stdout.writer());
1423+
const w = bw.writer();
1424+
1425+
for (all_files) |hashed_file| {
1426+
try w.print("{s}: {s}: {s}\n", .{
1427+
@tagName(hashed_file.kind),
1428+
std.fmt.fmtSliceHexLower(&hashed_file.hash),
1429+
hashed_file.normalized_path,
1430+
});
1431+
}
1432+
1433+
try bw.flush();
1434+
}
1435+
14051436
fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {
14061437
defer wg.finish();
14071438
hashed_file.failure = hashFileFallible(dir, hashed_file);
@@ -1427,7 +1458,7 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
14271458
hasher.update(buf[0..bytes_read]);
14281459
}
14291460
},
1430-
.sym_link => {
1461+
.link => {
14311462
const link_name = try dir.readLink(hashed_file.fs_path, &buf);
14321463
if (fs.path.sep != canonical_sep) {
14331464
// Package hashes are intended to be consistent across
@@ -1480,7 +1511,7 @@ const HashedFile = struct {
14801511
fs.File.StatError ||
14811512
fs.Dir.ReadLinkError;
14821513

1483-
const Kind = enum { file, sym_link };
1514+
const Kind = enum { file, link };
14841515

14851516
fn lessThan(context: void, lhs: *const HashedFile, rhs: *const HashedFile) bool {
14861517
_ = context;

src/main.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5143,6 +5143,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
51435143
.thread_pool = &thread_pool,
51445144
.global_cache = global_cache_directory,
51455145
.recursive = true,
5146+
.debug_hash = false,
51465147
.work_around_btrfs_bug = work_around_btrfs_bug,
51475148
};
51485149
defer job_queue.deinit();
@@ -6991,6 +6992,7 @@ pub const usage_fetch =
69916992
\\Options:
69926993
\\ -h, --help Print this help and exit
69936994
\\ --global-cache-dir [path] Override path to global Zig cache directory
6995+
\\ --debug-hash Print verbose hash information to stdout
69946996
\\
69956997
;
69966998

@@ -7004,6 +7006,7 @@ fn cmdFetch(
70047006
std.process.hasEnvVarConstant("ZIG_BTRFS_WORKAROUND");
70057007
var opt_path_or_url: ?[]const u8 = null;
70067008
var override_global_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_GLOBAL_CACHE_DIR");
7009+
var debug_hash: bool = false;
70077010

70087011
{
70097012
var i: usize = 0;
@@ -7019,6 +7022,9 @@ fn cmdFetch(
70197022
i += 1;
70207023
override_global_cache_dir = args[i];
70217024
continue;
7025+
} else if (mem.eql(u8, arg, "--debug-hash")) {
7026+
debug_hash = true;
7027+
continue;
70227028
} else {
70237029
fatal("unrecognized parameter: '{s}'", .{arg});
70247030
}
@@ -7057,6 +7063,7 @@ fn cmdFetch(
70577063
.thread_pool = &thread_pool,
70587064
.global_cache = global_cache_directory,
70597065
.recursive = false,
7066+
.debug_hash = debug_hash,
70607067
.work_around_btrfs_bug = work_around_btrfs_bug,
70617068
};
70627069
defer job_queue.deinit();

0 commit comments

Comments
 (0)