| ... | @@ -40,6 +40,7 @@ const native_os = builtin.os.tag; | ... | @@ -40,6 +40,7 @@ const native_os = builtin.os.tag; |
| 40 | const std = @import("std"); | 40 | const std = @import("std"); |
| 41 | const Io = std.Io; | 41 | const Io = std.Io; |
| 42 | const fs = std.fs; | 42 | const fs = std.fs; |
| | 43 | const log = std.log.scoped(.fetch); |
| 43 | const assert = std.debug.assert; | 44 | const assert = std.debug.assert; |
| 44 | const ascii = std.ascii; | 45 | const ascii = std.ascii; |
| 45 | const Allocator = std.mem.Allocator; | 46 | const Allocator = std.mem.Allocator; |
| ... | @@ -324,7 +325,7 @@ pub const JobQueue = struct { | ... | @@ -324,7 +325,7 @@ pub const JobQueue = struct { |
| 324 | error.Canceled => |e| return e, | 325 | error.Canceled => |e| return e, |
| 325 | error.ReadFailed => comptime unreachable, | 326 | error.ReadFailed => comptime unreachable, |
| 326 | error.WriteFailed => comptime unreachable, | 327 | error.WriteFailed => comptime unreachable, |
| 327 | else => |e| std.log.warn("failed caching recompressed tarball to {f}: {t}", .{ dest_path, e }), | 328 | else => |e| log.warn("failed caching recompressed tarball to {f}: {t}", .{ dest_path, e }), |
| 328 | }; | 329 | }; |
| 329 | } | 330 | } |
| 330 | | 331 | |
| ... | @@ -508,14 +509,14 @@ pub fn run(f: *Fetch) RunError!void { | ... | @@ -508,14 +509,14 @@ pub fn run(f: *Fetch) RunError!void { |
| 508 | .path_or_url => |path_or_url| { | 509 | .path_or_url => |path_or_url| { |
| 509 | if (Io.Dir.cwd().openDir(io, path_or_url, .{ .iterate = true })) |dir| { | 510 | if (Io.Dir.cwd().openDir(io, path_or_url, .{ .iterate = true })) |dir| { |
| 510 | var resource: Resource = .{ .dir = dir }; | 511 | var resource: Resource = .{ .dir = dir }; |
| 511 | return f.runResource(path_or_url, &resource, null); | 512 | return f.runResource(path_or_url, &resource, null, false); |
| 512 | } else |dir_err| { | 513 | } else |dir_err| { |
| 513 | var server_header_buffer: [init_resource_buffer_size]u8 = undefined; | 514 | var server_header_buffer: [init_resource_buffer_size]u8 = undefined; |
| 514 | | 515 | |
| 515 | const file_err = if (dir_err == error.NotDir) e: { | 516 | const file_err = if (dir_err == error.NotDir) e: { |
| 516 | if (Io.Dir.cwd().openFile(io, path_or_url, .{})) |file| { | 517 | if (Io.Dir.cwd().openFile(io, path_or_url, .{})) |file| { |
| 517 | var resource: Resource = .{ .file = file.reader(io, &server_header_buffer) }; | 518 | var resource: Resource = .{ .file = file.reader(io, &server_header_buffer) }; |
| 518 | return f.runResource(path_or_url, &resource, null); | 519 | return f.runResource(path_or_url, &resource, null, false); |
| 519 | } else |err| break :e err; | 520 | } else |err| break :e err; |
| 520 | } else dir_err; | 521 | } else dir_err; |
| 521 | | 522 | |
| ... | @@ -527,11 +528,13 @@ pub fn run(f: *Fetch) RunError!void { | ... | @@ -527,11 +528,13 @@ pub fn run(f: *Fetch) RunError!void { |
| 527 | }; | 528 | }; |
| 528 | var resource: Resource = undefined; | 529 | var resource: Resource = undefined; |
| 529 | try f.initResource(uri, &resource, &server_header_buffer); | 530 | try f.initResource(uri, &resource, &server_header_buffer); |
| 530 | return f.runResource(try uri.path.toRawMaybeAlloc(arena), &resource, null); | 531 | return f.runResource(try uri.path.toRawMaybeAlloc(arena), &resource, null, false); |
| 531 | } | 532 | } |
| 532 | }, | 533 | }, |
| 533 | }; | 534 | }; |
| 534 | | 535 | |
| | 536 | var resource_buffer: [init_resource_buffer_size]u8 = undefined; |
| | 537 | |
| 535 | if (remote.hash) |expected_hash| { | 538 | if (remote.hash) |expected_hash| { |
| 536 | const package_root = try job_queue.root_pkg_path.join(arena, expected_hash.toSlice()); | 539 | const package_root = try job_queue.root_pkg_path.join(arena, expected_hash.toSlice()); |
| 537 | if (package_root.root_dir.handle.access(io, package_root.sub_path, .{})) |_| { | 540 | if (package_root.root_dir.handle.access(io, package_root.sub_path, .{})) |_| { |
| ... | @@ -543,19 +546,13 @@ pub fn run(f: *Fetch) RunError!void { | ... | @@ -543,19 +546,13 @@ pub fn run(f: *Fetch) RunError!void { |
| 543 | return queueJobsForDeps(f); | 546 | return queueJobsForDeps(f); |
| 544 | } else |err| switch (err) { | 547 | } else |err| switch (err) { |
| 545 | error.FileNotFound => { | 548 | error.FileNotFound => { |
| 546 | switch (f.lazy_status) { | 549 | log.debug("FileNotFound: {f}", .{package_root}); |
| 547 | .eager => {}, | | |
| 548 | .available => if (!job_queue.unlazy_set.contains(expected_hash)) { | | |
| 549 | f.lazy_status = .unavailable; | | |
| 550 | return; | | |
| 551 | }, | | |
| 552 | .unavailable => unreachable, | | |
| 553 | } | | |
| 554 | if (job_queue.read_only) return f.fail( | 550 | if (job_queue.read_only) return f.fail( |
| 555 | f.name_tok, | 551 | f.name_tok, |
| 556 | try eb.printString("package not found at '{f}'", .{package_root}), | 552 | try eb.printString("package not found at '{f}'", .{package_root}), |
| 557 | ); | 553 | ); |
| 558 | }, | 554 | }, |
| | 555 | error.Canceled => |e| return e, |
| 559 | else => |e| { | 556 | else => |e| { |
| 560 | try eb.addRootErrorMessage(.{ | 557 | try eb.addRootErrorMessage(.{ |
| 561 | .msg = try eb.printString("unable to open package cache directory {f}: {t}", .{ | 558 | .msg = try eb.printString("unable to open package cache directory {f}: {t}", .{ |
| ... | @@ -565,6 +562,38 @@ pub fn run(f: *Fetch) RunError!void { | ... | @@ -565,6 +562,38 @@ pub fn run(f: *Fetch) RunError!void { |
| 565 | return error.FetchFailed; | 562 | return error.FetchFailed; |
| 566 | }, | 563 | }, |
| 567 | } | 564 | } |
| | 565 | |
| | 566 | // Check global cache before remote fetch. |
| | 567 | const cached_tarball_sub_path = try std.fmt.allocPrint(arena, "p/{s}.tar.gz", .{expected_hash.toSlice()}); |
| | 568 | const cached_tarball_path: Cache.Path = .{ |
| | 569 | .root_dir = job_queue.global_cache, |
| | 570 | .sub_path = cached_tarball_sub_path, |
| | 571 | }; |
| | 572 | if (cached_tarball_path.root_dir.handle.openFile(io, cached_tarball_path.sub_path, .{})) |file| { |
| | 573 | log.debug("found global cached tarball {f}", .{cached_tarball_path}); |
| | 574 | var resource: Resource = .{ .file = file.reader(io, &resource_buffer) }; |
| | 575 | return f.runResource(cached_tarball_sub_path, &resource, remote.hash, true); |
| | 576 | } else |err| switch (err) { |
| | 577 | error.FileNotFound => log.debug("FileNotFound: {f}", .{cached_tarball_path}), |
| | 578 | error.Canceled => |e| return e, |
| | 579 | else => |e| { |
| | 580 | try eb.addRootErrorMessage(.{ |
| | 581 | .msg = try eb.printString("unable to open globally cached package {f}: {t}", .{ |
| | 582 | cached_tarball_path, e, |
| | 583 | }), |
| | 584 | }); |
| | 585 | return error.FetchFailed; |
| | 586 | }, |
| | 587 | } |
| | 588 | |
| | 589 | switch (f.lazy_status) { |
| | 590 | .eager => {}, |
| | 591 | .available => if (!job_queue.unlazy_set.contains(expected_hash)) { |
| | 592 | f.lazy_status = .unavailable; |
| | 593 | return; |
| | 594 | }, |
| | 595 | .unavailable => unreachable, |
| | 596 | } |
| 568 | } else if (job_queue.read_only) { | 597 | } else if (job_queue.read_only) { |
| 569 | try eb.addRootErrorMessage(.{ | 598 | try eb.addRootErrorMessage(.{ |
| 570 | .msg = try eb.addString("dependency is missing hash field"), | 599 | .msg = try eb.addString("dependency is missing hash field"), |
| ... | @@ -574,15 +603,13 @@ pub fn run(f: *Fetch) RunError!void { | ... | @@ -574,15 +603,13 @@ pub fn run(f: *Fetch) RunError!void { |
| 574 | } | 603 | } |
| 575 | | 604 | |
| 576 | // Fetch and unpack the remote into a temporary directory. | 605 | // Fetch and unpack the remote into a temporary directory. |
| 577 | | | |
| 578 | const uri = std.Uri.parse(remote.url) catch |err| return f.fail( | 606 | const uri = std.Uri.parse(remote.url) catch |err| return f.fail( |
| 579 | f.location_tok, | 607 | f.location_tok, |
| 580 | try eb.printString("invalid URI: {t}", .{err}), | 608 | try eb.printString("invalid URI: {t}", .{err}), |
| 581 | ); | 609 | ); |
| 582 | var buffer: [init_resource_buffer_size]u8 = undefined; | | |
| 583 | var resource: Resource = undefined; | 610 | var resource: Resource = undefined; |
| 584 | try f.initResource(uri, &resource, &buffer); | 611 | try f.initResource(uri, &resource, &resource_buffer); |
| 585 | return f.runResource(try uri.path.toRawMaybeAlloc(arena), &resource, remote.hash); | 612 | return f.runResource(try uri.path.toRawMaybeAlloc(arena), &resource, remote.hash, false); |
| 586 | } | 613 | } |
| 587 | | 614 | |
| 588 | pub fn deinit(f: *Fetch) void { | 615 | pub fn deinit(f: *Fetch) void { |
| ... | @@ -596,6 +623,7 @@ fn runResource( | ... | @@ -596,6 +623,7 @@ fn runResource( |
| 596 | uri_path: []const u8, | 623 | uri_path: []const u8, |
| 597 | resource: *Resource, | 624 | resource: *Resource, |
| 598 | remote_hash: ?Package.Hash, | 625 | remote_hash: ?Package.Hash, |
| | 626 | disable_recompress: bool, |
| 599 | ) RunError!void { | 627 | ) RunError!void { |
| 600 | const job_queue = f.job_queue; | 628 | const job_queue = f.job_queue; |
| 601 | assert(!job_queue.read_only); | 629 | assert(!job_queue.read_only); |
| ... | @@ -681,15 +709,17 @@ fn runResource( | ... | @@ -681,15 +709,17 @@ fn runResource( |
| 681 | return error.FetchFailed; | 709 | return error.FetchFailed; |
| 682 | }; | 710 | }; |
| 683 | | 711 | |
| 684 | // Spin off a task to recompress the tarball, with filtered files deleted, into | 712 | if (!disable_recompress) { |
| 685 | // the global cache. | 713 | // Spin off a task to recompress the tarball, with filtered files deleted, into |
| 686 | job_queue.group.async(io, JobQueue.recompress, .{ job_queue, computed_package_hash }); | 714 | // the global cache. |
| | 715 | job_queue.group.async(io, JobQueue.recompress, .{ job_queue, computed_package_hash }); |
| | 716 | } |
| 687 | | 717 | |
| 688 | // Remove temporary directory root if not already renamed to global cache. | 718 | // Remove temporary directory root if not already renamed to global cache. |
| 689 | if (!package_sub_path.eql(tmp_directory_path)) { | 719 | if (!package_sub_path.eql(tmp_directory_path)) { |
| 690 | tmp_directory_path.root_dir.handle.deleteDir(io, tmp_directory_path.sub_path) catch |err| switch (err) { | 720 | tmp_directory_path.root_dir.handle.deleteDir(io, tmp_directory_path.sub_path) catch |err| switch (err) { |
| 691 | error.Canceled => |e| return e, | 721 | error.Canceled => |e| return e, |
| 692 | else => |e| std.log.warn("failed to delete temporary directory {f}: {t}", .{ tmp_directory_path, e }), | 722 | else => |e| log.warn("failed to delete temporary directory {f}: {t}", .{ tmp_directory_path, e }), |
| 693 | }; | 723 | }; |
| 694 | } | 724 | } |
| 695 | | 725 | |
| ... | @@ -1588,7 +1618,7 @@ pub fn renameTmpIntoCache(io: Io, tmp_path: Cache.Path, dest_path: Cache.Path) ! | ... | @@ -1588,7 +1618,7 @@ pub fn renameTmpIntoCache(io: Io, tmp_path: Cache.Path, dest_path: Cache.Path) ! |
| 1588 | error.Canceled => |e| return e, | 1618 | error.Canceled => |e| return e, |
| 1589 | // Garbage files leftover in zig-cache/tmp/ is, as they say | 1619 | // Garbage files leftover in zig-cache/tmp/ is, as they say |
| 1590 | // on Star Trek, "operating within normal parameters". | 1620 | // on Star Trek, "operating within normal parameters". |
| 1591 | else => |e| std.log.warn("failed to delete temporary directory {f}: {t}", .{ tmp_path, e }), | 1621 | else => |e| log.warn("failed to delete temporary directory {f}: {t}", .{ tmp_path, e }), |
| 1592 | }; | 1622 | }; |
| 1593 | }, | 1623 | }, |
| 1594 | else => |e| return e, | 1624 | else => |e| return e, |