Skip to main content

packc/cli/
inspect_lock.rs

1#![forbid(unsafe_code)]
2
3use std::path::{Path, PathBuf};
4
5use anyhow::{Context, Result};
6use clap::Args;
7use greentic_pack::pack_lock::read_pack_lock;
8use serde::Serialize;
9use serde_json::Value;
10
11#[derive(Debug, Args)]
12pub struct InspectLockArgs {
13    /// Pack root directory containing pack.yaml.
14    #[arg(long = "in", value_name = "DIR", default_value = ".")]
15    pub input: PathBuf,
16
17    /// Path to pack.lock.cbor (default: pack.lock.cbor under pack root).
18    #[arg(long = "lock", value_name = "FILE")]
19    pub lock: Option<PathBuf>,
20}
21
22pub fn handle(args: InspectLockArgs) -> Result<()> {
23    let pack_dir = args
24        .input
25        .canonicalize()
26        .with_context(|| format!("failed to resolve pack dir {}", args.input.display()))?;
27    let lock_path = resolve_lock_path(&pack_dir, args.lock.as_deref());
28    let lock = read_pack_lock(&lock_path)
29        .with_context(|| format!("failed to read {}", lock_path.display()))?;
30
31    let json = to_sorted_json(&lock)?;
32    println!("{json}");
33    Ok(())
34}
35
36fn resolve_lock_path(pack_dir: &Path, override_path: Option<&Path>) -> PathBuf {
37    match override_path {
38        Some(path) if path.is_absolute() => path.to_path_buf(),
39        Some(path) => pack_dir.join(path),
40        None => pack_dir.join("pack.lock.cbor"),
41    }
42}
43
44fn to_sorted_json<T: Serialize>(value: &T) -> Result<String> {
45    let value = serde_json::to_value(value).context("encode lock to json")?;
46    let sorted = sort_json(value);
47    serde_json::to_string_pretty(&sorted).context("serialize json")
48}
49
50fn sort_json(value: Value) -> Value {
51    match value {
52        Value::Object(map) => {
53            let mut entries: Vec<(String, Value)> = map.into_iter().collect();
54            entries.sort_by(|a, b| a.0.cmp(&b.0));
55            let mut sorted = serde_json::Map::new();
56            for (key, value) in entries {
57                sorted.insert(key, sort_json(value));
58            }
59            Value::Object(sorted)
60        }
61        Value::Array(values) => Value::Array(values.into_iter().map(sort_json).collect()),
62        other => other,
63    }
64}