zig
zig copied to clipboard
`zig fetch`: resolve branch/tag names to commit SHA
When adding a dependency using zig fetch --save I usually just want the latest thing on the master/main branch. However, when running zig fetch --save git+https://github/abc/def#master this gets saved verbatim in build.zig.zon:
.@"def" = .{
.url = "git+https://github.com/abc/def#master",
.hash = "...",
},
Now, when compiling this in the future, the branch may point to another commit, leading to a hash-mismatch.
Old Proposal
Context for the discussion below
Old Proposal
This PR adds the new flag --resolve-commit to zig fetch which instead saves whatever commit the refspec points at instead:
.@"def" = .{
.url = "git+https://github.com/abc/def#123403399058fd83f7fbb597f3f8304007ff6a3c",
.hash = "...",
},
Naming
I'm open to other names for this flag. Some alternatives I've come up with:
--save-commit--latest
Open Questions
Are there any drawbacks to making this the default behavior and instead add a flag to restore the old behaviour?
New Proposal
This PR makes it so that zig fetch --save <URI>#<ref> now replaces the <ref> with the commit SHA in build.zig.zon. The old <ref> is moved to a query parameter ?ref=<ref> so that automated tooling still can check for changes upstream. See the discussion below for the rationale behind this decision. The example above would now become:
.@"def" = .{
.url = "git+https://github.com/abc/def?ref=master#123403399058fd83f7fbb597f3f8304007ff6a3c",
.hash = "...",
},
It is possible to restore the old behavior by adding the --preserve-url flag to the zig fetch invocation. This saves the URL verbatim to build.zig.zon.
I'm not too familiar with zig fetch, so I can't speak for the intended design, but here's my 2c idea/take:
Are there any drawbacks to making this the default behavior and instead add a flag to restore the old behaviour?
The current behavior informs the user when the remote was modified, which I think would be valid for use cases always wanting the newest commit (f.e. to be informed of bugfixes and safety/security patches upstream).
The naming --latest would sound ambiguous to me: --current-latest-commit fits the new behavior while --always-fetch-latest describes the old one.
Actually, I would propose the following idea as a most explicit interface:
- Have flags for both behaviors,
- Either named by user impact, i.e.
--always-fetch-latestand--current-latest - or by technical background,
--keep-refspecand--resolve-refspec(oid, refspec, commit id - not sure which naming is the most correct and understandable)
- Either named by user impact, i.e.
- Always check whether the given URL explicitly refers to a fixed commit id (I assume we can do this in a standardized manner?)
- If it doesn't (the commit referred to by this URL could change in the future), require the user to specify one of the flags to choose the behavior they want.
Considering how zig package manager works, I think this behavior should be the default. Update checking / security vuln checking should be a separate tool or pass imo.
@Cloudef Considering how zig package manager works, I think this behavior should be the default.
I'm inclined to agree. The package manager expects that the contend pointed to by the url field matches the hash, and with a branch that is not necessarily the case as the commit a branch references could change. I'd expect most people don't want their builds to randomly break when upstream suddenly push a new commit.
@rohlem The current behavior informs the user when the remote was modified, which I think would be valid for use cases always wanting the newest commit (f.e. to be informed of bugfixes and safety/security patches upstream).
This may work fine in a top-level application, but what happens if this is in a library with transitive dependencies? Consider three projects A -> B -> C, where A depends on a fixed commit in B and B depends on a branch in C. In the case where C pushes an update to its branch, this would suddenly cause the build in A to break as it inherits B's dependencies, even though A used a fixed commit. To fix, this would require a patch to B, which either requires forking the project or waiting for an upstream patch to be accepted. Neither case is great.
@Cloudef Update checking / security vuln checking should be a separate tool or pass imo.
In order to support updating/scanning we would have to preserve the original name of the branch/tag in addition to the latest commit. For example, running the command zig fetch --save git+https://github/abc/def#master we would add the following to build.zig.zon:
.@"def" = .{
.url = "git+https://github.com/abc/def#123403399058fd83f7fbb597f3f8304007ff6a3c",
.refspec = "master",
.hash = "...",
},
Where refspec (naming TDB) is the branch/tag all updates should be done against. One can then envision a command such as zig fetch --update def which updates the def to the latest commit pointed to by the master branch on the remote.
Since the git url already has special syntax, another option would be to use query parameters to encode more information for example.
Since the git url already has special syntax, another option would be to use query parameters to encode more information for example.
That's a nice solution! I updated the PR:
- Commits are now resolved by default.
- The original ref is stored as a query parameter
?ref=... - There's a new flag
--preserve-urlwhich keeps the original URL, restoring the old behavior.