| ... | ... | @@ -13,8 +13,9 @@ const Configuration = std.Build.Configuration; |
| 13 | 13 | |
| 14 | 14 | step: Step, |
| 15 | 15 | |
| 16 | | files: std.ArrayList(File), |
| 17 | | directories: std.ArrayList(Directory), |
| 16 | embeds: std.ArrayList(Embed) = .empty, |
| 17 | copies: std.ArrayList(Copy) = .empty, |
| 18 | directories: std.ArrayList(Directory) = .empty, |
| 18 | 19 | generated_directory: Configuration.GeneratedFileIndex, |
| 19 | 20 | mode: Mode = .whole_cached, |
| 20 | 21 | |
| ... | ... | @@ -37,158 +38,152 @@ pub const Mode = union(enum) { |
| 37 | 38 | mutate: std.Build.LazyPath, |
| 38 | 39 | }; |
| 39 | 40 | |
| 40 | | pub const File = struct { |
| 41 | | sub_path: []const u8, |
| 42 | | contents: Contents, |
| 43 | | }; |
| 41 | pub const Embed = Configuration.Step.WriteFile.Embed; |
| 44 | 42 | |
| 45 | | pub const Directory = struct { |
| 46 | | source: std.Build.LazyPath, |
| 47 | | sub_path: []const u8, |
| 48 | | options: Options, |
| 49 | | |
| 50 | | pub const Options = struct { |
| 51 | | /// File paths that end in any of these suffixes will be excluded from copying. |
| 52 | | exclude_extensions: []const []const u8 = &.{}, |
| 53 | | /// Only file paths that end in any of these suffixes will be included in copying. |
| 54 | | /// `null` means that all suffixes will be included. |
| 55 | | /// `exclude_extensions` takes precedence over `include_extensions`. |
| 56 | | include_extensions: ?[]const []const u8 = null, |
| 57 | | |
| 58 | | pub fn dupe(opts: Options, graph: *std.Build.Graph) Options { |
| 59 | | return .{ |
| 60 | | .exclude_extensions = graph.dupeStrings(opts.exclude_extensions), |
| 61 | | .include_extensions = if (opts.include_extensions) |incs| graph.dupeStrings(incs) else null, |
| 62 | | }; |
| 63 | | } |
| 64 | | |
| 65 | | pub fn pathIncluded(opts: Options, path: []const u8) bool { |
| 66 | | for (opts.exclude_extensions) |ext| { |
| 67 | | if (std.mem.endsWith(u8, path, ext)) |
| 68 | | return false; |
| 69 | | } |
| 70 | | if (opts.include_extensions) |incs| { |
| 71 | | for (incs) |inc| { |
| 72 | | if (std.mem.endsWith(u8, path, inc)) |
| 73 | | return true; |
| 74 | | } else { |
| 75 | | return false; |
| 76 | | } |
| 77 | | } |
| 78 | | return true; |
| 79 | | } |
| 80 | | }; |
| 43 | pub const Copy = struct { |
| 44 | sub_path: Configuration.String, |
| 45 | src_file: std.Build.LazyPath, |
| 81 | 46 | }; |
| 82 | 47 | |
| 83 | | pub const Contents = union(enum) { |
| 84 | | bytes: []const u8, |
| 85 | | copy: std.Build.LazyPath, |
| 48 | pub const Directory = struct { |
| 49 | sub_path: Configuration.String, |
| 50 | src_path: std.Build.LazyPath, |
| 51 | exclude_extensions: Configuration.OptionalStringList, |
| 52 | include_extensions: Configuration.OptionalStringList, |
| 86 | 53 | }; |
| 87 | 54 | |
| 88 | 55 | pub fn create(owner: *std.Build) *WriteFile { |
| 89 | 56 | const graph = owner.graph; |
| 90 | | const arena = graph.arena; |
| 91 | | const write_file = arena.create(WriteFile) catch @panic("OOM"); |
| 92 | | write_file.* = .{ |
| 93 | | .step = Step.init(.{ |
| 57 | const wf = graph.create(WriteFile); |
| 58 | wf.* = .{ |
| 59 | .step = .init(.{ |
| 94 | 60 | .tag = base_tag, |
| 95 | 61 | .name = "WriteFile", |
| 96 | 62 | .owner = owner, |
| 97 | 63 | }), |
| 98 | | .files = .empty, |
| 99 | | .directories = .empty, |
| 100 | | .generated_directory = graph.addGeneratedFile(&write_file.step), |
| 64 | .generated_directory = graph.addGeneratedFile(&wf.step), |
| 101 | 65 | }; |
| 102 | | return write_file; |
| 66 | return wf; |
| 103 | 67 | } |
| 104 | 68 | |
| 105 | | pub fn add(write_file: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.LazyPath { |
| 106 | | const graph = write_file.step.owner.graph; |
| 69 | /// Writes `contents` to a file at `sub_path` relative to the output |
| 70 | /// directory. |
| 71 | /// |
| 72 | /// `sub_path` may be a basename, or it may include subdirectories, which are |
| 73 | /// created as needed. |
| 74 | pub fn add(wf: *WriteFile, sub_path: []const u8, contents: []const u8) std.Build.LazyPath { |
| 75 | const graph = wf.step.owner.graph; |
| 76 | const wc = &graph.wip_configuration; |
| 107 | 77 | const arena = graph.arena; |
| 108 | | const file: File = .{ |
| 109 | | .sub_path = graph.dupePath(sub_path), |
| 110 | | .contents = .{ .bytes = graph.dupeString(bytes) }, |
| 111 | | }; |
| 112 | | write_file.files.append(arena, file) catch @panic("OOM"); |
| 113 | | write_file.maybeUpdateName(); |
| 78 | |
| 79 | wf.embeds.append(arena, .{ |
| 80 | .sub_path = wc.addString(sub_path) catch @panic("OOM"), |
| 81 | .contents = wc.addBytes(contents) catch @panic("OOM"), |
| 82 | }) catch @panic("OOM"); |
| 83 | |
| 84 | wf.maybeUpdateName(); |
| 85 | |
| 114 | 86 | return .{ |
| 115 | 87 | .generated = .{ |
| 116 | | .index = write_file.generated_directory, |
| 117 | | .sub_path = file.sub_path, |
| 88 | .index = wf.generated_directory, |
| 89 | .sub_path = graph.dupeString(sub_path), |
| 118 | 90 | }, |
| 119 | 91 | }; |
| 120 | 92 | } |
| 121 | 93 | |
| 122 | | /// Copies the provided file into the generated directory within the local |
| 123 | | /// cache, along with all the rest of the files added to this step. |
| 94 | /// Copies the provided file to `sub_path` relative to the output directory. |
| 124 | 95 | /// |
| 125 | | /// `sub_path` is the destination path relative to the local cache directory |
| 126 | | /// associated with this WriteFile. It may be a basename, or it may include |
| 127 | | /// subdirectories, which are created as needed. |
| 128 | | pub fn addCopyFile(write_file: *WriteFile, source: std.Build.LazyPath, sub_path: []const u8) std.Build.LazyPath { |
| 129 | | const graph = write_file.step.owner.graph; |
| 130 | | const duped_path = graph.dupePath(sub_path); |
| 96 | /// `sub_path` may be a basename, or it may include subdirectories, which are |
| 97 | /// created as needed. |
| 98 | pub fn addCopyFile(wf: *WriteFile, src_file: std.Build.LazyPath, sub_path: []const u8) std.Build.LazyPath { |
| 99 | const graph = wf.step.owner.graph; |
| 100 | const wc = &graph.wip_configuration; |
| 131 | 101 | const arena = graph.arena; |
| 132 | 102 | |
| 133 | | write_file.files.append(arena, .{ |
| 134 | | .sub_path = duped_path, |
| 135 | | .contents = .{ .copy = source }, |
| 103 | wf.copies.append(arena, .{ |
| 104 | .sub_path = wc.addString(sub_path) catch @panic("OOM"), |
| 105 | .src_file = src_file.dupe(graph), |
| 136 | 106 | }) catch @panic("OOM"); |
| 137 | 107 | |
| 138 | | write_file.maybeUpdateName(); |
| 139 | | source.addStepDependencies(&write_file.step); |
| 108 | wf.maybeUpdateName(); |
| 109 | |
| 110 | src_file.addStepDependencies(&wf.step); |
| 140 | 111 | |
| 141 | 112 | return .{ .generated = .{ |
| 142 | | .index = write_file.generated_directory, |
| 143 | | .sub_path = duped_path, |
| 113 | .index = wf.generated_directory, |
| 114 | .sub_path = graph.dupePath(sub_path), |
| 144 | 115 | } }; |
| 145 | 116 | } |
| 146 | 117 | |
| 118 | pub const CopyDirectoryOptions = struct { |
| 119 | /// File paths that end in any of these suffixes will be excluded from copying. |
| 120 | exclude_extensions: []const []const u8 = &.{}, |
| 121 | /// Only file paths that end in any of these suffixes will be included in copying. |
| 122 | /// `null` means that all suffixes will be included. |
| 123 | /// `exclude_extensions` takes precedence over `include_extensions`. |
| 124 | include_extensions: ?[]const []const u8 = null, |
| 125 | }; |
| 126 | |
| 147 | 127 | /// Copy files matching the specified exclude/include patterns to the specified |
| 148 | 128 | /// subdirectory relative to this step's generated directory. |
| 149 | 129 | /// |
| 150 | 130 | /// The returned value is a lazy path to the generated subdirectory. |
| 151 | 131 | pub fn addCopyDirectory( |
| 152 | | write_file: *WriteFile, |
| 153 | | source: std.Build.LazyPath, |
| 132 | wf: *WriteFile, |
| 133 | src_path: std.Build.LazyPath, |
| 154 | 134 | sub_path: []const u8, |
| 155 | | options: Directory.Options, |
| 135 | options: CopyDirectoryOptions, |
| 156 | 136 | ) std.Build.LazyPath { |
| 157 | | const graph = write_file.step.owner.graph; |
| 137 | const graph = wf.step.owner.graph; |
| 138 | const wc = &graph.wip_configuration; |
| 158 | 139 | const arena = graph.arena; |
| 159 | | const dir = Directory{ |
| 160 | | .source = source.dupe(graph), |
| 161 | | .sub_path = graph.dupePath(sub_path), |
| 162 | | .options = options.dupe(graph), |
| 163 | | }; |
| 164 | | write_file.directories.append(arena, dir) catch @panic("OOM"); |
| 165 | 140 | |
| 166 | | write_file.maybeUpdateName(); |
| 167 | | source.addStepDependencies(&write_file.step); |
| 141 | wf.directories.append(arena, .{ |
| 142 | .sub_path = wc.addString(sub_path) catch @panic("OOM"), |
| 143 | .src_path = src_path.dupe(graph), |
| 144 | .exclude_extensions = if (options.exclude_extensions.len != 0) |
| 145 | .init(wc.addStringList(options.exclude_extensions) catch @panic("OOM")) |
| 146 | else |
| 147 | .none, |
| 148 | .include_extensions = if (options.include_extensions) |list| |
| 149 | .init(wc.addStringList(list) catch @panic("OOM")) |
| 150 | else |
| 151 | .none, |
| 152 | }) catch @panic("OOM"); |
| 153 | |
| 154 | wf.maybeUpdateName(); |
| 155 | |
| 156 | src_path.addStepDependencies(&wf.step); |
| 157 | |
| 168 | 158 | return .{ |
| 169 | 159 | .generated = .{ |
| 170 | | .index = write_file.generated_directory, |
| 171 | | .sub_path = dir.sub_path, |
| 160 | .index = wf.generated_directory, |
| 161 | .sub_path = graph.dupePath(sub_path), |
| 172 | 162 | }, |
| 173 | 163 | }; |
| 174 | 164 | } |
| 175 | 165 | |
| 176 | 166 | /// Returns a `LazyPath` representing the base directory that contains all the |
| 177 | 167 | /// files from this `WriteFile`. |
| 178 | | pub fn getDirectory(write_file: *WriteFile) std.Build.LazyPath { |
| 179 | | return .{ .generated = .{ .index = write_file.generated_directory } }; |
| 168 | pub fn getDirectory(wf: *WriteFile) std.Build.LazyPath { |
| 169 | return .{ .generated = .{ .index = wf.generated_directory } }; |
| 180 | 170 | } |
| 181 | 171 | |
| 182 | | fn maybeUpdateName(write_file: *WriteFile) void { |
| 183 | | if (write_file.files.items.len == 1 and write_file.directories.items.len == 0) { |
| 172 | fn maybeUpdateName(wf: *WriteFile) void { |
| 173 | const graph = wf.step.owner.graph; |
| 174 | const wc = &graph.wip_configuration; |
| 175 | const files_count = wf.embeds.items.len + wf.copies.items.len; |
| 176 | if (files_count == 1 and wf.directories.items.len == 0) { |
| 184 | 177 | // First time adding a file; update name. |
| 185 | | if (std.mem.eql(u8, write_file.step.name, "WriteFile")) { |
| 186 | | write_file.step.name = write_file.step.owner.fmt("WriteFile {s}", .{write_file.files.items[0].sub_path}); |
| 178 | const sub_path = if (wf.embeds.items.len == 1) wf.embeds.items[0].sub_path else wf.copies.items[0].sub_path; |
| 179 | if (std.mem.eql(u8, wf.step.name, "WriteFile")) { |
| 180 | wf.step.name = wf.step.owner.fmt("WriteFile {s}", .{wc.stringSlice(sub_path)}); |
| 187 | 181 | } |
| 188 | | } else if (write_file.directories.items.len == 1 and write_file.files.items.len == 0) { |
| 182 | } else if (wf.directories.items.len == 1 and files_count == 0) { |
| 189 | 183 | // First time adding a directory; update name. |
| 190 | | if (std.mem.eql(u8, write_file.step.name, "WriteFile")) { |
| 191 | | write_file.step.name = write_file.step.owner.fmt("WriteFile {s}", .{write_file.directories.items[0].sub_path}); |
| 184 | const dir_name = wc.stringSlice(wf.directories.items[0].sub_path); |
| 185 | if (std.mem.eql(u8, wf.step.name, "WriteFile")) { |
| 186 | wf.step.name = wf.step.owner.fmt("WriteFile {s}", .{dir_name}); |
| 192 | 187 | } |
| 193 | 188 | } |
| 194 | 189 | } |