From ec290209db5f19a71339f5e20763a37d20a7b316 Mon Sep 17 00:00:00 2001 From: zabereer Date: Thu, 7 Feb 2019 18:47:30 +0000 Subject: [PATCH] add `$pipestatus` support --- CHANGELOG.md | 2 ++ src/env.cpp | 14 +++++++-- src/exec.cpp | 1 + src/proc.cpp | 18 ++++++++++++ src/proc.h | 6 ++++ tests/pipestatus.err | 12 ++++++++ tests/pipestatus.in | 67 ++++++++++++++++++++++++++++++++++++++++++++ tests/pipestatus.out | 52 ++++++++++++++++++++++++++++++++++ 8 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 tests/pipestatus.err create mode 100644 tests/pipestatus.in create mode 100644 tests/pipestatus.out diff --git a/CHANGELOG.md b/CHANGELOG.md index ff7e38d99..874c07b97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - The vcs-prompt functions have been renamed to names without double-underscore, so __fish_git_prompt is now fish_git_prompt, __fish_vcs_prompt is now fish_vcs_prompt, __fish_hg_prompt is now fish_hg_prompt and __fish_svn_prompt is now fish_svn_prompt. Shims at the old names have been added, and the variables have kept their old names (#5586). ## Notable fixes and improvements +- Add `$pipestatus` support + ### Syntax changes and new commands - None yet. diff --git a/src/env.cpp b/src/env.cpp index ff787bc47..fb1867c93 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -315,8 +315,8 @@ bool string_set_contains(const T &set, const wchar_t *val) { /// Check if a variable may not be set using the set command. static bool is_read_only(const wchar_t *val) { const string_set_t env_read_only = { - L"PWD", L"SHLVL", L"history", L"status", L"version", - L"FISH_VERSION", L"fish_pid", L"hostname", L"_", L"fish_private_mode"}; + L"PWD", L"SHLVL", L"history", L"pipestatus", L"status", L"version", + L"FISH_VERSION", L"fish_pid", L"hostname", L"_", L"fish_private_mode"}; return string_set_contains(env_read_only, val) || (in_private_mode() && wcscmp(L"fish_history", val) == 0); } @@ -329,7 +329,7 @@ static bool variable_should_auto_pathvar(const wcstring &name) { } /// Table of variables whose value is dynamically calculated, such as umask, status, etc. -static const string_set_t env_electric = {L"history", L"status", L"umask"}; +static const string_set_t env_electric = {L"history", L"pipestatus", L"status", L"umask"}; static bool is_electric(const wcstring &key) { return contains(env_electric, key); } @@ -1407,6 +1407,14 @@ maybe_t env_stack_t::get(const wcstring &key, env_mode_flags_t mode) wcstring_list_t result; if (history) history->get_history(result); return env_var_t(L"history", result); + } else if (key == L"pipestatus") { + const auto& js = proc_get_last_job_statuses(); + wcstring_list_t result; + result.reserve(js->size()); + for (auto&& i : *js) { + result.emplace_back(to_string(i)); + } + return env_var_t(L"pipestatus", result); } else if (key == L"status") { return env_var_t(L"status", to_string(proc_get_last_status())); } else if (key == L"umask") { diff --git a/src/exec.cpp b/src/exec.cpp index 431c4e042..b3da399a4 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -1008,6 +1008,7 @@ bool exec_job(parser_t &parser, shared_ptr j) { } j->continue_job(false); + proc_set_last_job_statuses(*j); return true; } diff --git a/src/proc.cpp b/src/proc.cpp index 94b5358a6..78addc711 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -56,6 +56,9 @@ /// Status of last process to exit. static int last_status = 0; +/// Statuses of last job's processes to exit. +static std::shared_ptr> last_job_statuses{new std::vector{0}}; + /// The signals that signify crashes to us. static const int crashsignals[] = {SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGSYS}; @@ -145,6 +148,21 @@ void proc_set_last_status(int s) { int proc_get_last_status() { return last_status; } +void proc_set_last_job_statuses(const job_t &last_job) { + ASSERT_IS_MAIN_THREAD(); + std::shared_ptr> ljs{new std::vector}; + ljs->reserve(last_job.processes.size()); + for (auto &&p : last_job.processes) { + ljs->emplace_back(p->pid ? proc_format_status(p->status) : p->status); + } + last_job_statuses = std::move(ljs); +} + +std::shared_ptr> proc_get_last_job_statuses() { + ASSERT_IS_MAIN_THREAD(); + return last_job_statuses; +} + // Basic thread safe job IDs. The vector consumed_job_ids has a true value wherever the job ID // corresponding to that slot is in use. The job ID corresponding to slot 0 is 1. static owning_lock> locked_consumed_job_ids; diff --git a/src/proc.h b/src/proc.h index 1620e4e5b..d743e9ce0 100644 --- a/src/proc.h +++ b/src/proc.h @@ -349,6 +349,12 @@ void proc_set_last_status(int s); /// Returns the status of the last process to exit. int proc_get_last_status(); +/// Sets the status of the last job's processes to exit from last_job. +void proc_set_last_job_statuses(const job_t &last_job); + +/// Returns the status of the last job's processes to exit. +std::shared_ptr> proc_get_last_job_statuses(); + /// Notify the user about stopped or terminated jobs. Delete terminated jobs from the job list. /// /// \param interactive whether interactive jobs should be reaped as well diff --git a/tests/pipestatus.err b/tests/pipestatus.err new file mode 100644 index 000000000..263a0a3d8 --- /dev/null +++ b/tests/pipestatus.err @@ -0,0 +1,12 @@ + +#################### +# pipestatus variable - builtins only + +#################### +# pipestatus variable - no builtins + +#################### +# pipestatus variable - mixed + +#################### +# pipestatus variable - non-pipe diff --git a/tests/pipestatus.in b/tests/pipestatus.in new file mode 100644 index 000000000..32a423f1b --- /dev/null +++ b/tests/pipestatus.in @@ -0,0 +1,67 @@ +logmsg "pipestatus variable - builtins only" + +false | false | false; echo $pipestatus +false | false | false; echo $status + +true | true | true; echo $pipestatus +true | true | true; echo $status + +false | true | false; echo $pipestatus +false | true | false; echo $status + +true | false | true; echo $pipestatus +true | false | true; echo $status + +logmsg "pipestatus variable - no builtins" + +command false | command false | command false; echo $pipestatus +command false | command false | command false; echo $status + +command true | command true | command true; echo $pipestatus +command true | command true | command true; echo $status + +command false | command true | command false; echo $pipestatus +command false | command true | command false; echo $status + +command true | command false | command true; echo $pipestatus +command true | command false | command true; echo $status + +logmsg "pipestatus variable - mixed" + +command false | command false | false; echo $pipestatus +command false | command false | false; echo $status + +command true | true | command true; echo $pipestatus +command true | true | command true; echo $status + +false | command true | command false; echo $pipestatus +false | command true | command false; echo $status + +true | false | command true; echo $pipestatus +true | false | command true; echo $status + +sh -c 'exit 5' | sh -c 'exit 2'; echo $pipestatus +sh -c 'exit 5' | sh -c 'exit 2'; echo $status + +sh -c 'exit 3' | false | sh -c 'exit 6'; echo $pipestatus +sh -c 'exit 3' | false | sh -c 'exit 6'; echo $status + +sh -c 'exit 9' | true | sh -c 'exit 3' | false; echo $pipestatus +sh -c 'exit 9' | true | sh -c 'exit 3' | false; echo $status + +logmsg "pipestatus variable - non-pipe" + +true; echo $pipestatus +true; echo $status + +false; echo $pipestatus +false; echo $status + +command true; echo $pipestatus +command true; echo $status + +command false; echo $pipestatus +command false; echo $status + +sh -c 'exit 4'; echo $pipestatus +sh -c 'exit 4'; echo $status diff --git a/tests/pipestatus.out b/tests/pipestatus.out new file mode 100644 index 000000000..3a717080b --- /dev/null +++ b/tests/pipestatus.out @@ -0,0 +1,52 @@ + +#################### +# pipestatus variable - builtins only +1 1 1 +1 +0 0 0 +0 +1 0 1 +1 +0 1 0 +0 + +#################### +# pipestatus variable - no builtins +1 1 1 +1 +0 0 0 +0 +1 0 1 +1 +0 1 0 +0 + +#################### +# pipestatus variable - mixed +1 1 1 +1 +0 0 0 +0 +1 0 1 +1 +0 1 0 +0 +5 2 +2 +3 1 6 +6 +9 0 3 1 +1 + +#################### +# pipestatus variable - non-pipe +0 +0 +1 +1 +0 +0 +1 +1 +4 +4