authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-08 19:29:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-08 19:29:17-07:00
log4a2cf388440f6efadf9c7664b63c3949b25d6824
tree1e57478fcd8dc316b04a0881d80e277c94b5e279
parentefbfa8ef3ebdb172bf3774a54279951ebb29c4c9

Package.Fetch: apply inclusion rules from build.zig.zon


2 files changed, 65 insertions(+), 6 deletions(-)

src/Package/Fetch.zig+61-5
......@@ -1249,6 +1249,9 @@ fn computeHash(
12491249 var all_files = std.ArrayList(*HashedFile).init(gpa);
12501250 defer all_files.deinit();
12511251
1252 var all_deletions = std.ArrayList(*DeletedFile).init(gpa);
1253 defer all_deletions.deinit();
1254
12521255 var walker = try @as(fs.IterableDir, .{ .dir = tmp_directory.handle }).walk(gpa);
12531256 defer walker.deinit();
12541257
......@@ -1267,10 +1270,25 @@ fn computeHash(
12671270 ) });
12681271 return error.FetchFailed;
12691272 }) |entry| {
1270 _ = filter; // TODO: apply filter rules here
1273 if (entry.kind == .directory) continue;
1274
1275 if (!filter.includePath(entry.path)) {
1276 // Delete instead of including in hash calculation.
1277 const deleted_file = try arena.create(DeletedFile);
1278 deleted_file.* = .{
1279 .fs_path = try arena.dupe(u8, entry.path),
1280 .failure = undefined, // to be populated by the worker
1281 };
1282 wait_group.start();
1283 try thread_pool.spawn(workerDeleteFile, .{
1284 tmp_directory.handle, deleted_file, &wait_group,
1285 });
1286 try all_deletions.append(deleted_file);
1287 continue;
1288 }
12711289
12721290 const kind: HashedFile.Kind = switch (entry.kind) {
1273 .directory => continue,
1291 .directory => unreachable,
12741292 .file => .file,
12751293 .sym_link => .sym_link,
12761294 else => return f.fail(f.location_tok, try eb.printString(
......@@ -1295,7 +1313,6 @@ fn computeHash(
12951313 try thread_pool.spawn(workerHashFile, .{
12961314 tmp_directory.handle, hashed_file, &wait_group,
12971315 });
1298
12991316 try all_files.append(hashed_file);
13001317 }
13011318 }
......@@ -1315,6 +1332,17 @@ fn computeHash(
13151332 };
13161333 hasher.update(&hashed_file.hash);
13171334 }
1335 for (all_deletions.items) |deleted_file| {
1336 deleted_file.failure catch |err| {
1337 any_failures = true;
1338 try eb.addRootErrorMessage(.{
1339 .msg = try eb.printString("failed to delete excluded path '{s}' from package: {s}", .{
1340 deleted_file.fs_path, @errorName(err),
1341 }),
1342 });
1343 };
1344 }
1345
13181346 if (any_failures) return error.FetchFailed;
13191347 return hasher.finalResult();
13201348}
......@@ -1324,6 +1352,11 @@ fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {
13241352 hashed_file.failure = hashFileFallible(dir, hashed_file);
13251353}
13261354
1355fn workerDeleteFile(dir: fs.Dir, deleted_file: *DeletedFile, wg: *WaitGroup) void {
1356 defer wg.finish();
1357 deleted_file.failure = deleteFileFallible(dir, deleted_file);
1358}
1359
13271360fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {
13281361 var buf: [8000]u8 = undefined;
13291362 var hasher = Manifest.Hash.init(.{});
......@@ -1347,6 +1380,20 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
13471380 hasher.final(&hashed_file.hash);
13481381}
13491382
1383fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error!void {
1384 try dir.deleteFile(deleted_file.fs_path);
1385 // In case the file was the last remaining file in the parent directory, attempt to
1386 // remove the parent directory.
1387 var opt_parent = fs.path.dirname(deleted_file.fs_path);
1388 while (opt_parent) |parent| : (opt_parent = fs.path.dirname(parent)) {
1389 dir.deleteDir(parent) catch |err| switch (err) {
1390 error.DirNotEmpty => return,
1391 error.FileNotFound => return,
1392 else => |e| return e,
1393 };
1394 }
1395}
1396
13501397fn isExecutable(file: fs.File) !bool {
13511398 if (builtin.os.tag == .windows) {
13521399 // TODO check the ACL on Windows.
......@@ -1360,6 +1407,15 @@ fn isExecutable(file: fs.File) !bool {
13601407 }
13611408}
13621409
1410const DeletedFile = struct {
1411 fs_path: []const u8,
1412 failure: Error!void,
1413
1414 const Error =
1415 fs.Dir.DeleteFileError ||
1416 fs.Dir.DeleteDirError;
1417};
1418
13631419const HashedFile = struct {
13641420 fs_path: []const u8,
13651421 normalized_path: []const u8,
......@@ -1402,7 +1458,7 @@ fn normalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 {
14021458const Filter = struct {
14031459 include_paths: std.StringArrayHashMapUnmanaged(void) = .{},
14041460
1405 /// sub_path is relative to the tarball root.
1461 /// sub_path is relative to the package root.
14061462 pub fn includePath(self: Filter, sub_path: []const u8) bool {
14071463 if (self.include_paths.count() == 0) return true;
14081464 if (self.include_paths.contains("")) return true;
......@@ -1410,7 +1466,7 @@ const Filter = struct {
14101466
14111467 // Check if any included paths are parent directories of sub_path.
14121468 var dirname = sub_path;
1413 while (std.fs.path.dirname(sub_path)) |next_dirname| {
1469 while (std.fs.path.dirname(dirname)) |next_dirname| {
14141470 if (self.include_paths.contains(sub_path)) return true;
14151471 dirname = next_dirname;
14161472 }
src/Package/Manifest.zig+4-1
......@@ -318,7 +318,10 @@ const Parse = struct {
318318
319319 for (array_init.ast.elements) |elem_node| {
320320 const path_string = try parseString(p, elem_node);
321 try p.paths.put(p.gpa, path_string, {});
321 // This is normalized so that it can be used in string comparisons
322 // against file system paths.
323 const normalized = try std.fs.path.resolve(p.arena, &.{path_string});
324 try p.paths.put(p.gpa, normalized, {});
322325 }
323326 }
324327