diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-04-07 15:07:00 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-07 15:07:00 -0700 |
| commit | fdd6c31e8b25f9eed81c1e78fa71eca17fd29f68 (patch) | |
| tree | 61686eb9bc1399946d702e2fe024b6bf259f5b44 /lib/std/Build/Step/WriteFile.zig | |
| parent | c78f996ff986b8843f328e1f083547c538ac865b (diff) | |
| parent | eee5400b7dc37845ea5f42e0841320953e7852b2 (diff) | |
| download | zig-fdd6c31e8b25f9eed81c1e78fa71eca17fd29f68.tar.gz zig-fdd6c31e8b25f9eed81c1e78fa71eca17fd29f68.zip | |
Merge pull request #19167 from castholm/installHeader
std.Build: fix `Compile.installHeader` behavior, add `WriteFile.addCopyDirectory`
Diffstat (limited to 'lib/std/Build/Step/WriteFile.zig')
| -rw-r--r-- | lib/std/Build/Step/WriteFile.zig | 134 |
1 files changed, 130 insertions, 4 deletions
diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig index d0ac68377a..310decdfe7 100644 --- a/lib/std/Build/Step/WriteFile.zig +++ b/lib/std/Build/Step/WriteFile.zig @@ -15,9 +15,11 @@ const ArrayList = std.ArrayList; const WriteFile = @This(); step: Step, -/// The elements here are pointers because we need stable pointers for the -/// GeneratedFile field. + +// The elements here are pointers because we need stable pointers for the GeneratedFile field. files: std.ArrayListUnmanaged(*File), +directories: std.ArrayListUnmanaged(*Directory), + output_source_files: std.ArrayListUnmanaged(OutputSourceFile), generated_directory: std.Build.GeneratedFile, @@ -33,6 +35,33 @@ pub const File = struct { } }; +pub const Directory = struct { + source: std.Build.LazyPath, + sub_path: []const u8, + options: Options, + generated_dir: std.Build.GeneratedFile, + + pub const Options = struct { + /// File paths that end in any of these suffixes will be excluded from copying. + exclude_extensions: []const []const u8 = &.{}, + /// Only file paths that end in any of these suffixes will be included in copying. + /// `null` means that all suffixes will be included. + /// `exclude_extensions` takes precedence over `include_extensions`. + include_extensions: ?[]const []const u8 = null, + + pub fn dupe(self: Options, b: *std.Build) Options { + return .{ + .exclude_extensions = b.dupeStrings(self.exclude_extensions), + .include_extensions = if (self.include_extensions) |incs| b.dupeStrings(incs) else null, + }; + } + }; + + pub fn getPath(self: *Directory) std.Build.LazyPath { + return .{ .generated = &self.generated_dir }; + } +}; + pub const OutputSourceFile = struct { contents: Contents, sub_path: []const u8, @@ -53,6 +82,7 @@ pub fn create(owner: *std.Build) *WriteFile { .makeFn = make, }), .files = .{}, + .directories = .{}, .output_source_files = .{}, .generated_directory = .{ .step = &wf.step }, }; @@ -96,6 +126,31 @@ pub fn addCopyFile(wf: *WriteFile, source: std.Build.LazyPath, sub_path: []const return file.getPath(); } +/// Copy files matching the specified exclude/include patterns to the specified subdirectory +/// relative to this step's generated directory. +/// The returned value is a lazy path to the generated subdirectory. +pub fn addCopyDirectory( + wf: *WriteFile, + source: std.Build.LazyPath, + sub_path: []const u8, + options: Directory.Options, +) std.Build.LazyPath { + const b = wf.step.owner; + const gpa = b.allocator; + const dir = gpa.create(Directory) catch @panic("OOM"); + dir.* = .{ + .source = source.dupe(b), + .sub_path = b.dupePath(sub_path), + .options = options.dupe(b), + .generated_dir = .{ .step = &wf.step }, + }; + wf.directories.append(gpa, dir) catch @panic("OOM"); + + wf.maybeUpdateName(); + source.addStepDependencies(&wf.step); + return dir.getPath(); +} + /// A path relative to the package root. /// Be careful with this because it updates source files. This should not be /// used as part of the normal build process, but as a utility occasionally @@ -130,11 +185,16 @@ pub fn getDirectory(wf: *WriteFile) std.Build.LazyPath { } fn maybeUpdateName(wf: *WriteFile) void { - if (wf.files.items.len == 1) { + if (wf.files.items.len == 1 and wf.directories.items.len == 0) { // First time adding a file; update name. if (std.mem.eql(u8, wf.step.name, "WriteFile")) { wf.step.name = wf.step.owner.fmt("WriteFile {s}", .{wf.files.items[0].sub_path}); } + } else if (wf.directories.items.len == 1 and wf.files.items.len == 0) { + // First time adding a directory; update name. + if (std.mem.eql(u8, wf.step.name, "WriteFile")) { + wf.step.name = wf.step.owner.fmt("WriteFile {s}", .{wf.directories.items[0].sub_path}); + } } } @@ -209,6 +269,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { }, } } + for (wf.directories.items) |dir| { + man.hash.addBytes(dir.source.getPath2(b, step)); + man.hash.addBytes(dir.sub_path); + for (dir.options.exclude_extensions) |ext| man.hash.addBytes(ext); + if (dir.options.include_extensions) |incs| for (incs) |inc| man.hash.addBytes(inc); + } if (try step.cacheHit(&man)) { const digest = man.final(); @@ -233,6 +299,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { }; defer cache_dir.close(); + const cwd = fs.cwd(); + for (wf.files.items) |file| { if (fs.path.dirname(file.sub_path)) |dirname| { cache_dir.makePath(dirname) catch |err| { @@ -252,7 +320,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { .copy => |file_source| { const source_path = file_source.getPath(b); const prev_status = fs.Dir.updateFile( - fs.cwd(), + cwd, source_path, cache_dir, file.sub_path, @@ -279,6 +347,64 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { cache_path, file.sub_path, }); } + for (wf.directories.items) |dir| { + const full_src_dir_path = dir.source.getPath2(b, step); + const dest_dirname = dir.sub_path; + + if (dest_dirname.len != 0) { + cache_dir.makePath(dest_dirname) catch |err| { + return step.fail("unable to make path '{}{s}{c}{s}': {s}", .{ + b.cache_root, cache_path, fs.path.sep, dest_dirname, @errorName(err), + }); + }; + } + + var src_dir = b.build_root.handle.openDir(full_src_dir_path, .{ .iterate = true }) catch |err| { + return step.fail("unable to open source directory '{s}': {s}", .{ + full_src_dir_path, @errorName(err), + }); + }; + defer src_dir.close(); + + var it = try src_dir.walk(b.allocator); + next_entry: while (try it.next()) |entry| { + for (dir.options.exclude_extensions) |ext| { + if (std.mem.endsWith(u8, entry.path, ext)) continue :next_entry; + } + if (dir.options.include_extensions) |incs| { + for (incs) |inc| { + if (std.mem.endsWith(u8, entry.path, inc)) break; + } else { + continue :next_entry; + } + } + const full_src_entry_path = b.pathJoin(&.{ full_src_dir_path, entry.path }); + const dest_path = b.pathJoin(&.{ dest_dirname, entry.path }); + switch (entry.kind) { + .directory => try cache_dir.makePath(dest_path), + .file => { + const prev_status = fs.Dir.updateFile( + cwd, + full_src_entry_path, + cache_dir, + dest_path, + .{}, + ) catch |err| { + return step.fail("unable to update file from '{s}' to '{}{s}{c}{s}': {s}", .{ + full_src_entry_path, + b.cache_root, + cache_path, + fs.path.sep, + dest_path, + @errorName(err), + }); + }; + _ = prev_status; + }, + else => continue, + } + } + } try step.writeManifest(&man); } |
