summaryrefslogtreecommitdiff
path: root/vendor/github.com/playwright-community/playwright-go/run.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/playwright-community/playwright-go/run.go')
-rw-r--r--vendor/github.com/playwright-community/playwright-go/run.go409
1 files changed, 0 insertions, 409 deletions
diff --git a/vendor/github.com/playwright-community/playwright-go/run.go b/vendor/github.com/playwright-community/playwright-go/run.go
deleted file mode 100644
index 79ad11e..0000000
--- a/vendor/github.com/playwright-community/playwright-go/run.go
+++ /dev/null
@@ -1,409 +0,0 @@
-package playwright
-
-import (
- "archive/zip"
- "bytes"
- "errors"
- "fmt"
- "io"
- "log"
- "log/slog"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
-)
-
-const playwrightCliVersion = "1.52.0"
-
-var (
- logger = slog.Default()
- playwrightCDNMirrors = []string{
- "https://playwright.azureedge.net",
- "https://playwright-akamai.azureedge.net",
- "https://playwright-verizon.azureedge.net",
- }
-)
-
-// PlaywrightDriver wraps the Playwright CLI of upstream Playwright.
-//
-// It's required for playwright-go to work.
-type PlaywrightDriver struct {
- Version string
- options *RunOptions
-}
-
-func NewDriver(options ...*RunOptions) (*PlaywrightDriver, error) {
- transformed, err := transformRunOptions(options...) // get default values
- if err != nil {
- return nil, err
- }
- return &PlaywrightDriver{
- options: transformed,
- Version: playwrightCliVersion,
- }, nil
-}
-
-func getDefaultCacheDirectory() (string, error) {
- userHomeDir, err := os.UserHomeDir()
- if err != nil {
- return "", fmt.Errorf("could not get user home directory: %w", err)
- }
- switch runtime.GOOS {
- case "windows":
- return filepath.Join(userHomeDir, "AppData", "Local"), nil
- case "darwin":
- return filepath.Join(userHomeDir, "Library", "Caches"), nil
- case "linux":
- return filepath.Join(userHomeDir, ".cache"), nil
- }
- return "", errors.New("could not determine cache directory")
-}
-
-func (d *PlaywrightDriver) isUpToDateDriver() (bool, error) {
- if _, err := os.Stat(d.options.DriverDirectory); os.IsNotExist(err) {
- if err := os.MkdirAll(d.options.DriverDirectory, 0o777); err != nil {
- return false, fmt.Errorf("could not create driver directory: %w", err)
- }
- }
- if _, err := os.Stat(getDriverCliJs(d.options.DriverDirectory)); os.IsNotExist(err) {
- return false, nil
- } else if err != nil {
- return false, fmt.Errorf("could not check if driver is up2date: %w", err)
- }
- cmd := d.Command("--version")
- output, err := cmd.Output()
- if err != nil {
- return false, fmt.Errorf("could not run driver: %w", err)
- }
- if bytes.Contains(output, []byte(d.Version)) {
- return true, nil
- }
- // avoid triggering downloads and accidentally overwriting files
- return false, fmt.Errorf("driver exists but version not %s in : %s", d.Version, d.options.DriverDirectory)
-}
-
-// Command returns an exec.Cmd for the driver.
-func (d *PlaywrightDriver) Command(arg ...string) *exec.Cmd {
- cmd := exec.Command(getNodeExecutable(d.options.DriverDirectory), append([]string{getDriverCliJs(d.options.DriverDirectory)}, arg...)...)
- cmd.SysProcAttr = defaultSysProcAttr
- return cmd
-}
-
-// Install downloads the driver and the browsers depending on [RunOptions].
-func (d *PlaywrightDriver) Install() error {
- if err := d.DownloadDriver(); err != nil {
- return fmt.Errorf("could not install driver: %w", err)
- }
- if d.options.SkipInstallBrowsers {
- return nil
- }
-
- d.log("Downloading browsers...")
- if err := d.installBrowsers(); err != nil {
- return fmt.Errorf("could not install browsers: %w", err)
- }
- d.log("Downloaded browsers successfully")
-
- return nil
-}
-
-// Uninstall removes the driver and the browsers.
-func (d *PlaywrightDriver) Uninstall() error {
- d.log("Removing browsers...")
- if err := d.uninstallBrowsers(); err != nil {
- return fmt.Errorf("could not uninstall browsers: %w", err)
- }
-
- d.log("Removing driver...")
- if err := os.RemoveAll(d.options.DriverDirectory); err != nil {
- return fmt.Errorf("could not remove driver directory: %w", err)
- }
-
- d.log("Uninstall driver successfully")
- return nil
-}
-
-// DownloadDriver downloads the driver only
-func (d *PlaywrightDriver) DownloadDriver() error {
- up2Date, err := d.isUpToDateDriver()
- if err != nil {
- return err
- }
- if up2Date {
- return nil
- }
-
- d.log("Downloading driver", "path", d.options.DriverDirectory)
-
- body, err := downloadDriver(d.getDriverURLs())
- if err != nil {
- return err
- }
- zipReader, err := zip.NewReader(bytes.NewReader(body), int64(len(body)))
- if err != nil {
- return fmt.Errorf("could not read zip content: %w", err)
- }
-
- for _, zipFile := range zipReader.File {
- zipFileDiskPath := filepath.Join(d.options.DriverDirectory, zipFile.Name)
- if zipFile.FileInfo().IsDir() {
- if err := os.MkdirAll(zipFileDiskPath, os.ModePerm); err != nil {
- return fmt.Errorf("could not create directory: %w", err)
- }
- continue
- }
-
- outFile, err := os.Create(zipFileDiskPath)
- if err != nil {
- return fmt.Errorf("could not create driver: %w", err)
- }
- file, err := zipFile.Open()
- if err != nil {
- return fmt.Errorf("could not open zip file: %w", err)
- }
- if _, err = io.Copy(outFile, file); err != nil {
- return fmt.Errorf("could not copy response body to file: %w", err)
- }
- if err := outFile.Close(); err != nil {
- return fmt.Errorf("could not close file (driver): %w", err)
- }
- if err := file.Close(); err != nil {
- return fmt.Errorf("could not close file (zip file): %w", err)
- }
- if zipFile.Mode().Perm()&0o100 != 0 && runtime.GOOS != "windows" {
- if err := makeFileExecutable(zipFileDiskPath); err != nil {
- return fmt.Errorf("could not make executable: %w", err)
- }
- }
- }
-
- d.log("Downloaded driver successfully")
-
- return nil
-}
-
-func (d *PlaywrightDriver) log(msg string, args ...any) {
- if d.options.Verbose {
- logger.Info(msg, args...)
- }
-}
-
-func (d *PlaywrightDriver) run() (*connection, error) {
- transport, err := newPipeTransport(d, d.options.Stderr)
- if err != nil {
- return nil, err
- }
- connection := newConnection(transport)
- return connection, nil
-}
-
-func (d *PlaywrightDriver) installBrowsers() error {
- additionalArgs := []string{"install"}
- if d.options.Browsers != nil {
- additionalArgs = append(additionalArgs, d.options.Browsers...)
- }
-
- if d.options.OnlyInstallShell {
- additionalArgs = append(additionalArgs, "--only-shell")
- }
-
- if d.options.DryRun {
- additionalArgs = append(additionalArgs, "--dry-run")
- }
-
- cmd := d.Command(additionalArgs...)
- cmd.Stdout = d.options.Stdout
- cmd.Stderr = d.options.Stderr
- return cmd.Run()
-}
-
-func (d *PlaywrightDriver) uninstallBrowsers() error {
- cmd := d.Command("uninstall")
- cmd.Stdout = d.options.Stdout
- cmd.Stderr = d.options.Stderr
- return cmd.Run()
-}
-
-// RunOptions are custom options to run the driver
-type RunOptions struct {
- // DriverDirectory points to the playwright driver directory.
- // It should have two subdirectories: node and package.
- // You can also specify it using the environment variable PLAYWRIGHT_DRIVER_PATH.
- //
- // Default is user cache directory + "/ms-playwright-go/x.xx.xx":
- // - Windows: %USERPROFILE%\AppData\Local
- // - macOS: ~/Library/Caches
- // - Linux: ~/.cache
- DriverDirectory string
- // OnlyInstallShell only downloads the headless shell. (For chromium browsers only)
- OnlyInstallShell bool
- SkipInstallBrowsers bool
- // if not set and SkipInstallBrowsers is false, will download all browsers (chromium, firefox, webkit)
- Browsers []string
- Verbose bool // default true
- Stdout io.Writer
- Stderr io.Writer
- Logger *slog.Logger
- // DryRun does not install browser/dependencies. It will only print information.
- DryRun bool
-}
-
-// Install does download the driver and the browsers.
-//
-// Use this before playwright.Run() or use playwright cli to install the driver and browsers
-func Install(options ...*RunOptions) error {
- driver, err := NewDriver(options...)
- if err != nil {
- return fmt.Errorf("could not get driver instance: %w", err)
- }
- if err := driver.Install(); err != nil {
- return fmt.Errorf("could not install driver: %w", err)
- }
- return nil
-}
-
-// Run starts a Playwright instance.
-//
-// Requires the driver and the browsers to be installed before.
-// Either use Install() or use playwright cli.
-func Run(options ...*RunOptions) (*Playwright, error) {
- driver, err := NewDriver(options...)
- if err != nil {
- return nil, fmt.Errorf("could not get driver instance: %w", err)
- }
- up2date, err := driver.isUpToDateDriver()
- if err != nil || !up2date {
- return nil, fmt.Errorf("please install the driver (v%s) first: %w", playwrightCliVersion, err)
- }
- connection, err := driver.run()
- if err != nil {
- return nil, err
- }
- playwright, err := connection.Start()
- return playwright, err
-}
-
-func transformRunOptions(options ...*RunOptions) (*RunOptions, error) {
- option := &RunOptions{
- Verbose: true,
- }
- if len(options) == 1 {
- option = options[0]
- }
- if option.DriverDirectory == "" { // if user did not set it, try to get it from env
- option.DriverDirectory = os.Getenv("PLAYWRIGHT_DRIVER_PATH")
- }
- if option.DriverDirectory == "" {
- cacheDirectory, err := getDefaultCacheDirectory()
- if err != nil {
- return nil, fmt.Errorf("could not get default cache directory: %w", err)
- }
- option.DriverDirectory = filepath.Join(cacheDirectory, "ms-playwright-go", playwrightCliVersion)
- }
- if option.Stdout == nil {
- option.Stdout = os.Stdout
- }
- if option.Stderr == nil {
- option.Stderr = os.Stderr
- } else if option.Logger == nil {
- log.SetOutput(option.Stderr)
- }
- if option.Logger != nil {
- logger = option.Logger
- }
- return option, nil
-}
-
-func getNodeExecutable(driverDirectory string) string {
- envPath := os.Getenv("PLAYWRIGHT_NODEJS_PATH")
- if envPath != "" {
- return envPath
- }
-
- node := "node"
- if runtime.GOOS == "windows" {
- node = "node.exe"
- }
- return filepath.Join(driverDirectory, node)
-}
-
-func getDriverCliJs(driverDirectory string) string {
- return filepath.Join(driverDirectory, "package", "cli.js")
-}
-
-func (d *PlaywrightDriver) getDriverURLs() []string {
- platform := ""
- switch runtime.GOOS {
- case "windows":
- platform = "win32_x64"
- case "darwin":
- if runtime.GOARCH == "arm64" {
- platform = "mac-arm64"
- } else {
- platform = "mac"
- }
- case "linux":
- if runtime.GOARCH == "arm64" {
- platform = "linux-arm64"
- } else {
- platform = "linux"
- }
- }
-
- baseURLs := []string{}
- pattern := "%s/builds/driver/playwright-%s-%s.zip"
- if !d.isReleaseVersion() {
- pattern = "%s/builds/driver/next/playwright-%s-%s.zip"
- }
-
- if hostEnv := os.Getenv("PLAYWRIGHT_DOWNLOAD_HOST"); hostEnv != "" {
- baseURLs = append(baseURLs, fmt.Sprintf(pattern, hostEnv, d.Version, platform))
- } else {
- for _, mirror := range playwrightCDNMirrors {
- baseURLs = append(baseURLs, fmt.Sprintf(pattern, mirror, d.Version, platform))
- }
- }
- return baseURLs
-}
-
-// isReleaseVersion checks if the version is not a beta or alpha release
-// this helps to determine the url from where to download the driver
-func (d *PlaywrightDriver) isReleaseVersion() bool {
- return !strings.Contains(d.Version, "beta") && !strings.Contains(d.Version, "alpha") && !strings.Contains(d.Version, "next")
-}
-
-func makeFileExecutable(path string) error {
- stats, err := os.Stat(path)
- if err != nil {
- return fmt.Errorf("could not stat driver: %w", err)
- }
- if err := os.Chmod(path, stats.Mode()|0x40); err != nil {
- return fmt.Errorf("could not set permissions: %w", err)
- }
- return nil
-}
-
-func downloadDriver(driverURLs []string) (body []byte, e error) {
- for _, driverURL := range driverURLs {
- resp, err := http.Get(driverURL)
- if err != nil {
- e = errors.Join(e, fmt.Errorf("could not download driver from %s: %w", driverURL, err))
- continue
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- e = errors.Join(e, fmt.Errorf("error: got non 200 status code: %d (%s) from %s", resp.StatusCode, resp.Status, driverURL))
- continue
- }
- body, err = io.ReadAll(resp.Body)
- if err != nil {
- e = errors.Join(e, fmt.Errorf("could not read response body: %w", err))
- continue
- }
- return body, nil
- }
- return nil, e
-}