jessevdk/go-assetsでファイルを埋め込む

Go言語の素敵なところの一つとして、最終的な成果物を1バイナリに収めることができる、という点にあると思う。結果として、非常に簡単にコマンドラインツールなどを配布することができる。 しかし、例えばコード生成を行うようなツールでテンプレートファイルを別途持っているような場合や、アプリケーション中で使う画像などを含む場合など、Goのソースコード以外のファイルを必要とする場合、全てを1ファイルで、とはいかない。 そのような場合に便利なのがjessevdk/go-assets である。以前は多くの人がgo-bindataを使用していたと思われるが、作者がやめてしまったため、使えなくなってしまった。代替としてこれが便利。 jessevdk/go-assetsを使用するには、まずjessevdk/go-assets-builder を使用する。これは、指定したファイルをGoのソースコードに埋め込んで、それらを扱うためのAssetsというオブジェクトを作成してくれるツールである。 インストールは簡単で、go getするだけ。 1 $ go get github.com/jessevdk/go-assets-builder インストールできたら、次のように使う。 1 2 3 $ ls assets/ foo.html.tmpl bar.png $ go-assets-builder assets -o assets.go すると、assetsディレクトリの内容が埋め込まれたassets.goが生成される。今回は特にパッケージ名を指定していないのて、package mainとして作成された。必要なら-pオプションでパッケージ名を指定することもできる。 生成されたあとは、実際に使いたいソースコード内で次のように使う。 1 2 3 4 f, _ := Assets.Open("/assets/foo.html.tmpl") // in production, need to handle error defer f.Close() // Do something with f ここで作成されたfはos.Fileと同じインターフェースを備えている。要するに、os.Openを使用したときと同じように操作することができる。 また、Assetsという変数を別に使いたいときは、go-assets-builderでパッキングするときに-vオプションで変数名を指定することもできる。ディレクトリ全体ではなく、個別のファイルを指定することもできる。

2019-01-17 · nasa9084

きちんとやるnet/http

皆さん、net/httpパッケージは使っていますか? Go言語の標準パッケージであるnet/httpはPythonなどの標準HTTPパッケージに比べ、人間にとっても取り扱いがしやすいため、そのまま使用している方が多いかと思います。 しかし、このnet/httpパッケージ、簡単に使えるように見えて結構落とし穴が多いのです。 1. Response Bodyはクローズする必要がある 次のコードを見てみましょう。 1 2 3 4 5 6 7 8 9 resp, err := http.Get("https://example.com/api") if err != nil { return nil, err } var t T if err := json.NewDecoder(resp.Body).Decode(&t); err != nil { return nil, err } return &t, nil クライアントライブラリなどでよく書きそうな処理ですね。何も問題ないと思いましたか? 公式ドキュメント を見てみましょう。 It is the caller’s responsibility to close Body. Bodyをクローズするのは関数を呼んだ人の責任、とあります。そうです。Response.Bodyは Close()しなければならないのです。ちゃんとクローズされていない場合、次のリクエストでkeepaliveコネクションの再利用がされず、パフォーマンスの悪化やコネクションリークを起こす可能性があります。 2. Response Bodyを最後まで読む Response Bodyをきちんとクローズするように修正したコードが次のようなコードです。 1 2 3 4 5 6 7 8 9 10 resp, err := http.Get("https://example.com/api") if err != nil { return nil, err } defer resp.Body.Close() var t T if err := json.NewDecoder(resp.Body).Decode(&t); err != nil { return nil, err } return &t, nil deferを使うことできちんとクローズできているはずです。 さて、問題はないでしょうか?いいえ、これだけだとまだkeepaliveコネクションの再利用がされない恐れがあります。 ...

2019-01-08 · nasa9084

gitにもaliasの指定ができる件

tl;dr .gitconfigにもaliasの登録ができる [alias]ブロックにaliasを登録する tagsで単数・複数の悩みを解消する discardで変更を取り消す unstageでaddを取り消す uncommitでcommitを取り消す ignoreで.gitignoreを生成する git aliases この記事は今すぐalias登録すべきワンライナー by ゆめみ① Advent Calendar 2018 の6日目の穴埋め記事です。 こちらのアドベントカレンダーは今すぐalias登録べきワンライナーということで、みなさん.bashrcや.zshrcのaliasについて記事を書いてらっしゃいますが、実は.gitconfigという、gitコマンドの設定を書いておくファイルにもaliasの指定ができます。 誰もshellのaliasとは言ってない!(・・・はず)ので、いくつか.gitconfig用に便利なaliasを紹介していきましょう aliasの登録方法 .gitconfigは基本的にiniファイルです。そのため、次のように登録します。 1 2 3 [alias] aliasname1 = some command 1st aliasname2 = some command 2nd 簡単ですね? [alias]というブロックを作成し、alias名=コマンドの形で記述します。 このときコマンドはgit xxxの形で実行される、xxxの部分のみを指定します。 例えば、 1 2 [alias] stat = git status と指定すると実際の実行時にはgit git statusという形で実行されてしまいエラーになるので注意しましょう。 gitのつかないコマンドを実行したい場合は頭に!をつけます。 1 2 [alias] ls = !ls このように記載すると、git lsでlsが実行されます。 git tags git tagというコマンドがありまして。まぁみなさんご存知でしょうが、tagの一覧を出したり、新しいtagを作ったりするコマンドです。これ単体では特に問題がないのですが、リモートリポジトリと合わせて使うと、ちょっと悩みが発生します。 git tagコマンドでタグをつけた後、リモートリポジトリにpushするときのコマンドはgit push --tagsです。これはtagをまとめてpushするので、複数形なんでしょう。しかしです。tagの一覧を出すときに使うのもgit tagと単数形なんですね。 ついついgit tagsと打ってしまいませんか? そんなあなたはこんなaliasを登録しておきましょう 1 2 [alias] tags = tag 地味ですが、これで単数形か複数形か悩まずに済みます。 ...

2018-12-12 · nasa9084

git repositoryの初期化ルーチン

おそらくみなさんもgit repositoryを作る時、毎回だいたい同じような手順で初期化をするのではないでしょうか。 メモがてら、自分の初期化ルーチンをまとめておきます tools 使用しているツールは以下の通り: hub : .zshrc でgitコマンドにエイリアスを張ってます gitignore.io : 先日記事を書いたように 、git ignoreコマンドとして使ってます git-license : 自作のサブコマンドです routine 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 新しいリポジトリ用のディレクトリを作成 $ mkdir new-repository $ cd new-repository $ git init # GitHub上にnasa9084/new-repositoryリポジトリを作成 # hubコマンドの機能 $ git create # まずは空の状態で初回コミット $ git commit -m 'initial commit' --allow-empty # .gitignoreを作成(今回はgo言語プロジェクト向け) $ git ignore emacs,macos,go > .gitignore $ git add .gitignore $ git commit -m 'add .gitignore for emacs,macos,go' # LICENSEを作成 $ git license -u nasa9084 mit > LICENSE $ git add LICENSE $ git commit -m 'add MIT License' $ git push -u origin master ここまでがルーチンで、ここからMakefileを作ったり開発したりします。 ...

2018-12-07 · nasa9084

x/crypto/openpgpでデータを暗号化する

OpenPGPはPGP(Pretty Good Privacy)をベースとした暗号化フォーマットです。 Go言語でもgolang.org/x/crypto/openpgp という準標準パッケージで提供されています。 PGPは公開鍵暗号としてメールの暗号化等でよく使用されますが、パスフレーズを用いた対称暗号として使用することもできますので、今回はこちらを紹介します。 TL;DR 暗号化にはSymmetricallyEncrypt()を使用する 復号にはReadMessage()を使用する prompt次第で無限ループする恐れがあるので注意 暗号化 x/crypto/openpgpパッケージでパスフレーズを用いてファイルを暗号化するには、SymmetricallyEncrypt関数を使用します。 シグネチャは次のようになっています。 1 func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) 順番に見て行きます。まずは引数から。 第一引数であるciphertextには、暗号化されたテキストを出力するio.Writerを与えます。*os.Fileなどを与えてもいいですが、*bytes.Bufferなどを与えてその後*os.Fileにコピーする方が良いでしょう。可読なテキストではなく、バイト列が出力されます。 第二引数のpassphraseはその名の通り、パスフレーズを与えます。 第三引数のhintsには暗号化するファイルのメタデータなどを含むことができますが、単純にnilを与えても良いです。 第四引数のconfigで暗号化方式や乱数エントロピーソース、圧縮アルゴリズムなどを設定することができます。設定しなければ乱数としてcrypto/rand.Readerが、ハッシュ関数としてSHA-256が、暗号化関数としてAES-128が、現在時刻としてtime.Nowが、RSAのビット数として2048がそれぞれ使用されます。圧縮はされません。 返り値は二値で、io.WriteCloserとerrorです。返り値のio.WriteCloserに暗号化したい内容を書き込むことで暗号化が行われます。必ずCloseする必要があるので忘れないように注意しましょう。 使用例 1 2 3 4 5 6 7 8 func encrypt(in io.Reader, out io.Writer, passphrase []byte) error { // omit error handling w, _ := openpgp.SymmetricallyEncrypt(out, passphrase, nil, nil) defer w.Close() io.Copy(w, in) return nil } 復号 暗号化したファイルを復号するには、ReadMessage関数を使用します。Decrypt〜のような関数ではないので注意が必要でしょう。関数のシグネチャは次のようになっています。 1 func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (*MessageDetails, error) こちらも順に見て行きましょう。 第一引数のio.Readerには暗号化されたファイルを与えます。読み込みですから、*os.Fileを直接与えてもいいかもしれません。 第二引数は復号に使用する鍵へのKeyRingですから、パスフレーズで暗号化した今回はnilを与えます。 第三引数であるpromptがこの関数の肝で、パスフレーズを返すコールバック関数を与えます。PromptFunctionの定義は次のようになっています。 1 type PromptFunction func(keys []Key, symmetric bool) ([]byte, error) 今回の用途の場合は引数を使用する必要はありません。基本的には単純にパスフレーズを返す関数とするか、標準入力等からパスフレーズを読み込んで返す、という関数として作成すれば良いでしょう。 一点だけ注意点があり、ドキュメントに次のような記載があります。 If the decrypted private key or given passphrase isn’t correct, the function will be called again, forever. ...

2018-11-26 · nasa9084

Generator Pattern

Generator PatternはGo言語における並列処理パターンの一つで、goroutine-safeな値列の生成などに使用することができます。 コードを見た方が早いと思いますので、コードを掲載しましょう。 次の例は複数のgoroutineから共通の連番を採番したいときに利用することができます。 1 2 3 4 5 6 7 8 9 10 11 12 13 func GenInt(ctx context.Context, max int) <-chan int { ch := make(chan int) go func() { defer close(ch) for i := 0; i < max; i++ { select { case <-ctx.Done(): return case ch <- i: } } return ch } 返された<-chan intからintの値を取得するようにすることで、重複のない連番を取得することができます。 Go言語において、chanは複数箇所から値の取り出しを行うことができますが、chanに入力された一つの値はどこか一箇所からしか取り出すことができません。そのため、lock等を使用しなくとも、必ず重複無く連番を取得することができます。 lockを使用した場合、若干動作が遅いため、可能であればlockを使用しないで、chanを使用して実装できるとより高速な、Goらしいコードとすることができます。

2018-11-21 · nasa9084

LINE DEVELOPER DAY 2018に参加した

LINE DEVELOPER DAY 2018 はLINEの技術に関して紹介するイベントで、2018年11月21日に開催されたので、参加してみました。 開催地は白金台の八芳園です。初めて来たのですが、厳かな日本庭園なんですね。ちょっと気後れしてしまいます。 八芳園の入り口にはDEVELOPER DAYのロゴ入り暖簾が下がっていました。 会場の建物に向かうには庭園を抜ける必要があり、八芳園を少しですが楽しめるのはなかなか良かったように思います。 受付は外にあり、非常に良い雰囲気でした。雨だったとしても建物の中でやれる様なプランはあったのでしょうが、雰囲気が大きく変わっていたと思いますので、雨じゃ無くて良かったですね。 GitHubのイベントに行ったときなんかも思ったのですが、会場の壁でこういうことをできるのは企業主体のカンファレンスのすごいところだなーと思います。 これだけで雰囲気が結構違うとは思うんですが、コミュニティ主体だとここにお金をかける意味はあんまり無いので、やろうという話にもならないことが多い気がします。 写真を撮った時点ではまだオープニングセッションの最中だったので稼働はしていなかったのですが、会場では通常の発表の他、ポスターセッションも行われるようでした。 カメラを向けても止まってはくれなかったのでちょっとぶれちゃってますが、歴戦のカンファレンススタッフであるとりいさんもスタッフ参加とのこと。 LINE DEVELOPER DAY 2018は参加費無料で、約1300人の動員(予定)だそうです。

2018-11-21 · nasa9084

git ignoreコマンドで.gitignoreを取得する

割とみんな知ってるのかもしれないですが。 git-xxxという名称で実行可能ファイルをパスの通ったところに配置すると、git xxxというgitのサブコマンドの形で実行することができるようになります。これを利用したのが拙作git-license で、git license [option] license_name > LICENSEの形で実行するとLICENSEファイルを簡単に作成することができます。 その他、git configでエイリアスを指定して、サブコマンドとして登録することも可能です。 同様にして、git ignoreで`.gitignoreファイルを簡単に取得できるようにしてみましょう。 おそらく現代では多くの人が.gitignoreの生成やテンプレート化をして、あるいはテンプレート化されたものを利用しているのではないでしょうか。GitHubのWUI上でリポジトリを作成するときにも生成することができますし、そのさい使用される.gitignoreファイルとしてgithub/gitignore が提供されています。 今回紹介するのはgitignore.io というサービスです。 gitignore.ioはその名の通り、.gitignoreファイルを生成するサービスです。 基本的な使い方は非常に簡単で、ブラウザでアクセスして、テキストボックスに必要な言語、OS、エディタやIDEなどを指定していくだけです。指定が終わったらCreateボタンを押すことで、選択した対象用の.gitignoreテンプレートを全て含んだ.gitignoreファイルが作成されます。これを保存すれば良いですね。 しかし、その他の作業をコマンドラインから行なっていると、いちいちブラウザでアクセスして、マウスで操作して・・・というのが非常に面倒に感じます。 大丈夫です!gitignore.ioではもちろんAPIを提供しています(というか、WUIで生成された.gitignoreのURLがそのままAPIのURL)。 次のように実行してみます。 1 $ curl https://www.gitignore.io/api/go,emacs,macos https://www.gitignore.io/api/の後ろに、カンマ区切りで必要なものを列挙して行くだけで、簡単にコマンドラインから.gitignoreファイルを取得できます。 ここまでやったらもう少し簡単にしたいですね?いちいちURLを打つのは面倒ですし、忘れてしまうかもしれません。せっかくなのでgitのサブコマンドとしてgit ignoreとできるようにしてみましょう。次のコマンドを実行してみます。 1 $ git config --global alias.ignore '!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi' もしくは、~/.gitconfigファイルの[alias]のセクションに次のように設定しても良いでしょう。 1 2 [alias] ignore = !curl -L -s https://www.gitignore.io/api/$@ $@は引数をそのまま渡すという変数です。このように設定をすることで、git ignoreとしてgitignore.ioのAPIを利用することができるようになります。実際に使用する時は次のように使用します。 1 $ git ignore go,emacs,macos 言語や環境のリストは全てまとめて一つの引数のため、カンマの後にスペースを入れないことに注意です。指定できる環境の一覧はgit ignore listとすることで表示できます。 標準出力をそのままリダイレクトして、.gitignoreファイルに書き込めばプロジェクトの初期設定として使用できるでしょう。

2018-11-13 · nasa9084

jessevdk/go-flagsでサブコマンドを実装する

Go言語を用いてコマンドラインツールを開発する際、皆さんはフラグのパースやサブコマンドの実装にどんなパッケージを使用していますか?標準のflagパッケージのほか、、spf13/cobra 、alecthomas/kingpin などもよく使われているようです。 私は専ら、jessevdk/go-flags (以下go-flags)を使用しています。 go-flagsはその名の通り、基本的にはオプション/フラグの解析用パッケージで、ドキュメント もフラグ解析に関するものがほとんどです。 しかし、go-flagsでは、サブコマンドの実装も可能です。今回はこれに焦点を当ててご紹介していきます。 go-flagsでは、親コマンドにサブコマンドを登録する、という形でサブコマンドを実装していきます。サブコマンドは構造体として実装し、それぞれがオプションを格納する構造体を兼ねる形となります。 終端の、実際に何かの動作をするコマンドは Commander interfaceを実装している必要がありますが、中間のサブコマンド(docker containerのような、グルーピングのためのサブコマンド)はこれを実装していなくても構いません。 Commander interfaceの定義は次のようになっています。 1 2 3 type Commander interface { Execute(args []string) error } 非常に単純ですね。argsにはコマンドでパースされなかったあまりの引数が渡されます。 実際の実装例を見てみましょう。 1 2 3 4 5 6 7 8 type subcommand struct { verbose bool `short:"v" long:"verbose"` } func (cmd *subcommand) Execute(args []string) error { // some exec return nil } サブコマンドを実装したら、親のコマンドにサブコマンドとして登録します。 ドキュメントを見ると、Command構造体に登録する関数があること、Parser構造体はCommand構造体が埋め込まれていること、がわかります。 通常、go-flagsパッケージを使用する場合はパッケージグローバルのParse関数を使用することが多いと思うのですが、サブコマンドを実装する場合はトップレベルのパーサーを自分で作る必要があります。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 type options struct { // ... } var opts options // global option var parser = flags.NewParser(&opts, flags.Default) var subcmd subcommand func init() { parser.AddCommand("subcmd", "subcommand", "", &subcmd, ) } func main() { if _, err := parser.Parse(); err != nil { if fe, ok := err.(*flags.Error); ok && fe.Type == flags.ErrHelp { os.Exit(0) } log.Print(err) os.Exit(1) } } このように登録することで、subcmdという名前のサブコマンドが使用できるようになりました。go run main.go subcmdなどとすると、subcommand.Execute関数が実行されます。 実際にはParser.AddSubCommandのエラーをハンドリングしたりなど、もう少しやらなければならないことはあると思いますが、基本的には以上です。 ...

2018-11-06 · nasa9084

Ergodox EZを購入した

割と今更感もなくはないのですが、Ergodox EZという分割キーボードを購入しました。 Ergodoxは基本的には自分でパーツを揃えて組み立てる、いわゆる自作キーボードの一つですが、オープンソースで設計などが公開されており、その設計を使って完成品を販売しているのがErgodox EZです。 今回は公式サイト から購入しました。 構成は次のようなものです。 Color: BLACK Tilt kit/Wing Rest: YES Keycap: Blank Switches: Cherry MX Blue 以上で$325、日本円で37,125円でした。送料がかかるという情報も多かったのですが、送料は無料で、関税が2000円ちょいくらいかかりました。 wing restの箱は凹んでいました。。。 まぁ、ペラッペラのビニールだけの状態で渡航して来たので、こんなものでしょう。 箱自体はしっかりしており、多少凹んでも中の本体には影響ありませんでした。 いつ使うのかよくわからないワッシャーと、キートップ・スイッチの交換に使う道具、謎のステッカーがついていました。 web上には日本語の情報がなく、ごく最近のことだと思うのですが、現在販売されているErgodox EZにはCIY という機構が組み入れられています。キースイッチが半田付けされておらず、いわゆるソケットのようなものに刺さっているため、自分でキースイッチを交換できる、というものです。 このため、自作のErgodoxか、キーボードの故障を覚悟の上での改造のみで可能だった、一部のキースイッチのみ交換する、などが簡単に行えるようになっています。 現在は会社で使っています。 やはりエンターキー周りがなれず、slackでちょいちょい誤爆しますね。 できるだけJIS配列に近づけた構成にしており、現在のファームウェアはnasa9084/qmk_firmware のdevelopブランチで管理しています。 今の所レイヤーはうまく使いこなせていないため、いいかんじの知見があれば教えてほしいところです。 ファームウェアのコンパイル時、arch linuxの場合、sudo pacman -S avr-libcする必要があったほか、macosの場合、brew install avr-gccする必要があったのですこしハマりました

2018-10-31 · nasa9084