mod config;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command as OsCommand;
use clap::Parser;
use config::{Cargo, CargoCfg, CargoLock, Workspace};
#[derive(Parser)]
#[clap(name = "cargo", bin_name = "cargo")]
enum App {
Ws(Ws),
}
#[derive(clap::Args, Debug)]
#[clap(
author,
version,
override_usage = "cargo ws [options]",
about = "generate vscode workspace file"
)]
struct Ws {
#[clap(short, long, value_parser, default_value = ".")]
root: String,
}
fn generate(args: &Ws) {
let cargo_path = Path::new(&args.root).join("Cargo.toml");
let cargo_lock_path = Path::new(&args.root).join("Cargo.lock");
let cargo = Cargo::from_path(cargo_path).expect("Failed to parse Cargo.toml");
let cargo_lock = CargoLock::from_path(cargo_lock_path).expect("Failed to parse Cargo.lock");
let cargo_cfg = CargoCfg::read().expect("Failed to parse Cargo config");
let default_registry = cargo_cfg
.registry()
.unwrap_or("index.crates.io".to_string());
let home = dirs::home_dir().expect("Failed to get current user home directory");
let rustup_home = Path::new(&home).join(".rustup");
if !rustup_home.exists() {
println!("rustc rust be installed");
return;
}
let output = OsCommand::new("rustup")
.arg("default")
.output()
.expect("Failed to execute rustup");
let result = String::from_utf8_lossy(output.stdout.as_slice()).to_string();
let toolchain = result
.split(" ")
.take(1)
.next()
.expect("Failed to parse rustup toolchain");
let rustup = rustup_home
.join("toolchains")
.join(toolchain)
.join("lib")
.join("rustlib")
.join("src")
.join("rust")
.join("library");
let cargo_home = Path::new(&home).join(".cargo");
if !cargo_home.exists() {
println!("cargo not be installed");
return;
}
let registry_src = fs::read_dir(cargo_home.join("registry").join("src").as_path())
.expect("Failed to walk $HOME/.cargo");
let mut registry = PathBuf::new();
for entry in registry_src.filter_map(|res| res.ok()) {
let filename = entry.file_name().to_string_lossy().to_string();
if filename.starts_with(&default_registry) {
registry = entry.path();
}
}
let ws = Workspace::from(rustup, registry, &cargo_lock).expect("Failed to create workspace");
let name = match cargo.package {
Some(ref pack) => pack.name.clone(),
None => "cargo-ws".to_string(),
};
let path = name + ".code-workspace";
ws.apply(path).expect("Failed to save workspace file");
}
fn main() {
let app = App::parse();
match app {
App::Ws(args) => generate(&args),
}
}