Bare run in a terminal prints the help screen; add -h/--help
A zero-argument invocation now shows the usage text when stdout is a console (double-clicked exe, interactive shell). Without a terminal — Docker entrypoint, services, pipes — a bare invocation still starts the proxy, so the container image and service behavior are unchanged.
This commit is contained in:
+67
-28
@@ -35,8 +35,74 @@ var version = "dev"
|
||||
// process: a signed update has been staged and the GPU lock is idle.
|
||||
const exitCodeUpdate = 3
|
||||
|
||||
// stdoutIsTerminal reports whether stdout is a console (char device), as
|
||||
// opposed to a pipe or file — which is what Docker containers and services
|
||||
// see.
|
||||
func stdoutIsTerminal() bool {
|
||||
fi, err := os.Stdout.Stat()
|
||||
return err == nil && fi.Mode()&os.ModeCharDevice != 0
|
||||
}
|
||||
|
||||
// parseFlags extracts -config <path> (or -config=<path>), the
|
||||
// --install-service / --remove-service switches, --no-copy, -h/--help and
|
||||
// the hidden --elevated-child marker from args.
|
||||
func parseFlags(args []string) (configPath string, install, remove, noCopy, help, elevatedChild bool, rest []string) {
|
||||
rest = args[:0]
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch {
|
||||
case args[i] == "-config" && i+1 < len(args):
|
||||
configPath = args[i+1]
|
||||
i++
|
||||
case strings.HasPrefix(args[i], "-config="):
|
||||
configPath = strings.TrimPrefix(args[i], "-config=")
|
||||
case args[i] == "--install-service" || args[i] == "-install-service":
|
||||
install = true
|
||||
case args[i] == "--remove-service" || args[i] == "-remove-service":
|
||||
remove = true
|
||||
case args[i] == "--no-copy" || args[i] == "-no-copy":
|
||||
noCopy = true
|
||||
case args[i] == "-h" || args[i] == "--help" || args[i] == "-help":
|
||||
help = true
|
||||
case args[i] == "--elevated-child":
|
||||
elevatedChild = true
|
||||
default:
|
||||
rest = append(rest, args[i])
|
||||
}
|
||||
}
|
||||
return configPath, install, remove, noCopy, help, elevatedChild, rest
|
||||
}
|
||||
|
||||
const usageText = `gpu-turnstile — GPU arbitration proxy for Ollama + ComfyUI
|
||||
|
||||
Usage:
|
||||
gpu-turnstile -config <path> run the proxy
|
||||
gpu-turnstile --install-service [--no-copy] [-config path] install + start as a service
|
||||
gpu-turnstile --remove-service stop + uninstall the service
|
||||
gpu-turnstile -h | --help this help
|
||||
|
||||
Options:
|
||||
-config <path> config file (default: gpu-turnstile.env next to the exe)
|
||||
--install-service copies the binary into the canonical location
|
||||
(%ProgramFiles%\gpu-turnstile or /var/lib/gpu-turnstile)
|
||||
unless --no-copy; on Windows a UAC prompt appears when
|
||||
the shell is not elevated
|
||||
--no-copy with --install-service: register the current location as-is
|
||||
|
||||
All runtime settings are environment variables or KEY=VALUE lines in the
|
||||
config file (OLLAMA_URL, COMFY_URL, LOGLEVEL, ...); see README.md.
|
||||
`
|
||||
|
||||
func main() {
|
||||
configPath, install, remove, noCopy, elevatedChild, args := parseFlags(os.Args[1:])
|
||||
configPath, install, remove, noCopy, help, elevatedChild, args := parseFlags(os.Args[1:])
|
||||
bare := configPath == "" && !install && !remove && !elevatedChild && len(args) == 0
|
||||
if help || (bare && stdoutIsTerminal()) {
|
||||
// Bare invocation in a terminal (e.g. double-clicked on Windows)
|
||||
// shows the help instead of starting a proxy window with no visible
|
||||
// explanation. Without a terminal — Docker containers, services,
|
||||
// pipes — a bare invocation starts the proxy as before.
|
||||
fmt.Print(usageText)
|
||||
return
|
||||
}
|
||||
if len(args) > 0 && args[0] == "service" {
|
||||
// Legacy subcommand form: gpu-turnstile service install|remove.
|
||||
if len(args) != 2 || (args[1] != "install" && args[1] != "remove") {
|
||||
@@ -89,33 +155,6 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// parseFlags extracts -config <path> (or -config=<path>), the
|
||||
// --install-service / --remove-service switches, --no-copy and the hidden
|
||||
// --elevated-child marker from args.
|
||||
func parseFlags(args []string) (configPath string, install, remove, noCopy, elevatedChild bool, rest []string) {
|
||||
rest = args[:0]
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch {
|
||||
case args[i] == "-config" && i+1 < len(args):
|
||||
configPath = args[i+1]
|
||||
i++
|
||||
case strings.HasPrefix(args[i], "-config="):
|
||||
configPath = strings.TrimPrefix(args[i], "-config=")
|
||||
case args[i] == "--install-service" || args[i] == "-install-service":
|
||||
install = true
|
||||
case args[i] == "--remove-service" || args[i] == "-remove-service":
|
||||
remove = true
|
||||
case args[i] == "--no-copy" || args[i] == "-no-copy":
|
||||
noCopy = true
|
||||
case args[i] == "--elevated-child":
|
||||
elevatedChild = true
|
||||
default:
|
||||
rest = append(rest, args[i])
|
||||
}
|
||||
}
|
||||
return configPath, install, remove, noCopy, elevatedChild, rest
|
||||
}
|
||||
|
||||
// defaultConfigPath returns gpu-turnstile.env next to the executable.
|
||||
func defaultConfigPath() string {
|
||||
exe, err := os.Executable()
|
||||
|
||||
Reference in New Issue
Block a user