20190403のGoに関する記事は5件です。

Macにgoをインストールするまで

macにgoをインストールするまで

インストール手順

anyenvのインストール

brew install anyenv
# .bash_profileを直接変更しても良い
echo 'eval "$(anyenv init -)"' >> ~/.bash_profile
exec $SHELL -l

goenvのインストール

anyenv install goenv
# インストールができてるか確認できる
goenv -v

exec $SHELL -l
goenv install -l
# 何もなければ最新のバージョンをインストール
goenv install 1.12.1
# 特定ディレクトリ配下で異なるバージョン使いたければlocal使う
goenv global 1.12.1

# インストールできてるか確認
go version

GOPATHの追加

hadaは$HOME直下にgoディレクトリを作成してそこをGOPATHにした

最終的な.bash_profile

.bash_profile
export GOPATH=$HOME/go
export GOBIN=$GOPATH/1.12.1/bin
export PATH=$GOPATH/bin:$PATH
eval "$(anyenv init -)"

go envとかでgo周りの環境変数が正しく設定されてるか確認
GOPATHにバージョン名のディレクトリとかできるけど気にしない
/Users/yota.hada/go/1.12.1

depを入れる

go get -u github.com/golang/dep/cmd/dep

# GOBINを設定してればdepコマンドが使えるはず
dep version

vscode使ってる場合

goの拡張機能入れる

settingにGOPATHを追加する

settings.json
"go.gocodeAutoBuild": true,
"go.gopath": "/Users/yota.hada/go/1.12.1",

最初にgoファイル開いたときに推奨のライブラリとかおすすめされるのでインストールしておく

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【2019年4月版】Solidityでビルドしたバイナリがちゃんと動くかHyperledgerのUTでデバッグしてみる。

ちょっと、何言ってるかわからない。

えっと、Ethereum スマートコントラクトの Hyperledger 上でのデバッグ方法です。いや、やっぱりわかりませんね。

こちらの記事「Hyperledger fabric の EVM を試す」で Hyperledger 上で EVM が動かせて、Solidity でビルドしたスマートコントラクトがデプロイできてちゃんと動作する、というのはご紹介いたしました。

ところがですね・・・デプロイ手順がめんどくさいweb3.js経由のデプロイしてしっかりブロックチェーンに書き込まれると後戻りができないのでその手前でごにょごにょしてみたいわけです。

ま、要するにデプロイ手順がめんどくさいのです!!

今回のゴール

hyperledger-fabric で EVM のチェインコード(Hyperledger流のスマートコントラクト)を実行する実際のモジュールである "fabic-chaincode-evm" のUTコードに自前のスマートコントラクトを追加してデバッグしてみる、という試みです。

対象環境

OS: Windows 10
IDE: VSCode
言語: GO 1.12.1

VSCodeはエディタですがもはやIDEでしょうということで。

対象のスマートコントラクト

実際にEVMで動くかどうか試してみたいのは前回の記事「イーサリアムのテストネットで初めてのオリジナルトークンを公開してみる」でデプロイした"マイERC20トークン"のスマートコントラクトです。OpenZeppelinをimportしたスマートコントラクトがHyperledgerで動くなら、ERC721トークンがHyperledgerに乗っかることも可能じゃないですかっ!?っていうことで、試してみたいわけです。
簡単ではございますが、こちらです。

pragma solidity ^0.5.2;

import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";

contract MyTokenERC20Sample is ERC20, ERC20Detailed {

  string private _name = "Hyperledger Token";
  string private _symbol = "HYP";
  uint8 private _decimals = 18;

  uint value = 1000000;

  constructor()
    ERC20Detailed(_name, _symbol, _decimals)
    public
    {
        _mint(msg.sender, value);
    }
}

_decimalvalue が適当すぎるのはご愛嬌ということで・・・

対象プロジェクト

Hyperledger配下には多数のプロジェクトがございますが、今回のターゲットは以下です。

環境構築

それではさっそくデバッグ環境の構築を行います。

GO言語環境の構築

fabric-chaincode-evm の開発環境であるGo言語での開発環境構築を整えます。

Go言語バージョン 1.12.1のインストーラーを以下のダウンロードサイトからダウンロード&インストールをお願いします。

インストール後、$GOPATH/binPATHに追加しておきます。

続いてdepを入れます。

> go get -u github.com/golang/dep/cmd/dep

プロジェクトのクローン

go getでプロジェクトを取得します。

> go get -u github.com/hyperledger/fabric-chaincode-evm

うまくいかない場合はmkdirで自前でフォルダ作成し、階層ずれないように注意しつつgit cloneします。

> mkdir $GOPATH/src/github.com/hyperledger
> cd $GOPATH/src/github.com/hyperledger
> git clone https://github.com/hyperledger/fabric-chaincode-evm.git
> cd fabric-chaincode-evm

つづいて依存モジュールのインストールdepで一発です。

> dep ensure

VSCode の起動

VS Codeを起動し、Go言語用のプラグインをインストールしてください。Extentionの検索でgoを調べるとMicrosoft提供のGoプラグインが見つかると思います。

ターゲットの階層へ移動

いよいよ確信へと迫ります。

> cd evmcc

まずは試しにターミナルから go test と打って通常のUTが動くかどうか、確かめます。いや、動いてくれなきゃ困るけど・・・

> go test

VSCodeのデバッグ設定

続きましてVSCodeから単体テストのデバッグ起動を行うための設定をします。

デバッグ画面から ⚙ ボタンクリックによってlaunch.jsonが開きます。エディタの右下のAdd Configuration...ボタンがありがたいです。
Add Configuration...ボタンでGo: Launch test functionを選ぶとスニペット貼り付けてくれるので、以下のように設定を変更します。

    {
      "name": "Launch test function",
      "type": "go",
      "request": "launch",
      "mode": "test",
      "program": "${workspaceFolder}/evmcc",
      "args": ["-ginkgo.v", "-ginkgo.trace"]
    },

上記のように go test から ginkgo にフラグなどの引数を渡したい場合は-ginkgo.vのように記述します。

例えばログを詳細に出したい場合は以下のようにするわけです。

go test -ginkgo.v

Ginkgo について

さらっと Ginkgo についてご紹介すると GO言語での BDD ベースのテストフレームワークでございます。

他言語での BDD フレームワークに親しんでいる方は特に引っかかることもないと思います。DescribeContextの 2 段階構成でIt,Expectと書けます。
またアサーションは標準でgomegaがおすすめなようです。

以下は evmcc_test.go の一部です。

evmcc_test.go
    Describe("Init", func() {
        It("returns an OK response", func() {
            res := evmcc.Init(stub)
            Expect(res.Status).To(Equal(int32(shim.OK)))
            Expect(res.Payload).To(Equal([]byte(nil)))
        })
    })

テストケースの作成

さて環境構築は完了です。いよいよテストケースを追加してみます。

Solidity でビルドしたバイナリの準備

いつもの通り、Remix サーバーで上記で紹介したスマートコントラクトのコードを貼り付けます。

OpenZeppelin のコードがsolidity ^0.5.2;の縛りが入っているのでこちらもそれに合わせます。
コンパイラを0.5.2以上のものを選択し、コンパイラのロードが終了後Ctrl+Sなどでコンパイルします。
コンパイルが無事に終わったようであればBytecodeボタンをクリックでバイナリを取得し、適当なテキストエディタに貼り付けておきます。

テストコードの追加

他のテストケースの冒頭部分を拝借して以下のようなコードを追加いたしました。
ここでは単にデプロイするだけのチェックです。

    Describe("ERC20 with OpenZeppelin Dapp", func() {
        var (
            user0Cert = `-----BEGIN CERTIFICATE-----
MIIB/zCCAaWgAwIBAgIRAKaex32sim4PQR6kDPEPVnwwCgYIKoZIzj0EAwIwaTEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFDASBgNVBAoTC2V4YW1wbGUuY29tMRcwFQYDVQQDEw5jYS5leGFt
cGxlLmNvbTAeFw0xNzA3MjYwNDM1MDJaFw0yNzA3MjQwNDM1MDJaMEoxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp
c2NvMQ4wDAYDVQQDEwVwZWVyMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPzs
BSdIIB0GrKmKWn0N8mMfxWs2s1D6K+xvTvVJ3wUj3znNBxj+k2j2tpPuJUExt61s
KbpP3GF9/crEahpXXRajTTBLMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAA
MCsGA1UdIwQkMCKAIEvLfQX685pz+rh2q5yCA7e0a/a5IGDuJVHRWfp++HThMAoG
CCqGSM49BAMCA0gAMEUCIH5H9W3tsCrti6tsN9UfY1eeTKtExf/abXhfqfVeRChk
AiEA0GxTPOXVHo0gJpMbHc9B73TL5ZfDhujoDyjb8DToWPQ=
-----END CERTIFICATE-----`

            creator = marshalCreator("TestOrg", []byte(user0Cert))

            deployCode  = []byte("60c0604052601160808190527f48... b3068c0029")
        )

        BeforeEach(func() {
            // Set contract creator
            stub.GetCreatorReturns(creator, nil)
        })

        It("will create and store the runtime bytecode from the deploy bytecode and a user account", func() {
            // zero address, and deploy code is contract creation
            stub.GetArgsReturns([][]byte{[]byte(crypto.ZeroAddress.String()), deployCode})
            res := evmcc.Invoke(stub)
            Expect(res.Status).To(Equal(int32(shim.OK)))

        })
    })

そして最後のExpectの箇所にブレークポイントを設定し、デバッグを走らせてみましょう。
ちゃんとブレークポイント決まりました!(よね?!)

これでSolidityのビルドバイナリを貼り付ければダイレクトに実行中のEVM(の外側)がデバッグできる環境ができました。

プロパティ(引数なしメソッド)のテストコード

このスマートコントラクトはERC20 Detailsを継承していますのでsymbolなどのプロパティがあります。

これを取得してAssertするテストコードは以下のようになります。

evmcc_test.go
stub.GetArgsReturns([][]byte{[]byte(contractAddress.String()), []byte("95d89b41"})
res := evmcc.Invoke(stub)
Expect(res.Status).To(Equal(int32(shim.OK)))
// encoded bytes for "HYP"
// It consists of three elements which take byte32 each:
// - 0x32 the location of data
// - 0x3  the length of array
// - 0x728980 left-aligned 'HYP'
// Payload is "00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000372898000000000000000000000000000000000000000000000000000000000000"
Expect(string(res.Payload[64:67])).To(Equal("HYP"))

まず1行目の95d89b41symbolのメソッドがある番地です。これはRemixからスマートコントラクトを動かしてみて、symbolの値を取得するとそのトランザクションログが流れますが、そのinputの欄からコピーできます。
(というかそれ以外に計算方法などないのだろうか・・・??)

またSolidityは文字列の扱いが強烈に大変です。生UTF-8バイナリがbytes32に入っている、という型としてきます。なんだかよくわからないけどそんなもんです。。。
なので上記のテストケースもres.Payload[64:67]stringにする、という方法でHYPと比較しています。

Web3.js では。

Web3.js ではこのHexな文字列と元の文字列との交換は簡単で以下のように行います。

> web3.padRight(web3.fromAscii('HYP'), 34)
"0x48595000000000000000000000000000"

逆は

> web3.toAscii("0x48595000000000000000000000000000")
"HYP                   "

でOKです。ちょっと後半の0000...の箇所が空白が入ってしまうのはアレですが・・・

メソッドのテストコード

引数付きのメソッドもだいたい似たようなものですが、メソッドの番地の後ろに引数のbyte値をつなげて呼び出す必要があります。これもRemixで叩いてみて、ログが流れますのでinput欄からコピーすれば丸ごと取得できます。

実際には以下のようなコードとなります。

evmcc_test.go
// 1000 -> 0x00000000000000000000000000000000000000000000000000000000000003e8
stub.GetArgsReturns([][]byte{[]byte(contractAddress.String()), []byte(transfer + hex.EncodeToString(user2Addr.Word256().Bytes()) + "00000000000000000000000000000000000000000000000000000000000003e8")})
res := evmcc.Invoke(stub)
Expect(res.Status).To(Equal(int32(shim.OK)))

stub.GetArgsReturns([][]byte{[]byte(contractAddress.String()), []byte(balanceOf + hex.EncodeToString(user2Addr.Word256().Bytes()))})
res = evmcc.Invoke(stub)
Expect(res.Status).To(Equal(int32(shim.OK)))
// 1000 -> 0x00000000000000000000000000000000000000000000000000000000000003e8
Expect(hex.EncodeToString(res.Payload)).To(Equal("00000000000000000000000000000000000000000000000000000000000003e8"))

transfera9059cbbbalanceOf70a08231が割り当てられており、その後ろに引数となる値(ここではuser2Addr.Word256().Bytes()1000のバイナリ値の文字列など)をくっつけて丸ごと投げています。

戻り値が数値の場合も諦めてHexな文字列で比較してしまっています。

まとめ

以下が実際に追加した箇所のテストコードになります。

SolidityのTypeのエンコードや文字列の扱い(生UTF-8のbytes32)などかなり大変ですが、リアルにスマートコントラクトが動くのがわかるので、そしてどんだけ大きくてもガス代取られないしバグっても問題ないので、トライ&エラーするには大変有効であると思います。

以上!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Goでフロントも作れるVugu触ってみたよ

なにこれ

VuguがGo言語でフロントをVueやReactっぽく書ける様にしてくれるらしい。
https://www.vugu.org/
ちょっと触ってみた。

Inspired by modern web UI libraries like Vue and React.
Single-file components.
Runs in most modern browsers.
Simple and sane dev and build environment. (Say goodbye to that node_modules folder!)
Write UIs with the ease of HTML+CSS for presentation, and the facility of Go for interface logic. It's pretty cool! See the Getting Started page.

Vuguの読み方わからん。。。バグ?の訳無いよね。

Getting Started

Go 1.12以上が必要の様です。

とても簡単な導入チュートリアルです。とりあえず動かしてみるだけなら簡単です。こんな事やります。

  1. まずプロジェクトフォルダを作ります
  2. go.modを作ります。go mod initでつくれます。
  3. Vuguのコンポーネントファイルを作成。root.vuguというファイルを作成してサンプルコードをコピペ
  4. 開発用のサーバ作成。これもdevserver.goというファイルを作成してサンプルコードをコピペ
  5. 開発サーバを立ち上げる go run devserver.go
  6. ブラウザからhttp://127.0.0.1:8844/にアクセス
  7. 驚く

簡単ですね。
軽くコード触った感じだとこれはVueですね。

ちょこっと改造してみる

上記チュートリアルを行うと、ボタンのオンオフで文字表示のオンオフができる様になります。

これだけだとつまらないのでちょこっと改造します。
ElmのHello World的存在のカウンターアプリを作ってみます。

こんな感じの超シンプルなカウンターアプリができます。

スクリーンショット 2019-04-03 20.33.52.png

上記チュートリアルのroot.vuguを修正します。

<div class="my-first-vugu-comp">
    <button @click="data.Toggle()">Test</button>
    <div vg-if="data.Show">I am here!</div>

    <br>
    <!-- カウンター -->
    <button @click="data.Increment()">+</button>
    <div><span vg-html='data.Count'></span></div>
    <button @click="data.Decrement()">-</button>
    <br>
</div>

<style>
.my-first-vugu-comp { background: #eee; }
</style>

<script type="application/x-go">
type RootData struct {
    Show bool
    Count int
}

func (data *RootData) Toggle() {
    data.Show = !data.Show
}

func (data *RootData) Increment() {
    data.Count = data.Count + 1
}

func (data *RootData) Decrement() {
    data.Count = data.Count - 1
}
</script>

単純にRootDataのメソッドIncrement()Decrement()を定義してボタンアクションに応じてRootData構造体のCountの状態を変化させているだけです。

ちょっと困った事

現在のCountを表示させる方法がわからん。。。
Documentを漁って、vg-htmlを見つけ出して多分これだろ。って感じで試したら表示された。

おわりに

新しく出たものですからね。documentはまだ少ないですね。
ひよっこの私にはちょっとまだ私には良さはわからず。。。
おとなしく他の人の情報待ちします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoでVueっぽくWebアプリが作れるVugu事始め

ツイートが100RT超えたので、Qiitaにも書いてみます。

Go 1.11がJavaScript APIをすべてサポートしたライブラリを開発し、WebAssemblyに新しい未来が見えました。それまでのWebAssemblyはDOMやネットワーク操作ができないとされてきたので、ループ処理の高速化や数値計算、またはCanvasをゴリゴリ使うゲームくらいしか使い道がないよね…といった評価でした。しかしJavaScript APIが実装されたことで、DOM操作やネットワーク処理が可能になり、WebアプリケーションをそのままGoに置き換えられるんじゃないかという可能性が出てきました。

GoではじめるWebAssebmly その1「Hello World」 | hifive開発者ブログ

とは言え、直接書くとコードがなかなか複雑というか、残念な感じになっていました。例えばネットワークのオンライン、オフラインをイベント通知を受け取る場合のコードは下記のようになります。

  navigator := js.Global().Get("navigator")
  cb1 := js.NewCallback(func(args []js.Value) {
    if navigator.Get("onLine").Bool() {
      println("Network is Online");
    } else {
      println("Network is Offline");
    }

  })
  window.Call("addEventListener", "online", cb1)
  window.Call("addEventListener", "offline", cb1)

その内、良い感じにラッピングしたフレームワーク(しかも仮想DOMが使えるような)が出るんじゃないかと思っていたのですが、ついにVuguによって実現しそうです。

Vugu: A modern UI library for Go+WebAssembly

ということで、Getting startedに沿った進め方を紹介します。

Go 1.12のインストール

VuguはGo 1.12が必須です。ということでインストールします。goenv を使うと楽ちんです。

$ goenv install 1.12
$ goenv local 1.12

go.modの作成

go.mod というファイルを作ります。内容は次の通りです。

module example.org/someone/testapp

root.vuguの作成

root.vuguはWeb Component風にUI、Goがまとまったファイルになります。たぶん画面ごとにvuguファイルを作っていくのでしょう。root.vuguの内容は次の通りです。

<div class="my-first-vugu-comp">
    <button @click="data.Toggle()">Test</button>
    <div vg-if="data.Show">I am here!</div>
</div>

<style>
.my-first-vugu-comp { background: #eee; }
</style>

<script type="application/x-go">
type RootData struct { Show bool }
func (data *RootData) Toggle() { data.Show = !data.Show }
</script>

見て分かりますが、scriptタグがapplication/x-goになっていて、その中はGoを記述します。RootDataを定義しておいて、それがイベント時に送られてくるので、その内容を書き換えるといった具合です。Vueとはちょっと書き方が違いますが、分からないものでもないでしょう。

開発用サーバを作る

ここは単純なGoです。devserver.go というファイルで作りますが、名前は何でも良いです。

// +build ignore

package main

import (
    "log"
    "net/http"
    "os"

    "github.com/vugu/vugu/simplehttp"
)

func main() {
    wd, _ := os.Getwd()
    l := "127.0.0.1:8844"
    log.Printf("Starting HTTP Server at %q", l)
    h := simplehttp.New(wd, true)
    // include a CSS file
    // simplehttp.DefaultStaticData["CSSFiles"] = []string{ "/my/file.css" }
    log.Fatal(http.ListenAndServe(l, h))
}

実行する

では実行します。単に実行するだけでvuguのダウンロードも行ってくれる辺り、Goは素晴らしいですね。

$ go run devserver.go

これで http://localhost:8844 でサーバが立ち上がります。

アクセスする

では実際にアクセスします。アクセスすると最初にローディングが走って、Webの画面が表示されます。このローディングの時にWebAssemblyやGoファイルが生成されます。

Untitled3.gif

Hot reloadはないですが、HTTPサーバは落とさずに再読み込みするだけで表示が更新されます。ネットワークを見ると、ちゃんとWebAssemblyファイルが生成されているのが分かります。これは動的なようで、静的ファイルはありませんでした。

Screenshot_ 2019-04-03 10.52.36.png

まとめ

guvuはまだリリースしたてで、Experimentalなステージです。しかし、Goで書けるので型付けがあり、柔軟な書き方ができること、さらにWebAssemblyによって高速なWebアプリケーション(後、普通のJavaScriptより難読化が進んでいる)が作れるのがメリットになるでしょう。何よりVueっぽく書けるのが個人的に一押しポイントです。

なお、DOMやネットワーク操作はWebブラウザ側のJavaScriptで実行されます。WebAssemblyでもDOM書き換えが高速化されたり、CORS制限を越えたネットワークアクセスができる訳ではないのでご注意ください。

ぜひVuguを体験してみてください!

Vugu: A modern UI library for Go+WebAssembly

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ghq的なやつを作った

背景

loves ghq

ghq良いですよね。
無思考でGoPath配下の構造に倣ってプロジェクトを管理できるの、最高だと思います。

ところで、僕は横着者なので、プロジェクトがPythonで出来ていようがC#だろうがVimScriptだろうが、ghqでgetしてたりします。
要するに「何も考えずにプロジェクト管理はghqに委ねる」というスタンスをとりたいのです。
そして、そのスタンスだとghqはちょっといくらか不足があり、それをPRとして本家に出そうと考えたときに、内部のちょっとしたメンテナンスしにくさを感じました。

forked ghq

ちょっとこれは根本的に違うもの作ったほうが自身のニーズを満たせそうだ、と思い立ったので、
別のプロジェクトとして gogh を作ってしまいました。
(あんまりそういうスタンスでのForkは良くないと思うんですが)

gogh の目指すところ

  • 目的
    • GitHub(+GHE)でホストしているプロジェクトの、ローカルでの配置を管理する
      • ghqにならい、Golang風構成(i.e. ./github.com/kyoh86/gogh)でClone
      • 対象ホストごとに設定を切り替える。デフォルトはgithub.comをターゲットとする
    • プロジェクト間をまたぐような操作を極力サポートする
      • ローカルでの操作も、リモートでの操作も
      • 逆にプロジェクト内に収まるようなものは hub の領域と捉える。サポートしない。
      • プロジェクトがまだない状態での操作もサポート対象とする
        • create
        • fork
        • etc...?
  • ghq との差異
    • 設定や一つ一つの機能をシンプルにする
      • そのためにもGitHub以外のホストはサポートしない。
      • 最大公約数的な機能ではなく、最小公倍数的な機能を作る。
    • ghq look は作らない
      • jump into project とされてはいるものの、実態は当該ディレクトリをWDとするシェルの起動。
      • つまり cd - は機能しないし、気づくとプロセスツリーがエライことになってる。
      • 代わりにzsh/bash functionとして似たような機能を提供する。(gogogh
    • 重複した名前のプロジェクトも分かりやすく表示する
      • 重複した名前のプロジェクトが増えてくると、全部長ったらしいパスで表示されたりするのは困る。
      • --unique オプションの出力がとても難解なので、もっとシンプルに。-f=short
    • git config によらない。
      • いろんなツールの設定がgitconfigにあふれて管理めんどくさいし分かりづらい。
      • そして設定値の呼び出しがとても重い。
    • 設定ファイル自体を対象ホストごとに分ける
      • git config 内に設定を持とうとしたこと(と、おそらく歴史的経緯)で、ホストごとに分けられる設定、分けられない設定がややこしい
      • ホストごとに設定しないと変な挙動を示すこともままある
    • GitHub 以外の何かは対応しない
      • そちらは別の何かで管理するほうが良さそう
      • 今の所そもそも向き合ったことがないけど…
    • hub との間を埋める
      • ghqでできることとhubでできることの間に、いつもちょっと面倒なこと、が発生していたのを解消する
      • 新たにforkするとき:元プロジェクトをClone、forkしてプロジェクトを作る
      • 新たにプロジェクト作るとき:ローカルにプロジェクトフォルダを作り、GitHub上にもリポジトリを作る。
    • (些末な宗教) github.com/onsi/gomegagithub.com/urfave/cli が好きではない。github.com/stretchr/testifygithub.com/alecthomas/kingpin がいい。
    • (実験的・ニーズ不明)単なるCLIとして作るのではなく、同時にライブラリとして使える何かを作ってみたい。(github.com/kyoh86/gogh/gogh package)。 hub リスペクトなのだけど。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む