blob: b40839f4c4616fbc0235be70aba57a21273930a3 [file] [edit]
// 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
}