There's an echo in my head

日々のメモ。

Alpine上でstart_serverを使おうとしたらno such file or directory

lestrrat-go/server-starterというホットデプロイしてくれるものがある。

github.com

これをAlpine LinuxなDockerコンテナ上で使おうとしたら下記のようなエラーが出た。

standard_init_linux.go:190: exec user process caused "no such file or directory"

結論から書くと、原因は依存ライブラリがdynamic linkされた実行ファイルを使っているのが原因だった。どうやらReleasesに置かれている実行ファイルはlibcなどが環境にある前提のものらしく、Alpine Linuxにはそのようなものはないので上記のようなエラーが出てしまっていた。

というわけでgolangで書いたアプリケーションのstatic link化を参考に手元でstatic linkしたものをビルドして使ったら上記のようなエラーは出なくなった。

cd $GOPATH/src/github.com/lestrrat-go/server-starter/cmd/start_server
GOOS=linux GOARCH=amd64 go build -a -tags netgo -installsuffix netgo --ldflags '-extldflags "-static"'

しかしここで指定してるnetgoとは何なんだろう :thinking:

rubyでprotocプラグインを書いてみた

Swagger書きたくない…!というところからProtocol Buffersのサービスとメッセージ定義をもとに似たようなことができないかと考えていたところ、yuguiさんのprotocプラグインの書き方を見てできそうな気がしたので試してみた。

そうして上記記事と同じことをprotobuf gemを使って実装してみたのがこちら。

github.com

ここでは大したことはできてないけど、plugin.pb.rbdescriptor.pb.rbを見る限りprotoファイルに記述されている内容はすべて取れそうなので、がんばれはできなくはなさそう。

ただ結局やりたいことって更新されたprotoファイルから継続的にスケルトンのコードを上手いこと生成、挿入することだったりするので、一ファイルを毎回上書きするようなprotocの使い方には合致しないのではという気がしている。もしかしたらCodeGeneratorResponse::Fileのinsertion_pointがそこら辺を上手いこと面倒見てくれるのかもしれないけど、要調査。

ちなみにProtocol Buffersを扱うgemとしてはgoogle-protobuf gemもあるが、現状こちらだけを使ってprotocプラグインを書くことはできない。なぜならこちらには前述のplugin.pb.rbとdescriptor.pb.rbに相当するメッセージの定義が無いためオリジナルのprotoファイルから生成する必要があるのだが、オリジナルがproto2で記述されているため、proto3しか扱えないprotocのrubyの処理系では現状生成することができないからだ。 両gemでインターフェースやクラスツリーは統一されているだろうからprotobuf gemのplugin.pb.rbとdescriptor.pb.rbだけrequireしてgoogle-protobuf gemで処理を実装することもできるかもしれないけど、あまりメリットはなさそう。

dotenv-execというnpmを作った

作った。

www.npmjs.com

npmだと.envを読み込むdotenvというライブラリはあるんだけど、それをもってコマンドを実行するコマンドは提供していなかった。Ruby版のdotenvに含まれるdotenvコマンドみたいなやつ。なので同じようにdotenvというコマンドを実装した。名前は変えた方がよかったんだろうか :thinking:

実装するにはKernel.execのようにexec(3)ができるメソッドが必要だけど、nodeでそれをやるにはkexecというnpmを使う必要があった。child_process.execなどは結果をコールバックで受ける形になっていてプロセスは切り替わらない。で、このkexecがgypを使っていてインストールをするにはコンパイルが必要になり、ピュアJavascriptなdotenvに追加するのはすでに導入している人がアップデートするときには辛そうだなーと思ったので別のパッケージとした。

引数の処理がナイーブな感じがしているので、また変更を入れるかもしれない。

追記 3/12

もともとhubotを起動するためにhubot-dotenvを使っていて、わざわざ.envファイルを読み込むためだけに別のnpmを入れるのもなんかな…と思ったのがこの開発の動機だった。でもよくよく考えればhubotの場合はbin/hubotというシェルスクリプト経由で起動できるようになっているので、ここに.envを読み込むシェルスクリプトを組み込めばnpmを増やす必要はないということに気づいた。生成されたコマンドを書き換えることにはなるので好き好きではあるけど、備忘録として。

gitが自動解決できずに発生したTSVファイルのコンフリクトを可能な限り解決するfix_tsv_conflictを作った

作った。

github.com

ゲームのマスターデータをTSVファイルで管理していると、内容自体は衝突していないのに同時に同じ箇所に書き足したということで衝突してしまうことがある。あとはエディタの設定で末尾の空白スペークが消えてしまったとか。そういった単純なコンフリクトをこのコマンドは自動で解決してくれる。

使い方は二つあって、一つ目は

fix_tsv_conflict <目的のTSVファイル>

とするとどこを解決したか、もしくは解決できなかったかを標準エラーに書き出し、最終的な結果を標準出力に書き出す。もう一つは、-oオプションをつけることで標準出力に書き出さず直接ファイルを書き換える。

fix_tsv_conflict -o <目的のTSVファイル>

このコマンドが使える前提として、行の先頭に整数値を使ったidカラムがあることがあるので要注意。

コンフリクトの解決方針としては次のようにしている。

  • コンフリクトしたブロックごとに解決する、一行でも解決できなければコンフリクトした状態のまま残す
  • idカラムがユニークになるように残す
  • idカラムが同じで末尾の空のカラム数が異なるだけ場合は、総カラム数に近い方を残す
    • コンフリクトの解決が目的なので、空のカラム数の調整は行わない

ruby gemなので、gem installして使う。

gem install fix_tsv_conflict

今回初めてRefinementsを使ったけど、Travisで複数のRubyバージョンをまわしていたらバージョン間のRefinementsの対応の違いによってちょこちょこ落ちることがあった。新しいバージョンほど適用できる範囲が増えているので着実に進化しているのだなと感じた。

あと今回、データは標準出力に、通知は標準エラーにというのを意識して実装した。このコマンド自体は実際は-oオプションで直接上書きするのであまり関係ないかもしれないけど、他のツールをパイプして使ったりログを記録したりとかやっているとどちらに出力するかで自動化やモニタリングのしやすさが変わるのを最近感じている。

複数のgit-pr-release用のトークンを発行する方法

1台目のマシンでgit-pr-releaseを叩いて認証すると、2台目のマシンでgit-pr-releaseで叩いたときに同一ユーザの認証に失敗する。

GET https://api.github.com/repos/<your>/<product>/pulls/<number>: 401 - Bad credentials // See: https://developer.github.com/v3 (Octokit::Unauthorized)

これは1台目の認証でGitHub上にgit-pr-releaseという名前のトークンが発行されたために、2台目の認証で同名のトークンの発行に失敗するためである。

なので複数台のマシンでgit-pr-releaseを使いたい場合には

  1. 1台目でgit-pr-releaseを叩いて認証する
  2. トークンの一覧からgit-pr-releaseというトークンの名前を変更する
  3. 2台目でgit-pr-releaseを叩いて認証する

というように、新しいマシンで認証するまえに発行済のトークンの名前を変更しておけば良い。

ちなみに再認証したい場合には~/.gitconfigにある次のようなセクションを削除もしくはコメントアウトしておけば良い。

[pr-release]                 
  token = <your token>
このブログに出てくるコードスニペッツは、引用あるいは断りがない限りMITライセンスです。