|
1 | 1 | //! Represents one independent job whose responsibility is to:
|
2 | 2 | //!
|
3 |
| -//! 1. Check the global zig package cache to see if the hash already exists. |
4 |
| -//! If so, load, parse, and validate the build.zig.zon file therein, and |
5 |
| -//! goto step 8. Likewise if the location is a relative path, treat this |
6 |
| -//! the same as a cache hit. Otherwise, proceed. |
| 3 | +//! 1. if local zig packages is enabled: |
| 4 | +//! a. Check the local zig package directory to see if the hash already exists. |
| 5 | +//! If so, load, parse, and validate the build.zig.zon file therein, and |
| 6 | +//! goto step 8. Likewise if the location is a relative path, treat this |
| 7 | +//! the same as a cache hit. Otherwise, proceed. |
| 8 | +//! b. Check the global zig package cache to see if the hash already exists. |
| 9 | +//! If so, load, parse, and validate the build.zig.zon file therein, copy |
| 10 | +//! it to the local zig package directory and goto step 8. Otherwise, proceed. |
| 11 | +//! if local zig packages is disabled: |
| 12 | +//! Check the global zig package cache to see if the hash already exists. |
| 13 | +//! If so, load, parse, and validate the build.zig.zon file therein, and |
| 14 | +//! goto step 8. Likewise if the location is a relative path, treat this |
| 15 | +//! the same as a cache hit. Otherwise, proceed. |
7 | 16 | //! 2. Fetch and unpack a URL into a temporary directory.
|
8 | 17 | //! 3. Load, parse, and validate the build.zig.zon file therein. It is allowed
|
9 | 18 | //! for the file to be missing, in which case this fetched package is considered
|
|
18 | 27 | //! directory. If the hash already exists, delete the temporary directory and
|
19 | 28 | //! leave the zig package cache directory untouched as it may be in use by the
|
20 | 29 | //! system. This is done even if the hash is invalid, in case the package with
|
21 |
| -//! the different hash is used in the future. |
| 30 | +//! the different hash is used in the future. If local packages is enabled, copy |
| 31 | +//! the package locally. |
22 | 32 | //! 7. Validate the computed hash against the expected hash. If invalid,
|
23 | 33 | //! this job is done.
|
24 | 34 | //! 8. Spawn a new fetch job for each dependency in the manifest file. Use
|
@@ -97,6 +107,7 @@ pub const JobQueue = struct {
|
97 | 107 | thread_pool: *ThreadPool,
|
98 | 108 | wait_group: WaitGroup = .{},
|
99 | 109 | global_cache: Cache.Directory,
|
| 110 | + local_package_cache_root: ?Cache.Directory, |
100 | 111 | /// If true then, no fetching occurs, and:
|
101 | 112 | /// * The `global_cache` directory is assumed to be the direct parent
|
102 | 113 | /// directory of on-disk packages rather than having the "p/" directory
|
@@ -299,7 +310,7 @@ pub fn run(f: *Fetch) RunError!void {
|
299 | 310 | const arena = f.arena.allocator();
|
300 | 311 | const gpa = f.arena.child_allocator;
|
301 | 312 | const cache_root = f.job_queue.global_cache;
|
302 |
| - |
| 313 | + const local_package_cache = f.job_queue.local_package_cache_root; |
303 | 314 | try eb.init(gpa);
|
304 | 315 |
|
305 | 316 | // Check the global zig package cache to see if the hash already exists. If
|
@@ -372,41 +383,102 @@ pub fn run(f: *Fetch) RunError!void {
|
372 | 383 | const prefixed_pkg_sub_path = "p" ++ s ++ expected_hash;
|
373 | 384 | const prefix_len: usize = if (f.job_queue.read_only) "p/".len else 0;
|
374 | 385 | const pkg_sub_path = prefixed_pkg_sub_path[prefix_len..];
|
375 |
| - if (cache_root.handle.access(pkg_sub_path, .{})) |_| { |
376 |
| - assert(f.lazy_status != .unavailable); |
377 |
| - f.package_root = .{ |
378 |
| - .root_dir = cache_root, |
379 |
| - .sub_path = try arena.dupe(u8, pkg_sub_path), |
380 |
| - }; |
381 |
| - try loadManifest(f, f.package_root); |
382 |
| - try checkBuildFileExistence(f); |
383 |
| - if (!f.job_queue.recursive) return; |
384 |
| - return queueJobsForDeps(f); |
385 |
| - } else |err| switch (err) { |
386 |
| - error.FileNotFound => { |
387 |
| - switch (f.lazy_status) { |
388 |
| - .eager => {}, |
389 |
| - .available => if (!f.job_queue.unlazy_set.contains(expected_hash)) { |
390 |
| - f.lazy_status = .unavailable; |
391 |
| - return; |
392 |
| - }, |
393 |
| - .unavailable => unreachable, |
| 386 | + var check_cache_root = local_package_cache == null; |
| 387 | + if (local_package_cache) |lpc| { |
| 388 | + if (lpc.handle.access(&expected_hash, .{})) { |
| 389 | + f.package_root = .{ |
| 390 | + .root_dir = lpc, |
| 391 | + .sub_path = try arena.dupe(u8, &expected_hash), |
| 392 | + }; |
| 393 | + try loadManifest(f, f.package_root); |
| 394 | + try checkBuildFileExistence(f); |
| 395 | + if (!f.job_queue.recursive) return; |
| 396 | + return queueJobsForDeps(f); |
| 397 | + } else |err| switch (err) { |
| 398 | + error.FileNotFound => { |
| 399 | + check_cache_root = true; |
| 400 | + }, |
| 401 | + else => |e| { |
| 402 | + try eb.addRootErrorMessage(.{ |
| 403 | + .msg = try eb.printString("unable to open local package cache directory '{}{s}': {s}", .{ |
| 404 | + lpc, &expected_hash, @errorName(e), |
| 405 | + }), |
| 406 | + }); |
| 407 | + return error.FetchFailed; |
| 408 | + }, |
| 409 | + } |
| 410 | + } |
| 411 | + if (check_cache_root) { |
| 412 | + if (cache_root.handle.access(pkg_sub_path, .{})) |_| { |
| 413 | + assert(f.lazy_status != .unavailable); |
| 414 | + if (local_package_cache) |lpc| { |
| 415 | + var dst_handle = lpc.handle.makeOpenPath(&expected_hash, .{}) catch |err| { |
| 416 | + try eb.addRootErrorMessage(.{ |
| 417 | + .msg = try eb.printString("unable to open local package cache directory '{}{s}': {s}", .{ |
| 418 | + lpc, &expected_hash, @errorName(err), |
| 419 | + }), |
| 420 | + }); |
| 421 | + return error.FetchFailed; |
| 422 | + }; |
| 423 | + defer dst_handle.close(); |
| 424 | + var src_handle = cache_root.handle.openDir(pkg_sub_path, .{}) catch |err| { |
| 425 | + try eb.addRootErrorMessage(.{ |
| 426 | + .msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{ |
| 427 | + cache_root, pkg_sub_path, @errorName(err), |
| 428 | + }), |
| 429 | + }); |
| 430 | + return error.FetchFailed; |
| 431 | + }; |
| 432 | + defer src_handle.close(); |
| 433 | + f.recursiveDirectoryCopy(src_handle, dst_handle) catch |err| { |
| 434 | + const src = try cache_root.join(arena, &.{pkg_sub_path}); |
| 435 | + const dest = try lpc.join(arena, &.{&expected_hash}); |
| 436 | + try eb.addRootErrorMessage(.{ .msg = try eb.printString( |
| 437 | + "sunable to copy into local package directory '{s}' from package cache directory '{s}': {s}", |
| 438 | + .{ dest, src, @errorName(err) }, |
| 439 | + ) }); |
| 440 | + return error.FetchFailed; |
| 441 | + }; |
| 442 | + f.package_root = .{ |
| 443 | + .root_dir = lpc, |
| 444 | + .sub_path = try arena.dupe(u8, &expected_hash), |
| 445 | + }; |
| 446 | + } else { |
| 447 | + f.package_root = .{ |
| 448 | + .root_dir = cache_root, |
| 449 | + .sub_path = try arena.dupe(u8, pkg_sub_path), |
| 450 | + }; |
394 | 451 | }
|
395 |
| - if (f.job_queue.read_only) return f.fail( |
396 |
| - f.name_tok, |
397 |
| - try eb.printString("package not found at '{}{s}'", .{ |
398 |
| - cache_root, pkg_sub_path, |
399 |
| - }), |
400 |
| - ); |
401 |
| - }, |
402 |
| - else => |e| { |
403 |
| - try eb.addRootErrorMessage(.{ |
404 |
| - .msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{ |
405 |
| - cache_root, pkg_sub_path, @errorName(e), |
406 |
| - }), |
407 |
| - }); |
408 |
| - return error.FetchFailed; |
409 |
| - }, |
| 452 | + try loadManifest(f, f.package_root); |
| 453 | + try checkBuildFileExistence(f); |
| 454 | + if (!f.job_queue.recursive) return; |
| 455 | + return queueJobsForDeps(f); |
| 456 | + } else |err| switch (err) { |
| 457 | + error.FileNotFound => { |
| 458 | + switch (f.lazy_status) { |
| 459 | + .eager => {}, |
| 460 | + .available => if (!f.job_queue.unlazy_set.contains(expected_hash)) { |
| 461 | + f.lazy_status = .unavailable; |
| 462 | + return; |
| 463 | + }, |
| 464 | + .unavailable => unreachable, |
| 465 | + } |
| 466 | + if (f.job_queue.read_only) return f.fail( |
| 467 | + f.name_tok, |
| 468 | + try eb.printString("package not found at '{}{s}'", .{ |
| 469 | + cache_root, pkg_sub_path, |
| 470 | + }), |
| 471 | + ); |
| 472 | + }, |
| 473 | + else => |e| { |
| 474 | + try eb.addRootErrorMessage(.{ |
| 475 | + .msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{ |
| 476 | + cache_root, pkg_sub_path, @errorName(e), |
| 477 | + }), |
| 478 | + }); |
| 479 | + return error.FetchFailed; |
| 480 | + }, |
| 481 | + } |
410 | 482 | }
|
411 | 483 | } else if (f.job_queue.read_only) {
|
412 | 484 | try eb.addRootErrorMessage(.{
|
@@ -444,6 +516,7 @@ fn runResource(
|
444 | 516 | const eb = &f.error_bundle;
|
445 | 517 | const s = fs.path.sep_str;
|
446 | 518 | const cache_root = f.job_queue.global_cache;
|
| 519 | + const local_package_cache = f.job_queue.local_package_cache_root; |
447 | 520 | const rand_int = std.crypto.random.int(u64);
|
448 | 521 | const tmp_dir_sub_path = "tmp" ++ s ++ Manifest.hex64(rand_int);
|
449 | 522 |
|
@@ -526,6 +599,36 @@ fn runResource(
|
526 | 599 | ) });
|
527 | 600 | return error.FetchFailed;
|
528 | 601 | };
|
| 602 | + if (local_package_cache) |lpc| { |
| 603 | + var dst_handle = lpc.handle.makeOpenPath(&Manifest.hexDigest(f.actual_hash), .{}) catch |err| { |
| 604 | + try eb.addRootErrorMessage(.{ |
| 605 | + .msg = try eb.printString("unable to open local package cache directory '{}{s}': {s}", .{ |
| 606 | + lpc, &Manifest.hexDigest(f.actual_hash), @errorName(err), |
| 607 | + }), |
| 608 | + }); |
| 609 | + return error.FetchFailed; |
| 610 | + }; |
| 611 | + defer dst_handle.close(); |
| 612 | + var src_handle = cache_root.handle.openDir(f.package_root.sub_path, .{}) catch |err| { |
| 613 | + try eb.addRootErrorMessage(.{ |
| 614 | + .msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{ |
| 615 | + cache_root, f.package_root.sub_path, @errorName(err), |
| 616 | + }), |
| 617 | + }); |
| 618 | + return error.FetchFailed; |
| 619 | + }; |
| 620 | + defer src_handle.close(); |
| 621 | + f.recursiveDirectoryCopy(src_handle, dst_handle) catch |err| { |
| 622 | + const src = try cache_root.join(arena, &.{f.package_root.sub_path}); |
| 623 | + const dest = try lpc.join(arena, &.{&Manifest.hexDigest(f.actual_hash)}); |
| 624 | + try eb.addRootErrorMessage(.{ .msg = try eb.printString( |
| 625 | + "unable to copy into local package directory '{s}' from package cache directory '{s}': {s}", |
| 626 | + .{ dest, src, @errorName(err) }, |
| 627 | + ) }); |
| 628 | + return error.FetchFailed; |
| 629 | + }; |
| 630 | + } |
| 631 | + |
529 | 632 | // Remove temporary directory root if not already renamed to global cache.
|
530 | 633 | if (!std.mem.eql(u8, package_sub_path, tmp_dir_sub_path)) {
|
531 | 634 | cache_root.handle.deleteDir(tmp_dir_sub_path) catch {};
|
|
0 commit comments