mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 00:13:21 +01:00
allow nuscripts to be run again on windows with assoc/ftype (#14318)
# Description This PR tries to correct the problem of nushell scripts being made executable on Windows systems. In order to do this, these steps need to take place. 1. `assoc .nu=nuscript` 2. `ftype nuscript=C:\path\to\nu.exe '%1' %*` 3. modify the env var PATHEXT by appending `;.NU` at the end Once those steps are done and this PR is landed, one should be able to create a script such as this. ```nushell ❯ open im_exe.nu def main [arg] { print $"Hello ($arg)!" } ``` Then they should be able to do this to run the nushell script. ```nushell ❯ im_exe Nushell Hello Nushell! ``` Under-the-hood, nushell is shelling out to cmd.exe in order to run the nushell script. # User-Facing Changes closes #13020 # 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 toolkit.nu; toolkit test stdlib"` 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. -->
This commit is contained in:
parent
8c1ab7e0a3
commit
f7832c0e82
@ -51,7 +51,6 @@ impl Command for External {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cwd = engine_state.cwd(Some(stack))?;
|
let cwd = engine_state.cwd(Some(stack))?;
|
||||||
|
|
||||||
let name: Value = call.req(engine_state, stack, 0)?;
|
let name: Value = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
let name_str: Cow<str> = match &name {
|
let name_str: Cow<str> = match &name {
|
||||||
@ -68,10 +67,36 @@ impl Command for External {
|
|||||||
_ => Path::new(&*name_str).to_owned(),
|
_ => Path::new(&*name_str).to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// On Windows, the user could have run the cmd.exe built-in "assoc" command
|
||||||
|
// Example: "assoc .nu=nuscript" and then run the cmd.exe built-in "ftype" command
|
||||||
|
// Example: "ftype nuscript=C:\path\to\nu.exe '%1' %*" and then added the nushell
|
||||||
|
// script extension ".NU" to the PATHEXT environment variable. In this case, we use
|
||||||
|
// the which command, which will find the executable with or without the extension.
|
||||||
|
// If it "which" returns true, that means that we've found the nushell script and we
|
||||||
|
// believe the user wants to use the windows association to run the script. The only
|
||||||
|
// easy way to do this is to run cmd.exe with the script as an argument.
|
||||||
|
let potential_nuscript_in_windows = if cfg!(windows) {
|
||||||
|
// let's make sure it's a .nu scrtipt
|
||||||
|
if let Some(executable) = which(&expanded_name, "", cwd.as_ref()) {
|
||||||
|
let ext = executable
|
||||||
|
.extension()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_uppercase();
|
||||||
|
ext == "NU"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
// Find the absolute path to the executable. On Windows, set the
|
// Find the absolute path to the executable. On Windows, set the
|
||||||
// executable to "cmd.exe" if it's a CMD internal command. If the
|
// executable to "cmd.exe" if it's a CMD internal command. If the
|
||||||
// command is not found, display a helpful error message.
|
// command is not found, display a helpful error message.
|
||||||
let executable = if cfg!(windows) && is_cmd_internal_command(&name_str) {
|
let executable = if cfg!(windows)
|
||||||
|
&& (is_cmd_internal_command(&name_str) || potential_nuscript_in_windows)
|
||||||
|
{
|
||||||
PathBuf::from("cmd.exe")
|
PathBuf::from("cmd.exe")
|
||||||
} else {
|
} else {
|
||||||
// Determine the PATH to be used and then use `which` to find it - though this has no
|
// Determine the PATH to be used and then use `which` to find it - though this has no
|
||||||
@ -97,7 +122,7 @@ impl Command for External {
|
|||||||
// Configure args.
|
// Configure args.
|
||||||
let args = eval_arguments_from_call(engine_state, stack, call)?;
|
let args = eval_arguments_from_call(engine_state, stack, call)?;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
if is_cmd_internal_command(&name_str) {
|
if is_cmd_internal_command(&name_str) || potential_nuscript_in_windows {
|
||||||
use std::os::windows::process::CommandExt;
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
// The /D flag disables execution of AutoRun commands from registry.
|
// The /D flag disables execution of AutoRun commands from registry.
|
||||||
|
Loading…
Reference in New Issue
Block a user