mirror of
https://github.com/taigrr/wails.git
synced 2026-04-02 13:19:00 -07:00
Compare commits
7 Commits
firebug
...
migrate-to
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0367bdf8be | ||
|
|
594efcb79e | ||
|
|
8c96bba1f9 | ||
|
|
1d785d7d40 | ||
|
|
cfc0cc053b | ||
|
|
d572418ec3 | ||
|
|
8c7480d277 |
@@ -100,6 +100,19 @@ func (p *ProgramHelper) InstallGoPackage(packageName string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// InstallNPMPackage installs the given npm package
|
||||
func (p *ProgramHelper) InstallNPMPackage(packageName string, save bool) error {
|
||||
args := strings.Split("install "+packageName, " ")
|
||||
if save {
|
||||
args = append(args, "--save")
|
||||
}
|
||||
_, stderr, err := p.shell.Run("npm", args...)
|
||||
if err != nil {
|
||||
fmt.Println(stderr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// RunCommand runs the given command
|
||||
func (p *ProgramHelper) RunCommand(command string) error {
|
||||
args := strings.Split(command, " ")
|
||||
|
||||
@@ -13,6 +13,18 @@ import (
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
// PackageManager indicates different package managers
|
||||
type PackageManager int
|
||||
|
||||
const (
|
||||
// UNKNOWN package manager
|
||||
UNKNOWN PackageManager = iota
|
||||
// NPM package manager
|
||||
NPM
|
||||
// YARN package manager
|
||||
YARN
|
||||
)
|
||||
|
||||
type author struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
@@ -153,6 +165,23 @@ func (po *ProjectOptions) Defaults() {
|
||||
po.WailsVersion = Version
|
||||
}
|
||||
|
||||
// GetNPMBinaryName returns the type of package manager used by the project
|
||||
func (po *ProjectOptions) GetNPMBinaryName() (PackageManager, error) {
|
||||
if po.FrontEnd == nil {
|
||||
return UNKNOWN, fmt.Errorf("No frontend specified in project options")
|
||||
}
|
||||
|
||||
if strings.Index(po.FrontEnd.Install, "npm") > -1 {
|
||||
return NPM, nil
|
||||
}
|
||||
|
||||
if strings.Index(po.FrontEnd.Install, "yarn") > -1 {
|
||||
return YARN, nil
|
||||
}
|
||||
|
||||
return UNKNOWN, nil
|
||||
}
|
||||
|
||||
// PromptForInputs asks the user to input project details
|
||||
func (po *ProjectOptions) PromptForInputs() error {
|
||||
|
||||
|
||||
408
cmd/wails/15_migrate.go
Normal file
408
cmd/wails/15_migrate.go
Normal file
@@ -0,0 +1,408 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/leaanthony/spinner"
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
)
|
||||
|
||||
// Constants
|
||||
var checkSpinner = spinner.NewSpinner()
|
||||
var migrateProjectOptions = &cmd.ProjectOptions{}
|
||||
var migrateFS = cmd.NewFSHelper()
|
||||
var migrateGithub = cmd.NewGitHubHelper()
|
||||
var programHelper = cmd.NewProgramHelper()
|
||||
var lessThanV1 *semver.Constraints
|
||||
|
||||
// The user's go.mod
|
||||
var goMod string
|
||||
var goModFile string
|
||||
|
||||
// The user's main.js
|
||||
var mainJSFile string
|
||||
var mainJSContents string
|
||||
|
||||
// Frontend directory
|
||||
var frontEndDir string
|
||||
|
||||
func init() {
|
||||
|
||||
var dryrun bool
|
||||
var err error
|
||||
|
||||
lessThanV1, err = semver.NewConstraint("< v1.0.0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// var forceRebuild = false
|
||||
checkSpinner.SetSpinSpeed(50)
|
||||
|
||||
commandDescription := `EXPERIMENTAL - This command attempts to migrate projects to the latest Wails version.`
|
||||
updateCmd := app.Command("migrate", "Migrate projects to latest Wails release").
|
||||
LongDescription(commandDescription).
|
||||
BoolFlag("dryrun", "Only display what would be done", &dryrun)
|
||||
|
||||
updateCmd.Action(func() error {
|
||||
|
||||
message := "Migrate Project"
|
||||
logger.PrintSmallBanner(message)
|
||||
logger.Red("WARNING: This is an experimental command. Ensure you have backups of your project!")
|
||||
logger.Red("It currently only supports npm based projects.")
|
||||
fmt.Println()
|
||||
|
||||
// Check project directory
|
||||
err := checkProjectDirectory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find Wails version from go.mod
|
||||
wailsVersion, err := getWailsVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get latest stable version
|
||||
var latestVersion *semver.Version
|
||||
latestVersion, err = getLatestWailsVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var canMigrate bool
|
||||
canMigrate, err = canMigrateVersion(wailsVersion, latestVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !canMigrate {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check for wailsbridge
|
||||
wailsBridge, err := checkWailsBridge()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Is main.js using bridge.Init()
|
||||
canUpdateMainJS, err := checkMainJS()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Check if we are using legacy js runtime
|
||||
|
||||
// Operations
|
||||
logger.Yellow("Operations to perform:")
|
||||
|
||||
logger.Yellowf(" - Update to Wails v%s\n", latestVersion)
|
||||
|
||||
if len(wailsBridge) > 0 {
|
||||
logger.Yellow(" - Delete wailsbridge.js")
|
||||
}
|
||||
|
||||
if canUpdateMainJS {
|
||||
logger.Yellow(" - Patch main.js")
|
||||
}
|
||||
|
||||
logger.Yellow(" - Ensure '@wailsapp/runtime` module is installed")
|
||||
|
||||
if dryrun {
|
||||
logger.White("Exiting: Dry Run")
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Red("*WARNING* About to modify your project!")
|
||||
logger.Red("Type 'YES' to continue: ")
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
scanner.Scan()
|
||||
input := scanner.Text()
|
||||
if input != "YES" {
|
||||
logger.Red("ABORTED!")
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Yellow("Let's do this!")
|
||||
|
||||
err = updateWailsVersion(wailsVersion, latestVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(wailsBridge) > 0 {
|
||||
err = deleteWailsBridge(wailsBridge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if canUpdateMainJS {
|
||||
err = patchMainJS()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Install runtime
|
||||
err = installWailsRuntime()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
logger.Yellow("Migration complete! Check project by running `wails build`.")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func checkProjectDirectory() error {
|
||||
// Get versions
|
||||
checkSpinner.Start("Check Project Directory")
|
||||
|
||||
// Check we are in project directory
|
||||
err := migrateProjectOptions.LoadConfig(migrateFS.Cwd())
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory")
|
||||
}
|
||||
|
||||
checkSpinner.Success()
|
||||
return nil
|
||||
}
|
||||
|
||||
func getWailsVersion() (*semver.Version, error) {
|
||||
checkSpinner.Start("Get Wails Version")
|
||||
var result *semver.Version
|
||||
|
||||
// Load file
|
||||
var err error
|
||||
goModFile, err = filepath.Abs(filepath.Join(".", "go.mod"))
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return nil, fmt.Errorf("Unable to load go.mod at %s", goModFile)
|
||||
}
|
||||
goMod, err = migrateFS.LoadAsString(goModFile)
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return nil, fmt.Errorf("Unable to load go.mod")
|
||||
}
|
||||
|
||||
// Find wails version
|
||||
versionRegexp := regexp.MustCompile(`.*github.com/wailsapp/wails.*(v\d+.\d+.\d+)`)
|
||||
versions := versionRegexp.FindStringSubmatch(goMod)
|
||||
|
||||
if len(versions) != 2 {
|
||||
return nil, fmt.Errorf("Unable to determine Wails version")
|
||||
}
|
||||
|
||||
version := versions[1]
|
||||
result, err = semver.NewVersion(version)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse Wails version: %s", version)
|
||||
}
|
||||
checkSpinner.Success("Found Wails Version: " + version)
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
func canMigrateVersion(wailsVersion *semver.Version, latestVersion *semver.Version) (bool, error) {
|
||||
checkSpinner.Start("Checking ability to Migrate")
|
||||
|
||||
// Check if we are at the latest version!!!!
|
||||
if wailsVersion.Equal(latestVersion) || wailsVersion.GreaterThan(latestVersion) {
|
||||
checkSpinner.Errorf("Checking ability to Migrate: No! (v%s >= v%s)", wailsVersion, latestVersion)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Check for < v1.0.0
|
||||
if lessThanV1.Check(wailsVersion) {
|
||||
checkSpinner.Successf("Checking ability to Migrate: Yes! (v%s < v1.0.0)", wailsVersion)
|
||||
return true, nil
|
||||
}
|
||||
checkSpinner.Error("Unable to migrate")
|
||||
return false, fmt.Errorf("No migration rules for version %s", wailsVersion)
|
||||
}
|
||||
|
||||
func checkWailsBridge() (string, error) {
|
||||
checkSpinner.Start("Checking if legacy Wails Bridge present")
|
||||
|
||||
// Check frontend dir is available
|
||||
if migrateProjectOptions.FrontEnd == nil ||
|
||||
len(migrateProjectOptions.FrontEnd.Dir) == 0 ||
|
||||
!migrateFS.DirExists(migrateProjectOptions.FrontEnd.Dir) {
|
||||
checkSpinner.Error("Unable to determine frontend directory")
|
||||
return "", fmt.Errorf("Unable to determine frontend directory")
|
||||
}
|
||||
|
||||
frontEndDir = migrateProjectOptions.FrontEnd.Dir
|
||||
|
||||
wailsBridgePath, err := filepath.Abs(filepath.Join(".", frontEndDir, "src", "wailsbridge.js"))
|
||||
if err != nil {
|
||||
checkSpinner.Error(err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
// If it doesn't exist, return blank string
|
||||
if !migrateFS.FileExists(wailsBridgePath) {
|
||||
checkSpinner.Success("Checking if legacy Wails Bridge present: No")
|
||||
return "", nil
|
||||
}
|
||||
|
||||
checkSpinner.Success("Checking if legacy Wails Bridge present: Yes")
|
||||
return wailsBridgePath, nil
|
||||
|
||||
}
|
||||
|
||||
// This function determines if the main.js file using wailsbridge can be auto-updated
|
||||
func checkMainJS() (bool, error) {
|
||||
|
||||
checkSpinner.Start("Checking if main.js can be migrated")
|
||||
var err error
|
||||
|
||||
// Check main.js is there
|
||||
if migrateProjectOptions.FrontEnd == nil ||
|
||||
len(migrateProjectOptions.FrontEnd.Dir) == 0 ||
|
||||
!migrateFS.DirExists(migrateProjectOptions.FrontEnd.Dir) {
|
||||
checkSpinner.Error("Unable to determine frontend directory")
|
||||
return false, fmt.Errorf("Unable to determine frontend directory")
|
||||
}
|
||||
|
||||
frontEndDir = migrateProjectOptions.FrontEnd.Dir
|
||||
|
||||
mainJSFile, err = filepath.Abs(filepath.Join(".", frontEndDir, "src", "main.js"))
|
||||
if err != nil {
|
||||
checkSpinner.Error("Unable to find main.js")
|
||||
return false, err
|
||||
}
|
||||
|
||||
mainJSContents, err = migrateFS.LoadAsString(mainJSFile)
|
||||
if err != nil {
|
||||
checkSpinner.Error("Unable to load main.js")
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Check we have a line like: import Bridge from "./wailsbridge";
|
||||
if strings.Index(mainJSContents, `import Bridge from "./wailsbridge";`) == -1 {
|
||||
checkSpinner.Success("Checking if main.js can be migrated: No - Cannot find `import Bridge`")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Check we have a line like: Bridge.Start(() => {
|
||||
if strings.Index(mainJSContents, `Bridge.Start(`) == -1 {
|
||||
checkSpinner.Success("Checking if main.js can be migrated: No - Cannot find `Bridge.Start`")
|
||||
return false, nil
|
||||
}
|
||||
checkSpinner.Success("Checking if main.js can be migrated: Yes")
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func getLatestWailsVersion() (*semver.Version, error) {
|
||||
checkSpinner.Start("Checking GitHub for latest Wails version")
|
||||
version, err := migrateGithub.GetLatestStableRelease()
|
||||
if err != nil {
|
||||
checkSpinner.Error("Checking GitHub for latest Wails version: Failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
checkSpinner.Successf("Checking GitHub for latest Wails version: v%s", version)
|
||||
return version.Version, nil
|
||||
}
|
||||
|
||||
func updateWailsVersion(currentVersion, latestVersion *semver.Version) error {
|
||||
// Patch go.mod
|
||||
checkSpinner.Start("Patching go.mod")
|
||||
|
||||
wailsModule := "github.com/wailsapp/wails"
|
||||
old := fmt.Sprintf("%s v%s", wailsModule, currentVersion)
|
||||
new := fmt.Sprintf("%s v%s", wailsModule, latestVersion)
|
||||
|
||||
goMod = strings.Replace(goMod, old, new, -1)
|
||||
err := ioutil.WriteFile(goModFile, []byte(goMod), 0600)
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return err
|
||||
}
|
||||
|
||||
checkSpinner.Success()
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteWailsBridge(bridgeFilename string) error {
|
||||
// Patch go.mod
|
||||
checkSpinner.Start("Delete legacy wailsbridge.js")
|
||||
|
||||
err := migrateFS.RemoveFile(bridgeFilename)
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return err
|
||||
}
|
||||
|
||||
checkSpinner.Success()
|
||||
return nil
|
||||
}
|
||||
|
||||
func patchMainJS() error {
|
||||
// Patch main.js
|
||||
checkSpinner.Start("Patching main.js")
|
||||
|
||||
// Patch import line
|
||||
oldImportLine := `import Bridge from "./wailsbridge";`
|
||||
newImportLine := `import * as Wails from "@wailsapp/runtime";`
|
||||
mainJSContents = strings.Replace(mainJSContents, oldImportLine, newImportLine, -1)
|
||||
|
||||
// Patch Start line
|
||||
oldStartLine := `Bridge.Start`
|
||||
newStartLine := `Wails.Init`
|
||||
mainJSContents = strings.Replace(mainJSContents, oldStartLine, newStartLine, -1)
|
||||
|
||||
err := ioutil.WriteFile(mainJSFile, []byte(mainJSContents), 0600)
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return err
|
||||
}
|
||||
|
||||
checkSpinner.Success()
|
||||
return nil
|
||||
}
|
||||
|
||||
func installWailsRuntime() error {
|
||||
|
||||
checkSpinner.Start("Installing @wailsapp/runtime module")
|
||||
|
||||
// Change to the frontend directory
|
||||
err := os.Chdir(frontEndDir)
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Determine package manager
|
||||
packageManager, err := migrateProjectOptions.GetNPMBinaryName()
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return nil
|
||||
}
|
||||
|
||||
switch packageManager {
|
||||
case cmd.NPM:
|
||||
// npm install --save @wailsapp/runtime
|
||||
programHelper.InstallNPMPackage("@wailsapp/runtime", true)
|
||||
default:
|
||||
checkSpinner.Error()
|
||||
return fmt.Errorf("Unknown package manager")
|
||||
}
|
||||
|
||||
checkSpinner.Success()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user