Realize が Go 1.11 の Modules で使えない

去年、 [[Go] Realizeが便利なので、もう少し仲良くなってみる](https://qiita.com/enta0701/items/9f60ad18600acab8c93d) という記事を公開してから今でもたまにいいねしていただけるのですが、ホットリロードツールとしては本当に realize は使いやすいですよね。

※ もうこの時点で 「いや、こっちのツールのほうがいいよ」 などありましたら、ぜひコメントで教えていただけると泣いて喜びます :pray: 

しかし、 Go 1.11 から組み込まれた Modules を使おうとすると realize は動かなくなってしまいます。
本記事では、この原因を探しにいった旅行記になります。

## 発生した問題

`realize init` コマンドを打つと、 `.realize.yaml` というファイルが生成されます。
このファイルを元に、監視するファイルの絞り込みや、変更されたときに Before/After で行うコマンドの指定など、さまざまなオプションを指定することができます。

例えば、.go のファイルを監視して変更がされた場合に、再度 `go run ...` をさせたい場合は、以下のように設定します（一部抜粋）。

```yaml
...
schema:
  watcher:
    extensions:
    - go
  commands:
    run:
      status: true
...
```

ところが、 `GO111MODULE=on` では realize の起動ができなくなってしまいます。

```bash
$ realize start
[09:38:37][MYAPP] : Watching 0 file/s 0 folder/s
[09:38:37][MYAPP] : Build started
[09:38:37][MYAPP] : Build
 exec: not started
```
この原因を探っていきます。

## Issue はあるのか

### [Go module support](Go module support #207)

> とりあえず、Gopkg.toml を go.mod と go.sum に置き換えたら？

んーそうじゃないんだよな…

### [Cannot do `--run` with go1.11 using go mod under windows. ](https://github.com/oxequa/realize/issues/217)

Windows に限った話ではなく、 Mac / Linux でも起きてるよー、とのこと。
ただ、根本的な原因が見えなかったので、直接コードを見ることにしました。

## コードを読む

### realize.go

とりあえず `main` パッケージから読み始めます。

まずは `realize start` してる部分を探します。
CLI パッケージは `gopkg.in/urfave/cli.v2` を使ってるみたいですね。


```go
Commands: []*cli.Command{
	{
		Name:   "start",
		...
		Action: start,
	},
```

プライベート関数 `start` を呼んでるので、次はそちら。
いろいろ書かれていますが、最後の `return r.Start()` の先にありそうですね。

### cli.go

見る限り、goroutine で複数のプロジェクトを監視できるようにしてるみたいですね。
複数プロジェクトをまたいだ開発や、そもそも設定でプロジェクトのパスを設定できるため、リポジトリ内には `.realize.yaml` を含めない、みたいなことも可能だそうです。


```golang
// Start realize workflow
func (r *Realize) Start() error {
	if len(r.Schema.Projects) > 0 {
		var wg sync.WaitGroup
		wg.Add(len(r.Schema.Projects))
		for k := range r.Schema.Projects {
			r.Schema.Projects[k].exit = make(chan os.Signal, 1)
			signal.Notify(r.Schema.Projects[k].exit, os.Interrupt)
			r.Schema.Projects[k].parent = r
			go r.Schema.Projects[k].Watch(&wg)
		}
		wg.Wait()
	} else {
		return errors.New("there are no projects")
	}
	return nil
}
```

次は、 `r.Schema.Projects[k].Watch(&wg)` 関数を辿ってみます。

### projects.go

```golang
// Watch a project
func (p *Project) Watch(wg *sync.WaitGroup) {
	...
	// before start checks
	p.Before()
	// start watcher
	go p.Reload("", p.stop)
	...
```

コメントがありがたいですね。 `p.Before()` この辺が怪しそうです。


```golang
func (p *Project) Before() {
	...
	if hasGoMod(Wdir()) {
		p.Tools.vgo = true
	}
	...
	// setup go tools
	p.Tools.Setup()
	// global commands before
	p.cmd(p.stop, "before", true)
	// indexing files and dirs
	for _, dir := range p.Watcher.Paths {
		base, _ := filepath.Abs(p.Path)
	...
```

`hasGoMod(Wdir())` で `p.Tools.vgo` が True になっている。
Go1.11 なら `go mod ...` で良いんじゃなかったっけ…？

`Wdir()` は  Working ディレクトリを返します。
では、 `hasGoMod()` は？

### utils.go

```golang
func hasGoMod(dir string) bool {
	filename := path.Join(dir, "go.mod")
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		return false
	}

	return true
}

```

ははーん。 `go.mod` があると、 `vgo` は True になるんですね。
もしや…

### tools.go

ありました。
`projects.go` の `Before()` 内にある `Setup()` で以下のように書かれていました。

```golang
// Setup go tools
func (t *Tools) Setup() {
	var gocmd string
	if t.vgo {
		gocmd = "vgo"
	} else {
		gocmd = "go"
	}
	...

	t.Install.name = "Install"
	t.Install.cmd = replace([]string{gocmd, "install"}, t.Install.Method)
	t.Install.Args = split([]string{}, t.Install.Args)
	...
```

つまり **Go Modules には対応していない** みたいです。


## まとめ

「お、これは PR チャンスなのでは？」
「いや、そもそもここまで書いてるんだったら、PR 出してマージされましたーぐらいまで話もってこいや」

と思われる方もいらっしゃるでしょう。

しかし、[Cannot do `--run` with go1.11 using go mod under windows. ](https://github.com/oxequa/realize/issues/217) や、他のいくつかの Issue をご覧になった方はすでに把握していると思うんですが、数日前のコメントで

> thanks for the support and for the reports, in the last months we had some company changes but in the first trimester 2019 we will release a new version

> レポーティングありがとー。2019年の第一期に新しいバージョン出すね。

とのこと。
1.12 から `GO111MODULE=on` の挙動が標準になるらしい点も踏まえると、もうちょっと待ってみてもいいかな…それでもだめなら他のツールか、もしくは自作してみるのもありかもしれない。

明らかに間違っている情報などありましたら、コメント等でいただけますと幸いです。

[2019/05/12 追記]
@taiba さんより、 [Cannot do `--run` with go1.11 using go mod under windows. #217](https://github.com/oxequa/realize/issues/217) の [コメント](https://github.com/oxequa/realize/issues/217#issuecomment-459198990) で解決策が提示されていると教えていただきました。