0

我试图grunt watch在我的用户登录我的 OS X 机器时运行,这样我就不必grunt watch每次都手动在我的 $APP_ROOT 目录中运行。

我有以下org.grunt.watch.plist文件/Library/LaunchAgents

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>

    <key>Label</key>
    <string>org.grunt.watch</string>

    <key>RunAtLoad</key>
    <true/>

     <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/grunt-watch-launchd</string>
    </array>

  </dict>
</plist>

/usr/local/bin/grunt-watch-launchd是我创建的一个 shell 脚本:

#!/bin/sh

APP_ROOT=/path/to/htdocs/app
/usr/local/bin/daemon -- /usr/local/bin/grunt watch --gruntfile="$APP_ROOT"/Gruntfile.js > /tmp/grunt-watch-launchd.log 2>&1

该脚本应使用daemon实用程序(与 一起安装brew install daemon)并“守护”该grunt watch命令,该命令依次加载Gruntfile.js配置并启动监视任务。

/usr/local/bin/grunt-watch-launchd当我使用我的用户从 CLI手动运行时,一切正常。我看到一个daemonwith ps aux | grep gruntwhich 运行grunt watch命令。APP_ROOT如果我随后watchGruntfile.js.

但关键是我希望当我用我的用户登录时launchd自动启动。/usr/local/bin/grunt-watch-launchd问题是当我运行时launchctl

launchctl load /Library/LaunchAgents/org.grunt.watch.plist

服务未加载。或者至少,launchd调用脚本(因为我看到文件/tmp/grunt-watch-launchd.log是创建的,所以脚本运行,虽然/tmp/grunt-watch-launchd.log是空的),但守护进程似乎没有被创建或以某种方式被launchd.

此外,里面什么也没有出现/var/log/system.log。如果我尝试launchctl使用 sudo 运行:

sudo launchctl unload /Library/LaunchAgents/org.grunt.watch.plist && sudo launchctl load /Library/LaunchAgents/org.grunt.watch.plist

/tmp/grunt-watch-launchd.log将包含以下行:

daemon: fatal: refusing to execute unsafe program: /usr/local/bin/grunt (/usr/local/lib is group writable)

使用 sudo,/var/log/system.log告诉我:

Jun 11 18:22:24 antons-mbp com.apple.xpc.launchd[1] (org.grunt.watch[83009]): Service exited with abnormal code: 1

无论哪种方式(launchctl使用和不使用 sudo),我都可以确认该服务未启动:

mymachine:~ user$ launchctl list | grep grunt
-   0   org.grunt.watch

当我的用户登录时,有什么问题以及将这个脚本作为守护进程运行的正确方法是什么?

感谢您的关注。

编辑:我忘了说我使用的是 Mac OS X 10.12 Sierra,安装了 Gruntnpm并且我使用的是 MacBook Pro(13 英寸,2012 年中)(如果有帮助的话)。

编辑2:我发现了问题。作为launchd代理运行时,脚本无法找到命令,因为代理的用户不是我的用户。因此发生了 127 错误。

所以这适用于所有像我这样坚持使用非常简单的launchd代理的人:

  • 始终检查您使用的命令是否在启动该命令的用户的 PATH 中。使用绝对路径,如有必要,在脚本的第一行设置 PATH 变量。

  • 将所有命令输出重定向到一个文件,以便您可以查看启动脚本时是否发生错误(在我的情况下,由于某种原因launchd错误没有出现)。/var/log/system.log

4

1 回答 1

1

我对任何一个gruntdaemon实用程序都不熟悉,但我很确定daemon这与 launchd 管理工作的方式相冲突。本质上,您使用的是两种不同的守护进程创建工具,它们的工作方式不同,您只需要选择一个即可。

更具体地说,我怀疑daemongrunt在后台启动(即守护它)。但launchd希望它管理的工作留在可以监视和控制它们的前台。可能发生的情况是,launchd 启动您的脚本,脚本grunt watch在后台运行,然后退出......并且 launchd 看到该作业已退出并有助于清理剩余的子进程,例如grunt. 结果:没有实际grunt的守护进程运行。

您可以添加<key>AbandonProcessGroup</key><true/>到您的 .plist 以告诉 launchd 不要杀死后台进程,但实际上最好以 launchd 的方式做事并留grunt在前台。因此,要么daemon从脚本中删除该命令,要么将其替换为将在 launchd 下作为顶级进程exec运行的命令(正常运行时,它将使其成为 shell 的子进程,并将 shell 保留为 launchd 下的顶级进程grunt)。

这里可能还有其他问题,但在这个问题得到修复之前很难说清楚。

于 2017-06-11T19:08:43.097 回答