| ... | ... | @@ -199,12 +199,13 @@ pub fn main(init: process.Init.Minimal) !void { |
| 199 | 199 | .random_seed = parseRandomSeed(seed_arg), |
| 200 | 200 | }; |
| 201 | 201 | |
| 202 | | const cmd = stringToEnum(enum { libc, init, fetch, build }, cmd_name) orelse |
| 202 | const cmd = stringToEnum(enum { libc, init, fetch, build, @"cache-cat" }, cmd_name) orelse |
| 203 | 203 | fatal("bad command name: {q}", .{cmd_name}); |
| 204 | 204 | switch (cmd) { |
| 205 | 205 | .libc => return cmdLibC(gpa, &graph, args[arg_i..]), |
| 206 | 206 | .init => return cmdInit(gpa, &graph, args[arg_i..]), |
| 207 | 207 | .fetch => return cmdFetch(gpa, &graph, args[arg_i..]), |
| 208 | .@"cache-cat" => return cmdCacheCat(gpa, &graph, args[arg_i..]), |
| 208 | 209 | .build => {}, |
| 209 | 210 | } |
| 210 | 211 | |
| ... | ... | @@ -1880,6 +1881,101 @@ fn cmdFetch(gpa: Allocator, graph: *Graph, args: []const []const u8) !void { |
| 1880 | 1881 | return process.cleanExit(io); |
| 1881 | 1882 | } |
| 1882 | 1883 | |
| 1884 | fn cmdCacheCat(gpa: Allocator, graph: *Graph, args: []const []const u8) !void { |
| 1885 | const io = graph.io; |
| 1886 | |
| 1887 | var arg_i: usize = 0; |
| 1888 | var contents: std.ArrayList(u8) = .empty; |
| 1889 | defer contents.deinit(gpa); |
| 1890 | |
| 1891 | while (nextArg(args, &arg_i)) |arg| { |
| 1892 | if (mem.startsWith(u8, arg, "-")) { |
| 1893 | if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { |
| 1894 | try Io.File.stdout().writeStreamingAll(io, usage_cache_cat); |
| 1895 | return process.cleanExit(io); |
| 1896 | } else { |
| 1897 | fatal("unrecognized parameter: {q}", .{arg}); |
| 1898 | } |
| 1899 | } else { |
| 1900 | var file = Dir.cwd().openFile(io, arg, .{}) catch |err| fatal("opening {q} failed: {t}", .{ arg, err }); |
| 1901 | defer file.close(io); |
| 1902 | |
| 1903 | var manifest_reader = file.reader(io, &.{}); // Reads positionally from zero. |
| 1904 | contents.clearRetainingCapacity(); |
| 1905 | manifest_reader.interface.appendRemainingUnlimited(gpa, &contents) catch |err| switch (err) { |
| 1906 | error.OutOfMemory => |e| return e, |
| 1907 | error.ReadFailed => switch (manifest_reader.err.?) { |
| 1908 | error.Canceled => |e| return e, |
| 1909 | else => |e| fatal("reading from {q} failed: {t}", .{ arg, e }), |
| 1910 | }, |
| 1911 | }; |
| 1912 | const hex_digest = Dir.path.basename(arg); |
| 1913 | cacheCatOne(hex_digest, contents.items, initStdoutWriter(io)) catch |err| switch (err) { |
| 1914 | error.WriteFailed => fatal("writing to stdout failed: {t}", .{stdout_writer_allocation.err.?}), |
| 1915 | else => |e| fatal("parsing {q} failed: {t}", .{ arg, e }), |
| 1916 | }; |
| 1917 | try stdout_writer_allocation.flush(); |
| 1918 | } |
| 1919 | } |
| 1920 | } |
| 1921 | |
| 1922 | fn cacheCatOne(input_hex_digest: []const u8, contents: []const u8, writer: *Io.Writer) !void { |
| 1923 | var bin_digest: Cache.BinDigest = undefined; |
| 1924 | _ = try fmt.hexToBytes(&bin_digest, input_hex_digest); |
| 1925 | |
| 1926 | var hh: Cache.HashHelper = .{}; |
| 1927 | hh.hasher.update(&bin_digest); |
| 1928 | |
| 1929 | var serializer: std.zon.Serializer = .{ .writer = writer }; |
| 1930 | var top_level = try serializer.beginStruct(.{}); |
| 1931 | try top_level.field("input_hash", input_hex_digest, .{}); |
| 1932 | var files_tuple = try top_level.beginTupleField("files", .{}); |
| 1933 | var off: usize = 0; |
| 1934 | while (off + 1 < contents.len) { |
| 1935 | const file_off: Cache.Manifest.File.Offset = @fromBackingInt(@intCast(off)); |
| 1936 | const file = try file_off.getFallibleConst(contents); |
| 1937 | const path = try Cache.Manifest.filePathFallible(contents, file_off); |
| 1938 | if (path.len == 0) return error.InvalidFormat; |
| 1939 | |
| 1940 | var file_obj = try files_tuple.beginStructField(.{ .whitespace_style = .{ .wrap = false } }); |
| 1941 | try file_obj.field("size", file.size, .{}); |
| 1942 | try file_obj.field("inode", file.inode, .{}); |
| 1943 | try file_obj.field("mtime", file.mtime, .{}); |
| 1944 | const hex_digest = Cache.binToHex(file.digest); |
| 1945 | try file_obj.field("digest", @as([]const u8, &hex_digest), .{}); |
| 1946 | if (file.flags.is_directory) try file_obj.field("directory", true, .{}); |
| 1947 | if (file.flags.metadata_only) try file_obj.field("metadata", true, .{}); |
| 1948 | try file_obj.field("prefix", file.flags.prefix, .{}); |
| 1949 | try file_obj.field("path", path, .{}); |
| 1950 | try file_obj.end(); |
| 1951 | |
| 1952 | hh.hasher.update(&file.digest); |
| 1953 | |
| 1954 | off += Cache.Manifest.File.sizeOf(path.len); |
| 1955 | } |
| 1956 | |
| 1957 | try files_tuple.end(); |
| 1958 | |
| 1959 | var discovered_bin_digest: Cache.BinDigest = undefined; |
| 1960 | hh.hasher.final(&discovered_bin_digest); |
| 1961 | const discovered_hex_digest = Cache.binToHex(discovered_bin_digest); |
| 1962 | try top_level.field("discovered_hash", @as([]const u8, &discovered_hex_digest), .{}); |
| 1963 | |
| 1964 | try top_level.end(); |
| 1965 | try writer.writeByte('\n'); |
| 1966 | } |
| 1967 | |
| 1968 | const usage_cache_cat = |
| 1969 | \\Usage: zig cache-cat <paths> |
| 1970 | \\ |
| 1971 | \\ Prints .zig-cache/h/* manifest files in text form. |
| 1972 | \\ |
| 1973 | \\Options: |
| 1974 | \\ -h, --help Print this help and exit |
| 1975 | \\ |
| 1976 | \\ |
| 1977 | ; |
| 1978 | |
| 1883 | 1979 | const usage_fetch = |
| 1884 | 1980 | \\Usage: zig fetch [options] <url> |
| 1885 | 1981 | \\Usage: zig fetch [options] <path> |