#![deny(unsafe_code)]
#![warn(rust_2018_idioms)]
use std::{fs, io, path::Path};
use anyhow::{bail, Context, Error};
use pico_args::Arguments;
use cargo_parcel::util::DisplayArgs;
fn write_cargo_alias() -> anyhow::Result<()> {
match fs::metadata(".cargo/config") {
Ok(_) => {
bail!("`.cargo/config` exists, not modifying");
}
Err(e) if e.kind() == io::ErrorKind::NotFound => {
fs::create_dir_all(".cargo")?;
fs::write(".cargo/config", CARGO_CONFIG_CONTENTS)
.context("Could not write `.cargo/config`")?;
}
Err(e) => {
bail!("Could not check for existence of `.cargo/config`: {}", e);
}
}
Ok(())
}
fn write_parcel_crate() -> anyhow::Result<()> {
match fs::metadata("parcel") {
Ok(_) => {
bail!("`parcel` exists, not creating");
}
Err(e) if e.kind() == io::ErrorKind::NotFound => {
for dir in &["parcel", "parcel/src"] {
fs::create_dir(dir)?;
}
for (filename, contents) in &[
("Cargo.toml", PARCEL_CARGO_TOML_CONTENTS),
(".gitignore", PARCEL_GITIGNORE_CONTENTS),
("src/main.rs", PARCEL_MAIN_CONTENTS),
] {
let path = Path::new("parcel").join(filename);
fs::write(path, contents)?;
}
}
Err(e) => {
bail!("Could not check for existence of `parcel`: {}", e);
}
}
Ok(())
}
fn run() -> Result<(), Error> {
let subcommand = match std::env::args_os().nth(2) {
None => {
print!("{}", GLOBAL_HELP);
return Ok(());
}
Some(s) => s,
};
let subcommand = &*subcommand.to_string_lossy();
match subcommand {
"init" => {
let matches = Arguments::from_vec(std::env::args_os().skip(3).collect());
let remainder = matches.finish();
if !remainder.is_empty() {
bail!("unprocessed arguments: {}", DisplayArgs(remainder.iter()))
}
write_parcel_crate()?;
write_cargo_alias()?;
}
_ => {
bail!("{}", GLOBAL_HELP);
}
}
Ok(())
}
pub fn main() -> ! {
let rc = match run() {
Ok(()) => 0,
Err(e) => {
eprintln!("{}", e);
1
}
};
std::process::exit(rc);
}
static CARGO_CONFIG_CONTENTS: &str = r#"[alias]
parcel = "run --manifest-path ./parcel/Cargo.toml --"
"#;
static PARCEL_GITIGNORE_CONTENTS: &str = r#"/target
"#;
static PARCEL_CARGO_TOML_CONTENTS: &str = concat!(
r#"[package]
name = "parcel"
version = "0.0.1"
edition = "2018"
publish = false
[dependencies]
cargo-parcel = ""#,
env!("CARGO_PKG_VERSION"),
r#""
[profile.dev]
# Disable debug info for faster builds, and less used diskspace.
debug = false
"#
);
static PARCEL_MAIN_CONTENTS: &str = r#"fn main() {
cargo_parcel::main();
}
"#;
static GLOBAL_HELP: &str = r#"Extended cargo installer -- bootstrapper
USAGE:
cargo parcel init
This is the "parcel" cargo plugin, which is normally overriden by a cargo alias
in `.cargo/config`. This plugin only implements the `install` subcommand to
prepare a crate for use with `cargo-parcel`.
See <https://gitlab.com/rotty/cargo-parcel/blob/master/README.md> for more
information.
"#;