From 87036a07bcffbcd64a5b54efdab8bf175fcb5b1d Mon Sep 17 00:00:00 2001 From: kermieisinthehouse Date: Thu, 28 Oct 2021 16:19:23 -0700 Subject: [PATCH] Start browser on server start (#1832) * Start browser on server start * Add config option for opening browser --- go.mod | 1 + go.sum | 3 + graphql/documents/data/config.graphql | 1 + graphql/schema/types/config.graphql | 4 ++ pkg/api/resolver_mutation_configure.go | 2 + pkg/api/resolver_query_configuration.go | 2 + pkg/api/server.go | 19 ++++++- pkg/manager/config/config.go | 12 ++++ pkg/manager/config/init.go | 25 ++++++++ pkg/manager/manager.go | 31 ++++++++++ .../components/Changelog/versions/v0110.md | 1 + .../SettingsInterfacePanel.tsx | 27 +++++++++ ui/v2.5/src/locales/en-GB.json | 5 ++ vendor/github.com/pkg/browser/LICENSE | 23 ++++++++ vendor/github.com/pkg/browser/README.md | 55 ++++++++++++++++++ vendor/github.com/pkg/browser/browser.go | 57 +++++++++++++++++++ .../github.com/pkg/browser/browser_darwin.go | 5 ++ .../github.com/pkg/browser/browser_freebsd.go | 14 +++++ .../github.com/pkg/browser/browser_linux.go | 21 +++++++ .../github.com/pkg/browser/browser_netbsd.go | 14 +++++ .../github.com/pkg/browser/browser_openbsd.go | 14 +++++ .../pkg/browser/browser_unsupported.go | 12 ++++ .../github.com/pkg/browser/browser_windows.go | 7 +++ vendor/modules.txt | 3 + 24 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 vendor/github.com/pkg/browser/LICENSE create mode 100644 vendor/github.com/pkg/browser/README.md create mode 100644 vendor/github.com/pkg/browser/browser.go create mode 100644 vendor/github.com/pkg/browser/browser_darwin.go create mode 100644 vendor/github.com/pkg/browser/browser_freebsd.go create mode 100644 vendor/github.com/pkg/browser/browser_linux.go create mode 100644 vendor/github.com/pkg/browser/browser_netbsd.go create mode 100644 vendor/github.com/pkg/browser/browser_openbsd.go create mode 100644 vendor/github.com/pkg/browser/browser_unsupported.go create mode 100644 vendor/github.com/pkg/browser/browser_windows.go diff --git a/go.mod b/go.mod index 299a472d5..e540f1ddf 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/json-iterator/go v1.1.9 github.com/mattn/go-sqlite3 v1.14.6 github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007 + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/remeh/sizedwaitgroup v1.0.0 github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac github.com/rs/cors v1.6.0 diff --git a/go.sum b/go.sum index 457db0ce0..c14e7d637 100644 --- a/go.sum +++ b/go.sum @@ -554,6 +554,8 @@ github.com/pierrec/lz4/v4 v4.1.4/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuR github.com/pierrec/lz4/v4 v4.1.7/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -901,6 +903,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210521090106-6ca3eb03dfc2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/graphql/documents/data/config.graphql b/graphql/documents/data/config.graphql index a9cf7b903..67f8c60c6 100644 --- a/graphql/documents/data/config.graphql +++ b/graphql/documents/data/config.graphql @@ -52,6 +52,7 @@ fragment ConfigInterfaceData on ConfigInterfaceResult { wallShowTitle wallPlayback maximumLoopDuration + noBrowser autostartVideo showStudioAsText css diff --git a/graphql/schema/types/config.graphql b/graphql/schema/types/config.graphql index a0eadff42..213b253dc 100644 --- a/graphql/schema/types/config.graphql +++ b/graphql/schema/types/config.graphql @@ -222,6 +222,8 @@ input ConfigInterfaceInput { handyKey: String """Funscript Time Offset""" funscriptOffset: Int + """True if we should not auto-open a browser window on startup""" + noBrowser: Boolean } type ConfigDisableDropdownCreate { @@ -241,6 +243,8 @@ type ConfigInterfaceResult { wallPlayback: String """Maximum duration (in seconds) in which a scene video will loop in the scene player""" maximumLoopDuration: Int + """"True if we should not auto-open a browser window on startup""" + noBrowser: Boolean """If true, video will autostart on load in the scene player""" autostartVideo: Boolean """If true, studio overlays will be shown as text instead of logo images""" diff --git a/pkg/api/resolver_mutation_configure.go b/pkg/api/resolver_mutation_configure.go index d3ff51e9b..2071f531d 100644 --- a/pkg/api/resolver_mutation_configure.go +++ b/pkg/api/resolver_mutation_configure.go @@ -239,6 +239,8 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models. setBool(config.SoundOnPreview, input.SoundOnPreview) setBool(config.WallShowTitle, input.WallShowTitle) + setBool(config.NoBrowser, input.NoBrowser) + if input.WallPlayback != nil { c.Set(config.WallPlayback, *input.WallPlayback) } diff --git a/pkg/api/resolver_query_configuration.go b/pkg/api/resolver_query_configuration.go index 6242f9cab..e5777ef1b 100644 --- a/pkg/api/resolver_query_configuration.go +++ b/pkg/api/resolver_query_configuration.go @@ -108,6 +108,7 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult { soundOnPreview := config.GetSoundOnPreview() wallShowTitle := config.GetWallShowTitle() wallPlayback := config.GetWallPlayback() + noBrowser := config.GetNoBrowserFlag() maximumLoopDuration := config.GetMaximumLoopDuration() autostartVideo := config.GetAutostartVideo() showStudioAsText := config.GetShowStudioAsText() @@ -124,6 +125,7 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult { WallShowTitle: &wallShowTitle, WallPlayback: &wallPlayback, MaximumLoopDuration: &maximumLoopDuration, + NoBrowser: &noBrowser, AutostartVideo: &autostartVideo, ShowStudioAsText: &showStudioAsText, CSS: &css, diff --git a/pkg/api/server.go b/pkg/api/server.go index d29b6a707..e9fd23efe 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -23,6 +23,7 @@ import ( "github.com/go-chi/chi" "github.com/go-chi/chi/middleware" "github.com/gorilla/websocket" + "github.com/pkg/browser" "github.com/rs/cors" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/manager" @@ -243,12 +244,26 @@ func Start(uiBox embed.FS, loginUIBox embed.FS) { printVersion() printLatestVersion(context.TODO()) logger.Infof("stash is listening on " + address) + if tlsConfig != nil { + displayAddress = "https://" + displayAddress + "/" + } else { + displayAddress = "http://" + displayAddress + "/" + } + + // This can be done before actually starting the server, as modern browsers will + // automatically reload the page if a local port is closed at page load and then opened. + if !c.GetNoBrowserFlag() && manager.GetInstance().IsDesktop() { + err = browser.OpenURL(displayAddress) + if err != nil { + logger.Error("Could not open browser: " + err.Error()) + } + } if tlsConfig != nil { - logger.Infof("stash is running at https://" + displayAddress + "/") + logger.Infof("stash is running at " + displayAddress) logger.Error(server.ListenAndServeTLS("", "")) } else { - logger.Infof("stash is running at http://" + displayAddress + "/") + logger.Infof("stash is running at " + displayAddress) logger.Error(server.ListenAndServe()) } }() diff --git a/pkg/manager/config/config.go b/pkg/manager/config/config.go index 7790c7dfe..4105c22da 100644 --- a/pkg/manager/config/config.go +++ b/pkg/manager/config/config.go @@ -165,6 +165,10 @@ const DLNADefaultEnabled = "dlna.default_enabled" const DLNADefaultIPWhitelist = "dlna.default_whitelist" const DLNAInterfaces = "dlna.interfaces" +// Desktop Integration Options +const NoBrowser = "noBrowser" +const NoBrowserDefault = false + // Logging options const LogFile = "logFile" const LogOut = "logOut" @@ -247,6 +251,12 @@ func (i *Instance) GetCPUProfilePath() string { return i.cpuProfilePath } +func (i *Instance) GetNoBrowserFlag() bool { + i.Lock() + defer i.Unlock() + return viper.GetBool(NoBrowser) +} + func (i *Instance) Set(key string, value interface{}) { i.Lock() defer i.Unlock() @@ -1098,6 +1108,8 @@ func (i *Instance) setDefaultValues(write bool) error { // Set generated to the metadata path for backwards compat viper.SetDefault(Generated, viper.GetString(Metadata)) + viper.SetDefault(NoBrowser, NoBrowserDefault) + // Set default scrapers and plugins paths viper.SetDefault(ScrapersPath, defaultScrapersPath) viper.SetDefault(PluginsPath, defaultPluginsPath) diff --git a/pkg/manager/config/init.go b/pkg/manager/config/init.go index 27e57baf1..76e588ef4 100644 --- a/pkg/manager/config/init.go +++ b/pkg/manager/config/init.go @@ -19,6 +19,7 @@ var once sync.Once type flagStruct struct { configFilePath string cpuProfilePath string + nobrowser bool } func Initialize() (*Instance, error) { @@ -42,6 +43,7 @@ func Initialize() (*Instance, error) { } if !instance.isNewSystem { + setExistingSystemDefaults(instance) err = instance.SetInitialConfig() } }) @@ -97,6 +99,28 @@ func initConfig(flags flagStruct) error { return nil } +// setExistingSystemDefaults sets config options that are new and unset in an existing install, +// but should have a separate default than for brand-new systems, to maintain behavior. +func setExistingSystemDefaults(instance *Instance) { + if !instance.isNewSystem { + configDirtied := false + + // Existing systems as of the introduction of auto-browser open should retain existing + // behavior and not start the browser automatically. + if !viper.InConfig("nobrowser") { + configDirtied = true + viper.Set("nobrowser", "true") + } + + if configDirtied { + err := viper.WriteConfig() + if err != nil { + logger.Errorf("Could not save existing system defaults: %s", err.Error()) + } + } + } +} + func initFlags() flagStruct { flags := flagStruct{} @@ -104,6 +128,7 @@ func initFlags() flagStruct { pflag.Int("port", 9999, "port to serve from") pflag.StringVarP(&flags.configFilePath, "config", "c", "", "config file to use") pflag.StringVar(&flags.cpuProfilePath, "cpuprofile", "", "write cpu profile to file") + pflag.BoolVar(&flags.nobrowser, "nobrowser", false, "Don't open a browser window after launch") pflag.Parse() if err := viper.BindPFlags(pflag.CommandLine); err != nil { diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index bbb7a206b..f4acc5505 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -4,9 +4,12 @@ import ( "context" "errors" "fmt" + "io/ioutil" "os" "path/filepath" + "runtime" "runtime/pprof" + "strings" "sync" "time" @@ -391,6 +394,34 @@ func (s *singleton) Migrate(ctx context.Context, input models.MigrateInput) erro return nil } +func (s *singleton) IsDesktop() bool { + // check if running under root + if os.Getuid() == 0 { + return false + } + // check if started by init, e.g. stash is a *nix systemd service / MacOS launchd service + if os.Getppid() == 1 { + return false + } + if IsServerDockerized() { + return false + } + + return true +} + +func IsServerDockerized() bool { + if runtime.GOOS == "linux" { + _, dockerEnvErr := os.Stat("/.dockerenv") + cgroups, _ := ioutil.ReadFile("/proc/self/cgroup") + if os.IsExist(dockerEnvErr) || strings.Contains(string(cgroups), "docker") { + return true + } + } + + return false +} + func (s *singleton) GetSystemStatus() *models.SystemStatus { status := models.SystemStatusEnumOk dbSchema := int(database.Version()) diff --git a/ui/v2.5/src/components/Changelog/versions/v0110.md b/ui/v2.5/src/components/Changelog/versions/v0110.md index 23a8828fc..3bd43033c 100644 --- a/ui/v2.5/src/components/Changelog/versions/v0110.md +++ b/ui/v2.5/src/components/Changelog/versions/v0110.md @@ -1,4 +1,5 @@ ### ✨ New Features +* Optionally open browser on startup (enabled by default for new systems). ([#1832](https://github.com/stashapp/stash/pull/1832)) * Support setting defaults for Delete File and Delete Generated Files in the Interface Settings. ([#1852](https://github.com/stashapp/stash/pull/1852)) * Added Identify task to automatically identify scenes from stash-box/scraper sources. See manual entry for details. ([#1839](https://github.com/stashapp/stash/pull/1839)) * Added support for matching scenes using perceptual hashes when querying stash-box. ([#1858](https://github.com/stashapp/stash/pull/1858)) diff --git a/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx b/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx index af02aad5a..9a262f52e 100644 --- a/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx +++ b/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx @@ -32,6 +32,7 @@ export const SettingsInterfacePanel: React.FC = () => { const [menuItemIds, setMenuItemIds] = useState( allMenuItems.map((item) => item.id) ); + const [noBrowser, setNoBrowserFlag] = useState(false); const [soundOnPreview, setSoundOnPreview] = useState(true); const [wallShowTitle, setWallShowTitle] = useState(true); const [wallPlayback, setWallPlayback] = useState("video"); @@ -59,6 +60,7 @@ export const SettingsInterfacePanel: React.FC = () => { wallShowTitle, wallPlayback, maximumLoopDuration, + noBrowser, autostartVideo, showStudioAsText, css, @@ -80,6 +82,7 @@ export const SettingsInterfacePanel: React.FC = () => { setWallShowTitle(iCfg.wallShowTitle ?? true); setWallPlayback(iCfg.wallPlayback ?? "video"); setMaximumLoopDuration(iCfg.maximumLoopDuration ?? 0); + setNoBrowserFlag(iCfg?.noBrowser ?? false); setAutostartVideo(iCfg.autostartVideo ?? false); setShowStudioAsText(iCfg.showStudioAsText ?? false); setCSS(iCfg.css ?? ""); @@ -180,6 +183,30 @@ export const SettingsInterfacePanel: React.FC = () => { +
+ +

+ {intl.formatMessage({ + id: "config.ui.desktop_integration.desktop_integration", + })} +

+ + setNoBrowserFlag(!noBrowser)} + /> + + {intl.formatMessage({ + id: "config.ui.desktop_integration.skip_opening_browser_on_startup", + })} + + +
+
{intl.formatMessage({ id: "config.ui.scene_wall.heading" })}
+All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/pkg/browser/README.md b/vendor/github.com/pkg/browser/README.md new file mode 100644 index 000000000..72b1976e3 --- /dev/null +++ b/vendor/github.com/pkg/browser/README.md @@ -0,0 +1,55 @@ + +# browser + import "github.com/pkg/browser" + +Package browser provides helpers to open files, readers, and urls in a browser window. + +The choice of which browser is started is entirely client dependant. + + + + + +## Variables +``` go +var Stderr io.Writer = os.Stderr +``` +Stderr is the io.Writer to which executed commands write standard error. + +``` go +var Stdout io.Writer = os.Stdout +``` +Stdout is the io.Writer to which executed commands write standard output. + + +## func OpenFile +``` go +func OpenFile(path string) error +``` +OpenFile opens new browser window for the file path. + + +## func OpenReader +``` go +func OpenReader(r io.Reader) error +``` +OpenReader consumes the contents of r and presents the +results in a new browser window. + + +## func OpenURL +``` go +func OpenURL(url string) error +``` +OpenURL opens a new browser window pointing to url. + + + + + + + + + +- - - +Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md) diff --git a/vendor/github.com/pkg/browser/browser.go b/vendor/github.com/pkg/browser/browser.go new file mode 100644 index 000000000..d7969d74d --- /dev/null +++ b/vendor/github.com/pkg/browser/browser.go @@ -0,0 +1,57 @@ +// Package browser provides helpers to open files, readers, and urls in a browser window. +// +// The choice of which browser is started is entirely client dependant. +package browser + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" +) + +// Stdout is the io.Writer to which executed commands write standard output. +var Stdout io.Writer = os.Stdout + +// Stderr is the io.Writer to which executed commands write standard error. +var Stderr io.Writer = os.Stderr + +// OpenFile opens new browser window for the file path. +func OpenFile(path string) error { + path, err := filepath.Abs(path) + if err != nil { + return err + } + return OpenURL("file://" + path) +} + +// OpenReader consumes the contents of r and presents the +// results in a new browser window. +func OpenReader(r io.Reader) error { + f, err := ioutil.TempFile("", "browser.*.html") + if err != nil { + return fmt.Errorf("browser: could not create temporary file: %v", err) + } + if _, err := io.Copy(f, r); err != nil { + f.Close() + return fmt.Errorf("browser: caching temporary file failed: %v", err) + } + if err := f.Close(); err != nil { + return fmt.Errorf("browser: caching temporary file failed: %v", err) + } + return OpenFile(f.Name()) +} + +// OpenURL opens a new browser window pointing to url. +func OpenURL(url string) error { + return openBrowser(url) +} + +func runCmd(prog string, args ...string) error { + cmd := exec.Command(prog, args...) + cmd.Stdout = Stdout + cmd.Stderr = Stderr + return cmd.Run() +} diff --git a/vendor/github.com/pkg/browser/browser_darwin.go b/vendor/github.com/pkg/browser/browser_darwin.go new file mode 100644 index 000000000..8507cf7c2 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_darwin.go @@ -0,0 +1,5 @@ +package browser + +func openBrowser(url string) error { + return runCmd("open", url) +} diff --git a/vendor/github.com/pkg/browser/browser_freebsd.go b/vendor/github.com/pkg/browser/browser_freebsd.go new file mode 100644 index 000000000..4fc7ff076 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_freebsd.go @@ -0,0 +1,14 @@ +package browser + +import ( + "errors" + "os/exec" +) + +func openBrowser(url string) error { + err := runCmd("xdg-open", url) + if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound { + return errors.New("xdg-open: command not found - install xdg-utils from ports(8)") + } + return err +} diff --git a/vendor/github.com/pkg/browser/browser_linux.go b/vendor/github.com/pkg/browser/browser_linux.go new file mode 100644 index 000000000..d26cdddf9 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_linux.go @@ -0,0 +1,21 @@ +package browser + +import ( + "os/exec" + "strings" +) + +func openBrowser(url string) error { + providers := []string{"xdg-open", "x-www-browser", "www-browser"} + + // There are multiple possible providers to open a browser on linux + // One of them is xdg-open, another is x-www-browser, then there's www-browser, etc. + // Look for one that exists and run it + for _, provider := range providers { + if _, err := exec.LookPath(provider); err == nil { + return runCmd(provider, url) + } + } + + return &exec.Error{Name: strings.Join(providers, ","), Err: exec.ErrNotFound} +} diff --git a/vendor/github.com/pkg/browser/browser_netbsd.go b/vendor/github.com/pkg/browser/browser_netbsd.go new file mode 100644 index 000000000..65a5e5a29 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_netbsd.go @@ -0,0 +1,14 @@ +package browser + +import ( + "errors" + "os/exec" +) + +func openBrowser(url string) error { + err := runCmd("xdg-open", url) + if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound { + return errors.New("xdg-open: command not found - install xdg-utils from pkgsrc(7)") + } + return err +} diff --git a/vendor/github.com/pkg/browser/browser_openbsd.go b/vendor/github.com/pkg/browser/browser_openbsd.go new file mode 100644 index 000000000..4fc7ff076 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_openbsd.go @@ -0,0 +1,14 @@ +package browser + +import ( + "errors" + "os/exec" +) + +func openBrowser(url string) error { + err := runCmd("xdg-open", url) + if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound { + return errors.New("xdg-open: command not found - install xdg-utils from ports(8)") + } + return err +} diff --git a/vendor/github.com/pkg/browser/browser_unsupported.go b/vendor/github.com/pkg/browser/browser_unsupported.go new file mode 100644 index 000000000..7c5c17d34 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_unsupported.go @@ -0,0 +1,12 @@ +// +build !linux,!windows,!darwin,!openbsd,!freebsd,!netbsd + +package browser + +import ( + "fmt" + "runtime" +) + +func openBrowser(url string) error { + return fmt.Errorf("openBrowser: unsupported operating system: %v", runtime.GOOS) +} diff --git a/vendor/github.com/pkg/browser/browser_windows.go b/vendor/github.com/pkg/browser/browser_windows.go new file mode 100644 index 000000000..63e192959 --- /dev/null +++ b/vendor/github.com/pkg/browser/browser_windows.go @@ -0,0 +1,7 @@ +package browser + +import "golang.org/x/sys/windows" + +func openBrowser(url string) error { + return windows.ShellExecute(0, nil, windows.StringToUTF16Ptr(url), nil, nil, windows.SW_SHOWNORMAL) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index ec073c4e3..fad685063 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -249,6 +249,9 @@ github.com/nfnt/resize # github.com/pelletier/go-toml v1.7.0 ## explicit; go 1.12 github.com/pelletier/go-toml +# github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 +## explicit; go 1.14 +github.com/pkg/browser # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors