2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pythonとgolangでcliツールを作ってみる

Last updated at Posted at 2024-12-09

この記事はデジタルキューブグループ エンジニアチームアドベントカレンダー2024 12月10日の記事です。

取り組みの経緯

今後プラットフォームエンジニアリングといった動きを強めたいと思った場合に、社内向けツールなどを作る機会も増えるかもしれない

普段システムの開発や保守を行わない人たちに対してはwebアプリとして提供したり、また、インフラチームなどに対してはcliから使えるものの方が都合のよい場合もある

普段はpythonでのバックエンド開発が多いため、pythonでのcliツール作成を試してみる
また、linux環境などでも使いやすいバイナリとして生成できるgolangでのcliツール作成も試す

goを触るのが初めてなので、cliツールのサンプル作成を通してgoも完全に理解する

自分のバックグラウンド

開発では以下の言語に触れてきた経験が多い

  • node(typescript)
  • python

なので、自分の頭の整理がてら、この辺の言語で使われてる仕組みと比較しながら理解していくメモ書きがあると思う

環境

  • python 3.12.2
  • golang 1.23.4

python版

clickというライブラリを使うと手軽でいいっぽい

以下の感じで普通にインストールすれば使える

$ pip install click

clickが無難にポピュラーそうなので使ってみたが、標準ライブラリの argparse を使ったりするケースもありそうだし、他の競合として firetyper なんてのもあるっぽい

githubのスター数見るとfireが結構人気っぽいのでfireもそのうち試してみる

フォルダ構成は以下

.
├── cli_python.py
└── clipython

clipythoncli_python.py へのシンボリックリンク

本来、実行コマンドは以下となっている

いくつかの例
$ python cli_python.py --help
$ python cli_python.py hello --help
$ python cli_python.py goodbye -n Sugo

シンボリックリンクを設置することで以下のように実行できるようにしている

いくつかの例
$ ./clipython --help
$ ./clipython hello --help
$ ./clipython goodbye -n Sugo

サブコマンドとしてhelloとgoodbyeが実行できるようになっている

cli_python.py
#!/usr/bin/env python

import click


@click.group()
def cli():
    pass


@cli.command(help="こんにちはを誰かに言う")
@click.option("-n", "--name", type=str, help="Specify your name")
def hello(name):
    click.echo(f"Hello {name}")


@cli.command(help="さよならを誰かに言う")
@click.option("-n", "--name", type=str, help="Specify the name of the other party")
def goodbye(name):
    click.echo(f"Goodby {name}")


def main():
    cli()


if __name__ == "__main__":
    main()

以下は実際にコマンドを実行した例

$ ./clipython --help
Usage: clipython [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  goodbye  さよならを誰かに言う
  hello    こんにちはを誰かに言う


$ ./clipython hello --help
Usage: clipython hello [OPTIONS]

  こんにちはを誰かに言う

Options:
  -n, --name TEXT  Specify your name
  --help           Show this message and exit.


$ ./clipython goodbye -n Sugo
Goodbye Sugo

golang版

cobraというcliツール作成のためのフレームワーク的なのを使うのがいいっぽい
また、cobra-cliをインストールして使えるようにし、それでinitするとベースのものがいい感じに用意できるっぽい

とりあえず始めてみる

$ go mod init cli_go
$ go get -u github.com/spf13/cobra@latest
$ go install github.com/spf13/cobra-cli@latest
$ cobra-cli init --license MIT --viper=false

go mod init がまだよくわからないし、たぶん命名規則もちょっと守れてなさそうではある
go getnpm i 相当なものなんだろうということは理解できた
go install もあまりわかっていない、ツールのグローバルインストールなイメージ

この段階で以下のような状態になる

.
├── main.go
├── cmd/
│   └── root.go
├── go.mod
├── go.sum
└── LICENSE

ちょっと雑だけど、 go.modpackage.jsongo.sumpackage-lock.json くらいのイメージ

一旦デフォの状態で動くか見てみる

$ go run main.go
A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.

動くのでサブコマンドを実行できるよう続きを進める

$ cobra-cli add hello
$ cobra-cli add goodbye

この段階で以下のような状態になる

.
├── main.go
├── cmd/
│   ├── root.go
│   ├── hello.go
│   └── goodbye.go
├── go.mod
├── go.sum
└── LICENSE

各サブコマンドを編集していく

hello.go
package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
)

var helloCmd = &cobra.Command{
	Use:   "hello",
	Short: "こんにちはを誰かに言う",
	Long: `こんにちはを誰かに言う
ことを長く説明する箇所`,
	Run: func(cmd *cobra.Command, args []string) {
		flag, _ := cmd.Flags().GetString("name")
		greet := fmt.Sprintf("Hello %s", flag)
		fmt.Println(greet)
	},
}

func init() {
	rootCmd.AddCommand(helloCmd)
	helloCmd.Flags().StringP("name", "n", "ANONYMOUS", "Specify your name")
}

goodbye.go
package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
)

var goodbyeCmd = &cobra.Command{
	Use:   "goodbye",
	Short: "さよならを誰かに言う",
	Long: `さよならを誰かに言う
ことを長く説明する箇所`,
	Run: func(cmd *cobra.Command, args []string) {
		flag, _ := cmd.Flags().GetString("name")
		greet := fmt.Sprintf("Goodbye %s", flag)
		fmt.Println(greet)
	},
}

func init() {
	rootCmd.AddCommand(goodbyeCmd)
	goodbyeCmd.Flags().StringP("name", "n", "ANONYMOUS", "Specify the name of the other party")
}

実行結果が以下

$ go run main.go hello
Hello ANONYMOUS

$ go run main.go goodbye
Goodbye ANONYMOUS

$ go run main.go hello --name Sugo
Hello Sugo

$ go run main.go hello -n Sugo
Hello Sugo

$ go run main.go goodbye --name Sugo
Goodbye Sugo

$ go run main.go goodbye -n Sugo
Goodbye Sugo

コマンドの説明もついでなのでちょっと書き換えてみる

root.go
package cmd

import (
	"os"

	"github.com/spf13/cobra"
)



var rootCmd = &cobra.Command{
	Use:   "cli_go",
- 	Short: "A brief description of your application",
- 	Long: `A longer description that spans multiple lines and likely contains
- examples and usage of using your application. For example:
- 
- Cobra is a CLI library for Go that empowers applications.
- This application is a tool to generate the needed files
- to quickly create a Cobra application.`,
+ 	Short: "コマンド全体の短い説明文",
+ 	Long: `コマンド全体の長い説明文`,
}

func Execute() {
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

func init() {
	rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

ビルドしてみる

$ go build

実行してみる

$ ./cli_go
コマンド全体の長い説明文

Usage:
  cli_go [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  goodbye     さよならを誰かに言う
  hello       こんにちはを誰かに言う
  help        Help about any command

Flags:
  -h, --help     help for cli_go
  -t, --toggle   Help message for toggle

Use "cli_go [command] --help" for more information about a command.

$ ./cli_go hello
Hello ANONYMOUS

$ ./cli_go hello -n Sugo
Hello Sugo

$ ./cli_go goodbye
Goodbye ANONYMOUS

$ ./cli_go goodbye --name Sugo
Goodbye Sugo

まとめ

完全に理解した

感想

click(python)で作成した方はpythonの実行環境が必要なため、アプリケーションサーバーなどにsshで入って運用/保守などで使うのであれば作るのも手軽でよさそう
pythonの実行環境によってはうまく動作しない可能性もあると思うので、各自に配布してローカルから使ってもらうなどといった場合には向かなさそう

逆にgolang版はバイナリを配るだけでよく、プラットフォーム的な制約は少なさそう
ただ、(まだ入門段階だからかもしれないが)golangの開発環境の整備や開発がなかなか面倒には感じた

最初はこう思ったけど、ちょっと書いたり調べたりしてるとgolangの書き心地は割といいかもしれない、開発環境整備ももう少し理解したら案外すんなりかも

補足

これが地味に助かった

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?