package main import ( "flag" "io" "os" "os/exec" "path/filepath" "runtime" "strings" ) func main() { var binaryPath string var buildAssetsPath string var frontendURL string var iconPath string var mode string flag.StringVar(&binaryPath, "binary", "", "") flag.StringVar(&buildAssetsPath, "build-assets", "", "") flag.StringVar(&frontendURL, "frontend-url", "http://127.0.0.1:9245", "") flag.StringVar(&iconPath, "icon", "", "") flag.StringVar(&mode, "mode", "run", "") flag.Parse() require(binaryPath != "", "missing --binary") require(buildAssetsPath != "", "missing --build-assets") environment := os.Environ() if mode == "dev" && os.Getenv("FRONTEND_DEVSERVER_URL") == "" { environment = append(environment, "FRONTEND_DEVSERVER_URL="+frontendURL) } if runtime.GOOS == "darwin" { os.Exit(runDarwin(binaryPath, buildAssetsPath, iconPath, mode, environment)) } command := exec.Command(binaryPath) command.Stdout = os.Stdout command.Stderr = os.Stderr command.Stdin = os.Stdin command.Env = environment if err := command.Run(); err != nil { if exitError, ok := err.(*exec.ExitError); ok { os.Exit(exitError.ExitCode()) } panic(err) } } func runDarwin(binaryPath string, buildAssetsPath string, iconPath string, mode string, environment []string) int { appName := strings.TrimSuffix(filepath.Base(binaryPath), filepath.Ext(binaryPath)) if appName == "" { appName = "wails-app" } appDir := filepath.Join(os.TempDir(), appName+"-bazel-"+mode) defer os.RemoveAll(appDir) appContents := filepath.Join(appDir, "Contents") appMacOS := filepath.Join(appContents, "MacOS") appResources := filepath.Join(appContents, "Resources") appBinary := filepath.Join(appMacOS, appName) must(os.MkdirAll(appMacOS, 0o755)) must(os.MkdirAll(appResources, 0o755)) must(copyFile(binaryPath, appBinary, 0o755)) for _, candidate := range []string{ filepath.Join(buildAssetsPath, "darwin", "Info.dev.plist"), filepath.Join(buildAssetsPath, "darwin", "Info.plist"), } { if mode != "dev" && strings.HasSuffix(candidate, "Info.dev.plist") { continue } if _, err := os.Stat(candidate); err == nil { must(copyFile(candidate, filepath.Join(appContents, "Info.plist"), 0o644)) break } } if iconPath != "" { if _, err := os.Stat(iconPath); err == nil { must(copyFile(iconPath, filepath.Join(appResources, filepath.Base(iconPath)), 0o644)) } } if _, err := os.Stat("/usr/bin/codesign"); err == nil { codesign := exec.Command("/usr/bin/codesign", "--force", "--deep", "--sign", "-", appDir) _ = codesign.Run() } command := exec.Command(appBinary) command.Stdout = os.Stdout command.Stderr = os.Stderr command.Stdin = os.Stdin command.Env = environment if err := command.Run(); err != nil { if exitError, ok := err.(*exec.ExitError); ok { return exitError.ExitCode() } panic(err) } return 0 } func copyFile(sourcePath string, destinationPath string, mode os.FileMode) error { sourceFile, err := os.Open(sourcePath) if err != nil { return err } defer sourceFile.Close() destinationFile, err := os.Create(destinationPath) if err != nil { return err } defer destinationFile.Close() if _, err := io.Copy(destinationFile, sourceFile); err != nil { return err } return destinationFile.Chmod(mode) } func must(err error) { if err != nil { panic(err) } } func require(condition bool, message string) { if !condition { panic(message) } }