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 CLI template #4

Merged
merged 23 commits into from Oct 3, 2019
Merged

Add CLI template #4

merged 23 commits into from Oct 3, 2019

Conversation

@meowsbits
Copy link
Contributor

meowsbits commented Oct 1, 2019

This is a little rough yet, but working, so wanted to get it up for review before and during and informed by polish.

This creates a CLI template which generates a working CLI program that interfaces with an arbitrary HTTP endpoint complying with the given OpenRPC spec.

Shout out to @shanejonas for the idea.

# Generate the code for a CLI client.
$ go run main.go -cli -cli.name=ethrpc -spec parse/testdata/eth_openrpc.json

# Build the binary.
$ go build -o ethrpc main/cli.go

# Move it to anywhere in your path.
$ mv ethrpc ~/bin/

# Learn about installing auto-completions.
$ ethrpc completion --help
To load completion run

. <(ethrpc completion)

To configure your bash shell to load completions for each session add to your bashrc

# ~/.bashrc or ~/.profile
. <(ethrpc completion)

Usage:
  ethrpc completion [flags]

Flags:
  -h, --help   help for completion

Global Flags:
      --config string      config file (default is $HOME/.ethrpc.yaml)
      --http-addr string   Address for JSON-RPC HTTP calls (default "http://localhost:8545")

# Autocomplete FTW.
$ . <(ethrpc completion)

# Do autocomplete <tab> <tab>
$ ethrpc 
completion                                  eth_getBlockByHash                          eth_getProof                                eth_getTransactionCount                     eth_mining                                  eth_submitWork
eth_blockNumber                             eth_getBlockByNumber                        eth_getRawTransactionByBlockHashAndIndex    eth_getTransactionReceipt                   eth_newBlockFilter                          eth_syncing
eth_call                                    eth_getBlockTransactionCountByHash          eth_getRawTransactionByBlockNumberAndIndex  eth_getUncleByBlockHashAndIndex             eth_newFilter                               eth_uninstallFilter
eth_chainId                                 eth_getBlockTransactionCountByNumber        eth_getRawTransactionByHash                 eth_getUncleByBlockNumberAndIndex           eth_newPendingTransactionFilter             net_listening
eth_coinbase                                eth_getCode                                 eth_getStorageAt                            eth_getUncleCountByBlockHash                eth_pendingTransactions                     net_peerCount
eth_estimateGas                             eth_getFilterChanges                        eth_getTransactionByBlockHashAndIndex       eth_getUncleCountByBlockNumber              eth_protocolVersion                         net_version
eth_gasPrice                                eth_getFilterLogs                           eth_getTransactionByBlockNumberAndIndex     eth_getWork                                 eth_sendRawTransaction                      web3_clientVersion
eth_getBalance                              eth_getLogs                                 eth_getTransactionByHash                    eth_hashrate                                eth_submitHashrate                          web3_sha3

# Get help.
$ ethrpc eth_mining --help


Params: <NONE>
Returns:

    description: Whether of not the client is mining,
    type: boolean

Usage:
  ethrpc eth_mining [flags]

Flags:
  -h, --help   help for eth_mining

Global Flags:
      --config string      config file (default is $HOME/.ethrpc.yaml)
      --http-addr string   Address for JSON-RPC HTTP calls (default "http://localhost:8545")

# Run.
$ ethrpc --http-addr http://localhost:8545 eth_mining
{"jsonrpc":"2.0","id":15860,"result":false}

$ ethrpc eth_getBlockByNumber "latest" true
{"jsonrpc":"2.0","id":7192,"result":{"difficulty":"0x400000000","extraData":"0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa","gasLimit":"0x1388","gasUsed":"0x0","hash":"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000042","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x21c","stateRoot":"0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544","timestamp":"0x0","totalDifficulty":"0x400000000","transactions":[],"transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","uncles":[]}}

$ echo "latest" true | xargs ethrpc eth_getBlockByNumber
{"jsonrpc":"2.0","id":6775,"result":{"difficulty":"0x400000000","extraData":"0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa","gasLimit":"0x1388","gasUsed":"0x0","hash":"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000042","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x21c","stateRoot":"0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544","timestamp":"0x0","totalDifficulty":"0x400000000","transactions":[],"transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","uncles":[]}}


# Plays well with a CLI JSON-parsing program, like 'jj' - https://github.com/tidwall/jj
$ echo "latest" true | xargs ethrpc eth_getBlockByNumber | jj result.nonce
0x0000000000000042

# Has meaningful exit codes
# Successful HTTP, erroring JSONRPC response.
$ ethrpc eth_getBlockByNumber 
{"jsonrpc":"2.0","id":7518,"error":{"code":-32602,"message":"missing value for required argument 0"}}
$ echo $?
1

# Erroring HTTP call.
$ ethrpc --http-addr=http://dne.guru eth_getBlockByNumber > /dev/null
$ echo $?
2

# And of course 0 for success.
meowsbits added 21 commits Sep 30, 2019
The eth implementation of openrpc schema is not specific to this
project. This file named as such (lately openrpc.json) is confusing,
so I moved it to a testdata dir b/c that's all it's used for anyways.
Adds a comment near top describing basic functionality.
Carry only 'description' field over is not that
generalized. Merging structs should be a little
more agnostic.
Copy link
Owner

gregdhill left a comment

This is great work! Thanks for the contribution :)

I've added a few comments, please let me know what you think.

/*
Copyright © 2019 NAME HERE <EMAIL ADDRESS>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
Comment on lines 3 to 17

This comment has been minimized.

Copy link
@gregdhill

gregdhill Oct 3, 2019

Owner

I don't think we should add licensing, but I would be interested to hear your thoughts?

This comment has been minimized.

Copy link
@meowsbits

meowsbits Oct 3, 2019

Author Contributor

Agreed; I just had that in there as leftover from cobra. Off the top of my head not sure if cobra's Apache 2 is "contagious" or not, but would be worth brushing up on.

"errors"
"fmt"
"log"
"github.com/spf13/cobra"

This comment has been minimized.

Copy link
@gregdhill

gregdhill Oct 3, 2019

Owner

Perhaps not for this PR, but if we're going to use cobra for the generated cli we should use it ourselves.

This comment has been minimized.

Copy link
@meowsbits

meowsbits Oct 3, 2019

Author Contributor

Yea. I'd be happy to go with it if you are (but maybe next PR). Only question left is to understand license implications, as bespoke above.


t.Run("Should be same at least once, in a while", func(t *testing.T) {

This comment has been minimized.

Copy link
@gregdhill

gregdhill Oct 3, 2019

Owner

Hmm, this validates what I've found in the past. There's definitely some non-determinism in the parser that needs to be fixed at some point.

This comment has been minimized.

Copy link
@meowsbits

meowsbits Oct 3, 2019

Author Contributor

👍 👓

return ProgramName
}

func sliceFn(sl []interface{}, i int) interface{} {

This comment has been minimized.

Copy link
@gregdhill

gregdhill Oct 3, 2019

Owner

Unused, I think because you've moved this to the util pkg?

/*
Copyright © 2019 NAME HERE <EMAIL ADDRESS>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
Comment on lines 4 to 18

This comment has been minimized.

Copy link
@gregdhill

gregdhill Oct 3, 2019

Owner

Not sure about this, see comment below.

This comment has been minimized.

Copy link
@meowsbits

meowsbits Oct 3, 2019

Author Contributor

See comment above. Have removed.

meowsbits added 2 commits Oct 3, 2019
This has been moved to utils/.

Just for fun, not sure where this went:
golang/go#30153
@gregdhill gregdhill merged commit b461c26 into gregdhill:master Oct 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

2 participants
You can’t perform that action at this time.