(breaking) std.fs.copyFile now integrates with Dir
Removed: * `std.fs.updateFile` * `std.fs.updateFileMode` * `std.fs.copyFile` * `std.fs.copyFileMode` Added: * `std.fs.Dir.copyFile` * `std.fs.copyFileAbsolute` * `std.fs.updateFileAbsolute` Moved: * `std.fs.Dir.UpdateFileOptions` => `std.fs.CopyFileOptions` Deprecated: * `std.fs.deleteDir` * `std.fs.deleteDirC` * `std.fs.deleteDirW` * `std.fs.readLink` * `std.fs.readLinkC`master
parent
e3c92d0532
commit
555a2c0328
|
@ -847,7 +847,8 @@ pub const Builder = struct {
|
||||||
if (self.verbose) {
|
if (self.verbose) {
|
||||||
warn("cp {} {} ", .{ source_path, dest_path });
|
warn("cp {} {} ", .{ source_path, dest_path });
|
||||||
}
|
}
|
||||||
const prev_status = try fs.updateFile(source_path, dest_path);
|
const cwd = fs.cwd();
|
||||||
|
const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{});
|
||||||
if (self.verbose) switch (prev_status) {
|
if (self.verbose) switch (prev_status) {
|
||||||
.stale => warn("# installed\n", .{}),
|
.stale => warn("# installed\n", .{}),
|
||||||
.fresh => warn("# up-to-date\n", .{}),
|
.fresh => warn("# up-to-date\n", .{}),
|
||||||
|
|
115
lib/std/fs.zig
115
lib/std/fs.zig
|
@ -86,51 +86,33 @@ pub const PrevStatus = enum {
|
||||||
fresh,
|
fresh,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Deprecated; use `Dir.updateFile`.
|
pub const CopyFileOptions = struct {
|
||||||
pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {
|
/// When this is `null` the mode is copied from the source file.
|
||||||
|
override_mode: ?File.Mode = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path`
|
||||||
|
/// are absolute. See `Dir.updateFile` for a function that operates on both
|
||||||
|
/// absolute and relative paths.
|
||||||
|
pub fn updateFileAbsolute(
|
||||||
|
source_path: []const u8,
|
||||||
|
dest_path: []const u8,
|
||||||
|
args: CopyFileOptions,
|
||||||
|
) !PrevStatus {
|
||||||
|
assert(path.isAbsolute(source_path));
|
||||||
|
assert(path.isAbsolute(dest_path));
|
||||||
const my_cwd = cwd();
|
const my_cwd = cwd();
|
||||||
return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{});
|
return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated; use `Dir.updateFile`.
|
/// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path`
|
||||||
pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !Dir.PrevStatus {
|
/// are absolute. See `Dir.copyFile` for a function that operates on both
|
||||||
|
/// absolute and relative paths.
|
||||||
|
pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: CopyFileOptions) !void {
|
||||||
|
assert(path.isAbsolute(source_path));
|
||||||
|
assert(path.isAbsolute(dest_path));
|
||||||
const my_cwd = cwd();
|
const my_cwd = cwd();
|
||||||
return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{ .override_mode = mode });
|
return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args);
|
||||||
}
|
|
||||||
|
|
||||||
/// Guaranteed to be atomic.
|
|
||||||
/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
|
|
||||||
/// there is a possibility of power loss or application termination leaving temporary files present
|
|
||||||
/// in the same directory as dest_path.
|
|
||||||
/// Destination file will have the same mode as the source file.
|
|
||||||
/// TODO rework this to integrate with Dir
|
|
||||||
pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
|
|
||||||
var in_file = try cwd().openFile(source_path, .{});
|
|
||||||
defer in_file.close();
|
|
||||||
|
|
||||||
const stat = try in_file.stat();
|
|
||||||
|
|
||||||
var atomic_file = try AtomicFile.init(dest_path, stat.mode);
|
|
||||||
defer atomic_file.deinit();
|
|
||||||
|
|
||||||
try atomic_file.file.writeFileAll(in_file, .{ .in_len = stat.size });
|
|
||||||
return atomic_file.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Guaranteed to be atomic.
|
|
||||||
/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
|
|
||||||
/// there is a possibility of power loss or application termination leaving temporary files present
|
|
||||||
/// in the same directory as dest_path.
|
|
||||||
/// TODO rework this to integrate with Dir
|
|
||||||
pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
|
|
||||||
var in_file = try cwd().openFile(source_path, .{});
|
|
||||||
defer in_file.close();
|
|
||||||
|
|
||||||
var atomic_file = try AtomicFile.init(dest_path, mode);
|
|
||||||
defer atomic_file.deinit();
|
|
||||||
|
|
||||||
try atomic_file.file.writeFileAll(in_file, .{});
|
|
||||||
return atomic_file.finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO update this API to avoid a getrandom syscall for every operation.
|
/// TODO update this API to avoid a getrandom syscall for every operation.
|
||||||
|
@ -245,18 +227,17 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {
|
||||||
os.windows.CloseHandle(handle);
|
os.windows.CloseHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `error.DirNotEmpty` if the directory is not empty.
|
/// Deprecated; use `Dir.deleteDir`.
|
||||||
/// To delete a directory recursively, see `deleteTree`.
|
|
||||||
pub fn deleteDir(dir_path: []const u8) !void {
|
pub fn deleteDir(dir_path: []const u8) !void {
|
||||||
return os.rmdir(dir_path);
|
return os.rmdir(dir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string.
|
/// Deprecated; use `Dir.deleteDirC`.
|
||||||
pub fn deleteDirC(dir_path: [*:0]const u8) !void {
|
pub fn deleteDirC(dir_path: [*:0]const u8) !void {
|
||||||
return os.rmdirC(dir_path);
|
return os.rmdirC(dir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string.
|
/// Deprecated; use `Dir.deleteDirW`.
|
||||||
pub fn deleteDirW(dir_path: [*:0]const u16) !void {
|
pub fn deleteDirW(dir_path: [*:0]const u16) !void {
|
||||||
return os.rmdirW(dir_path);
|
return os.rmdirW(dir_path);
|
||||||
}
|
}
|
||||||
|
@ -1218,22 +1199,17 @@ pub const Dir = struct {
|
||||||
return os.faccessatW(self.fd, sub_path_w, 0, 0);
|
return os.faccessatW(self.fd, sub_path_w, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const UpdateFileOptions = struct {
|
|
||||||
override_mode: ?File.Mode = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing.
|
/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing.
|
||||||
/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime,
|
/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime,
|
||||||
/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.
|
/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.
|
||||||
/// Returns the previous status of the file before updating.
|
/// Returns the previous status of the file before updating.
|
||||||
/// If any of the directories do not exist for dest_path, they are created.
|
/// If any of the directories do not exist for dest_path, they are created.
|
||||||
/// If `override_mode` is provided, then that value is used rather than the source path's mode.
|
|
||||||
pub fn updateFile(
|
pub fn updateFile(
|
||||||
source_dir: Dir,
|
source_dir: Dir,
|
||||||
source_path: []const u8,
|
source_path: []const u8,
|
||||||
dest_dir: Dir,
|
dest_dir: Dir,
|
||||||
dest_path: []const u8,
|
dest_path: []const u8,
|
||||||
options: UpdateFileOptions,
|
options: CopyFileOptions,
|
||||||
) !PrevStatus {
|
) !PrevStatus {
|
||||||
var src_file = try source_dir.openFile(source_path, .{});
|
var src_file = try source_dir.openFile(source_path, .{});
|
||||||
defer src_file.close();
|
defer src_file.close();
|
||||||
|
@ -1272,6 +1248,34 @@ pub const Dir = struct {
|
||||||
return PrevStatus.stale;
|
return PrevStatus.stale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Guaranteed to be atomic.
|
||||||
|
/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
|
||||||
|
/// there is a possibility of power loss or application termination leaving temporary files present
|
||||||
|
/// in the same directory as dest_path.
|
||||||
|
pub fn copyFile(
|
||||||
|
source_dir: Dir,
|
||||||
|
source_path: []const u8,
|
||||||
|
dest_dir: Dir,
|
||||||
|
dest_path: []const u8,
|
||||||
|
options: CopyFileOptions,
|
||||||
|
) !void {
|
||||||
|
var in_file = try source_dir.openFile(source_path, .{});
|
||||||
|
defer in_file.close();
|
||||||
|
|
||||||
|
var size: ?u64 = null;
|
||||||
|
const mode = options.override_mode orelse blk: {
|
||||||
|
const stat = try in_file.stat();
|
||||||
|
size = stat.size;
|
||||||
|
break :blk stat.mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });
|
||||||
|
defer atomic_file.deinit();
|
||||||
|
|
||||||
|
try atomic_file.file.writeFileAll(in_file, .{ .in_len = size });
|
||||||
|
return atomic_file.finish();
|
||||||
|
}
|
||||||
|
|
||||||
pub const AtomicFileOptions = struct {
|
pub const AtomicFileOptions = struct {
|
||||||
mode: File.Mode = File.default_mode,
|
mode: File.Mode = File.default_mode,
|
||||||
};
|
};
|
||||||
|
@ -1471,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {
|
||||||
return walker;
|
return walker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read value of a symbolic link.
|
/// Deprecated; use `Dir.readLink`.
|
||||||
/// The return value is a slice of buffer, from index `0`.
|
|
||||||
pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
||||||
return os.readlink(pathname, buffer);
|
return os.readlink(pathname, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `readLink`, except the parameter is null-terminated.
|
/// Deprecated; use `Dir.readLinkC`.
|
||||||
pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
||||||
return os.readlinkC(pathname_c, buffer);
|
return os.readlinkC(pathname_c, buffer);
|
||||||
}
|
}
|
||||||
|
@ -1584,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `realpath`, except caller must free the returned memory.
|
/// `realpath`, except caller must free the returned memory.
|
||||||
|
/// TODO integrate with `Dir`
|
||||||
pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
|
pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
|
||||||
var buf: [MAX_PATH_BYTES]u8 = undefined;
|
var buf: [MAX_PATH_BYTES]u8 = undefined;
|
||||||
return mem.dupe(allocator, u8, try os.realpath(pathname, &buf));
|
return mem.dupe(allocator, u8, try os.realpath(pathname, &buf));
|
||||||
|
@ -1592,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
|
||||||
test "" {
|
test "" {
|
||||||
_ = makeDirAbsolute;
|
_ = makeDirAbsolute;
|
||||||
_ = makeDirAbsoluteZ;
|
_ = makeDirAbsoluteZ;
|
||||||
|
_ = copyFileAbsolute;
|
||||||
|
_ = updateFileAbsolute;
|
||||||
|
_ = Dir.copyFile;
|
||||||
_ = @import("fs/path.zig");
|
_ = @import("fs/path.zig");
|
||||||
_ = @import("fs/file.zig");
|
_ = @import("fs/file.zig");
|
||||||
_ = @import("fs/get_app_data_dir.zig");
|
_ = @import("fs/get_app_data_dir.zig");
|
||||||
|
|
|
@ -113,14 +113,16 @@ test "fs.copyFile" {
|
||||||
const dest_file = "tmp_test_copy_file2.txt";
|
const dest_file = "tmp_test_copy_file2.txt";
|
||||||
const dest_file2 = "tmp_test_copy_file3.txt";
|
const dest_file2 = "tmp_test_copy_file3.txt";
|
||||||
|
|
||||||
try fs.cwd().writeFile(src_file, data);
|
const cwd = fs.cwd();
|
||||||
defer fs.cwd().deleteFile(src_file) catch {};
|
|
||||||
|
|
||||||
try fs.copyFile(src_file, dest_file);
|
try cwd.writeFile(src_file, data);
|
||||||
defer fs.cwd().deleteFile(dest_file) catch {};
|
defer cwd.deleteFile(src_file) catch {};
|
||||||
|
|
||||||
try fs.copyFileMode(src_file, dest_file2, File.default_mode);
|
try cwd.copyFile(src_file, cwd, dest_file, .{});
|
||||||
defer fs.cwd().deleteFile(dest_file2) catch {};
|
defer cwd.deleteFile(dest_file) catch {};
|
||||||
|
|
||||||
|
try cwd.copyFile(src_file, cwd, dest_file2, .{ .override_mode = File.default_mode });
|
||||||
|
defer cwd.deleteFile(dest_file2) catch {};
|
||||||
|
|
||||||
try expectFileContents(dest_file, data);
|
try expectFileContents(dest_file, data);
|
||||||
try expectFileContents(dest_file2, data);
|
try expectFileContents(dest_file2, data);
|
||||||
|
|
Loading…
Reference in New Issue