util: block impure retries only when explicitly disabled
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I808c7976b97b3337c541f3bd4848eb486a6a6964
This commit is contained in:
parent
e385c74b57
commit
cd6a314bc8
5 changed files with 62 additions and 7 deletions
|
|
@ -31,7 +31,10 @@ struct PackageOutputs {
|
||||||
outputs: HashMap<String, serde_json::Value>,
|
outputs: HashMap<String, serde_json::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_info(args: &[String]) -> Result<i32> {
|
pub fn handle_info(
|
||||||
|
args: &[String],
|
||||||
|
cfg: &crate::config::CommandConfig,
|
||||||
|
) -> Result<i32> {
|
||||||
// Get the package argument (skip flags)
|
// Get the package argument (skip flags)
|
||||||
let pkg = args
|
let pkg = args
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -63,7 +66,8 @@ pub fn handle_info(args: &[String]) -> Result<i32> {
|
||||||
let meta_cmd = NixCommand::new("eval")
|
let meta_cmd = NixCommand::new("eval")
|
||||||
.arg("--json")
|
.arg("--json")
|
||||||
.arg(&eval_arg)
|
.arg(&eval_arg)
|
||||||
.print_build_logs(false);
|
.print_build_logs(false)
|
||||||
|
.with_config(cfg);
|
||||||
|
|
||||||
let meta_output = meta_cmd.output()?;
|
let meta_output = meta_cmd.output()?;
|
||||||
|
|
||||||
|
|
@ -91,7 +95,8 @@ pub fn handle_info(args: &[String]) -> Result<i32> {
|
||||||
let outputs_cmd = NixCommand::new("eval")
|
let outputs_cmd = NixCommand::new("eval")
|
||||||
.arg("--json")
|
.arg("--json")
|
||||||
.arg(format!("{}.outputs", outputs_expr))
|
.arg(format!("{}.outputs", outputs_expr))
|
||||||
.print_build_logs(false);
|
.print_build_logs(false)
|
||||||
|
.with_config(cfg);
|
||||||
|
|
||||||
let outputs_output = outputs_cmd.output()?;
|
let outputs_output = outputs_cmd.output()?;
|
||||||
let outputs: Option<PackageOutputs> = if outputs_output.status.success() {
|
let outputs: Option<PackageOutputs> = if outputs_output.status.success() {
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,21 @@ impl NixCommand {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply per-command configuration: sets `--impure` (when explicitly enabled)
|
||||||
|
/// and any extra environment variables declared in the config file. Call
|
||||||
|
/// this before any retry-specific overrides so that retry logic can still
|
||||||
|
/// force `impure(true)` afterwards.
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_config(mut self, cfg: &crate::config::CommandConfig) -> Self {
|
||||||
|
if cfg.impure == Some(true) {
|
||||||
|
self = self.impure(true);
|
||||||
|
}
|
||||||
|
for (k, v) in &cfg.env {
|
||||||
|
self = self.env(k, v);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn build_command(&self) -> Command {
|
fn build_command(&self) -> Command {
|
||||||
let mut cmd = Command::new("nix");
|
let mut cmd = Command::new("nix");
|
||||||
cmd.arg(&self.subcommand);
|
cmd.arg(&self.subcommand);
|
||||||
|
|
@ -321,6 +336,7 @@ pub fn handle_nix_command(
|
||||||
hash_extractor: &dyn HashExtractor,
|
hash_extractor: &dyn HashExtractor,
|
||||||
fixer: &dyn NixFileFixer,
|
fixer: &dyn NixFileFixer,
|
||||||
classifier: &dyn NixErrorClassifier,
|
classifier: &dyn NixErrorClassifier,
|
||||||
|
cfg: &crate::config::CommandConfig,
|
||||||
) -> Result<i32> {
|
) -> Result<i32> {
|
||||||
let intercept_env = matches!(command, "run" | "shell");
|
let intercept_env = matches!(command, "run" | "shell");
|
||||||
handle_nix_with_retry(
|
handle_nix_with_retry(
|
||||||
|
|
@ -330,6 +346,7 @@ pub fn handle_nix_command(
|
||||||
fixer,
|
fixer,
|
||||||
classifier,
|
classifier,
|
||||||
intercept_env,
|
intercept_env,
|
||||||
|
cfg,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,10 @@ fn prompt_input_selection(inputs: &[String]) -> Result<Vec<String>> {
|
||||||
///
|
///
|
||||||
/// If `args` is non-empty, use them as explicit input names.
|
/// If `args` is non-empty, use them as explicit input names.
|
||||||
/// Otherwise, fetch inputs interactively and prompt for selection.
|
/// Otherwise, fetch inputs interactively and prompt for selection.
|
||||||
pub fn handle_update(args: &[String]) -> Result<i32> {
|
pub fn handle_update(
|
||||||
|
args: &[String],
|
||||||
|
cfg: &crate::config::CommandConfig,
|
||||||
|
) -> Result<i32> {
|
||||||
let selected = if args.is_empty() {
|
let selected = if args.is_empty() {
|
||||||
let inputs = fetch_flake_inputs()?;
|
let inputs = fetch_flake_inputs()?;
|
||||||
if inputs.is_empty() {
|
if inputs.is_empty() {
|
||||||
|
|
@ -66,7 +69,7 @@ pub fn handle_update(args: &[String]) -> Result<i32> {
|
||||||
args.to_vec()
|
args.to_vec()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut cmd = NixCommand::new("flake").arg("lock");
|
let mut cmd = NixCommand::new("flake").arg("lock").with_config(cfg);
|
||||||
for name in &selected {
|
for name in &selected {
|
||||||
cmd = cmd.arg("--update-input").arg(name);
|
cmd = cmd.arg("--update-input").arg(name);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,11 @@ pub enum EhError {
|
||||||
|
|
||||||
#[error("no inputs selected")]
|
#[error("no inputs selected")]
|
||||||
UpdateCancelled,
|
UpdateCancelled,
|
||||||
|
|
||||||
|
#[error(
|
||||||
|
"package {reason} but `--impure` is disabled for `{command}` in config"
|
||||||
|
)]
|
||||||
|
ImpureRequired { command: String, reason: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, EhError>;
|
pub type Result<T> = std::result::Result<T, EhError>;
|
||||||
|
|
@ -77,6 +82,7 @@ impl EhError {
|
||||||
Self::JsonParse { .. } => 13,
|
Self::JsonParse { .. } => 13,
|
||||||
Self::NoFlakeInputs => 14,
|
Self::NoFlakeInputs => 14,
|
||||||
Self::UpdateCancelled => 0,
|
Self::UpdateCancelled => 0,
|
||||||
|
Self::ImpureRequired { .. } => 15,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,6 +116,12 @@ impl EhError {
|
||||||
Self::NoFlakeInputs => {
|
Self::NoFlakeInputs => {
|
||||||
Some("run this from a directory with a flake.lock that has inputs")
|
Some("run this from a directory with a flake.lock that has inputs")
|
||||||
},
|
},
|
||||||
|
Self::ImpureRequired { .. } => {
|
||||||
|
Some(
|
||||||
|
"set `impure = true` for this command (or globally) in .eh.toml or \
|
||||||
|
~/.config/eh/config.toml, or pass `--impure` manually",
|
||||||
|
)
|
||||||
|
},
|
||||||
Self::Io(_)
|
Self::Io(_)
|
||||||
| Self::Regex(_)
|
| Self::Regex(_)
|
||||||
| Self::Utf8(_)
|
| Self::Utf8(_)
|
||||||
|
|
|
||||||
|
|
@ -485,6 +485,7 @@ pub fn handle_nix_with_retry(
|
||||||
fixer: &dyn NixFileFixer,
|
fixer: &dyn NixFileFixer,
|
||||||
classifier: &dyn NixErrorClassifier,
|
classifier: &dyn NixErrorClassifier,
|
||||||
interactive: bool,
|
interactive: bool,
|
||||||
|
cfg: &crate::config::CommandConfig,
|
||||||
) -> Result<i32> {
|
) -> Result<i32> {
|
||||||
validate_nix_args(args)?;
|
validate_nix_args(args)?;
|
||||||
|
|
||||||
|
|
@ -494,10 +495,17 @@ pub fn handle_nix_with_retry(
|
||||||
let pkg = package_name(args);
|
let pkg = package_name(args);
|
||||||
let pre_eval_action = pre_evaluate(args)?;
|
let pre_eval_action = pre_evaluate(args)?;
|
||||||
if let Some((env_var, reason)) = pre_eval_action.env_override() {
|
if let Some((env_var, reason)) = pre_eval_action.env_override() {
|
||||||
|
if cfg.impure == Some(false) {
|
||||||
|
return Err(EhError::ImpureRequired {
|
||||||
|
command: subcommand.to_string(),
|
||||||
|
reason: reason.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
print_retry_msg(pkg, reason, env_var);
|
print_retry_msg(pkg, reason, env_var);
|
||||||
let mut retry_cmd = NixCommand::new(subcommand)
|
let mut retry_cmd = NixCommand::new(subcommand)
|
||||||
.print_build_logs(true)
|
.print_build_logs(true)
|
||||||
.args_ref(args)
|
.args_ref(args)
|
||||||
|
.with_config(cfg)
|
||||||
.env(env_var, "1")
|
.env(env_var, "1")
|
||||||
.impure(true);
|
.impure(true);
|
||||||
if interactive {
|
if interactive {
|
||||||
|
|
@ -513,6 +521,7 @@ pub fn handle_nix_with_retry(
|
||||||
.print_build_logs(true)
|
.print_build_logs(true)
|
||||||
.interactive(true)
|
.interactive(true)
|
||||||
.args_ref(args)
|
.args_ref(args)
|
||||||
|
.with_config(cfg)
|
||||||
.run_with_logs(StdIoInterceptor)?;
|
.run_with_logs(StdIoInterceptor)?;
|
||||||
if status.success() {
|
if status.success() {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
|
|
@ -522,7 +531,8 @@ pub fn handle_nix_with_retry(
|
||||||
// Capture output to check for errors that need retry (hash mismatches etc.)
|
// Capture output to check for errors that need retry (hash mismatches etc.)
|
||||||
let output_cmd = NixCommand::new(subcommand)
|
let output_cmd = NixCommand::new(subcommand)
|
||||||
.print_build_logs(true)
|
.print_build_logs(true)
|
||||||
.args_ref(args);
|
.args_ref(args)
|
||||||
|
.with_config(cfg);
|
||||||
let output = output_cmd.output()?;
|
let output = output_cmd.output()?;
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
|
||||||
|
|
@ -561,7 +571,8 @@ pub fn handle_nix_with_retry(
|
||||||
);
|
);
|
||||||
let mut retry_cmd = NixCommand::new(subcommand)
|
let mut retry_cmd = NixCommand::new(subcommand)
|
||||||
.print_build_logs(true)
|
.print_build_logs(true)
|
||||||
.args_ref(args);
|
.args_ref(args)
|
||||||
|
.with_config(cfg);
|
||||||
if interactive {
|
if interactive {
|
||||||
retry_cmd = retry_cmd.interactive(true);
|
retry_cmd = retry_cmd.interactive(true);
|
||||||
}
|
}
|
||||||
|
|
@ -594,10 +605,17 @@ pub fn handle_nix_with_retry(
|
||||||
if classifier.should_retry(&stderr) {
|
if classifier.should_retry(&stderr) {
|
||||||
let action = classify_retry_action(&stderr);
|
let action = classify_retry_action(&stderr);
|
||||||
if let Some((env_var, reason)) = action.env_override() {
|
if let Some((env_var, reason)) = action.env_override() {
|
||||||
|
if cfg.impure == Some(false) {
|
||||||
|
return Err(EhError::ImpureRequired {
|
||||||
|
command: subcommand.to_string(),
|
||||||
|
reason: reason.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
print_retry_msg(pkg, reason, env_var);
|
print_retry_msg(pkg, reason, env_var);
|
||||||
let mut retry_cmd = NixCommand::new(subcommand)
|
let mut retry_cmd = NixCommand::new(subcommand)
|
||||||
.print_build_logs(true)
|
.print_build_logs(true)
|
||||||
.args_ref(args)
|
.args_ref(args)
|
||||||
|
.with_config(cfg)
|
||||||
.env(env_var, "1")
|
.env(env_var, "1")
|
||||||
.impure(true);
|
.impure(true);
|
||||||
if interactive {
|
if interactive {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue