| ... | ... | @@ -547,7 +547,7 @@ const Fmt = struct { |
| 547 | 547 | color: Color, |
| 548 | 548 | gpa: *Allocator, |
| 549 | 549 | |
| 550 | | const SeenMap = std.BufSet; |
| 550 | const SeenMap = std.AutoHashMap(fs.File.INode, void); |
| 551 | 551 | }; |
| 552 | 552 | |
| 553 | 553 | pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { |
| ... | ... | @@ -644,7 +644,14 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { |
| 644 | 644 | }; |
| 645 | 645 | |
| 646 | 646 | for (input_files.span()) |file_path| { |
| 647 | | try fmtPath(&fmt, file_path, check_flag); |
| 647 | // Get the real path here to avoid Windows failing on relative file paths with . or .. in them. |
| 648 | const real_path = fs.realpathAlloc(gpa, file_path) catch |err| { |
| 649 | std.debug.warn("unable to open '{}': {}\n", .{ file_path, err }); |
| 650 | process.exit(1); |
| 651 | }; |
| 652 | defer gpa.free(real_path); |
| 653 | |
| 654 | try fmtPath(&fmt, file_path, check_flag, fs.cwd(), real_path); |
| 648 | 655 | } |
| 649 | 656 | if (fmt.any_error) { |
| 650 | 657 | process.exit(1); |
| ... | ... | @@ -673,20 +680,9 @@ const FmtError = error{ |
| 673 | 680 | EndOfStream, |
| 674 | 681 | } || fs.File.OpenError; |
| 675 | 682 | |
| 676 | | fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { |
| 677 | | // get the real path here to avoid Windows failing on relative file paths with . or .. in them |
| 678 | | const real_path = fs.realpathAlloc(fmt.gpa, file_path) catch |err| { |
| 679 | | std.debug.warn("unable to open '{}': {}\n", .{ file_path, err }); |
| 680 | | fmt.any_error = true; |
| 681 | | return; |
| 682 | | }; |
| 683 | | defer fmt.gpa.free(real_path); |
| 684 | | |
| 685 | | if (fmt.seen.exists(real_path)) return; |
| 686 | | try fmt.seen.put(real_path); |
| 687 | | |
| 688 | | fmtPathFile(fmt, file_path, check_mode, real_path) catch |err| switch (err) { |
| 689 | | error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, real_path), |
| 683 | fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void { |
| 684 | fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) { |
| 685 | error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path), |
| 690 | 686 | else => { |
| 691 | 687 | std.debug.warn("unable to format '{}': {}\n", .{ file_path, err }); |
| 692 | 688 | fmt.any_error = true; |
| ... | ... | @@ -695,29 +691,30 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { |
| 695 | 691 | }; |
| 696 | 692 | } |
| 697 | 693 | |
| 698 | | fn fmtPathDir(fmt: *Fmt, file_path: []const u8, check_mode: bool, parent_real_path: []const u8) FmtError!void { |
| 699 | | var dir = try fs.cwd().openDir(parent_real_path, .{ .iterate = true }); |
| 694 | fn fmtPathDir( |
| 695 | fmt: *Fmt, |
| 696 | file_path: []const u8, |
| 697 | check_mode: bool, |
| 698 | parent_dir: fs.Dir, |
| 699 | parent_sub_path: []const u8, |
| 700 | ) FmtError!void { |
| 701 | var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true }); |
| 700 | 702 | defer dir.close(); |
| 701 | 703 | |
| 704 | const stat = try dir.stat(); |
| 705 | if (try fmt.seen.put(stat.inode, {})) |_| return; |
| 706 | |
| 702 | 707 | var dir_it = dir.iterate(); |
| 703 | 708 | while (try dir_it.next()) |entry| { |
| 704 | 709 | const is_dir = entry.kind == .Directory; |
| 705 | 710 | if (is_dir or mem.endsWith(u8, entry.name, ".zig")) { |
| 706 | 711 | const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name }); |
| 707 | | const sub_real_path = fs.realpathAlloc(fmt.gpa, full_path) catch |err| { |
| 708 | | std.debug.warn("unable to open '{}': {}\n", .{ file_path, err }); |
| 709 | | fmt.any_error = true; |
| 710 | | return; |
| 711 | | }; |
| 712 | | defer fmt.gpa.free(sub_real_path); |
| 713 | | |
| 714 | | if (fmt.seen.exists(sub_real_path)) return; |
| 715 | | try fmt.seen.put(sub_real_path); |
| 712 | defer fmt.gpa.free(full_path); |
| 716 | 713 | |
| 717 | 714 | if (is_dir) { |
| 718 | | try fmtPathDir(fmt, full_path, check_mode, sub_real_path); |
| 715 | try fmtPathDir(fmt, full_path, check_mode, dir, entry.name); |
| 719 | 716 | } else { |
| 720 | | fmtPathFile(fmt, full_path, check_mode, sub_real_path) catch |err| { |
| 717 | fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| { |
| 721 | 718 | std.debug.warn("unable to format '{}': {}\n", .{ full_path, err }); |
| 722 | 719 | fmt.any_error = true; |
| 723 | 720 | return; |
| ... | ... | @@ -727,8 +724,14 @@ fn fmtPathDir(fmt: *Fmt, file_path: []const u8, check_mode: bool, parent_real_pa |
| 727 | 724 | } |
| 728 | 725 | } |
| 729 | 726 | |
| 730 | | fn fmtPathFile(fmt: *Fmt, file_path: []const u8, check_mode: bool, real_path: []const u8) FmtError!void { |
| 731 | | const source_file = try fs.cwd().openFile(real_path, .{}); |
| 727 | fn fmtPathFile( |
| 728 | fmt: *Fmt, |
| 729 | file_path: []const u8, |
| 730 | check_mode: bool, |
| 731 | dir: fs.Dir, |
| 732 | sub_path: []const u8, |
| 733 | ) FmtError!void { |
| 734 | const source_file = try dir.openFile(sub_path, .{}); |
| 732 | 735 | defer source_file.close(); |
| 733 | 736 | |
| 734 | 737 | const stat = try source_file.stat(); |
| ... | ... | @@ -743,6 +746,9 @@ fn fmtPathFile(fmt: *Fmt, file_path: []const u8, check_mode: bool, real_path: [] |
| 743 | 746 | }; |
| 744 | 747 | defer fmt.gpa.free(source_code); |
| 745 | 748 | |
| 749 | // Add to set after no longer possible to get error.IsDir. |
| 750 | if (try fmt.seen.put(stat.inode, {})) |_| return; |
| 751 | |
| 746 | 752 | const tree = try std.zig.parse(fmt.gpa, source_code); |
| 747 | 753 | defer tree.deinit(); |
| 748 | 754 | |
| ... | ... | @@ -761,7 +767,7 @@ fn fmtPathFile(fmt: *Fmt, file_path: []const u8, check_mode: bool, real_path: [] |
| 761 | 767 | fmt.any_error = true; |
| 762 | 768 | } |
| 763 | 769 | } else { |
| 764 | | const baf = try io.BufferedAtomicFile.create(fmt.gpa, fs.cwd(), real_path, .{ .mode = stat.mode }); |
| 770 | const baf = try io.BufferedAtomicFile.create(fmt.gpa, dir, sub_path, .{ .mode = stat.mode }); |
| 765 | 771 | defer baf.destroy(); |
| 766 | 772 | |
| 767 | 773 | const anything_changed = try std.zig.render(fmt.gpa, baf.stream(), tree); |