| // Copyright (c) The OpenTofu Authors | |
| // SPDX-License-Identifier: MPL-2.0 | |
| // Copyright (c) 2023 HashiCorp, Inc. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| package webbrowser | |
| import ( | |
| "fmt" | |
| "os" | |
| "os/exec" | |
| ) | |
| // NewExecLauncher creates and returns a Launcher that just attempts to run | |
| // the executable at the given path, with the given URL as its first and | |
| // only argument. | |
| // | |
| // The given path must be ready to use, without reference to the PATH | |
| // environment variable. The caller can use [exec.LookPath] to prepare | |
| // a suitable path if searching PATH is appropriate. | |
| // | |
| // This is intended to allow overriding which browser to use using the | |
| // BROWSER environment variable on Unix-like systems, but the rules for | |
| // that are in "package main". [ParseBrowserEnv] implements parsing of the | |
| // value of that environment variable when the main package decides it's | |
| // appropriate to do so. | |
| func NewExecLauncher(execPath string) Launcher { | |
| return execLauncher{ | |
| execPath: execPath, | |
| } | |
| } | |
| type execLauncher struct { | |
| execPath string | |
| } | |
| func (l execLauncher) OpenURL(url string) error { | |
| cmd := &exec.Cmd{ | |
| Path: l.execPath, | |
| Args: []string{l.execPath, url}, | |
| Env: os.Environ(), | |
| } | |
| err := cmd.Run() | |
| if err != nil { | |
| return fmt.Errorf("%s: %w", l.execPath, err) | |
| } | |
| return nil | |
| } | |
| // ParseBrowserEnv takes the raw value of a BROWSER environment variable and | |
| // attempts to parse it as a reference to an executable, whose absolute | |
| // path is returned if successful. Returns an empty string if the value cannot | |
| // be interpreted as an executable to run. | |
| // | |
| // This implements the simple form of this environment variable commonly used | |
| // by software on Unix-like systems, where the value must be literally just | |
| // a command to run whose first and only argument would be the URL to open. | |
| // | |
| // It does NOT support the more complex interpretation of that environment | |
| // variable that was proposed at http://www.catb.org/~esr/BROWSER/ , because | |
| // that form has not been widely implemented and the implementations that | |
| // exist do not have consistent behavior due to the proposal being | |
| // ambiguous. | |
| // | |
| // Callers that use this should typically pass a successful result to | |
| // [NewExecLauncher] to use the resolved command as a browser launcher. The | |
| // caller is responsible for deciding the policy for whether to consider a | |
| // BROWSER environment variable and for accessing the environment table to | |
| // obtain its value. | |
| func ParseBrowserEnv(raw string) string { | |
| if raw == "" { | |
| return "" // empty is treated the same as unset | |
| } | |
| execPath, err := exec.LookPath(raw) | |
| if err != nil { | |
| // We silently ignore variable values we cannot use, because this | |
| // environment variable is not OpenTofu-specific and so it may have | |
| // been set for the benefit of software other than OpenTofu which | |
| // interprets it differently. | |
| return "" | |
| } | |
| return execPath | |
| } |