use std::path::PathBuf;
use clap::{CommandFactory, Parser, ValueEnum};
use crate::{environment::NowEnvironment, workflow::NowWorkflowParams};
mod builder;
mod environment;
mod job;
mod project;
mod secret;
mod utils;
mod workflow;
#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub(crate) enum CheckoutStrategy {
None,
Default,
}
static LONG_ABOUT: &str = "now - Nix-based distributed command runner.
\x1b[1;4mExamples:\x1b[0m
\x1b[2m# Initialize a basic workflow in ./now.nix\x1b[0m
now init
\x1b[2m# Load envvars from a dotenv file\x1b[0m
now run --env-file .env .now/workflow-with-secrets.nix
\x1b[2m# Run the \"deploy\" job (and all dependencies), and specify a remote builder for the run\x1b[0m
now run \\
--job deploy \\
--builders \"ssh://mac aarch64-darwin\" \\
.now/remote.nix";
#[derive(Parser)]
#[command(version, about, long_about = LONG_ABOUT)]
enum Command {
Init {
workflow: Option<PathBuf>,
},
Run {
workflow: PathBuf,
#[arg(short, long = "job", value_name = "JOB")]
jobs: Option<Vec<String>>,
#[arg(long)]
all_jobs: bool,
#[arg(short, long, value_name = "FILE")]
env_file: Option<PathBuf>,
#[arg(long)]
eval: bool,
#[arg(
long = "checkout",
value_enum,
default_value_t = CheckoutStrategy::Default,
value_name = "STRATEGY",
)]
checkout_strategy: CheckoutStrategy,
#[arg(short, long)]
builders: Option<String>,
#[arg(
short,
long = "nixpkgs",
default_value = "<nixpkgs>",
value_name = "EXPRESSION"
)]
nixpkgs_expr: String,
},
Completions {
shell: clap_complete::Shell,
},
}
fn main() -> color_eyre::Result<()> {
match Command::parse() {
Command::Init { workflow } => {
let mut path = workflow.unwrap_or(PathBuf::from("."));
if path.is_dir()
|| (!path.exists() && path.extension().is_none_or(|extension| extension != "nix"))
{
path.push("now.nix");
}
if path.exists() {
return Err(color_eyre::eyre::eyre!(
"'{}' already exists",
path.to_string_lossy(),
));
}
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
std::fs::write(&path, include_bytes!("init.nix"))?;
eprintln!(
"'{}' has been initialized with a basic workflow",
path.to_string_lossy(),
)
}
Command::Run {
mut workflow,
nixpkgs_expr,
jobs,
all_jobs,
env_file,
eval,
checkout_strategy,
builders,
} => {
if all_jobs && jobs.is_some() {
return Err(color_eyre::eyre::eyre!(
"Conflicting --job and --all-jobs options"
));
}
if workflow.is_dir() {
let now = workflow.join("now.nix");
if now.exists() && !now.is_dir() {
workflow = now;
} else {
return Err(color_eyre::eyre::eyre!(
"Workflow 'now.nix' not found in directory '{}'",
workflow.to_string_lossy()
));
}
} else if !workflow.exists() {
return Err(color_eyre::eyre::eyre!(
"Workflow '{}' not found",
workflow.to_string_lossy()
));
}
let mut environment = NowEnvironment::get(&workflow, env_file.as_ref(), &nixpkgs_expr)?;
environment.run_workflow(NowWorkflowParams {
workflow,
nixpkgs_expr,
eval,
jobs,
all_jobs,
checkout_strategy,
builders,
})?;
}
Command::Completions { shell } => {
clap_complete::generate(
shell,
&mut Command::command(),
env!("CARGO_BIN_NAME"),
&mut std::io::stdout(),
);
}
}
Ok(())
}