Commit ffd53a459e
Changed files (4)
lib
compiler
std
lib/compiler/std-docs.zig
@@ -167,9 +167,8 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
const remainder = stat.size % 512;
break :p if (remainder > 0) 512 - remainder else 0;
};
- comptime assert(@sizeOf(TarHeader) == 512);
- var file_header = TarHeader.init();
+ var file_header = std.tar.output.Header.init();
file_header.typeflag = .regular;
try file_header.setPath("std", entry.path);
try file_header.setSize(stat.size);
@@ -383,77 +382,3 @@ fn openBrowserTabThread(gpa: Allocator, url: []const u8) !void {
try child.spawn();
_ = try child.wait();
}
-
-/// Forked from https://github.com/mattnite/tar/blob/main/src/main.zig which is
-/// MIT licensed.
-pub const TarHeader = extern struct {
- name: [100]u8,
- mode: [7:0]u8,
- uid: [7:0]u8,
- gid: [7:0]u8,
- size: [11:0]u8,
- mtime: [11:0]u8,
- checksum: [7:0]u8,
- typeflag: FileType,
- linkname: [100]u8,
- magic: [5:0]u8,
- version: [2]u8,
- uname: [31:0]u8,
- gname: [31:0]u8,
- devmajor: [7:0]u8,
- devminor: [7:0]u8,
- prefix: [155]u8,
- pad: [12]u8,
-
- const FileType = enum(u8) {
- regular = '0',
- hard_link = '1',
- symbolic_link = '2',
- character = '3',
- block = '4',
- directory = '5',
- fifo = '6',
- reserved = '7',
- pax_global = 'g',
- extended = 'x',
- _,
- };
-
- fn init() TarHeader {
- var ret = std.mem.zeroes(TarHeader);
- ret.magic = [_:0]u8{ 'u', 's', 't', 'a', 'r' };
- ret.version = [_:0]u8{ '0', '0' };
- return ret;
- }
-
- fn setPath(self: *TarHeader, prefix: []const u8, path: []const u8) !void {
- if (prefix.len + 1 + path.len > 100) {
- var i: usize = 0;
- while (i < path.len and path.len - i > 100) {
- while (path[i] != '/') : (i += 1) {}
- }
-
- _ = try std.fmt.bufPrint(&self.prefix, "{s}/{s}", .{ prefix, path[0..i] });
- _ = try std.fmt.bufPrint(&self.name, "{s}", .{path[i + 1 ..]});
- } else {
- _ = try std.fmt.bufPrint(&self.name, "{s}/{s}", .{ prefix, path });
- }
- }
-
- fn setSize(self: *TarHeader, size: u64) !void {
- _ = try std.fmt.bufPrint(&self.size, "{o:0>11}", .{size});
- }
-
- fn updateChecksum(self: *TarHeader) !void {
- const offset = @offsetOf(TarHeader, "checksum");
- var checksum: usize = 0;
- for (std.mem.asBytes(self), 0..) |val, i| {
- checksum += if (i >= offset and i < offset + @sizeOf(@TypeOf(self.checksum)))
- ' '
- else
- val;
- }
-
- _ = try std.fmt.bufPrint(&self.checksum, "{o:0>7}", .{checksum});
- }
-};
lib/std/tar/output.zig
@@ -0,0 +1,85 @@
+/// A struct that is exactly 512 bytes and matches tar file format. This is
+/// intended to be used for outputting tar files; for parsing there is
+/// `std.tar.Header`.
+pub const Header = extern struct {
+ // This struct was originally copied from
+ // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT
+ // licensed.
+
+ name: [100]u8,
+ mode: [7:0]u8,
+ uid: [7:0]u8,
+ gid: [7:0]u8,
+ size: [11:0]u8,
+ mtime: [11:0]u8,
+ checksum: [7:0]u8,
+ typeflag: FileType,
+ linkname: [100]u8,
+ magic: [5:0]u8,
+ version: [2]u8,
+ uname: [31:0]u8,
+ gname: [31:0]u8,
+ devmajor: [7:0]u8,
+ devminor: [7:0]u8,
+ prefix: [155]u8,
+ pad: [12]u8,
+
+ pub const FileType = enum(u8) {
+ regular = '0',
+ hard_link = '1',
+ symbolic_link = '2',
+ character = '3',
+ block = '4',
+ directory = '5',
+ fifo = '6',
+ reserved = '7',
+ pax_global = 'g',
+ extended = 'x',
+ _,
+ };
+
+ pub fn init() Header {
+ var ret = std.mem.zeroes(Header);
+ ret.magic = [_:0]u8{ 'u', 's', 't', 'a', 'r' };
+ ret.version = [_:0]u8{ '0', '0' };
+ return ret;
+ }
+
+ pub fn setPath(self: *Header, prefix: []const u8, path: []const u8) !void {
+ if (prefix.len + 1 + path.len > 100) {
+ var i: usize = 0;
+ while (i < path.len and path.len - i > 100) {
+ while (path[i] != '/') : (i += 1) {}
+ }
+
+ _ = try std.fmt.bufPrint(&self.prefix, "{s}/{s}", .{ prefix, path[0..i] });
+ _ = try std.fmt.bufPrint(&self.name, "{s}", .{path[i + 1 ..]});
+ } else {
+ _ = try std.fmt.bufPrint(&self.name, "{s}/{s}", .{ prefix, path });
+ }
+ }
+
+ pub fn setSize(self: *Header, size: u64) !void {
+ _ = try std.fmt.bufPrint(&self.size, "{o:0>11}", .{size});
+ }
+
+ pub fn updateChecksum(self: *Header) !void {
+ const offset = @offsetOf(Header, "checksum");
+ var checksum: usize = 0;
+ for (std.mem.asBytes(self), 0..) |val, i| {
+ checksum += if (i >= offset and i < offset + @sizeOf(@TypeOf(self.checksum)))
+ ' '
+ else
+ val;
+ }
+
+ _ = try std.fmt.bufPrint(&self.checksum, "{o:0>7}", .{checksum});
+ }
+
+ comptime {
+ assert(@sizeOf(Header) == 512);
+ }
+};
+
+const std = @import("../std.zig");
+const assert = std.debug.assert;
lib/std/tar.zig
@@ -1,23 +1,25 @@
-/// Tar archive is single ordinary file which can contain many files (or
-/// directories, symlinks, ...). It's build by series of blocks each size of 512
-/// bytes. First block of each entry is header which defines type, name, size
-/// permissions and other attributes. Header is followed by series of blocks of
-/// file content, if any that entry has content. Content is padded to the block
-/// size, so next header always starts at block boundary.
-///
-/// This simple format is extended by GNU and POSIX pax extensions to support
-/// file names longer than 256 bytes and additional attributes.
-///
-/// This is not comprehensive tar parser. Here we are only file types needed to
-/// support Zig package manager; normal file, directory, symbolic link. And
-/// subset of attributes: name, size, permissions.
-///
-/// GNU tar reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html
-/// pax reference: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13
-///
+//! Tar archive is single ordinary file which can contain many files (or
+//! directories, symlinks, ...). It's build by series of blocks each size of 512
+//! bytes. First block of each entry is header which defines type, name, size
+//! permissions and other attributes. Header is followed by series of blocks of
+//! file content, if any that entry has content. Content is padded to the block
+//! size, so next header always starts at block boundary.
+//!
+//! This simple format is extended by GNU and POSIX pax extensions to support
+//! file names longer than 256 bytes and additional attributes.
+//!
+//! This is not comprehensive tar parser. Here we are only file types needed to
+//! support Zig package manager; normal file, directory, symbolic link. And
+//! subset of attributes: name, size, permissions.
+//!
+//! GNU tar reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html
+//! pax reference: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13
+
const std = @import("std.zig");
const assert = std.debug.assert;
+pub const output = @import("tar/output.zig");
+
pub const Options = struct {
/// Number of directory levels to skip when extracting files.
strip_components: u32 = 0,
src/Compilation.zig
@@ -733,6 +733,7 @@ pub const MiscTask = enum {
compiler_rt,
zig_libc,
analyze_mod,
+ docs_copy,
@"musl crti.o",
@"musl crtn.o",
@@ -3765,22 +3766,106 @@ fn taskDocsWasm(comp: *Compilation, wg: *WaitGroup) !void {
fn workerDocsCopy(comp: *Compilation, wg: *WaitGroup) void {
defer wg.finish();
+ docsCopyFallible(comp) catch |err| {
+ return comp.lockAndSetMiscFailure(
+ .docs_copy,
+ "unable to copy autodocs artifacts: {s}",
+ .{@errorName(err)},
+ );
+ };
+}
+fn docsCopyFallible(comp: *Compilation) anyerror!void {
const emit = comp.docs_emit.?;
var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
- // TODO create an error to be reported instead of logging
- log.err("unable to create output directory '{}{s}': {s}", .{
- emit.directory, emit.sub_path, @errorName(err),
- });
- return;
+ return comp.lockAndSetMiscFailure(
+ .docs_copy,
+ "unable to create output directory '{}{s}': {s}",
+ .{ emit.directory, emit.sub_path, @errorName(err) },
+ );
};
defer out_dir.close();
for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| {
const basename = std.fs.path.basename(sub_path);
comp.zig_lib_directory.handle.copyFile(sub_path, out_dir, basename, .{}) catch |err| {
- log.err("unable to copy {s}: {s}", .{ sub_path, @errorName(err) });
+ comp.lockAndSetMiscFailure(.docs_copy, "unable to copy {s}: {s}", .{
+ sub_path,
+ @errorName(err),
+ });
+ return;
+ };
+ }
+
+ var tar_file = out_dir.createFile("sources.tar", .{}) catch |err| {
+ return comp.lockAndSetMiscFailure(
+ .docs_copy,
+ "unable to create '{}{s}/sources.tar': {s}",
+ .{ emit.directory, emit.sub_path, @errorName(err) },
+ );
+ };
+ defer tar_file.close();
+
+ const root = comp.root_mod.root;
+ const root_mod_name = comp.root_mod.fully_qualified_name;
+ const sub_path = if (root.sub_path.len == 0) "." else root.sub_path;
+ var mod_dir = root.root_dir.handle.openDir(sub_path, .{ .iterate = true }) catch |err| {
+ return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{}': {s}", .{
+ root, @errorName(err),
+ });
+ };
+
+ var walker = try mod_dir.walk(comp.gpa);
+ defer walker.deinit();
+
+ const padding_buffer = [1]u8{0} ** 512;
+
+ while (try walker.next()) |entry| {
+ switch (entry.kind) {
+ .file => {
+ if (!std.mem.endsWith(u8, entry.basename, ".zig")) continue;
+ if (std.mem.eql(u8, entry.basename, "test.zig")) continue;
+ if (std.mem.endsWith(u8, entry.basename, "_test.zig")) continue;
+ },
+ else => continue,
+ }
+
+ var file = mod_dir.openFile(entry.path, .{}) catch |err| {
+ return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{}{s}': {s}", .{
+ root, entry.path, @errorName(err),
+ });
+ };
+ defer file.close();
+
+ const stat = file.stat() catch |err| {
+ return comp.lockAndSetMiscFailure(.docs_copy, "unable to stat '{}{s}': {s}", .{
+ root, entry.path, @errorName(err),
+ });
+ };
+
+ var file_header = std.tar.output.Header.init();
+ file_header.typeflag = .regular;
+ try file_header.setPath(root_mod_name, entry.path);
+ try file_header.setSize(stat.size);
+ try file_header.updateChecksum();
+
+ const header_bytes = std.mem.asBytes(&file_header);
+ const padding = p: {
+ const remainder = stat.size % 512;
+ const n = if (remainder > 0) 512 - remainder else 0;
+ break :p padding_buffer[0..n];
};
+
+ var header_and_trailer: [2]std.os.iovec_const = .{
+ .{ .iov_base = header_bytes.ptr, .iov_len = header_bytes.len },
+ .{ .iov_base = padding.ptr, .iov_len = padding.len },
+ };
+
+ try tar_file.writeFileAll(file, .{
+ .in_len = stat.size,
+ .headers_and_trailers = &header_and_trailer,
+ .header_count = 1,
+ });
}
}