Skip to content

Commit 2d7176e

Browse files
authored
Merge pull request #665 from nix-community/headless
Headless mode
2 parents 0c03c7b + 96c9e95 commit 2d7176e

File tree

12 files changed

+741
-406
lines changed

12 files changed

+741
-406
lines changed

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ askalono.workspace = true
3030
bstr = "1.12.1"
3131
cargo = "0.93.0"
3232
chumsky = "=1.0.0-alpha.8"
33+
enum_dispatch = "0.3.13"
3334
expand = "0.3.0"
3435
flate2 = "1.1.5"
3536
heck = "0.5.0"
@@ -93,3 +94,6 @@ vendored = ["cargo/vendored-libgit2", "cargo/vendored-openssl"]
9394
lto = true
9495
panic = "abort"
9596
codegen-units = 1
97+
98+
[lints.rust]
99+
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(not_build)"] }

build.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@ use clap::{CommandFactory, ValueEnum};
88
use clap_complete::{Shell, generate_to};
99
use clap_mangen::Man;
1010

11-
include!("src/cli.rs");
11+
mod cli {
12+
include!("src/cli.rs");
13+
}
1214

1315
fn main() {
1416
println!("cargo:rerun-if-env-changed=GEN_ARTIFACTS");
17+
println!("cargo:rustc-cfg=not_build");
1518

1619
if let Some(dir) = env::var_os("GEN_ARTIFACTS") {
1720
let out = &Path::new(&dir);
1821
create_dir_all(out).unwrap();
19-
let cmd = &mut Opts::command();
22+
let cmd = &mut cli::Opts::command();
2023

2124
Man::new(cmd.clone())
2225
.render(&mut File::create(out.join("nix-init.1")).unwrap())

src/build.rs renamed to src/builder.rs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,30 @@
11
use std::fmt::{self, Display, Formatter};
22

3-
use parse_display::Display;
3+
use crate::cli::CargoVendor;
44

55
#[derive(Clone, Copy)]
6-
pub enum BuildType {
6+
pub enum Builder {
77
BuildGoModule,
88
BuildPythonPackage {
99
application: bool,
10-
rust: Option<RustVendor>,
10+
rust: Option<CargoVendor>,
1111
},
1212
BuildRustPackage {
13-
vendor: RustVendor,
13+
vendor: CargoVendor,
1414
},
1515
MkDerivation {
16-
rust: Option<RustVendor>,
16+
rust: Option<CargoVendor>,
1717
},
1818
}
1919

20-
#[derive(Clone, Copy, Display)]
21-
#[display(style = "camelCase")]
22-
pub enum RustVendor {
23-
FetchCargoVendor,
24-
ImportCargoLock,
25-
}
26-
27-
impl Display for BuildType {
20+
impl Display for Builder {
2821
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2922
match self {
30-
BuildType::BuildGoModule => {
23+
Builder::BuildGoModule => {
3124
write!(f, "buildGoModule")?;
3225
}
3326

34-
BuildType::BuildPythonPackage { application, rust } => {
27+
Builder::BuildPythonPackage { application, rust } => {
3528
write!(
3629
f,
3730
"buildPython{}",
@@ -46,18 +39,18 @@ impl Display for BuildType {
4639
}
4740
}
4841

49-
BuildType::BuildRustPackage { vendor } => {
42+
Builder::BuildRustPackage { vendor } => {
5043
write!(
5144
f,
5245
"buildRustPackage - {}",
5346
match vendor {
54-
RustVendor::FetchCargoVendor => "cargoHash",
55-
RustVendor::ImportCargoLock => "cargoLock",
47+
CargoVendor::FetchCargoVendor => "cargoHash",
48+
CargoVendor::ImportCargoLock => "cargoLock",
5649
}
5750
)?;
5851
}
5952

60-
BuildType::MkDerivation { rust } => {
53+
Builder::MkDerivation { rust } => {
6154
write!(f, "stdenv.mkDerivation")?;
6255
if let Some(rust) = rust {
6356
write!(f, " + {rust}")?;

src/cli.rs

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use std::path::PathBuf;
22

3-
use clap::Parser;
3+
use clap::{Parser, ValueEnum};
44

55
/// Generate Nix packages with hash prefetching, license detection, and more
66
/// https://github.com/nix-community/nix-init
77
#[derive(Parser)]
8-
#[command(version, verbatim_doc_comment)]
8+
#[command(verbatim_doc_comment)]
99
pub struct Opts {
1010
/// The path or directory to output the generated file to
1111
pub output: Option<PathBuf>,
@@ -14,6 +14,42 @@ pub struct Opts {
1414
#[arg(short, long)]
1515
pub url: Option<String>,
1616

17+
/// Specify the tag or revision
18+
#[arg(long)]
19+
pub rev: Option<String>,
20+
21+
/// Always fetch submodules when possible
22+
///
23+
/// use --submodules=false to never fetch submodules
24+
#[arg(short = 'S', long, num_args=0..=1, require_equals = true, default_missing_value = "true")]
25+
pub submodules: Option<bool>,
26+
27+
/// Specify the version of the package, or print nix-init version if no arguments are present
28+
#[arg(short = 'V', long)]
29+
pub version: Option<Option<String>>,
30+
31+
/// Specify the pname
32+
#[arg(long)]
33+
pub pname: Option<String>,
34+
35+
/// Specify the builder
36+
#[arg(long)]
37+
pub builder: Option<BuilderFunction>,
38+
39+
/// Specify how the cargo dependencies are vendored
40+
#[arg(long)]
41+
pub cargo_vendor: Option<CargoVendor>,
42+
43+
/// Always overwrite files
44+
///
45+
/// use --overwrite=false to never overwrite files
46+
#[arg(short = 'y', long, num_args=0..=1, require_equals = true, default_missing_value = "true")]
47+
pub overwrite: Option<bool>,
48+
49+
/// Don't prompt for anything (requires --url)
50+
#[arg(long)]
51+
pub headless: bool,
52+
1753
/// Path to nixpkgs (in nix)
1854
///
1955
/// Examples:
@@ -33,3 +69,25 @@ pub struct Opts {
3369
#[arg(short, long)]
3470
pub config: Option<PathBuf>,
3571
}
72+
73+
#[derive(Clone, ValueEnum)]
74+
#[clap(rename_all = "camelCase")]
75+
pub enum BuilderFunction {
76+
BuildGoModule,
77+
BuildPythonApplication,
78+
BuildPythonPackage,
79+
BuildRustPackage,
80+
MkDerivation,
81+
}
82+
83+
#[derive(Clone, Copy, ValueEnum)]
84+
#[clap(rename_all = "camelCase")]
85+
#[cfg_attr(
86+
not_build,
87+
derive(parse_display::Display),
88+
display(style = "camelCase")
89+
)]
90+
pub enum CargoVendor {
91+
FetchCargoVendor,
92+
ImportCargoLock,
93+
}

src/frontend/headless.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use std::path::{Path, PathBuf};
2+
3+
use anyhow::{Result, bail};
4+
use tracing::error;
5+
6+
use crate::{
7+
builder::Builder,
8+
fetcher::{Revisions, Version},
9+
frontend::Frontend,
10+
utils::by_name_path,
11+
};
12+
13+
pub struct Headless;
14+
15+
impl Frontend for Headless {
16+
fn url(&mut self) -> Result<String> {
17+
bail!("specifying a URL with --url is required in headless mode");
18+
}
19+
20+
fn rev(&mut self, revs: Option<Revisions>) -> Result<(String, Option<Version>)> {
21+
Ok(if let Some(mut revs) = revs {
22+
(revs.latest.clone(), revs.versions.remove(&revs.latest))
23+
} else {
24+
(String::new(), None)
25+
})
26+
}
27+
28+
fn fetch_submodules(&mut self) -> Result<bool> {
29+
Ok(true)
30+
}
31+
32+
fn version(&mut self, version: &str) -> Result<String> {
33+
Ok(version.to_owned())
34+
}
35+
36+
fn pname(&mut self, pname: Option<String>) -> Result<String> {
37+
Ok(pname.unwrap_or_default())
38+
}
39+
40+
fn builder(&mut self, builders: Vec<Builder>) -> Result<Builder> {
41+
Ok(builders[0])
42+
}
43+
44+
fn output(&mut self, pname: &str, builder: &Builder) -> Result<PathBuf> {
45+
Ok(match by_name_path(pname, builder) {
46+
Some(path) => path.into(),
47+
None => PathBuf::from("."),
48+
})
49+
}
50+
51+
fn overwrite(&mut self, path: &Path) -> Result<bool> {
52+
error!(
53+
"path {} already exists, use --overwrite to overwrite to always overwrite files",
54+
path.display()
55+
);
56+
Ok(false)
57+
}
58+
}

src/frontend/mod.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
mod headless;
2+
mod readline;
3+
4+
use std::path::{Path, PathBuf};
5+
6+
use anyhow::Result;
7+
use enum_dispatch::enum_dispatch;
8+
9+
use crate::{
10+
builder::Builder,
11+
fetcher::{Revisions, Version},
12+
frontend::{headless::Headless, readline::Readline},
13+
};
14+
15+
#[enum_dispatch]
16+
pub trait Frontend {
17+
fn url(&mut self) -> Result<String>;
18+
19+
fn rev(&mut self, revs: Option<Revisions>) -> Result<(String, Option<Version>)>;
20+
21+
fn fetch_submodules(&mut self) -> Result<bool>;
22+
23+
fn version(&mut self, version: &str) -> Result<String>;
24+
25+
fn pname(&mut self, pname: Option<String>) -> Result<String>;
26+
27+
fn builder(&mut self, builders: Vec<Builder>) -> Result<Builder>;
28+
29+
fn output(&mut self, pname: &str, builder: &Builder) -> Result<PathBuf>;
30+
31+
fn overwrite(&mut self, path: &Path) -> Result<bool>;
32+
}
33+
34+
#[enum_dispatch(Frontend)]
35+
pub enum FrontendDispatch {
36+
Headless(Headless),
37+
Readline(Readline),
38+
}
39+
40+
impl FrontendDispatch {
41+
pub fn should_overwrite(&mut self, path: &Path, opt_overwrite: Option<bool>) -> Result<bool> {
42+
match opt_overwrite {
43+
Some(b) => Ok(b),
44+
None => self.overwrite(path),
45+
}
46+
}
47+
}
48+
49+
pub fn headless() -> FrontendDispatch {
50+
Headless.into()
51+
}
52+
53+
pub fn readline() -> Result<FrontendDispatch> {
54+
Readline::new().map(Into::into)
55+
}

0 commit comments

Comments
 (0)