uv/crates/uv-python/build.rs
Skyler Hawthorne 9214855109
fix compile error on missing uv-python metadata (#16154)
The `uv-python` crate reads the checked-in download metadata to write
out a minified version to be statically included into the binary.

Sometimes, the resulting `download-metadata-minified.json` can go
missing, such as when `uv` is installed via `cargo` as a git source, and
there is an update; `cargo` will do a hard reset on the git repo it
stores in the cache, causing it to be deleted. In these instances, the
`uv-python` crate does not currently re-run its build script, because as
it happens, there was no change to the `download-metadata.json` since it
was last compiled. This causes a build error like:

```
            Updating git repository `https://github.com/astral-sh/uv`
          Installing uv v0.8.24 (https://github.com/astral-sh/uv?tag=0.8.24#252f8873)
            Updating crates.io index
           Compiling uv-version v0.8.24 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-version)
           Compiling uv-git v0.0.1 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-git)
           Compiling uv-build-backend v0.1.0 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-build-backend)
           Compiling uv-configuration v0.0.1 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-configuration)
           Compiling uv-client v0.0.1 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-client)
           Compiling uv-extract v0.0.1 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-extract)
           Compiling uv-workspace v0.0.1 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-workspace)
           Compiling uv-python v0.0.1 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-python)
           Compiling uv-requirements-txt v0.0.1 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-requirements-txt)
           Compiling uv-bin-install v0.0.1 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-bin-install)
           Compiling uv-publish v0.1.0 (/home/skhawtho/.cargo/git/checkouts/uv-c9e40703e19509a8/252f887/crates/uv-publish)
        error: couldn't read `crates/uv-python/src/download-metadata-minified.json`: No such file or directory (os error 2)
           --> crates/uv-python/src/downloads.rs:795:45
            |
        795 | const BUILTIN_PYTHON_DOWNLOADS_JSON: &str = include_str!("download-metadata-minified.json");
            |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

        error: could not compile `uv-python` (lib) due to 1 previous error
        error: failed to compile `uv v0.8.24 (https://github.com/astral-sh/uv?tag=0.8.24#252f8873)`, intermediate artifacts can be found at `/home/skhawtho/.cache/cargo`.
        To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.
```

This fixes the issue by also adding a `rerun-if-changed` on the
resulting minified JSON file.

Separately, this revision also changes the output directory of the
minified file to the build script's output directory via the `OUT_DIR`
environment variable, so as not to pollute the source code.
2025-10-07 12:33:04 -05:00

51 lines
1.4 KiB
Rust

use std::path::PathBuf;
use std::{env, fs};
fn process_json(data: &serde_json::Value) -> serde_json::Value {
let mut out_data = serde_json::Map::new();
if let Some(obj) = data.as_object() {
for (key, value) in obj {
out_data.insert(key.clone(), value.clone());
}
}
serde_json::Value::Object(out_data)
}
fn main() {
let version_metadata = PathBuf::from_iter([
env::var("CARGO_MANIFEST_DIR").unwrap(),
"download-metadata.json".into(),
]);
let version_metadata_minified = PathBuf::from_iter([
env::var("OUT_DIR").unwrap(),
"download-metadata-minified.json".into(),
]);
println!(
"cargo::rerun-if-changed={}",
version_metadata.to_str().unwrap()
);
println!(
"cargo::rerun-if-changed={}",
version_metadata_minified.to_str().unwrap()
);
let json_data: serde_json::Value = serde_json::from_str(
#[allow(clippy::disallowed_methods)]
&fs::read_to_string(version_metadata).expect("Failed to read download-metadata.json"),
)
.expect("Failed to parse JSON");
let filtered_data = process_json(&json_data);
#[allow(clippy::disallowed_methods)]
fs::write(
version_metadata_minified,
serde_json::to_string(&filtered_data).expect("Failed to serialize JSON"),
)
.expect("Failed to write minified JSON");
}