@@ -311,19 +311,34 @@ pub fn fetchAndAddDependencies(
311
311
}
312
312
313
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
327
const sub_mod , const found_existing = try getCachedPackage (
315
328
arena ,
329
+ fetch_location ,
316
330
global_cache_directory ,
317
331
dep .* ,
318
332
all_modules ,
319
333
root_prog_node ,
320
334
) orelse .{
321
335
try fetchAndUnpack (
336
+ fetch_location ,
322
337
thread_pool ,
323
338
http_client ,
324
339
directory ,
325
340
global_cache_directory ,
326
- dep ,
341
+ dep .* ,
327
342
report ,
328
343
all_modules ,
329
344
root_prog_node ,
@@ -503,9 +518,10 @@ const FetchLocation = union(enum) {
503
518
/// This may be a file that requires unpacking (such as a .tar.gz),
504
519
/// or the path to the root directory of a package.
505
520
file : []const u8 ,
521
+ directory : []const u8 ,
506
522
http_request : std.Uri ,
507
523
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
525
switch (dep .location ) {
510
526
.url = > | url | {
511
527
const uri = std .Uri .parse (url ) catch | err | switch (err ) {
@@ -522,14 +538,22 @@ const FetchLocation = union(enum) {
522
538
return report .fail (dep .location_tok , "Absolute paths are not allowed. Use a relative path instead" , .{});
523
539
}
524
540
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
}
529
553
530
554
pub fn deinit (f : * FetchLocation , gpa : Allocator ) void {
531
555
switch (f .* ) {
532
- .file = > | path | gpa .free (path ),
556
+ inline .file , .directory = > | path | gpa .free (path ),
533
557
.http_request = > {},
534
558
}
535
559
f .* = undefined ;
@@ -545,20 +569,19 @@ const FetchLocation = union(enum) {
545
569
) ! ReadableResource {
546
570
switch (f ) {
547
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
572
const owned_path = try gpa .dupe (u8 , file );
554
573
errdefer gpa .free (owned_path );
555
-
556
574
return .{
557
575
.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 , .{}) },
562
585
};
563
586
},
564
587
.http_request = > | uri | {
@@ -611,7 +634,7 @@ const ReadableResource = struct {
611
634
switch (rr .resource ) {
612
635
.directory = > {
613
636
return .{
614
- .hash = computePathHash (rr .path ),
637
+ .hash = try computePathHash (allocator , root_dir , rr .path ),
615
638
.root_src_dir_path = try allocator .dupe (u8 , rr .path ),
616
639
.root_dir = root_dir ,
617
640
};
@@ -851,11 +874,19 @@ fn ProgressReader(comptime ReaderType: type) type {
851
874
/// (i.e. whether or not its transitive dependencies have been fetched).
852
875
fn getCachedPackage (
853
876
gpa : Allocator ,
877
+ fetch_location : FetchLocation ,
854
878
global_cache_directory : Compilation.Directory ,
855
879
dep : Manifest.Dependency ,
856
880
all_modules : * AllModules ,
857
881
root_prog_node : * std.Progress.Node ,
858
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
890
const s = fs .path .sep_str ;
860
891
// Check if the expected_hash is already present in the global package
861
892
// cache, and thereby avoid both fetching and unpacking.
@@ -912,11 +943,12 @@ fn getCachedPackage(
912
943
}
913
944
914
945
fn fetchAndUnpack (
946
+ fetch_location : FetchLocation ,
915
947
thread_pool : * ThreadPool ,
916
948
http_client : * std.http.Client ,
917
949
directory : Compilation.Directory ,
918
950
global_cache_directory : Compilation.Directory ,
919
- dep : * Manifest.Dependency ,
951
+ dep : Manifest.Dependency ,
920
952
report : Report ,
921
953
all_modules : * AllModules ,
922
954
root_prog_node : * std.Progress.Node ,
@@ -931,13 +963,10 @@ fn fetchAndUnpack(
931
963
pkg_prog_node .activate ();
932
964
pkg_prog_node .context .refresh ();
933
965
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 );
938
967
defer readable_resource .deinit (gpa );
939
968
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
970
defer package_location .deinit (gpa );
942
971
943
972
const actual_hex = Manifest .hexDigest (package_location .hash );
@@ -965,13 +994,6 @@ fn fetchAndUnpack(
965
994
}));
966
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
}
976
998
977
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
1111
}
1090
1112
1091
1113
/// 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 );
1093
1117
var hasher = Manifest .Hash .init (.{});
1094
- hasher .update (path );
1118
+ hasher .update (resolved_path );
1095
1119
return hasher .finalResult ();
1096
1120
}
1097
1121
0 commit comments