aboutsummaryrefslogtreecommitdiff
path: root/src-self-hosted
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-06-20 23:06:04 -0400
committerAndrew Kelley <andrew@ziglang.org>2020-06-20 23:06:04 -0400
commitedea7a46e5484e30c338699207c8f4b4d8370c97 (patch)
treeaf5d6b5650fe48c56d22a38e54db74e3871c98a8 /src-self-hosted
parent5229f6ec68708c3e66393a50ad9f9032ee7f4257 (diff)
parentfaf783e5959a09fb2a1680f8bb7558db96dcbed9 (diff)
downloadzig-edea7a46e5484e30c338699207c8f4b4d8370c97.tar.gz
zig-edea7a46e5484e30c338699207c8f4b4d8370c97.zip
Merge branch 'DrDeano-master'
closes #5648
Diffstat (limited to 'src-self-hosted')
-rw-r--r--src-self-hosted/main.zig138
1 files changed, 86 insertions, 52 deletions
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
index 6c13f8ab00..29930270eb 100644
--- a/src-self-hosted/main.zig
+++ b/src-self-hosted/main.zig
@@ -546,8 +546,9 @@ const Fmt = struct {
any_error: bool,
color: Color,
gpa: *Allocator,
+ out_buffer: std.ArrayList(u8),
- const SeenMap = std.BufSet;
+ const SeenMap = std.AutoHashMap(fs.File.INode, void);
};
pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
@@ -641,10 +642,20 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
.seen = Fmt.SeenMap.init(gpa),
.any_error = false,
.color = color,
+ .out_buffer = std.ArrayList(u8).init(gpa),
};
+ defer fmt.seen.deinit();
+ defer fmt.out_buffer.deinit();
for (input_files.span()) |file_path| {
- try fmtPath(&fmt, file_path, check_flag);
+ // Get the real path here to avoid Windows failing on relative file paths with . or .. in them.
+ const real_path = fs.realpathAlloc(gpa, file_path) catch |err| {
+ std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
+ process.exit(1);
+ };
+ defer gpa.free(real_path);
+
+ try fmtPath(&fmt, file_path, check_flag, fs.cwd(), real_path);
}
if (fmt.any_error) {
process.exit(1);
@@ -670,61 +681,79 @@ const FmtError = error{
ReadOnlyFileSystem,
LinkQuotaExceeded,
FileBusy,
+ EndOfStream,
} || fs.File.OpenError;
-fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
- // get the real path here to avoid Windows failing on relative file paths with . or .. in them
- var real_path = fs.realpathAlloc(fmt.gpa, file_path) catch |err| {
- std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
- fmt.any_error = true;
- return;
- };
- defer fmt.gpa.free(real_path);
-
- if (fmt.seen.exists(real_path)) return;
- try fmt.seen.put(real_path);
-
- const source_file = fs.cwd().openFile(real_path, .{}) catch |err| switch (err) {
- error.IsDir, error.AccessDenied => {
- var dir = try fs.cwd().openDir(file_path, .{ .iterate = true });
- defer dir.close();
-
- var dir_it = dir.iterate();
-
- while (try dir_it.next()) |entry| {
- if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) {
- const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
- try fmtPath(fmt, full_path, check_mode);
- }
- }
- return;
- },
+fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
+ fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
+ error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
else => {
- std.debug.warn("unable to open '{}': {}\n", .{ file_path, err });
+ std.debug.warn("unable to format '{}': {}\n", .{ file_path, err });
fmt.any_error = true;
return;
},
};
+}
+
+fn fmtPathDir(
+ fmt: *Fmt,
+ file_path: []const u8,
+ check_mode: bool,
+ parent_dir: fs.Dir,
+ parent_sub_path: []const u8,
+) FmtError!void {
+ var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
+ defer dir.close();
+
+ const stat = try dir.stat();
+ if (try fmt.seen.put(stat.inode, {})) |_| return;
+
+ var dir_it = dir.iterate();
+ while (try dir_it.next()) |entry| {
+ const is_dir = entry.kind == .Directory;
+ if (is_dir or mem.endsWith(u8, entry.name, ".zig")) {
+ const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
+ defer fmt.gpa.free(full_path);
+
+ if (is_dir) {
+ try fmtPathDir(fmt, full_path, check_mode, dir, entry.name);
+ } else {
+ fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| {
+ std.debug.warn("unable to format '{}': {}\n", .{ full_path, err });
+ fmt.any_error = true;
+ return;
+ };
+ }
+ }
+ }
+}
+
+fn fmtPathFile(
+ fmt: *Fmt,
+ file_path: []const u8,
+ check_mode: bool,
+ dir: fs.Dir,
+ sub_path: []const u8,
+) FmtError!void {
+ const source_file = try dir.openFile(sub_path, .{});
defer source_file.close();
- const stat = source_file.stat() catch |err| {
- std.debug.warn("unable to stat '{}': {}\n", .{ file_path, err });
- fmt.any_error = true;
- return;
- };
+ const stat = try source_file.stat();
- const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| {
- std.debug.warn("unable to read '{}': {}\n", .{ file_path, err });
- fmt.any_error = true;
- return;
+ if (stat.kind == .Directory)
+ return error.IsDir;
+
+ const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) {
+ error.ConnectionResetByPeer => unreachable,
+ error.ConnectionTimedOut => unreachable,
+ else => |e| return e,
};
defer fmt.gpa.free(source_code);
- const tree = std.zig.parse(fmt.gpa, source_code) catch |err| {
- std.debug.warn("error parsing file '{}': {}\n", .{ file_path, err });
- fmt.any_error = true;
- return;
- };
+ // Add to set after no longer possible to get error.IsDir.
+ if (try fmt.seen.put(stat.inode, {})) |_| return;
+
+ const tree = try std.zig.parse(fmt.gpa, source_code);
defer tree.deinit();
for (tree.errors) |parse_error| {
@@ -742,14 +771,19 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
fmt.any_error = true;
}
} else {
- const baf = try io.BufferedAtomicFile.create(fmt.gpa, fs.cwd(), real_path, .{ .mode = stat.mode });
- defer baf.destroy();
-
- const anything_changed = try std.zig.render(fmt.gpa, baf.stream(), tree);
- if (anything_changed) {
- std.debug.warn("{}\n", .{file_path});
- try baf.finish();
- }
+ // As a heuristic, we make enough capacity for the same as the input source.
+ try fmt.out_buffer.ensureCapacity(source_code.len);
+ fmt.out_buffer.items.len = 0;
+ const anything_changed = try std.zig.render(fmt.gpa, fmt.out_buffer.writer(), tree);
+ if (!anything_changed)
+ return; // Good thing we didn't waste any file system access on this.
+
+ var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
+ defer af.deinit();
+
+ try af.file.writeAll(fmt.out_buffer.items);
+ try af.finish();
+ std.debug.warn("{}\n", .{file_path});
}
}