Skip to content
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

Add entrypoint for iox2 cli #106

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

orecham
Copy link

@orecham orecham commented Jan 28, 2024

Notes for Reviewer

  1. Adds the top-level entry-point CLI for iox2
    $ ./target/debug/iox2 --help
    
  2. The top level CLI discovers available commands by looking for binaries with the prefix iox2- in the $PATH or in the cargo build directories
  3. Binaries that are discovered can be viewed using --list - the same as how cargo handles external binaries
    $ ./target/debug/iox2 --list
    
  4. The locations checked for binaries can be viewed using:
    $ ./target/debug/iox2 --paths
    
  5. Discovered binaries in PATH can be executed as if they were a defined sub command
    $ ./target/debug/iox2 services
    
  6. Discovered binaries in cargo build directories can only be executed with the flag --dev set
    $ ./target/debug/iox2 --dev services
    
    1. This distinction is to deal with the case where a binary with the same name is found in both the $PATH and in the build directories

Example Usage:

iceoryx2 git:(iox2-98-entrypoint-for-iox2-cli) ./target/debug/iox2 --help
Usage: iox2 [OPTIONS] [COMMAND]

Options:
  -l, --list     List all installed commands
  -p, --paths    Display paths that will be checked for installed commands
  -d, --dev      Specify to execute development versions of commands if they exist
  -h, --help     Print help
  -V, --version  Print version

Commands:
  ...         See all installed commands with --listiceoryx2 git:(iox2-98-entrypoint-for-iox2-cli) ./target/debug/iox2 --paths
Development Binary Paths:
  /Users/orecham/Code/iceoryx2/target/debug

Installed Binary Paths:
  /opt/homebrew/bin
  /opt/homebrew/sbin
  /usr/local/bin
  /usr/bin
  /bin
  /usr/sbin
  /sbin
  /Users/orecham/.cargo/biniceoryx2 git:(iox2-98-entrypoint-for-iox2-cli) ./target/debug/iox2 --list
Installed Commands:
  introspect (dev)
  processes (dev)
  pub (dev)
  rpc (dev)
  services (dev)
  sub (dev)iceoryx2 git:(iox2-98-entrypoint-for-iox2-cli) ./target/debug/iox2 --dev introspect
Not implemented. Stay tuned !

Pre-Review Checklist for the PR Author

  1. Add sensible notes for the reviewer
  2. PR title is short, expressive and meaningful
  3. Relevant issues are linked
  4. Every source code file has a copyright header with SPDX-License-Identifier: Apache-2.0 OR MIT
  5. Branch follows the naming format (iox2-123-introduce-posix-ipc-example)
  6. Commits messages are according to this guideline
  7. Tests follow the best practice for testing
  8. Changelog updated in the unreleased section including API breaking changes
  9. Assign PR to reviewer
  10. All checks have passed (except task-list-completed)

Checklist for the PR Reviewer

  • Commits are properly organized and messages are according to the guideline
  • Unit tests have been written for new behavior
  • Public API is documented
  • PR title describes the changes

Post-review Checklist for the PR Author

  1. All open points are addressed and tracked via issues

References

Use either 'Closes #123' or 'Relates to #123' to reference the corresponding issue.

Closes #ISSUE-NUMBER

@orecham
Copy link
Author

orecham commented Jan 28, 2024

@elBoberido @elfenpiff I am not quite finished, but could I get a preliminary review of the code to check if it is following rust conventions and idioms ?

Copy link
Member

@elBoberido elBoberido left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a full review. Was just a bit curious and skimmed through the files. Looking forward to see this in action.

iceoryx2-cli/iox2/src/commands.rs Outdated Show resolved Hide resolved
pub external_command: Vec<String>,
}

fn help_template() -> &'static str {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@orecham I thought clap is generating the whole help automatically. Was it not compatible with commands?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elfenpiff The problem is that clap cannot dynamically generate the help, which is required if the available commands are to be determined by the binaries that are present.

Copy link
Contributor

@elfenpiff elfenpiff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, and I already played around with it a bit. You have to add the copyright header to every .rs file - yeah I know, but this is what eclipse wants -

iceoryx2-cli/iox2/src/commands.rs Outdated Show resolved Hide resolved
Copy link
Member

@elBoberido elBoberido left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. I played a bit around and have a few wishes :)

  • cargo also lists some of the commands with --help
  • it seems iox2 services --help prints the iox2 help instead of the one from iox2-services

iceoryx2-cli/iox2/src/commands.rs Outdated Show resolved Hide resolved
@orecham orecham force-pushed the iox2-98-entrypoint-for-iox2-cli branch from 7e72ce3 to 38ebaf2 Compare May 22, 2024 19:51
@orecham
Copy link
Author

orecham commented May 22, 2024

@elBoberido

* cargo also lists some of the commands with `--help`

This would require commands to be included in the iox2 binary i.e. not be external. If implemented, these commands would be listed under Commands: before ... See all installed commands with --list

* it seems `iox2 services --help` prints the `iox2` help instead of the one from `iox2-services`

This is probably because the services binary does not include a CLI that parses the arguments. When these commands are implemented to parse the CLI, it should print the help of the specific command.

@orecham orecham force-pushed the iox2-98-entrypoint-for-iox2-cli branch 3 times, most recently from ef76b75 to 1ac970b Compare May 22, 2024 23:39
@orecham orecham force-pushed the iox2-98-entrypoint-for-iox2-cli branch from 1ac970b to 5e04e86 Compare May 22, 2024 23:56
iceoryx2-cli/iox2/Cargo.toml Outdated Show resolved Hide resolved
iceoryx2-cli/iox2/Cargo.toml Outdated Show resolved Hide resolved
iceoryx2-cli/iox2/src/commands.rs Outdated Show resolved Hide resolved
iceoryx2-cli/iox2/src/commands.rs Outdated Show resolved Hide resolved
@orecham orecham force-pushed the iox2-98-entrypoint-for-iox2-cli branch from 5e04e86 to f21d72b Compare May 23, 2024 21:15
Copy link

codecov bot commented May 23, 2024

Codecov Report

Attention: Patch coverage is 0% with 225 lines in your changes are missing coverage. Please review.

Project coverage is 79.16%. Comparing base (07ee2f0) to head (e158d01).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #106      +/-   ##
==========================================
- Coverage   80.02%   79.16%   -0.87%     
==========================================
  Files         183      192       +9     
  Lines       20423    20648     +225     
==========================================
+ Hits        16343    16345       +2     
- Misses       4080     4303     +223     
Files Coverage Δ
iceoryx2-cli/iox2-introspect/src/main.rs 0.00% <0.00%> (ø)
iceoryx2-cli/iox2-processes/src/main.rs 0.00% <0.00%> (ø)
iceoryx2-cli/iox2-pub/src/main.rs 0.00% <0.00%> (ø)
iceoryx2-cli/iox2-rpc/src/main.rs 0.00% <0.00%> (ø)
iceoryx2-cli/iox2-services/src/main.rs 0.00% <0.00%> (ø)
iceoryx2-cli/iox2-sub/src/main.rs 0.00% <0.00%> (ø)
iceoryx2-cli/iox2/src/cli.rs 0.00% <0.00%> (ø)
iceoryx2-cli/iox2/src/main.rs 0.00% <0.00%> (ø)
iceoryx2-cli/iox2/src/commands.rs 0.00% <0.00%> (ø)

... and 3 files with indirect coverage changes

@orecham
Copy link
Author

orecham commented May 23, 2024

@elBoberido @elfenpiff Getting a puzzling error in the mac os CI job:

error: package `clap_builder v4.5.2` cannot be built because it requires rustc 1.74 or newer, while the currently active rustc version is 1.73.0
Either upgrade to rustc 1.74 or newer, or use
cargo update -p clap_builder@4.5.2 --precise ver
where `ver` is the latest version of `clap_builder` supporting rustc 1.73.0
Error: Process completed with exit code 101.

It's puzzling because the version I specify in the Cargo.toml is not v4.5.2:

clap = { version = "4.4.18", features = ["derive"] }

Have you seen this before ?

@elBoberido
Copy link
Member

@elBoberido @elfenpiff Getting a puzzling error in the mac os CI job:

error: package `clap_builder v4.5.2` cannot be built because it requires rustc 1.74 or newer, while the currently active rustc version is 1.73.0
// snip
Have you seen this before ?

It's a dependency from human-panic. You can either try an older version of human-panic or you can add default-features = false to the human-panic dependency. This will turn off the colors but also removes the dependency on clap. You could also try to convince the maintainer of anstyle and anstream to add a flag to not use clap and then ask the maintainer of human-panic to use that flag. Then continue until none of the dependencies is using clap by default 😅

Btw, this is the relevant output of cargo tree

├── clap v4.5.4
│   ├── clap_builder v4.5.2
│   │   ├── anstream v0.6.14
│   │   │   ├── anstyle v1.0.7
│   │   │   ├── anstyle-parse v0.2.4
│   │   │   │   └── utf8parse v0.2.1
│   │   │   ├── anstyle-query v1.0.3
│   │   │   ├── colorchoice v1.0.1
│   │   │   ├── is_terminal_polyfill v1.70.0
│   │   │   └── utf8parse v0.2.1
│   │   ├── anstyle v1.0.7
│   │   ├── clap_lex v0.7.0
│   │   └── strsim v0.11.1
│   └── clap_derive v4.5.4 (proc-macro)
│       ├── heck v0.5.0
│       ├── proc-macro2 v1.0.76
│       │   └── unicode-ident v1.0.12
│       ├── quote v1.0.35
│       │   └── proc-macro2 v1.0.76 (*)
│       └── syn v2.0.48
│           ├── proc-macro2 v1.0.76 (*)
│           ├── quote v1.0.35 (*)
│           └── unicode-ident v1.0.12

@orecham
Copy link
Author

orecham commented May 24, 2024

It's a dependency from human-panic. You can either try an older version of human-panic or you can add default-features = false to the human-panic dependency. This will turn off the colors but also removes the dependency on clap. You could also try to convince the maintainer of anstyle and anstream to add a flag to not use clap and then ask the maintainer of human-panic to use that flag. Then continue until none of the dependencies is using clap by default 😅

@elBoberido Is it possible to increase the version of rustc in the CI Image ?

@orecham orecham force-pushed the iox2-98-entrypoint-for-iox2-cli branch from 9bfebdd to e158d01 Compare May 24, 2024 21:43
@elfenpiff
Copy link
Contributor

It's a dependency from human-panic. You can either try an older version of human-panic or you can add default-features = false to the human-panic dependency. This will turn off the colors but also removes the dependency on clap. You could also try to convince the maintainer of anstyle and anstream to add a flag to not use clap and then ask the maintainer of human-panic to use that flag. Then continue until none of the dependencies is using clap by default 😅

@elBoberido Is it possible to increase the version of rustc in the CI Image ?

Yes, this is not a problem! I could create a separate PR and increase it to rust version 1.74 - but we can also go higher.

@orecham
Copy link
Author

orecham commented May 25, 2024

It's a dependency from human-panic. You can either try an older version of human-panic or you can add default-features = false to the human-panic dependency. This will turn off the colors but also removes the dependency on clap. You could also try to convince the maintainer of anstyle and anstream to add a flag to not use clap and then ask the maintainer of human-panic to use that flag. Then continue until none of the dependencies is using clap by default 😅

@elBoberido Is it possible to increase the version of rustc in the CI Image ?

Yes, this is not a problem! I could create a separate PR and increase it to rust version 1.74 - but we can also go higher.

@elfenpiff Any version 1.74 or above will make things easier for this PR. You can choose what you like. Or just let me know how to do it and I can do the PR.

Note that ubuntu_22_04_aarch64_min_version_debug has the same problem.

@elfenpiff
Copy link
Contributor

@orecham I updated all dependencies to the newest version and upgraded the minimum rust version to 1.75. PR is merged: #222

So you could continue from here.

@elBoberido
Copy link
Member

@elBoberido

* cargo also lists some of the commands with `--help`

This would require commands to be included in the iox2 binary i.e. not be external. If implemented, these commands would be listed under Commands: before ... See all installed commands with --list

Not necessarily. The --help call could do a --list behind the scene and either list all commands or do it similar to cargo --list and only show the most important ones like

Commands:
    introspec
    processes
    services
    ...         See all commands with --list

Not for this PR but maybe something for a follow up if you like the idea.

* it seems `iox2 services --help` prints the `iox2` help instead of the one from `iox2-services`

This is probably because the services binary does not include a CLI that parses the arguments. When these commands are implemented to parse the CLI, it should print the help of the specific command.

If I call iox2-services --help it prints Not implemented. Stay tuned !. I guess the argument is not forwarded to the command.

Comment on lines +132 to +142
if is_valid_command_binary(&path) {
path.file_name()
.and_then(|n| n.to_str())
.map(|command_name| CommandInfo {
name: command_name.to_string(),
path: path.clone(),
is_development: false,
})
} else {
None
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplication leads to errors. The one from the development binaries strips the iox2- prefix but this does not. Can the two implementations be combined?

Comment on lines +88 to +93
let development_commands = find_development_command_binaries();
let installed_commands = find_installed_command_binaries();

let mut all_commands = development_commands;
all_commands.extend(installed_commands.iter().cloned());
all_commands
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question is what to prioritize, the development versions or the installed versions

Personally, I would prefer this

Installed Commands:
  introspect 
  introspect (dev) 
  processes (dev) 
  pub 
  pub (dev) 
  rpc (dev) 
  services (dev) 
  sub (dev)

over this

  introspect (dev) 
  introspect 
  processes (dev) 
  pub (dev) 
  pub 
  rpc (dev) 
  services (dev) 
  sub (dev)

But not so much to have a lengthy discussion about this 😅

The main reason would be to use the installed foo with iox2 foo. Currently it does not work when foo and foo (dev) is found. When foo (dev) is listed as second entry, one could assume that iox2 foo would be called and iox2 --dev foo would call foo (dev). What do you think?

pub fn list() {
println!("{}", "Installed Commands:".bright_green().bold());
let mut installed_commands = find();
installed_commands.sort_by_key(|command| command.name.clone());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
installed_commands.sort_by_key(|command| command.name.clone());
installed_commands.sort_by_cached_key(|command| command.name.clone());

This is probably be faster

" {} {}",
command.name.bold(),
if command.is_development {
"(dev) ".italic()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"(dev) ".italic()
"(dev)".italic()

// SPDX-License-Identifier: Apache-2.0 OR MIT

fn main() {
println!("Not implemented. Stay tuned !");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
println!("Not implemented. Stay tuned !");
println!("Not implemented. Stay tuned!");

Same in the other files

struct CommandInfo {
name: String,
path: PathBuf,
is_development: bool,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Food for thought. What do you think of using something like this instead of is_development

#[derive(Clone, Debug, PartialEq)]
enum BinaryType {
    Installed,
    Development,
}

impl BinaryType {
    fn suffix(&self) -> &'static str {
        match self {
            Self::Installed => "",
            Self::Development => "(dev)",
        }
    }
}

Depending on how much code you want to share for finding the iox2 commands, this might make it more readable than passing true and false.

path.file_name()
.and_then(|n| n.to_str())
.map(|command_name| {
let stripped = command_name.strip_prefix("iox2-").unwrap_or(command_name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let stripped = command_name.strip_prefix("iox2-").unwrap_or(command_name);
let stripped = command_name.strip_prefix("iox2-").expect("The filter already ensured to be an iox2 command binary");

Comment on lines +106 to +120
.map(|entry| entry.path())
.filter(|path_buf: &PathBuf| is_valid_command_binary(path_buf.as_path()))
.filter_map(|path| {
path.file_name()
.and_then(|n| n.to_str())
.map(|command_name| {
let stripped = command_name.strip_prefix("iox2-").unwrap_or(command_name);
CommandInfo {
name: stripped.to_string(),
path: path.clone(),
is_development: true,
}
})
})
.collect()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case you want to reduce the indentation even more, then this would be an option

        .map(|entry| entry.path())
        .filter(|path_buf: &PathBuf| is_valid_command_binary(path_buf.as_path()))
        .filter_map(|path| {
            path.as_path()
                .file_name()
                .and_then(|n| n.to_os_string().into_string().ok())
                .map(|name| (path, name.strip_prefix("iox2-").expect("").to_string()))
        })
        .map(|(path, name)| CommandInfo {
            name,
            path,
            is_development: true,
        })
        .collect()

Comment on lines +147 to +156
fn is_valid_command_binary(path: &Path) -> bool {
path.is_file()
&& path
.file_stem()
.unwrap()
.to_str()
.unwrap()
.starts_with("iox2-")
&& path.extension().is_none() // Exclude files with extensions (e.g. '.d')
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use either expect instead of unwrap or rewrite this to return a Option<PathBuf> and then you can just use ? or .ok()? in case the function returns a Result.

Returning an Option<PathBuf> might even simplify the filter_map above.

Comment on lines +40 to +44
if cli.list {
commands::list();
} else if cli.paths {
commands::paths();
} else if !cli.external_command.is_empty() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can there be a situation where none of this three branches will be taken? If yes, could you add an else branch and print something useful for the user?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

iceoryx2-cal::hash Introduce uuid type and make it convertable to FileName
4 participants