use std::path::{Path, PathBuf};
use anyhow::bail;
use cargo::core::Workspace;
use cargo::ops::{self, UpdateOptions};
use cargo::util::context::GlobalContext;
use path_absolutize::*;
pub struct Cargo {
path: PathBuf,
cfg: Option<GlobalContext>,
}
impl Cargo {
pub fn new(path: &Path) -> Self {
Self {
path: path.to_owned(),
cfg: None,
}
}
pub fn open(&mut self) -> anyhow::Result<()> {
let cfg = GlobalContext::default()?;
self.cfg = Some(cfg);
if let Some(cfg) = &self.cfg {
let manifest_path = std::path::Path::new(&self.path).join("Cargo.toml");
let p = manifest_path.absolutize()?;
if !manifest_path.exists() {
bail!("Cargo.toml not found at: {}", manifest_path.display());
}
let lock_path = std::path::Path::new(&self.path).join("Cargo.lock");
if !lock_path.exists() {
bail!("Cargo.lock not found at: {}. Run 'cargo build' in the repository to generate it.", lock_path.display());
}
match std::fs::read_to_string(&lock_path) {
Ok(contents) => {
if !contents.contains("[package]")
&& !contents.contains("version =")
&& !contents.trim().is_empty()
{
bail!("Cargo.lock at {} appears to be malformed. Run 'cargo build' to regenerate it.", lock_path.display());
}
},
Err(e) => {
bail!(
"Failed to read Cargo.lock at {}: {}",
lock_path.display(),
e
);
},
}
match Workspace::new(&p, cfg) {
Ok(_ws) => {
Ok(())
},
Err(e) => {
bail!("Failed to create Cargo workspace: {}. Make sure both Cargo.toml and Cargo.lock are valid.", e);
},
}
} else {
bail!("No Config");
}
}
pub fn update_workspace(&mut self) -> anyhow::Result<()> {
if let Some(cfg) = &self.cfg {
let manifest_path = std::path::Path::new(&self.path).join("Cargo.toml");
let p = manifest_path.absolutize()?;
if !manifest_path.exists() {
bail!("Cargo.toml not found at: {}", manifest_path.display());
}
let lock_path = std::path::Path::new(&self.path).join("Cargo.lock");
if !lock_path.exists() {
bail!("Cargo.lock not found at: {}. Run 'cargo build' in the repository to generate it.", lock_path.display());
}
let ws = match Workspace::new(&p, cfg) {
Ok(ws) => ws,
Err(e) => bail!("Failed to create Cargo workspace: {}. Make sure both Cargo.toml and Cargo.lock are valid.", e)
};
let update_opts = UpdateOptions {
precise: None,
recursive: true,
to_update: Vec::new(),
dry_run: false,
workspace: true,
gctx: cfg,
};
match ops::update_lockfile(&ws, &update_opts) {
Ok(_) => {
println!("Updated Cargo.lock for {}", &p.display());
Ok(())
},
Err(e) => bail!("Failed to update Cargo.lock: {}", e),
}
} else {
bail!("No Config");
}
}
}