Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce the zig fetch subcommand and symlink support in zig packages #17363

Merged
merged 6 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/Liveness.zig"
"${CMAKE_SOURCE_DIR}/src/Module.zig"
"${CMAKE_SOURCE_DIR}/src/Package.zig"
"${CMAKE_SOURCE_DIR}/src/Package/hash.zig"
"${CMAKE_SOURCE_DIR}/src/RangeSet.zig"
"${CMAKE_SOURCE_DIR}/src/Sema.zig"
"${CMAKE_SOURCE_DIR}/src/TypedValue.zig"
Expand Down
4 changes: 3 additions & 1 deletion lib/std/fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2003,10 +2003,12 @@ pub const Dir = struct {
return os.windows.CreateSymbolicLink(self.fd, sym_link_path_w, target_path_w, flags.is_directory);
}

pub const ReadLinkError = os.ReadLinkError;

/// Read value of a symbolic link.
/// The return value is a slice of `buffer`, from index `0`.
/// Asserts that the path parameter has no null bytes.
pub fn readLink(self: Dir, sub_path: []const u8, buffer: []u8) ![]u8 {
pub fn readLink(self: Dir, sub_path: []const u8, buffer: []u8) ReadLinkError![]u8 {
if (builtin.os.tag == .wasi and !builtin.link_libc) {
return self.readLinkWasi(sub_path, buffer);
}
Expand Down
76 changes: 69 additions & 7 deletions lib/std/tar.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ pub const Options = struct {
strip_components: u32 = 0,
/// How to handle the "mode" property of files from within the tar file.
mode_mode: ModeMode = .executable_bit_only,
/// Provide this to receive detailed error messages.
/// When this is provided, some errors which would otherwise be returned immediately
/// will instead be added to this structure. The API user must check the errors
/// in diagnostics to know whether the operation succeeded or failed.
diagnostics: ?*Diagnostics = null,

const ModeMode = enum {
pub const ModeMode = enum {
/// The mode from the tar file is completely ignored. Files are created
/// with the default mode when creating files.
ignore,
Expand All @@ -13,12 +18,46 @@ pub const Options = struct {
/// Other bits of the mode are left as the default when creating files.
executable_bit_only,
};

pub const Diagnostics = struct {
allocator: std.mem.Allocator,
errors: std.ArrayListUnmanaged(Error) = .{},

pub const Error = union(enum) {
unable_to_create_sym_link: struct {
code: anyerror,
file_name: []const u8,
link_name: []const u8,
},
unsupported_file_type: struct {
file_name: []const u8,
file_type: Header.FileType,
},
};

pub fn deinit(d: *Diagnostics) void {
for (d.errors.items) |item| {
switch (item) {
.unable_to_create_sym_link => |info| {
d.allocator.free(info.file_name);
d.allocator.free(info.link_name);
},
.unsupported_file_type => |info| {
d.allocator.free(info.file_name);
},
}
}
d.errors.deinit(d.allocator);
d.* = undefined;
}
};
};

pub const Header = struct {
bytes: *const [512]u8,

pub const FileType = enum(u8) {
normal_alias = 0,
normal = '0',
hard_link = '1',
symbolic_link = '2',
Expand Down Expand Up @@ -65,13 +104,18 @@ pub const Header = struct {
return str(header, 0, 0 + 100);
}

pub fn linkName(header: Header) []const u8 {
return str(header, 157, 157 + 100);
}

pub fn prefix(header: Header) []const u8 {
return str(header, 345, 345 + 155);
}

pub fn fileType(header: Header) FileType {
const result = @as(FileType, @enumFromInt(header.bytes[156]));
return if (result == @as(FileType, @enumFromInt(0))) .normal else result;
const result: FileType = @enumFromInt(header.bytes[156]);
if (result == .normal_alias) return .normal;
return result;
}

fn str(header: Header, start: usize, end: usize) []const u8 {
Expand Down Expand Up @@ -148,7 +192,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
const header: Header = .{ .bytes = chunk[0..512] };
const file_size = try header.fileSize();
const rounded_file_size = std.mem.alignForward(u64, file_size, 512);
const pad_len = @as(usize, @intCast(rounded_file_size - file_size));
const pad_len: usize = @intCast(rounded_file_size - file_size);
const unstripped_file_name = if (file_name_override_len > 0)
file_name_buffer[0..file_name_override_len]
else
Expand All @@ -175,7 +219,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
while (true) {
const temp = try buffer.readChunk(reader, @intCast(rounded_file_size + 512 - file_off));
if (temp.len == 0) return error.UnexpectedEndOfStream;
const slice = temp[0..@as(usize, @intCast(@min(file_size - file_off, temp.len)))];
const slice = temp[0..@intCast(@min(file_size - file_off, temp.len))];
try file.writeAll(slice);

file_off += slice.len;
Expand Down Expand Up @@ -228,8 +272,26 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
buffer.skip(reader, @intCast(rounded_file_size)) catch return error.TarHeadersTooBig;
},
.hard_link => return error.TarUnsupportedFileType,
.symbolic_link => return error.TarUnsupportedFileType,
else => return error.TarUnsupportedFileType,
.symbolic_link => {
const file_name = try stripComponents(unstripped_file_name, options.strip_components);
const link_name = header.linkName();

dir.symLink(link_name, file_name, .{}) catch |err| {
const d = options.diagnostics orelse return error.UnableToCreateSymLink;
try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{
.code = err,
.file_name = try d.allocator.dupe(u8, file_name),
.link_name = try d.allocator.dupe(u8, link_name),
} });
};
},
else => |file_type| {
const d = options.diagnostics orelse return error.TarUnsupportedFileType;
try d.errors.append(d.allocator, .{ .unsupported_file_type = .{
.file_name = try d.allocator.dupe(u8, unstripped_file_name),
.file_type = file_type,
} });
},
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions lib/std/zig/ErrorBundle.zig
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ fn renderErrorMessageToWriter(
try counting_stderr.writeAll(": ");
// This is the length of the part before the error message:
// e.g. "file.zig:4:5: error: "
const prefix_len = @as(usize, @intCast(counting_stderr.context.bytes_written));
const prefix_len: usize = @intCast(counting_stderr.context.bytes_written);
try ttyconf.setColor(stderr, .reset);
try ttyconf.setColor(stderr, .bold);
if (err_msg.count == 1) {
Expand Down Expand Up @@ -356,16 +356,16 @@ pub const Wip = struct {
}

const compile_log_str_index = if (compile_log_text.len == 0) 0 else str: {
const str = @as(u32, @intCast(wip.string_bytes.items.len));
const str: u32 = @intCast(wip.string_bytes.items.len);
try wip.string_bytes.ensureUnusedCapacity(gpa, compile_log_text.len + 1);
wip.string_bytes.appendSliceAssumeCapacity(compile_log_text);
wip.string_bytes.appendAssumeCapacity(0);
break :str str;
};

wip.setExtra(0, ErrorMessageList{
.len = @as(u32, @intCast(wip.root_list.items.len)),
.start = @as(u32, @intCast(wip.extra.items.len)),
.len = @intCast(wip.root_list.items.len),
.start = @intCast(wip.extra.items.len),
.compile_log_text = compile_log_str_index,
});
try wip.extra.appendSlice(gpa, @as([]const u32, @ptrCast(wip.root_list.items)));
Expand All @@ -385,7 +385,7 @@ pub const Wip = struct {

pub fn addString(wip: *Wip, s: []const u8) !u32 {
const gpa = wip.gpa;
const index = @as(u32, @intCast(wip.string_bytes.items.len));
const index: u32 = @intCast(wip.string_bytes.items.len);
try wip.string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
wip.string_bytes.appendSliceAssumeCapacity(s);
wip.string_bytes.appendAssumeCapacity(0);
Expand All @@ -394,7 +394,7 @@ pub const Wip = struct {

pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) !u32 {
const gpa = wip.gpa;
const index = @as(u32, @intCast(wip.string_bytes.items.len));
const index: u32 = @intCast(wip.string_bytes.items.len);
try wip.string_bytes.writer(gpa).print(fmt, args);
try wip.string_bytes.append(gpa, 0);
return index;
Expand All @@ -406,15 +406,15 @@ pub const Wip = struct {
}

pub fn addErrorMessage(wip: *Wip, em: ErrorMessage) !MessageIndex {
return @as(MessageIndex, @enumFromInt(try addExtra(wip, em)));
return @enumFromInt(try addExtra(wip, em));
}

pub fn addErrorMessageAssumeCapacity(wip: *Wip, em: ErrorMessage) MessageIndex {
return @as(MessageIndex, @enumFromInt(addExtraAssumeCapacity(wip, em)));
return @enumFromInt(addExtraAssumeCapacity(wip, em));
}

pub fn addSourceLocation(wip: *Wip, sl: SourceLocation) !SourceLocationIndex {
return @as(SourceLocationIndex, @enumFromInt(try addExtra(wip, sl)));
return @enumFromInt(try addExtra(wip, sl));
}

pub fn addReferenceTrace(wip: *Wip, rt: ReferenceTrace) !void {
Expand All @@ -430,7 +430,7 @@ pub const Wip = struct {
const other_list = other.getMessages();

// The ensureUnusedCapacity call above guarantees this.
const notes_start = wip.reserveNotes(@as(u32, @intCast(other_list.len))) catch unreachable;
const notes_start = wip.reserveNotes(@intCast(other_list.len)) catch unreachable;
for (notes_start.., other_list) |note, message| {
wip.extra.items[note] = @intFromEnum(wip.addOtherMessage(other, message) catch unreachable);
}
Expand All @@ -455,7 +455,7 @@ pub const Wip = struct {
try wip.extra.ensureUnusedCapacity(wip.gpa, notes_len +
notes_len * @typeInfo(ErrorBundle.ErrorMessage).Struct.fields.len);
wip.extra.items.len += notes_len;
return @as(u32, @intCast(wip.extra.items.len - notes_len));
return @intCast(wip.extra.items.len - notes_len);
}

fn addOtherMessage(wip: *Wip, other: ErrorBundle, msg_index: MessageIndex) !MessageIndex {
Expand Down Expand Up @@ -510,7 +510,7 @@ pub const Wip = struct {

fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 {
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
const result = @as(u32, @intCast(wip.extra.items.len));
const result: u32 = @intCast(wip.extra.items.len);
wip.extra.items.len += fields.len;
setExtra(wip, result, extra);
return result;
Expand Down
Loading