Improve with-env robustness (#12523)

# Description
Work for #7149

- **Error `with-env` given uneven count in list form**
- **Fix `with-env` `CantConvert` to record**
- **Error `with-env` when given protected env vars**
- **Deprecate list/table input of vars to `with-env`**
- **Remove examples for deprecated input**

# User-Facing Changes

## Deprecation of the following forms

```
> with-env [MYENV "my env value"] { $env.MYENV }
my env value

> with-env [X Y W Z] { $env.X }
Y

> with-env [[X W]; [Y Z]] { $env.W }
Z
```

## recommended standardized form

```
# Set by key-value record
> with-env {X: "Y", W: "Z"} { [$env.X $env.W] }
╭───┬───╮
│ 0 │ Y │
│ 1 │ Z │
╰───┴───╯
```

## (Side effect) Repeated definitions in an env shorthand are now
disallowed

```
> FOO=bar FOO=baz $env
Error: nu:🐚:column_defined_twice

  × Record field or table column used twice: FOO
   ╭─[entry #1:1:1]
 1 │ FOO=bar FOO=baz $env
   · ─┬─     ─┬─
   ·  │       ╰── field redefined here
   ·  ╰── field first defined here
   ╰────
```
This commit is contained in:
Stefan Holderbach
2024-04-16 13:08:58 +02:00
committed by GitHub
parent 5f818eaefe
commit c9e9b138eb
10 changed files with 57 additions and 49 deletions

View File

@ -41,31 +41,14 @@ impl Command for WithEnv {
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Set the MYENV environment variable",
example: r#"with-env [MYENV "my env value"] { $env.MYENV }"#,
result: Some(Value::test_string("my env value")),
},
Example {
description: "Set by primitive value list",
example: r#"with-env [X Y W Z] { $env.X }"#,
result: Some(Value::test_string("Y")),
},
Example {
description: "Set by single row table",
example: r#"with-env [[X W]; [Y Z]] { $env.W }"#,
result: Some(Value::test_string("Z")),
},
Example {
description: "Set by key-value record",
example: r#"with-env {X: "Y", W: "Z"} { [$env.X $env.W] }"#,
result: Some(Value::list(
vec![Value::test_string("Y"), Value::test_string("Z")],
Span::test_data(),
)),
},
]
vec![Example {
description: "Set by key-value record",
example: r#"with-env {X: "Y", W: "Z"} { [$env.X $env.W] }"#,
result: Some(Value::list(
vec![Value::test_string("Y"), Value::test_string("Z")],
Span::test_data(),
)),
}]
}
}
@ -85,6 +68,16 @@ fn with_env(
match &variable {
Value::List { vals: table, .. } => {
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "Deprecated argument type".into(),
msg: "providing the variables to `with-env` as a list or single row table has been deprecated".into(),
span: Some(variable.span()),
help: Some("use the record form instead".into()),
inner: vec![],
},
);
if table.len() == 1 {
// single row([[X W]; [Y Z]])
match &table[0] {
@ -95,7 +88,7 @@ fn with_env(
}
x => {
return Err(ShellError::CantConvert {
to_type: "string list or single row".into(),
to_type: "record".into(),
from_type: x.get_type().to_string(),
span: call
.positional_nth(1)
@ -111,7 +104,13 @@ fn with_env(
if row.len() == 2 {
env.insert(row[0].coerce_string()?, row[1].clone());
}
// TODO: else error?
if row.len() == 1 {
return Err(ShellError::IncorrectValue {
msg: format!("Missing value for $env.{}", row[0].coerce_string()?),
val_span: row[0].span(),
call_span: call.head,
});
}
}
}
}
@ -123,7 +122,7 @@ fn with_env(
}
x => {
return Err(ShellError::CantConvert {
to_type: "string list or single row".into(),
to_type: "record".into(),
from_type: x.get_type().to_string(),
span: call
.positional_nth(1)
@ -134,6 +133,16 @@ fn with_env(
}
};
// TODO: factor list of prohibited env vars into common place
for prohibited in ["PWD", "FILE_PWD", "CURRENT_FILE"] {
if env.contains_key(prohibited) {
return Err(ShellError::AutomaticEnvVarSetManually {
envvar_name: prohibited.into(),
span: call.head,
});
}
}
for (k, v) in env {
stack.add_env_var(k, v);
}