1use 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#[derive(Parser, Debug)]
17#[clap(about = "Command line options for the `query` subcommand", version)]
18pub struct QueryOptions {
19 #[clap(long)]
21 pub lockfile: PathBuf,
22
23 #[clap(long)]
25 pub config: PathBuf,
26
27 #[clap(long)]
29 pub splicing_manifest: PathBuf,
30
31 #[clap(long, env = "CARGO")]
33 pub cargo: PathBuf,
34
35 #[clap(long, env = "RUSTC")]
37 pub rustc: PathBuf,
38}
39
40pub fn query(opt: QueryOptions) -> Result<()> {
42 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 let lockfile: Context = match serde_json::from_str(&content) {
54 Ok(ctx) => ctx,
55 Err(_) => bail!("Could not load lockfile"),
56 };
57
58 let digest = match &lockfile.checksum {
60 Some(d) => d.clone(),
61 None => bail!("No digest provided in lockfile"),
62 };
63
64 let config = Config::try_from_path(&opt.config)?;
66
67 let splicing_manifest = SplicingManifest::try_from_path(&opt.splicing_manifest)?;
68
69 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 Ok(())
84}