Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add .no_unpack = PATH and --no-unpack to build.zig.zon and zig fetch #22042

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

marler8997
Copy link
Contributor

closes #17895

Enhances zig with the ability to fetch a dependency of any file type.

@marler8997 marler8997 force-pushed the noUnpack branch 3 times, most recently from e81c7c5 to 7c07035 Compare November 21, 2024 14:58
Comment on lines 921 to 924
const path_relative = std.mem.trimLeft(u8, path, "/");
return .{ .file = f.parent_package_root.openFile(path_relative, .{}) catch |err| {
return f.fail(f.location_tok, try eb.printString("unable to open '{}{s}': {s}", .{
f.parent_package_root, path, @errorName(err),
f.parent_package_root, path_relative, @errorName(err),
Copy link
Contributor

@castholm castholm Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect. A file URL like file:///foo represents the absolute path /foo. Relative paths can not be represented as file URLs (something like file:foo is not spec-compliant, there must always be a slash after the colon), see RFC 8089 and https://url.spec.whatwg.org/ for specifics.

I have an open PR #21931 which improves the validation and processing of file URLs but even if that PR were to be rejected, interpreting a path starting with a slash as relative is wrong and these changes should be reverted.

This also means that we can't use .url = "file://localhost/example_dep_file.txt" in test packages since absolute paths are not portable. For the tests to work, the dependency would need to be added as a regular HTTP URL and the tests themselves would need to start a web server that serves the file over HTTP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a new iteration that uses an absolute file path instead.

error.ParseFailure => continue,
else => |e| return e,
};
if (dep.unpack) return fail(p, main_tokens[field_init], "unpack cannot be set to true, omit it instead", .{});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.lazy = false is allowed despite it being the default, so it seems inconsistent that .unpack = true is an error. Either both should be forbidden or both should be allowed. I don't think there's any harm in allowing .unpack = true.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think anytime you can decrease the "surface area" of an interface it's a win, failing to do so does more harm than people realize.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @castholm. It should be able to be set to true.

pub fn build(b: *std.Build) void {
const dep = b.dependency("somedependency", .{});
b.getInstallStep().dependOn(&b.addInstallFile(
dep.path("example_dep_file.txt"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if one is necessarily better than the other, but personally, if I have a dependency like .url = "https://example.com/foo/bar/file.txt", my natural assumption would be that I use dep.path("") to obtain a path to the file, not dep.path("file.txt").

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with the solution that I didn't have to add any code for as the existing code paths already supported dep.path("file.txt"), willing to add extra code to support a special mapping if we feel it's advantageous.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is a good goal of having unpack=false use case be able to have a matching hash with unpack=true use case where the file is for example in a .tar.gz.

In order for this to work, however, we need to also support mirrors and the concept of URL being independent from hash. In the unpack use case, the file names are determined in-bound, not by the URL.

With no unpack, the file name still needs to be independent from the URL. So, I think the bool unpack should be changed to optional string, which specifies the sub-path, which may include path components. This is the string one passes to dep.path to access the file.

This makes it possible to have a unpacked single file have the same hash, and build.zig logic, as a pack that contains the same file, as long as the provided sub-path components match.

zig fetch however can keep the --no-unpack flag and default-populate the string filename based on the URL or the HTTP file name header.

@alexrp alexrp added this to the 0.14.0 milestone Feb 18, 2025
Copy link
Member

@andrewrk andrewrk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. It looks nearly ready to land, however, I have identified an API issue that is worth addressing beforehand.

error.ParseFailure => continue,
else => |e| return e,
};
if (dep.unpack) return fail(p, main_tokens[field_init], "unpack cannot be set to true, omit it instead", .{});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @castholm. It should be able to be set to true.

pub fn build(b: *std.Build) void {
const dep = b.dependency("somedependency", .{});
b.getInstallStep().dependOn(&b.addInstallFile(
dep.path("example_dep_file.txt"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is a good goal of having unpack=false use case be able to have a matching hash with unpack=true use case where the file is for example in a .tar.gz.

In order for this to work, however, we need to also support mirrors and the concept of URL being independent from hash. In the unpack use case, the file names are determined in-bound, not by the URL.

With no unpack, the file name still needs to be independent from the URL. So, I think the bool unpack should be changed to optional string, which specifies the sub-path, which may include path components. This is the string one passes to dep.path to access the file.

This makes it possible to have a unpacked single file have the same hash, and build.zig logic, as a pack that contains the same file, as long as the provided sub-path components match.

zig fetch however can keep the --no-unpack flag and default-populate the string filename based on the URL or the HTTP file name header.

@marler8997 marler8997 force-pushed the noUnpack branch 2 times, most recently from c7816a9 to 8ee494f Compare February 28, 2025 15:33
@marler8997 marler8997 changed the title Add .unpack = false and --no-unpack to build.zig.zon and zig fetch Add .no_unpack = PATH and --no-unpack to build.zig.zon and zig fetch Feb 28, 2025
@marler8997
Copy link
Contributor Author

marler8997 commented Feb 28, 2025

I've updated the API according to the suggestions. Since we've moved from .unpack = false to an optional path, I also renamed the field to no_unpack so now we have:

.no_unpack = "foo/bar.zip",

This makes it consistent with the --no-unpack command-line option to zig fetch. I also implemented an optional path on the command-line via --no-unpack=foo/bar.zip but also allow --no-unpack with no path to default to using the URL basename.

closes ziglang#17895

Enhances zig with the ability to fetch a dependency of any file type.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

use case: ability to declare dependency on single file
4 participants