Skip to content

Commit cd346f1

Browse files
committed
haskell: extract opts module
1 parent 1b6f9e6 commit cd346f1

File tree

2 files changed

+126
-122
lines changed

2 files changed

+126
-122
lines changed

nix-script-haskell/src/main.rs

Lines changed: 3 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,7 @@
1-
use anyhow::{Context, Result};
2-
use clap::Parser;
3-
use nix_script_directives::Directives;
4-
use std::path::PathBuf;
5-
use std::process::{Command, ExitStatus};
6-
7-
/// `nix-script-haskell` is a wrapper around `nix-script` with options for
8-
/// scripts written in Haskell.
9-
///
10-
/// I pay attention to all the same #! directives as nix-script, so you can
11-
/// still use `#!runtimeInputs` and friends to get external dependencies. (There
12-
/// is no need to specify `#!build` or `#!buildInputs` with regards to GHC or
13-
/// packages, though; I take care of that.)
14-
///
15-
/// In addition, I pay attention to some additional directives specific to
16-
/// Haskell programs:
17-
///
18-
/// `#!haskellPackages` should contain a list of packages the compiling GHC
19-
/// instance will know about. The available set of packages depends on your
20-
/// Nix installation; look in `haskellPackages` on `search.nixos.org` to get a
21-
/// full list.
22-
///
23-
/// `#!ghcFlags` should be a string of command-line options to pass to `ghc`
24-
/// when compiling.
25-
#[derive(Debug, Parser)]
26-
#[clap(version, trailing_var_arg = true)]
27-
struct Opts {
28-
/// Launch a ghcid session watching the script
29-
#[clap(long, conflicts_with("shell"))]
30-
ghcid: bool,
31-
32-
/// Enter a shell with all script dependencies
33-
#[clap(long, conflicts_with("ghcid"))]
34-
shell: bool,
35-
36-
/// In shell mode, run this command instead of a shell.
37-
#[clap(long, requires("shell"))]
38-
run: Option<String>,
39-
40-
/// In shell mode, run a "pure" shell (that is, one that isolates the
41-
/// shell a little more from what you have in your environment.)
42-
#[clap(long, requires("shell"))]
43-
pure: bool,
44-
45-
#[clap(long, default_value("nix-script"), hide(true))]
46-
nix_script_bin: PathBuf,
47-
48-
/// The script and arguments to pass to nix-script
49-
#[arg(num_args = 1.., required = true)]
50-
script_and_arguments: Vec<String>,
51-
}
52-
53-
impl Opts {
54-
fn run(&self) -> Result<ExitStatus> {
55-
let (script, args) = self
56-
.get_script_and_arguments()
57-
.context("could not get script and arguments")?;
58-
59-
let directives = Directives::from_file("#!", &script)
60-
.context("could not parse directives from script")?;
61-
62-
let mut nix_script = Command::new(&self.nix_script_bin);
63-
64-
let build_command = format!(
65-
"mv $SRC $SRC.hs; ghc {} -o $OUT $SRC.hs",
66-
directives
67-
.all
68-
.get("ghcFlags")
69-
.map(|ps| ps.join(" "))
70-
.unwrap_or_default()
71-
);
72-
log::debug!("build command is `{}`", build_command);
73-
nix_script.arg("--build-command").arg(build_command);
1+
mod opts;
742

75-
let compiler = format!(
76-
"haskellPackages.ghcWithPackages (ps: with ps; [ {} ])",
77-
directives
78-
.all
79-
.get("haskellPackages")
80-
.map(|ps| ps.join(" "))
81-
.unwrap_or_default()
82-
);
83-
log::debug!("compiler is `{}`", &compiler);
84-
nix_script.arg("--build-input").arg(compiler);
85-
86-
if self.shell {
87-
log::debug!("entering shell mode");
88-
nix_script.arg("--shell");
89-
} else if self.ghcid {
90-
log::debug!("entering ghcid mode");
91-
nix_script
92-
.arg("--shell")
93-
.arg("--runtime-input")
94-
.arg("ghcid")
95-
.arg("--run")
96-
.arg(format!("ghcid {}", script.display()));
97-
}
98-
99-
nix_script.arg(script);
100-
nix_script.args(args);
101-
102-
let mut child = nix_script.spawn().with_context(|| {
103-
format!(
104-
"could not call {}. Is it on the PATH?",
105-
self.nix_script_bin.display()
106-
)
107-
})?;
108-
109-
child.wait().context("could not run the script")
110-
}
111-
112-
fn get_script_and_arguments(&self) -> Result<(PathBuf, Vec<String>)> {
113-
log::trace!("parsing script and args");
114-
115-
let script = PathBuf::from(
116-
self.script_and_arguments
117-
.first()
118-
.context("no script to run; this is a bug; please report")?,
119-
);
120-
121-
Ok((script, self.script_and_arguments[1..].to_vec()))
122-
}
123-
}
3+
use clap::Parser;
4+
use opts::Opts;
1245

1256
fn main() {
1267
env_logger::Builder::from_env("NIX_SCRIPT_LOG").init();

nix-script-haskell/src/opts.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use anyhow::{Context, Result};
2+
use clap::Parser;
3+
use nix_script_directives::Directives;
4+
use std::path::PathBuf;
5+
use std::process::{Command, ExitStatus};
6+
7+
/// `nix-script-haskell` is a wrapper around `nix-script` with options for
8+
/// scripts written in Haskell.
9+
///
10+
/// I pay attention to all the same #! directives as nix-script, so you can
11+
/// still use `#!runtimeInputs` and friends to get external dependencies. (There
12+
/// is no need to specify `#!build` or `#!buildInputs` with regards to GHC or
13+
/// packages, though; I take care of that.)
14+
///
15+
/// In addition, I pay attention to some additional directives specific to
16+
/// Haskell programs:
17+
///
18+
/// `#!haskellPackages` should contain a list of packages the compiling GHC
19+
/// instance will know about. The available set of packages depends on your
20+
/// Nix installation; look in `haskellPackages` on `search.nixos.org` to get a
21+
/// full list.
22+
///
23+
/// `#!ghcFlags` should be a string of command-line options to pass to `ghc`
24+
/// when compiling.
25+
#[derive(Debug, Parser)]
26+
#[clap(version, trailing_var_arg = true)]
27+
pub struct Opts {
28+
/// Launch a ghcid session watching the script
29+
#[clap(long, conflicts_with("shell"))]
30+
ghcid: bool,
31+
32+
/// Enter a shell with all script dependencies
33+
#[clap(long, conflicts_with("ghcid"))]
34+
shell: bool,
35+
36+
/// In shell mode, run this command instead of a shell.
37+
#[clap(long, requires("shell"))]
38+
run: Option<String>,
39+
40+
/// In shell mode, run a "pure" shell (that is, one that isolates the
41+
/// shell a little more from what you have in your environment.)
42+
#[clap(long, requires("shell"))]
43+
pure: bool,
44+
45+
#[clap(long, default_value("nix-script"), hide(true))]
46+
nix_script_bin: PathBuf,
47+
48+
/// The script and args to pass to nix-script
49+
#[arg(num_args = 1.., required = true)]
50+
script_and_args: Vec<String>,
51+
}
52+
53+
impl Opts {
54+
pub fn run(&self) -> Result<ExitStatus> {
55+
let (script, args) = self
56+
.get_script_and_args()
57+
.context("could not get script and args")?;
58+
59+
let directives = Directives::from_file("#!", &script)
60+
.context("could not parse directives from script")?;
61+
62+
let mut nix_script = Command::new(&self.nix_script_bin);
63+
64+
let build_command = format!(
65+
"mv $SRC $SRC.hs; ghc {} -o $OUT $SRC.hs",
66+
directives
67+
.all
68+
.get("ghcFlags")
69+
.map(|ps| ps.join(" "))
70+
.unwrap_or_default()
71+
);
72+
log::debug!("build command is `{}`", build_command);
73+
nix_script.arg("--build-command").arg(build_command);
74+
75+
let compiler = format!(
76+
"haskellPackages.ghcWithPackages (ps: with ps; [ {} ])",
77+
directives
78+
.all
79+
.get("haskellPackages")
80+
.map(|ps| ps.join(" "))
81+
.unwrap_or_default()
82+
);
83+
log::debug!("compiler is `{}`", &compiler);
84+
nix_script.arg("--build-input").arg(compiler);
85+
86+
if self.shell {
87+
log::debug!("entering shell mode");
88+
nix_script.arg("--shell");
89+
} else if self.ghcid {
90+
log::debug!("entering ghcid mode");
91+
nix_script
92+
.arg("--shell")
93+
.arg("--runtime-input")
94+
.arg("ghcid")
95+
.arg("--run")
96+
.arg(format!("ghcid {}", script.display()));
97+
}
98+
99+
nix_script.arg(script);
100+
nix_script.args(args);
101+
102+
let mut child = nix_script.spawn().with_context(|| {
103+
format!(
104+
"could not call {}. Is it on the PATH?",
105+
self.nix_script_bin.display()
106+
)
107+
})?;
108+
109+
child.wait().context("could not run the script")
110+
}
111+
112+
fn get_script_and_args(&self) -> Result<(PathBuf, Vec<String>)> {
113+
log::trace!("parsing script and args");
114+
115+
let script = PathBuf::from(
116+
self.script_and_args
117+
.first()
118+
.context("no script to run; this is a bug; please report")?,
119+
);
120+
121+
Ok((script, self.script_and_args[1..].to_vec()))
122+
}
123+
}

0 commit comments

Comments
 (0)