如何在无头(非GUI)环境中检测当前Go进程是否为运行?
How to detect if the current Go process is running in a headless (non-GUI) environment?
我有一个要安装托盘图标的 Go 程序。如果进程是无头的,也就是说,它将无法创建图形用户界面,Go 程序仍然有意义并且应该 运行,但显然它不应安装托盘图标。
Go中检测当前Go进程是否headless的方法是什么?
目前,我使用以下代码:
func isHeadless() bool {
_, display := os.LookupEnv("DISPLAY")
return !(runtime.GOOS == "windows" || display)
}
此代码在 "normal" Windows、Linux 或 Mac OS X 上运行良好,我敢打赌它也会 运行 在 FreeBSD、NetBSD、Dragonfly 和许多其他平台上都很好。
不过,该代码显然有很多问题:
- 它假设 Windows 永远不会是无头的(错误,如果进程是在没有用户登录的情况下启动的,而且还有 Windows 10 IoT Core 可以配置为无头 https://docs.microsoft.com/en-us/windows/iot-core/learn-about-hardware/headlessmode)
- 不支持Android(其中也有针对物联网的无头版本)。
- 它假设所有非Windows的东西都有一个X服务器,因此有一个DISPLAY环境变量(错误,例如,Android)
那么,在无头环境下,Go 中检测当前进程是否为无头/运行ning 的正确方法是什么?
我不是在寻找变通方法,例如向我的程序添加 --headless
命令行开关。因为,我已经 拥有 无论如何,对于有头脑但希望程序表现得像没有头脑的用户。
在其他一些编程环境中,存在这样的功能。例如,Java 有 java.awt.GraphicsEnvironment.isHeadless()
,我正在寻找 Go 中的类似功能。
有些人建议只尝试创建 UI,然后捕获错误。这不起作用,至少不适用于我使用的库。我使用 github.com/getlantern/systray
。当 systray.Run()
无法创建 UI 时,进程终止。我设置系统托盘的代码如下所示:
func setupSystray() { // called from main()
go func() {
systray.Run(onReady, nil)
}()
}
func onReady() {
systray.SetTitle("foo")
// ...
}
当我 运行 Linux 上的此代码未设置 DISPLAY
时,输出如下:
$ ./myapp-linux-amd64
Unable to init server: Could not connect: Connection refused
(myapp-linux-amd64:5783): Gtk-WARNING **: 19:42:37.914: cannot open display:
$ echo $?
1
可以说这是库中的一个缺陷(我已经在库上创建了一个票证 https://github.com/getlantern/systray/issues/71),但是一些其他 API 和环境仍然提供了一个函数 isHeadless()
,我正在寻找 Golang 中的等效项。
我认为您可能从错误的角度解决了这个问题。
可靠地检测到您的程序确实看到了无头机器,IMO,出于多种原因是徒劳的。
因此,我认为我会采用一种通常用于文件系统的方法:
- 尝试执行操作。
- 如果失败,收集错误。
- 分析错误并采取相应措施。
也就是说,只需尝试在您的代码中显式初始化任何与 GUI 堆栈一起工作的客户端(您的)端,捕获任何可能的错误并对其进行分析。如果它说它未能初始化子系统,那么只需举起相关标志并继续。
由于认为缺少 library/solution,我自己创建了一个。 https://github.com/christianhujer/isheadless
用法示例:
package main
import (
. "fmt"
. "github.com/christianhujer/isheadless"
. "os"
)
func main() {
headless := IsHeadless()
Fprintf(Stderr, "%s: info: headless: %v\n", Args[0], headless)
Exit(map[bool]int{true: 0, false: 1}[headless])
}
示例运行:
$ ./isheadless ; echo $?
./isheadless: info: headless: false
1
$ DISPLAY= ./isheadless ; echo $?
./isheadless: info: headless: true
0
好吧,问题的答案正如它所说的那样
就是看看 Java 在它的 isHeadless()
.
中做了什么
Here 是 OpenJDK 10 所做的。
我不能复制代码,因为它可能会违反其许可证,
但本质上,细分如下:
- 获取系统属性"java.awt.headless";如果找到,请使用它。
- 获取系统属性"javaplugin.version";如果它存在,
会话不是无头的。使用此值。
- 获取系统属性"os.name"。如果字面上包含
子字符串 "OS X" 和系统 属性 "awt.toolkit"
等于字符串 "sun.awt.HToolkit",会话不是无头的。
使用此值。
- 检查系统是否属性"os.name"
等于 "Linux"、"SunOS"、"FreeBSD"、"NetBSD"、"OpenBSD" 之一
或 "AIX",如果是,则尝试寻找环境变量 "DISPLAY";
如果它不存在,则会话是无头的。
如您所见,实际上这张支票很蹩脚
而且我没有看到 Windows.
的任何特殊处理
不过,这准确地回答了你的问题。
我有一个要安装托盘图标的 Go 程序。如果进程是无头的,也就是说,它将无法创建图形用户界面,Go 程序仍然有意义并且应该 运行,但显然它不应安装托盘图标。
Go中检测当前Go进程是否headless的方法是什么?
目前,我使用以下代码:
func isHeadless() bool {
_, display := os.LookupEnv("DISPLAY")
return !(runtime.GOOS == "windows" || display)
}
此代码在 "normal" Windows、Linux 或 Mac OS X 上运行良好,我敢打赌它也会 运行 在 FreeBSD、NetBSD、Dragonfly 和许多其他平台上都很好。
不过,该代码显然有很多问题:
- 它假设 Windows 永远不会是无头的(错误,如果进程是在没有用户登录的情况下启动的,而且还有 Windows 10 IoT Core 可以配置为无头 https://docs.microsoft.com/en-us/windows/iot-core/learn-about-hardware/headlessmode)
- 不支持Android(其中也有针对物联网的无头版本)。
- 它假设所有非Windows的东西都有一个X服务器,因此有一个DISPLAY环境变量(错误,例如,Android)
那么,在无头环境下,Go 中检测当前进程是否为无头/运行ning 的正确方法是什么?
我不是在寻找变通方法,例如向我的程序添加 --headless
命令行开关。因为,我已经 拥有 无论如何,对于有头脑但希望程序表现得像没有头脑的用户。
在其他一些编程环境中,存在这样的功能。例如,Java 有 java.awt.GraphicsEnvironment.isHeadless()
,我正在寻找 Go 中的类似功能。
有些人建议只尝试创建 UI,然后捕获错误。这不起作用,至少不适用于我使用的库。我使用 github.com/getlantern/systray
。当 systray.Run()
无法创建 UI 时,进程终止。我设置系统托盘的代码如下所示:
func setupSystray() { // called from main()
go func() {
systray.Run(onReady, nil)
}()
}
func onReady() {
systray.SetTitle("foo")
// ...
}
当我 运行 Linux 上的此代码未设置 DISPLAY
时,输出如下:
$ ./myapp-linux-amd64
Unable to init server: Could not connect: Connection refused
(myapp-linux-amd64:5783): Gtk-WARNING **: 19:42:37.914: cannot open display:
$ echo $?
1
可以说这是库中的一个缺陷(我已经在库上创建了一个票证 https://github.com/getlantern/systray/issues/71),但是一些其他 API 和环境仍然提供了一个函数 isHeadless()
,我正在寻找 Golang 中的等效项。
我认为您可能从错误的角度解决了这个问题。
可靠地检测到您的程序确实看到了无头机器,IMO,出于多种原因是徒劳的。
因此,我认为我会采用一种通常用于文件系统的方法:
- 尝试执行操作。
- 如果失败,收集错误。
- 分析错误并采取相应措施。
也就是说,只需尝试在您的代码中显式初始化任何与 GUI 堆栈一起工作的客户端(您的)端,捕获任何可能的错误并对其进行分析。如果它说它未能初始化子系统,那么只需举起相关标志并继续。
由于认为缺少 library/solution,我自己创建了一个。 https://github.com/christianhujer/isheadless
用法示例:
package main
import (
. "fmt"
. "github.com/christianhujer/isheadless"
. "os"
)
func main() {
headless := IsHeadless()
Fprintf(Stderr, "%s: info: headless: %v\n", Args[0], headless)
Exit(map[bool]int{true: 0, false: 1}[headless])
}
示例运行:
$ ./isheadless ; echo $?
./isheadless: info: headless: false
1
$ DISPLAY= ./isheadless ; echo $?
./isheadless: info: headless: true
0
好吧,问题的答案正如它所说的那样
就是看看 Java 在它的 isHeadless()
.
Here 是 OpenJDK 10 所做的。
我不能复制代码,因为它可能会违反其许可证, 但本质上,细分如下:
- 获取系统属性"java.awt.headless";如果找到,请使用它。
- 获取系统属性"javaplugin.version";如果它存在, 会话不是无头的。使用此值。
- 获取系统属性"os.name"。如果字面上包含 子字符串 "OS X" 和系统 属性 "awt.toolkit" 等于字符串 "sun.awt.HToolkit",会话不是无头的。 使用此值。
- 检查系统是否属性"os.name" 等于 "Linux"、"SunOS"、"FreeBSD"、"NetBSD"、"OpenBSD" 之一 或 "AIX",如果是,则尝试寻找环境变量 "DISPLAY"; 如果它不存在,则会话是无头的。
如您所见,实际上这张支票很蹩脚 而且我没有看到 Windows.
的任何特殊处理不过,这准确地回答了你的问题。