Go modules利用時にvscode-goのinferGopathが無効化される理由
環境
事象
- vscode-goにはワークスペースやユーザ毎に
$GOPATH
を推測するgo.inferGopath
というオプションがあり、自分は常に有効化している(VSCodeでGoのデバッグにも以前に書いた) - しかし、Go modulesを使用しているディレクトリ(go.modが配置されている)をVSCodeで開くと下記のエラーが表示された
The "inferGopath" setting is disabled for this workspace because Go modules are being used.
原因
- Go modulesを使用している場合は
$GOPATH
の設定が不要だから - Go modulesを使用する利点の1つは
$GOPATH
を通さず、$GOPATH
配下外に作成されたディレクトリ上で外部の依存パッケージを扱えること- しかし、Goの
import
は$GOPATH/src
や$GOROOT
からパッケージを探す仕様だったはず...- ちなみにgo.modが直下になるように
$GOPATH
を設定すると$GOPATH/go.mod exists but should not
とエラーが表示される
- ちなみにgo.modが直下になるように
- 自分で定義したパッケージをimportするときはどうすればいいのか?
- しかし、Goの
Go modules使用時に自分で定義したパッケージをimportしたい
- 答え:User-written packages fail to import with go.mod. GO111MOD=on
go.modのモジュール名/パッケージ名
でimportできる- 結局、importからは
$GOPATH/src/モジュール名
に見えているっていう理解でいいのかな... - ちなみにモジュール名は実際のディレクトリ名と異なっていても良い模様
- 結局、importからは
その他
使用しているAlfred Workflows一覧
環境
- Alfred 4.0.3
Alfred Powepackを利用している場合は2台のMacでAlfredの設定を同期することも可能(ドキュメント)だが、1台からの片方向同期かつWorkflowsだけを同期するのは難しそうなので、業務で使用するMacとは手作業で同期を行うことにしようと思った。(JIRAチケットへのジャンプ等、業務でしか使わない設定も少なくないので...)
今後も良さそうなWorkflowsがあったら、このドキュメントに追加していく。
Workflows
(自作)フォルダを検索してターミナルで開く
- filefilter(public.folder) → Browse in Terminal
Docker Compose上で起動したwebpack-dev-serverに設定されたプロキシが動作しなくてハマった話
環境
- macOS 10.14.4
- docker-compose version 1.23.2
- webpack-dev-server 3.7.2
- webpack 4.37.0
フロントエンド(webpack-dev-server)、バックエンドをそれぞれDocker Compose上にコンテナとして起動して開発していた際にハマったお話。
事象
webpack-dev-serverはホストするjs内で発行されるHTTPリクエストをプロキシすることができる
webpack.config.js
を以下のように設定(抜粋)- APIサーバーは5000番ポートを開いているとする
devServer: { contentBase: path.join(__dirname, 'dist'), compress: true, port: 8080, historyApiFallback: true, proxy: { '/api': 'http://localhost:5000', }
- 上記設定を反映したwebpack-dev-serverを起動し(
docker-compose up
)、実際にlocalhost:8080にアクセスしてfetch('/api')...
をブラウザから実行すると、webpack-dev-serverが以下のエラーを出力した
[HPM] Error occurred while trying to proxy request /api from localhost:8080 to http://localhost:5000 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)
- httpレスポンスは以下(抜粋)
504 Gateway Timeout Error occured while trying to proxy to: localhost:8080/api
原因
Docker Compose上のコンテナが参加するネットワークでは、
docker-compose.yml
上のサービス名で名前解決が行われるため。従って、
webpack.config.js
を下記のように書き換えると上手くいく
... proxy: { '/api': 'http://api:5000', }
- なお、
docker-compose.yml
では以下のようにサービス名をapi
としている
version: "3.4" services: api: build: context: ./api ...
敗因
- 書いてみるとこれだけのことだが、多分2,3時間ぐらいハマっていた
- サービス名で名前解決ができること自体はDocker Composeのドキュメントに書いてあることだし、以前から知っていた。なぜ気づけなかったのか...
- 多分だが、ブラウザからDocker Compose上のwebpack-dev-serverにアクセスする際は、
- のでwebpack-dev-serverが動作しているのがDocker Compose上であることを忘れていたというか、しっかり認識できていなかったような気がする。
- また、Docker Compose上のネットワーク内のコンテナ間もlocalhostで通信できるようなイメージだったのも原因かもしれない。
- あと、ステータスコード504 Gateway Timeoutの理解が不足している感もある。webpack-dev-serverがlocalhost:5000が存在しないためにレスポンスを得られない→ポート5000で動作しているはずのHTTPサーバーのログを確認する→ログがない→接続先がおかしい?というような手順をスムーズに踏めたら良かった。
- Goで書いているHTTPサーバは外部ファイルへのログ出力を未実装で、結局調査のために書いたんだけど、ここを面倒くさがらずに早く実行するべきだったかな...
bashコマンドは読取権限のあるファイルなら処理できる
環境
Permission denied
$ touch hoge.sh && ./hoge.sh
するとbash: ./hoge.sh: Permission denied
になる- 実行権限がない
- しかし
$ touch hoge.sh && bash hoge.sh
は正常終了するのはなぜか?
読取権限
httptest.Serverとhttptest.ResponseRecorderの使い分け
環境
httptest.Serverとhttptest.ResponseRecorder
- ServerとResponseRecorderは何が違うのか?どう使い分けるのか?
- 答え:When to use httptest.Server and httptest.ResponseRecorder
httptest.Server
- httptest.Serverは外部のHTTPサーバと通信を行うコードをテストするために利用する(外部APIの挙動のエミュレート)
- クライアント-サーバモデルで言うと、テストしたい対象がクライアントの場合に相当する模様
httptestパッケージより引用
package main import ( "fmt" "io/ioutil" "log" "net/http" "net/http/httptest" ) func main() { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, client") })) defer ts.Close() res, err := http.Get(ts.URL) if err != nil { log.Fatal(err) } greeting, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) } fmt.Printf("%s", greeting) }
httptest.NewRecorder
- httptest.NewRecorderは純粋にHTTPリクエストに対するハンドラーの動作をテストするために利用する
- 例えばHello worldを返すだけのWebサーバのコードを書いた場合のテストコードはhttptest.NewRecorderで十分
httptestパッケージより引用
package main import ( "fmt" "io" "io/ioutil" "net/http" "net/http/httptest" ) func main() { handler := func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "<html><body>Hello World!</body></html>") } req := httptest.NewRequest("GET", "http://example.com/foo", nil) w := httptest.NewRecorder() handler(w, req) resp := w.Result() body, _ := ioutil.ReadAll(resp.Body) fmt.Println(resp.StatusCode) fmt.Println(resp.Header.Get("Content-Type")) fmt.Println(string(body)) }
関連:NewRecorderを利用する場合にserveHTTPを使用する必要があるのか
http.HandlerFunc(articlesHandler).ServeHTTP(rr, req)
してレスポンスを検証している例もある- 例えばTesting HTTP handlers in Goや他の書籍のサンプルコードにもあった
- マルチプレクサ経由でhandlerを呼び出している(HandleFuncはマルチプレクサ(ServeMux)を返し、ServeHTTPはマルチプレクサに登録されているパターンにマッチするハンドラを呼び出す)
- 結局テストコード中でハンドラを登録しているなら初めからServerを使うか、ハンドラの処理だけにフォーカスするかした方が良いのではないか?(Goのhttpパッケージをテストしたいわけではない)
参考
draw.ioで両端が矢印の線を引く方法
AWSの構成図をdraw.ioで描いていて、両端が矢印の線を引く方法が分からなかった。もう諦めてCacooを使おうかと思っていたところ解決策が見つかった。
How to create a bidirectional arrow? : draw.io Helpdesk
ちなみに上記で操作しているサイドバーはcmd+shift+p
で表示できる(Macの場合)
VSCodeでGoのデバッグ
今更感はあるがVSCodeでGoのソースコードをデバッグしてみたので記録。
環境
delveインストール
VSCodeにテスト対象の$GOPATHを認識させる
- 方法は複数あるが、VSCodeのworkspaceディレクトリを自動的に$GOPATHとして認識してくれるようにするのが1番手軽そう
- settings.jsonに
"go.inferGopath": true
を追記 - stackoverflow.com
- settings.jsonに
launch.jsonを作る
- テスト対象のプロジェクトをVSCodeで開き、[構成の追加]をクリック(画像は既に構成追加済み)
- launch.jsonが作成される(作成済みの場合は追記される)
{ // IntelliSense を使用して利用可能な属性を学べます。 // 既存の属性の説明をホバーして表示します。 // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Launch", "type": "go", "request": "launch", "mode": "auto", "program": "${fileDirname}", "env": {}, "args": [] } ] }
"program": "${fileDirname}",
は開いているファイルが属するパッケージをテスト対象にする- その他の設定値に関する説明はDebugging Go code using VS Code · microsoft/vscode-go Wiki · GitHubを参照
デバッグする
- breakpointを置く
- テストコードの[debug test]をクリックする。テストメソッド単位で実行できる。
- breakpointの位置で処理が止まる。テストメソッドの中でも止められるし、テストメソッドから呼ばれた先のメソッドの中でも止められる。
- これでテストが通らなくなった場合の原因調査がスムーズに
まとめ
- VSCodeでソースコードのdebugを行う際は、launch.json等の設定ファイルへの習熟が必要な印象があったが、Goの場合はあまり考えることがない
- delveは必要だったが、それ以外はVSCodeとGo本体というシンプルな構成でデバッグ可能
Goやっていきましょう