mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-09 07:08:59 +00:00
tar: find package root dir in pipeToFileSystem
While iterating over all files in tarball set root_dir in diagnostic if there is single root in tarball. Will be used in package manager with strip_components = 0 to find the root of the fetched package.
This commit is contained in:
parent
24304a4385
commit
b1e70edd90
1 changed files with 102 additions and 8 deletions
110
lib/std/tar.zig
110
lib/std/tar.zig
|
|
@ -29,6 +29,9 @@ pub const Diagnostics = struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
errors: std.ArrayListUnmanaged(Error) = .{},
|
errors: std.ArrayListUnmanaged(Error) = .{},
|
||||||
|
|
||||||
|
root_entries: usize = 0,
|
||||||
|
root_dir: ?[]const u8 = null,
|
||||||
|
|
||||||
pub const Error = union(enum) {
|
pub const Error = union(enum) {
|
||||||
unable_to_create_sym_link: struct {
|
unable_to_create_sym_link: struct {
|
||||||
code: anyerror,
|
code: anyerror,
|
||||||
|
|
@ -45,6 +48,45 @@ pub const Diagnostics = struct {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn findRoot(d: *Diagnostics, path: []const u8, kind: FileKind) !void {
|
||||||
|
if (rootDir(path)) |root_dir| {
|
||||||
|
d.root_entries += 1;
|
||||||
|
if (kind == .directory and d.root_entries == 1) {
|
||||||
|
d.root_dir = try d.allocator.dupe(u8, root_dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (d.root_dir) |r| {
|
||||||
|
d.allocator.free(r);
|
||||||
|
d.root_dir = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If path is package root returns root_dir name, otherwise null.
|
||||||
|
fn rootDir(path: []const u8) ?[]const u8 {
|
||||||
|
if (path.len == 0) return null;
|
||||||
|
|
||||||
|
const start_index: usize = if (path[0] == '/') 1 else 0;
|
||||||
|
const end_index: usize = if (path[path.len - 1] == '/') path.len - 1 else path.len;
|
||||||
|
const buf = path[start_index..end_index];
|
||||||
|
return if (std.mem.indexOfScalarPos(u8, buf, 0, '/') == null)
|
||||||
|
buf
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
test rootDir {
|
||||||
|
const expectEqualStrings = testing.expectEqualStrings;
|
||||||
|
const expect = testing.expect;
|
||||||
|
|
||||||
|
try expectEqualStrings("a", rootDir("a").?);
|
||||||
|
try expectEqualStrings("b", rootDir("b").?);
|
||||||
|
try expectEqualStrings("c", rootDir("/c").?);
|
||||||
|
try expectEqualStrings("d", rootDir("/d/").?);
|
||||||
|
try expect(rootDir("a/b") == null);
|
||||||
|
try expect(rootDir("") == null);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(d: *Diagnostics) void {
|
pub fn deinit(d: *Diagnostics) void {
|
||||||
for (d.errors.items) |item| {
|
for (d.errors.items) |item| {
|
||||||
switch (item) {
|
switch (item) {
|
||||||
|
|
@ -61,6 +103,10 @@ pub const Diagnostics = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.errors.deinit(d.allocator);
|
d.errors.deinit(d.allocator);
|
||||||
|
if (d.root_dir) |r| {
|
||||||
|
d.allocator.free(r);
|
||||||
|
d.root_dir = null;
|
||||||
|
}
|
||||||
d.* = undefined;
|
d.* = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -580,19 +626,21 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
|
||||||
.link_name_buffer = &link_name_buffer,
|
.link_name_buffer = &link_name_buffer,
|
||||||
.diagnostics = options.diagnostics,
|
.diagnostics = options.diagnostics,
|
||||||
});
|
});
|
||||||
|
|
||||||
while (try iter.next()) |file| {
|
while (try iter.next()) |file| {
|
||||||
|
const file_name = stripComponents(file.name, options.strip_components);
|
||||||
|
if (options.diagnostics) |d| {
|
||||||
|
try d.findRoot(file_name, file.kind);
|
||||||
|
}
|
||||||
|
|
||||||
switch (file.kind) {
|
switch (file.kind) {
|
||||||
.directory => {
|
.directory => {
|
||||||
const file_name = stripComponents(file.name, options.strip_components);
|
|
||||||
if (file_name.len != 0 and !options.exclude_empty_directories) {
|
if (file_name.len != 0 and !options.exclude_empty_directories) {
|
||||||
try dir.makePath(file_name);
|
try dir.makePath(file_name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.file => {
|
.file => {
|
||||||
if (file.size == 0 and file.name.len == 0) return;
|
|
||||||
const file_name = stripComponents(file.name, options.strip_components);
|
|
||||||
if (file_name.len == 0) return error.BadFileName;
|
if (file_name.len == 0) return error.BadFileName;
|
||||||
|
|
||||||
if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {
|
if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {
|
||||||
defer fs_file.close();
|
defer fs_file.close();
|
||||||
try file.writeAll(fs_file);
|
try file.writeAll(fs_file);
|
||||||
|
|
@ -605,12 +653,8 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.sym_link => {
|
.sym_link => {
|
||||||
// The file system path of the symbolic link.
|
|
||||||
const file_name = stripComponents(file.name, options.strip_components);
|
|
||||||
if (file_name.len == 0) return error.BadFileName;
|
if (file_name.len == 0) return error.BadFileName;
|
||||||
// The data inside the symbolic link.
|
|
||||||
const link_name = file.link_name;
|
const link_name = file.link_name;
|
||||||
|
|
||||||
createDirAndSymlink(dir, link_name, file_name) catch |err| {
|
createDirAndSymlink(dir, link_name, file_name) catch |err| {
|
||||||
const d = options.diagnostics orelse return error.UnableToCreateSymLink;
|
const d = options.diagnostics orelse return error.UnableToCreateSymLink;
|
||||||
try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{
|
try d.errors.append(d.allocator, .{ .unable_to_create_sym_link = .{
|
||||||
|
|
@ -799,6 +843,7 @@ test PaxIterator {
|
||||||
|
|
||||||
test {
|
test {
|
||||||
_ = @import("tar/test.zig");
|
_ = @import("tar/test.zig");
|
||||||
|
_ = Diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "header parse size" {
|
test "header parse size" {
|
||||||
|
|
@ -993,6 +1038,55 @@ test pipeToFileSystem {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "pipeToFileSystem root_dir" {
|
||||||
|
const data = @embedFile("tar/testdata/example.tar");
|
||||||
|
var fbs = std.io.fixedBufferStream(data);
|
||||||
|
const reader = fbs.reader();
|
||||||
|
|
||||||
|
// with strip_components = 1
|
||||||
|
{
|
||||||
|
var tmp = testing.tmpDir(.{ .no_follow = true });
|
||||||
|
defer tmp.cleanup();
|
||||||
|
var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
|
||||||
|
defer diagnostics.deinit();
|
||||||
|
|
||||||
|
pipeToFileSystem(tmp.dir, reader, .{
|
||||||
|
.strip_components = 1,
|
||||||
|
.diagnostics = &diagnostics,
|
||||||
|
}) catch |err| {
|
||||||
|
// Skip on platform which don't support symlinks
|
||||||
|
if (err == error.UnableToCreateSymLink) return error.SkipZigTest;
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
// there is no root_dir
|
||||||
|
try testing.expect(diagnostics.root_dir == null);
|
||||||
|
try testing.expectEqual(3, diagnostics.root_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// with strip_components = 0
|
||||||
|
{
|
||||||
|
fbs.reset();
|
||||||
|
var tmp = testing.tmpDir(.{ .no_follow = true });
|
||||||
|
defer tmp.cleanup();
|
||||||
|
var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
|
||||||
|
defer diagnostics.deinit();
|
||||||
|
|
||||||
|
pipeToFileSystem(tmp.dir, reader, .{
|
||||||
|
.strip_components = 0,
|
||||||
|
.diagnostics = &diagnostics,
|
||||||
|
}) catch |err| {
|
||||||
|
// Skip on platform which don't support symlinks
|
||||||
|
if (err == error.UnableToCreateSymLink) return error.SkipZigTest;
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
// root_dir found
|
||||||
|
try testing.expectEqualStrings("example", diagnostics.root_dir.?);
|
||||||
|
try testing.expectEqual(1, diagnostics.root_entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn normalizePath(bytes: []u8) []u8 {
|
fn normalizePath(bytes: []u8) []u8 {
|
||||||
const canonical_sep = std.fs.path.sep_posix;
|
const canonical_sep = std.fs.path.sep_posix;
|
||||||
if (std.fs.path.sep == canonical_sep) return bytes;
|
if (std.fs.path.sep == canonical_sep) return bytes;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue