在文件更改时自动重新编译和重新加载服务器

Posted

技术标签:

【中文标题】在文件更改时自动重新编译和重新加载服务器【英文标题】:Go Auto-Recompile and Reload Server on file change 【发布时间】:2013-11-05 11:18:15 【问题描述】:

我知道 AppEngine 会这样做,但我不会为它编写代码。

我尝试使用来自 Ruby 世界的 Guard 来监听 .go 文件的变化,并执行以下命令:

killall foo
go build -race
./foo &

但它从不将foo 发送到后台,它只是无限期挂起。

你们是如何解决这个问题的?解决方案也必须是跨平台的(GNU/Linux 和 Mac)。

【问题讨论】:

不是真正的“Go”问题,你试过了吗:nohup ./foo > /var/log/foo/out.log & @MartinGallagher 谢谢,它有效。 【参考方案1】:

一位朋友为 go 编写了一个简单的编译守护程序,对我自己的小型网络/http-projects 来说就像一个魅力。

您可以在此处找到存储库:https://github.com/githubnemo/CompileDaemon

【讨论】:

看起来它不运行二进制文件,它只构建它们。还有其他解决方案可以帮助我们完成剩下的工作吗? 这是旧答案,但 CompileDaemon 也使用CompileDaemon -command="./MyProgram -my-options" 运行它 编译守护进程很好,但据我了解,它无法在没有构建的情况下运行命令。在某些情况下,您只需要运行“go run ./my_app”而不先构建它。在这种情况下,编译守护进程是无用的。【参考方案2】:

您也可以试试 Codegangsta 的 Gin。火了就忘了。

https://github.com/codegangsta/gin

编辑: 我现在更喜欢CompileDaemon。 Gin 有时不接受请求

【讨论】:

【参考方案3】:

我最近发现了一个reflex 工具。它速度很快,而且效果很好。它与nodemon(来自nodejs world)和guard(来自ruby world)非常相似。

大部分时间我都在使用它,如下所示:

reflex -d none -s -R vendor. -r \.go$ -- go run cmd/server/main.go

但是将它的选项放在像 .reflex 这样的文件中可能更方便,其内容如下:

-d none -s -R vendor. -r \.go$

那么你就这样运行它

reflex $(cat .reflex) -- go run cmd/server/main.go

你可以对“热重载”测试做同样的事情:

reflex $(cat .reflex) -- go test ./... -v

还有一个配置选项,您可以在其中指定同时运行的多个命令,但我并没有真正使用它。

【讨论】:

看来reflex(现在)可以直接读取配置文件了。您的第三个示例可以重写为reflex -c .reflex -- go run cmd/server/main.go 感谢@ESV,没有注意到这种变化,很高兴知道这一点。 而且它仅适用于 Linux。 :( 好吧,它也适用于 OSX,不过从未尝试过 Windows。【参考方案4】:

如果有人还在寻找解决方案,我编写了一些 shell 脚本来执行此操作,并且可以通过 docker 环境使用它,repos at https://github.com/zephinzer/golang-dev

【讨论】:

【参考方案5】:

您可以为此使用nodemon。只需创建一个 nodemon.json 文件,其中包含您的配置、要监视的文件、要忽略的文件以及文件更改时要执行的命令。类似这样的配置。

nodemon.json


  "watch": ["*"],
  "ext": "go graphql",
  "ignore": ["*gen*.go"],
  "exec": "go run scripts/gqlgen.go && (killall -9 server || true ) && go run ./server/server.go"

您确实需要 nodejs 才能使其工作。 但它比我迄今为止使用的任何其他特定工具都要好。

【讨论】:

这是救命稻草,谢谢。使用 nodemon 比标准的 appengine 文件观察器要好得多。这是对我感兴趣的“python dev_appserver.py app/--automatic_restart=no”的 exec 命令【参考方案6】:

在 GO 世界中有 2 个主要竞争者 freshglide

但我会选择Fresh https://github.com/gravityblast/fresh

【讨论】:

为什么选择fresh 而不是glide?是什么让您比CompileDaemonreflex 更有吸引力?【参考方案7】:

在互联网上滚动寻找一个使用标准 linux 工具(inotify 和 bash)的简单解决方案后,我最终创建了这个简单的 bash 脚本来完成这项工作。

我在运行 golang:1.12 并使用 go run . 提供文件的容器中对其进行了测试。在使用之前阅读脚本,因为它会根据文件夹名称杀死 go run 进程,如果与您运行的其他进程发生冲突,它可能会杀死它们。

#!/bin/bash

go run . &
while inotifywait --exclude .swp -e modify -r . ;
do
    # find PID of the file generated by `go run .` to kill it. make sure the grep does not match other processes running on the system
    IDS=$(ps ax | grep "/tmp/go-build" | grep "b001/exe/main" | grep -v "grep" | awk 'print $1')
    if [ ! -z "$IDS" ]
    then
        kill $IDS;
    fi
    go run . &
done;

【讨论】:

仅当程序在当前目录树中被修改时才有效。如果一个包位于 fs 中的其他位置被修改,这不会重新启动应用程序。这样的smthg更聪明github.com/clementauger/grelot 我喜欢 --exclude .swp... VI 的乐趣。【参考方案8】:

另一个选项,如果你的机器上安装了 nodejs

使用 -g npm i -g nodemon 安装 nodemon

转到您的代码目录并运行:

nodemon --watch './**/*.go' --signal SIGTERM --exec 'go' run cmd/MyProgram/main.go

这将在每次任何.go 文件更改时发送 SIGTERM 并将运行 go run cmd/Myprogram/main.go

完全跨平台。

【讨论】:

但是,正确地安装npm可能会很棘手(并且特定于平台)。 nvm 可能是获取npm 的最佳方式:npm throws error without sudo NPM 是完全跨平台的,如果您将 npm 与 sudo 一起使用,您只是安装错误。 NVM 不解决跨平台问题,它解决了版本控制 就像在节点世界中的魅力一样。 就我而言,我必须使用 -e 指定扩展名:nodemon -e go --signal SIGTERM --exec 'go' run . 完美。正是我想要的【参考方案9】:

我使用了一个名为entr的工具

安装brew install entr (mac) 或者,sudo apt-get install entr (linux)

要重新编译并运行.go 文件更改,请运行以下命令...

ls **/*.go | entr go run main.go

【讨论】:

这个命令的问题是它不能捕获新文件。它只监视初步 ls 中列出的文件。【参考方案10】:

有一个go版本的nodemon:https://github.com/mitranim/gow

go install github.com/mitranim/gow@latest

用法

# Start and restart on change
gow run .

# Pass args to the program
gow run . arg0 arg1 ...

# Run subdirectory
gow run ./subdir

# Vet and re-vet on change; verbose mode is recommended
gow -v vet

# Clear terminal on restart
gow -c run .

# Specify file extension to watch
gow -e=go,mod,html run .

# Help
gow -h

【讨论】:

【参考方案11】:

最好的选择是在你的机器上安装nodejs 并使用nodemon

使用 -g sudo npm install -g nodemon 安装 nodemon 还要使用 sudo 来避免任何写权限

现在转到您的程序目录并运行:

nodemon --watch './**/*.go' --signal SIGTERM --exec 'go' run path-to-the-main-file-of-go-program-with-extension

这将在每次任何.go 文件更改时发送 SIGTERM 并将运行 go run main-go-file-of-program-with-extension

完全跨平台。 这将适用于任何编程语言,只需将命令更改为

nodemon --watch './**/*.extension-of-programming-file-without-preceeding-dot' --signal SIGTERM --exec 'go' run path-to-the-main-file-of-program-with-extension

【讨论】:

以上是关于在文件更改时自动重新编译和重新加载服务器的主要内容,如果未能解决你的问题,请参考以下文章

Angular:防止资产文件夹发生更改时自动重新编译

在 playframework 中重新加载自定义文件更改的应用程序

.NET Core 3.0:Razor 视图不会在更改时自动重新编译

如何让 grails run-app 在文件更改时重新编译它们?

springaop动态加载不同类

如何重新编译 Elixir 项目并从 iex 中重新加载它?