mirror of
https://github.com/taigrr/wails.git
synced 2026-04-02 05:08:54 -07:00
Compare commits
12 Commits
v2.0.0-bet
...
cross-comp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68cd6a7f0e | ||
|
|
e00ffdbeea | ||
|
|
4eebbfd22c | ||
|
|
1998736baa | ||
|
|
89579db7fa | ||
|
|
3679114445 | ||
|
|
9e5dd0bc86 | ||
|
|
8c9ca5be95 | ||
|
|
526136099b | ||
|
|
f490bf8bc9 | ||
|
|
3edca62a38 | ||
|
|
79188c503f |
17
cmd/fs.go
17
cmd/fs.go
@@ -12,6 +12,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
@@ -47,6 +48,22 @@ func (fs *FSHelper) FileExists(path string) bool {
|
||||
return fi.Mode().IsRegular()
|
||||
}
|
||||
|
||||
// FindFile returns the first occurrence of match inside path.
|
||||
func (fs *FSHelper) FindFile(path, match string) (string, error) {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if !f.IsDir() && strings.Contains(f.Name(), match) {
|
||||
return f.Name(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("file not found")
|
||||
}
|
||||
|
||||
// CreateFile creates a file at the given filename location with the contents
|
||||
// set to the given data. It will create intermediary directories if needed.
|
||||
func (fs *FSHelper) CreateFile(filename string, data []byte) error {
|
||||
|
||||
115
cmd/helpers.go
115
cmd/helpers.go
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/leaanthony/mewn"
|
||||
"github.com/leaanthony/mewn/lib"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/leaanthony/spinner"
|
||||
)
|
||||
@@ -56,22 +57,68 @@ func InstallGoDependencies(verbose bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// EmbedAssets will embed the built frontend assets via mewn.
|
||||
func EmbedAssets() ([]string, error) {
|
||||
mewnFiles := lib.GetMewnFiles([]string{}, false)
|
||||
|
||||
referencedAssets, err := lib.GetReferencedAssets(mewnFiles)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
targetFiles := []string{}
|
||||
|
||||
for _, referencedAsset := range referencedAssets {
|
||||
packfileData, err := lib.GeneratePackFileString(referencedAsset, false)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
targetFile := filepath.Join(referencedAsset.BaseDir, referencedAsset.PackageName+"-mewn.go")
|
||||
targetFiles = append(targetFiles, targetFile)
|
||||
ioutil.WriteFile(targetFile, []byte(packfileData), 0644)
|
||||
}
|
||||
|
||||
return targetFiles, nil
|
||||
}
|
||||
|
||||
// BuildApplication will attempt to build the project based on the given inputs
|
||||
func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error {
|
||||
|
||||
if buildMode == BuildModeBridge && projectOptions.CrossCompile {
|
||||
return fmt.Errorf("you cant serve the application in cross-compilation")
|
||||
}
|
||||
|
||||
// Generate Windows assets if needed
|
||||
if runtime.GOOS == "windows" {
|
||||
if projectOptions.Platform == "windows" {
|
||||
cleanUp := !packageApp
|
||||
err := NewPackageHelper().PackageWindows(projectOptions, cleanUp)
|
||||
err := NewPackageHelper(projectOptions.Platform).PackageWindows(projectOptions, cleanUp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Check Mewn is installed
|
||||
err := CheckMewn(projectOptions.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
if projectOptions.CrossCompile {
|
||||
// Check build directory
|
||||
buildDirectory := filepath.Join(fs.Cwd(), "build")
|
||||
if !fs.DirExists(buildDirectory) {
|
||||
fs.MkDir(buildDirectory)
|
||||
}
|
||||
|
||||
// Check Docker
|
||||
if err := CheckIfInstalled("docker"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check xgo
|
||||
if err := CheckIfInstalled("xgo"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Check Mewn is installed
|
||||
err := CheckMewn(projectOptions.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
compileMessage := "Packing + Compiling project"
|
||||
@@ -89,17 +136,38 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
||||
println(compileMessage)
|
||||
}
|
||||
|
||||
// embed resources
|
||||
targetFiles, err := EmbedAssets()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// cleanup temporary embedded assets
|
||||
defer func() {
|
||||
for _, filename := range targetFiles {
|
||||
if err := os.Remove(filename); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
buildCommand := slicer.String()
|
||||
buildCommand.Add("mewn")
|
||||
if projectOptions.CrossCompile {
|
||||
buildCommand.Add("xgo")
|
||||
} else {
|
||||
buildCommand.Add("mewn")
|
||||
}
|
||||
|
||||
if buildMode == BuildModeBridge {
|
||||
// Ignore errors
|
||||
buildCommand.Add("-i")
|
||||
}
|
||||
|
||||
buildCommand.Add("build")
|
||||
if !projectOptions.CrossCompile {
|
||||
buildCommand.Add("build")
|
||||
}
|
||||
|
||||
if binaryName != "" {
|
||||
if binaryName != "" && !projectOptions.CrossCompile {
|
||||
// Alter binary name based on OS
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
@@ -115,7 +183,7 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
||||
}
|
||||
|
||||
// If we are forcing a rebuild
|
||||
if forceRebuild {
|
||||
if forceRebuild && !projectOptions.CrossCompile {
|
||||
buildCommand.Add("-a")
|
||||
}
|
||||
|
||||
@@ -126,7 +194,7 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
||||
}
|
||||
|
||||
// Add windows flags
|
||||
if runtime.GOOS == "windows" && buildMode == BuildModeProd {
|
||||
if projectOptions.Platform == "windows" && buildMode == BuildModeProd {
|
||||
ldflags += "-H windowsgui "
|
||||
}
|
||||
|
||||
@@ -143,6 +211,13 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
||||
}
|
||||
|
||||
buildCommand.AddSlice([]string{"-ldflags", ldflags})
|
||||
|
||||
if projectOptions.CrossCompile {
|
||||
buildCommand.Add("-targets", projectOptions.Platform+"/"+projectOptions.Architecture)
|
||||
buildCommand.Add("-out", "build/"+binaryName)
|
||||
buildCommand.Add("./")
|
||||
}
|
||||
|
||||
err = NewProgramHelper(projectOptions.Verbose).RunCommandArray(buildCommand.AsSlice())
|
||||
if err != nil {
|
||||
if packSpinner != nil {
|
||||
@@ -169,7 +244,7 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
||||
func PackageApplication(projectOptions *ProjectOptions) error {
|
||||
// Package app
|
||||
message := "Generating .app"
|
||||
if runtime.GOOS == "windows" {
|
||||
if projectOptions.Platform == "windows" {
|
||||
err := CheckWindres()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -177,12 +252,15 @@ func PackageApplication(projectOptions *ProjectOptions) error {
|
||||
message = "Generating resource bundle"
|
||||
}
|
||||
var packageSpinner *spinner.Spinner
|
||||
if projectOptions.Verbose {
|
||||
if !projectOptions.Verbose {
|
||||
packageSpinner = spinner.New(message)
|
||||
packageSpinner.SetSpinSpeed(50)
|
||||
packageSpinner.Start()
|
||||
} else {
|
||||
println(message)
|
||||
}
|
||||
err := NewPackageHelper().Package(projectOptions)
|
||||
|
||||
err := NewPackageHelper(projectOptions.Platform).Package(projectOptions)
|
||||
if err != nil {
|
||||
if packageSpinner != nil {
|
||||
packageSpinner.Error()
|
||||
@@ -254,6 +332,15 @@ func CheckWindres() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckIfInstalled returns if application is installed
|
||||
func CheckIfInstalled(application string) (err error) {
|
||||
programHelper := NewProgramHelper()
|
||||
if !programHelper.IsInstalled(application) {
|
||||
return fmt.Errorf("%s not installed. Ensure you have installed %s correctly", application, application)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstallFrontendDeps attempts to install the frontend dependencies based on the given options
|
||||
func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forceRebuild bool, caller string) error {
|
||||
|
||||
|
||||
@@ -18,17 +18,19 @@ import (
|
||||
|
||||
// PackageHelper helps with the 'wails package' command
|
||||
type PackageHelper struct {
|
||||
fs *FSHelper
|
||||
log *Logger
|
||||
system *SystemHelper
|
||||
platform string
|
||||
fs *FSHelper
|
||||
log *Logger
|
||||
system *SystemHelper
|
||||
}
|
||||
|
||||
// NewPackageHelper creates a new PackageHelper!
|
||||
func NewPackageHelper() *PackageHelper {
|
||||
func NewPackageHelper(platform string) *PackageHelper {
|
||||
return &PackageHelper{
|
||||
fs: NewFSHelper(),
|
||||
log: NewLogger(),
|
||||
system: NewSystemHelper(),
|
||||
platform: platform,
|
||||
fs: NewFSHelper(),
|
||||
log: NewLogger(),
|
||||
system: NewSystemHelper(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,16 +65,23 @@ func defaultString(val string, defaultVal string) string {
|
||||
func (b *PackageHelper) getPackageFileBaseDir() string {
|
||||
// Calculate template base dir
|
||||
_, filename, _, _ := runtime.Caller(1)
|
||||
return filepath.Join(path.Dir(filename), "packages", runtime.GOOS)
|
||||
return filepath.Join(path.Dir(filename), "packages", b.platform)
|
||||
}
|
||||
|
||||
// Package the application into a platform specific package
|
||||
func (b *PackageHelper) Package(po *ProjectOptions) error {
|
||||
switch runtime.GOOS {
|
||||
switch b.platform {
|
||||
case "darwin":
|
||||
// Check we have the exe
|
||||
if !b.fs.FileExists(po.BinaryName) {
|
||||
return fmt.Errorf("cannot bundle non-existent binary file '%s'. Please build with 'wails build' first", po.BinaryName)
|
||||
// Check cross-compiled application
|
||||
if b.platform == runtime.GOOS {
|
||||
return fmt.Errorf("cannot bundle non-existent binary file '%s'. Please build with 'wails build' first", po.BinaryName)
|
||||
}
|
||||
|
||||
if _, err := b.fs.FindFile(path.Join(b.fs.Cwd(), "build"), "darwin"); err != nil {
|
||||
return fmt.Errorf("cannot bundle non-existent cross-compiled binary file '%s'. Please build with 'wails build -x darwin' first", po.BinaryName)
|
||||
}
|
||||
}
|
||||
return b.packageOSX(po)
|
||||
case "windows":
|
||||
@@ -80,7 +89,7 @@ func (b *PackageHelper) Package(po *ProjectOptions) error {
|
||||
case "linux":
|
||||
return fmt.Errorf("linux is not supported at this time. Please see https://github.com/wailsapp/wails/issues/2")
|
||||
default:
|
||||
return fmt.Errorf("platform '%s' not supported for bundling yet", runtime.GOOS)
|
||||
return fmt.Errorf("platform '%s' not supported for bundling yet", b.platform)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +112,22 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
|
||||
|
||||
// Check binary exists
|
||||
source := path.Join(b.fs.Cwd(), exe)
|
||||
|
||||
if b.platform != runtime.GOOS {
|
||||
|
||||
file, err := b.fs.FindFile(path.Join(b.fs.Cwd(), "build"), "darwin")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// rename to exe
|
||||
if err := os.Rename(path.Join(b.fs.Cwd(), "build", file), path.Join(b.fs.Cwd(), "build", exe)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source = path.Join(b.fs.Cwd(), "build", exe)
|
||||
}
|
||||
|
||||
if !b.fs.FileExists(source) {
|
||||
// We need to build!
|
||||
return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", exe)
|
||||
@@ -192,16 +217,36 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
|
||||
// Build syso
|
||||
sysofile := filepath.Join(b.fs.Cwd(), basename+"-res.syso")
|
||||
|
||||
batfile, err := fs.LocalDir(".")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// cross-compile
|
||||
if b.platform != runtime.GOOS {
|
||||
folder, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
windresBatFile := filepath.Join(batfile.fullPath, "windres.bat")
|
||||
windresCommand := []string{windresBatFile, sysofile, tgtRCFile}
|
||||
err = NewProgramHelper().RunCommandArray(windresCommand)
|
||||
if err != nil {
|
||||
return err
|
||||
args := []string{
|
||||
"docker", "run", "--rm",
|
||||
"-v", folder + ":/build",
|
||||
"--entrypoint", "/bin/sh",
|
||||
"techknowlogick/xgo",
|
||||
"-c", "/usr/bin/x86_64-w64-mingw32-windres -o /build/" + basename + "-res.syso /build/" + basename + ".rc",
|
||||
}
|
||||
|
||||
if err := NewProgramHelper().RunCommandArray(args); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
batfile, err := fs.LocalDir(".")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
windresBatFile := filepath.Join(batfile.fullPath, "windres.bat")
|
||||
windresCommand := []string{windresBatFile, sysofile, tgtRCFile}
|
||||
err = NewProgramHelper().RunCommandArray(windresCommand)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
|
||||
@@ -158,7 +158,10 @@ type ProjectOptions struct {
|
||||
selectedTemplate *TemplateDetails
|
||||
WailsVersion string
|
||||
typescriptDefsFilename string
|
||||
Verbose bool `json:"-"`
|
||||
Verbose bool `json:"-"`
|
||||
CrossCompile bool `json:"-"`
|
||||
Platform string `json:"-"`
|
||||
Architecture string `json:"-"`
|
||||
}
|
||||
|
||||
// Defaults sets the default project template
|
||||
|
||||
@@ -3,7 +3,10 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/leaanthony/spinner"
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
)
|
||||
@@ -15,6 +18,7 @@ func init() {
|
||||
var debugMode = false
|
||||
var typescriptFilename = ""
|
||||
var verbose = false
|
||||
var platform = ""
|
||||
|
||||
buildSpinner := spinner.NewSpinner()
|
||||
buildSpinner.SetSpinSpeed(50)
|
||||
@@ -26,7 +30,8 @@ func init() {
|
||||
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
||||
BoolFlag("d", "Build in Debug mode", &debugMode).
|
||||
BoolFlag("verbose", "Verbose output", &verbose).
|
||||
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename)
|
||||
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename).
|
||||
StringFlag("x", "Cross-compile application to specified platform via xgo", &platform)
|
||||
|
||||
initCmd.Action(func() error {
|
||||
|
||||
@@ -130,6 +135,29 @@ func init() {
|
||||
buildSpinner.Success()
|
||||
}
|
||||
|
||||
// Set cross-compile
|
||||
projectOptions.Platform = runtime.GOOS
|
||||
if len(platform) > 0 {
|
||||
|
||||
projectOptions.CrossCompile = true
|
||||
projectOptions.Platform = platform
|
||||
projectOptions.Architecture = "amd64"
|
||||
|
||||
// check build architecture
|
||||
if strings.Contains(platform, "/") {
|
||||
p := strings.Split(platform, "/")
|
||||
projectOptions.Platform = p[0]
|
||||
projectOptions.Architecture = p[1]
|
||||
}
|
||||
|
||||
// Check supported platforms
|
||||
supportedPlatforms := slicer.String([]string{"linux/amd64", "linux/386", "windows/amd64", "windows/386", "darwin/amd64"})
|
||||
targetPlatform := projectOptions.Platform + "/" + projectOptions.Architecture
|
||||
if !supportedPlatforms.Contains(targetPlatform) {
|
||||
println("\n*** WARNING: Unsupported target platform", targetPlatform+".", "Supported:", supportedPlatforms.Join(", "))
|
||||
}
|
||||
}
|
||||
|
||||
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, packageApp, projectOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
2
go.mod
2
go.mod
@@ -10,7 +10,7 @@ require (
|
||||
github.com/kennygrant/sanitize v1.2.4
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/leaanthony/mewn v0.10.7
|
||||
github.com/leaanthony/slicer v1.4.0
|
||||
github.com/leaanthony/slicer v1.4.1
|
||||
github.com/leaanthony/spinner v0.5.3
|
||||
github.com/mattn/go-colorable v0.1.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.7 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -28,8 +28,8 @@ github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmPA=
|
||||
github.com/leaanthony/mewn v0.10.7/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
||||
github.com/leaanthony/slicer v1.4.0 h1:Q9u4w+UBU4WHjXnEDdz+eRLMKF/rnyosRBiqULnc1J8=
|
||||
github.com/leaanthony/slicer v1.4.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
github.com/leaanthony/slicer v1.4.1 h1:X/SmRIDhkUAolP79mSTO0jTcVX1k504PJBqvV6TwP0w=
|
||||
github.com/leaanthony/slicer v1.4.1/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y=
|
||||
github.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo=
|
||||
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
||||
|
||||
Reference in New Issue
Block a user