cargo_bazel/cli/
query.rs

1//! The cli entrypoint for the `query` subcommand
2
3use std::fs;
4use std::path::PathBuf;
5
6use anyhow::{bail, Result};
7use clap::Parser;
8
9use crate::config::Config;
10use crate::context::Context;
11use crate::lockfile::Digest;
12use crate::metadata::Cargo;
13use crate::splicing::SplicingManifest;
14
15/// Command line options for the `query` subcommand
16#[derive(Parser, Debug)]
17#[clap(about = "Command line options for the `query` subcommand", version)]
18pub struct QueryOptions {
19    /// The lockfile path for reproducible Cargo->Bazel renderings
20    #[clap(long)]
21    pub lockfile: PathBuf,
22
23    /// The config file with information about the Bazel and Cargo workspace
24    #[clap(long)]
25    pub config: PathBuf,
26
27    /// A generated manifest of splicing inputs
28    #[clap(long)]
29    pub splicing_manifest: PathBuf,
30
31    /// The path to a Cargo binary to use for gathering metadata
32    #[clap(long, env = "CARGO")]
33    pub cargo: PathBuf,
34
35    /// The path to a rustc binary for use with Cargo
36    #[clap(long, env = "RUSTC")]
37    pub rustc: PathBuf,
38}
39
40/// Determine if the current lockfile needs to be re-pinned
41pub fn query(opt: QueryOptions) -> Result<()> {
42    // Read the lockfile
43    let content = match fs::read_to_string(&opt.lockfile) {
44        Ok(c) => c,
45        Err(e) => bail!(
46            "Unable to read lockfile `{}`\n{:?}",
47            opt.lockfile.display(),
48            e
49        ),
50    };
51
52    // Deserialize it so we can easily compare it with
53    let lockfile: Context = match serde_json::from_str(&content) {
54        Ok(ctx) => ctx,
55        Err(_) => bail!("Could not load lockfile"),
56    };
57
58    // Check to see if a digest has been set
59    let digest = match &lockfile.checksum {
60        Some(d) => d.clone(),
61        None => bail!("No digest provided in lockfile"),
62    };
63
64    // Load the config file
65    let config = Config::try_from_path(&opt.config)?;
66
67    let splicing_manifest = SplicingManifest::try_from_path(&opt.splicing_manifest)?;
68
69    // Generate a new digest so we can compare it with the one in the lockfile
70    let expected = Digest::new(
71        &lockfile,
72        &config,
73        &splicing_manifest,
74        &Cargo::new(opt.cargo, opt.rustc.clone()),
75        &opt.rustc,
76    )?;
77
78    if digest != expected {
79        bail!("Digests do not match: Current {digest:?} != Expected {expected:?}");
80    }
81
82    // There is no need to repin
83    Ok(())
84}