use async_std::path::PathBuf;
use clap::{Parser, Subcommand};
use console::style;
use std::{env, sync::Arc};
pub mod action;
pub mod archive;
pub mod builder;
pub mod context;
pub mod copy;
pub mod deps;
pub mod error;
pub mod exec;
pub mod images;
pub mod init;
pub mod installer;
pub mod log;
pub mod manifest;
pub mod platform;
pub mod prelude;
pub mod result;
pub mod runner;
pub mod script;
pub mod signatures;
pub mod tpl;
pub mod utils;
cfg_if! {
if #[cfg(feature = "multiplatform")] {
pub mod macos;
pub mod linux;
pub mod windows;
} else {
#[cfg(any(target_os = "macos", feature = "unix"))]
pub mod macos;
#[cfg(any(target_os = "linux", feature = "unix"))]
pub mod linux;
#[cfg(target_os = "windows")]
pub mod windows;
}
}
use prelude::*;
#[derive(Debug, Parser)]
#[clap(name = "cargo")]
#[clap(bin_name = "cargo")]
#[clap(
// setting = AppSettings::SubcommandRequiredElseHelp,
// setting = clap::AppSettings::DeriveDisplayOrder,
dont_collapse_args_in_usage = true,
)]
enum Cmd {
#[clap(name = "nw")]
#[clap(about, author, version)]
#[clap(
// setting = clap::AppSettings::DeriveDisplayOrder,
)]
Args(Args),
}
#[derive(Debug, clap::Args)]
struct Args {
#[clap(name = "manifest")]
location: Option<String>,
#[clap(subcommand)]
action: Action,
#[clap(short, long)]
verbose: bool,
#[cfg(feature = "unix")]
#[clap(short, long)]
#[cfg(feature = "unix")]
platform: Option<Platform>,
}
#[derive(Subcommand, Debug)]
enum Action {
Build {
#[clap(short, long)]
sdk: bool,
#[clap(short, long, name = "nwjs-version")]
nwjs_version_override: Option<String>,
#[clap(short, long, name = "dry-run")]
dry_run: bool,
#[cfg(any(target_os = "linux", feature = "unix"))]
#[clap(short, long, help = "Snap distribution channel (linux only)")]
#[cfg(any(target_os = "linux", feature = "unix", feature = "multiplatform"))]
channel: Option<Channel>,
#[cfg(any(target_os = "linux", feature = "unix"))]
#[clap(short, long, help = "Snap package confinement (linux only)")]
#[cfg(any(target_os = "linux", feature = "unix"))]
confinement: Option<Confinement>,
#[clap(short, long)]
arch: Option<Architecture>,
#[clap(short, long)]
output: Option<String>,
#[clap(short, long)]
target: Option<Vec<Target>>,
#[clap(subcommand)]
default: Option<Target>,
},
Clean {
#[clap(long)]
dist: bool,
#[clap(long)]
deps: bool,
#[clap(long)]
all: bool,
},
Init {
#[clap(name = "name")]
name: Option<String>,
#[clap(long)]
js: bool,
#[clap(long)]
manifest: bool,
#[clap(long)]
force: bool,
},
Publish {
#[clap(short, long)]
output: Option<String>,
},
Run {
#[clap(short, long)]
sdk: bool,
#[clap(short, long, name = "nwjs-version")]
nwjs_version_override: Option<String>,
},
#[cfg(feature = "test")]
Test {
},
}
pub async fn async_main() -> Result<()> {
let args = Cmd::parse();
let Cmd::Args(Args {
action,
location,
verbose,
#[cfg(feature = "unix")]
platform,
}) = args;
cfg_if! {
if #[cfg(not(feature = "unix"))] {
let platform = Platform::default();
} else {
let platform = platform.unwrap_or_default();
}
}
match action {
Action::Build {
sdk,
nwjs_version_override,
dry_run,
arch,
target,
default,
output,
#[cfg(any(target_os = "linux", feature = "unix"))]
channel,
#[cfg(any(target_os = "linux", feature = "unix"))]
confinement,
} => {
if verbose {
log::enable_verbose();
}
let mut targets = TargetSet::new();
if let Some(target) = target {
targets.extend(target);
}
if let Some(default) = default {
targets.insert(default);
}
if dry_run {
targets.insert(Target::All);
}
if targets.contains(&Target::All) {
targets = Target::get_all_targets();
}
cfg_if! {
if #[cfg(not(any(target_os = "linux", feature = "unix")))] {
let channel = Some(Channel::default());
let confinement = Some(Confinement::default());
}
}
let options = Options {
sdk,
nwjs_version_override,
dry_run,
channel,
confinement,
};
let arch = if let Some(arch) = arch {
arch
} else {
Architecture::detect()?
};
let ctx = Arc::new(Context::create(location, output, platform, arch, options).await?);
let has_archive = ctx.manifest.package.archive.is_some()
|| targets.contains(&Target::All)
|| targets.contains(&Target::Archive);
if let Some(list) = &ctx.manifest.package.disable {
for disable in list.iter() {
match disable {
Target::All => targets.clear(),
_ => {
targets.remove(disable);
}
}
}
}
if has_archive {
targets.insert(Target::Archive);
}
let installer = create_installer(&ctx);
let build = Arc::new(Builder::new(ctx));
build.execute(&targets, &installer).await?;
}
Action::Clean { all, deps, dist } => {
let deps = deps || all;
let dist = dist || all;
let ctx = Arc::new(
Context::create(
location,
None,
platform,
Architecture::detect()?,
Options::default(),
)
.await?,
);
if dist {
ctx.deps.clean().await?;
}
if deps {
ctx.clean_dependencies().await?;
}
ctx.clean().await?;
}
Action::Init {
name,
js,
manifest,
force,
} => {
let folder: PathBuf = env::current_dir().unwrap().into();
let name = if let Some(name) = name {
name
} else {
folder.file_name().unwrap().to_str().unwrap().to_string()
};
let template_kind = if js {
TemplateKind::BasicJs
} else {
TemplateKind::BasicRs
};
let options = init::Options {
template_kind,
manifest,
force,
};
let mut project = init::Project::try_new(name, folder, options)?;
project.generate().await?;
}
Action::Publish { output } => {
let arch = Architecture::detect()?;
let ctx = Arc::new(
Context::create(location, output, platform, arch, Options::default()).await?,
);
let installer = create_installer(&ctx);
let target_folder = installer.target_folder();
execute_actions(Stage::Publish, &ctx, &installer.tpl(), &target_folder).await?;
}
Action::Run {
sdk,
nwjs_version_override,
} => {
let arch = Architecture::detect()?;
let options = Options {
sdk,
nwjs_version_override,
..Options::default()
};
let ctx = Arc::new(Context::create(location, None, platform, arch, options).await?);
let runner = Runner::new(ctx);
runner.run().await?;
}
#[cfg(feature = "test")]
Action::Test {} => {
let arch = Architecture::detect()?;
let ctx = Arc::new(
Context::create(location, None, platform, arch, Options::default()).await?,
);
println!("{ctx:#?}");
}
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<()> {
let result = async_main().await;
match &result {
Err(Error::Warning(warn)) => {
println!("\nWarning: {}\n", style(warn).yellow())
}
Err(err) => println!("\n{}\n", style(err).red()),
Ok(_) => {}
};
if result.is_err() {
std::process::exit(1);
}
Ok(())
}