I'm including build metadata in my binaries --version output to help with debugging. The vergen crate(s) have been very helpful with this.
What I haven't figured out is how to know whether the binary was built with or without --locked. Is there some env variable that rustc/cargo sets? I have tried searching but clearly I don't know the correct words to use to find what I need.
The closest approximation I have so far is using the git dirty status as a proxy, under the assumption that the lockfile gets updated if run without --locked.
By the time the build is running, the resulting .lock file must, by definition, be a working one, which you can and probably should encode in this metadata.
The only other usage I can see would be to perform the "compression" of just storing a commit revision, and hoping the .lock file at that revision is indeed the one you are using. In which case, your "closest approximation" of looking for a clean git status is rather exactly what you need to do.
I think it would be useful to know when evaluating a bug report. Ideally I want the users to run with --locked but it would be nice to know for sure they have or haven't. One could even go a step further and abort compilation without it set, or warn loudly on startup.
With the git status I'm also unsure of the order of operations - will that diff be available by the time my build script runs? Probably; but it seems rather hacky. It also doesn't test for the absence/presence of --locked, only the potential side-effect of leaving it out.
I'm mostly just surprised this isn't exposed at all.
If someone runs without --locked and then after the error runs again with --locked, the lockfile would still have been updated if it was outdated and thus the second build would succeed even if the lockfile was originally outdated, which would have the same result as the initial build not erroring out when --locked misses.
cargo update -w after having updated their .toml constraints;
or even just cargo update directly to bump the .lock file versions as high as possible.
and only then run the cargo check/build --locked command, which is the (only) context that your build.rs gets to see.
As shown in the diagram, this means that your build.rs would witness a --locked invocation, but without this guaranteeing that the .lock file state matches the expected one / that of the reference point.
Hence the question about said "reference point": what is it in your case? You mention checking for git status, so I am tempted to think it's indeed a specific git revision, rather than just a specific file value, checksum or whatnot.
Be it as it may, the only way to ensure the .lock file hasn't been mutated since is then, well, by checking that directly; do not try to rely on --locked. So if it was a given file value, checksum, or whatnot, check that the new checksum matches the expected one, for instance, and if it is a specific git revision, checking for git status —if the build environment is that of said git repository!— is then indeed the right thing to do
Thanks I understand its pretty much impossible to guarantee anything here. However I am surprised that its this cumbersome to get at least some information out in a uniform manner.
Local builds one can handle using some variation of git describe --tags --dirty. This however falls apart for cargo install where all you can access is the SHA from the vcs json file. In particular --locked would be helpful here.
I know fully reproducible builds aren't really there yet for rust, but I was hoping one could at least confirm source and dependency versions.
Ah, that was my missing context! Yeah, for cargo install it is sensible to want to know whether the install was done with --locked or not. You could try running cargo metadata, but I don't know what its behavior is when used from the build.rs of a cargo installed package
cargo metadata requires --locked to be passed in so its essentially going to re-evaluate the dependency graph independently from the build process if I were to guess.
Could be useful to extract the dep graph but that would require somehow passing in the exact same configuration as the build received.
One way to detect the locked, or more generally lock file, status of a project would be to publish a library which exports a constant that varies with version:
1.0.0: pub const LOCKED: bool = false;
1.0.10: pub const LOCKED: bool = true;
1.0.20: pub const LOCKED: bool = false;
Then publish your binary package with a lockfile pointing to version "1.0.10" of this, and if it sees anything else, it knows it wasn't built with an unaltered lock file.
The disadvantage of this strategy is that you have to revert the dependency in your own project after every cargo update.