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>,
|
||||
}
|
||||
|
||||
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)
|
||||
let pkg = args
|
||||
.iter()
|
||||
|
|
@ -63,7 +66,8 @@ pub fn handle_info(args: &[String]) -> Result<i32> {
|
|||
let meta_cmd = NixCommand::new("eval")
|
||||
.arg("--json")
|
||||
.arg(&eval_arg)
|
||||
.print_build_logs(false);
|
||||
.print_build_logs(false)
|
||||
.with_config(cfg);
|
||||
|
||||
let meta_output = meta_cmd.output()?;
|
||||
|
||||
|
|
@ -91,7 +95,8 @@ pub fn handle_info(args: &[String]) -> Result<i32> {
|
|||
let outputs_cmd = NixCommand::new("eval")
|
||||
.arg("--json")
|
||||
.arg(format!("{}.outputs", outputs_expr))
|
||||
.print_build_logs(false);
|
||||
.print_build_logs(false)
|
||||
.with_config(cfg);
|
||||
|
||||
let outputs_output = outputs_cmd.output()?;
|
||||
let outputs: Option<PackageOutputs> = if outputs_output.status.success() {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,21 @@ impl NixCommand {
|
|||
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 {
|
||||
let mut cmd = Command::new("nix");
|
||||
cmd.arg(&self.subcommand);
|
||||
|
|
@ -321,6 +336,7 @@ pub fn handle_nix_command(
|
|||
hash_extractor: &dyn HashExtractor,
|
||||
fixer: &dyn NixFileFixer,
|
||||
classifier: &dyn NixErrorClassifier,
|
||||
cfg: &crate::config::CommandConfig,
|
||||
) -> Result<i32> {
|
||||
let intercept_env = matches!(command, "run" | "shell");
|
||||
handle_nix_with_retry(
|
||||
|
|
@ -330,6 +346,7 @@ pub fn handle_nix_command(
|
|||
fixer,
|
||||
classifier,
|
||||
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.
|
||||
/// 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 inputs = fetch_flake_inputs()?;
|
||||
if inputs.is_empty() {
|
||||
|
|
@ -66,7 +69,7 @@ pub fn handle_update(args: &[String]) -> Result<i32> {
|
|||
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 {
|
||||
cmd = cmd.arg("--update-input").arg(name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ pub enum EhError {
|
|||
|
||||
#[error("no inputs selected")]
|
||||
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>;
|
||||
|
|
@ -77,6 +82,7 @@ impl EhError {
|
|||
Self::JsonParse { .. } => 13,
|
||||
Self::NoFlakeInputs => 14,
|
||||
Self::UpdateCancelled => 0,
|
||||
Self::ImpureRequired { .. } => 15,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +116,12 @@ impl EhError {
|
|||
Self::NoFlakeInputs => {
|
||||
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::Regex(_)
|
||||
| Self::Utf8(_)
|
||||
|
|
|
|||
|
|
@ -485,6 +485,7 @@ pub fn handle_nix_with_retry(
|
|||
fixer: &dyn NixFileFixer,
|
||||
classifier: &dyn NixErrorClassifier,
|
||||
interactive: bool,
|
||||
cfg: &crate::config::CommandConfig,
|
||||
) -> Result<i32> {
|
||||
validate_nix_args(args)?;
|
||||
|
||||
|
|
@ -494,10 +495,17 @@ pub fn handle_nix_with_retry(
|
|||
let pkg = package_name(args);
|
||||
let pre_eval_action = pre_evaluate(args)?;
|
||||
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);
|
||||
let mut retry_cmd = NixCommand::new(subcommand)
|
||||
.print_build_logs(true)
|
||||
.args_ref(args)
|
||||
.with_config(cfg)
|
||||
.env(env_var, "1")
|
||||
.impure(true);
|
||||
if interactive {
|
||||
|
|
@ -513,6 +521,7 @@ pub fn handle_nix_with_retry(
|
|||
.print_build_logs(true)
|
||||
.interactive(true)
|
||||
.args_ref(args)
|
||||
.with_config(cfg)
|
||||
.run_with_logs(StdIoInterceptor)?;
|
||||
if status.success() {
|
||||
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.)
|
||||
let output_cmd = NixCommand::new(subcommand)
|
||||
.print_build_logs(true)
|
||||
.args_ref(args);
|
||||
.args_ref(args)
|
||||
.with_config(cfg);
|
||||
let output = output_cmd.output()?;
|
||||
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)
|
||||
.print_build_logs(true)
|
||||
.args_ref(args);
|
||||
.args_ref(args)
|
||||
.with_config(cfg);
|
||||
if interactive {
|
||||
retry_cmd = retry_cmd.interactive(true);
|
||||
}
|
||||
|
|
@ -594,10 +605,17 @@ pub fn handle_nix_with_retry(
|
|||
if classifier.should_retry(&stderr) {
|
||||
let action = classify_retry_action(&stderr);
|
||||
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);
|
||||
let mut retry_cmd = NixCommand::new(subcommand)
|
||||
.print_build_logs(true)
|
||||
.args_ref(args)
|
||||
.with_config(cfg)
|
||||
.env(env_var, "1")
|
||||
.impure(true);
|
||||
if interactive {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue