Skip to content

Commit 4594206

Browse files
AdamGoertzandrewrk
authored andcommitted
Fix diamond dependencies with directory packages
1 parent c6b9205 commit 4594206

File tree

1 file changed

+54
-30
lines changed

1 file changed

+54
-30
lines changed

src/Package.zig

+54-30
Original file line numberDiff line numberDiff line change
@@ -311,19 +311,34 @@ pub fn fetchAndAddDependencies(
311311
}
312312

313313
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+
314327
const sub_mod, const found_existing = try getCachedPackage(
315328
arena,
329+
fetch_location,
316330
global_cache_directory,
317331
dep.*,
318332
all_modules,
319333
root_prog_node,
320334
) orelse .{
321335
try fetchAndUnpack(
336+
fetch_location,
322337
thread_pool,
323338
http_client,
324339
directory,
325340
global_cache_directory,
326-
dep,
341+
dep.*,
327342
report,
328343
all_modules,
329344
root_prog_node,
@@ -503,9 +518,10 @@ const FetchLocation = union(enum) {
503518
/// This may be a file that requires unpacking (such as a .tar.gz),
504519
/// or the path to the root directory of a package.
505520
file: []const u8,
521+
directory: []const u8,
506522
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 {
509525
switch (dep.location) {
510526
.url => |url| {
511527
const uri = std.Uri.parse(url) catch |err| switch (err) {
@@ -522,14 +538,22 @@ const FetchLocation = union(enum) {
522538
return report.fail(dep.location_tok, "Absolute paths are not allowed. Use a relative path instead", .{});
523539
}
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) };
526550
},
527551
}
528552
}
529553

530554
pub fn deinit(f: *FetchLocation, gpa: Allocator) void {
531555
switch (f.*) {
532-
.file => |path| gpa.free(path),
556+
inline .file, .directory => |path| gpa.free(path),
533557
.http_request => {},
534558
}
535559
f.* = undefined;
@@ -545,20 +569,19 @@ const FetchLocation = union(enum) {
545569
) !ReadableResource {
546570
switch (f) {
547571
.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-
553572
const owned_path = try gpa.dupe(u8, file);
554573
errdefer gpa.free(owned_path);
555-
556574
return .{
557575
.path = owned_path,
558-
.resource = if (is_dir)
559-
.{ .directory = try root_dir.handle.openIterableDir(file, .{}) }
560-
else
561-
.{ .file = try root_dir.handle.openFile(file, .{}) },
576+
.resource = .{ .file = try root_dir.handle.openFile(file, .{}) },
577+
};
578+
},
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, .{}) },
562585
};
563586
},
564587
.http_request => |uri| {
@@ -611,7 +634,7 @@ const ReadableResource = struct {
611634
switch (rr.resource) {
612635
.directory => {
613636
return .{
614-
.hash = computePathHash(rr.path),
637+
.hash = try computePathHash(allocator, root_dir, rr.path),
615638
.root_src_dir_path = try allocator.dupe(u8, rr.path),
616639
.root_dir = root_dir,
617640
};
@@ -851,11 +874,19 @@ fn ProgressReader(comptime ReaderType: type) type {
851874
/// (i.e. whether or not its transitive dependencies have been fetched).
852875
fn getCachedPackage(
853876
gpa: Allocator,
877+
fetch_location: FetchLocation,
854878
global_cache_directory: Compilation.Directory,
855879
dep: Manifest.Dependency,
856880
all_modules: *AllModules,
857881
root_prog_node: *std.Progress.Node,
858882
) !?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+
859890
const s = fs.path.sep_str;
860891
// Check if the expected_hash is already present in the global package
861892
// cache, and thereby avoid both fetching and unpacking.
@@ -912,11 +943,12 @@ fn getCachedPackage(
912943
}
913944

914945
fn fetchAndUnpack(
946+
fetch_location: FetchLocation,
915947
thread_pool: *ThreadPool,
916948
http_client: *std.http.Client,
917949
directory: Compilation.Directory,
918950
global_cache_directory: Compilation.Directory,
919-
dep: *Manifest.Dependency,
951+
dep: Manifest.Dependency,
920952
report: Report,
921953
all_modules: *AllModules,
922954
root_prog_node: *std.Progress.Node,
@@ -931,13 +963,10 @@ fn fetchAndUnpack(
931963
pkg_prog_node.activate();
932964
pkg_prog_node.context.refresh();
933965

934-
var fetch_location = try FetchLocation.init(gpa, dep.*, report);
935-
defer fetch_location.deinit(gpa);
936-
937-
var readable_resource = try fetch_location.fetch(gpa, directory, http_client, dep.*, report);
966+
var readable_resource = try fetch_location.fetch(gpa, directory, http_client, dep, report);
938967
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);
941970
defer package_location.deinit(gpa);
942971

943972
const actual_hex = Manifest.hexDigest(package_location.hash);
@@ -965,13 +994,6 @@ fn fetchAndUnpack(
965994
}));
966995
return error.PackageFetchFailed;
967996
}
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);
975997
}
976998

977999
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(
10891111
}
10901112

10911113
/// Compute the hash of a file path.
1092-
fn computePathHash(path: []const u8) [Manifest.Hash.digest_length]u8 {
1114+
fn 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);
10931117
var hasher = Manifest.Hash.init(.{});
1094-
hasher.update(path);
1118+
hasher.update(resolved_path);
10951119
return hasher.finalResult();
10961120
}
10971121

0 commit comments

Comments
 (0)