-
Notifications
You must be signed in to change notification settings - Fork 29
skill: add basic implementation of skill
#364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Although the main functionality has been completed, some edge cases and potential improvements still need to be considered, such as command usage clarification, test coverage, more elegant implementation and performance optimization. |
sload
skill
src/uu/skill/src/command.rs
Outdated
pub const SIGNALS: &[&str] = &[ | ||
"HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "BUS", "FPE", "KILL", "USR1", "SEGV", "USR2", | ||
"PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "URG", | ||
"XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "POLL", "PWR", "SYS", | ||
]; | ||
const DEFAULT_SIGNAL: &str = "TERM"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the signals defined in uucore: https://github.com/uutils/coreutils/blob/main/src/uucore/src/lib/features/signals.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use text (code blocks) instead of picture, using text will make it easier to be searched :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this post can help you to understand the EXIT
"signal", which can be considered as a trap to capture something. it's an extension of shell, bash, zsh, fish, etc..
https://unix.stackexchange.com/questions/385030/are-exit-debug-return-and-err-signals
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use text (code blocks) instead of picture, using text will make it easier to be searched :)
Sorry, my mistake. I’ll stick to using text in our future conversations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this post can help you to understand the
EXIT
"signal", which can be considered as a trap to capture something. it's an extension of shell, bash, zsh, fish, etc..https://unix.stackexchange.com/questions/385030/are-exit-debug-return-and-err-signals
After reviewing these articles, it appears that signals like EXIT
are specific to the shell and not applicable to all processes. Therefore, in the context of the skill command, I have excluded them. Does this approach seem correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it can be processed in this way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, my mistake. I’ll stick to using text in our future
Please don't be nervous, it's not a mistake :)
src/uu/skill/src/command.rs
Outdated
} | ||
} | ||
|
||
pub fn parse_command(args: &mut impl uucore::Args) -> Vec<OsString> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you please explain what this function does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I can explain, i know it looks a little wired :)
Issue Explanation:
The core problem lies in the signal format expected by skill, which follows the structure:
skill [signal] [options] <expression
However, the signal is passed in the form -HUP
instead of -s HUP
, preventing clap from automatically parsing it from the arguments.
Solution Approach:
To handle this correctly:
- Signal as an Indexed Argument:
We must define signal as an indexed argument in clap so it can be properly parsed. - Expression as an Indexed Argument
Since theexpression
is also passed in a similar way(not an option), it must also be treated as an indexed argument.
But after doing things above, another problem comes in: Clap's Restriction on Optional Arguments:
clap enforces a rule where if a later indexed argument is required, earlier ones cannot be optional.
This means signal
must be marked as required to comply with clap's parsing logic, which is conflict with skill's Default Behavior:
The standard skill implementation (procps-ng 3.3.17) allows signal
to be optional with a default value.
To reconcile this with clap's requirements, we preprocess the arguments before passing them to clap, ensuring signal is always provided (even if defaulted) to satisfy parsing constraints.
Summary of the Issue
The root cause of these challenges stems from the fact that skill's argument format (as defined in procps-ng 3.3.17) cannot be directly modeled using clap's parsing rules.
However, this doesn’t imply any limitation in clap—rather, skill’s unconventional syntax (e.g., -HUP instead of -s HUP) deviates from typical CLI conventions, making parsing more complex.
Whatever, I will add more comments to the code to make it more reasonable :)
Also, if there are other more elegant way to process that, please tell me, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cakebaker can you give us some help? seems like this is something clap can't handle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maplestarplayl and if it is possible, could you write some document(comment) and unit tests to make sure it doesn't regressing in future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maplestarplayl and if it is possible, could you write some document(comment) and unit tests to make sure it doesn't regressing in future?
Have added corresponding tests in the command.rs
file
Great work, and please don't forget run |
Refactor the util functions with pgrep's process.rs, and add corresponding tests for command and user usage in |
Can you please run |
} | ||
#[cfg(target_os = "linux")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
#[cfg(target_os = "linux")] | |
} | |
#[cfg(target_os = "linux")] |
} | ||
#[cfg(target_os = "linux")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
#[cfg(target_os = "linux")] | |
} | |
#[cfg(target_os = "linux")] |
} | ||
#[cfg(target_os = "linux")] | ||
#[test] | ||
fn test_mutiple_signal() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A typo:
fn test_mutiple_signal() { | |
fn test_multiple_signal() { |
} | ||
#[cfg(target_os = "linux")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
#[cfg(target_os = "linux")] | |
} | |
#[cfg(target_os = "linux")] |
} | ||
#[cfg(target_os = "linux")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
#[cfg(target_os = "linux")] | |
} | |
#[cfg(target_os = "linux")] |
#[test] | ||
fn test_list_option() { | ||
new_ucmd!() | ||
.arg("-l") | ||
.succeeds() | ||
.no_stderr() | ||
.stdout_contains("HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS"); | ||
} | ||
|
||
#[cfg(target_os = "linux")] | ||
#[test] | ||
fn test_list_option_long() { | ||
new_ucmd!() | ||
.arg("--list") | ||
.succeeds() | ||
.no_stderr() | ||
.stdout_contains("HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here it might make sense to combine the functions into one and simply loop through the args, something like:
for arg in ["-l", "--list"] {
new_ucmd!()
.arg(arg)
...
}
#[cfg(target_os = "linux")] | ||
#[test] | ||
fn test_table_option() { | ||
new_ucmd!() | ||
.arg("-L") | ||
.succeeds() | ||
.no_stderr() | ||
.stdout_contains("1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS") | ||
.stdout_contains("8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM") | ||
.stdout_contains("15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN") | ||
.stdout_contains("22 TTOU 23 URG 24 XCPU 25 XFSZ 26 VTALRM 27 PROF 28 WINCH") | ||
.stdout_contains("29 POLL 30 PWR 31 SYS"); | ||
} | ||
|
||
#[cfg(target_os = "linux")] | ||
#[test] | ||
fn test_table_option_long() { | ||
new_ucmd!() | ||
.arg("--table") | ||
.succeeds() | ||
.no_stderr() | ||
.stdout_contains("1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS") | ||
.stdout_contains("8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM") | ||
.stdout_contains("15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN") | ||
.stdout_contains("22 TTOU 23 URG 24 XCPU 25 XFSZ 26 VTALRM 27 PROF 28 WINCH") | ||
.stdout_contains("29 POLL 30 PWR 31 SYS"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same with these two functions.
|
||
#[cfg(target_os = "linux")] | ||
#[test] | ||
fn test_mutiple_options() { | ||
new_ucmd!() | ||
.arg("-nv") // no action + verbose | ||
.arg("1") | ||
.succeeds() | ||
.stdout_contains("Would send signal TERM to process 1"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is identical to test_default_signal
, so it can be removed.
#[cfg(target_os = "linux")] | |
#[test] | |
fn test_mutiple_options() { | |
new_ucmd!() | |
.arg("-nv") // no action + verbose | |
.arg("1") | |
.succeeds() | |
.stdout_contains("Would send signal TERM to process 1"); | |
} |
use uu_pgrep::process::{walk_process, ProcessInformation}; | ||
#[cfg(target_os = "linux")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use uu_pgrep::process::{walk_process, ProcessInformation}; | |
#[cfg(target_os = "linux")] | |
use uu_pgrep::process::{walk_process, ProcessInformation}; | |
#[cfg(target_os = "linux")] |
|
||
#[cfg(target_os = "linux")] | ||
pub fn get_process_owner(process: &mut ProcessInformation) -> Option<String> { | ||
// let status_path = format!("/proc/{}/status", pid); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would either remove this line or add a TODO with a reason why it's commented out.
|
||
// Mainly used to parse the signal to make sure it is valid | ||
// and insert the default signal if it's not present | ||
pub fn parse_command(args: &mut impl uucore::Args) -> Vec<String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this function can fail, I would return a Result
.
eprintln!("Invalid signal: {}", &signal); | ||
std::process::exit(2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my previous comment about returning a Result
. We usually use something like:
return Err(USimpleError::new(2, format!("Invalid signal: {}", &signal)));
eprintln!("Too many signals"); | ||
std::process::exit(2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my previous comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall good job :)
This pr add the
skill
command, but only works on Linux