GitHub Gistにファイルをアップロードするコマンドをgolangで作った
Gistを作る時、毎回catでファイル内容を表示してコピーして、GistのWeb画面にペーストしてたんだけど、
これが地味にめんどくなってきたので、ファイルを渡すとGistを作ってくれるコマンドをgolangで作った。
使い方
target.go
をGistにアップロードする場合。
$ gistup target.go
- 複数ファイルをGistにアップロードする場合。
$ gistup target.go target_test.go target_linux.go
- 標準入力をGistにアップロードする場合。
$ stdin | gistup
アップロードが成功するとブラウザで作成されたGistのページを開きます。
(開けなかった場合はURLを表示。)
デフォルトでは最初にユーザ名とパスワードでログインを求められます。
(後述のオプションで匿名を選択すればログイン不要。)
また、デフォルトでは非公開のGistとして作成されます。
(こちらもオプションで公開のGistとして作成することも可能です。)
オプション
-a
- 匿名のGistを投稿します。
-d <description>
- Gistの説明を追加します。
-n <file_name>
- 標準入力からGistにアップロードする場合のファイル名を設定します。
- 指定しない場合はGistのデフォルト
gistfile1.txt
になります。
-p
- パブリック(公開)のGistを投稿します。
所感など
入力時のコンテキストキャンセル検知
ユーザ名、パスワード入力は下記のようにコンテキストのキャンセルを検知できるようにしている。
func readString(ctx context.Context, hint string, readFunc func(t *tty.TTY) (string, error), t *tty.TTY) (string, error) { fmt.Printf("%s: ", hint) ch := make(chan string) errCh := make(chan error) go func() { s, err := readFunc(t) if err != nil { errCh <- err } ch <- s }() var s string select { case <-ctx.Done(): return "", ctx.Err() case s = <-ch: case err := <-errCh: return "", err } return s, nil }
理由はgistupはInterruptシグナル(Ctrl+C
)を受けてコンテキストをキャンセルする仕組み(下記参照)になっているのだが、
sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt) ctx, cancel := context.WithCancel(context.Background()) go func() { <-sigCh cancel() }()
これだと、入力中にCtrl+C
を押しても終わらない。
なので、ゴルーチンで入力処理を実行して、コンテキストのキャンセルと、入力終了をselect
で同時に待つようにした。
結果、入力中にCtrl+C
を押すと終了するようにできた。
ユーザ名、パスワードの入力はTTY
を使用
gistupではユーザ名とパスワードの入力にTTY
を使用している。
理由は、最初、標準入力からユーザ名とパスワードを取得していたけど、
標準入力をGistにアップロードする箇所を実装してる時にユーザ名、パスワードの取得ができなくなる事に気づいた。
いろいろ調べたけど引き続き標準入力からユーザ名、パスワードを取得するのは難しそうで、調べて出てきたのはperlの質問でTTY
を使っているやつだった。
「goでTTY
って確かmattnさんが作ってたよな」と探したらあって、
ただ、パスワードを読むメソッドしか無かったのでReadString
メソッドをプルリクエストした。
その後、速攻でマージして頂けたのでユーザ名の入力にはReadString
を使用。
パイプで前のコマンドの結果貰うツールでStdinからユーザ名とかパスワードを入力しようとするとパイプの方を拾っちゃってうまくいかなかった。
— 178inaba (@i178inaba) 2017年7月26日
go-ttyのReadString(さっきPRした)を使ったらうまくいった。
皆さんもぜひ!https://t.co/PGlJcQEUJr
結果、ユーザ名、パスワードを入力しつつ、標準入力から取得した文字列をGistにアップロードすることができた。
まとめ
これでコピペせずにGistにアップロードできるようになった。
またなんか作ったら書きます。
あと、PR大歓迎です😆