authorgravatar for adambgoertz@gmail.comAdam Goertz <adambgoertz@gmail.com> 2023-09-27 01:29:28-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-29 00:32:43-07:00
log4594206e72475f1fb5900e986be039ebe54d43d9
tree57a6ce4a53e1e316034a4be9ad95150a5bf77807
parentc6b92050055537d9edbdda10d5c215e5d9f327a0

Fix diamond dependencies with directory packages


1 files changed, 54 insertions(+), 30 deletions(-)

src/Package.zig+54-30
...@@ -311,19 +311,34 @@ pub fn fetchAndAddDependencies(...@@ -311,19 +311,34 @@ pub fn fetchAndAddDependencies(
311 }311 }
312312
313 for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, *dep| {313 for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, *dep| {
314 var fetch_location = try FetchLocation.init(gpa, dep.*, directory, report);
315 defer fetch_location.deinit(gpa);
316
317 // Directories do not provide a hash in build.zig.zon.
318 // Hash the path to the module rather than its contents.
319 if (fetch_location == .directory) {
320 if (dep.hash != null) {
321 return report.fail(dep.hash_tok, "hash not allowed for directory package", .{});
322 }
323 const hex_digest = Manifest.hexDigest(try computePathHash(gpa, directory, fetch_location.directory));
324 dep.hash = try gpa.dupe(u8, &hex_digest);
325 }
326
314 const sub_mod, const found_existing = try getCachedPackage(327 const sub_mod, const found_existing = try getCachedPackage(
315 arena,328 arena,
329 fetch_location,
316 global_cache_directory,330 global_cache_directory,
317 dep.*,331 dep.*,
318 all_modules,332 all_modules,
319 root_prog_node,333 root_prog_node,
320 ) orelse .{334 ) orelse .{
321 try fetchAndUnpack(335 try fetchAndUnpack(
336 fetch_location,
322 thread_pool,337 thread_pool,
323 http_client,338 http_client,
324 directory,339 directory,
325 global_cache_directory,340 global_cache_directory,
326 dep,341 dep.*,
327 report,342 report,
328 all_modules,343 all_modules,
329 root_prog_node,344 root_prog_node,
...@@ -503,9 +518,10 @@ const FetchLocation = union(enum) {...@@ -503,9 +518,10 @@ const FetchLocation = union(enum) {
503 /// This may be a file that requires unpacking (such as a .tar.gz),518 /// This may be a file that requires unpacking (such as a .tar.gz),
504 /// or the path to the root directory of a package.519 /// or the path to the root directory of a package.
505 file: []const u8,520 file: []const u8,
521 directory: []const u8,
506 http_request: std.Uri,522 http_request: std.Uri,
507523
508 pub fn init(gpa: Allocator, dep: Manifest.Dependency, report: Report) !FetchLocation {524 pub fn init(gpa: Allocator, dep: Manifest.Dependency, root_dir: Compilation.Directory, report: Report) !FetchLocation {
509 switch (dep.location) {525 switch (dep.location) {
510 .url => |url| {526 .url => |url| {
511 const uri = std.Uri.parse(url) catch |err| switch (err) {527 const uri = std.Uri.parse(url) catch |err| switch (err) {
...@@ -522,14 +538,22 @@ const FetchLocation = union(enum) {...@@ -522,14 +538,22 @@ const FetchLocation = union(enum) {
522 return report.fail(dep.location_tok, "Absolute paths are not allowed. Use a relative path instead", .{});538 return report.fail(dep.location_tok, "Absolute paths are not allowed. Use a relative path instead", .{});
523 }539 }
524540
525 return .{ .file = try gpa.dupe(u8, path) };541 const is_dir = isDirectory(root_dir, path) catch |err| switch (err) {
542 error.FileNotFound => return report.fail(dep.location_tok, "File not found: {s}", .{path}),
543 else => return err,
544 };
545
546 return if (is_dir)
547 .{ .directory = try gpa.dupe(u8, path) }
548 else
549 .{ .file = try gpa.dupe(u8, path) };
526 },550 },
527 }551 }
528 }552 }
529553
530 pub fn deinit(f: *FetchLocation, gpa: Allocator) void {554 pub fn deinit(f: *FetchLocation, gpa: Allocator) void {
531 switch (f.*) {555 switch (f.*) {
532 .file => |path| gpa.free(path),556 inline .file, .directory => |path| gpa.free(path),
533 .http_request => {},557 .http_request => {},
534 }558 }
535 f.* = undefined;559 f.* = undefined;
...@@ -545,20 +569,19 @@ const FetchLocation = union(enum) {...@@ -545,20 +569,19 @@ const FetchLocation = union(enum) {
545 ) !ReadableResource {569 ) !ReadableResource {
546 switch (f) {570 switch (f) {
547 .file => |file| {571 .file => |file| {
548 const is_dir = isDirectory(root_dir, file) catch |err| switch (err) {
549 error.FileNotFound => return report.fail(dep.location_tok, "File not found: {s}", .{file}),
550 else => return err,
551 };
552
553 const owned_path = try gpa.dupe(u8, file);572 const owned_path = try gpa.dupe(u8, file);
554 errdefer gpa.free(owned_path);573 errdefer gpa.free(owned_path);
555
556 return .{574 return .{
557 .path = owned_path,575 .path = owned_path,
558 .resource = if (is_dir)576 .resource = .{ .file = try root_dir.handle.openFile(file, .{}) },
559 .{ .directory = try root_dir.handle.openIterableDir(file, .{}) }577 };
560 else578 },
561 .{ .file = try root_dir.handle.openFile(file, .{}) },579 .directory => |dir| {
580 const owned_path = try gpa.dupe(u8, dir);
581 errdefer gpa.free(owned_path);
582 return .{
583 .path = owned_path,
584 .resource = .{ .directory = try root_dir.handle.openIterableDir(dir, .{}) },
562 };585 };
563 },586 },
564 .http_request => |uri| {587 .http_request => |uri| {
...@@ -611,7 +634,7 @@ const ReadableResource = struct {...@@ -611,7 +634,7 @@ const ReadableResource = struct {
611 switch (rr.resource) {634 switch (rr.resource) {
612 .directory => {635 .directory => {
613 return .{636 return .{
614 .hash = computePathHash(rr.path),637 .hash = try computePathHash(allocator, root_dir, rr.path),
615 .root_src_dir_path = try allocator.dupe(u8, rr.path),638 .root_src_dir_path = try allocator.dupe(u8, rr.path),
616 .root_dir = root_dir,639 .root_dir = root_dir,
617 };640 };
...@@ -851,11 +874,19 @@ fn ProgressReader(comptime ReaderType: type) type {...@@ -851,11 +874,19 @@ fn ProgressReader(comptime ReaderType: type) type {
851/// (i.e. whether or not its transitive dependencies have been fetched).874/// (i.e. whether or not its transitive dependencies have been fetched).
852fn getCachedPackage(875fn getCachedPackage(
853 gpa: Allocator,876 gpa: Allocator,
877 fetch_location: FetchLocation,
854 global_cache_directory: Compilation.Directory,878 global_cache_directory: Compilation.Directory,
855 dep: Manifest.Dependency,879 dep: Manifest.Dependency,
856 all_modules: *AllModules,880 all_modules: *AllModules,
857 root_prog_node: *std.Progress.Node,881 root_prog_node: *std.Progress.Node,
858) !?struct { DependencyModule, bool } {882) !?struct { DependencyModule, bool } {
883 // There is no fixed location to check for directory modules.
884 // Instead, check whether it is already listed in all_modules.
885 if (fetch_location == .directory) {
886 const hex_digest = dep.hash.?[0..hex_multihash_len];
887 return if (all_modules.get(hex_digest.*)) |mod| .{ mod.?, true } else null;
888 }
889
859 const s = fs.path.sep_str;890 const s = fs.path.sep_str;
860 // Check if the expected_hash is already present in the global package891 // Check if the expected_hash is already present in the global package
861 // cache, and thereby avoid both fetching and unpacking.892 // cache, and thereby avoid both fetching and unpacking.
...@@ -912,11 +943,12 @@ fn getCachedPackage(...@@ -912,11 +943,12 @@ fn getCachedPackage(
912}943}
913944
914fn fetchAndUnpack(945fn fetchAndUnpack(
946 fetch_location: FetchLocation,
915 thread_pool: *ThreadPool,947 thread_pool: *ThreadPool,
916 http_client: *std.http.Client,948 http_client: *std.http.Client,
917 directory: Compilation.Directory,949 directory: Compilation.Directory,
918 global_cache_directory: Compilation.Directory,950 global_cache_directory: Compilation.Directory,
919 dep: *Manifest.Dependency,951 dep: Manifest.Dependency,
920 report: Report,952 report: Report,
921 all_modules: *AllModules,953 all_modules: *AllModules,
922 root_prog_node: *std.Progress.Node,954 root_prog_node: *std.Progress.Node,
...@@ -931,13 +963,10 @@ fn fetchAndUnpack(...@@ -931,13 +963,10 @@ fn fetchAndUnpack(
931 pkg_prog_node.activate();963 pkg_prog_node.activate();
932 pkg_prog_node.context.refresh();964 pkg_prog_node.context.refresh();
933965
934 var fetch_location = try FetchLocation.init(gpa, dep.*, report);966 var readable_resource = try fetch_location.fetch(gpa, directory, http_client, dep, report);
935 defer fetch_location.deinit(gpa);
936
937 var readable_resource = try fetch_location.fetch(gpa, directory, http_client, dep.*, report);
938 defer readable_resource.deinit(gpa);967 defer readable_resource.deinit(gpa);
939968
940 var package_location = try readable_resource.unpack(gpa, thread_pool, directory, global_cache_directory, dep.*, report, &pkg_prog_node);969 var package_location = try readable_resource.unpack(gpa, thread_pool, directory, global_cache_directory, dep, report, &pkg_prog_node);
941 defer package_location.deinit(gpa);970 defer package_location.deinit(gpa);
942971
943 const actual_hex = Manifest.hexDigest(package_location.hash);972 const actual_hex = Manifest.hexDigest(package_location.hash);
...@@ -965,13 +994,6 @@ fn fetchAndUnpack(...@@ -965,13 +994,6 @@ fn fetchAndUnpack(
965 }));994 }));
966 return error.PackageFetchFailed;995 return error.PackageFetchFailed;
967 }996 }
968 } else {
969 if (dep.hash != null) {
970 return report.fail(dep.hash_tok, "hash not allowed for directory package", .{});
971 }
972 // Since directory dependencies don't provide a hash in build.zig.zon,
973 // set the hash here to be the hash of the path to the dependency.
974 dep.hash = try gpa.dupe(u8, &actual_hex);
975 }997 }
976998
977 const build_zig_path = try std.fs.path.join(gpa, &.{ package_location.root_src_dir_path, build_zig_basename });999 const build_zig_path = try std.fs.path.join(gpa, &.{ package_location.root_src_dir_path, build_zig_basename });
...@@ -1089,9 +1111,11 @@ fn computePackageHash(...@@ -1089,9 +1111,11 @@ fn computePackageHash(
1089}1111}
10901112
1091/// Compute the hash of a file path.1113/// Compute the hash of a file path.
1092fn computePathHash(path: []const u8) [Manifest.Hash.digest_length]u8 {1114fn computePathHash(gpa: Allocator, dir: Compilation.Directory, path: []const u8) ![Manifest.Hash.digest_length]u8 {
1115 const resolved_path = try std.fs.path.resolve(gpa, &.{ dir.path.?, path });
1116 defer gpa.free(resolved_path);
1093 var hasher = Manifest.Hash.init(.{});1117 var hasher = Manifest.Hash.init(.{});
1094 hasher.update(path);1118 hasher.update(resolved_path);
1095 return hasher.finalResult();1119 return hasher.finalResult();
1096}1120}
10971121