Go言語を修正してソースからビルドする

Go自体に手を入れたいということがあって、ソースからビルドしてみた。

Goのソースコードを入手

公式のサイトから手に入る。開発中のものが欲しい場合にはgithubから取得する。

$ cd /tmp
$ wget https://storage.googleapis.com/golang/go1.8.3.src.tar.gz
$ tar xf go1.8.3.src.tar.gz
$ cd go

GOROOT_BOOTSTRAP を設定する

Goをビルドするために必要なGoを指定する環境変数。デフォルトでは $HOME/go1.4 になっている。必ずしも1.4が必要なわけではなく、1.4以上のバージョンであれば良い

$ which go
/usr/local/go/bin/go
$ go version
go version go1.8 darwin/amd64
$ export GOROOT_BOOTSTRAP=/usr/local/go

ビルド

src に移動して all.bash を実行する。 all.bashsrc に移動しないと実行できない。完了までには数分かかる。

$ cd src
$ ./all.bash

完了すると bin/go が出来ている。

$ cd ../bin
$ ./go version
go version go1.8.3 darwin/amd64

独自の修正を加えた場合

修正した内容にexportedなものがあれば、必ずapi配下の goX.Y.txt (X.Yはバージョン番号)を修正する。

例えば、fmtパッケージに

func PrintTwice(args ...interface{}) {
    Print(args...)
    Print(args...)
}

という変更を加えた場合、go1.8.txtに

pkg fmt, PrintTwice(...interface{})

というのを追記する。

ビルドの最後の方に、apiの変更をチェックするタスクがあって、そこで整合性の確認が行われるため、この記載がないとエラーになってしまう。

all.bash を使わない方法がありそうだけど中身は見てない。

まとめ

  • Goをソースからビルドするのは難しくない
  • 必要なバージョンは1.4以上で、1.4必須ではない
  • exportされた修正がある場合は、goX.Y.txtも修正する

goaのDSLのAttributeについて

スニペットづくりのためにコード読んでいて気づいたのでメモ。 v1の方。

Attributeとは

AttributeはView, Type, Attribute, Attributesの中で使える関数で、属性を指定するのに使用する。nested attributeってのがあるらしく、Attributeの中でAttributeが使えるらしいが、よくわからない。

Attributeの引数

ドキュメントによると、Attributeの定義は以下のようになっている。
https://goa.design/reference/goa/design/apidsl/#func-attribute-a-name-apidsl-attribute-a

func Attribute(name string, args ...interface{})

1つ目がAttributeの名前になるstringで、2つ目はinterface{}の可変長引数になっている。

2つ目の可変長引数には何渡しても良いのかというとそうではなくて、実際に使える値のパターンもドキュメントに記載されている。(ちゃんと読んでなかった)

Attribute(name string, dataType DataType, description string, dsl func())

Attribute(name string, dataType DataType, description string)

Attribute(name string, dataType DataType, dsl func())

Attribute(name string, dataType DataType)

Attribute(name string, dsl func())  // dataType is String or Object (if DSL defines child attributes)

Attribute(name string)          // dataType is String

Attributeの仲間

DSLとしてAttributeのaliasになっているものがある。

  • Param
  • Member
  • Header

の3つ。

Param

https://goa.design/reference/goa/design/apidsl/#func-param-a-name-apidsl-param-a

func Param(name string, args ...interface{})

Param can be used in: Params
Param is an alias of Attribute.

とのこと。

Member

https://goa.design/reference/goa/design/apidsl/#func-member-a-name-apidsl-member-a

func Member(name string, args ...interface{})

Member can be used in: Payload
Member is an alias of Attribute.

とのこと。

Header

https://goa.design/reference/goa/design/apidsl/#func-header-a-name-apidsl-header-a

func Header(name string, args ...interface{})

Headerだけちょっと異なっている。

Header can be used in: Headers, APIKeySecurity, JWTSecurity

Header is an alias of Attribute for the most part.

Within an APIKeySecurity or JWTSecurity definition, Header defines that an implementation must check the given header to get the API Key. In this case, no args parameter is necessary.

APIKeySecurity, JWTSecurityと使う場合には、 args を指定してはいけないとのこと。

こういう利用のされ方になる。

JWTSecurity("jwt", func() {
    Header("Authorization")
    TokenURL("<a href="https://example.com/token">https://example.com/token</a>")
    Scope("my_system:write", "Write to the system")
    Scope("my_system:read", "Read anything in there")
})

コードを確認

ParamとMember

// Member is an alias of Attribute.
func Member(name string, args ...interface{}) {
    Attribute(name, args...)
}

// Param is an alias of Attribute.
func Param(name string, args ...interface{}) {
    Attribute(name, args...)
}

ParamとMemberは内部でAttributeを呼んでいるだけ。

Header

func Header(name string, args ...interface{}) {
    if _, ok := dslengine.CurrentDefinition().(*design.SecuritySchemeDefinition); ok {
        if len(args) != 0 {
            dslengine.ReportError("do not specify args")
            return
        }
        inHeader(name)
        return
    }

    Attribute(name, args...)
}

Headerは処理中のデザイン定義を表す dslengine.CurrentDefinition が、 *design.SecuritySchemeDefinition (APIKeySecurity or JWTSecurity) だった場合には args の長さをチェックして、0だったらinHeader を呼び出して終了する。

inHeader はどのヘッダーにAPIキーが指定されているかを設定する処理。

*design.SecuritySchemeDefinition ではなければ、そのまま Attribute を呼び出す。

感想

まとめは特にないので、感想書いとく。

汎用的な関数を作るときの名前って大事だけど、今回のような、Attribute、Param、Memberの総称とか簡単に思いつかない。aliasという形で別名にして提供するってのは良いやり方だと思った。

ドキュメントもちゃんと読むだけじゃなくて、コードも合わせて確認すると理解度が高まる。調べようと思っていたこと以外にも、参考になることがある。

ところで、スニペットの進捗はあまり進んでない。来週とかかな…

VSCode用のgoaのコードスニペットを作ってみた

昨日行われたgoa勉強会 in 六本木一丁目 - connpassに参加するついでに、 以前作っていたVSCode用のgoaのコードスニペットの紹介を飛び込みLTで行ってきた。

資料

LTの資料はこちら。

goaのdesignをラクに書く

コードスニペットこちら。

vscode goa snippets

実際に動いているところをキャプチャしたやつ。

https://gist.githubusercontent.com/kawaken/f33592f483e21f3e38d66b63b6fb76ec/raw/6c9d9ed7f276c54c70972ca51494c212bfa0981e/goa-snippets.gif

飛び込みLTは初めてだったせいかめっちゃ手が震えてしまって、うまくタイピングできない感じだったけど、Twitterの方では反応もらえてたので良かった。

スニペットについて

スニペット自体は簡単に書けるので別に難しい作業ではないんだけど、同じDSLでも引数が異なるものもあるので、組み合わせるとけっこう膨大になると思う。 なので、必要最小限って感じで上手くまとめようと思って書き始めたものの、手が止まっていた。

例えば、Routingは揃ってない。昨日LTでいるなぁと思ったのでGETだけ追加した。

誰かやってくれたらそれでも良いんだけど、昨日LTした反応が素直に嬉しかったし、VSCode自体はすごく気に入っているので、 マーケットプレイスに上げるところも視野にがんばってみようかなとか思った。

go get で permission denied が発生する

goのバージョンアップが上手くできてなかったので発生した。

事象

go get でパッケージをインストールしようとすると、以下のようなエラーが起きる。

$ go get -u github.com/kawaken/chatwork-cli
go install runtime/internal/atomic: open /usr/local/go/pkg/linux_amd64/runtime/internal/atomic.a: permission denied

どうやら古いバージョンを移動や削除せずに、tarで展開してしまったのが良くなかったらしい。

ちゃんとバージョンアップする

現行のバージョンを確認。

$ go version
go version go1.7.1 linux/amd64

既存のgoをバージョン付きのパスに変更する。残す必要がなければ削除して良い。

$ sudo mv /usr/local/go /usr/local/$(go version | awk '{print $3}')
$ ls -d1 /usr/local/go*
/usr/local/go1.7.1/

新しいバージョンのgoをインストールする。

# cd /usr/local/src/
# wget https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz
# tar -C /usr/local -xf go1.8.3.linux-amd64.tar.gz
# go version
go version go1.8.3 linux/amd64

slackのstatusを更新するやつを利用してみた

こちらの記事を読んで早速試してみた。

GoogleカレンダーとSlackステータスをワンクリックで連携できるアプリをGoogle Apps Scriptで書いた - 詩と創作・思索のひろば

基本的にはそのまま使えるけど、少し修正した。 GASを使ってSlackと連携するためのやり方が勉強になった。

プライベート予定をスルーする

そもそも会社のカレンダーで同僚に公開できないような予定を管理するのはどうなん?というのはあるものの、まぁだからといって表示していいものでもないのも確かにそうなので。

EventのVisibilityがPRIVATEの時にはスルーするようにした。

他人の出退勤の予定をスルーする

社内の運用で、特に出退勤に関する予定をチームメンバーにも登録するというのが定着している。例えば、

  • 16時早退(山田)
  • 午前休: 佐藤
  • 田中(2h休)

といったタイトルで登録されている。

終日予定で登録されていれば良いのだけど、休んでいる時間帯で登録する人もいる。その時間になると、slackのstatusがみんな同じ他人の休みを表示してしまって使い物にならない。

他人から登録された予定を弾いたら良いかと思ったが、ミーティングの予定は主催者が参加者をゲストとして登録することがある。仕方ないので、タイトルのキーワードマッチで弾くようにした。

let IGNORED_COLLEAGUE_EVENT_REGEX = /^[出帰退]社|早退|休み|時間休|[hH]休|半休|午[前後]休|健康診断|外出|移動$/;

その他

登録の都合上予定がかぶることがあって、そういうときにどちらかしか表示されないようになっているので、そこをどうにかしたい。あとは、勤怠情報をつぶやく専用チャンネルがあるので、そこに「今日は Aさん がおやすみです」とか投稿できるようにしたい。

修正したやつはこちら。

https://github.com/motemen/gas-google-calendar-to-slack-status-farm/compare/master…kawaken:add-conditions-to-ignore

読んだ: Java本格入門 ~モダンスタイルによる基礎からオブジェクト指向・実用ライブラリまで

最近Java をやることになったが、久しぶりなので改めて学習しようと思い、読んでみた。

Java本格入門 ~モダンスタイルによる基礎からオブジェクト指向・実用ライブラリまで

Java本格入門 ~モダンスタイルによる基礎からオブジェクト指向・実用ライブラリまで

Javaの本は沢山あるんだけど、最新のバージョンを踏まえた入門系の書籍は書店では見つけられなくて、Twitterで見かけたこの本はJava8にも対応しているようだったので、購入した。

入門なので、言語の基本的な型などの話から、ビルドやテストの話まで幅広く記述されている。全く知らないわけでもないので、前半はサラッと読んで後半をじっくりと読んだ。

所々で「今までこうだったけど、今はこうだよ」という説明が丁寧にされていて、自分の知識をアップデートできたし、とても良かった。

読んだ: みんなのGo

かいつまんで読んでたやつを改めてちゃんと読んだ。

みんなのGo言語【現場で使える実践テクニック】

みんなのGo言語【現場で使える実践テクニック】

Goでプログラム書くときに、こう言う時はどういう実装が良いのかな?と悩むことがあるけど、そういう時に参考にできる実践的な書籍だと思う。

個人的にはCLIのツールを作ったりすることが多いので、その辺が参考になった。

あと、テストのところとか。

必要なところをかいつまんで読めるので、Tour of Goやった後とかで、実際にやりたいことがあれば参考にしたら良さそう。