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(...@@ -1249,6 +1249,9 @@ fn computeHash(
1249 var all_files = std.ArrayList(*HashedFile).init(gpa);1249 var all_files = std.ArrayList(*HashedFile).init(gpa);
1250 defer all_files.deinit();1250 defer all_files.deinit();
12511251
1252 var all_deletions = std.ArrayList(*DeletedFile).init(gpa);
1253 defer all_deletions.deinit();
1254
1252 var walker = try @as(fs.IterableDir, .{ .dir = tmp_directory.handle }).walk(gpa);1255 var walker = try @as(fs.IterableDir, .{ .dir = tmp_directory.handle }).walk(gpa);
1253 defer walker.deinit();1256 defer walker.deinit();
12541257
...@@ -1267,10 +1270,25 @@ fn computeHash(...@@ -1267,10 +1270,25 @@ fn computeHash(
1267 ) });1270 ) });
1268 return error.FetchFailed;1271 return error.FetchFailed;
1269 }) |entry| {1272 }) |entry| {
1270 _ = filter; // TODO: apply filter rules here1273 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
1272 const kind: HashedFile.Kind = switch (entry.kind) {1290 const kind: HashedFile.Kind = switch (entry.kind) {
1273 .directory => continue,1291 .directory => unreachable,
1274 .file => .file,1292 .file => .file,
1275 .sym_link => .sym_link,1293 .sym_link => .sym_link,
1276 else => return f.fail(f.location_tok, try eb.printString(1294 else => return f.fail(f.location_tok, try eb.printString(
...@@ -1295,7 +1313,6 @@ fn computeHash(...@@ -1295,7 +1313,6 @@ fn computeHash(
1295 try thread_pool.spawn(workerHashFile, .{1313 try thread_pool.spawn(workerHashFile, .{
1296 tmp_directory.handle, hashed_file, &wait_group,1314 tmp_directory.handle, hashed_file, &wait_group,
1297 });1315 });
1298
1299 try all_files.append(hashed_file);1316 try all_files.append(hashed_file);
1300 }1317 }
1301 }1318 }
...@@ -1315,6 +1332,17 @@ fn computeHash(...@@ -1315,6 +1332,17 @@ fn computeHash(
1315 };1332 };
1316 hasher.update(&hashed_file.hash);1333 hasher.update(&hashed_file.hash);
1317 }1334 }
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
1318 if (any_failures) return error.FetchFailed;1346 if (any_failures) return error.FetchFailed;
1319 return hasher.finalResult();1347 return hasher.finalResult();
1320}1348}
...@@ -1324,6 +1352,11 @@ fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {...@@ -1324,6 +1352,11 @@ fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {
1324 hashed_file.failure = hashFileFallible(dir, hashed_file);1352 hashed_file.failure = hashFileFallible(dir, hashed_file);
1325}1353}
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
1327fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {1360fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {
1328 var buf: [8000]u8 = undefined;1361 var buf: [8000]u8 = undefined;
1329 var hasher = Manifest.Hash.init(.{});1362 var hasher = Manifest.Hash.init(.{});
...@@ -1347,6 +1380,20 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void...@@ -1347,6 +1380,20 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
1347 hasher.final(&hashed_file.hash);1380 hasher.final(&hashed_file.hash);
1348}1381}
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
1350fn isExecutable(file: fs.File) !bool {1397fn isExecutable(file: fs.File) !bool {
1351 if (builtin.os.tag == .windows) {1398 if (builtin.os.tag == .windows) {
1352 // TODO check the ACL on Windows.1399 // TODO check the ACL on Windows.
...@@ -1360,6 +1407,15 @@ fn isExecutable(file: fs.File) !bool {...@@ -1360,6 +1407,15 @@ fn isExecutable(file: fs.File) !bool {
1360 }1407 }
1361}1408}
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
1363const HashedFile = struct {1419const HashedFile = struct {
1364 fs_path: []const u8,1420 fs_path: []const u8,
1365 normalized_path: []const u8,1421 normalized_path: []const u8,
...@@ -1402,7 +1458,7 @@ fn normalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 {...@@ -1402,7 +1458,7 @@ fn normalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 {
1402const Filter = struct {1458const Filter = struct {
1403 include_paths: std.StringArrayHashMapUnmanaged(void) = .{},1459 include_paths: std.StringArrayHashMapUnmanaged(void) = .{},
14041460
1405 /// sub_path is relative to the tarball root.1461 /// sub_path is relative to the package root.
1406 pub fn includePath(self: Filter, sub_path: []const u8) bool {1462 pub fn includePath(self: Filter, sub_path: []const u8) bool {
1407 if (self.include_paths.count() == 0) return true;1463 if (self.include_paths.count() == 0) return true;
1408 if (self.include_paths.contains("")) return true;1464 if (self.include_paths.contains("")) return true;
...@@ -1410,7 +1466,7 @@ const Filter = struct {...@@ -1410,7 +1466,7 @@ const Filter = struct {
14101466
1411 // Check if any included paths are parent directories of sub_path.1467 // Check if any included paths are parent directories of sub_path.
1412 var dirname = sub_path;1468 var dirname = sub_path;
1413 while (std.fs.path.dirname(sub_path)) |next_dirname| {1469 while (std.fs.path.dirname(dirname)) |next_dirname| {
1414 if (self.include_paths.contains(sub_path)) return true;1470 if (self.include_paths.contains(sub_path)) return true;
1415 dirname = next_dirname;1471 dirname = next_dirname;
1416 }1472 }
src/Package/Manifest.zig+4-1
...@@ -318,7 +318,10 @@ const Parse = struct {...@@ -318,7 +318,10 @@ const Parse = struct {
318318
319 for (array_init.ast.elements) |elem_node| {319 for (array_init.ast.elements) |elem_node| {
320 const path_string = try parseString(p, elem_node);320 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, {});
322 }325 }
323 }326 }
324327