| ... | @@ -499,13 +499,13 @@ const Report = struct { | ... | @@ -499,13 +499,13 @@ const Report = struct { |
| 499 | }; | 499 | }; |
| 500 | | 500 | |
| 501 | const FetchLocation = union(enum) { | 501 | const FetchLocation = union(enum) { |
| 502 | /// The absolute path to a file or directory. | 502 | /// The relative path to a file or directory. |
| 503 | /// This may be a file that requires unpacking (such as a .tar.gz), | 503 | /// This may be a file that requires unpacking (such as a .tar.gz), |
| 504 | /// or the path to the root directory of a package. | 504 | /// or the path to the root directory of a package. |
| 505 | file: []const u8, | 505 | file: []const u8, |
| 506 | http_request: std.Uri, | 506 | http_request: std.Uri, |
| 507 | | 507 | |
| 508 | pub fn init(gpa: Allocator, directory: Compilation.Directory, dep: Manifest.Dependency, report: Report) !FetchLocation { | 508 | pub fn init(gpa: Allocator, dep: Manifest.Dependency, report: Report) !FetchLocation { |
| 509 | switch (dep.location) { | 509 | switch (dep.location) { |
| 510 | .url => |url| { | 510 | .url => |url| { |
| 511 | const uri = std.Uri.parse(url) catch |err| switch (err) { | 511 | const uri = std.Uri.parse(url) catch |err| switch (err) { |
| ... | @@ -518,18 +518,11 @@ const FetchLocation = union(enum) { | ... | @@ -518,18 +518,11 @@ const FetchLocation = union(enum) { |
| 518 | return .{ .http_request = uri }; | 518 | return .{ .http_request = uri }; |
| 519 | }, | 519 | }, |
| 520 | .path => |path| { | 520 | .path => |path| { |
| 521 | const unescaped = try std.Uri.unescapeString(gpa, path); | 521 | if (fs.path.isAbsolute(path)) { |
| 522 | defer gpa.free(unescaped); | | |
| 523 | const unnormalized_path = try unnormalizePath(gpa, unescaped); | | |
| 524 | defer gpa.free(unnormalized_path); | | |
| 525 | | | |
| 526 | if (fs.path.isAbsolute(unnormalized_path)) { | | |
| 527 | return report.fail(dep.location_tok, "Absolute paths are not allowed. Use a relative path instead", .{}); | 522 | return report.fail(dep.location_tok, "Absolute paths are not allowed. Use a relative path instead", .{}); |
| 528 | } | 523 | } |
| 529 | | 524 | |
| 530 | const new_path = try fs.path.resolve(gpa, &.{ directory.path.?, unnormalized_path }); | 525 | return .{ .file = try gpa.dupe(u8, path) }; |
| 531 | | | |
| 532 | return .{ .file = new_path }; | | |
| 533 | }, | 526 | }, |
| 534 | } | 527 | } |
| 535 | } | 528 | } |
| ... | @@ -563,9 +556,9 @@ const FetchLocation = union(enum) { | ... | @@ -563,9 +556,9 @@ const FetchLocation = union(enum) { |
| 563 | return .{ | 556 | return .{ |
| 564 | .path = owned_path, | 557 | .path = owned_path, |
| 565 | .resource = if (is_dir) | 558 | .resource = if (is_dir) |
| 566 | .{ .directory = try fs.openIterableDirAbsolute(file, .{}) } | 559 | .{ .directory = try root_dir.handle.openIterableDir(file, .{}) } |
| 567 | else | 560 | else |
| 568 | .{ .file = try fs.openFileAbsolute(file, .{}) }, | 561 | .{ .file = try root_dir.handle.openFile(file, .{}) }, |
| 569 | }; | 562 | }; |
| 570 | }, | 563 | }, |
| 571 | .http_request => |uri| { | 564 | .http_request => |uri| { |
| ... | @@ -609,6 +602,7 @@ const ReadableResource = struct { | ... | @@ -609,6 +602,7 @@ const ReadableResource = struct { |
| 609 | rr: *ReadableResource, | 602 | rr: *ReadableResource, |
| 610 | allocator: Allocator, | 603 | allocator: Allocator, |
| 611 | thread_pool: *ThreadPool, | 604 | thread_pool: *ThreadPool, |
| | 605 | root_dir: Compilation.Directory, |
| 612 | global_cache_directory: Compilation.Directory, | 606 | global_cache_directory: Compilation.Directory, |
| 613 | dep: Manifest.Dependency, | 607 | dep: Manifest.Dependency, |
| 614 | report: Report, | 608 | report: Report, |
| ... | @@ -618,7 +612,8 @@ const ReadableResource = struct { | ... | @@ -618,7 +612,8 @@ const ReadableResource = struct { |
| 618 | .directory => { | 612 | .directory => { |
| 619 | return .{ | 613 | return .{ |
| 620 | .hash = computePathHash(rr.path), | 614 | .hash = computePathHash(rr.path), |
| 621 | .dir_path = try allocator.dupe(u8, rr.path), | 615 | .root_src_dir_path = try allocator.dupe(u8, rr.path), |
| | 616 | .root_dir = root_dir, |
| 622 | }; | 617 | }; |
| 623 | }, | 618 | }, |
| 624 | inline .file, .http_request => |*r| { | 619 | inline .file, .http_request => |*r| { |
| ... | @@ -684,15 +679,16 @@ const ReadableResource = struct { | ... | @@ -684,15 +679,16 @@ const ReadableResource = struct { |
| 684 | | 679 | |
| 685 | const pkg_dir_sub_path = "p" ++ s ++ Manifest.hexDigest(actual_hash); | 680 | const pkg_dir_sub_path = "p" ++ s ++ Manifest.hexDigest(actual_hash); |
| 686 | const unpacked_path = try global_cache_directory.join(allocator, &.{pkg_dir_sub_path}); | 681 | const unpacked_path = try global_cache_directory.join(allocator, &.{pkg_dir_sub_path}); |
| 687 | errdefer allocator.free(unpacked_path); | 682 | defer allocator.free(unpacked_path); |
| 688 | | 683 | |
| 689 | const relative_unpacked_path = try fs.path.relative(allocator, global_cache_directory.path.?, unpacked_path); | 684 | const relative_unpacked_path = try fs.path.relative(allocator, global_cache_directory.path.?, unpacked_path); |
| 690 | defer allocator.free(relative_unpacked_path); | 685 | errdefer allocator.free(relative_unpacked_path); |
| 691 | try renameTmpIntoCache(global_cache_directory.handle, tmp_dir_sub_path, relative_unpacked_path); | 686 | try renameTmpIntoCache(global_cache_directory.handle, tmp_dir_sub_path, relative_unpacked_path); |
| 692 | | 687 | |
| 693 | return .{ | 688 | return .{ |
| 694 | .hash = actual_hash, | 689 | .hash = actual_hash, |
| 695 | .dir_path = unpacked_path, | 690 | .root_src_dir_path = relative_unpacked_path, |
| | 691 | .root_dir = global_cache_directory, |
| 696 | }; | 692 | }; |
| 697 | }, | 693 | }, |
| 698 | } | 694 | } |
| ... | @@ -785,10 +781,11 @@ pub const PackageLocation = struct { | ... | @@ -785,10 +781,11 @@ pub const PackageLocation = struct { |
| 785 | /// For packages that require unpacking, this is the hash of the package contents. | 781 | /// For packages that require unpacking, this is the hash of the package contents. |
| 786 | /// For directories, this is the hash of the absolute file path. | 782 | /// For directories, this is the hash of the absolute file path. |
| 787 | hash: [Manifest.Hash.digest_length]u8, | 783 | hash: [Manifest.Hash.digest_length]u8, |
| 788 | dir_path: []const u8, | 784 | root_src_dir_path: []const u8, |
| | 785 | root_dir: Compilation.Directory, |
| 789 | | 786 | |
| 790 | pub fn deinit(pl: *PackageLocation, allocator: Allocator) void { | 787 | pub fn deinit(pl: *PackageLocation, allocator: Allocator) void { |
| 791 | allocator.free(pl.dir_path); | 788 | allocator.free(pl.root_src_dir_path); |
| 792 | pl.* = undefined; | 789 | pl.* = undefined; |
| 793 | } | 790 | } |
| 794 | }; | 791 | }; |
| ... | @@ -934,13 +931,13 @@ fn fetchAndUnpack( | ... | @@ -934,13 +931,13 @@ fn fetchAndUnpack( |
| 934 | pkg_prog_node.activate(); | 931 | pkg_prog_node.activate(); |
| 935 | pkg_prog_node.context.refresh(); | 932 | pkg_prog_node.context.refresh(); |
| 936 | | 933 | |
| 937 | var fetch_location = try FetchLocation.init(gpa, directory, dep.*, report); | 934 | var fetch_location = try FetchLocation.init(gpa, dep.*, report); |
| 938 | defer fetch_location.deinit(gpa); | 935 | defer fetch_location.deinit(gpa); |
| 939 | | 936 | |
| 940 | var readable_resource = try fetch_location.fetch(gpa, directory, http_client, dep.*, report); | 937 | var readable_resource = try fetch_location.fetch(gpa, directory, http_client, dep.*, report); |
| 941 | defer readable_resource.deinit(gpa); | 938 | defer readable_resource.deinit(gpa); |
| 942 | | 939 | |
| 943 | var package_location = try readable_resource.unpack(gpa, thread_pool, global_cache_directory, dep.*, report, &pkg_prog_node); | 940 | var package_location = try readable_resource.unpack(gpa, thread_pool, directory, global_cache_directory, dep.*, report, &pkg_prog_node); |
| 944 | defer package_location.deinit(gpa); | 941 | defer package_location.deinit(gpa); |
| 945 | | 942 | |
| 946 | const actual_hex = Manifest.hexDigest(package_location.hash); | 943 | const actual_hex = Manifest.hexDigest(package_location.hash); |
| ... | @@ -973,24 +970,23 @@ fn fetchAndUnpack( | ... | @@ -973,24 +970,23 @@ fn fetchAndUnpack( |
| 973 | return report.fail(dep.hash_tok, "hash not allowed for directory package", .{}); | 970 | return report.fail(dep.hash_tok, "hash not allowed for directory package", .{}); |
| 974 | } | 971 | } |
| 975 | // Since directory dependencies don't provide a hash in build.zig.zon, | 972 | // Since directory dependencies don't provide a hash in build.zig.zon, |
| 976 | // set the hash here to be the hash of the absolute path to the dependency. | 973 | // set the hash here to be the hash of the path to the dependency. |
| 977 | dep.hash = try gpa.dupe(u8, &actual_hex); | 974 | dep.hash = try gpa.dupe(u8, &actual_hex); |
| 978 | } | 975 | } |
| 979 | | 976 | |
| 980 | const build_zig_path = try std.fs.path.join(gpa, &.{ package_location.dir_path, build_zig_basename }); | 977 | const build_zig_path = try std.fs.path.join(gpa, &.{ package_location.root_src_dir_path, build_zig_basename }); |
| 981 | defer gpa.free(build_zig_path); | 978 | defer gpa.free(build_zig_path); |
| 982 | assert(fs.path.isAbsolute(build_zig_path)); | | |
| 983 | | 979 | |
| 984 | global_cache_directory.handle.access(build_zig_path, .{}) catch |err| switch (err) { | 980 | package_location.root_dir.handle.access(build_zig_path, .{}) catch |err| switch (err) { |
| 985 | error.FileNotFound => { | 981 | error.FileNotFound => { |
| 986 | const module = try create(gpa, package_location.dir_path, ""); | 982 | const module = try createWithDir(gpa, package_location.root_dir, package_location.root_src_dir_path, ""); |
| 987 | try all_modules.put(gpa, actual_hex, .{ .non_zig_pkg = module }); | 983 | try all_modules.put(gpa, actual_hex, .{ .non_zig_pkg = module }); |
| 988 | return .{ .non_zig_pkg = module }; | 984 | return .{ .non_zig_pkg = module }; |
| 989 | }, | 985 | }, |
| 990 | else => return err, | 986 | else => return err, |
| 991 | }; | 987 | }; |
| 992 | | 988 | |
| 993 | const module = try create(gpa, package_location.dir_path, build_zig_basename); | 989 | const module = try createWithDir(gpa, package_location.root_dir, package_location.root_src_dir_path, build_zig_basename); |
| 994 | try all_modules.put(gpa, actual_hex, .{ .zig_pkg = module }); | 990 | try all_modules.put(gpa, actual_hex, .{ .zig_pkg = module }); |
| 995 | return .{ .zig_pkg = module }; | 991 | return .{ .zig_pkg = module }; |
| 996 | } | 992 | } |
| ... | @@ -1126,25 +1122,6 @@ fn normalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 { | ... | @@ -1126,25 +1122,6 @@ fn normalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 { |
| 1126 | return normalized; | 1122 | return normalized; |
| 1127 | } | 1123 | } |
| 1128 | | 1124 | |
| 1129 | /// Make a OS-specific file system path | | |
| 1130 | /// This performs the inverse operation of normalizePath, | | |
| 1131 | /// converting forward slashes into backslashes on Windows | | |
| 1132 | fn unnormalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 { | | |
| 1133 | const canonical_sep = '/'; | | |
| 1134 | | | |
| 1135 | const unnormalized = try arena.dupe(u8, fs_path); | | |
| 1136 | if (fs.path.sep == canonical_sep) | | |
| 1137 | return unnormalized; | | |
| 1138 | | | |
| 1139 | for (unnormalized) |*byte| { | | |
| 1140 | switch (byte.*) { | | |
| 1141 | canonical_sep => byte.* = fs.path.sep, | | |
| 1142 | else => continue, | | |
| 1143 | } | | |
| 1144 | } | | |
| 1145 | return unnormalized; | | |
| 1146 | } | | |
| 1147 | | | |
| 1148 | fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void { | 1125 | fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void { |
| 1149 | defer wg.finish(); | 1126 | defer wg.finish(); |
| 1150 | hashed_file.failure = hashFileFallible(dir, hashed_file); | 1127 | hashed_file.failure = hashFileFallible(dir, hashed_file); |