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:
@@ -91,9 +91,13 @@ override file values. Invalid values fail at startup.
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
go build ./cmd/gpu-turnstile
|
go build ./cmd/gpu-turnstile
|
||||||
./gpu-turnstile
|
OLLAMA_URL=http://127.0.0.1:11435 COMFY_URL=http://127.0.0.1:8189 ./gpu-turnstile
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Running the binary with no arguments in a terminal prints the help screen
|
||||||
|
(same as `-h`/`--help`); without a terminal (services, containers) a bare
|
||||||
|
invocation starts the proxy.
|
||||||
|
|
||||||
### Run natively on Windows (current primary deployment)
|
### Run natively on Windows (current primary deployment)
|
||||||
|
|
||||||
Download `gpu-turnstile.exe` from a release and install it as a Windows
|
Download `gpu-turnstile.exe` from a release and install it as a Windows
|
||||||
|
|||||||
+67
-28
@@ -35,8 +35,74 @@ var version = "dev"
|
|||||||
// process: a signed update has been staged and the GPU lock is idle.
|
// process: a signed update has been staged and the GPU lock is idle.
|
||||||
const exitCodeUpdate = 3
|
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() {
|
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" {
|
if len(args) > 0 && args[0] == "service" {
|
||||||
// Legacy subcommand form: gpu-turnstile service install|remove.
|
// Legacy subcommand form: gpu-turnstile service install|remove.
|
||||||
if len(args) != 2 || (args[1] != "install" && args[1] != "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.
|
// defaultConfigPath returns gpu-turnstile.env next to the executable.
|
||||||
func defaultConfigPath() string {
|
func defaultConfigPath() string {
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
|
|||||||
Reference in New Issue
Block a user