Skip to content

Commit

Permalink
Merge pull request #17363 from ziglang/tar-symlinks
Browse files Browse the repository at this point in the history
introduce the `zig fetch` subcommand and symlink support in zig packages
  • Loading branch information
andrewrk authored Oct 3, 2023
2 parents 4930094 + 573a13f commit df4853a
Show file tree
Hide file tree
Showing 8 changed files with 681 additions and 261 deletions.
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

0 comments on commit df4853a

Please sign in to comment.