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

CLI Improvement #236

Closed

Conversation

dora-gt
Copy link
Member

@dora-gt dora-gt commented Aug 22, 2019

BREAKING CHANGES

  • Ethereum settlement engine now doesn't accept key argument. Use private_key instead.
  • Ethereum settlement engine now doesn't accept watch_incoming flag because it was a flag and default_value was true, which doesn't make sense and structopt considers it as an error. Instead I implemented without_incoming_watcher flag which disables incoming watcher.
    • structopt: help: message: default_value is meaningless for bool
  • node now doesn't accept ilp_address argument. Instead address argument or ILP_ADDRESS env var will be accepted.

@dora-gt dora-gt force-pushed the feature/cli-improvement/main branch 4 times, most recently from 6df6bab to c3641d3 Compare August 23, 2019 14:14
@dora-gt dora-gt changed the title [WIP] DO NOT MERGE: CLI Improvement CLI Improvement Aug 24, 2019
Copy link
Member

@emschwartz emschwartz left a comment

Choose a reason for hiding this comment

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

Right now the configuration of the node and SE works differently. I think we should make them more consistent.

I would suggest allowing the user to use all three methods: CLI arguments, a config file, and env vars. We could make it so you pass the path to the config file as a positional argument (interledger node ./path/to/config) so that it doesn't conflict with the CLI arguments.

The main benefit I see of allowing all options to be passed in as CLI args is that you could get the explanation of all of them by running --help

let mut config = config::Config::new();
config.merge(self.clone()).unwrap();
config
.merge(config::Environment::with_prefix("ILP"))
Copy link
Member

Choose a reason for hiding this comment

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

Should these be prefixed with ILP or something Ethereum-related?

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought ILP was required at least and adding ETH_SE or something would be too much (it becomes like ILP_ETH_SE_ETHEREUM_ENDPOINT), so... I think just ILP is enough🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

I just left it as ILP but if there are more suitable options, it would be easy to fix.

crates/interledger-settlement-engines/src/main.rs Outdated Show resolved Hide resolved
crates/interledger-settlement-engines/src/main.rs Outdated Show resolved Hide resolved
crates/interledger-settlement-engines/src/main.rs Outdated Show resolved Hide resolved
docs/operating-manuals/README.md Outdated Show resolved Hide resolved
docs/operating-manuals/eth-se-configurations.md Outdated Show resolved Hide resolved
docs/operating-manuals/eth-se-configurations.md Outdated Show resolved Hide resolved
docs/operating-manuals/node-configurations.md Outdated Show resolved Hide resolved
examples/eth_xrp_three_nodes/README.md Show resolved Hide resolved
@emschwartz emschwartz mentioned this pull request Aug 27, 2019
15 tasks
@dora-gt
Copy link
Member Author

dora-gt commented Aug 28, 2019

I fixed some of the issues but I still have to fix documents. I'm working on this.

The biggest changes are:

  • We no longer use structopt because recognition complexity problem wasn't solved. Now it looks simpler, I think.
  • Now every command accepts 1) command line arguments, 2) config file, 3) environment variables.

@dora-gt dora-gt force-pushed the feature/cli-improvement/main branch from 4557bf6 to b5d75d3 Compare August 28, 2019 13:55
@dora-gt
Copy link
Member Author

dora-gt commented Aug 28, 2019

I think I've addressed issues, if you have anything else, please tell me.

Copy link
Member

@emschwartz emschwartz left a comment

Choose a reason for hiding this comment

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

The direction looks good to me. The main points I'd make are that:

  • configuration files should be passed in with node config.yml instead of node --config config.yml
  • we should try to use the required flag on Clap so that the --help prints correctly

crates/interledger-settlement-engines/src/main.rs Outdated Show resolved Hide resolved
crates/interledger-settlement-engines/src/main.rs Outdated Show resolved Hide resolved
crates/interledger-settlement-engines/src/main.rs Outdated Show resolved Hide resolved
crates/interledger-settlement-engines/src/main.rs Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Show resolved Hide resolved
docs/operating-manuals/README.md Outdated Show resolved Hide resolved
@dora-gt
Copy link
Member Author

dora-gt commented Aug 28, 2019

configuration files should be passed in with node config.yml instead of node --config config.yml

Currently it accepts like this.

we should try to use the required flag on Clap so that the --help prints correctly

I've tried for several hours to hack this... but I couldn't come up with how to cleanly and entirely realize this... Anyway, let me try some more.

@dora-gt
Copy link
Member Author

dora-gt commented Aug 28, 2019

The problem is that if we set required flag, it is parsed BEFORE parameters from configuration files are given. So even if we set a configuration file, it warns that some required parameters are not set. To prevent this,

  • We might need to hack help
    • Negative, there are so many points that generate help strings, we cannot hack this entirely.
  • We might need to use env or get_matches_from
    • Negative, we might need to parse twice or need to parse on our own, which looks a bit ugly.
    • That said, if we have any solution, I think this approach is closer to it.

@dora-gt
Copy link
Member Author

dora-gt commented Aug 29, 2019

Refactored entirely.

image

image

image

@dora-gt dora-gt force-pushed the feature/cli-improvement/main branch 4 times, most recently from 945b207 to 942ec2a Compare August 29, 2019 13:07
Ok(path)
}

fn merge_args(config: &mut Config, matches: &ArgMatches) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

FYI, you get a lot of the logic being added here for free with Abscissa, which allows you to impl this trait to merge command-line options into the configuration:

https://docs.rs/abscissa_core/0.3.0/abscissa_core/config/trait.Override.html

let file_config = file_config.collect().unwrap();

// if the key is not defined in the given config already, set it to the config
// because the original values override the ones from the config file
Copy link
Member

Choose a reason for hiding this comment

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

Should the file take precedence over the CLI args or vice versa?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't see the clear difference because, in either case, we can override it by environment variables. hmmm do you have a preference?

crates/interledger/src/main.rs Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
("accounts", Some(node_accounts_matches)) => match node_accounts_matches.subcommand() {
("add", Some(node_accounts_add_matches)) => {
merge_args(&mut config, &node_accounts_add_matches);
runner.run(get_or_error(config.try_into::<NodeAccountsAddOpt>()));
Copy link
Member

Choose a reason for hiding this comment

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

I think this code would be clearer without the Runner thing. You could just copy that code into here, since it's not actually abstracting anything away

Copy link
Member Author

Choose a reason for hiding this comment

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

I wanted to make it readable. In the original code, there were many lines between subcommand matches, so it looked hard to read for me. I think this is clearer than inserting the code here because we can understand it intuitively as:

  • Here is to parse subcommands
  • There are many subcommands and some of these also have its own subcommands
  • Subcommands execute some logic using options

I think too long code is hard to understand. Isn't breaking the responsibility into some parts a good method? At least, I've believed so.

Copy link
Member Author

Choose a reason for hiding this comment

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

ummm but it actually doesn't abstract. Don't you also want to make it just a fn?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I think it would be simpler to just use a fn instead of the Runner trait

@@ -47,7 +47,7 @@ fn three_nodes() {

let node1 = InterledgerNode {
ilp_address: Address::from_str("example.one").unwrap(),
default_spsp_account: Some(0),
default_spsp_account: None,
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be set to one of the accounts?

Copy link
Member

@gakonst gakonst Aug 30, 2019

Choose a reason for hiding this comment

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

No need, all tests explicitly declare the accounts they're sending to - pushing a PR which requires this type to always be Username

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you.


- Environment variables
- Configuration files
- Command line arguments
Copy link
Member

Choose a reason for hiding this comment

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

It's slightly confusing that this list is in the opposite order as the one above. I would just write this list once and clarify there what the prioritization is

@gakonst
Copy link
Member

gakonst commented Aug 30, 2019

Feature request from: #108 (comment)

We want to add an option to load config files from stdin, allowing a user to do cat alice.yaml | interledger node. The use case for this is that we're going to have encrypted config files, and the user will run sops -d alice.yaml | interledger node.

@dora-gt
Copy link
Member Author

dora-gt commented Aug 30, 2019

Which format would you like to pass to STDIN?

I'm asking because unfortunately Config file module was private and I can't reuse the code. I have to write some glue code to parse it though it may be possible to copy as it is licensed under MIT/Apache 2.0.

@gakonst gakonst added this to To do in Hackathon Kit Aug 30, 2019
@dora-gt dora-gt force-pushed the feature/cli-improvement/main branch from 8c55ac4 to f55d3c4 Compare August 30, 2019 12:27
@gakonst gakonst moved this from To do to Under Review in Hackathon Kit Aug 30, 2019
@gakonst
Copy link
Member

gakonst commented Aug 30, 2019

Which format would you like to pass to STDIN?

So the config module understands which deserializer to use based on the config file extension (.yaml, .json, etc.). Us passing it from STDIN means that the config module cannot parse it. We could manually import serde_yaml and serde_json, and try all until one works.

Hacky idea (doesn't compile)

    let parsed = serde_yaml::from_str(&s);
    if parsed.is_err() {
        parsed = serde_json::from_str(&s);
    }

@dora-gt
Copy link
Member Author

dora-gt commented Aug 30, 2019

Since our CLI supports YAML, TOML, JSON, etc... thanks to Config module, it seems natural that we support these format for STDIN.

Ok, I'll try.

@gakonst
Copy link
Member

gakonst commented Sep 5, 2019

FYI: I've tested encrypting a YAML configuration file with sops and then running a node with sops -d alice.yaml | cargo run -- node and it's working well. It also similarly works well for the ethereum engine, sops -d engine.yaml | cargo run --package interledger-settlement-engines -- ethereum-ledger.

This looks good to me, do we need to add more things?

@dora-gt
Copy link
Member Author

dora-gt commented Sep 5, 2019

Thank you @gakonst , unfortunately I found a bug. If it is run on Docker, it tries to read from STDIN which causes an IO-block. It is because isatty is false on Docker even when it is not piped.

I'm trying to fix this.

@dora-gt
Copy link
Member Author

dora-gt commented Sep 5, 2019

^ was not a problem, just using -t option for Docker.

crates/interledger-settlement-engines/Cargo.toml Outdated Show resolved Hide resolved
crates/interledger-settlement-engines/Cargo.toml Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Show resolved Hide resolved
crates/interledger/src/main.rs Show resolved Hide resolved
("accounts", Some(node_accounts_matches)) => match node_accounts_matches.subcommand() {
("add", Some(node_accounts_add_matches)) => {
merge_args(&mut config, &node_accounts_add_matches);
runner.run(get_or_error(config.try_into::<NodeAccountsAddOpt>()));
Copy link
Member

Choose a reason for hiding this comment

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

Yeah I think it would be simpler to just use a fn instead of the Runner trait

crates/interledger/src/main.rs Show resolved Hide resolved
docs/operating-manuals/README.md Outdated Show resolved Hide resolved
@dora-gt
Copy link
Member Author

dora-gt commented Sep 6, 2019

Thank you Evan for taking time, I'll check and fix.

@dora-gt
Copy link
Member Author

dora-gt commented Sep 6, 2019

Fixed most points, I'm wondering just: #236 (comment)

Copy link
Member

@emschwartz emschwartz left a comment

Choose a reason for hiding this comment

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

Looking good. Let's just change the parameter names and then get this merged in

crates/interledger/src/main.rs Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
crates/interledger-settlement-engines/src/main.rs Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
crates/interledger/src/main.rs Outdated Show resolved Hide resolved
docs/operating-manuals/README.md Outdated Show resolved Hide resolved
examples/eth-settlement/README.md Show resolved Hide resolved
crates/interledger/src/main.rs Show resolved Hide resolved
crates/interledger/src/main.rs Show resolved Hide resolved
docs/operating-manuals/README.md Outdated Show resolved Hide resolved
Hackathon Kit automation moved this from Needs Review (PRs only) to Reviewed Sep 9, 2019
@dora-gt dora-gt force-pushed the feature/cli-improvement/main branch 2 times, most recently from 3e66dd8 to d129e09 Compare September 9, 2019 14:26
Every command accepts arguments, config file settings, env vars. `interledger` and
`interledger-settlement-engines` are almost consistent.

BREAKING CHANGE: Some arguments are now obsolete. On interledger package: server_secret ->
secret_seed, btp_server -> btp_server_url, http_server -> http_server_url, redis_connection ->
redis_url, http_address -> http_bind_address, settlement_address -> settlement_api_bind_address,
btp_address -> btp_bind_address, btp_uri -> btp_server_url, http_url -> http_server_url. On
interledger-settlement-engines package: http_address -> settlement_api_bind_address,
ethereum_endpoint -> ethereum_url, redis_uri -> redis_url.

Signed-off-by: Taiga Nakayama <dora@dora-gt.jp>
@emschwartz emschwartz mentioned this pull request Sep 9, 2019
@emschwartz
Copy link
Member

Merged in as #290

@emschwartz emschwartz closed this Sep 9, 2019
@dora-gt dora-gt deleted the feature/cli-improvement/main branch September 20, 2019 19:29
@emschwartz emschwartz moved this from Reviewed to Done in Hackathon Kit Oct 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Hackathon Kit
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants