use clap::Parser;
use crate::lock_file::LockFile;
mod lock_file;
mod manifest;
const CRATES_IO: &str = "https://static.crates.io/crates";
const CARGO_HOME: &str = "cargo";
const CARGO_CRATES: &str = "cargo/vendor";
const VENDORED_SOURCES: &str = "vendored-sources";
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
cargo_lock: String,
#[clap(short, long, default_value = "generated-sources.json")]
output: String,
}
fn get_package_sources(
package: &lock_file::Package,
) -> Option<(Vec<manifest::Source>, toml::map::Map<String, toml::Value>)> {
let name = &package.name;
let version = &package.version;
if let Some(source) = package.source.as_ref() {
if source.starts_with("git+") {
todo!("git");
}
if let Some(checksum) = package.checksum.as_ref() {
let archive = manifest::Source::Archive(manifest::Archive {
archive_type: "tar-gzip".into(),
url: format!("{CRATES_IO}/{name}/{name}-{version}.crate"),
sha256: checksum.into(),
dest: format!("{CARGO_CRATES}/{name}-{version}"),
});
let inline = manifest::Source::Inline(manifest::Inline {
contents: format!(r#"{{"package": "{checksum}", "files": {{}}}}"#),
dest: format!("{CARGO_CRATES}/{name}-{version}"),
dest_filename: ".cargo-checksum.json".into(),
});
let crate_sources = vec![archive, inline];
let mut c = toml::map::Map::new();
c.insert("crates-io".into(), {
let mut obj = toml::map::Map::new();
obj.insert("replace-with".into(), VENDORED_SOURCES.into());
obj.into()
});
return Some((crate_sources, c));
}
}
None
}
fn main() {
let args = Args::parse();
let cargo_lock = std::fs::read_to_string(&args.cargo_lock).unwrap();
let cargo_lock: LockFile = toml::de::from_str(&cargo_lock).unwrap();
let mut package_sources: Vec<manifest::Source> = Vec::new();
let mut cargo_vendored_sources = toml::map::Map::new();
cargo_vendored_sources.insert(VENDORED_SOURCES.into(), {
let mut obj = toml::map::Map::new();
obj.insert("directory".into(), CARGO_CRATES.into());
obj.into()
});
for package in cargo_lock.package {
if let Some((mut pkg_sources, cargo_vendored_entry)) = get_package_sources(&package) {
package_sources.append(&mut pkg_sources);
for (key, value) in cargo_vendored_entry {
cargo_vendored_sources.insert(key, value);
}
}
}
let mut sources = package_sources.clone();
let cargo_vendored_sources = {
let mut sources = toml::map::Map::new();
sources.insert("source".into(), cargo_vendored_sources.into());
let source = toml::to_string(&sources).unwrap();
manifest::Source::Inline(manifest::Inline {
contents: source,
dest: CARGO_HOME.into(),
dest_filename: "config".into(),
})
};
sources.push(cargo_vendored_sources);
println!("{}", serde_json::to_string_pretty(&sources).unwrap());
}