Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate browser package from gh (#62)
- Loading branch information
Showing
4 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Package browser facilitates opening of URLs in a web browser. | ||
package browser | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"os/exec" | ||
|
||
cliBrowser "github.com/cli/browser" | ||
"github.com/cli/go-gh/pkg/config" | ||
"github.com/cli/safeexec" | ||
"github.com/google/shlex" | ||
) | ||
|
||
// Browser represents a web browser that can be used to open up URLs. | ||
type Browser struct { | ||
launcher string | ||
stderr io.Writer | ||
stdout io.Writer | ||
} | ||
|
||
// New initializes a Browser. If a launcher is not specified | ||
// one is determined based on environment variables or from the | ||
// configuration file. | ||
// The order of precedence for determining a launcher is: | ||
// - Specified launcher; | ||
// - GH_BROWSER environment variable; | ||
// - browser option from configuration file; | ||
// - BROWSER environment variable. | ||
func New(launcher string, stdout, stderr io.Writer) Browser { | ||
if launcher == "" { | ||
launcher = resolveLauncher() | ||
} | ||
b := Browser{ | ||
launcher: launcher, | ||
stderr: stderr, | ||
stdout: stdout, | ||
} | ||
return b | ||
} | ||
|
||
// Browse opens the launcher and navigates to the specified URL. | ||
func (b *Browser) Browse(url string) error { | ||
return b.browse(url, nil) | ||
} | ||
|
||
func (b *Browser) browse(url string, env []string) error { | ||
if b.launcher == "" { | ||
return cliBrowser.OpenURL(url) | ||
} | ||
launcherArgs, err := shlex.Split(b.launcher) | ||
if err != nil { | ||
return err | ||
} | ||
launcherExe, err := safeexec.LookPath(launcherArgs[0]) | ||
if err != nil { | ||
return err | ||
} | ||
args := append(launcherArgs[1:], url) | ||
cmd := exec.Command(launcherExe, args...) | ||
cmd.Stdout = b.stdout | ||
cmd.Stderr = b.stderr | ||
if env != nil { | ||
cmd.Env = env | ||
} | ||
return cmd.Run() | ||
} | ||
|
||
func resolveLauncher() string { | ||
if ghBrowser := os.Getenv("GH_BROWSER"); ghBrowser != "" { | ||
return ghBrowser | ||
} | ||
cfg, err := config.Read() | ||
if err == nil { | ||
if cfgBrowser, _ := cfg.Get([]string{"browser"}); cfgBrowser != "" { | ||
return cfgBrowser | ||
} | ||
} | ||
return os.Getenv("BROWSER") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package browser | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/cli/go-gh/pkg/config" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestHelperProcess(t *testing.T) { | ||
if os.Getenv("GH_WANT_HELPER_PROCESS") != "1" { | ||
return | ||
} | ||
fmt.Fprintf(os.Stdout, "%v", os.Args[3:]) | ||
os.Exit(0) | ||
} | ||
|
||
func TestBrowse(t *testing.T) { | ||
launcher := fmt.Sprintf("%q -test.run=TestHelperProcess -- chrome", os.Args[0]) | ||
stdout := &bytes.Buffer{} | ||
stderr := &bytes.Buffer{} | ||
b := Browser{launcher: launcher, stdout: stdout, stderr: stderr} | ||
err := b.browse("github.com", []string{"GH_WANT_HELPER_PROCESS=1"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "[chrome github.com]", stdout.String()) | ||
assert.Equal(t, "", stderr.String()) | ||
} | ||
|
||
func TestResolveLauncher(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
env map[string]string | ||
config *config.Config | ||
wantLauncher string | ||
}{ | ||
{ | ||
name: "GH_BROWSER set", | ||
env: map[string]string{ | ||
"GH_BROWSER": "GH_BROWSER", | ||
}, | ||
wantLauncher: "GH_BROWSER", | ||
}, | ||
{ | ||
name: "config browser set", | ||
config: config.ReadFromString("browser: CONFIG_BROWSER"), | ||
wantLauncher: "CONFIG_BROWSER", | ||
}, | ||
{ | ||
name: "BROWSER set", | ||
env: map[string]string{ | ||
"BROWSER": "BROWSER", | ||
}, | ||
wantLauncher: "BROWSER", | ||
}, | ||
{ | ||
name: "GH_BROWSER and config browser set", | ||
env: map[string]string{ | ||
"GH_BROWSER": "GH_BROWSER", | ||
}, | ||
config: config.ReadFromString("browser: CONFIG_BROWSER"), | ||
wantLauncher: "GH_BROWSER", | ||
}, | ||
{ | ||
name: "config browser and BROWSER set", | ||
env: map[string]string{ | ||
"BROWSER": "BROWSER", | ||
}, | ||
config: config.ReadFromString("browser: CONFIG_BROWSER"), | ||
wantLauncher: "CONFIG_BROWSER", | ||
}, | ||
{ | ||
name: "GH_BROWSER and BROWSER set", | ||
env: map[string]string{ | ||
"BROWSER": "BROWSER", | ||
"GH_BROWSER": "GH_BROWSER", | ||
}, | ||
wantLauncher: "GH_BROWSER", | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if tt.env != nil { | ||
for k, v := range tt.env { | ||
old := os.Getenv(k) | ||
os.Setenv(k, v) | ||
defer os.Setenv(k, old) | ||
} | ||
} | ||
if tt.config != nil { | ||
old := config.Read | ||
config.Read = func() (*config.Config, error) { | ||
return tt.config, nil | ||
} | ||
defer func() { config.Read = old }() | ||
} | ||
launcher := resolveLauncher() | ||
assert.Equal(t, tt.wantLauncher, launcher) | ||
}) | ||
} | ||
} |