podman
137 строк · 3.4 Кб
1// Package webbrowser provides a simple API for opening web pages on your
2// default browser.
3package webbrowser
4
5import (
6"errors"
7"fmt"
8"net/url"
9"os"
10"os/exec"
11"runtime"
12"strings"
13)
14
15var (
16ErrCantOpenBrowser = errors.New("webbrowser: can't open browser")
17ErrNoCandidates = errors.New("webbrowser: no browser candidate found for your OS")
18)
19
20// Candidates contains a list of registered `Browser`s that will be tried with Open.
21var Candidates []Browser
22
23type Browser interface {
24// Command returns a ready to be used Cmd that will open an URL.
25Command(string) (*exec.Cmd, error)
26// Open tries to open a URL in your default browser. NOTE: This may cause
27// your program to hang until the browser process is closed in some OSes,
28// see https://github.com/toqueteos/webbrowser/issues/4.
29Open(string) error
30}
31
32// Open tries to open a URL in your default browser ensuring you have a display
33// set up and not running this from SSH. NOTE: This may cause your program to
34// hang until the browser process is closed in some OSes, see
35// https://github.com/toqueteos/webbrowser/issues/4.
36func Open(s string) (err error) {
37if len(Candidates) == 0 {
38return ErrNoCandidates
39}
40
41// Try to determine if there's a display available (only linux) and we
42// aren't on a terminal (all but windows).
43switch runtime.GOOS {
44case "linux":
45// No display, no need to open a browser. Lynx users **MAY** have
46// something to say about this.
47if os.Getenv("DISPLAY") == "" {
48return fmt.Errorf("webbrowser: tried to open %q, no screen found", s)
49}
50fallthrough
51case "darwin":
52// Check SSH env vars.
53if os.Getenv("SSH_CLIENT") != "" || os.Getenv("SSH_TTY") != "" {
54return fmt.Errorf("webbrowser: tried to open %q, but you are running a shell session", s)
55}
56}
57
58// Try all candidates
59for _, candidate := range Candidates {
60err := candidate.Open(s)
61if err == nil {
62return nil
63}
64}
65
66return ErrCantOpenBrowser
67}
68
69func init() {
70// Register the default Browser for current OS, if it exists.
71if os, ok := osCommand[runtime.GOOS]; ok {
72Candidates = append(Candidates, browserCommand{os.cmd, os.args})
73}
74}
75
76var (
77osCommand = map[string]*browserCommand{
78"android": &browserCommand{"xdg-open", nil},
79"darwin": &browserCommand{"open", nil},
80"freebsd": &browserCommand{"xdg-open", nil},
81"linux": &browserCommand{"xdg-open", nil},
82"netbsd": &browserCommand{"xdg-open", nil},
83"openbsd": &browserCommand{"xdg-open", nil}, // It may be open instead
84"windows": &browserCommand{"cmd", []string{"/c", "start"}},
85}
86winSchemes = [3]string{"https", "http", "file"}
87)
88
89type browserCommand struct {
90cmd string
91args []string
92}
93
94func (b browserCommand) Command(s string) (*exec.Cmd, error) {
95u, err := url.Parse(s)
96if err != nil {
97return nil, err
98}
99
100validUrl := ensureValidURL(u)
101
102b.args = append(b.args, validUrl)
103
104return exec.Command(b.cmd, b.args...), nil
105}
106
107func (b browserCommand) Open(s string) error {
108cmd, err := b.Command(s)
109if err != nil {
110return err
111}
112
113return cmd.Run()
114}
115
116func ensureScheme(u *url.URL) {
117for _, s := range winSchemes {
118if u.Scheme == s {
119return
120}
121}
122u.Scheme = "http"
123}
124
125func ensureValidURL(u *url.URL) string {
126// Enforce a scheme (windows requires scheme to be set to work properly).
127ensureScheme(u)
128s := u.String()
129
130// Escape characters not allowed by cmd/bash
131switch runtime.GOOS {
132case "windows":
133s = strings.Replace(s, "&", `^&`, -1)
134}
135
136return s
137}
138