Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

runResource

Consumes resource, even if an error is returned.

Fetch.runResource
fn runResource(
    f: *Fetch,
    uri_path: []const u8,
    resource: *Resource,
    remote_hash: ?Package.Hash,
    disable_recompress: bool,
) RunError!void

File

lib/compiler/Maker/Fetch.zig:695

Code

fn runResource(
    f: *Fetch,
    uri_path: []const u8,
    resource: *Resource,
    remote_hash: ?Package.Hash,
    disable_recompress: bool,
) RunError!void {
    const job_queue = f.job_queue;
    assert(!job_queue.read_only);

    const io = job_queue.io;
    defer resource.deinit(io);

    const arena = f.arena.allocator();
    const eb = &f.error_bundle;
    const rand_int = r: {
        var x: u64 = undefined;
        io.random(@ptrCast(&x));
        break :r x;
    };
    const tmp_dir_sub_path = ".tmp-" ++ std.fmt.hex(rand_int);
    const tmp_tmp_dir_sub_path = "tmp/" ++ tmp_dir_sub_path;
    const tmp_directory_path: Path = if (job_queue.local_storage) |ls|
        try ls.pkg_root.join(arena, tmp_dir_sub_path)
    else
        .{
            .root_dir = job_queue.global_cache,
            .sub_path = tmp_tmp_dir_sub_path,
        };

    const package_sub_path = blk: {
        var tmp_directory: Directory = .{
            .path = tmp_directory_path.sub_path,
            .handle = handle: {
                const dir = tmp_directory_path.root_dir.handle.createDirPathOpen(io, tmp_directory_path.sub_path, .{
                    .open_options = .{ .iterate = true },
                }) catch |err| {
                    try eb.addRootErrorMessage(.{
                        .msg = try eb.printString("unable to create temporary directory '{f}': {t}", .{
                            tmp_directory_path, err,
                        }),
                    });
                    return error.FetchFailed;
                };
                break :handle dir;
            },
        };
        defer tmp_directory.handle.close(io);

        // Fetch and unpack a resource into a temporary directory.
        var unpack_result = try unpackResource(f, resource, uri_path, tmp_directory);

        const pkg_path: Path = .{ .root_dir = tmp_directory, .sub_path = unpack_result.root_dir };

        // Load, parse, and validate the unpacked build.zig.zon file. It is allowed
        // for the file to be missing, in which case this fetched package is
        // considered to be a "naked" package.
        try loadManifest(f, pkg_path);

        const filter: Filter = .{
            .include_paths = if (f.have_manifest) f.manifest.paths else .{},
        };

        // Ignore errors that were excluded by manifest, such as failure to
        // create symlinks that weren't supposed to be included anyway.
        try unpack_result.validate(f, filter);

        // Apply the manifest's inclusion rules to the temporary directory by
        // deleting excluded files.
        // Empty directories have already been omitted by `unpackResource`.
        // Compute the package hash based on the remaining files in the temporary
        // directory.
        f.computed_hash = try computeHash(f, pkg_path, filter);

        if (unpack_result.root_dir.len > 0)
            break :blk try tmp_directory_path.join(arena, unpack_result.root_dir);

        break :blk tmp_directory_path;
    };

    const computed_package_hash = computedPackageHash(f);

    // Rename the temporary directory into the local zig package directory. If
    // the hash already exists, delete the temporary directory and leave the
    // zig package directory untouched as it may be in use. This is done even
    // if the hash is invalid, in case the package with the different hash is
    // used in the future.
    if (job_queue.local_storage) |ls| {
        f.package_root = try ls.pkg_root.join(arena, computed_package_hash.toSlice());
        renameTmpIntoCache(io, package_sub_path, f.package_root) catch |err| {
            try eb.addRootErrorMessage(.{ .msg = try eb.printString(
                "failed to rename temporary directory {f} into package cache directory {f}: {t}",
                .{ package_sub_path, f.package_root, err },
            ) });
            return error.FetchFailed;
        };
    } else {
        f.package_root = tmp_directory_path;
    }
    f.remote_package_root = f.package_root;

    if (!disable_recompress) {
        // Spin off a task to recompress the tarball, with filtered files deleted, into
        // the global cache.
        job_queue.group.async(io, JobQueue.recompress, .{ job_queue, computed_package_hash, f.package_root });
    }

    // Remove temporary directory root if not already renamed to global cache.
    if (!package_sub_path.eql(tmp_directory_path)) {
        tmp_directory_path.root_dir.handle.deleteDir(io, tmp_directory_path.sub_path) catch |err| switch (err) {
            error.Canceled => |e| return e,
            else => |e| log.warn("failed to delete temporary directory {f}: {t}", .{ tmp_directory_path, e }),
        };
    }

    // Validate the computed hash against the expected hash. If invalid, this
    // job is done.

    if (remote_hash) |declared_hash| {
        const hash_tok = f.hash_tok.unwrap().?;
        if (!computed_package_hash.eql(&declared_hash)) {
            return f.fail(hash_tok, try eb.printString(
                "hash mismatch: manifest declares {s} but the fetched package has {s}",
                .{ declared_hash.toSlice(), computed_package_hash.toSlice() },
            ));
        }
    } else if (!f.omit_missing_hash_error) {
        const notes_len = 1;
        try eb.addRootErrorMessage(.{
            .msg = try eb.addString("dependency is missing hash field"),
            .src_loc = try f.srcLoc(f.location_tok),
            .notes_len = notes_len,
        });
        const notes_start = try eb.reserveNotes(notes_len);
        eb.extra.items[notes_start] = @backingInt(try eb.addErrorMessage(.{
            .msg = try eb.printString("expected .hash = {q},", .{computed_package_hash.toSlice()}),
        }));
        return error.FetchFailed;
    }

    // Spawn a new fetch job for each dependency in the manifest file. Use
    // a mutex and a hash map so that redundant jobs do not get queued up.
    if (!job_queue.recursive) return;
    return queueJobsForDeps(f);
}