2023-01-20 21:20:38 +00:00
|
|
|
mod command;
|
2022-01-18 08:48:28 +00:00
|
|
|
mod config_files;
|
2023-04-05 19:34:47 +00:00
|
|
|
mod ide;
|
2022-01-18 08:48:28 +00:00
|
|
|
mod logger;
|
2023-02-05 21:20:35 +00:00
|
|
|
mod run;
|
2023-01-20 18:44:49 +00:00
|
|
|
mod signals;
|
Do not block signals for child processes (#11402)
# Description / User-Facing Changes
Signals are no longer blocked for child processes launched from both
interactive and non-interactive mode. The only exception is that
`SIGTSTP`, `SIGTTIN`, and `SIGTTOU` remain blocked for child processes
launched only from **interactive** mode. This is to help prevent nushell
from getting into an unrecoverable state, since we don't support
background jobs. Anyways, this fully fixes #9026.
# Other Notes
- Needs Rust version `>= 1.66` for a fix in
`std::process::Command::spawn`, but it looks our current Rust version is
way above this.
- Uses `sigaction` instead of `signal`, since the behavior of `signal`
can apparently differ across systems. Also, the `sigaction` man page
says:
> The sigaction() function supersedes the signal() function, and should
be used in preference.
Additionally, using both `sigaction` and `signal` is not recommended.
Since we were already using `sigaction` in some places (and possibly
some of our dependencies as well), this PR replaces all usages of
`signal`.
# Tests
Might want to wait for #11178 for testing.
2024-01-15 22:08:21 +00:00
|
|
|
#[cfg(unix)]
|
2023-01-20 21:20:38 +00:00
|
|
|
mod terminal;
|
2022-02-09 22:08:16 +00:00
|
|
|
mod test_bins;
|
2021-08-10 18:57:08 +00:00
|
|
|
|
2023-06-14 22:27:12 +00:00
|
|
|
#[cfg(feature = "mimalloc")]
|
|
|
|
#[global_allocator]
|
|
|
|
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
|
|
|
|
2023-01-20 21:20:38 +00:00
|
|
|
use crate::{
|
|
|
|
command::parse_commandline_args,
|
2023-02-05 21:20:35 +00:00
|
|
|
config_files::set_config_path,
|
2023-01-20 21:20:38 +00:00
|
|
|
logger::{configure, logger},
|
|
|
|
};
|
2023-01-26 23:56:55 +00:00
|
|
|
use command::gather_commandline_args;
|
2024-03-28 16:27:12 +00:00
|
|
|
use log::{trace, Level};
|
2022-01-18 08:48:28 +00:00
|
|
|
use miette::Result;
|
2023-03-20 04:05:22 +00:00
|
|
|
use nu_cli::gather_parent_env_vars;
|
2023-06-23 19:23:08 +00:00
|
|
|
use nu_cmd_base::util::get_init_cwd;
|
2023-11-02 15:18:57 +00:00
|
|
|
use nu_lsp::LanguageServer;
|
Fix #12416 by canonicalizing XDG_CONFIG_HOME before comparing to config_dir() (#12420)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx
you can also mention related issues, PRs or discussions!
-->
# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.
Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
Fixes #12416. Turns out that in src/main.rs, `XDG_CONFIG_HOME` wasn't
being canonicalized before being compared to `nu_path::config_dir()` to
check if `XDG_CONFIG_HOME` was set to an invalid value. This has been
rectified now.
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
Setting `XDG_CONFIG_HOME` to a symlink should work now.
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
I manually tested it and the error has disappeared:
New behavior (this branch):
![image](https://github.com/nushell/nushell/assets/45539777/062d1cc5-551c-431c-b138-d3da8de018bd)
Old behavior (main):
![image](https://github.com/nushell/nushell/assets/45539777/22c4b5a3-3fd0-4ab6-9cf0-ae25488645ba)
Thanks to a pointer from Devyn, I've now added tests to make sure the
`xdg_config_home_invalid` error doesn't pop up when `XDG_CONFIG_HOME` is
a symlink (and does when it's actually invalid).
Turns out two of the tests in `test_config_path` tried modifying
`XDG_CONFIG_HOME` using `playground.with_env` but used `nu!`, so the
subprocess didn't actually use the modified value of `XDG_CONFIG_HOME`.
When I added them, I was unaware that the `.with_env` didn't actually
modify the environment. This has now been rectified.
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-04-06 14:09:03 +00:00
|
|
|
use nu_path::canonicalize_with;
|
2023-09-01 06:18:55 +00:00
|
|
|
use nu_protocol::{
|
Error on non-zero exit statuses (#13515)
# Description
This PR makes it so that non-zero exit codes and termination by signal
are treated as a normal `ShellError`. Currently, these are silent
errors. That is, if an external command fails, then it's code block is
aborted, but the parent block can sometimes continue execution. E.g.,
see #8569 and this example:
```nushell
[1 2] | each { ^false }
```
Before this would give:
```
╭───┬──╮
│ 0 │ │
│ 1 │ │
╰───┴──╯
```
Now, this shows an error:
```
Error: nu::shell::eval_block_with_input
× Eval block failed with pipeline input
╭─[entry #1:1:2]
1 │ [1 2] | each { ^false }
· ┬
· ╰── source value
╰────
Error: nu::shell::non_zero_exit_code
× External command had a non-zero exit code
╭─[entry #1:1:17]
1 │ [1 2] | each { ^false }
· ──┬──
· ╰── exited with code 1
╰────
```
This PR fixes #12874, fixes #5960, fixes #10856, and fixes #5347. This
PR also partially addresses #10633 and #10624 (only the last command of
a pipeline is currently checked). It looks like #8569 is already fixed,
but this PR will make sure it is definitely fixed (fixes #8569).
# User-Facing Changes
- Non-zero exit codes and termination by signal now cause an error to be
thrown.
- The error record value passed to a `catch` block may now have an
`exit_code` column containing the integer exit code if the error was due
to an external command.
- Adds new config values, `display_errors.exit_code` and
`display_errors.termination_signal`, which determine whether an error
message should be printed in the respective error cases. For
non-interactive sessions, these are set to `true`, and for interactive
sessions `display_errors.exit_code` is false (via the default config).
# Tests
Added a few tests.
# After Submitting
- Update docs and book.
- Future work:
- Error if other external commands besides the last in a pipeline exit
with a non-zero exit code. Then, deprecate `do -c` since this will be
the default behavior everywhere.
- Add a better mechanism for exit codes and deprecate
`$env.LAST_EXIT_CODE` (it's buggy).
2024-09-07 06:44:26 +00:00
|
|
|
engine::EngineState, report_shell_error, ByteStream, PipelineData, ShellError, Span, Spanned,
|
2024-06-05 08:42:55 +00:00
|
|
|
Value,
|
2023-09-01 06:18:55 +00:00
|
|
|
};
|
2023-04-29 10:48:32 +00:00
|
|
|
use nu_std::load_standard_library;
|
2024-06-27 23:56:56 +00:00
|
|
|
use nu_utils::perf;
|
2023-02-05 21:20:35 +00:00
|
|
|
use run::{run_commands, run_file, run_repl};
|
2023-12-21 16:00:38 +00:00
|
|
|
use signals::ctrlc_protection;
|
2024-07-07 22:29:01 +00:00
|
|
|
use std::{path::PathBuf, str::FromStr, sync::Arc};
|
2022-09-29 18:37:48 +00:00
|
|
|
|
2023-06-14 21:12:55 +00:00
|
|
|
fn get_engine_state() -> EngineState {
|
|
|
|
let engine_state = nu_cmd_lang::create_default_context();
|
2024-04-21 12:36:26 +00:00
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
let engine_state = nu_cmd_plugin::add_plugin_command_context(engine_state);
|
2023-06-14 21:12:55 +00:00
|
|
|
let engine_state = nu_command::add_shell_command_context(engine_state);
|
|
|
|
let engine_state = nu_cmd_extra::add_extra_command_context(engine_state);
|
|
|
|
let engine_state = nu_cli::add_cli_context(engine_state);
|
|
|
|
nu_explore::add_explore_context(engine_state)
|
|
|
|
}
|
|
|
|
|
2021-09-20 21:37:26 +00:00
|
|
|
fn main() -> Result<()> {
|
2023-01-24 20:28:59 +00:00
|
|
|
let entire_start_time = std::time::Instant::now();
|
|
|
|
let mut start_time = std::time::Instant::now();
|
2024-02-22 18:14:10 +00:00
|
|
|
miette::set_panic_hook();
|
2021-10-01 16:39:50 +00:00
|
|
|
let miette_hook = std::panic::take_hook();
|
|
|
|
std::panic::set_hook(Box::new(move |x| {
|
2021-12-04 12:38:21 +00:00
|
|
|
crossterm::terminal::disable_raw_mode().expect("unable to disable raw mode");
|
2021-10-01 16:39:50 +00:00
|
|
|
miette_hook(x);
|
|
|
|
}));
|
2021-09-21 19:37:16 +00:00
|
|
|
|
2022-01-04 22:30:34 +00:00
|
|
|
// Get initial current working directory.
|
2022-03-16 18:17:06 +00:00
|
|
|
let init_cwd = get_init_cwd();
|
2023-06-14 21:12:55 +00:00
|
|
|
let mut engine_state = get_engine_state();
|
2021-07-17 06:31:34 +00:00
|
|
|
|
2022-01-24 15:05:19 +00:00
|
|
|
// Custom additions
|
|
|
|
let delta = {
|
|
|
|
let mut working_set = nu_protocol::engine::StateWorkingSet::new(&engine_state);
|
|
|
|
working_set.add_decl(Box::new(nu_cli::NuHighlight));
|
2022-02-18 18:43:34 +00:00
|
|
|
working_set.add_decl(Box::new(nu_cli::Print));
|
2022-01-24 15:05:19 +00:00
|
|
|
working_set.render()
|
|
|
|
};
|
2022-07-14 14:09:27 +00:00
|
|
|
|
|
|
|
if let Err(err) = engine_state.merge_delta(delta) {
|
Error on non-zero exit statuses (#13515)
# Description
This PR makes it so that non-zero exit codes and termination by signal
are treated as a normal `ShellError`. Currently, these are silent
errors. That is, if an external command fails, then it's code block is
aborted, but the parent block can sometimes continue execution. E.g.,
see #8569 and this example:
```nushell
[1 2] | each { ^false }
```
Before this would give:
```
╭───┬──╮
│ 0 │ │
│ 1 │ │
╰───┴──╯
```
Now, this shows an error:
```
Error: nu::shell::eval_block_with_input
× Eval block failed with pipeline input
╭─[entry #1:1:2]
1 │ [1 2] | each { ^false }
· ┬
· ╰── source value
╰────
Error: nu::shell::non_zero_exit_code
× External command had a non-zero exit code
╭─[entry #1:1:17]
1 │ [1 2] | each { ^false }
· ──┬──
· ╰── exited with code 1
╰────
```
This PR fixes #12874, fixes #5960, fixes #10856, and fixes #5347. This
PR also partially addresses #10633 and #10624 (only the last command of
a pipeline is currently checked). It looks like #8569 is already fixed,
but this PR will make sure it is definitely fixed (fixes #8569).
# User-Facing Changes
- Non-zero exit codes and termination by signal now cause an error to be
thrown.
- The error record value passed to a `catch` block may now have an
`exit_code` column containing the integer exit code if the error was due
to an external command.
- Adds new config values, `display_errors.exit_code` and
`display_errors.termination_signal`, which determine whether an error
message should be printed in the respective error cases. For
non-interactive sessions, these are set to `true`, and for interactive
sessions `display_errors.exit_code` is false (via the default config).
# Tests
Added a few tests.
# After Submitting
- Update docs and book.
- Future work:
- Error if other external commands besides the last in a pipeline exit
with a non-zero exit code. Then, deprecate `do -c` since this will be
the default behavior everywhere.
- Add a better mechanism for exit codes and deprecate
`$env.LAST_EXIT_CODE` (it's buggy).
2024-09-07 06:44:26 +00:00
|
|
|
report_shell_error(&engine_state, &err);
|
2022-07-14 14:09:27 +00:00
|
|
|
}
|
2022-01-24 15:05:19 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
// TODO: make this conditional in the future
|
2024-07-07 22:29:01 +00:00
|
|
|
ctrlc_protection(&mut engine_state);
|
2022-06-09 12:08:15 +00:00
|
|
|
|
2023-12-07 14:13:50 +00:00
|
|
|
// Begin: Default NU_LIB_DIRS, NU_PLUGIN_DIRS
|
|
|
|
// Set default NU_LIB_DIRS and NU_PLUGIN_DIRS here before the env.nu is processed. If
|
|
|
|
// the env.nu file exists, these values will be overwritten, if it does not exist, or
|
|
|
|
// there is an error reading it, these values will be used.
|
|
|
|
let nushell_config_path = if let Some(mut path) = nu_path::config_dir() {
|
|
|
|
path.push("nushell");
|
2024-08-01 08:16:31 +00:00
|
|
|
path.into()
|
2023-12-07 14:13:50 +00:00
|
|
|
} else {
|
|
|
|
// Not really sure what to default this to if nu_path::config_dir() returns None
|
|
|
|
std::path::PathBuf::new()
|
|
|
|
};
|
|
|
|
|
Use XDG_CONFIG_HOME before default config directory (#12118)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx
you can also mention related issues, PRs or discussions!
-->
Closes #12103
# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.
Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
As described in #12103, this PR makes Nushell use `XDG_CONFIG_HOME` as
the config directory if it exists. Otherwise, it uses the old behavior,
which was to use `dirs_next::config_dir()`.
Edit: We discussed choosing between `XDG_CONFIG_HOME` and the default
config directory in Discord and decided against it, at least for now.
<s>@kubouch also suggested letting users choose between
`XDG_CONFIG_HOME` and the default config directory if config files
aren't found on startup and `XDG_CONFIG_HOME` is set to a value
different from the default config directory</s>
On Windows and MacOS, if the `XDG_CONFIG_HOME` variable is set but
`XDG_CONFIG_HOME` is either empty or doesn't exist *and* the old config
directory is non-empty, Nushell will issue a warning on startup saying
that it won't move files from the old config directory to the new one.
To do this, I had to add a `nu_path::config_dir_old()` function. I
assume that at some point, we will remove the warning message and the
function can be removed too. Alternatively, instead of having that
function there, `main.rs` could directly call `dirs_next::config_dir()`.
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
When `$env.XDG_CONFIG_HOME` is set to an absolute path, Nushell will use
`$"($env.XDG_CONFIG_HOME)/nushell"` as its config directory (previously,
this only worked on Linux).
To use `App Data\Roaming` (Windows) or `Library/Application Support`
(MacOS) instead (the old behavior), one can either leave
`XDG_CONFIG_HOME` unset or set it to an empty string.
If `XDG_CONFIG_HOME` is set, but to a non-absolute/invalid path, Nushell
will report an error on startup and use the default config directory
instead:
![image](https://github.com/nushell/nushell/assets/45539777/a434fe04-b7c8-4e95-b50c-80628008ad08)
On Windows and MacOS, if the `XDG_CONFIG_HOME` variable is set but
`XDG_CONFIG_HOME` is either empty or doesn't exist *and* the old config
directory is non-empty, Nushell will issue a warning on startup saying
that it won't move files from the old config directory to the new one.
![image](https://github.com/nushell/nushell/assets/45539777/1686cc17-4083-4c12-aecf-1d832460ca57)
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
The existing config path tests have been modified to use
`XDG_CONFIG_HOME` to change the config directory on all OSes, not just
Linux.
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
The documentation will have to be updated to note that Nushell uses
`XDG_CONFIG_HOME` now. As @fdncred pointed out, it's possible for people
to set `XDG_CONFIG_HOME` to, say, `~/.config/nushell` rather than
`~/.config`, so the documentation could warn about that mistake.
2024-03-11 11:15:46 +00:00
|
|
|
if let Ok(xdg_config_home) = std::env::var("XDG_CONFIG_HOME") {
|
|
|
|
if !xdg_config_home.is_empty() {
|
Fix #12416 by canonicalizing XDG_CONFIG_HOME before comparing to config_dir() (#12420)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx
you can also mention related issues, PRs or discussions!
-->
# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.
Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
Fixes #12416. Turns out that in src/main.rs, `XDG_CONFIG_HOME` wasn't
being canonicalized before being compared to `nu_path::config_dir()` to
check if `XDG_CONFIG_HOME` was set to an invalid value. This has been
rectified now.
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
Setting `XDG_CONFIG_HOME` to a symlink should work now.
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
I manually tested it and the error has disappeared:
New behavior (this branch):
![image](https://github.com/nushell/nushell/assets/45539777/062d1cc5-551c-431c-b138-d3da8de018bd)
Old behavior (main):
![image](https://github.com/nushell/nushell/assets/45539777/22c4b5a3-3fd0-4ab6-9cf0-ae25488645ba)
Thanks to a pointer from Devyn, I've now added tests to make sure the
`xdg_config_home_invalid` error doesn't pop up when `XDG_CONFIG_HOME` is
a symlink (and does when it's actually invalid).
Turns out two of the tests in `test_config_path` tried modifying
`XDG_CONFIG_HOME` using `playground.with_env` but used `nu!`, so the
subprocess didn't actually use the modified value of `XDG_CONFIG_HOME`.
When I added them, I was unaware that the `.with_env` didn't actually
modify the environment. This has now been rectified.
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-04-06 14:09:03 +00:00
|
|
|
if nushell_config_path
|
|
|
|
!= canonicalize_with(&xdg_config_home, &init_cwd)
|
|
|
|
.unwrap_or(PathBuf::from(&xdg_config_home))
|
|
|
|
.join("nushell")
|
|
|
|
{
|
Error on non-zero exit statuses (#13515)
# Description
This PR makes it so that non-zero exit codes and termination by signal
are treated as a normal `ShellError`. Currently, these are silent
errors. That is, if an external command fails, then it's code block is
aborted, but the parent block can sometimes continue execution. E.g.,
see #8569 and this example:
```nushell
[1 2] | each { ^false }
```
Before this would give:
```
╭───┬──╮
│ 0 │ │
│ 1 │ │
╰───┴──╯
```
Now, this shows an error:
```
Error: nu::shell::eval_block_with_input
× Eval block failed with pipeline input
╭─[entry #1:1:2]
1 │ [1 2] | each { ^false }
· ┬
· ╰── source value
╰────
Error: nu::shell::non_zero_exit_code
× External command had a non-zero exit code
╭─[entry #1:1:17]
1 │ [1 2] | each { ^false }
· ──┬──
· ╰── exited with code 1
╰────
```
This PR fixes #12874, fixes #5960, fixes #10856, and fixes #5347. This
PR also partially addresses #10633 and #10624 (only the last command of
a pipeline is currently checked). It looks like #8569 is already fixed,
but this PR will make sure it is definitely fixed (fixes #8569).
# User-Facing Changes
- Non-zero exit codes and termination by signal now cause an error to be
thrown.
- The error record value passed to a `catch` block may now have an
`exit_code` column containing the integer exit code if the error was due
to an external command.
- Adds new config values, `display_errors.exit_code` and
`display_errors.termination_signal`, which determine whether an error
message should be printed in the respective error cases. For
non-interactive sessions, these are set to `true`, and for interactive
sessions `display_errors.exit_code` is false (via the default config).
# Tests
Added a few tests.
# After Submitting
- Update docs and book.
- Future work:
- Error if other external commands besides the last in a pipeline exit
with a non-zero exit code. Then, deprecate `do -c` since this will be
the default behavior everywhere.
- Add a better mechanism for exit codes and deprecate
`$env.LAST_EXIT_CODE` (it's buggy).
2024-09-07 06:44:26 +00:00
|
|
|
report_shell_error(
|
Use XDG_CONFIG_HOME before default config directory (#12118)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx
you can also mention related issues, PRs or discussions!
-->
Closes #12103
# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.
Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
As described in #12103, this PR makes Nushell use `XDG_CONFIG_HOME` as
the config directory if it exists. Otherwise, it uses the old behavior,
which was to use `dirs_next::config_dir()`.
Edit: We discussed choosing between `XDG_CONFIG_HOME` and the default
config directory in Discord and decided against it, at least for now.
<s>@kubouch also suggested letting users choose between
`XDG_CONFIG_HOME` and the default config directory if config files
aren't found on startup and `XDG_CONFIG_HOME` is set to a value
different from the default config directory</s>
On Windows and MacOS, if the `XDG_CONFIG_HOME` variable is set but
`XDG_CONFIG_HOME` is either empty or doesn't exist *and* the old config
directory is non-empty, Nushell will issue a warning on startup saying
that it won't move files from the old config directory to the new one.
To do this, I had to add a `nu_path::config_dir_old()` function. I
assume that at some point, we will remove the warning message and the
function can be removed too. Alternatively, instead of having that
function there, `main.rs` could directly call `dirs_next::config_dir()`.
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
When `$env.XDG_CONFIG_HOME` is set to an absolute path, Nushell will use
`$"($env.XDG_CONFIG_HOME)/nushell"` as its config directory (previously,
this only worked on Linux).
To use `App Data\Roaming` (Windows) or `Library/Application Support`
(MacOS) instead (the old behavior), one can either leave
`XDG_CONFIG_HOME` unset or set it to an empty string.
If `XDG_CONFIG_HOME` is set, but to a non-absolute/invalid path, Nushell
will report an error on startup and use the default config directory
instead:
![image](https://github.com/nushell/nushell/assets/45539777/a434fe04-b7c8-4e95-b50c-80628008ad08)
On Windows and MacOS, if the `XDG_CONFIG_HOME` variable is set but
`XDG_CONFIG_HOME` is either empty or doesn't exist *and* the old config
directory is non-empty, Nushell will issue a warning on startup saying
that it won't move files from the old config directory to the new one.
![image](https://github.com/nushell/nushell/assets/45539777/1686cc17-4083-4c12-aecf-1d832460ca57)
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
The existing config path tests have been modified to use
`XDG_CONFIG_HOME` to change the config directory on all OSes, not just
Linux.
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
The documentation will have to be updated to note that Nushell uses
`XDG_CONFIG_HOME` now. As @fdncred pointed out, it's possible for people
to set `XDG_CONFIG_HOME` to, say, `~/.config/nushell` rather than
`~/.config`, so the documentation could warn about that mistake.
2024-03-11 11:15:46 +00:00
|
|
|
&engine_state,
|
|
|
|
&ShellError::InvalidXdgConfig {
|
|
|
|
xdg: xdg_config_home,
|
|
|
|
default: nushell_config_path.display().to_string(),
|
|
|
|
},
|
|
|
|
);
|
2024-08-01 08:16:31 +00:00
|
|
|
} else if let Some(old_config) = dirs::config_dir()
|
|
|
|
.and_then(|p| p.canonicalize().ok())
|
|
|
|
.map(|p| p.join("nushell"))
|
2024-06-11 19:10:31 +00:00
|
|
|
{
|
Use XDG_CONFIG_HOME before default config directory (#12118)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx
you can also mention related issues, PRs or discussions!
-->
Closes #12103
# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.
Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
As described in #12103, this PR makes Nushell use `XDG_CONFIG_HOME` as
the config directory if it exists. Otherwise, it uses the old behavior,
which was to use `dirs_next::config_dir()`.
Edit: We discussed choosing between `XDG_CONFIG_HOME` and the default
config directory in Discord and decided against it, at least for now.
<s>@kubouch also suggested letting users choose between
`XDG_CONFIG_HOME` and the default config directory if config files
aren't found on startup and `XDG_CONFIG_HOME` is set to a value
different from the default config directory</s>
On Windows and MacOS, if the `XDG_CONFIG_HOME` variable is set but
`XDG_CONFIG_HOME` is either empty or doesn't exist *and* the old config
directory is non-empty, Nushell will issue a warning on startup saying
that it won't move files from the old config directory to the new one.
To do this, I had to add a `nu_path::config_dir_old()` function. I
assume that at some point, we will remove the warning message and the
function can be removed too. Alternatively, instead of having that
function there, `main.rs` could directly call `dirs_next::config_dir()`.
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
When `$env.XDG_CONFIG_HOME` is set to an absolute path, Nushell will use
`$"($env.XDG_CONFIG_HOME)/nushell"` as its config directory (previously,
this only worked on Linux).
To use `App Data\Roaming` (Windows) or `Library/Application Support`
(MacOS) instead (the old behavior), one can either leave
`XDG_CONFIG_HOME` unset or set it to an empty string.
If `XDG_CONFIG_HOME` is set, but to a non-absolute/invalid path, Nushell
will report an error on startup and use the default config directory
instead:
![image](https://github.com/nushell/nushell/assets/45539777/a434fe04-b7c8-4e95-b50c-80628008ad08)
On Windows and MacOS, if the `XDG_CONFIG_HOME` variable is set but
`XDG_CONFIG_HOME` is either empty or doesn't exist *and* the old config
directory is non-empty, Nushell will issue a warning on startup saying
that it won't move files from the old config directory to the new one.
![image](https://github.com/nushell/nushell/assets/45539777/1686cc17-4083-4c12-aecf-1d832460ca57)
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
The existing config path tests have been modified to use
`XDG_CONFIG_HOME` to change the config directory on all OSes, not just
Linux.
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
The documentation will have to be updated to note that Nushell uses
`XDG_CONFIG_HOME` now. As @fdncred pointed out, it's possible for people
to set `XDG_CONFIG_HOME` to, say, `~/.config/nushell` rather than
`~/.config`, so the documentation could warn about that mistake.
2024-03-11 11:15:46 +00:00
|
|
|
let xdg_config_empty = nushell_config_path
|
|
|
|
.read_dir()
|
|
|
|
.map_or(true, |mut dir| dir.next().is_none());
|
|
|
|
let old_config_empty = old_config
|
|
|
|
.read_dir()
|
|
|
|
.map_or(true, |mut dir| dir.next().is_none());
|
|
|
|
if !old_config_empty && xdg_config_empty {
|
|
|
|
eprintln!(
|
|
|
|
"WARNING: XDG_CONFIG_HOME has been set but {} is empty.\n",
|
|
|
|
nushell_config_path.display(),
|
|
|
|
);
|
|
|
|
eprintln!(
|
|
|
|
"Nushell will not move your configuration files from {}",
|
|
|
|
old_config.display()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-11 19:10:31 +00:00
|
|
|
let default_nushell_completions_path = if let Some(mut path) = nu_path::data_dir() {
|
|
|
|
path.push("nushell");
|
|
|
|
path.push("completions");
|
2024-08-01 08:16:31 +00:00
|
|
|
path.into()
|
2024-06-11 19:10:31 +00:00
|
|
|
} else {
|
|
|
|
std::path::PathBuf::new()
|
|
|
|
};
|
|
|
|
|
2023-12-07 14:13:50 +00:00
|
|
|
let mut default_nu_lib_dirs_path = nushell_config_path.clone();
|
|
|
|
default_nu_lib_dirs_path.push("scripts");
|
|
|
|
engine_state.add_env_var(
|
|
|
|
"NU_LIB_DIRS".to_string(),
|
2024-06-11 19:10:31 +00:00
|
|
|
Value::test_list(vec![
|
|
|
|
Value::test_string(default_nu_lib_dirs_path.to_string_lossy()),
|
|
|
|
Value::test_string(default_nushell_completions_path.to_string_lossy()),
|
|
|
|
]),
|
2023-12-07 14:13:50 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut default_nu_plugin_dirs_path = nushell_config_path;
|
|
|
|
default_nu_plugin_dirs_path.push("plugins");
|
|
|
|
engine_state.add_env_var(
|
|
|
|
"NU_PLUGIN_DIRS".to_string(),
|
2024-04-20 15:04:41 +00:00
|
|
|
Value::test_list(vec![Value::test_string(
|
|
|
|
default_nu_plugin_dirs_path.to_string_lossy(),
|
|
|
|
)]),
|
2023-12-07 14:13:50 +00:00
|
|
|
);
|
|
|
|
// End: Default NU_LIB_DIRS, NU_PLUGIN_DIRS
|
|
|
|
|
Add `stor` family of commands (#11170)
# Description
This PR adds the `stor` family of commands. These commands are meant to
create, open, insert, update, delete, reset data in an in-memory sqlite
database. This is really an experiment to see how creatively we can use
an in-memory database.
```
Usage:
> stor
Subcommands:
stor create - Create a table in the in-memory sqlite database
stor delete - Delete a table or specified rows in the in-memory sqlite database
stor export - Export the in-memory sqlite database to a sqlite database file
stor import - Import a sqlite database file into the in-memory sqlite database
stor insert - Insert information into a specified table in the in-memory sqlite database
stor open - Opens the in-memory sqlite database
stor reset - Reset the in-memory database by dropping all tables
stor update - Update information in a specified table in the in-memory sqlite database
Flags:
-h, --help - Display the help message for this command
Input/output types:
╭─#─┬──input──┬─output─╮
│ 0 │ nothing │ string │
╰───┴─────────┴────────╯
```
### Examples
## stor create
```nushell
❯ stor create --table-name nudb --columns {bool1: bool, int1: int, float1: float, str1: str, datetime1: datetime}
╭──────┬────────────────╮
│ nudb │ [list 0 items] │
╰──────┴────────────────╯
```
## stor insert
```nushell
❯ stor insert --table-name nudb --data-record {bool1: true, int1: 2, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
```
## stor open
```nushell
❯ stor open | table -e
╭──────┬────────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 2 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯ │
╰──────┴────────────────────────────────────────────────────────────────────╯
```
## stor update
```nushell
❯ stor update --table-name nudb --update-record {str1: toby datetime1: 2021-04-17} --where-clause "bool1 = 1"
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
❯ stor open | table -e
╭──────┬─────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬─str1─┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 2 │ 1.10 │ toby │ 2021-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴──────┴────────────────────────────╯ │
╰──────┴─────────────────────────────────────────────────────────────────╯
```
## insert another row
```nushell
❯ stor insert --table-name nudb --data-record {bool1: true, int1: 5, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}
╭──────┬────────────────╮
│ nudb │ [table 2 rows] │
╰──────┴────────────────╯
❯ stor open | table -e
╭──────┬────────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 2 │ 1.10 │ toby │ 2021-04-17 00:00:00 +00:00 │ │
│ │ │ 1 │ 2 │ 1 │ 5 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯ │
╰──────┴────────────────────────────────────────────────────────────────────╯
```
## stor delete (specific row(s))
```nushell
❯ stor delete --table-name nudb --where-clause "int1 == 5"
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
```
## insert multiple tables
```nushell
❯ stor create --table-name nudb1 --columns {bool1: bool, int1: int, float1: float, str1: str, datetime1: datetime}
╭───────┬────────────────╮
│ nudb │ [table 1 row] │
│ nudb1 │ [list 0 items] │
╰───────┴────────────────╯
❯ stor insert --table-name nudb1 --data-record {bool1: true, int1: 2, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}
╭───────┬───────────────╮
│ nudb │ [table 1 row] │
│ nudb1 │ [table 1 row] │
╰───────┴───────────────╯
❯ stor create --table-name nudb2 --columns {bool1: bool, int1: int, float1: float, str1: str, datetime1: datetime}
╭───────┬────────────────╮
│ nudb │ [table 1 row] │
│ nudb1 │ [table 1 row] │
│ nudb2 │ [list 0 items] │
╰───────┴────────────────╯
❯ stor insert --table-name nudb2 --data-record {bool1: true, int1: 2, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}
╭───────┬───────────────╮
│ nudb │ [table 1 row] │
│ nudb1 │ [table 1 row] │
│ nudb2 │ [table 1 row] │
╰───────┴───────────────╯
```
## stor delete (specific table)
```nushell
❯ stor delete --table-name nudb1
╭───────┬───────────────╮
│ nudb │ [table 1 row] │
│ nudb2 │ [table 1 row] │
╰───────┴───────────────╯
```
## stor reset (all tables are deleted)
```nushell
❯ stor reset
```
## stor export
```nushell
❯ stor export --file-name nudb.sqlite3
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
❯ open nudb.sqlite3 | table -e
╭──────┬────────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 5 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯ │
╰──────┴────────────────────────────────────────────────────────────────────╯
❯ open nudb.sqlite3 | schema | table -e
╭────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │ ╭──────┬──────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ tables │ │ │ ╭───────────────┬──────────────────────────────────────────────────────────────────────────────╮ │ │
│ │ │ nudb │ │ │ ╭─#─┬─cid─┬───name────┬─────type─────┬─notnull─┬───────default────────┬─pk─╮ │ │ │
│ │ │ │ │ columns │ │ 0 │ 0 │ id │ INTEGER │ 1 │ │ 1 │ │ │ │
│ │ │ │ │ │ │ 1 │ 1 │ bool1 │ BOOLEAN │ 0 │ │ 0 │ │ │ │
│ │ │ │ │ │ │ 2 │ 2 │ int1 │ INTEGER │ 0 │ │ 0 │ │ │ │
│ │ │ │ │ │ │ 3 │ 3 │ float1 │ REAL │ 0 │ │ 0 │ │ │ │
│ │ │ │ │ │ │ 4 │ 4 │ str1 │ VARCHAR(255) │ 0 │ │ 0 │ │ │ │
│ │ │ │ │ │ │ 5 │ 5 │ datetime1 │ DATETIME │ 0 │ STRFTIME('%Y-%m-%d │ 0 │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ %H:%M:%f', 'NOW') │ │ │ │ │
│ │ │ │ │ │ ╰─#─┴─cid─┴───name────┴─────type─────┴─notnull─┴───────default────────┴─pk─╯ │ │ │
│ │ │ │ │ constraints │ [list 0 items] │ │ │
│ │ │ │ │ foreign_keys │ [list 0 items] │ │ │
│ │ │ │ │ indexes │ [list 0 items] │ │ │
│ │ │ │ ╰───────────────┴──────────────────────────────────────────────────────────────────────────────╯ │ │
│ │ ╰──────┴──────────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
## Using with `query db`
```nushell
❯ stor open | query db "select * from nudb"
╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮
│ 0 │ 1 │ 1 │ 5 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │
╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯
```
## stor import
```nushell
❯ stor open
# note, nothing is returned. there is nothing in memory, atm.
❯ stor import --file-name nudb.sqlite3
╭──────┬───────────────╮
│ nudb │ [table 1 row] │
╰──────┴───────────────╯
❯ stor open | table -e
╭──────┬────────────────────────────────────────────────────────────────────╮
│ │ ╭─#─┬id─┬bool1┬int1┬float1┬──str1───┬─────────datetime1──────────╮ │
│ nudb │ │ 0 │ 1 │ 1 │ 5 │ 1.10 │ fdncred │ 2023-04-17 00:00:00 +00:00 │ │
│ │ ╰───┴───┴─────┴────┴──────┴─────────┴────────────────────────────╯ │
╰──────┴────────────────────────────────────────────────────────────────────╯
```
TODO:
- [x] `stor export` - Export a fully formed sqlite db file.
- [x] `stor import` - Imports a specified sqlite db file.
- [x] Perhaps feature-gate it with the sqlite feature
- [x] Update `query db` to work with the in-memory database
- [x] Remove `open --in-memory`
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-11-29 16:02:46 +00:00
|
|
|
// This is the real secret sauce to having an in-memory sqlite db. You must
|
|
|
|
// start a connection to the memory database in main so it will exist for the
|
|
|
|
// lifetime of the program. If it's created with how MEMORY_DB is defined
|
|
|
|
// you'll be able to access this open connection from anywhere in the program
|
|
|
|
// by using the identical connection string.
|
|
|
|
#[cfg(feature = "sqlite")]
|
|
|
|
let db = nu_command::open_connection_in_memory_custom()?;
|
|
|
|
#[cfg(feature = "sqlite")]
|
|
|
|
db.last_insert_rowid();
|
|
|
|
|
2023-01-26 23:56:55 +00:00
|
|
|
let (args_to_nushell, script_name, args_to_script) = gather_commandline_args();
|
|
|
|
let parsed_nu_cli_args = parse_commandline_args(&args_to_nushell.join(" "), &mut engine_state)
|
2024-06-05 08:42:55 +00:00
|
|
|
.unwrap_or_else(|err| {
|
Error on non-zero exit statuses (#13515)
# Description
This PR makes it so that non-zero exit codes and termination by signal
are treated as a normal `ShellError`. Currently, these are silent
errors. That is, if an external command fails, then it's code block is
aborted, but the parent block can sometimes continue execution. E.g.,
see #8569 and this example:
```nushell
[1 2] | each { ^false }
```
Before this would give:
```
╭───┬──╮
│ 0 │ │
│ 1 │ │
╰───┴──╯
```
Now, this shows an error:
```
Error: nu::shell::eval_block_with_input
× Eval block failed with pipeline input
╭─[entry #1:1:2]
1 │ [1 2] | each { ^false }
· ┬
· ╰── source value
╰────
Error: nu::shell::non_zero_exit_code
× External command had a non-zero exit code
╭─[entry #1:1:17]
1 │ [1 2] | each { ^false }
· ──┬──
· ╰── exited with code 1
╰────
```
This PR fixes #12874, fixes #5960, fixes #10856, and fixes #5347. This
PR also partially addresses #10633 and #10624 (only the last command of
a pipeline is currently checked). It looks like #8569 is already fixed,
but this PR will make sure it is definitely fixed (fixes #8569).
# User-Facing Changes
- Non-zero exit codes and termination by signal now cause an error to be
thrown.
- The error record value passed to a `catch` block may now have an
`exit_code` column containing the integer exit code if the error was due
to an external command.
- Adds new config values, `display_errors.exit_code` and
`display_errors.termination_signal`, which determine whether an error
message should be printed in the respective error cases. For
non-interactive sessions, these are set to `true`, and for interactive
sessions `display_errors.exit_code` is false (via the default config).
# Tests
Added a few tests.
# After Submitting
- Update docs and book.
- Future work:
- Error if other external commands besides the last in a pipeline exit
with a non-zero exit code. Then, deprecate `do -c` since this will be
the default behavior everywhere.
- Add a better mechanism for exit codes and deprecate
`$env.LAST_EXIT_CODE` (it's buggy).
2024-09-07 06:44:26 +00:00
|
|
|
report_shell_error(&engine_state, &err);
|
2024-06-05 08:42:55 +00:00
|
|
|
std::process::exit(1)
|
|
|
|
});
|
2023-01-20 18:44:49 +00:00
|
|
|
|
2023-07-17 21:32:29 +00:00
|
|
|
// keep this condition in sync with the branches at the end
|
2023-08-04 20:43:35 +00:00
|
|
|
engine_state.is_interactive = parsed_nu_cli_args.interactive_shell.is_some()
|
|
|
|
|| (parsed_nu_cli_args.testbin.is_none()
|
|
|
|
&& parsed_nu_cli_args.commands.is_none()
|
|
|
|
&& script_name.is_empty());
|
2023-07-17 21:32:29 +00:00
|
|
|
|
2023-03-09 02:59:33 +00:00
|
|
|
engine_state.is_login = parsed_nu_cli_args.login_shell.is_some();
|
|
|
|
|
2024-01-17 15:40:59 +00:00
|
|
|
engine_state.history_enabled = parsed_nu_cli_args.no_history.is_none();
|
|
|
|
|
2023-02-01 23:03:05 +00:00
|
|
|
let use_color = engine_state.get_config().use_ansi_coloring;
|
2024-06-05 08:42:55 +00:00
|
|
|
|
|
|
|
// Set up logger
|
2023-02-05 21:20:35 +00:00
|
|
|
if let Some(level) = parsed_nu_cli_args
|
|
|
|
.log_level
|
|
|
|
.as_ref()
|
|
|
|
.map(|level| level.item.clone())
|
|
|
|
{
|
2023-01-24 20:28:59 +00:00
|
|
|
let level = if Level::from_str(&level).is_ok() {
|
|
|
|
level
|
|
|
|
} else {
|
|
|
|
eprintln!(
|
|
|
|
"ERROR: log library did not recognize log level '{level}', using default 'info'"
|
|
|
|
);
|
|
|
|
"info".to_string()
|
|
|
|
};
|
|
|
|
let target = parsed_nu_cli_args
|
|
|
|
.log_target
|
2023-02-05 21:20:35 +00:00
|
|
|
.as_ref()
|
|
|
|
.map(|target| target.item.clone())
|
2023-01-24 20:28:59 +00:00
|
|
|
.unwrap_or_else(|| "stderr".to_string());
|
|
|
|
|
2024-06-05 08:42:55 +00:00
|
|
|
let make_filters = |filters: &Option<Vec<Spanned<String>>>| {
|
|
|
|
filters.as_ref().map(|filters| {
|
|
|
|
filters
|
|
|
|
.iter()
|
|
|
|
.map(|filter| filter.item.clone())
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
})
|
|
|
|
};
|
|
|
|
let filters = logger::Filters {
|
|
|
|
include: make_filters(&parsed_nu_cli_args.log_include),
|
|
|
|
exclude: make_filters(&parsed_nu_cli_args.log_exclude),
|
|
|
|
};
|
|
|
|
|
|
|
|
logger(|builder| configure(&level, &target, filters, builder))?;
|
2023-01-24 20:28:59 +00:00
|
|
|
// info!("start logging {}:{}:{}", file!(), line!(), column!());
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("start logging", start_time, use_color);
|
2023-01-24 20:28:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
start_time = std::time::Instant::now();
|
2023-01-20 18:44:49 +00:00
|
|
|
set_config_path(
|
|
|
|
&mut engine_state,
|
2024-08-01 08:16:31 +00:00
|
|
|
init_cwd.as_ref(),
|
2023-01-20 18:44:49 +00:00
|
|
|
"config.nu",
|
|
|
|
"config-path",
|
2023-09-12 23:00:58 +00:00
|
|
|
parsed_nu_cli_args.config_file.as_ref(),
|
2023-01-20 18:44:49 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
set_config_path(
|
|
|
|
&mut engine_state,
|
2024-08-01 08:16:31 +00:00
|
|
|
init_cwd.as_ref(),
|
2023-01-20 18:44:49 +00:00
|
|
|
"env.nu",
|
|
|
|
"env-path",
|
2023-09-12 23:00:58 +00:00
|
|
|
parsed_nu_cli_args.env_file.as_ref(),
|
2023-01-20 18:44:49 +00:00
|
|
|
);
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("set_config_path", start_time, use_color);
|
2023-01-20 18:44:49 +00:00
|
|
|
|
Do not block signals for child processes (#11402)
# Description / User-Facing Changes
Signals are no longer blocked for child processes launched from both
interactive and non-interactive mode. The only exception is that
`SIGTSTP`, `SIGTTIN`, and `SIGTTOU` remain blocked for child processes
launched only from **interactive** mode. This is to help prevent nushell
from getting into an unrecoverable state, since we don't support
background jobs. Anyways, this fully fixes #9026.
# Other Notes
- Needs Rust version `>= 1.66` for a fix in
`std::process::Command::spawn`, but it looks our current Rust version is
way above this.
- Uses `sigaction` instead of `signal`, since the behavior of `signal`
can apparently differ across systems. Also, the `sigaction` man page
says:
> The sigaction() function supersedes the signal() function, and should
be used in preference.
Additionally, using both `sigaction` and `signal` is not recommended.
Since we were already using `sigaction` in some places (and possibly
some of our dependencies as well), this PR replaces all usages of
`signal`.
# Tests
Might want to wait for #11178 for testing.
2024-01-15 22:08:21 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
start_time = std::time::Instant::now();
|
|
|
|
terminal::acquire(engine_state.is_interactive);
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("acquire_terminal", start_time, use_color);
|
Do not block signals for child processes (#11402)
# Description / User-Facing Changes
Signals are no longer blocked for child processes launched from both
interactive and non-interactive mode. The only exception is that
`SIGTSTP`, `SIGTTIN`, and `SIGTTOU` remain blocked for child processes
launched only from **interactive** mode. This is to help prevent nushell
from getting into an unrecoverable state, since we don't support
background jobs. Anyways, this fully fixes #9026.
# Other Notes
- Needs Rust version `>= 1.66` for a fix in
`std::process::Command::spawn`, but it looks our current Rust version is
way above this.
- Uses `sigaction` instead of `signal`, since the behavior of `signal`
can apparently differ across systems. Also, the `sigaction` man page
says:
> The sigaction() function supersedes the signal() function, and should
be used in preference.
Additionally, using both `sigaction` and `signal` is not recommended.
Since we were already using `sigaction` in some places (and possibly
some of our dependencies as well), this PR replaces all usages of
`signal`.
# Tests
Might want to wait for #11178 for testing.
2024-01-15 22:08:21 +00:00
|
|
|
}
|
2023-01-20 18:44:49 +00:00
|
|
|
|
2024-03-28 16:27:12 +00:00
|
|
|
start_time = std::time::Instant::now();
|
2023-04-12 17:36:29 +00:00
|
|
|
if let Some(include_path) = &parsed_nu_cli_args.include_path {
|
2023-04-12 18:21:02 +00:00
|
|
|
let span = include_path.span;
|
|
|
|
let vals: Vec<_> = include_path
|
|
|
|
.item
|
2023-04-21 20:30:36 +00:00
|
|
|
.split('\x1e') // \x1e is the record separator character (a character that is unlikely to appear in a path)
|
2023-09-03 14:27:29 +00:00
|
|
|
.map(|x| Value::string(x.trim().to_string(), span))
|
2023-04-12 18:21:02 +00:00
|
|
|
.collect();
|
|
|
|
|
2023-09-03 14:27:29 +00:00
|
|
|
engine_state.add_env_var("NU_LIB_DIRS".into(), Value::list(vals, span));
|
2023-04-12 17:36:29 +00:00
|
|
|
}
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("NU_LIB_DIRS setup", start_time, use_color);
|
2023-04-12 17:36:29 +00:00
|
|
|
|
2023-05-23 20:48:50 +00:00
|
|
|
start_time = std::time::Instant::now();
|
|
|
|
// First, set up env vars as strings only
|
2024-08-01 08:16:31 +00:00
|
|
|
gather_parent_env_vars(&mut engine_state, init_cwd.as_ref());
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("gather env vars", start_time, use_color);
|
2023-05-23 20:48:50 +00:00
|
|
|
|
2023-09-01 06:48:13 +00:00
|
|
|
engine_state.add_env_var(
|
|
|
|
"NU_VERSION".to_string(),
|
|
|
|
Value::string(env!("CARGO_PKG_VERSION"), Span::unknown()),
|
|
|
|
);
|
|
|
|
|
2023-05-07 12:29:15 +00:00
|
|
|
if parsed_nu_cli_args.no_std_lib.is_none() {
|
|
|
|
load_standard_library(&mut engine_state)?;
|
|
|
|
}
|
|
|
|
|
2023-04-05 19:34:47 +00:00
|
|
|
// IDE commands
|
|
|
|
if let Some(ide_goto_def) = parsed_nu_cli_args.ide_goto_def {
|
|
|
|
ide::goto_def(&mut engine_state, &script_name, &ide_goto_def);
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
} else if let Some(ide_hover) = parsed_nu_cli_args.ide_hover {
|
|
|
|
ide::hover(&mut engine_state, &script_name, &ide_hover);
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
} else if let Some(ide_complete) = parsed_nu_cli_args.ide_complete {
|
2023-04-12 17:36:29 +00:00
|
|
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
|
|
|
engine_state.add_env_var("PWD".into(), Value::test_string(cwd.to_string_lossy()));
|
|
|
|
|
2023-04-05 19:34:47 +00:00
|
|
|
ide::complete(Arc::new(engine_state), &script_name, &ide_complete);
|
|
|
|
|
|
|
|
return Ok(());
|
2023-04-13 17:53:18 +00:00
|
|
|
} else if let Some(max_errors) = parsed_nu_cli_args.ide_check {
|
|
|
|
ide::check(&mut engine_state, &script_name, &max_errors);
|
2023-04-05 19:34:47 +00:00
|
|
|
|
add `--ide-ast` for a simplistic ast for editors (#8995)
# Description
This is WIP. This generates a simplistic AST so that we can call it from
the vscode side for semantic token highlighting. The output is a
minified version of this screenshot.
![image](https://user-images.githubusercontent.com/343840/234354668-872d6267-9946-4b92-8a13-4fed45b4513a.png)
The script
```
def test [arg] {
print $arg
for i in (seq 1 10) {
echo $i
}
}
```
The simplistic AST
```json
[{"content":"def","index":0,"shape":"shape_internalcall","span":{"end":15,"start":12}},{"content":"test","index":1,"shape":"shape_string","span":{"end":20,"start":16}},{"content":"[arg]","index":2,"shape":"shape_signature","span":{"end":26,"start":21}},{"content":"{\r\n ","index":3,"shape":"shape_closure","span":{"end":32,"start":27}},{"content":"print","index":4,"shape":"shape_internalcall","span":{"end":37,"start":32}},{"content":"$arg","index":5,"shape":"shape_variable","span":{"end":42,"start":38}},{"content":"for","index":6,"shape":"shape_internalcall","span":{"end":49,"start":46}},{"content":"i","index":7,"shape":"shape_vardecl","span":{"end":51,"start":50}},{"content":"in","index":8,"shape":"shape_keyword","span":{"end":54,"start":52}},{"content":"(","index":9,"shape":"shape_block","span":{"end":56,"start":55}},{"content":"seq","index":10,"shape":"shape_internalcall","span":{"end":59,"start":56}},{"content":"1","index":11,"shape":"shape_int","span":{"end":61,"start":60}},{"content":"10","index":12,"shape":"shape_int","span":{"end":64,"start":62}},{"content":")","index":13,"shape":"shape_block","span":{"end":65,"start":64}},{"content":"{\r\n ","index":14,"shape":"shape_block","span":{"end":73,"start":66}},{"content":"echo","index":15,"shape":"shape_internalcall","span":{"end":77,"start":73}},{"content":"$i","index":16,"shape":"shape_variable","span":{"end":80,"start":78}},{"content":"\r\n }","index":17,"shape":"shape_block","span":{"end":85,"start":80}},{"content":"\r\n}","index":18,"shape":"shape_closure","span":{"end":88,"start":85}}]
```
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the
standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-04-28 13:51:51 +00:00
|
|
|
return Ok(());
|
|
|
|
} else if parsed_nu_cli_args.ide_ast.is_some() {
|
|
|
|
ide::ast(&mut engine_state, &script_name);
|
|
|
|
|
2023-04-05 19:34:47 +00:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2023-01-24 20:28:59 +00:00
|
|
|
start_time = std::time::Instant::now();
|
2023-01-20 18:44:49 +00:00
|
|
|
if let Some(testbin) = &parsed_nu_cli_args.testbin {
|
|
|
|
// Call out to the correct testbin
|
|
|
|
match testbin.item.as_str() {
|
|
|
|
"echo_env" => test_bins::echo_env(true),
|
|
|
|
"echo_env_stderr" => test_bins::echo_env(false),
|
2024-02-21 13:15:05 +00:00
|
|
|
"echo_env_stderr_fail" => test_bins::echo_env_and_fail(false),
|
2023-11-28 12:42:35 +00:00
|
|
|
"echo_env_mixed" => test_bins::echo_env_mixed(),
|
2023-01-20 18:44:49 +00:00
|
|
|
"cococo" => test_bins::cococo(),
|
|
|
|
"meow" => test_bins::meow(),
|
|
|
|
"meowb" => test_bins::meowb(),
|
|
|
|
"relay" => test_bins::relay(),
|
|
|
|
"iecho" => test_bins::iecho(),
|
|
|
|
"fail" => test_bins::fail(),
|
|
|
|
"nonu" => test_bins::nonu(),
|
|
|
|
"chop" => test_bins::chop(),
|
|
|
|
"repeater" => test_bins::repeater(),
|
special-case ExternalStream in bytes starts-with (#8203)
# Description
`bytes starts-with` converts the input into a `Value` before running
.starts_with to find if the binary matches. This has two side effects:
it makes the code simpler, only dealing in whole values, and simplifying
a lot of input pipeline handling and value transforming it would
otherwise have to do. _Especially_ in the presence of a cell path to
drill into. It also makes buffers the entire input into memory, which
can take up a lot of memory when dealing with large files, especially if
you only want to check the first few bytes (like for a magic number).
This PR adds a special branch on PipelineData::ExternalStream with a
streaming version of starts_with.
# User-Facing Changes
Opening large files and running bytes starts-with on them will not take
a long time.
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# Drawbacks
Streaming checking is more complicated, and there may be bugs. I tested
it with multiple chunks with string data and binary data and it seems to
work alright up to 8k and over bytes, though.
The existing `operate` method still exists because the way it handles
cell paths and values is complicated. This causes some "code
duplication", or at least some intent duplication, between the value
code and the streaming code. This might be worthwhile considering the
performance gains (approaching infinity on larger inputs).
Another thing to consider is that my ExternalStream branch considers
string data as valid input. The operate branch only parses Binary
values, so it would fail. `open` is kind of unpredictable on whether it
returns string data or binary data, even when passing `--raw`. I think
this can be a problem but not really one I'm trying to tackle in this
PR, so, it's worth considering.
2023-02-26 14:17:44 +00:00
|
|
|
"repeat_bytes" => test_bins::repeat_bytes(),
|
2023-01-20 18:44:49 +00:00
|
|
|
"nu_repl" => test_bins::nu_repl(),
|
2023-02-24 20:39:52 +00:00
|
|
|
"input_bytes_length" => test_bins::input_bytes_length(),
|
2023-01-20 18:44:49 +00:00
|
|
|
_ => std::process::exit(1),
|
|
|
|
}
|
|
|
|
std::process::exit(0)
|
|
|
|
}
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("run test_bins", start_time, use_color);
|
2023-01-24 20:28:59 +00:00
|
|
|
|
|
|
|
start_time = std::time::Instant::now();
|
2023-01-20 18:44:49 +00:00
|
|
|
let input = if let Some(redirect_stdin) = &parsed_nu_cli_args.redirect_stdin {
|
2024-03-28 16:27:12 +00:00
|
|
|
trace!("redirecting stdin");
|
Replace `ExternalStream` with new `ByteStream` type (#12774)
# Description
This PR introduces a `ByteStream` type which is a `Read`-able stream of
bytes. Internally, it has an enum over three different byte stream
sources:
```rust
pub enum ByteStreamSource {
Read(Box<dyn Read + Send + 'static>),
File(File),
Child(ChildProcess),
}
```
This is in comparison to the current `RawStream` type, which is an
`Iterator<Item = Vec<u8>>` and has to allocate for each read chunk.
Currently, `PipelineData::ExternalStream` serves a weird dual role where
it is either external command output or a wrapper around `RawStream`.
`ByteStream` makes this distinction more clear (via `ByteStreamSource`)
and replaces `PipelineData::ExternalStream` in this PR:
```rust
pub enum PipelineData {
Empty,
Value(Value, Option<PipelineMetadata>),
ListStream(ListStream, Option<PipelineMetadata>),
ByteStream(ByteStream, Option<PipelineMetadata>),
}
```
The PR is relatively large, but a decent amount of it is just repetitive
changes.
This PR fixes #7017, fixes #10763, and fixes #12369.
This PR also improves performance when piping external commands. Nushell
should, in most cases, have competitive pipeline throughput compared to,
e.g., bash.
| Command | Before (MB/s) | After (MB/s) | Bash (MB/s) |
| -------------------------------------------------- | -------------:|
------------:| -----------:|
| `throughput \| rg 'x'` | 3059 | 3744 | 3739 |
| `throughput \| nu --testbin relay o> /dev/null` | 3508 | 8087 | 8136 |
# User-Facing Changes
- This is a breaking change for the plugin communication protocol,
because the `ExternalStreamInfo` was replaced with `ByteStreamInfo`.
Plugins now only have to deal with a single input stream, as opposed to
the previous three streams: stdout, stderr, and exit code.
- The output of `describe` has been changed for external/byte streams.
- Temporary breaking change: `bytes starts-with` no longer works with
byte streams. This is to keep the PR smaller, and `bytes ends-with`
already does not work on byte streams.
- If a process core dumped, then instead of having a `Value::Error` in
the `exit_code` column of the output returned from `complete`, it now is
a `Value::Int` with the negation of the signal number.
# After Submitting
- Update docs and book as necessary
- Release notes (e.g., plugin protocol changes)
- Adapt/convert commands to work with byte streams (high priority is
`str length`, `bytes starts-with`, and maybe `bytes ends-with`).
- Refactor the `tee` code, Devyn has already done some work on this.
---------
Co-authored-by: Devyn Cairns <devyn.cairns@gmail.com>
2024-05-16 14:11:18 +00:00
|
|
|
PipelineData::ByteStream(ByteStream::stdin(redirect_stdin.span)?, None)
|
2023-01-20 18:44:49 +00:00
|
|
|
} else {
|
2024-03-28 16:27:12 +00:00
|
|
|
trace!("not redirecting stdin");
|
2023-01-20 18:44:49 +00:00
|
|
|
PipelineData::empty()
|
|
|
|
};
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("redirect stdin", start_time, use_color);
|
2022-10-21 15:20:21 +00:00
|
|
|
|
2024-03-28 16:27:12 +00:00
|
|
|
start_time = std::time::Instant::now();
|
2023-09-01 06:18:55 +00:00
|
|
|
// Set up the $nu constant before evaluating config files (need to have $nu available in them)
|
2024-05-09 23:29:27 +00:00
|
|
|
engine_state.generate_nu_constant();
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("create_nu_constant", start_time, use_color);
|
2023-09-01 06:18:55 +00:00
|
|
|
|
2024-04-23 11:37:50 +00:00
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
if let Some(plugins) = &parsed_nu_cli_args.plugins {
|
2024-04-27 17:08:12 +00:00
|
|
|
use nu_plugin_engine::{GetPlugin, PluginDeclaration};
|
2024-06-21 11:27:09 +00:00
|
|
|
use nu_protocol::{engine::StateWorkingSet, ErrSpan, PluginIdentity, RegisteredPlugin};
|
2024-04-23 11:37:50 +00:00
|
|
|
|
|
|
|
// Load any plugins specified with --plugins
|
|
|
|
start_time = std::time::Instant::now();
|
|
|
|
|
|
|
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
|
|
for plugin_filename in plugins {
|
|
|
|
// Make sure the plugin filenames are canonicalized
|
|
|
|
let filename = canonicalize_with(&plugin_filename.item, &init_cwd)
|
|
|
|
.err_span(plugin_filename.span)
|
|
|
|
.map_err(ShellError::from)?;
|
|
|
|
|
|
|
|
let identity = PluginIdentity::new(&filename, None)
|
|
|
|
.err_span(plugin_filename.span)
|
|
|
|
.map_err(ShellError::from)?;
|
|
|
|
|
|
|
|
// Create the plugin and add it to the working set
|
2024-04-27 17:08:12 +00:00
|
|
|
let plugin = nu_plugin_engine::add_plugin_to_working_set(&mut working_set, &identity)?;
|
2024-04-23 11:37:50 +00:00
|
|
|
|
2024-06-21 11:27:09 +00:00
|
|
|
// Spawn the plugin to get the metadata and signatures
|
|
|
|
let interface = plugin.clone().get_plugin(None)?;
|
|
|
|
|
|
|
|
// Set its metadata
|
|
|
|
plugin.set_metadata(Some(interface.get_metadata()?));
|
|
|
|
|
|
|
|
// Add the commands from the signature to the working set
|
|
|
|
for signature in interface.get_signature()? {
|
2024-04-23 11:37:50 +00:00
|
|
|
let decl = PluginDeclaration::new(plugin.clone(), signature);
|
|
|
|
working_set.add_decl(Box::new(decl));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
engine_state.merge_delta(working_set.render())?;
|
|
|
|
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("load plugins specified in --plugins", start_time, use_color)
|
2024-04-23 11:37:50 +00:00
|
|
|
}
|
|
|
|
|
2024-04-14 12:32:30 +00:00
|
|
|
start_time = std::time::Instant::now();
|
|
|
|
if parsed_nu_cli_args.lsp {
|
2024-06-27 23:56:56 +00:00
|
|
|
perf!("lsp starting", start_time, use_color);
|
2024-04-14 12:32:30 +00:00
|
|
|
|
|
|
|
if parsed_nu_cli_args.no_config_file.is_none() {
|
|
|
|
let mut stack = nu_protocol::engine::Stack::new();
|
|
|
|
config_files::setup_config(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
parsed_nu_cli_args.plugin_file,
|
|
|
|
parsed_nu_cli_args.config_file,
|
|
|
|
parsed_nu_cli_args.env_file,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-07-07 22:29:01 +00:00
|
|
|
LanguageServer::initialize_stdio_connection()?.serve_requests(engine_state)?
|
2024-04-14 12:32:30 +00:00
|
|
|
} else if let Some(commands) = parsed_nu_cli_args.commands.clone() {
|
2023-02-05 21:20:35 +00:00
|
|
|
run_commands(
|
2023-01-20 18:44:49 +00:00
|
|
|
&mut engine_state,
|
2023-02-05 21:20:35 +00:00
|
|
|
parsed_nu_cli_args,
|
2023-02-01 23:03:05 +00:00
|
|
|
use_color,
|
2023-02-05 21:20:35 +00:00
|
|
|
&commands,
|
2023-01-20 18:44:49 +00:00
|
|
|
input,
|
2023-03-24 15:41:33 +00:00
|
|
|
entire_start_time,
|
2024-05-09 23:29:27 +00:00
|
|
|
);
|
2023-03-09 02:59:33 +00:00
|
|
|
} else if !script_name.is_empty() {
|
2023-02-05 21:20:35 +00:00
|
|
|
run_file(
|
2023-01-20 18:44:49 +00:00
|
|
|
&mut engine_state,
|
2023-02-05 21:20:35 +00:00
|
|
|
parsed_nu_cli_args,
|
2023-02-01 23:03:05 +00:00
|
|
|
use_color,
|
2023-01-20 18:44:49 +00:00
|
|
|
script_name,
|
2023-02-05 21:20:35 +00:00
|
|
|
args_to_script,
|
2023-01-20 18:44:49 +00:00
|
|
|
input,
|
2024-05-09 23:29:27 +00:00
|
|
|
);
|
2023-01-20 18:44:49 +00:00
|
|
|
} else {
|
Replace `ExternalStream` with new `ByteStream` type (#12774)
# Description
This PR introduces a `ByteStream` type which is a `Read`-able stream of
bytes. Internally, it has an enum over three different byte stream
sources:
```rust
pub enum ByteStreamSource {
Read(Box<dyn Read + Send + 'static>),
File(File),
Child(ChildProcess),
}
```
This is in comparison to the current `RawStream` type, which is an
`Iterator<Item = Vec<u8>>` and has to allocate for each read chunk.
Currently, `PipelineData::ExternalStream` serves a weird dual role where
it is either external command output or a wrapper around `RawStream`.
`ByteStream` makes this distinction more clear (via `ByteStreamSource`)
and replaces `PipelineData::ExternalStream` in this PR:
```rust
pub enum PipelineData {
Empty,
Value(Value, Option<PipelineMetadata>),
ListStream(ListStream, Option<PipelineMetadata>),
ByteStream(ByteStream, Option<PipelineMetadata>),
}
```
The PR is relatively large, but a decent amount of it is just repetitive
changes.
This PR fixes #7017, fixes #10763, and fixes #12369.
This PR also improves performance when piping external commands. Nushell
should, in most cases, have competitive pipeline throughput compared to,
e.g., bash.
| Command | Before (MB/s) | After (MB/s) | Bash (MB/s) |
| -------------------------------------------------- | -------------:|
------------:| -----------:|
| `throughput \| rg 'x'` | 3059 | 3744 | 3739 |
| `throughput \| nu --testbin relay o> /dev/null` | 3508 | 8087 | 8136 |
# User-Facing Changes
- This is a breaking change for the plugin communication protocol,
because the `ExternalStreamInfo` was replaced with `ByteStreamInfo`.
Plugins now only have to deal with a single input stream, as opposed to
the previous three streams: stdout, stderr, and exit code.
- The output of `describe` has been changed for external/byte streams.
- Temporary breaking change: `bytes starts-with` no longer works with
byte streams. This is to keep the PR smaller, and `bytes ends-with`
already does not work on byte streams.
- If a process core dumped, then instead of having a `Value::Error` in
the `exit_code` column of the output returned from `complete`, it now is
a `Value::Int` with the negation of the signal number.
# After Submitting
- Update docs and book as necessary
- Release notes (e.g., plugin protocol changes)
- Adapt/convert commands to work with byte streams (high priority is
`str length`, `bytes starts-with`, and maybe `bytes ends-with`).
- Refactor the `tee` code, Devyn has already done some work on this.
---------
Co-authored-by: Devyn Cairns <devyn.cairns@gmail.com>
2024-05-16 14:11:18 +00:00
|
|
|
run_repl(&mut engine_state, parsed_nu_cli_args, entire_start_time)?
|
2022-01-26 14:42:39 +00:00
|
|
|
}
|
Replace `ExternalStream` with new `ByteStream` type (#12774)
# Description
This PR introduces a `ByteStream` type which is a `Read`-able stream of
bytes. Internally, it has an enum over three different byte stream
sources:
```rust
pub enum ByteStreamSource {
Read(Box<dyn Read + Send + 'static>),
File(File),
Child(ChildProcess),
}
```
This is in comparison to the current `RawStream` type, which is an
`Iterator<Item = Vec<u8>>` and has to allocate for each read chunk.
Currently, `PipelineData::ExternalStream` serves a weird dual role where
it is either external command output or a wrapper around `RawStream`.
`ByteStream` makes this distinction more clear (via `ByteStreamSource`)
and replaces `PipelineData::ExternalStream` in this PR:
```rust
pub enum PipelineData {
Empty,
Value(Value, Option<PipelineMetadata>),
ListStream(ListStream, Option<PipelineMetadata>),
ByteStream(ByteStream, Option<PipelineMetadata>),
}
```
The PR is relatively large, but a decent amount of it is just repetitive
changes.
This PR fixes #7017, fixes #10763, and fixes #12369.
This PR also improves performance when piping external commands. Nushell
should, in most cases, have competitive pipeline throughput compared to,
e.g., bash.
| Command | Before (MB/s) | After (MB/s) | Bash (MB/s) |
| -------------------------------------------------- | -------------:|
------------:| -----------:|
| `throughput \| rg 'x'` | 3059 | 3744 | 3739 |
| `throughput \| nu --testbin relay o> /dev/null` | 3508 | 8087 | 8136 |
# User-Facing Changes
- This is a breaking change for the plugin communication protocol,
because the `ExternalStreamInfo` was replaced with `ByteStreamInfo`.
Plugins now only have to deal with a single input stream, as opposed to
the previous three streams: stdout, stderr, and exit code.
- The output of `describe` has been changed for external/byte streams.
- Temporary breaking change: `bytes starts-with` no longer works with
byte streams. This is to keep the PR smaller, and `bytes ends-with`
already does not work on byte streams.
- If a process core dumped, then instead of having a `Value::Error` in
the `exit_code` column of the output returned from `complete`, it now is
a `Value::Int` with the negation of the signal number.
# After Submitting
- Update docs and book as necessary
- Release notes (e.g., plugin protocol changes)
- Adapt/convert commands to work with byte streams (high priority is
`str length`, `bytes starts-with`, and maybe `bytes ends-with`).
- Refactor the `tee` code, Devyn has already done some work on this.
---------
Co-authored-by: Devyn Cairns <devyn.cairns@gmail.com>
2024-05-16 14:11:18 +00:00
|
|
|
|
|
|
|
Ok(())
|
2022-01-26 14:42:39 +00:00
|
|
|
}
|