mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 22:13:36 +08:00
Refactored build command (#2123)
* Refactored build command * Update v2/cmd/wails/build.go Co-authored-by: stffabi <stffabi@users.noreply.github.com> * WIP * Refactor `wails doctor` * Refactor `wails dev` * Refactor `wails dev` * Fix merge conflict * Fix test * Update build_and_test.yml Co-authored-by: stffabi <stffabi@users.noreply.github.com>
This commit is contained in:
parent
9d53db4281
commit
ea6aee91f1
1
.github/workflows/build_and_test.yml
vendored
1
.github/workflows/build_and_test.yml
vendored
@ -29,6 +29,7 @@ jobs:
|
|||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
working-directory: ./v2
|
||||||
run: go test -v ./...
|
run: go test -v ./...
|
||||||
|
|
||||||
test_templates:
|
test_templates:
|
||||||
|
254
v2/cmd/wails/build.go
Normal file
254
v2/cmd/wails/build.go
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
|
"github.com/pterm/pterm"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/flags"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/gomod"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/project"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildApplication(f *flags.Build) error {
|
||||||
|
|
||||||
|
if f.NoColour {
|
||||||
|
pterm.DisableColor()
|
||||||
|
colour.ColourEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
quiet := f.Verbosity == flags.Quiet
|
||||||
|
|
||||||
|
// Create logger
|
||||||
|
logger := clilogger.New(os.Stdout)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
if quiet {
|
||||||
|
pterm.DisableOutput()
|
||||||
|
} else {
|
||||||
|
app.PrintBanner()
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.Process()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
projectOptions, err := project.Load(cwd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create BuildOptions
|
||||||
|
buildOptions := &build.Options{
|
||||||
|
Logger: logger,
|
||||||
|
OutputType: "desktop",
|
||||||
|
OutputFile: f.OutputFilename,
|
||||||
|
CleanBinDirectory: f.Clean,
|
||||||
|
Mode: f.GetBuildMode(),
|
||||||
|
Pack: !f.NoPackage,
|
||||||
|
LDFlags: f.LdFlags,
|
||||||
|
Compiler: f.Compiler,
|
||||||
|
SkipModTidy: f.SkipModTidy,
|
||||||
|
Verbosity: f.Verbosity,
|
||||||
|
ForceBuild: f.ForceBuild,
|
||||||
|
IgnoreFrontend: f.SkipFrontend,
|
||||||
|
Compress: f.Upx,
|
||||||
|
CompressFlags: f.UpxFlags,
|
||||||
|
UserTags: f.GetTags(),
|
||||||
|
WebView2Strategy: f.GetWebView2Strategy(),
|
||||||
|
TrimPath: f.TrimPath,
|
||||||
|
RaceDetector: f.RaceDetector,
|
||||||
|
WindowsConsole: f.WindowsConsole,
|
||||||
|
Obfuscated: f.Obfuscated,
|
||||||
|
GarbleArgs: f.GarbleArgs,
|
||||||
|
SkipBindings: f.SkipBindings,
|
||||||
|
ProjectData: projectOptions,
|
||||||
|
}
|
||||||
|
|
||||||
|
tableData := pterm.TableData{
|
||||||
|
{"Platform(s)", f.Platform},
|
||||||
|
{"Compiler", f.GetCompilerPath()},
|
||||||
|
{"Skip Bindings", bool2Str(f.SkipBindings)},
|
||||||
|
{"Build Mode", f.GetBuildModeAsString()},
|
||||||
|
{"Frontend Directory", projectOptions.GetFrontendDir()},
|
||||||
|
{"Obfuscated", bool2Str(f.Obfuscated)},
|
||||||
|
}
|
||||||
|
if f.Obfuscated {
|
||||||
|
tableData = append(tableData, []string{"Garble Args", f.GarbleArgs})
|
||||||
|
}
|
||||||
|
tableData = append(tableData, pterm.TableData{
|
||||||
|
{"Skip Frontend", bool2Str(f.SkipFrontend)},
|
||||||
|
{"Compress", bool2Str(f.Upx)},
|
||||||
|
{"Package", bool2Str(!f.NoPackage)},
|
||||||
|
{"Clean Bin Dir", bool2Str(f.Clean)},
|
||||||
|
{"LDFlags", f.LdFlags},
|
||||||
|
{"Tags", "[" + strings.Join(f.GetTags(), ",") + "]"},
|
||||||
|
{"Race Detector", bool2Str(f.RaceDetector)},
|
||||||
|
}...)
|
||||||
|
if len(buildOptions.OutputFile) > 0 && f.GetTargets().Length() == 1 {
|
||||||
|
tableData = append(tableData, []string{"Output File", f.OutputFilename})
|
||||||
|
}
|
||||||
|
pterm.DefaultSection.Println("Build Options")
|
||||||
|
|
||||||
|
err = pterm.DefaultTable.WithData(tableData).Render()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gomod.SyncGoMod(logger, f.UpdateWailsVersionGoMod)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check platform
|
||||||
|
validPlatformArch := slicer.String([]string{
|
||||||
|
"darwin",
|
||||||
|
"darwin/amd64",
|
||||||
|
"darwin/arm64",
|
||||||
|
"darwin/universal",
|
||||||
|
"linux",
|
||||||
|
"linux/amd64",
|
||||||
|
"linux/arm64",
|
||||||
|
"linux/arm",
|
||||||
|
"windows",
|
||||||
|
"windows/amd64",
|
||||||
|
"windows/arm64",
|
||||||
|
"windows/386",
|
||||||
|
})
|
||||||
|
|
||||||
|
outputBinaries := map[string]string{}
|
||||||
|
|
||||||
|
// Allows cancelling the build after the first error. It would be nice if targets.Each would support funcs
|
||||||
|
// returning an error.
|
||||||
|
var targetErr error
|
||||||
|
targets := f.GetTargets()
|
||||||
|
targets.Each(func(platform string) {
|
||||||
|
if targetErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !validPlatformArch.Contains(platform) {
|
||||||
|
buildOptions.Logger.Println("platform '%s' is not supported - skipping. Supported platforms: %s", platform, validPlatformArch.Join(","))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
desiredFilename := projectOptions.OutputFilename
|
||||||
|
if desiredFilename == "" {
|
||||||
|
desiredFilename = projectOptions.Name
|
||||||
|
}
|
||||||
|
desiredFilename = strings.TrimSuffix(desiredFilename, ".exe")
|
||||||
|
|
||||||
|
// Calculate platform and arch
|
||||||
|
platformSplit := strings.Split(platform, "/")
|
||||||
|
buildOptions.Platform = platformSplit[0]
|
||||||
|
buildOptions.Arch = f.GetDefaultArch()
|
||||||
|
if len(platformSplit) > 1 {
|
||||||
|
buildOptions.Arch = platformSplit[1]
|
||||||
|
}
|
||||||
|
banner := "Building target: " + buildOptions.Platform + "/" + buildOptions.Arch
|
||||||
|
pterm.DefaultSection.Println(banner)
|
||||||
|
|
||||||
|
if f.Upx && platform == "darwin/universal" {
|
||||||
|
pterm.Warning.Println("Warning: compress flag unsupported for universal binaries. Ignoring.")
|
||||||
|
f.Upx = false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch buildOptions.Platform {
|
||||||
|
case "linux":
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
pterm.Warning.Println("Crosscompiling to Linux not currently supported.\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "darwin":
|
||||||
|
if runtime.GOOS != "darwin" {
|
||||||
|
pterm.Warning.Println("Crosscompiling to Mac not currently supported.\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
macTargets := targets.Filter(func(platform string) bool {
|
||||||
|
return strings.HasPrefix(platform, "darwin")
|
||||||
|
})
|
||||||
|
if macTargets.Length() == 2 {
|
||||||
|
buildOptions.BundleName = fmt.Sprintf("%s-%s.app", desiredFilename, buildOptions.Arch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if targets.Length() > 1 {
|
||||||
|
// target filename
|
||||||
|
switch buildOptions.Platform {
|
||||||
|
case "windows":
|
||||||
|
desiredFilename = fmt.Sprintf("%s-%s", desiredFilename, buildOptions.Arch)
|
||||||
|
case "linux", "darwin":
|
||||||
|
desiredFilename = fmt.Sprintf("%s-%s-%s", desiredFilename, buildOptions.Platform, buildOptions.Arch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if buildOptions.Platform == "windows" {
|
||||||
|
desiredFilename += ".exe"
|
||||||
|
}
|
||||||
|
buildOptions.OutputFile = desiredFilename
|
||||||
|
|
||||||
|
if f.OutputFilename != "" {
|
||||||
|
buildOptions.OutputFile = f.OutputFilename
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.Obfuscated && f.SkipBindings {
|
||||||
|
pterm.Warning.Println("obfuscated flag overrides skipbindings flag.")
|
||||||
|
buildOptions.SkipBindings = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.DryRun {
|
||||||
|
// Start Time
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
compiledBinary, err := build.Build(buildOptions)
|
||||||
|
if err != nil {
|
||||||
|
pterm.Error.Println(err.Error())
|
||||||
|
targetErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buildOptions.IgnoreFrontend = true
|
||||||
|
buildOptions.CleanBinDirectory = false
|
||||||
|
|
||||||
|
// Output stats
|
||||||
|
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.\n", compiledBinary, time.Since(start).Round(time.Millisecond).String()))
|
||||||
|
|
||||||
|
outputBinaries[buildOptions.Platform+"/"+buildOptions.Arch] = compiledBinary
|
||||||
|
} else {
|
||||||
|
pterm.Info.Println("Dry run: skipped build.")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if targetErr != nil {
|
||||||
|
return targetErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.DryRun {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.NSIS {
|
||||||
|
amd64Binary := outputBinaries["windows/amd64"]
|
||||||
|
arm64Binary := outputBinaries["windows/arm64"]
|
||||||
|
if amd64Binary == "" && arm64Binary == "" {
|
||||||
|
return fmt.Errorf("cannot build nsis installer - no windows targets")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := build.GenerateNSISInstaller(buildOptions, amd64Binary, arm64Binary); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
38
v2/cmd/wails/dev.go
Normal file
38
v2/cmd/wails/dev.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pterm/pterm"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/flags"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/dev"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func devApplication(f *flags.Dev) error {
|
||||||
|
|
||||||
|
if f.NoColour {
|
||||||
|
pterm.DisableColor()
|
||||||
|
colour.ColourEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
quiet := f.Verbosity == flags.Quiet
|
||||||
|
|
||||||
|
// Create logger
|
||||||
|
logger := clilogger.New(os.Stdout)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
if quiet {
|
||||||
|
pterm.DisableOutput()
|
||||||
|
} else {
|
||||||
|
app.PrintBanner()
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.Process()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev.Application(f, logger)
|
||||||
|
|
||||||
|
}
|
165
v2/cmd/wails/doctor.go
Normal file
165
v2/cmd/wails/doctor.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pterm/pterm"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/flags"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/system"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/system/packagemanager"
|
||||||
|
"runtime"
|
||||||
|
"runtime/debug"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func diagnoseEnvironment(f *flags.Doctor) error {
|
||||||
|
|
||||||
|
if f.NoColour {
|
||||||
|
pterm.DisableColor()
|
||||||
|
colour.ColourEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
app.PrintBanner()
|
||||||
|
|
||||||
|
pterm.Print("Scanning system - Please wait (this may take a long time)...")
|
||||||
|
|
||||||
|
// Get system info
|
||||||
|
info, err := system.GetInfo()
|
||||||
|
if err != nil {
|
||||||
|
pterm.Println("Failed.")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pterm.Println("Done.")
|
||||||
|
|
||||||
|
pterm.DefaultSection.Println("System")
|
||||||
|
|
||||||
|
systemTabledata := [][]string{
|
||||||
|
{"OS", info.OS.Name},
|
||||||
|
{"Version", info.OS.Version},
|
||||||
|
{"ID", info.OS.ID},
|
||||||
|
{"Go Version", runtime.Version()},
|
||||||
|
{"Platform", runtime.GOOS},
|
||||||
|
{"Architecture", runtime.GOARCH},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pterm.DefaultTable.WithData(systemTabledata).Render()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pterm.DefaultSection.Println("Wails")
|
||||||
|
|
||||||
|
wailsTableData := [][]string{
|
||||||
|
{"Version", app.Version()},
|
||||||
|
}
|
||||||
|
|
||||||
|
if buildInfo, _ := debug.ReadBuildInfo(); buildInfo != nil {
|
||||||
|
buildSettingToName := map[string]string{
|
||||||
|
"vcs.revision": "Revision",
|
||||||
|
"vcs.modified": "Modified",
|
||||||
|
}
|
||||||
|
for _, buildSetting := range buildInfo.Settings {
|
||||||
|
name := buildSettingToName[buildSetting.Key]
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wailsTableData = append(wailsTableData, []string{name, buildSetting.Value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit early if PM not found
|
||||||
|
if info.PM != nil {
|
||||||
|
wailsTableData = append(wailsTableData, []string{"Package Manager", info.PM.Name()})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pterm.DefaultTable.WithData(wailsTableData).Render()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pterm.DefaultSection.Println("Dependencies")
|
||||||
|
|
||||||
|
// Output Dependencies Status
|
||||||
|
var dependenciesMissing = []string{}
|
||||||
|
var externalPackages = []*packagemanager.Dependency{}
|
||||||
|
var dependenciesAvailableRequired = 0
|
||||||
|
var dependenciesAvailableOptional = 0
|
||||||
|
|
||||||
|
dependenciesTableData := [][]string{
|
||||||
|
{"Dependency", "Package Name", "Status", "Version"},
|
||||||
|
}
|
||||||
|
|
||||||
|
hasOptionalDependencies := false
|
||||||
|
// Loop over dependencies
|
||||||
|
for _, dependency := range info.Dependencies {
|
||||||
|
|
||||||
|
name := dependency.Name
|
||||||
|
if dependency.Optional {
|
||||||
|
name = "*" + name
|
||||||
|
hasOptionalDependencies = true
|
||||||
|
}
|
||||||
|
packageName := "Unknown"
|
||||||
|
status := "Not Found"
|
||||||
|
|
||||||
|
// If we found the package
|
||||||
|
if dependency.PackageName != "" {
|
||||||
|
|
||||||
|
packageName = dependency.PackageName
|
||||||
|
|
||||||
|
// If it's installed, update the status
|
||||||
|
if dependency.Installed {
|
||||||
|
status = "Installed"
|
||||||
|
} else {
|
||||||
|
// Generate meaningful status text
|
||||||
|
status = "Available"
|
||||||
|
|
||||||
|
if dependency.Optional {
|
||||||
|
dependenciesAvailableOptional++
|
||||||
|
} else {
|
||||||
|
dependenciesAvailableRequired++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !dependency.Optional {
|
||||||
|
dependenciesMissing = append(dependenciesMissing, dependency.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dependency.External {
|
||||||
|
externalPackages = append(externalPackages, dependency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependenciesTableData = append(dependenciesTableData, []string{name, packageName, status, dependency.Version})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pterm.DefaultTable.WithHasHeader(true).WithData(dependenciesTableData).Render()
|
||||||
|
|
||||||
|
if hasOptionalDependencies {
|
||||||
|
pterm.Println("* - Optional Dependency")
|
||||||
|
}
|
||||||
|
|
||||||
|
pterm.DefaultSection.Println("Diagnosis")
|
||||||
|
|
||||||
|
// Generate an appropriate diagnosis
|
||||||
|
|
||||||
|
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
|
||||||
|
pterm.Println("Your system is ready for Wails development!")
|
||||||
|
} else {
|
||||||
|
pterm.Println("Your system has missing dependencies!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if dependenciesAvailableRequired != 0 {
|
||||||
|
pterm.Println("Required package(s) installation details: \n" + info.Dependencies.InstallAllRequiredCommand())
|
||||||
|
}
|
||||||
|
|
||||||
|
if dependenciesAvailableOptional != 0 {
|
||||||
|
pterm.Println("Optional package(s) installation details: \n" + info.Dependencies.InstallAllOptionalCommand())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dependenciesMissing) != 0 {
|
||||||
|
pterm.Println("Fatal:")
|
||||||
|
pterm.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
|
||||||
|
pterm.Println("Please read this article on how to resolve this: https://wails.io/guides/resolving-missing-packages")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
166
v2/cmd/wails/flags/build.go
Normal file
166
v2/cmd/wails/flags/build.go
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/system"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Quiet int = 0
|
||||||
|
Normal int = 1
|
||||||
|
Verbose int = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: unify this and `build.Options`
|
||||||
|
type Build struct {
|
||||||
|
Common
|
||||||
|
BuildCommon
|
||||||
|
|
||||||
|
NoPackage bool `name:"noPackage" description:"Skips platform specific packaging"`
|
||||||
|
SkipModTidy bool `name:"m" description:"Skip mod tidy before compile"`
|
||||||
|
Upx bool `description:"Compress final binary with UPX (if installed)"`
|
||||||
|
UpxFlags string `description:"Flags to pass to upx"`
|
||||||
|
Platform string `description:"Platform to target. Comma separate multiple platforms"`
|
||||||
|
OutputFilename string `name:"o" description:"Output filename"`
|
||||||
|
Clean bool `description:"Clean the bin directory before building"`
|
||||||
|
WebView2 string `description:"WebView2 installer strategy: download,embed,browser,error"`
|
||||||
|
ForceBuild bool `name:"f" description:"Force build of application"`
|
||||||
|
UpdateWailsVersionGoMod bool `name:"u" description:"Updates go.mod to use the same Wails version as the CLI"`
|
||||||
|
Debug bool `description:"Builds the application in debug mode"`
|
||||||
|
NSIS bool `description:"Generate NSIS installer for Windows"`
|
||||||
|
TrimPath bool `description:"Remove all file system paths from the resulting executable"`
|
||||||
|
WindowsConsole bool `description:"Keep the console when building for Windows"`
|
||||||
|
Obfuscated bool `description:"Code obfuscation of bound Wails methods"`
|
||||||
|
GarbleArgs string `description:"Arguments to pass to garble"`
|
||||||
|
DryRun bool `description:"Prints the build command without executing it"`
|
||||||
|
|
||||||
|
// Build Specific
|
||||||
|
|
||||||
|
// Internal state
|
||||||
|
compilerPath string
|
||||||
|
userTags []string
|
||||||
|
wv2rtstrategy string // WebView2 runtime strategy
|
||||||
|
defaultArch string // Default architecture
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) Default() *Build {
|
||||||
|
|
||||||
|
defaultPlatform := os.Getenv("GOOS")
|
||||||
|
if defaultPlatform == "" {
|
||||||
|
defaultPlatform = runtime.GOOS
|
||||||
|
}
|
||||||
|
defaultArch := os.Getenv("GOARCH")
|
||||||
|
if defaultArch == "" {
|
||||||
|
if system.IsAppleSilicon {
|
||||||
|
defaultArch = "arm64"
|
||||||
|
} else {
|
||||||
|
defaultArch = runtime.GOARCH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.defaultArch = defaultArch
|
||||||
|
platform := defaultPlatform + "/" + defaultArch
|
||||||
|
|
||||||
|
result := &Build{
|
||||||
|
Platform: platform,
|
||||||
|
WebView2: "download",
|
||||||
|
GarbleArgs: "-literals -tiny -seed=random",
|
||||||
|
}
|
||||||
|
result.BuildCommon = result.BuildCommon.Default()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) GetBuildMode() build.Mode {
|
||||||
|
if b.Debug {
|
||||||
|
return build.Debug
|
||||||
|
}
|
||||||
|
return build.Production
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) GetWebView2Strategy() string {
|
||||||
|
return b.wv2rtstrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) GetTargets() *slicer.StringSlicer {
|
||||||
|
var targets slicer.StringSlicer
|
||||||
|
targets.AddSlice(strings.Split(b.Platform, ","))
|
||||||
|
targets.Deduplicate()
|
||||||
|
return &targets
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) GetCompilerPath() string {
|
||||||
|
return b.compilerPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) GetTags() []string {
|
||||||
|
return b.userTags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) Process() error {
|
||||||
|
// Lookup compiler path
|
||||||
|
var err error
|
||||||
|
b.compilerPath, err = exec.LookPath(b.Compiler)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to find compiler: %s", b.Compiler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process User Tags
|
||||||
|
b.userTags, err = buildtags.Parse(b.Tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebView2 installer strategy (download by default)
|
||||||
|
b.WebView2 = strings.ToLower(b.WebView2)
|
||||||
|
if b.WebView2 != "" {
|
||||||
|
validWV2Runtime := slicer.String([]string{"download", "embed", "browser", "error"})
|
||||||
|
if !validWV2Runtime.Contains(b.WebView2) {
|
||||||
|
return fmt.Errorf("invalid option for flag 'webview2': %s", b.WebView2)
|
||||||
|
}
|
||||||
|
b.wv2rtstrategy = "wv2runtime." + b.WebView2
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func bool2Str(b bool) string {
|
||||||
|
if b {
|
||||||
|
return "true"
|
||||||
|
}
|
||||||
|
return "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) GetBuildModeAsString() string {
|
||||||
|
if b.Debug {
|
||||||
|
return "debug"
|
||||||
|
}
|
||||||
|
return "production"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Build) GetDefaultArch() string {
|
||||||
|
return b.defaultArch
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
_, _ = fmt.Fprintf(w, "Frontend Directory: \t%s\n", projectOptions.GetFrontendDir())
|
||||||
|
_, _ = fmt.Fprintf(w, "Obfuscated: \t%t\n", buildOptions.Obfuscated)
|
||||||
|
if buildOptions.Obfuscated {
|
||||||
|
_, _ = fmt.Fprintf(w, "Garble Args: \t%s\n", buildOptions.GarbleArgs)
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprintf(w, "Skip Frontend: \t%t\n", skipFrontend)
|
||||||
|
_, _ = fmt.Fprintf(w, "Compress: \t%t\n", buildOptions.Compress)
|
||||||
|
_, _ = fmt.Fprintf(w, "Package: \t%t\n", buildOptions.Pack)
|
||||||
|
_, _ = fmt.Fprintf(w, "Clean Bin Dir: \t%t\n", buildOptions.CleanBinDirectory)
|
||||||
|
_, _ = fmt.Fprintf(w, "LDFlags: \t\"%s\"\n", buildOptions.LDFlags)
|
||||||
|
_, _ = fmt.Fprintf(w, "Tags: \t[%s]\n", strings.Join(buildOptions.UserTags, ","))
|
||||||
|
_, _ = fmt.Fprintf(w, "Race Detector: \t%t\n", buildOptions.RaceDetector)
|
||||||
|
if len(buildOptions.OutputFile) > 0 && targets.Length() == 1 {
|
||||||
|
_, _ = fmt.Fprintf(w, "Output File: \t%s\n", buildOptions.OutputFile)
|
||||||
|
}
|
||||||
|
*/
|
18
v2/cmd/wails/flags/buildcommon.go
Normal file
18
v2/cmd/wails/flags/buildcommon.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
type BuildCommon struct {
|
||||||
|
LdFlags string `description:"Additional ldflags to pass to the compiler"`
|
||||||
|
Compiler string `description:"Use a different go compiler to build, eg go1.15beta1"`
|
||||||
|
SkipBindings bool `description:"Skips generation of bindings"`
|
||||||
|
RaceDetector bool `name:"race" description:"Build with Go's race detector"`
|
||||||
|
SkipFrontend bool `name:"s" description:"Skips building the frontend"`
|
||||||
|
Verbosity int `name:"v" description:"Verbosity level (0 = quiet, 1 = normal, 2 = verbose)"`
|
||||||
|
Tags string `description:"Build tags to pass to Go compiler. Must be quoted. Space or comma (but not both) separated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c BuildCommon) Default() BuildCommon {
|
||||||
|
return BuildCommon{
|
||||||
|
Compiler: "go",
|
||||||
|
Verbosity: 1,
|
||||||
|
}
|
||||||
|
}
|
5
v2/cmd/wails/flags/common.go
Normal file
5
v2/cmd/wails/flags/common.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
type Common struct {
|
||||||
|
NoColour bool `description:"Disable colour in output"`
|
||||||
|
}
|
144
v2/cmd/wails/flags/dev.go
Normal file
144
v2/cmd/wails/flags/dev.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/project"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dev struct {
|
||||||
|
BuildCommon
|
||||||
|
|
||||||
|
AssetDir string `flag:"assetdir" description:"Serve assets from the given directory instead of using the provided asset FS"`
|
||||||
|
Extensions string `flag:"e" description:"Extensions to trigger rebuilds (comma separated) eg go"`
|
||||||
|
ReloadDirs string `flag:"reloaddirs" description:"Additional directories to trigger reloads (comma separated)"`
|
||||||
|
Browser bool `flag:"browser" description:"Open the application in a browser"`
|
||||||
|
NoReload bool `flag:"noreload" description:"Disable reload on asset change"`
|
||||||
|
NoColour bool `flag:"nocolor" description:"Disable colour in output"`
|
||||||
|
WailsJSDir string `flag:"wailsjsdir" description:"Directory to generate the Wails JS modules"`
|
||||||
|
LogLevel string `flag:"loglevel" description:"LogLevel to use - Trace, Debug, Info, Warning, Error)"`
|
||||||
|
ForceBuild bool `flag:"f" description:"Force build of application"`
|
||||||
|
Debounce int `flag:"debounce" description:"The amount of time to wait to trigger a reload on change"`
|
||||||
|
DevServer string `flag:"devserver" description:"The address of the wails dev server"`
|
||||||
|
AppArgs string `flag:"appargs" description:"arguments to pass to the underlying app (quoted and space separated)"`
|
||||||
|
Save bool `flag:"save" description:"Save the given flags as defaults"`
|
||||||
|
FrontendDevServerURL string `flag:"frontenddevserverurl" description:"The url of the external frontend dev server to use"`
|
||||||
|
|
||||||
|
// Internal state
|
||||||
|
devServerURL *url.URL
|
||||||
|
projectConfig *project.Project
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Dev) Default() *Dev {
|
||||||
|
result := &Dev{
|
||||||
|
Extensions: "go",
|
||||||
|
Debounce: 100,
|
||||||
|
}
|
||||||
|
result.BuildCommon = result.BuildCommon.Default()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) Process() error {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
err = d.loadAndMergeProjectConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, _, err := net.SplitHostPort(d.DevServer); err != nil {
|
||||||
|
return fmt.Errorf("DevServer is not of the form 'host:port', please check your wails.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.devServerURL, err = url.Parse("http://" + d.DevServer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) loadAndMergeProjectConfig() error {
|
||||||
|
var err error
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.projectConfig, err = project.Load(cwd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.AssetDir, _ = lo.Coalesce(d.AssetDir, d.projectConfig.AssetDirectory)
|
||||||
|
d.projectConfig.AssetDirectory = filepath.ToSlash(d.AssetDir)
|
||||||
|
if d.AssetDir != "" {
|
||||||
|
d.AssetDir, err = filepath.Abs(d.AssetDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.ReloadDirs, _ = lo.Coalesce(d.ReloadDirs, d.projectConfig.ReloadDirectories)
|
||||||
|
d.projectConfig.ReloadDirectories = filepath.ToSlash(d.ReloadDirs)
|
||||||
|
d.DevServer, _ = lo.Coalesce(d.DevServer, d.projectConfig.DevServer)
|
||||||
|
d.projectConfig.DevServer = d.DevServer
|
||||||
|
d.FrontendDevServerURL, _ = lo.Coalesce(d.FrontendDevServerURL, d.projectConfig.FrontendDevServerURL)
|
||||||
|
d.projectConfig.FrontendDevServerURL = d.FrontendDevServerURL
|
||||||
|
d.WailsJSDir, _ = lo.Coalesce(d.WailsJSDir, d.projectConfig.GetWailsJSDir(), d.projectConfig.GetFrontendDir())
|
||||||
|
d.projectConfig.WailsJSDir = filepath.ToSlash(d.WailsJSDir)
|
||||||
|
|
||||||
|
if d.Debounce == 100 && d.projectConfig.DebounceMS != 100 {
|
||||||
|
if d.projectConfig.DebounceMS == 0 {
|
||||||
|
d.projectConfig.DebounceMS = 100
|
||||||
|
}
|
||||||
|
d.Debounce = d.projectConfig.DebounceMS
|
||||||
|
}
|
||||||
|
d.projectConfig.DebounceMS = d.Debounce
|
||||||
|
|
||||||
|
d.AppArgs, _ = lo.Coalesce(d.AppArgs, d.projectConfig.AppArgs)
|
||||||
|
|
||||||
|
if d.Save {
|
||||||
|
err = d.projectConfig.Save()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateBuildOptions creates a build.Options using the flags
|
||||||
|
func (d *Dev) GenerateBuildOptions() *build.Options {
|
||||||
|
result := &build.Options{
|
||||||
|
OutputType: "dev",
|
||||||
|
Mode: build.Dev,
|
||||||
|
Arch: runtime.GOARCH,
|
||||||
|
Pack: true,
|
||||||
|
Platform: runtime.GOOS,
|
||||||
|
LDFlags: d.LdFlags,
|
||||||
|
Compiler: d.Compiler,
|
||||||
|
ForceBuild: d.ForceBuild,
|
||||||
|
IgnoreFrontend: d.SkipFrontend,
|
||||||
|
Verbosity: d.Verbosity,
|
||||||
|
WailsJSDir: d.WailsJSDir,
|
||||||
|
RaceDetector: d.RaceDetector,
|
||||||
|
ProjectData: d.projectConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) ProjectConfig() *project.Project {
|
||||||
|
return d.projectConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) DevServerURL() *url.URL {
|
||||||
|
return d.devServerURL
|
||||||
|
}
|
9
v2/cmd/wails/flags/doctor.go
Normal file
9
v2/cmd/wails/flags/doctor.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
type Doctor struct {
|
||||||
|
Common
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Doctor) Default() *Doctor {
|
||||||
|
return &Doctor{}
|
||||||
|
}
|
14
v2/cmd/wails/flags/generate.go
Normal file
14
v2/cmd/wails/flags/generate.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
type GenerateModule struct {
|
||||||
|
Common
|
||||||
|
Tags string `description:"Build tags to pass to Go compiler. Must be quoted. Space or comma (but not both) separated"`
|
||||||
|
Verbosity int `name:"v" description:"Verbosity level (0 = quiet, 1 = normal, 2 = verbose)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenerateTemplate struct {
|
||||||
|
Common
|
||||||
|
Name string `description:"Name of the template to generate"`
|
||||||
|
Frontend string `description:"Frontend to use for the template"`
|
||||||
|
Quiet bool `description:"Suppress output"`
|
||||||
|
}
|
22
v2/cmd/wails/flags/init.go
Normal file
22
v2/cmd/wails/flags/init.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
type Init struct {
|
||||||
|
Common
|
||||||
|
|
||||||
|
TemplateName string `name:"t" description:"Name of built-in template to use, path to template or template url"`
|
||||||
|
ProjectName string `name:"n" description:"Name of project"`
|
||||||
|
CIMode bool `name:"ci" description:"CI Mode"`
|
||||||
|
ProjectDir string `name:"d" description:"Project directory"`
|
||||||
|
Quiet bool `name:"q" description:"Suppress output to console"`
|
||||||
|
InitGit bool `name:"g" description:"Initialise git repository"`
|
||||||
|
IDE string `name:"ide" description:"Generate IDE project files"`
|
||||||
|
List bool `name:"l" description:"List templates"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Init) Default() *Init {
|
||||||
|
|
||||||
|
result := &Init{
|
||||||
|
TemplateName: "vanilla",
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
6
v2/cmd/wails/flags/show.go
Normal file
6
v2/cmd/wails/flags/show.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
type ShowReleaseNotes struct {
|
||||||
|
Common
|
||||||
|
Version string `description:"The version to show the release notes for"`
|
||||||
|
}
|
7
v2/cmd/wails/flags/update.go
Normal file
7
v2/cmd/wails/flags/update.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
type Update struct {
|
||||||
|
Common
|
||||||
|
Version string `description:"The version to update to"`
|
||||||
|
PreRelease bool `name:"pre" description:"Update to latest pre-release"`
|
||||||
|
}
|
245
v2/cmd/wails/generate.go
Normal file
245
v2/cmd/wails/generate.go
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leaanthony/debme"
|
||||||
|
"github.com/leaanthony/gosod"
|
||||||
|
"github.com/pterm/pterm"
|
||||||
|
"github.com/tidwall/sjson"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/flags"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/template"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/project"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/bindings"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateModule(f *flags.GenerateModule) error {
|
||||||
|
|
||||||
|
if f.NoColour {
|
||||||
|
pterm.DisableColor()
|
||||||
|
colour.ColourEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
quiet := f.Verbosity == flags.Quiet
|
||||||
|
logger := clilogger.New(os.Stdout)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
buildTags, err := buildtags.Parse(f.Tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
projectConfig, err := project.Load(cwd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = bindings.GenerateBindings(bindings.Options{
|
||||||
|
Tags: buildTags,
|
||||||
|
TsPrefix: projectConfig.Bindings.TsGeneration.Prefix,
|
||||||
|
TsSuffix: projectConfig.Bindings.TsGeneration.Suffix,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateTemplate(f *flags.GenerateTemplate) error {
|
||||||
|
|
||||||
|
if f.NoColour {
|
||||||
|
pterm.DisableColor()
|
||||||
|
colour.ColourEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
quiet := f.Quiet
|
||||||
|
logger := clilogger.New(os.Stdout)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
// name is mandatory
|
||||||
|
if f.Name == "" {
|
||||||
|
return fmt.Errorf("please provide a template name using the -name flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the current directory is not empty, we create a new directory
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
templateDir := filepath.Join(cwd, f.Name)
|
||||||
|
if !fs.DirExists(templateDir) {
|
||||||
|
err := os.MkdirAll(templateDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
empty, err := fs.DirIsEmpty(templateDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pterm.DefaultSection.Println("Generating template")
|
||||||
|
|
||||||
|
if !empty {
|
||||||
|
templateDir = filepath.Join(cwd, f.Name)
|
||||||
|
printBulletPoint("Creating new template directory:", f.Name)
|
||||||
|
err = fs.Mkdir(templateDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create base template
|
||||||
|
baseTemplate, err := debme.FS(template.Base, "base")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g := gosod.New(baseTemplate)
|
||||||
|
g.SetTemplateFilters([]string{".template"})
|
||||||
|
|
||||||
|
err = os.Chdir(templateDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type templateData struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
TemplateDir string
|
||||||
|
WailsVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
printBulletPoint("Extracting base template files...")
|
||||||
|
|
||||||
|
err = g.Extract(templateDir, &templateData{
|
||||||
|
Name: f.Name,
|
||||||
|
TemplateDir: templateDir,
|
||||||
|
WailsVersion: app.Version(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chdir(cwd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we aren't migrating the files, just exit
|
||||||
|
if f.Frontend == "" {
|
||||||
|
pterm.Println()
|
||||||
|
pterm.Println()
|
||||||
|
pterm.Info.Println("No frontend specified to migrate. Template created.")
|
||||||
|
pterm.Println()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove frontend directory
|
||||||
|
frontendDir := filepath.Join(templateDir, "frontend")
|
||||||
|
err = os.RemoveAll(frontendDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the files into a new frontend directory
|
||||||
|
printBulletPoint("Migrating existing project files to frontend directory...")
|
||||||
|
|
||||||
|
sourceDir, err := filepath.Abs(f.Frontend)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newFrontendDir := filepath.Join(templateDir, "frontend")
|
||||||
|
err = fs.CopyDirExtended(sourceDir, newFrontendDir, []string{f.Name, "node_modules"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process package.json
|
||||||
|
err = processPackageJSON(frontendDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process package-lock.json
|
||||||
|
err = processPackageLockJSON(frontendDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove node_modules - ignore error, eg it doesn't exist
|
||||||
|
_ = os.RemoveAll(filepath.Join(frontendDir, "node_modules"))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processPackageJSON(frontendDir string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
packageJSON := filepath.Join(frontendDir, "package.json")
|
||||||
|
if !fs.FileExists(packageJSON) {
|
||||||
|
return fmt.Errorf("no package.json found - cannot process")
|
||||||
|
}
|
||||||
|
|
||||||
|
json, err := os.ReadFile(packageJSON)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will ignore these errors - it's not critical
|
||||||
|
printBulletPoint("Updating package.json data...")
|
||||||
|
json, _ = sjson.SetBytes(json, "name", "{{.ProjectName}}")
|
||||||
|
json, _ = sjson.SetBytes(json, "author", "{{.AuthorName}}")
|
||||||
|
|
||||||
|
err = os.WriteFile(packageJSON, json, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
baseDir := filepath.Dir(packageJSON)
|
||||||
|
printBulletPoint("Renaming package.json -> package.tmpl.json...")
|
||||||
|
err = os.Rename(packageJSON, filepath.Join(baseDir, "package.tmpl.json"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processPackageLockJSON(frontendDir string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
filename := filepath.Join(frontendDir, "package-lock.json")
|
||||||
|
if !fs.FileExists(filename) {
|
||||||
|
return fmt.Errorf("no package-lock.json found - cannot process")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
json := string(data)
|
||||||
|
|
||||||
|
// We will ignore these errors - it's not critical
|
||||||
|
printBulletPoint("Updating package-lock.json data...")
|
||||||
|
json, _ = sjson.Set(json, "name", "{{.ProjectName}}")
|
||||||
|
|
||||||
|
err = os.WriteFile(filename, []byte(json), 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
baseDir := filepath.Dir(filename)
|
||||||
|
printBulletPoint("Renaming package-lock.json -> package-lock.tmpl.json...")
|
||||||
|
err = os.Rename(filename, filepath.Join(baseDir, "package-lock.tmpl.json"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
278
v2/cmd/wails/init.go
Normal file
278
v2/cmd/wails/init.go
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"github.com/flytam/filenamify"
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/pterm/pterm"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/flags"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/buildassets"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/git"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/templates"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initProject(f *flags.Init) error {
|
||||||
|
|
||||||
|
if f.NoColour {
|
||||||
|
pterm.DisableColor()
|
||||||
|
colour.ColourEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
quiet := f.Quiet
|
||||||
|
|
||||||
|
// Create logger
|
||||||
|
logger := clilogger.New(os.Stdout)
|
||||||
|
logger.Mute(quiet)
|
||||||
|
|
||||||
|
// Are we listing templates?
|
||||||
|
if f.List {
|
||||||
|
app.PrintBanner()
|
||||||
|
templateList, err := templates.List()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pterm.DefaultSection.Println("Available templates")
|
||||||
|
|
||||||
|
table := pterm.TableData{{"Template", "Short Name", "Description"}}
|
||||||
|
for _, template := range templateList {
|
||||||
|
table = append(table, []string{template.Name, template.ShortName, template.Description})
|
||||||
|
}
|
||||||
|
err = pterm.DefaultTable.WithHasHeader(true).WithBoxed(true).WithData(table).Render()
|
||||||
|
pterm.Println()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate name
|
||||||
|
if len(f.ProjectName) == 0 {
|
||||||
|
return fmt.Errorf("please provide a project name using the -n flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate IDE option
|
||||||
|
supportedIDEs := slicer.String([]string{"vscode", "goland"})
|
||||||
|
ide := strings.ToLower(f.IDE)
|
||||||
|
if ide != "" {
|
||||||
|
if !supportedIDEs.Contains(ide) {
|
||||||
|
return fmt.Errorf("ide '%s' not supported. Valid values: %s", ide, supportedIDEs.Join(" "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !quiet {
|
||||||
|
app.PrintBanner()
|
||||||
|
}
|
||||||
|
|
||||||
|
pterm.DefaultSection.Printf("Initialising Project '%s'", f.ProjectName)
|
||||||
|
|
||||||
|
projectFilename, err := filenamify.Filenamify(f.ProjectName, filenamify.Options{
|
||||||
|
Replacement: "_",
|
||||||
|
MaxLength: 255,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
goBinary, err := exec.LookPath("go")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to find Go compiler. Please download and install Go: https://golang.org/dl/")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get base path and convert to forward slashes
|
||||||
|
goPath := filepath.ToSlash(filepath.Dir(goBinary))
|
||||||
|
// Trim bin directory
|
||||||
|
goSDKPath := strings.TrimSuffix(goPath, "/bin")
|
||||||
|
|
||||||
|
// Create Template Options
|
||||||
|
options := &templates.Options{
|
||||||
|
ProjectName: f.ProjectName,
|
||||||
|
TargetDir: f.ProjectDir,
|
||||||
|
TemplateName: f.TemplateName,
|
||||||
|
Logger: logger,
|
||||||
|
IDE: ide,
|
||||||
|
InitGit: f.InitGit,
|
||||||
|
ProjectNameFilename: projectFilename,
|
||||||
|
WailsVersion: app.Version(),
|
||||||
|
GoSDKPath: goSDKPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to discover author details from git config
|
||||||
|
findAuthorDetails(options)
|
||||||
|
|
||||||
|
// Start Time
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
// Install the template
|
||||||
|
remote, template, err := templates.Install(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install the default assets
|
||||||
|
err = buildassets.Install(options.TargetDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chdir(options.TargetDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.CIMode {
|
||||||
|
// Run `go mod tidy` to ensure `go.sum` is up to date
|
||||||
|
cmd := exec.Command("go", "mod", "tidy")
|
||||||
|
cmd.Dir = options.TargetDir
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if !quiet {
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
}
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Update go mod
|
||||||
|
workspace := os.Getenv("GITHUB_WORKSPACE")
|
||||||
|
pterm.Println("GitHub workspace:", workspace)
|
||||||
|
if workspace == "" {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
updateReplaceLine(workspace)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the `.git`` directory in the template project
|
||||||
|
err = os.RemoveAll(".git")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.InitGit {
|
||||||
|
err = initGit(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if quiet {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output stats
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
|
||||||
|
// Create pterm table
|
||||||
|
table := pterm.TableData{
|
||||||
|
{"Project Name", options.ProjectName},
|
||||||
|
{"Project Directory", options.TargetDir},
|
||||||
|
{"Template", template.Name},
|
||||||
|
{"Template Source", template.HelpURL},
|
||||||
|
}
|
||||||
|
err = pterm.DefaultTable.WithData(table).Render()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDE message
|
||||||
|
switch options.IDE {
|
||||||
|
case "vscode":
|
||||||
|
pterm.Println()
|
||||||
|
pterm.Info.Println("VSCode config files generated.")
|
||||||
|
case "goland":
|
||||||
|
pterm.Println()
|
||||||
|
pterm.Info.Println("Goland config files generated.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.InitGit {
|
||||||
|
pterm.Info.Println("Git repository initialised.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if remote {
|
||||||
|
pterm.Warning.Println("NOTE: You have created a project using a remote template. The Wails project takes no responsibility for 3rd party templates. Only use remote templates that you trust.")
|
||||||
|
}
|
||||||
|
|
||||||
|
pterm.Println("")
|
||||||
|
pterm.Printf("Initialised project '%s' in %s.\n", options.ProjectName, elapsed.Round(time.Millisecond).String())
|
||||||
|
pterm.Println("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initGit(options *templates.Options) error {
|
||||||
|
err := git.InitRepo(options.TargetDir)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Unable to initialise git repository:")
|
||||||
|
}
|
||||||
|
|
||||||
|
ignore := []string{
|
||||||
|
"build/bin",
|
||||||
|
"frontend/dist",
|
||||||
|
"frontend/node_modules",
|
||||||
|
}
|
||||||
|
err = os.WriteFile(filepath.Join(options.TargetDir, ".gitignore"), []byte(strings.Join(ignore, "\n")), 0644)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Unable to create gitignore")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// findAuthorDetails tries to find the user's name and email
|
||||||
|
// from gitconfig. If it finds them, it stores them in the project options
|
||||||
|
func findAuthorDetails(options *templates.Options) {
|
||||||
|
if git.IsInstalled() {
|
||||||
|
name, err := git.Name()
|
||||||
|
if err == nil {
|
||||||
|
options.AuthorName = strings.TrimSpace(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
email, err := git.Email()
|
||||||
|
if err == nil {
|
||||||
|
options.AuthorEmail = strings.TrimSpace(email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateReplaceLine(targetPath string) {
|
||||||
|
file, err := os.Open("go.mod")
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines []string
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = file.Close()
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, line := range lines {
|
||||||
|
println(line)
|
||||||
|
if strings.HasPrefix(line, "// replace") {
|
||||||
|
pterm.Println("Found replace line")
|
||||||
|
splitLine := strings.Split(line, " ")
|
||||||
|
splitLine[5] = targetPath + "/v2"
|
||||||
|
lines[i] = strings.Join(splitLine[1:], " ")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile("go.mod", []byte(strings.Join(lines, "\n")), 0644)
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
}
|
@ -1,46 +0,0 @@
|
|||||||
# Build
|
|
||||||
|
|
||||||
The build command processes the Wails project and generates an application binary.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
`wails build <flags>`
|
|
||||||
|
|
||||||
### Flags
|
|
||||||
|
|
||||||
| Flag | Details | Default |
|
|
||||||
| :------------- | :----------- | :------ |
|
|
||||||
| -clean | Clean the bin directory before building | |
|
|
||||||
| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go |
|
|
||||||
| -ldflags "custom ld flags" | Use given ldflags | |
|
|
||||||
| -o path/to/binary | Compile to given path/filename | |
|
|
||||||
| -k | Keep generated assets | |
|
|
||||||
| -tags | Build tags to pass to Go compiler (quoted and space separated) | |
|
|
||||||
| -upx | Compress final binary with UPX (if installed) | |
|
|
||||||
| -upxflags "custom flags" | Flags to pass to upx | |
|
|
||||||
| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 |
|
|
||||||
| -delve | If true, runs delve on the compiled binary | false |
|
|
||||||
|
|
||||||
## The Build Process
|
|
||||||
|
|
||||||
The build process is as follows:
|
|
||||||
|
|
||||||
- The flags are processed, and an Options struct built containing the build context.
|
|
||||||
- The type of target is determined, and a custom build process is followed for target.
|
|
||||||
|
|
||||||
### Desktop Target
|
|
||||||
|
|
||||||
- The frontend dependencies are installed. The command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored.
|
|
||||||
- The frontend is then built. This command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored.
|
|
||||||
- The project directory is checked to see if the `build` directory exists. If not, it is created and default project assets are copied to it.
|
|
||||||
- An asset bundle is then created by reading the `html` key from `wails.json` and loading the referenced file. This is then parsed, looking for local Javascript and CSS references. Those files are in turn loaded into memory, converted to C data and saved into the asset bundle located at `build/assets.h`, which also includes the original HTML.
|
|
||||||
- The application icon is then processed: if there is no `build/appicon.png`, a default icon is copied. On Windows,
|
|
||||||
an `app.ico` file is generated from this png. On Mac, `icons.icns` is generated.
|
|
||||||
- The platform assets in the `build/<platform>` directory are processed: manifest + icons compiled to a `.syso` file (
|
|
||||||
deleted after compilation), `info.plist` copied to `.app` on Mac.
|
|
||||||
- If we are building a universal binary for Mac, the application is compiled for both `arm64` and `amd64`. The `lipo`
|
|
||||||
tool is then executed to create the universal binary.
|
|
||||||
- If we are not building a universal binary for Mac, the application is built using `go build`, using build tags to indicate type of application and build mode (debug/production).
|
|
||||||
- If the `-upx` flag was provided, `upx` is invoked to compress the binary. Custom flags may be provided using the `-upxflags` flag.
|
|
||||||
|
|
||||||
|
|
@ -1,401 +0,0 @@
|
|||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"text/tabwriter"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/colour"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/project"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/system"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"github.com/leaanthony/slicer"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddBuildSubcommand adds the `build` command for the Wails application
|
|
||||||
func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|
||||||
|
|
||||||
outputType := "desktop"
|
|
||||||
|
|
||||||
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
|
|
||||||
|
|
||||||
command := app.NewSubCommand("build", "Builds the application")
|
|
||||||
|
|
||||||
// Setup noPackage flag
|
|
||||||
noPackage := false
|
|
||||||
command.BoolFlag("noPackage", "Skips platform specific packaging", &noPackage)
|
|
||||||
|
|
||||||
compilerCommand := "go"
|
|
||||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
|
||||||
|
|
||||||
skipModTidy := false
|
|
||||||
command.BoolFlag("m", "Skip mod tidy before compile", &skipModTidy)
|
|
||||||
|
|
||||||
compress := false
|
|
||||||
command.BoolFlag("upx", "Compress final binary with UPX (if installed)", &compress)
|
|
||||||
|
|
||||||
compressFlags := ""
|
|
||||||
command.StringFlag("upxflags", "Flags to pass to upx", &compressFlags)
|
|
||||||
|
|
||||||
defaultPlatform := os.Getenv("GOOS")
|
|
||||||
if defaultPlatform == "" {
|
|
||||||
defaultPlatform = runtime.GOOS
|
|
||||||
}
|
|
||||||
defaultArch := os.Getenv("GOARCH")
|
|
||||||
if defaultArch == "" {
|
|
||||||
if system.IsAppleSilicon {
|
|
||||||
defaultArch = "arm64"
|
|
||||||
} else {
|
|
||||||
defaultArch = runtime.GOARCH
|
|
||||||
}
|
|
||||||
}
|
|
||||||
platform := defaultPlatform + "/" + defaultArch
|
|
||||||
|
|
||||||
command.StringFlag("platform", "Platform to target. Comma separate multiple platforms", &platform)
|
|
||||||
|
|
||||||
// Verbosity
|
|
||||||
verbosity := 1
|
|
||||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - default, 2 - verbose)", &verbosity)
|
|
||||||
|
|
||||||
// ldflags to pass to `go`
|
|
||||||
ldflags := ""
|
|
||||||
command.StringFlag("ldflags", "optional ldflags", &ldflags)
|
|
||||||
|
|
||||||
// tags to pass to `go`
|
|
||||||
tags := ""
|
|
||||||
command.StringFlag("tags", "Build tags to pass to Go compiler. Must be quoted. Space or comma (but not both) separated", &tags)
|
|
||||||
|
|
||||||
outputFilename := ""
|
|
||||||
command.StringFlag("o", "Output filename", &outputFilename)
|
|
||||||
|
|
||||||
// Clean bin directory
|
|
||||||
cleanBinDirectory := false
|
|
||||||
command.BoolFlag("clean", "Clean the bin directory before building", &cleanBinDirectory)
|
|
||||||
|
|
||||||
webview2 := "download"
|
|
||||||
command.StringFlag("webview2", "WebView2 installer strategy: download,embed,browser,error.", &webview2)
|
|
||||||
|
|
||||||
skipFrontend := false
|
|
||||||
command.BoolFlag("s", "Skips building the frontend", &skipFrontend)
|
|
||||||
|
|
||||||
forceBuild := false
|
|
||||||
command.BoolFlag("f", "Force build application", &forceBuild)
|
|
||||||
|
|
||||||
updateGoModWailsVersion := false
|
|
||||||
command.BoolFlag("u", "Updates go.mod to use the same Wails version as the CLI", &updateGoModWailsVersion)
|
|
||||||
|
|
||||||
debug := false
|
|
||||||
command.BoolFlag("debug", "Retains debug data in the compiled application", &debug)
|
|
||||||
|
|
||||||
nsis := false
|
|
||||||
command.BoolFlag("nsis", "Generate NSIS installer for Windows", &nsis)
|
|
||||||
|
|
||||||
trimpath := false
|
|
||||||
command.BoolFlag("trimpath", "Remove all file system paths from the resulting executable", &trimpath)
|
|
||||||
|
|
||||||
raceDetector := false
|
|
||||||
command.BoolFlag("race", "Build with Go's race detector", &raceDetector)
|
|
||||||
|
|
||||||
windowsConsole := false
|
|
||||||
command.BoolFlag("windowsconsole", "Keep the console when building for Windows", &windowsConsole)
|
|
||||||
|
|
||||||
obfuscated := false
|
|
||||||
command.BoolFlag("obfuscated", "Code obfuscation of bound Wails methods", &obfuscated)
|
|
||||||
|
|
||||||
garbleargs := "-literals -tiny -seed=random"
|
|
||||||
command.StringFlag("garbleargs", "Arguments to pass to garble", &garbleargs)
|
|
||||||
|
|
||||||
dryRun := false
|
|
||||||
command.BoolFlag("dryrun", "Dry run, prints the config for the command that would be executed", &dryRun)
|
|
||||||
|
|
||||||
skipBindings := false
|
|
||||||
command.BoolFlag("skipbindings", "Skips generation of bindings", &skipBindings)
|
|
||||||
|
|
||||||
command.Action(func() error {
|
|
||||||
|
|
||||||
quiet := verbosity == 0
|
|
||||||
|
|
||||||
// Create logger
|
|
||||||
logger := clilogger.New(w)
|
|
||||||
logger.Mute(quiet)
|
|
||||||
|
|
||||||
// Validate output type
|
|
||||||
if !validTargetTypes.Contains(outputType) {
|
|
||||||
return fmt.Errorf("output type '%s' is not valid", outputType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !quiet {
|
|
||||||
app.PrintBanner()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lookup compiler path
|
|
||||||
compilerPath, err := exec.LookPath(compilerCommand)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to find compiler: %s", compilerCommand)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process User Tags
|
|
||||||
userTags, err := buildtags.Parse(tags)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Webview2 installer strategy (download by default)
|
|
||||||
wv2rtstrategy := ""
|
|
||||||
webview2 = strings.ToLower(webview2)
|
|
||||||
if webview2 != "" {
|
|
||||||
validWV2Runtime := slicer.String([]string{"download", "embed", "browser", "error"})
|
|
||||||
if !validWV2Runtime.Contains(webview2) {
|
|
||||||
return fmt.Errorf("invalid option for flag 'webview2': %s", webview2)
|
|
||||||
}
|
|
||||||
// These are the build tags associated with the strategies
|
|
||||||
switch webview2 {
|
|
||||||
case "embed":
|
|
||||||
wv2rtstrategy = "wv2runtime.embed"
|
|
||||||
case "error":
|
|
||||||
wv2rtstrategy = "wv2runtime.error"
|
|
||||||
case "browser":
|
|
||||||
wv2rtstrategy = "wv2runtime.browser"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mode := build.Production
|
|
||||||
modeString := "Production"
|
|
||||||
if debug {
|
|
||||||
mode = build.Debug
|
|
||||||
modeString = "Debug"
|
|
||||||
}
|
|
||||||
|
|
||||||
var targets slicer.StringSlicer
|
|
||||||
targets.AddSlice(strings.Split(platform, ","))
|
|
||||||
targets.Deduplicate()
|
|
||||||
|
|
||||||
cwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
projectOptions, err := project.Load(cwd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create BuildOptions
|
|
||||||
buildOptions := &build.Options{
|
|
||||||
Logger: logger,
|
|
||||||
OutputType: outputType,
|
|
||||||
OutputFile: outputFilename,
|
|
||||||
CleanBinDirectory: cleanBinDirectory,
|
|
||||||
Mode: mode,
|
|
||||||
Pack: !noPackage,
|
|
||||||
LDFlags: ldflags,
|
|
||||||
Compiler: compilerCommand,
|
|
||||||
SkipModTidy: skipModTidy,
|
|
||||||
Verbosity: verbosity,
|
|
||||||
ForceBuild: forceBuild,
|
|
||||||
IgnoreFrontend: skipFrontend,
|
|
||||||
Compress: compress,
|
|
||||||
CompressFlags: compressFlags,
|
|
||||||
UserTags: userTags,
|
|
||||||
WebView2Strategy: wv2rtstrategy,
|
|
||||||
TrimPath: trimpath,
|
|
||||||
RaceDetector: raceDetector,
|
|
||||||
WindowsConsole: windowsConsole,
|
|
||||||
Obfuscated: obfuscated,
|
|
||||||
GarbleArgs: garbleargs,
|
|
||||||
SkipBindings: skipBindings,
|
|
||||||
ProjectData: projectOptions,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start a new tabwriter
|
|
||||||
if !quiet {
|
|
||||||
w := new(tabwriter.Writer)
|
|
||||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
|
||||||
|
|
||||||
// Write out the system information
|
|
||||||
_, _ = fmt.Fprintf(w, "App Type: \t%s\n", buildOptions.OutputType)
|
|
||||||
_, _ = fmt.Fprintf(w, "Platforms: \t%s\n", platform)
|
|
||||||
_, _ = fmt.Fprintf(w, "Compiler: \t%s\n", compilerPath)
|
|
||||||
_, _ = fmt.Fprintf(w, "Skip Bindings: \t%t\n", skipBindings)
|
|
||||||
_, _ = fmt.Fprintf(w, "Build Mode: \t%s\n", modeString)
|
|
||||||
_, _ = fmt.Fprintf(w, "Frontend Directory: \t%s\n", projectOptions.GetFrontendDir())
|
|
||||||
_, _ = fmt.Fprintf(w, "Obfuscated: \t%t\n", buildOptions.Obfuscated)
|
|
||||||
if buildOptions.Obfuscated {
|
|
||||||
_, _ = fmt.Fprintf(w, "Garble Args: \t%s\n", buildOptions.GarbleArgs)
|
|
||||||
}
|
|
||||||
_, _ = fmt.Fprintf(w, "Skip Frontend: \t%t\n", skipFrontend)
|
|
||||||
_, _ = fmt.Fprintf(w, "Compress: \t%t\n", buildOptions.Compress)
|
|
||||||
_, _ = fmt.Fprintf(w, "Package: \t%t\n", buildOptions.Pack)
|
|
||||||
_, _ = fmt.Fprintf(w, "Clean Bin Dir: \t%t\n", buildOptions.CleanBinDirectory)
|
|
||||||
_, _ = fmt.Fprintf(w, "LDFlags: \t\"%s\"\n", buildOptions.LDFlags)
|
|
||||||
_, _ = fmt.Fprintf(w, "Tags: \t[%s]\n", strings.Join(buildOptions.UserTags, ","))
|
|
||||||
_, _ = fmt.Fprintf(w, "Race Detector: \t%t\n", buildOptions.RaceDetector)
|
|
||||||
if len(buildOptions.OutputFile) > 0 && targets.Length() == 1 {
|
|
||||||
_, _ = fmt.Fprintf(w, "Output File: \t%s\n", buildOptions.OutputFile)
|
|
||||||
}
|
|
||||||
_, _ = fmt.Fprintf(w, "\n")
|
|
||||||
err = w.Flush()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = SyncGoMod(logger, updateGoModWailsVersion)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check platform
|
|
||||||
validPlatformArch := slicer.String([]string{
|
|
||||||
"darwin",
|
|
||||||
"darwin/amd64",
|
|
||||||
"darwin/arm64",
|
|
||||||
"darwin/universal",
|
|
||||||
"linux",
|
|
||||||
"linux/amd64",
|
|
||||||
"linux/arm64",
|
|
||||||
"linux/arm",
|
|
||||||
"windows",
|
|
||||||
"windows/amd64",
|
|
||||||
"windows/arm64",
|
|
||||||
"windows/386",
|
|
||||||
})
|
|
||||||
|
|
||||||
outputBinaries := map[string]string{}
|
|
||||||
|
|
||||||
// Allows cancelling the build after the first error. It would be nice if targets.Each would support funcs
|
|
||||||
// returning an error.
|
|
||||||
var targetErr error
|
|
||||||
targets.Each(func(platform string) {
|
|
||||||
if targetErr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !validPlatformArch.Contains(platform) {
|
|
||||||
buildOptions.Logger.Println("platform '%s' is not supported - skipping. Supported platforms: %s", platform, validPlatformArch.Join(","))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
desiredFilename := projectOptions.OutputFilename
|
|
||||||
if desiredFilename == "" {
|
|
||||||
desiredFilename = projectOptions.Name
|
|
||||||
}
|
|
||||||
desiredFilename = strings.TrimSuffix(desiredFilename, ".exe")
|
|
||||||
|
|
||||||
// Calculate platform and arch
|
|
||||||
platformSplit := strings.Split(platform, "/")
|
|
||||||
buildOptions.Platform = platformSplit[0]
|
|
||||||
buildOptions.Arch = defaultArch
|
|
||||||
if len(platformSplit) > 1 {
|
|
||||||
buildOptions.Arch = platformSplit[1]
|
|
||||||
}
|
|
||||||
banner := "Building target: " + buildOptions.Platform + "/" + buildOptions.Arch
|
|
||||||
logger.Println(banner)
|
|
||||||
logger.Println(strings.Repeat("-", len(banner)))
|
|
||||||
|
|
||||||
if compress && platform == "darwin/universal" {
|
|
||||||
logger.Println("Warning: compress flag unsupported for universal binaries. Ignoring.")
|
|
||||||
compress = false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch buildOptions.Platform {
|
|
||||||
case "linux":
|
|
||||||
if runtime.GOOS != "linux" {
|
|
||||||
logger.Println("Crosscompiling to Linux not currently supported.\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "darwin":
|
|
||||||
if runtime.GOOS != "darwin" {
|
|
||||||
logger.Println("Crosscompiling to Mac not currently supported.\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
macTargets := targets.Filter(func(platform string) bool {
|
|
||||||
return strings.HasPrefix(platform, "darwin")
|
|
||||||
})
|
|
||||||
if macTargets.Length() == 2 {
|
|
||||||
buildOptions.BundleName = fmt.Sprintf("%s-%s.app", desiredFilename, buildOptions.Arch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if targets.Length() > 1 {
|
|
||||||
// target filename
|
|
||||||
switch buildOptions.Platform {
|
|
||||||
case "windows":
|
|
||||||
desiredFilename = fmt.Sprintf("%s-%s", desiredFilename, buildOptions.Arch)
|
|
||||||
case "linux", "darwin":
|
|
||||||
desiredFilename = fmt.Sprintf("%s-%s-%s", desiredFilename, buildOptions.Platform, buildOptions.Arch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if buildOptions.Platform == "windows" {
|
|
||||||
desiredFilename += ".exe"
|
|
||||||
}
|
|
||||||
buildOptions.OutputFile = desiredFilename
|
|
||||||
|
|
||||||
if outputFilename != "" {
|
|
||||||
buildOptions.OutputFile = outputFilename
|
|
||||||
}
|
|
||||||
|
|
||||||
if obfuscated && skipBindings {
|
|
||||||
logger.Println("Warning: obfuscated flag overrides skipbindings flag.")
|
|
||||||
buildOptions.SkipBindings = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dryRun {
|
|
||||||
// Start Time
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
compiledBinary, err := build.Build(buildOptions)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("Error: %s", err.Error())
|
|
||||||
targetErr = err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buildOptions.IgnoreFrontend = true
|
|
||||||
buildOptions.CleanBinDirectory = false
|
|
||||||
|
|
||||||
// Output stats
|
|
||||||
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.\n", compiledBinary, time.Since(start).Round(time.Millisecond).String()))
|
|
||||||
|
|
||||||
outputBinaries[buildOptions.Platform+"/"+buildOptions.Arch] = compiledBinary
|
|
||||||
} else {
|
|
||||||
logger.Println("Dry run: skipped build.")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if targetErr != nil {
|
|
||||||
return targetErr
|
|
||||||
}
|
|
||||||
|
|
||||||
if dryRun {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if nsis {
|
|
||||||
amd64Binary := outputBinaries["windows/amd64"]
|
|
||||||
arm64Binary := outputBinaries["windows/arm64"]
|
|
||||||
if amd64Binary == "" && arm64Binary == "" {
|
|
||||||
return fmt.Errorf("cannot build nsis installer - no windows targets")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := build.GenerateNSISInstaller(buildOptions, amd64Binary, arm64Binary); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func LogGreen(message string, args ...interface{}) {
|
|
||||||
text := fmt.Sprintf(message, args...)
|
|
||||||
println(colour.Green(text))
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
# Dev
|
|
||||||
|
|
||||||
The dev command allows you to develop your application through a standard browser.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
`wails dev <flags>`
|
|
||||||
|
|
||||||
### Flags
|
|
||||||
|
|
||||||
| Flag | Details | Default |
|
|
||||||
| :------------- | :----------- | :------ |
|
|
||||||
| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go |
|
|
||||||
| -ldflags "custom ld flags" | Use given ldflags | |
|
|
||||||
| -e list,of,extensions | File extensions to trigger rebuilds | go |
|
|
||||||
| -w | Show warnings | false |
|
|
||||||
| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 |
|
|
||||||
| -loglevel | Loglevel to pass to the application - Trace, Debug, Info, Warning, Error | Debug |
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
The project is built using a special mode that starts a webserver and starts listening to port 34115. When the frontend project is run independently, so long as the JS is wrapped with the runtime method `ready`, then the frontend will connect to the backend code via websockets. The interface should be present in your browser, and you should be able to interact with the backend as you would in a desktop app.
|
|
@ -1,694 +0,0 @@
|
|||||||
package dev
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"os/signal"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/bindings"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
|
|
||||||
|
|
||||||
"github.com/google/shlex"
|
|
||||||
buildcmd "github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/project"
|
|
||||||
|
|
||||||
"github.com/pkg/browser"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/colour"
|
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/logutils"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/process"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
|
||||||
)
|
|
||||||
|
|
||||||
func sliceToMap(input []string) map[string]struct{} {
|
|
||||||
result := map[string]struct{}{}
|
|
||||||
for _, value := range input {
|
|
||||||
result[value] = struct{}{}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
type devFlags struct {
|
|
||||||
ldflags string
|
|
||||||
compilerCommand string
|
|
||||||
assetDir string
|
|
||||||
extensions string
|
|
||||||
reloadDirs string
|
|
||||||
openBrowser bool
|
|
||||||
noReload bool
|
|
||||||
skipBindings bool
|
|
||||||
wailsjsdir string
|
|
||||||
tags string
|
|
||||||
verbosity int
|
|
||||||
loglevel string
|
|
||||||
forceBuild bool
|
|
||||||
debounceMS int
|
|
||||||
devServer string
|
|
||||||
appargs string
|
|
||||||
saveConfig bool
|
|
||||||
raceDetector bool
|
|
||||||
|
|
||||||
frontendDevServerURL string
|
|
||||||
skipFrontend bool
|
|
||||||
noColour bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSubcommand adds the `dev` command for the Wails application
|
|
||||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|
||||||
|
|
||||||
command := app.NewSubCommand("dev", "Development mode")
|
|
||||||
|
|
||||||
flags := defaultDevFlags()
|
|
||||||
command.StringFlag("ldflags", "optional ldflags", &flags.ldflags)
|
|
||||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &flags.compilerCommand)
|
|
||||||
command.StringFlag("assetdir", "Serve assets from the given directory instead of using the provided asset FS", &flags.assetDir)
|
|
||||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &flags.extensions)
|
|
||||||
command.StringFlag("reloaddirs", "Additional directories to trigger reloads (comma separated)", &flags.reloadDirs)
|
|
||||||
command.BoolFlag("browser", "Open application in browser", &flags.openBrowser)
|
|
||||||
command.BoolFlag("noreload", "Disable reload on asset change", &flags.noReload)
|
|
||||||
command.BoolFlag("nocolour", "Turn off colour cli output", &flags.noColour)
|
|
||||||
command.BoolFlag("skipbindings", "Skip bindings generation", &flags.skipBindings)
|
|
||||||
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &flags.wailsjsdir)
|
|
||||||
command.StringFlag("tags", "Build tags to pass to Go compiler. Must be quoted. Space or comma (but not both) separated", &flags.tags)
|
|
||||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &flags.verbosity)
|
|
||||||
command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &flags.loglevel)
|
|
||||||
command.BoolFlag("f", "Force build application", &flags.forceBuild)
|
|
||||||
command.IntFlag("debounce", "The amount of time to wait to trigger a reload on change", &flags.debounceMS)
|
|
||||||
command.StringFlag("devserver", "The address of the wails dev server", &flags.devServer)
|
|
||||||
command.StringFlag("frontenddevserverurl", "The url of the external frontend dev server to use", &flags.frontendDevServerURL)
|
|
||||||
command.StringFlag("appargs", "arguments to pass to the underlying app (quoted and space separated)", &flags.appargs)
|
|
||||||
command.BoolFlag("save", "Save given flags as defaults", &flags.saveConfig)
|
|
||||||
command.BoolFlag("race", "Build with Go's race detector", &flags.raceDetector)
|
|
||||||
command.BoolFlag("s", "Skips building the frontend", &flags.skipFrontend)
|
|
||||||
|
|
||||||
command.Action(func() error {
|
|
||||||
if flags.noColour {
|
|
||||||
colour.ColourEnabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create logger
|
|
||||||
logger := clilogger.New(w)
|
|
||||||
app.PrintBanner()
|
|
||||||
|
|
||||||
cwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
projectConfig, err := loadAndMergeProjectConfig(cwd, &flags)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
devServer := flags.devServer
|
|
||||||
if _, _, err := net.SplitHostPort(devServer); err != nil {
|
|
||||||
return fmt.Errorf("DevServer is not of the form 'host:port', please check your wails.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
devServerURL, err := url.Parse("http://" + devServer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update go.mod to use current wails version
|
|
||||||
err = buildcmd.SyncGoMod(logger, true)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run go mod tidy to ensure we're up-to-date
|
|
||||||
err = runCommand(cwd, false, "go", "mod", "tidy")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buildOptions := generateBuildOptions(flags)
|
|
||||||
buildOptions.ProjectData = projectConfig
|
|
||||||
buildOptions.SkipBindings = flags.skipBindings
|
|
||||||
buildOptions.Logger = logger
|
|
||||||
|
|
||||||
userTags, err := buildtags.Parse(flags.tags)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buildOptions.UserTags = userTags
|
|
||||||
|
|
||||||
err = build.CreateEmbedDirectories(cwd, buildOptions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !buildOptions.SkipBindings {
|
|
||||||
if flags.verbosity == build.VERBOSE {
|
|
||||||
logutils.LogGreen("Generating Bindings...")
|
|
||||||
}
|
|
||||||
stdout, err := bindings.GenerateBindings(bindings.Options{
|
|
||||||
Tags: buildOptions.UserTags,
|
|
||||||
TsPrefix: projectConfig.Bindings.TsGeneration.Prefix,
|
|
||||||
TsSuffix: projectConfig.Bindings.TsGeneration.Suffix,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if flags.verbosity == build.VERBOSE {
|
|
||||||
logutils.LogGreen(stdout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup signal handler
|
|
||||||
quitChannel := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
|
||||||
exitCodeChannel := make(chan int, 1)
|
|
||||||
|
|
||||||
// Build the frontend if requested, but ignore building the application itself.
|
|
||||||
ignoreFrontend := buildOptions.IgnoreFrontend
|
|
||||||
if !ignoreFrontend {
|
|
||||||
buildOptions.IgnoreApplication = true
|
|
||||||
if _, err := build.Build(buildOptions); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
buildOptions.IgnoreApplication = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// frontend:dev:watcher command.
|
|
||||||
frontendDevAutoDiscovery := projectConfig.IsFrontendDevServerURLAutoDiscovery()
|
|
||||||
if command := projectConfig.DevWatcherCommand; command != "" {
|
|
||||||
closer, devServerURL, err := runFrontendDevWatcherCommand(projectConfig.GetFrontendDir(), command, frontendDevAutoDiscovery)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if devServerURL != "" {
|
|
||||||
projectConfig.FrontendDevServerURL = devServerURL
|
|
||||||
flags.frontendDevServerURL = devServerURL
|
|
||||||
}
|
|
||||||
defer closer()
|
|
||||||
} else if frontendDevAutoDiscovery {
|
|
||||||
return fmt.Errorf("Unable to auto discover frontend:dev:serverUrl without a frontend:dev:watcher command, please either set frontend:dev:watcher or remove the auto discovery from frontend:dev:serverUrl")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do initial build but only for the application.
|
|
||||||
logger.Println("Building application for development...")
|
|
||||||
buildOptions.IgnoreFrontend = true
|
|
||||||
debugBinaryProcess, appBinary, err := restartApp(buildOptions, nil, flags, exitCodeChannel)
|
|
||||||
buildOptions.IgnoreFrontend = ignoreFrontend || flags.frontendDevServerURL != ""
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err := killProcessAndCleanupBinary(debugBinaryProcess, appBinary); err != nil {
|
|
||||||
logutils.LogDarkYellow("Unable to kill process and cleanup binary: %s", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// open browser
|
|
||||||
if flags.openBrowser {
|
|
||||||
err = browser.OpenURL(devServerURL.String())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the project files watcher
|
|
||||||
watcher, err := initialiseWatcher(cwd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func(watcher *fsnotify.Watcher) {
|
|
||||||
err := watcher.Close()
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
}(watcher)
|
|
||||||
|
|
||||||
logutils.LogGreen("Watching (sub)/directory: %s", cwd)
|
|
||||||
logutils.LogGreen("Using DevServer URL: %s", devServerURL)
|
|
||||||
if flags.frontendDevServerURL != "" {
|
|
||||||
logutils.LogGreen("Using Frontend DevServer URL: %s", flags.frontendDevServerURL)
|
|
||||||
}
|
|
||||||
logutils.LogGreen("Using reload debounce setting of %d milliseconds", flags.debounceMS)
|
|
||||||
|
|
||||||
// Show dev server URL in terminal after 3 seconds
|
|
||||||
go func() {
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
logutils.LogGreen("\n\nTo develop in the browser and call your bound Go methods from Javascript, navigate to: %s", devServerURL)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Watch for changes and trigger restartApp()
|
|
||||||
debugBinaryProcess = doWatcherLoop(buildOptions, debugBinaryProcess, flags, watcher, exitCodeChannel, quitChannel, devServerURL)
|
|
||||||
|
|
||||||
// Kill the current program if running and remove dev binary
|
|
||||||
if err := killProcessAndCleanupBinary(debugBinaryProcess, appBinary); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the process and the binary so defer knows about it and is a nop.
|
|
||||||
debugBinaryProcess = nil
|
|
||||||
appBinary = ""
|
|
||||||
|
|
||||||
logutils.LogGreen("Development mode exited")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func killProcessAndCleanupBinary(process *process.Process, binary string) error {
|
|
||||||
if process != nil && process.Running {
|
|
||||||
if err := process.Kill(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if binary != "" {
|
|
||||||
err := os.Remove(binary)
|
|
||||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func runCommand(dir string, exitOnError bool, command string, args ...string) error {
|
|
||||||
logutils.LogGreen("Executing: " + command + " " + strings.Join(args, " "))
|
|
||||||
cmd := exec.Command(command, args...)
|
|
||||||
cmd.Dir = dir
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
println(string(output))
|
|
||||||
println(err.Error())
|
|
||||||
if exitOnError {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultDevFlags generates devFlags with default options
|
|
||||||
func defaultDevFlags() devFlags {
|
|
||||||
return devFlags{
|
|
||||||
compilerCommand: "go",
|
|
||||||
verbosity: 1,
|
|
||||||
extensions: "go",
|
|
||||||
debounceMS: 100,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateBuildOptions creates a build.Options using the flags
|
|
||||||
func generateBuildOptions(flags devFlags) *build.Options {
|
|
||||||
result := &build.Options{
|
|
||||||
OutputType: "dev",
|
|
||||||
Mode: build.Dev,
|
|
||||||
Arch: runtime.GOARCH,
|
|
||||||
Pack: true,
|
|
||||||
Platform: runtime.GOOS,
|
|
||||||
LDFlags: flags.ldflags,
|
|
||||||
Compiler: flags.compilerCommand,
|
|
||||||
ForceBuild: flags.forceBuild,
|
|
||||||
IgnoreFrontend: flags.skipFrontend,
|
|
||||||
Verbosity: flags.verbosity,
|
|
||||||
WailsJSDir: flags.wailsjsdir,
|
|
||||||
RaceDetector: flags.raceDetector,
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadAndMergeProjectConfig reconciles flags passed to the CLI with project config settings and updates
|
|
||||||
// the project config if necessary
|
|
||||||
func loadAndMergeProjectConfig(projectFileDirectory string, flags *devFlags) (*project.Project, error) {
|
|
||||||
projectConfig, err := project.Load(projectFileDirectory)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.assetDir == "" && projectConfig.AssetDirectory != "" {
|
|
||||||
flags.assetDir = projectConfig.AssetDirectory
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.assetDir != projectConfig.AssetDirectory {
|
|
||||||
projectConfig.AssetDirectory = filepath.ToSlash(flags.assetDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.assetDir != "" {
|
|
||||||
flags.assetDir, err = filepath.Abs(flags.assetDir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.reloadDirs == "" && projectConfig.ReloadDirectories != "" {
|
|
||||||
flags.reloadDirs = projectConfig.ReloadDirectories
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.reloadDirs != projectConfig.ReloadDirectories {
|
|
||||||
projectConfig.ReloadDirectories = filepath.ToSlash(flags.reloadDirs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.devServer == "" && projectConfig.DevServer != "" {
|
|
||||||
flags.devServer = projectConfig.DevServer
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.frontendDevServerURL == "" && projectConfig.FrontendDevServerURL != "" {
|
|
||||||
flags.frontendDevServerURL = projectConfig.FrontendDevServerURL
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.wailsjsdir == "" && projectConfig.WailsJSDir != "" {
|
|
||||||
flags.wailsjsdir = projectConfig.GetWailsJSDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.wailsjsdir == "" {
|
|
||||||
flags.wailsjsdir = projectConfig.GetFrontendDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.wailsjsdir != projectConfig.WailsJSDir {
|
|
||||||
projectConfig.WailsJSDir = filepath.ToSlash(flags.wailsjsdir)
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.debounceMS == 100 && projectConfig.DebounceMS != 100 {
|
|
||||||
if projectConfig.DebounceMS == 0 {
|
|
||||||
projectConfig.DebounceMS = 100
|
|
||||||
}
|
|
||||||
flags.debounceMS = projectConfig.DebounceMS
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.debounceMS != projectConfig.DebounceMS {
|
|
||||||
projectConfig.DebounceMS = flags.debounceMS
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.appargs == "" && projectConfig.AppArgs != "" {
|
|
||||||
flags.appargs = projectConfig.AppArgs
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.saveConfig {
|
|
||||||
err = projectConfig.Save()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return projectConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// runFrontendDevWatcherCommand will run the `frontend:dev:watcher` command if it was given, ex- `npm run dev`
|
|
||||||
func runFrontendDevWatcherCommand(frontendDirectory string, devCommand string, discoverViteServerURL bool) (func(), string, error) {
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
scanner := NewStdoutScanner()
|
|
||||||
cmdSlice := strings.Split(devCommand, " ")
|
|
||||||
cmd := exec.CommandContext(ctx, cmdSlice[0], cmdSlice[1:]...)
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
cmd.Stdout = scanner
|
|
||||||
cmd.Dir = frontendDirectory
|
|
||||||
setParentGID(cmd)
|
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
cancel()
|
|
||||||
return nil, "", fmt.Errorf("unable to start frontend DevWatcher: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var viteServerURL string
|
|
||||||
if discoverViteServerURL {
|
|
||||||
select {
|
|
||||||
case serverURL := <-scanner.ViteServerURLChan:
|
|
||||||
viteServerURL = serverURL
|
|
||||||
case <-time.After(time.Second * 10):
|
|
||||||
cancel()
|
|
||||||
return nil, "", errors.New("failed to find Vite server URL")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logutils.LogGreen("Running frontend DevWatcher command: '%s'", devCommand)
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
const (
|
|
||||||
stateRunning int32 = 0
|
|
||||||
stateCanceling = 1
|
|
||||||
stateStopped = 2
|
|
||||||
)
|
|
||||||
state := stateRunning
|
|
||||||
go func() {
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
wasRunning := atomic.CompareAndSwapInt32(&state, stateRunning, stateStopped)
|
|
||||||
if err.Error() != "exit status 1" && wasRunning {
|
|
||||||
logutils.LogRed("Error from DevWatcher '%s': %s", devCommand, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
atomic.StoreInt32(&state, stateStopped)
|
|
||||||
wg.Done()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return func() {
|
|
||||||
if atomic.CompareAndSwapInt32(&state, stateRunning, stateCanceling) {
|
|
||||||
killProc(cmd, devCommand)
|
|
||||||
}
|
|
||||||
cancel()
|
|
||||||
wg.Wait()
|
|
||||||
}, viteServerURL, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// restartApp does the actual rebuilding of the application when files change
|
|
||||||
func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, exitCodeChannel chan int) (*process.Process, string, error) {
|
|
||||||
|
|
||||||
appBinary, err := build.Build(buildOptions)
|
|
||||||
println()
|
|
||||||
if err != nil {
|
|
||||||
logutils.LogRed("Build error - " + err.Error())
|
|
||||||
|
|
||||||
msg := "Continuing to run current version"
|
|
||||||
if debugBinaryProcess == nil {
|
|
||||||
msg = "No version running, build will be retriggered as soon as changes have been detected"
|
|
||||||
}
|
|
||||||
logutils.LogDarkYellow(msg)
|
|
||||||
return nil, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill existing binary if need be
|
|
||||||
if debugBinaryProcess != nil {
|
|
||||||
killError := debugBinaryProcess.Kill()
|
|
||||||
|
|
||||||
if killError != nil {
|
|
||||||
buildOptions.Logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
|
||||||
}
|
|
||||||
|
|
||||||
debugBinaryProcess = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse appargs if any
|
|
||||||
args, err := shlex.Split(flags.appargs)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
buildOptions.Logger.Fatal("Unable to parse appargs: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set environment variables accordingly
|
|
||||||
os.Setenv("loglevel", flags.loglevel)
|
|
||||||
os.Setenv("assetdir", flags.assetDir)
|
|
||||||
os.Setenv("devserver", flags.devServer)
|
|
||||||
os.Setenv("frontenddevserverurl", flags.frontendDevServerURL)
|
|
||||||
|
|
||||||
// Start up new binary with correct args
|
|
||||||
newProcess := process.NewProcess(appBinary, args...)
|
|
||||||
err = newProcess.Start(exitCodeChannel)
|
|
||||||
if err != nil {
|
|
||||||
// Remove binary
|
|
||||||
if fs.FileExists(appBinary) {
|
|
||||||
deleteError := fs.DeleteFile(appBinary)
|
|
||||||
if deleteError != nil {
|
|
||||||
buildOptions.Logger.Fatal("Unable to delete app binary: " + appBinary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buildOptions.Logger.Fatal("Unable to start application: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return newProcess, appBinary, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// doWatcherLoop is the main watch loop that runs while dev is active
|
|
||||||
func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, watcher *fsnotify.Watcher, exitCodeChannel chan int, quitChannel chan os.Signal, devServerURL *url.URL) *process.Process {
|
|
||||||
// Main Loop
|
|
||||||
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(flags.extensions, ","))
|
|
||||||
var dirsThatTriggerAReload []string
|
|
||||||
for _, dir := range strings.Split(flags.reloadDirs, ",") {
|
|
||||||
if dir == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
thePath, err := filepath.Abs(dir)
|
|
||||||
if err != nil {
|
|
||||||
logutils.LogRed("Unable to expand reloadDir '%s': %s", dir, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
dirsThatTriggerAReload = append(dirsThatTriggerAReload, thePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
quit := false
|
|
||||||
interval := time.Duration(flags.debounceMS) * time.Millisecond
|
|
||||||
timer := time.NewTimer(interval)
|
|
||||||
rebuild := false
|
|
||||||
reload := false
|
|
||||||
assetDir := ""
|
|
||||||
changedPaths := map[string]struct{}{}
|
|
||||||
|
|
||||||
// If we are using an external dev server, the reloading of the frontend part can be skipped or if the user requested it
|
|
||||||
skipAssetsReload := (flags.frontendDevServerURL != "" || flags.noReload)
|
|
||||||
|
|
||||||
assetDirURL := joinPath(devServerURL, "/wails/assetdir")
|
|
||||||
reloadURL := joinPath(devServerURL, "/wails/reload")
|
|
||||||
for quit == false {
|
|
||||||
// reload := false
|
|
||||||
select {
|
|
||||||
case exitCode := <-exitCodeChannel:
|
|
||||||
if exitCode == 0 {
|
|
||||||
quit = true
|
|
||||||
}
|
|
||||||
case err := <-watcher.Errors:
|
|
||||||
logutils.LogDarkYellow(err.Error())
|
|
||||||
case item := <-watcher.Events:
|
|
||||||
isEligibleFile := func(fileName string) bool {
|
|
||||||
// Iterate all file patterns
|
|
||||||
ext := filepath.Ext(fileName)
|
|
||||||
if ext != "" {
|
|
||||||
ext = ext[1:]
|
|
||||||
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle write operations
|
|
||||||
if item.Op&fsnotify.Write == fsnotify.Write {
|
|
||||||
// Ignore directories
|
|
||||||
itemName := item.Name
|
|
||||||
if fs.DirExists(itemName) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if isEligibleFile(itemName) {
|
|
||||||
rebuild = true
|
|
||||||
timer.Reset(interval)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, reloadDir := range dirsThatTriggerAReload {
|
|
||||||
if strings.HasPrefix(itemName, reloadDir) {
|
|
||||||
reload = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reload {
|
|
||||||
changedPaths[filepath.Dir(itemName)] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.Reset(interval)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle new fs entries that are created
|
|
||||||
if item.Op&fsnotify.Create == fsnotify.Create {
|
|
||||||
// If this is a folder, add it to our watch list
|
|
||||||
if fs.DirExists(item.Name) {
|
|
||||||
// node_modules is BANNED!
|
|
||||||
if !strings.Contains(item.Name, "node_modules") {
|
|
||||||
err := watcher.Add(item.Name)
|
|
||||||
if err != nil {
|
|
||||||
buildOptions.Logger.Fatal("%s", err.Error())
|
|
||||||
}
|
|
||||||
logutils.LogGreen("Added new directory to watcher: %s", item.Name)
|
|
||||||
}
|
|
||||||
} else if isEligibleFile(item.Name) {
|
|
||||||
// Handle creation of new file.
|
|
||||||
// Note: On some platforms an update to a file is represented as
|
|
||||||
// REMOVE -> CREATE instead of WRITE, so this is not only new files
|
|
||||||
// but also updates to existing files
|
|
||||||
rebuild = true
|
|
||||||
timer.Reset(interval)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case <-timer.C:
|
|
||||||
if rebuild {
|
|
||||||
rebuild = false
|
|
||||||
logutils.LogGreen("[Rebuild triggered] files updated")
|
|
||||||
// Try and build the app
|
|
||||||
newBinaryProcess, _, err := restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel)
|
|
||||||
if err != nil {
|
|
||||||
logutils.LogRed("Error during build: %s", err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// If we have a new process, saveConfig it
|
|
||||||
if newBinaryProcess != nil {
|
|
||||||
debugBinaryProcess = newBinaryProcess
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !skipAssetsReload && len(changedPaths) != 0 {
|
|
||||||
if assetDir == "" {
|
|
||||||
resp, err := http.Get(assetDirURL)
|
|
||||||
if err != nil {
|
|
||||||
logutils.LogRed("Error during retrieving assetdir: %s", err.Error())
|
|
||||||
} else {
|
|
||||||
content, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
logutils.LogRed("Error reading assetdir from devserver: %s", err.Error())
|
|
||||||
} else {
|
|
||||||
assetDir = string(content)
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if assetDir != "" {
|
|
||||||
for thePath := range changedPaths {
|
|
||||||
if strings.HasPrefix(thePath, assetDir) {
|
|
||||||
reload = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if len(dirsThatTriggerAReload) == 0 {
|
|
||||||
logutils.LogRed("Reloading couldn't be triggered: Please specify -assetdir or -reloaddirs")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if reload {
|
|
||||||
reload = false
|
|
||||||
_, err := http.Get(reloadURL)
|
|
||||||
if err != nil {
|
|
||||||
logutils.LogRed("Error during refresh: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changedPaths = map[string]struct{}{}
|
|
||||||
case <-quitChannel:
|
|
||||||
logutils.LogGreen("\nCaught quit")
|
|
||||||
quit = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return debugBinaryProcess
|
|
||||||
}
|
|
||||||
|
|
||||||
func joinPath(url *url.URL, subPath string) string {
|
|
||||||
u := *url
|
|
||||||
u.Path = path.Join(u.Path, subPath)
|
|
||||||
return u.String()
|
|
||||||
}
|
|
@ -1,174 +0,0 @@
|
|||||||
package doctor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"runtime/debug"
|
|
||||||
"strings"
|
|
||||||
"text/tabwriter"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/system"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/system/packagemanager"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddSubcommand adds the `doctor` command for the Wails application
|
|
||||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|
||||||
|
|
||||||
command := app.NewSubCommand("doctor", "Diagnose your environment")
|
|
||||||
|
|
||||||
command.Action(func() error {
|
|
||||||
|
|
||||||
logger := clilogger.New(w)
|
|
||||||
|
|
||||||
app.PrintBanner()
|
|
||||||
|
|
||||||
logger.Print("Scanning system - Please wait (this may take a long time)...")
|
|
||||||
|
|
||||||
// Get system info
|
|
||||||
info, err := system.GetInfo()
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("Failed.")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
logger.Println("Done.")
|
|
||||||
|
|
||||||
logger.Println("")
|
|
||||||
|
|
||||||
// Start a new tabwriter
|
|
||||||
w := new(tabwriter.Writer)
|
|
||||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
|
||||||
|
|
||||||
// Write out the system information
|
|
||||||
fmt.Fprintf(w, "System\n")
|
|
||||||
fmt.Fprintf(w, "------\n")
|
|
||||||
fmt.Fprintf(w, "%s\t%s\n", "OS:", info.OS.Name)
|
|
||||||
fmt.Fprintf(w, "%s\t%s\n", "Version: ", info.OS.Version)
|
|
||||||
fmt.Fprintf(w, "%s\t%s\n", "ID:", info.OS.ID)
|
|
||||||
|
|
||||||
// Output Go Information
|
|
||||||
fmt.Fprintf(w, "%s\t%s\n", "Go Version:", runtime.Version())
|
|
||||||
fmt.Fprintf(w, "%s\t%s\n", "Platform:", runtime.GOOS)
|
|
||||||
fmt.Fprintf(w, "%s\t%s\n", "Architecture:", runtime.GOARCH)
|
|
||||||
|
|
||||||
// Write out the wails information
|
|
||||||
fmt.Fprintf(w, "\n")
|
|
||||||
fmt.Fprintf(w, "Wails\n")
|
|
||||||
fmt.Fprintf(w, "------\n")
|
|
||||||
fmt.Fprintf(w, "%s\t%s\n", "Version: ", app.Version())
|
|
||||||
|
|
||||||
printBuildSettings(w)
|
|
||||||
|
|
||||||
// Exit early if PM not found
|
|
||||||
if info.PM != nil {
|
|
||||||
fmt.Fprintf(w, "%s\t%s\n", "Package Manager: ", info.PM.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output Dependencies Status
|
|
||||||
var dependenciesMissing = []string{}
|
|
||||||
var externalPackages = []*packagemanager.Dependency{}
|
|
||||||
var dependenciesAvailableRequired = 0
|
|
||||||
var dependenciesAvailableOptional = 0
|
|
||||||
fmt.Fprintf(w, "\n")
|
|
||||||
fmt.Fprintf(w, "Dependency\tPackage Name\tStatus\tVersion\n")
|
|
||||||
fmt.Fprintf(w, "----------\t------------\t------\t-------\n")
|
|
||||||
|
|
||||||
hasOptionalDependencies := false
|
|
||||||
// Loop over dependencies
|
|
||||||
for _, dependency := range info.Dependencies {
|
|
||||||
|
|
||||||
name := dependency.Name
|
|
||||||
if dependency.Optional {
|
|
||||||
name = "*" + name
|
|
||||||
hasOptionalDependencies = true
|
|
||||||
}
|
|
||||||
packageName := "Unknown"
|
|
||||||
status := "Not Found"
|
|
||||||
|
|
||||||
// If we found the package
|
|
||||||
if dependency.PackageName != "" {
|
|
||||||
|
|
||||||
packageName = dependency.PackageName
|
|
||||||
|
|
||||||
// If it's installed, update the status
|
|
||||||
if dependency.Installed {
|
|
||||||
status = "Installed"
|
|
||||||
} else {
|
|
||||||
// Generate meaningful status text
|
|
||||||
status = "Available"
|
|
||||||
|
|
||||||
if dependency.Optional {
|
|
||||||
dependenciesAvailableOptional++
|
|
||||||
} else {
|
|
||||||
dependenciesAvailableRequired++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !dependency.Optional {
|
|
||||||
dependenciesMissing = append(dependenciesMissing, dependency.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if dependency.External {
|
|
||||||
externalPackages = append(externalPackages, dependency)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(w, "%s \t%s \t%s \t%s\n", name, packageName, status, dependency.Version)
|
|
||||||
}
|
|
||||||
if hasOptionalDependencies {
|
|
||||||
fmt.Fprintf(w, "\n")
|
|
||||||
fmt.Fprintf(w, "* - Optional Dependency\n")
|
|
||||||
}
|
|
||||||
w.Flush()
|
|
||||||
logger.Println("")
|
|
||||||
logger.Println("Diagnosis")
|
|
||||||
logger.Println("---------")
|
|
||||||
|
|
||||||
// Generate an appropriate diagnosis
|
|
||||||
|
|
||||||
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
|
|
||||||
logger.Println("Your system is ready for Wails development!")
|
|
||||||
} else {
|
|
||||||
logger.Println("Your system has missing dependencies!\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
if dependenciesAvailableRequired != 0 {
|
|
||||||
logger.Println("Required package(s) installation details: \n" + info.Dependencies.InstallAllRequiredCommand())
|
|
||||||
}
|
|
||||||
|
|
||||||
if dependenciesAvailableOptional != 0 {
|
|
||||||
logger.Println("Optional package(s) installation details: \n" + info.Dependencies.InstallAllOptionalCommand())
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(dependenciesMissing) != 0 {
|
|
||||||
logger.Println("Fatal:")
|
|
||||||
logger.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
|
|
||||||
logger.Println("Please read this article on how to resolve this: https://wails.io/guides/resolving-missing-packages")
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Println("")
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func printBuildSettings(w *tabwriter.Writer) {
|
|
||||||
if buildInfo, _ := debug.ReadBuildInfo(); buildInfo != nil {
|
|
||||||
buildSettingToName := map[string]string{
|
|
||||||
"vcs.revision": "Revision",
|
|
||||||
"vcs.modified": "Modified",
|
|
||||||
}
|
|
||||||
for _, buildSetting := range buildInfo.Settings {
|
|
||||||
name := buildSettingToName[buildSetting.Key]
|
|
||||||
if name == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(w, "%s:\t%s\n", name, buildSetting.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
# Generate
|
|
||||||
|
|
||||||
The `generate` command provides the ability to generate various Wails related components.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
`wails generate [subcommand] [options]`
|
|
||||||
|
|
||||||
## Template
|
|
||||||
|
|
||||||
`wails generate template -name <name> [-frontend] [-q]`
|
|
||||||
|
|
||||||
Generate a starter template for you to customise.
|
|
||||||
|
|
||||||
| Flag | Details |
|
|
||||||
| :------------- | :----------- |
|
|
||||||
| -frontend | Copies all the files from the current directory into the template's `frontend` directory. Useful for converting frontend projects created by boilerplate generators. |
|
|
||||||
| -q | Suppress output |
|
|
||||||
|
|
||||||
|
|
||||||
## Module
|
|
||||||
|
|
||||||
`wails generate module [-h]`
|
|
||||||
|
|
||||||
Generate TS module for your frontend
|
|
@ -1,23 +0,0 @@
|
|||||||
package generate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate/template"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddSubcommand adds the `generate` command for the Wails application
|
|
||||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|
||||||
|
|
||||||
command := app.NewSubCommand("generate", "Code Generation Tools")
|
|
||||||
|
|
||||||
err := AddModuleCommand(app, command, w)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
template.AddSubCommand(app, command, w)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
package generate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/project"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/bindings"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
|
|
||||||
)
|
|
||||||
|
|
||||||
type generateFlags struct {
|
|
||||||
tags string
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddModuleCommand adds the `module` subcommand for the `generate` command
|
|
||||||
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) error {
|
|
||||||
|
|
||||||
command := parent.NewSubCommand("module", "Generate wailsjs modules")
|
|
||||||
genFlags := generateFlags{}
|
|
||||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &genFlags.tags)
|
|
||||||
|
|
||||||
command.Action(func() error {
|
|
||||||
cwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
projectConfig, err := project.Load(cwd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTags, err := buildtags.Parse(genFlags.tags)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = bindings.GenerateBindings(bindings.Options{
|
|
||||||
Tags: buildTags,
|
|
||||||
TsPrefix: projectConfig.Bindings.TsGeneration.Prefix,
|
|
||||||
TsSuffix: projectConfig.Bindings.TsGeneration.Suffix,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,214 +0,0 @@
|
|||||||
package template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/leaanthony/debme"
|
|
||||||
|
|
||||||
"github.com/leaanthony/gosod"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"github.com/tidwall/sjson"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed base
|
|
||||||
var base embed.FS
|
|
||||||
|
|
||||||
func AddSubCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
|
|
||||||
|
|
||||||
// command
|
|
||||||
command := parent.NewSubCommand("template", "Generates a wails template")
|
|
||||||
|
|
||||||
name := ""
|
|
||||||
command.StringFlag("name", "The name of the template", &name)
|
|
||||||
|
|
||||||
existingProjectDir := ""
|
|
||||||
command.StringFlag("frontend", "A path to an existing frontend project to include in the template", &existingProjectDir)
|
|
||||||
|
|
||||||
// Quiet Init
|
|
||||||
quiet := false
|
|
||||||
command.BoolFlag("q", "Suppress output to console", &quiet)
|
|
||||||
|
|
||||||
command.Action(func() error {
|
|
||||||
|
|
||||||
// name is mandatory
|
|
||||||
if name == "" {
|
|
||||||
command.PrintHelp()
|
|
||||||
return fmt.Errorf("no template name given")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the current directory is not empty, we create a new directory
|
|
||||||
cwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
templateDir := filepath.Join(cwd, name)
|
|
||||||
if !fs.DirExists(templateDir) {
|
|
||||||
err := os.MkdirAll(templateDir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
empty, err := fs.DirIsEmpty(templateDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !empty {
|
|
||||||
templateDir = filepath.Join(cwd, name)
|
|
||||||
println("Creating new template directory:", name)
|
|
||||||
err = fs.Mkdir(templateDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create base template
|
|
||||||
baseTemplate, err := debme.FS(base, "base")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
g := gosod.New(baseTemplate)
|
|
||||||
g.SetTemplateFilters([]string{".template"})
|
|
||||||
|
|
||||||
err = os.Chdir(templateDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type templateData struct {
|
|
||||||
Name string
|
|
||||||
Description string
|
|
||||||
TemplateDir string
|
|
||||||
WailsVersion string
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Extracting base template files...")
|
|
||||||
|
|
||||||
err = g.Extract(templateDir, &templateData{
|
|
||||||
Name: name,
|
|
||||||
TemplateDir: templateDir,
|
|
||||||
WailsVersion: app.Version(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Chdir(cwd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we aren't migrating the files, just exit
|
|
||||||
if existingProjectDir == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove frontend directory
|
|
||||||
frontendDir := filepath.Join(templateDir, "frontend")
|
|
||||||
err = os.RemoveAll(frontendDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the files into a new frontend directory
|
|
||||||
println("Migrating existing project files to frontend directory...")
|
|
||||||
|
|
||||||
sourceDir, err := filepath.Abs(existingProjectDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newFrontendDir := filepath.Join(templateDir, "frontend")
|
|
||||||
err = fs.CopyDirExtended(sourceDir, newFrontendDir, []string{name, "node_modules"})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process package.json
|
|
||||||
err = processPackageJSON(frontendDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process package-lock.json
|
|
||||||
err = processPackageLockJSON(frontendDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove node_modules - ignore error, eg it doesn't exist
|
|
||||||
_ = os.RemoveAll(filepath.Join(frontendDir, "node_modules"))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func processPackageJSON(frontendDir string) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
packageJSON := filepath.Join(frontendDir, "package.json")
|
|
||||||
if !fs.FileExists(packageJSON) {
|
|
||||||
println("No package.json found - cannot process.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
json, err := os.ReadFile(packageJSON)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We will ignore these errors - it's not critical
|
|
||||||
println("Updating package.json data...")
|
|
||||||
json, _ = sjson.SetBytes(json, "name", "{{.ProjectName}}")
|
|
||||||
json, _ = sjson.SetBytes(json, "author", "{{.AuthorName}}")
|
|
||||||
|
|
||||||
err = os.WriteFile(packageJSON, json, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
baseDir := filepath.Dir(packageJSON)
|
|
||||||
println("Renaming package.json -> package.tmpl.json...")
|
|
||||||
err = os.Rename(packageJSON, filepath.Join(baseDir, "package.tmpl.json"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func processPackageLockJSON(frontendDir string) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
filename := filepath.Join(frontendDir, "package-lock.json")
|
|
||||||
if !fs.FileExists(filename) {
|
|
||||||
println("No package-lock.json found - cannot process.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := os.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
json := string(data)
|
|
||||||
|
|
||||||
// We will ignore these errors - it's not critical
|
|
||||||
println("Updating package-lock.json data...")
|
|
||||||
json, _ = sjson.Set(json, "name", "{{.ProjectName}}")
|
|
||||||
|
|
||||||
err = os.WriteFile(filename, []byte(json), 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
baseDir := filepath.Dir(filename)
|
|
||||||
println("Renaming package-lock.json -> package-lock.tmpl.json...")
|
|
||||||
err = os.Rename(filename, filepath.Join(baseDir, "package-lock.tmpl.json"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,310 +0,0 @@
|
|||||||
package initialise
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/flytam/filenamify"
|
|
||||||
"github.com/leaanthony/slicer"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/buildassets"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/templates"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/git"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddSubcommand adds the `init` command for the Wails application
|
|
||||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|
||||||
|
|
||||||
command := app.NewSubCommand("init", "Initialise a new Wails project")
|
|
||||||
|
|
||||||
// Setup template name flag
|
|
||||||
templateName := "vanilla"
|
|
||||||
description := "Name of built-in template to use, path to template or template url."
|
|
||||||
command.StringFlag("t", description, &templateName)
|
|
||||||
|
|
||||||
// Setup project name
|
|
||||||
projectName := ""
|
|
||||||
command.StringFlag("n", "Name of project", &projectName)
|
|
||||||
|
|
||||||
// For CI
|
|
||||||
ciMode := false
|
|
||||||
command.BoolFlag("ci", "CI Mode", &ciMode)
|
|
||||||
|
|
||||||
// Setup project directory
|
|
||||||
projectDirectory := ""
|
|
||||||
command.StringFlag("d", "Project directory", &projectDirectory)
|
|
||||||
|
|
||||||
// Quiet Init
|
|
||||||
quiet := false
|
|
||||||
command.BoolFlag("q", "Suppress output to console", &quiet)
|
|
||||||
|
|
||||||
initGit := false
|
|
||||||
gitInstalled := git.IsInstalled()
|
|
||||||
if gitInstalled {
|
|
||||||
// Git Init
|
|
||||||
command.BoolFlag("g", "Initialise git repository", &initGit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VSCode project files
|
|
||||||
ide := ""
|
|
||||||
command.StringFlag("ide", "Generate IDE project files", &ide)
|
|
||||||
|
|
||||||
// List templates
|
|
||||||
list := false
|
|
||||||
command.BoolFlag("l", "List templates", &list)
|
|
||||||
|
|
||||||
command.Action(func() error {
|
|
||||||
|
|
||||||
// Create logger
|
|
||||||
logger := clilogger.New(w)
|
|
||||||
logger.Mute(quiet)
|
|
||||||
|
|
||||||
// Are we listing templates?
|
|
||||||
if list {
|
|
||||||
app.PrintBanner()
|
|
||||||
err := templates.OutputList(logger)
|
|
||||||
logger.Println("")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate name
|
|
||||||
if len(projectName) == 0 {
|
|
||||||
logger.Println("ERROR: Project name required")
|
|
||||||
logger.Println("")
|
|
||||||
command.PrintHelp()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate IDE option
|
|
||||||
supportedIDEs := slicer.String([]string{"vscode", "goland"})
|
|
||||||
ide = strings.ToLower(ide)
|
|
||||||
if ide != "" {
|
|
||||||
if !supportedIDEs.Contains(ide) {
|
|
||||||
return fmt.Errorf("ide '%s' not supported. Valid values: %s", ide, supportedIDEs.Join(" "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !quiet {
|
|
||||||
app.PrintBanner()
|
|
||||||
}
|
|
||||||
|
|
||||||
task := fmt.Sprintf("Initialising Project '%s'", projectName)
|
|
||||||
logger.Println(task)
|
|
||||||
logger.Println(strings.Repeat("-", len(task)))
|
|
||||||
|
|
||||||
projectFilename, err := filenamify.Filenamify(projectName, filenamify.Options{
|
|
||||||
Replacement: "_",
|
|
||||||
MaxLength: 255,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
goBinary, err := exec.LookPath("go")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to find Go compiler. Please download and install Go: https://golang.org/dl/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get base path and convert to forward slashes
|
|
||||||
goPath := filepath.ToSlash(filepath.Dir(goBinary))
|
|
||||||
// Trim bin directory
|
|
||||||
goSDKPath := strings.TrimSuffix(goPath, "/bin")
|
|
||||||
|
|
||||||
// Create Template Options
|
|
||||||
options := &templates.Options{
|
|
||||||
ProjectName: projectName,
|
|
||||||
TargetDir: projectDirectory,
|
|
||||||
TemplateName: templateName,
|
|
||||||
Logger: logger,
|
|
||||||
IDE: ide,
|
|
||||||
InitGit: initGit,
|
|
||||||
ProjectNameFilename: projectFilename,
|
|
||||||
WailsVersion: app.Version(),
|
|
||||||
GoSDKPath: goSDKPath,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to discover author details from git config
|
|
||||||
findAuthorDetails(options)
|
|
||||||
|
|
||||||
return initProject(options, quiet, ciMode)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// initProject is our main init command
|
|
||||||
func initProject(options *templates.Options, quiet bool, ciMode bool) error {
|
|
||||||
|
|
||||||
// Start Time
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
// Install the template
|
|
||||||
remote, template, err := templates.Install(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install the default assets
|
|
||||||
err = buildassets.Install(options.TargetDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Chdir(options.TargetDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ciMode {
|
|
||||||
// Run `go mod tidy` to ensure `go.sum` is up to date
|
|
||||||
cmd := exec.Command("go", "mod", "tidy")
|
|
||||||
cmd.Dir = options.TargetDir
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
if !quiet {
|
|
||||||
println("")
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
}
|
|
||||||
err = cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Update go mod
|
|
||||||
workspace := os.Getenv("GITHUB_WORKSPACE")
|
|
||||||
println("GitHub workspace:", workspace)
|
|
||||||
if workspace == "" {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
updateReplaceLine(workspace)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the `.git`` directory in the template project
|
|
||||||
err = os.RemoveAll(".git")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.InitGit {
|
|
||||||
err = initGit(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if quiet {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output stats
|
|
||||||
elapsed := time.Since(start)
|
|
||||||
options.Logger.Println("Project Name: " + options.ProjectName)
|
|
||||||
options.Logger.Println("Project Directory: " + options.TargetDir)
|
|
||||||
options.Logger.Println("Project Template: " + options.TemplateName)
|
|
||||||
options.Logger.Println("Template Support: " + template.HelpURL)
|
|
||||||
|
|
||||||
// IDE message
|
|
||||||
switch options.IDE {
|
|
||||||
case "vscode":
|
|
||||||
options.Logger.Println("VSCode config files generated.")
|
|
||||||
case "goland":
|
|
||||||
options.Logger.Println("Goland config files generated.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.InitGit {
|
|
||||||
options.Logger.Println("Git repository initialised.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if remote {
|
|
||||||
options.Logger.Println("\nNOTE: You have created a project using a remote template. The Wails project takes no responsibility for 3rd party templates. Only use remote templates that you trust.")
|
|
||||||
}
|
|
||||||
|
|
||||||
options.Logger.Println("")
|
|
||||||
options.Logger.Println(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
|
|
||||||
options.Logger.Println("")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initGit(options *templates.Options) error {
|
|
||||||
err := git.InitRepo(options.TargetDir)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Unable to initialise git repository:")
|
|
||||||
}
|
|
||||||
|
|
||||||
ignore := []string{
|
|
||||||
"build/bin",
|
|
||||||
"frontend/dist",
|
|
||||||
"frontend/node_modules",
|
|
||||||
}
|
|
||||||
err = os.WriteFile(filepath.Join(options.TargetDir, ".gitignore"), []byte(strings.Join(ignore, "\n")), 0644)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Unable to create gitignore")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// findAuthorDetails tries to find the user's name and email
|
|
||||||
// from gitconfig. If it finds them, it stores them in the project options
|
|
||||||
func findAuthorDetails(options *templates.Options) {
|
|
||||||
if git.IsInstalled() {
|
|
||||||
name, err := git.Name()
|
|
||||||
if err == nil {
|
|
||||||
options.AuthorName = strings.TrimSpace(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
email, err := git.Email()
|
|
||||||
if err == nil {
|
|
||||||
options.AuthorEmail = strings.TrimSpace(email)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateReplaceLine(targetPath string) {
|
|
||||||
file, err := os.Open("go.mod")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var lines []string
|
|
||||||
scanner := bufio.NewScanner(file)
|
|
||||||
for scanner.Scan() {
|
|
||||||
lines = append(lines, scanner.Text())
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, line := range lines {
|
|
||||||
println(line)
|
|
||||||
if strings.HasPrefix(line, "// replace") {
|
|
||||||
println("Found replace line")
|
|
||||||
splitLine := strings.Split(line, " ")
|
|
||||||
splitLine[5] = targetPath + "/v2"
|
|
||||||
lines[i] = strings.Join(splitLine[1:], " ")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.WriteFile("go.mod", []byte(strings.Join(lines, "\n")), 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed all:frontend/src
|
|
||||||
var assets embed.FS
|
|
||||||
|
|
||||||
//go:embed build/appicon.png
|
|
||||||
var icon []byte
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Create an instance of the app structure
|
|
||||||
app := NewApp()
|
|
||||||
|
|
||||||
// Create application with options
|
|
||||||
err := wails.Run(&options.App{
|
|
||||||
Title: "{{.ProjectName}}",
|
|
||||||
Width: 1024,
|
|
||||||
Height: 768,
|
|
||||||
MinWidth: 1024,
|
|
||||||
MinHeight: 768,
|
|
||||||
MaxWidth: 1280,
|
|
||||||
MaxHeight: 800,
|
|
||||||
DisableResize: false,
|
|
||||||
Fullscreen: false,
|
|
||||||
Frameless: false,
|
|
||||||
StartHidden: false,
|
|
||||||
HideWindowOnClose: false,
|
|
||||||
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
|
|
||||||
AssetServer: &assetserver.Options{
|
|
||||||
Assets: assets,
|
|
||||||
},
|
|
||||||
Menu: nil,
|
|
||||||
Logger: nil,
|
|
||||||
LogLevel: logger.DEBUG,
|
|
||||||
OnStartup: app.startup,
|
|
||||||
OnDomReady: app.domReady,
|
|
||||||
OnBeforeClose: app.beforeClose,
|
|
||||||
OnShutdown: app.shutdown,
|
|
||||||
WindowStartState: options.Normal,
|
|
||||||
Bind: []interface{}{
|
|
||||||
app,
|
|
||||||
},
|
|
||||||
// Windows platform specific options
|
|
||||||
Windows: &windows.Options{
|
|
||||||
WebviewIsTransparent: false,
|
|
||||||
WindowIsTranslucent: false,
|
|
||||||
DisableWindowIcon: false,
|
|
||||||
// DisableFramelessWindowDecorations: false,
|
|
||||||
WebviewUserDataPath: "",
|
|
||||||
IsZoomControlEnabled: false,
|
|
||||||
ZoomFactor: float64,
|
|
||||||
},
|
|
||||||
Mac: &mac.Options{
|
|
||||||
TitleBar: &mac.TitleBar{
|
|
||||||
TitlebarAppearsTransparent: true,
|
|
||||||
HideTitle: false,
|
|
||||||
HideTitleBar: false,
|
|
||||||
FullSizeContent: false,
|
|
||||||
UseToolbar: false,
|
|
||||||
HideToolbarSeparator: true,
|
|
||||||
},
|
|
||||||
Appearance: mac.NSAppearanceNameDarkAqua,
|
|
||||||
WebviewIsTransparent: true,
|
|
||||||
WindowIsTranslucent: true,
|
|
||||||
About: &mac.AboutInfo{
|
|
||||||
Title: "Plain Template",
|
|
||||||
Message: "Part of the Wails projects",
|
|
||||||
Icon: icon,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed all:frontend/dist
|
|
||||||
var assets embed.FS
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Create an instance of the app structure
|
|
||||||
app := NewApp()
|
|
||||||
|
|
||||||
// Create application with options
|
|
||||||
err := wails.Run(&options.App{
|
|
||||||
Title: "{{.ProjectName}}",
|
|
||||||
Width: 1024,
|
|
||||||
Height: 768,
|
|
||||||
AssetServer: &assetserver.Options{
|
|
||||||
Assets: assets,
|
|
||||||
},
|
|
||||||
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
|
|
||||||
OnStartup: app.startup,
|
|
||||||
Bind: []interface{}{
|
|
||||||
app,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
println("Error:", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package show
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/github"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddSubcommand adds the `show` command for the Wails application
|
|
||||||
func AddSubcommand(app *clir.Cli, w io.Writer) {
|
|
||||||
showCommand := app.NewSubCommand("show", "Shows various information")
|
|
||||||
|
|
||||||
version := internal.Version
|
|
||||||
releaseNotes := showCommand.NewSubCommand("releasenotes", "Shows the release notes for the current version")
|
|
||||||
releaseNotes.StringFlag("version", "The version to show the release notes for", &version)
|
|
||||||
releaseNotes.Action(func() error {
|
|
||||||
app.PrintBanner()
|
|
||||||
releaseNotes := github.GetReleaseNotes(version)
|
|
||||||
_, _ = fmt.Fprintln(w, releaseNotes)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,172 +0,0 @@
|
|||||||
package update
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/labstack/gommon/color"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/shell"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/github"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddSubcommand adds the `init` command for the Wails application
|
|
||||||
func AddSubcommand(app *clir.Cli, w io.Writer, currentVersion string) error {
|
|
||||||
|
|
||||||
command := app.NewSubCommand("update", "Update the Wails CLI")
|
|
||||||
command.LongDescription(`This command allows you to update your version of the Wails CLI.`)
|
|
||||||
|
|
||||||
// Setup flags
|
|
||||||
var prereleaseRequired bool
|
|
||||||
command.BoolFlag("pre", "Update CLI to latest Prerelease", &prereleaseRequired)
|
|
||||||
|
|
||||||
var specificVersion string
|
|
||||||
command.StringFlag("version", "Install a specific version (Overrides other flags) of the CLI", &specificVersion)
|
|
||||||
|
|
||||||
command.Action(func() error {
|
|
||||||
|
|
||||||
// Create logger
|
|
||||||
logger := clilogger.New(w)
|
|
||||||
|
|
||||||
// Print banner
|
|
||||||
app.PrintBanner()
|
|
||||||
logger.Println("Checking for updates...")
|
|
||||||
|
|
||||||
var desiredVersion *github.SemanticVersion
|
|
||||||
var err error
|
|
||||||
var valid bool
|
|
||||||
|
|
||||||
if len(specificVersion) > 0 {
|
|
||||||
// Check if this is a valid version
|
|
||||||
valid, err = github.IsValidTag(specificVersion)
|
|
||||||
if err == nil {
|
|
||||||
if !valid {
|
|
||||||
err = fmt.Errorf("version '%s' is invalid", specificVersion)
|
|
||||||
} else {
|
|
||||||
desiredVersion, err = github.NewSemanticVersion(specificVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if prereleaseRequired {
|
|
||||||
desiredVersion, err = github.GetLatestPreRelease()
|
|
||||||
} else {
|
|
||||||
desiredVersion, err = github.GetLatestStableRelease()
|
|
||||||
if err != nil {
|
|
||||||
println("")
|
|
||||||
println("No stable release found for this major version. To update to the latest pre-release (eg beta), run:")
|
|
||||||
println(" wails update -pre")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
fmt.Println(" Current Version : " + currentVersion)
|
|
||||||
|
|
||||||
if len(specificVersion) > 0 {
|
|
||||||
fmt.Printf(" Desired Version : v%s\n", desiredVersion)
|
|
||||||
} else {
|
|
||||||
if prereleaseRequired {
|
|
||||||
fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion)
|
|
||||||
} else {
|
|
||||||
fmt.Printf(" Latest Release : v%s\n", desiredVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateToVersion(logger, desiredVersion, len(specificVersion) > 0, currentVersion)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.SemanticVersion, force bool, currentVersion string) error {
|
|
||||||
|
|
||||||
var targetVersionString = "v" + targetVersion.String()
|
|
||||||
|
|
||||||
// Early exit
|
|
||||||
if targetVersionString == currentVersion {
|
|
||||||
logger.Println("\nLooks like you're up to date!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var desiredVersion string
|
|
||||||
|
|
||||||
if !force {
|
|
||||||
|
|
||||||
compareVersion := currentVersion
|
|
||||||
|
|
||||||
currentVersion, err := github.NewSemanticVersion(compareVersion)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var success bool
|
|
||||||
|
|
||||||
// Release -> Pre-Release = Massage current version to prerelease format
|
|
||||||
if targetVersion.IsPreRelease() && currentVersion.IsRelease() {
|
|
||||||
testVersion, err := github.NewSemanticVersion(compareVersion + "-0")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
success, _ = targetVersion.IsGreaterThan(testVersion)
|
|
||||||
}
|
|
||||||
// Pre-Release -> Release = Massage target version to prerelease format
|
|
||||||
if targetVersion.IsRelease() && currentVersion.IsPreRelease() {
|
|
||||||
// We are ok with greater than or equal
|
|
||||||
mainversion := currentVersion.MainVersion()
|
|
||||||
targetVersion, err = github.NewSemanticVersion(targetVersion.String())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
success, _ = targetVersion.IsGreaterThanOrEqual(mainversion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release -> Release = Standard check
|
|
||||||
if (targetVersion.IsRelease() && currentVersion.IsRelease()) ||
|
|
||||||
(targetVersion.IsPreRelease() && currentVersion.IsPreRelease()) {
|
|
||||||
|
|
||||||
success, _ = targetVersion.IsGreaterThan(currentVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare
|
|
||||||
if !success {
|
|
||||||
logger.Println("Error: The requested version is lower than the current version.")
|
|
||||||
logger.Println("If this is what you really want to do, use `wails update -version %s`", targetVersionString)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
desiredVersion = "v" + targetVersion.String()
|
|
||||||
|
|
||||||
} else {
|
|
||||||
desiredVersion = "v" + targetVersion.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
logger.Print("Installing Wails CLI " + desiredVersion + "...")
|
|
||||||
|
|
||||||
// Run command in non module directory
|
|
||||||
homeDir, err := os.UserHomeDir()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Cannot find home directory! Please file a bug report!")
|
|
||||||
}
|
|
||||||
|
|
||||||
sout, serr, err := shell.RunCommand(homeDir, "go", "install", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("Failed.")
|
|
||||||
logger.Println(sout + `\n` + serr)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
logger.Println("Done.")
|
|
||||||
logger.Println(color.Green("\nMake sure you update your project go.mod file to use " + desiredVersion + ":"))
|
|
||||||
logger.Println(color.Green(" require github.com/wailsapp/wails/v2 " + desiredVersion))
|
|
||||||
logger.Println(color.Red("\nTo view the release notes, please run `wails show releasenotes`"))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
530
v2/cmd/wails/internal/dev/dev.go
Normal file
530
v2/cmd/wails/internal/dev/dev.go
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
package dev
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/flags"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/gomod"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal/logutils"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/bindings"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
|
||||||
|
|
||||||
|
"github.com/google/shlex"
|
||||||
|
|
||||||
|
"github.com/pkg/browser"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/process"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sliceToMap(input []string) map[string]struct{} {
|
||||||
|
result := map[string]struct{}{}
|
||||||
|
for _, value := range input {
|
||||||
|
result[value] = struct{}{}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
type devFlags struct {
|
||||||
|
ldflags string
|
||||||
|
compilerCommand string
|
||||||
|
assetDir string
|
||||||
|
extensions string
|
||||||
|
reloadDirs string
|
||||||
|
openBrowser bool
|
||||||
|
noReload bool
|
||||||
|
skipBindings bool
|
||||||
|
wailsjsdir string
|
||||||
|
tags string
|
||||||
|
verbosity int
|
||||||
|
loglevel string
|
||||||
|
forceBuild bool
|
||||||
|
debounceMS int
|
||||||
|
devServer string
|
||||||
|
appargs string
|
||||||
|
saveConfig bool
|
||||||
|
raceDetector bool
|
||||||
|
|
||||||
|
frontendDevServerURL string
|
||||||
|
skipFrontend bool
|
||||||
|
noColour bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Application runs the application in dev mode
|
||||||
|
func Application(f *flags.Dev, logger *clilogger.CLILogger) error {
|
||||||
|
|
||||||
|
cwd := lo.Must(os.Getwd())
|
||||||
|
|
||||||
|
// Update go.mod to use current wails version
|
||||||
|
err := gomod.SyncGoMod(logger, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run go mod tidy to ensure we're up-to-date
|
||||||
|
err = runCommand(cwd, false, "go", "mod", "tidy")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buildOptions := f.GenerateBuildOptions()
|
||||||
|
buildOptions.Logger = logger
|
||||||
|
|
||||||
|
userTags, err := buildtags.Parse(f.Tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buildOptions.UserTags = userTags
|
||||||
|
|
||||||
|
err = build.CreateEmbedDirectories(cwd, buildOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
projectConfig := f.ProjectConfig()
|
||||||
|
|
||||||
|
if !buildOptions.SkipBindings {
|
||||||
|
if f.Verbosity == build.VERBOSE {
|
||||||
|
logutils.LogGreen("Generating Bindings...")
|
||||||
|
}
|
||||||
|
stdout, err := bindings.GenerateBindings(bindings.Options{
|
||||||
|
Tags: buildOptions.UserTags,
|
||||||
|
TsPrefix: projectConfig.Bindings.TsGeneration.Prefix,
|
||||||
|
TsSuffix: projectConfig.Bindings.TsGeneration.Suffix,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if f.Verbosity == build.VERBOSE {
|
||||||
|
logutils.LogGreen(stdout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup signal handler
|
||||||
|
quitChannel := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||||
|
exitCodeChannel := make(chan int, 1)
|
||||||
|
|
||||||
|
// Build the frontend if requested, but ignore building the application itself.
|
||||||
|
ignoreFrontend := buildOptions.IgnoreFrontend
|
||||||
|
if !ignoreFrontend {
|
||||||
|
buildOptions.IgnoreApplication = true
|
||||||
|
if _, err := build.Build(buildOptions); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buildOptions.IgnoreApplication = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// frontend:dev:watcher command.
|
||||||
|
frontendDevAutoDiscovery := projectConfig.IsFrontendDevServerURLAutoDiscovery()
|
||||||
|
if command := projectConfig.DevWatcherCommand; command != "" {
|
||||||
|
closer, devServerURL, err := runFrontendDevWatcherCommand(projectConfig.GetFrontendDir(), command, frontendDevAutoDiscovery)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if devServerURL != "" {
|
||||||
|
projectConfig.FrontendDevServerURL = devServerURL
|
||||||
|
f.FrontendDevServerURL = devServerURL
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
} else if frontendDevAutoDiscovery {
|
||||||
|
return fmt.Errorf("unable to auto discover frontend:dev:serverUrl without a frontend:dev:watcher command, please either set frontend:dev:watcher or remove the auto discovery from frontend:dev:serverUrl")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do initial build but only for the application.
|
||||||
|
logger.Println("Building application for development...")
|
||||||
|
buildOptions.IgnoreFrontend = true
|
||||||
|
debugBinaryProcess, appBinary, err := restartApp(buildOptions, nil, f, exitCodeChannel)
|
||||||
|
buildOptions.IgnoreFrontend = ignoreFrontend || f.FrontendDevServerURL != ""
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := killProcessAndCleanupBinary(debugBinaryProcess, appBinary); err != nil {
|
||||||
|
logutils.LogDarkYellow("Unable to kill process and cleanup binary: %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// open browser
|
||||||
|
if f.Browser {
|
||||||
|
err = browser.OpenURL(f.DevServerURL().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the project files watcher
|
||||||
|
watcher, err := initialiseWatcher(cwd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(watcher *fsnotify.Watcher) {
|
||||||
|
err := watcher.Close()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
}(watcher)
|
||||||
|
|
||||||
|
logutils.LogGreen("Watching (sub)/directory: %s", cwd)
|
||||||
|
logutils.LogGreen("Using DevServer URL: %s", f.DevServerURL())
|
||||||
|
if f.FrontendDevServerURL != "" {
|
||||||
|
logutils.LogGreen("Using Frontend DevServer URL: %s", f.FrontendDevServerURL)
|
||||||
|
}
|
||||||
|
logutils.LogGreen("Using reload debounce setting of %d milliseconds", f.Debounce)
|
||||||
|
|
||||||
|
// Show dev server URL in terminal after 3 seconds
|
||||||
|
go func() {
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
logutils.LogGreen("\n\nTo develop in the browser and call your bound Go methods from Javascript, navigate to: %s", f.DevServerURL())
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Watch for changes and trigger restartApp()
|
||||||
|
debugBinaryProcess = doWatcherLoop(buildOptions, debugBinaryProcess, f, watcher, exitCodeChannel, quitChannel, f.DevServerURL())
|
||||||
|
|
||||||
|
// Kill the current program if running and remove dev binary
|
||||||
|
if err := killProcessAndCleanupBinary(debugBinaryProcess, appBinary); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the process and the binary so defer knows about it and is a nop.
|
||||||
|
debugBinaryProcess = nil
|
||||||
|
appBinary = ""
|
||||||
|
|
||||||
|
logutils.LogGreen("Development mode exited")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func killProcessAndCleanupBinary(process *process.Process, binary string) error {
|
||||||
|
if process != nil && process.Running {
|
||||||
|
if err := process.Kill(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if binary != "" {
|
||||||
|
err := os.Remove(binary)
|
||||||
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCommand(dir string, exitOnError bool, command string, args ...string) error {
|
||||||
|
logutils.LogGreen("Executing: " + command + " " + strings.Join(args, " "))
|
||||||
|
cmd := exec.Command(command, args...)
|
||||||
|
cmd.Dir = dir
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
println(string(output))
|
||||||
|
println(err.Error())
|
||||||
|
if exitOnError {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// runFrontendDevWatcherCommand will run the `frontend:dev:watcher` command if it was given, ex- `npm run dev`
|
||||||
|
func runFrontendDevWatcherCommand(frontendDirectory string, devCommand string, discoverViteServerURL bool) (func(), string, error) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
scanner := NewStdoutScanner()
|
||||||
|
cmdSlice := strings.Split(devCommand, " ")
|
||||||
|
cmd := exec.CommandContext(ctx, cmdSlice[0], cmdSlice[1:]...)
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdout = scanner
|
||||||
|
cmd.Dir = frontendDirectory
|
||||||
|
setParentGID(cmd)
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
cancel()
|
||||||
|
return nil, "", fmt.Errorf("unable to start frontend DevWatcher: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var viteServerURL string
|
||||||
|
if discoverViteServerURL {
|
||||||
|
select {
|
||||||
|
case serverURL := <-scanner.ViteServerURLChan:
|
||||||
|
viteServerURL = serverURL
|
||||||
|
case <-time.After(time.Second * 10):
|
||||||
|
cancel()
|
||||||
|
return nil, "", errors.New("failed to find Vite server URL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logutils.LogGreen("Running frontend DevWatcher command: '%s'", devCommand)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
const (
|
||||||
|
stateRunning int32 = 0
|
||||||
|
stateCanceling = 1
|
||||||
|
stateStopped = 2
|
||||||
|
)
|
||||||
|
state := stateRunning
|
||||||
|
go func() {
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
wasRunning := atomic.CompareAndSwapInt32(&state, stateRunning, stateStopped)
|
||||||
|
if err.Error() != "exit status 1" && wasRunning {
|
||||||
|
logutils.LogRed("Error from DevWatcher '%s': %s", devCommand, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
atomic.StoreInt32(&state, stateStopped)
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
if atomic.CompareAndSwapInt32(&state, stateRunning, stateCanceling) {
|
||||||
|
killProc(cmd, devCommand)
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
wg.Wait()
|
||||||
|
}, viteServerURL, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// restartApp does the actual rebuilding of the application when files change
|
||||||
|
func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process, f *flags.Dev, exitCodeChannel chan int) (*process.Process, string, error) {
|
||||||
|
|
||||||
|
appBinary, err := build.Build(buildOptions)
|
||||||
|
println()
|
||||||
|
if err != nil {
|
||||||
|
logutils.LogRed("Build error - " + err.Error())
|
||||||
|
|
||||||
|
msg := "Continuing to run current version"
|
||||||
|
if debugBinaryProcess == nil {
|
||||||
|
msg = "No version running, build will be retriggered as soon as changes have been detected"
|
||||||
|
}
|
||||||
|
logutils.LogDarkYellow(msg)
|
||||||
|
return nil, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill existing binary if need be
|
||||||
|
if debugBinaryProcess != nil {
|
||||||
|
killError := debugBinaryProcess.Kill()
|
||||||
|
|
||||||
|
if killError != nil {
|
||||||
|
buildOptions.Logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
||||||
|
}
|
||||||
|
|
||||||
|
debugBinaryProcess = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse appargs if any
|
||||||
|
args, err := shlex.Split(f.AppArgs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
buildOptions.Logger.Fatal("Unable to parse appargs: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set environment variables accordingly
|
||||||
|
os.Setenv("loglevel", f.LogLevel)
|
||||||
|
os.Setenv("assetdir", f.AssetDir)
|
||||||
|
os.Setenv("devserver", f.DevServer)
|
||||||
|
os.Setenv("frontenddevserverurl", f.FrontendDevServerURL)
|
||||||
|
|
||||||
|
// Start up new binary with correct args
|
||||||
|
newProcess := process.NewProcess(appBinary, args...)
|
||||||
|
err = newProcess.Start(exitCodeChannel)
|
||||||
|
if err != nil {
|
||||||
|
// Remove binary
|
||||||
|
if fs.FileExists(appBinary) {
|
||||||
|
deleteError := fs.DeleteFile(appBinary)
|
||||||
|
if deleteError != nil {
|
||||||
|
buildOptions.Logger.Fatal("Unable to delete app binary: " + appBinary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildOptions.Logger.Fatal("Unable to start application: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return newProcess, appBinary, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// doWatcherLoop is the main watch loop that runs while dev is active
|
||||||
|
func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Process, f *flags.Dev, watcher *fsnotify.Watcher, exitCodeChannel chan int, quitChannel chan os.Signal, devServerURL *url.URL) *process.Process {
|
||||||
|
// Main Loop
|
||||||
|
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(f.Extensions, ","))
|
||||||
|
var dirsThatTriggerAReload []string
|
||||||
|
for _, dir := range strings.Split(f.ReloadDirs, ",") {
|
||||||
|
if dir == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
thePath, err := filepath.Abs(dir)
|
||||||
|
if err != nil {
|
||||||
|
logutils.LogRed("Unable to expand reloadDir '%s': %s", dir, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dirsThatTriggerAReload = append(dirsThatTriggerAReload, thePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
quit := false
|
||||||
|
interval := time.Duration(f.Debounce) * time.Millisecond
|
||||||
|
timer := time.NewTimer(interval)
|
||||||
|
rebuild := false
|
||||||
|
reload := false
|
||||||
|
assetDir := ""
|
||||||
|
changedPaths := map[string]struct{}{}
|
||||||
|
|
||||||
|
// If we are using an external dev server, the reloading of the frontend part can be skipped or if the user requested it
|
||||||
|
skipAssetsReload := f.FrontendDevServerURL != "" || f.NoReload
|
||||||
|
|
||||||
|
assetDirURL := joinPath(devServerURL, "/wails/assetdir")
|
||||||
|
reloadURL := joinPath(devServerURL, "/wails/reload")
|
||||||
|
for quit == false {
|
||||||
|
// reload := false
|
||||||
|
select {
|
||||||
|
case exitCode := <-exitCodeChannel:
|
||||||
|
if exitCode == 0 {
|
||||||
|
quit = true
|
||||||
|
}
|
||||||
|
case err := <-watcher.Errors:
|
||||||
|
logutils.LogDarkYellow(err.Error())
|
||||||
|
case item := <-watcher.Events:
|
||||||
|
isEligibleFile := func(fileName string) bool {
|
||||||
|
// Iterate all file patterns
|
||||||
|
ext := filepath.Ext(fileName)
|
||||||
|
if ext != "" {
|
||||||
|
ext = ext[1:]
|
||||||
|
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle write operations
|
||||||
|
if item.Op&fsnotify.Write == fsnotify.Write {
|
||||||
|
// Ignore directories
|
||||||
|
itemName := item.Name
|
||||||
|
if fs.DirExists(itemName) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if isEligibleFile(itemName) {
|
||||||
|
rebuild = true
|
||||||
|
timer.Reset(interval)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, reloadDir := range dirsThatTriggerAReload {
|
||||||
|
if strings.HasPrefix(itemName, reloadDir) {
|
||||||
|
reload = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reload {
|
||||||
|
changedPaths[filepath.Dir(itemName)] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Reset(interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle new fs entries that are created
|
||||||
|
if item.Op&fsnotify.Create == fsnotify.Create {
|
||||||
|
// If this is a folder, add it to our watch list
|
||||||
|
if fs.DirExists(item.Name) {
|
||||||
|
// node_modules is BANNED!
|
||||||
|
if !strings.Contains(item.Name, "node_modules") {
|
||||||
|
err := watcher.Add(item.Name)
|
||||||
|
if err != nil {
|
||||||
|
buildOptions.Logger.Fatal("%s", err.Error())
|
||||||
|
}
|
||||||
|
logutils.LogGreen("Added new directory to watcher: %s", item.Name)
|
||||||
|
}
|
||||||
|
} else if isEligibleFile(item.Name) {
|
||||||
|
// Handle creation of new file.
|
||||||
|
// Note: On some platforms an update to a file is represented as
|
||||||
|
// REMOVE -> CREATE instead of WRITE, so this is not only new files
|
||||||
|
// but also updates to existing files
|
||||||
|
rebuild = true
|
||||||
|
timer.Reset(interval)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-timer.C:
|
||||||
|
if rebuild {
|
||||||
|
rebuild = false
|
||||||
|
logutils.LogGreen("[Rebuild triggered] files updated")
|
||||||
|
// Try and build the app
|
||||||
|
newBinaryProcess, _, err := restartApp(buildOptions, debugBinaryProcess, f, exitCodeChannel)
|
||||||
|
if err != nil {
|
||||||
|
logutils.LogRed("Error during build: %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// If we have a new process, saveConfig it
|
||||||
|
if newBinaryProcess != nil {
|
||||||
|
debugBinaryProcess = newBinaryProcess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !skipAssetsReload && len(changedPaths) != 0 {
|
||||||
|
if assetDir == "" {
|
||||||
|
resp, err := http.Get(assetDirURL)
|
||||||
|
if err != nil {
|
||||||
|
logutils.LogRed("Error during retrieving assetdir: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
content, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
logutils.LogRed("Error reading assetdir from devserver: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
assetDir = string(content)
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if assetDir != "" {
|
||||||
|
for thePath := range changedPaths {
|
||||||
|
if strings.HasPrefix(thePath, assetDir) {
|
||||||
|
reload = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if len(dirsThatTriggerAReload) == 0 {
|
||||||
|
logutils.LogRed("Reloading couldn't be triggered: Please specify -assetdir or -reloaddirs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reload {
|
||||||
|
reload = false
|
||||||
|
_, err := http.Get(reloadURL)
|
||||||
|
if err != nil {
|
||||||
|
logutils.LogRed("Error during refresh: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changedPaths = map[string]struct{}{}
|
||||||
|
case <-quitChannel:
|
||||||
|
logutils.LogGreen("\nCaught quit")
|
||||||
|
quit = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return debugBinaryProcess
|
||||||
|
}
|
||||||
|
|
||||||
|
func joinPath(url *url.URL, subPath string) string {
|
||||||
|
u := *url
|
||||||
|
u.Path = path.Join(u.Path, subPath)
|
||||||
|
return u.String()
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
package build
|
package gomod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
"github.com/wailsapp/wails/v2/internal/gomod"
|
"github.com/wailsapp/wails/v2/internal/gomod"
|
||||||
"github.com/wailsapp/wails/v2/internal/goversion"
|
"github.com/wailsapp/wails/v2/internal/goversion"
|
||||||
@ -57,3 +58,8 @@ func SyncGoMod(logger *clilogger.CLILogger, updateWailsVersion bool) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LogGreen(message string, args ...interface{}) {
|
||||||
|
text := fmt.Sprintf(message, args...)
|
||||||
|
println(colour.Green(text))
|
||||||
|
}
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
8
v2/cmd/wails/internal/template/template.go
Normal file
8
v2/cmd/wails/internal/template/template.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package template
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed base
|
||||||
|
var Base embed.FS
|
@ -2,83 +2,100 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pterm/pterm"
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/show"
|
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/colour"
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/update"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build"
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/dev"
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/doctor"
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate"
|
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func fatal(message string) {
|
|
||||||
println(message)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func banner(_ *clir.Cli) string {
|
func banner(_ *clir.Cli) string {
|
||||||
return fmt.Sprintf("%s %s",
|
return fmt.Sprintf("%s %s",
|
||||||
colour.Green("Wails CLI"),
|
colour.Green("Wails CLI"),
|
||||||
colour.DarkRed(internal.Version))
|
colour.DarkRed(internal.Version))
|
||||||
}
|
}
|
||||||
|
|
||||||
func printFooter() {
|
func fatal(message string) {
|
||||||
println(colour.Green("\nIf Wails is useful to you or your company, please consider sponsoring the project:\nhttps://github.com/sponsors/leaanthony\n"))
|
printer := pterm.PrefixPrinter{
|
||||||
|
MessageStyle: &pterm.ThemeDefault.FatalMessageStyle,
|
||||||
|
Prefix: pterm.Prefix{
|
||||||
|
Style: &pterm.ThemeDefault.FatalPrefixStyle,
|
||||||
|
Text: " FATAL ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
printer.Println(message)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printBulletPoint(text string, args ...any) {
|
||||||
|
item := pterm.BulletListItem{
|
||||||
|
Level: 2,
|
||||||
|
Text: text,
|
||||||
|
}
|
||||||
|
t, err := pterm.DefaultBulletList.WithItems([]pterm.BulletListItem{item}).Srender()
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
t = strings.Trim(t, "\n\r")
|
||||||
|
pterm.Printf(t, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printFooter() {
|
||||||
|
printer := pterm.PrefixPrinter{
|
||||||
|
MessageStyle: pterm.NewStyle(pterm.FgLightGreen),
|
||||||
|
Prefix: pterm.Prefix{
|
||||||
|
Style: pterm.NewStyle(pterm.FgRed, pterm.BgLightWhite),
|
||||||
|
Text: "♥ ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
printer.Println("If Wails is useful to you or your company, please consider sponsoring the project:")
|
||||||
|
pterm.Println("https://github.com/sponsors/leaanthony\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func bool2Str(b bool) string {
|
||||||
|
if b {
|
||||||
|
return "true"
|
||||||
|
}
|
||||||
|
return "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
var app *clir.Cli
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
app := clir.NewCli("Wails", "Go/HTML Appkit", internal.Version)
|
app = clir.NewCli("Wails", "Go/HTML Appkit", internal.Version)
|
||||||
|
|
||||||
app.SetBannerFunction(banner)
|
app.SetBannerFunction(banner)
|
||||||
defer printFooter()
|
defer printFooter()
|
||||||
|
|
||||||
build.AddBuildSubcommand(app, os.Stdout)
|
app.NewSubCommandFunction("build", "Builds the application", buildApplication)
|
||||||
err = initialise.AddSubcommand(app, os.Stdout)
|
app.NewSubCommandFunction("dev", "Runs the application in development mode", devApplication)
|
||||||
if err != nil {
|
app.NewSubCommandFunction("doctor", "Diagnose your environment", diagnoseEnvironment)
|
||||||
fatal(err.Error())
|
app.NewSubCommandFunction("init", "Initialises a new Wails project", initProject)
|
||||||
}
|
app.NewSubCommandFunction("update", "Update the Wails CLI", update)
|
||||||
|
|
||||||
err = doctor.AddSubcommand(app, os.Stdout)
|
show := app.NewSubCommand("show", "Shows various information")
|
||||||
if err != nil {
|
show.NewSubCommandFunction("releasenotes", "Shows the release notes for the current version", showReleaseNotes)
|
||||||
fatal(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
err = dev.AddSubcommand(app, os.Stdout)
|
generate := app.NewSubCommand("generate", "Code Generation Tools")
|
||||||
if err != nil {
|
generate.NewSubCommandFunction("module", "Generates a new Wails module", generateModule)
|
||||||
fatal(err.Error())
|
generate.NewSubCommandFunction("template", "Generates a new Wails template", generateTemplate)
|
||||||
}
|
|
||||||
|
|
||||||
err = generate.AddSubcommand(app, os.Stdout)
|
|
||||||
if err != nil {
|
|
||||||
fatal(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
show.AddSubcommand(app, os.Stdout)
|
|
||||||
|
|
||||||
err = update.AddSubcommand(app, os.Stdout, internal.Version)
|
|
||||||
if err != nil {
|
|
||||||
fatal(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
command := app.NewSubCommand("version", "The Wails CLI version")
|
command := app.NewSubCommand("version", "The Wails CLI version")
|
||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
println(internal.Version)
|
pterm.Println(internal.Version)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err = app.Run()
|
err = app.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("\n\nERROR: " + err.Error())
|
pterm.Println()
|
||||||
|
pterm.Error.Println(err.Error())
|
||||||
printFooter()
|
printFooter()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
27
v2/cmd/wails/show.go
Normal file
27
v2/cmd/wails/show.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pterm/pterm"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/flags"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
func showReleaseNotes(f *flags.ShowReleaseNotes) error {
|
||||||
|
if f.NoColour {
|
||||||
|
pterm.DisableColor()
|
||||||
|
colour.ColourEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
version := internal.Version
|
||||||
|
if f.Version != "" {
|
||||||
|
version = f.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
app.PrintBanner()
|
||||||
|
releaseNotes := github.GetReleaseNotes(version, f.NoColour)
|
||||||
|
pterm.Println(releaseNotes)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
156
v2/cmd/wails/update.go
Normal file
156
v2/cmd/wails/update.go
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/labstack/gommon/color"
|
||||||
|
"github.com/pterm/pterm"
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/flags"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/colour"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/shell"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddSubcommand adds the `init` command for the Wails application
|
||||||
|
func update(f *flags.Update) error {
|
||||||
|
|
||||||
|
if f.NoColour {
|
||||||
|
colour.ColourEnabled = false
|
||||||
|
pterm.DisableColor()
|
||||||
|
|
||||||
|
}
|
||||||
|
// Print banner
|
||||||
|
app.PrintBanner()
|
||||||
|
pterm.Println("Checking for updates...")
|
||||||
|
|
||||||
|
var desiredVersion *github.SemanticVersion
|
||||||
|
var err error
|
||||||
|
var valid bool
|
||||||
|
|
||||||
|
if len(f.Version) > 0 {
|
||||||
|
// Check if this is a valid version
|
||||||
|
valid, err = github.IsValidTag(f.Version)
|
||||||
|
if err == nil {
|
||||||
|
if !valid {
|
||||||
|
err = fmt.Errorf("version '%s' is invalid", f.Version)
|
||||||
|
} else {
|
||||||
|
desiredVersion, err = github.NewSemanticVersion(f.Version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if f.PreRelease {
|
||||||
|
desiredVersion, err = github.GetLatestPreRelease()
|
||||||
|
} else {
|
||||||
|
desiredVersion, err = github.GetLatestStableRelease()
|
||||||
|
if err != nil {
|
||||||
|
pterm.Println("")
|
||||||
|
pterm.Println("No stable release found for this major version. To update to the latest pre-release (eg beta), run:")
|
||||||
|
pterm.Println(" wails update -pre")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pterm.Println()
|
||||||
|
|
||||||
|
pterm.Println(" Current Version : " + app.Version())
|
||||||
|
|
||||||
|
if len(f.Version) > 0 {
|
||||||
|
fmt.Printf(" Desired Version : v%s\n", desiredVersion)
|
||||||
|
} else {
|
||||||
|
if f.PreRelease {
|
||||||
|
fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" Latest Release : v%s\n", desiredVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateToVersion(desiredVersion, len(f.Version) > 0, app.Version())
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateToVersion(targetVersion *github.SemanticVersion, force bool, currentVersion string) error {
|
||||||
|
|
||||||
|
var targetVersionString = "v" + targetVersion.String()
|
||||||
|
|
||||||
|
if targetVersionString == currentVersion {
|
||||||
|
pterm.Println("\nLooks like you're up to date!\n")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var desiredVersion string
|
||||||
|
|
||||||
|
if !force {
|
||||||
|
|
||||||
|
compareVersion := currentVersion
|
||||||
|
|
||||||
|
currentVersion, err := github.NewSemanticVersion(compareVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var success bool
|
||||||
|
|
||||||
|
// Release -> Pre-Release = Massage current version to prerelease format
|
||||||
|
if targetVersion.IsPreRelease() && currentVersion.IsRelease() {
|
||||||
|
testVersion, err := github.NewSemanticVersion(compareVersion + "-0")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
success, _ = targetVersion.IsGreaterThan(testVersion)
|
||||||
|
}
|
||||||
|
// Pre-Release -> Release = Massage target version to prerelease format
|
||||||
|
if targetVersion.IsRelease() && currentVersion.IsPreRelease() {
|
||||||
|
// We are ok with greater than or equal
|
||||||
|
mainversion := currentVersion.MainVersion()
|
||||||
|
targetVersion, err = github.NewSemanticVersion(targetVersion.String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
success, _ = targetVersion.IsGreaterThanOrEqual(mainversion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release -> Release = Standard check
|
||||||
|
if (targetVersion.IsRelease() && currentVersion.IsRelease()) ||
|
||||||
|
(targetVersion.IsPreRelease() && currentVersion.IsPreRelease()) {
|
||||||
|
|
||||||
|
success, _ = targetVersion.IsGreaterThan(currentVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare
|
||||||
|
if !success {
|
||||||
|
pterm.Println("Error: The requested version is lower than the current version.")
|
||||||
|
pterm.Println("If this is what you really want to do, use `wails update -version %s`", targetVersionString)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
desiredVersion = "v" + targetVersion.String()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
desiredVersion = "v" + targetVersion.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
pterm.Println()
|
||||||
|
pterm.Print("Installing Wails CLI " + desiredVersion + "...")
|
||||||
|
|
||||||
|
// Run command in non module directory
|
||||||
|
homeDir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
fatal("Cannot find home directory! Please file a bug report!")
|
||||||
|
}
|
||||||
|
|
||||||
|
sout, serr, err := shell.RunCommand(homeDir, "go", "install", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion)
|
||||||
|
if err != nil {
|
||||||
|
pterm.Println("Failed.")
|
||||||
|
pterm.Error.Println(sout + `\n` + serr)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pterm.Println("Done.")
|
||||||
|
pterm.Println(color.Green("\nMake sure you update your project go.mod file to use " + desiredVersion + ":"))
|
||||||
|
pterm.Println(color.Green(" require github.com/wailsapp/wails/v2 " + desiredVersion))
|
||||||
|
pterm.Println(color.Red("\nTo view the release notes, please run `wails show releasenotes`"))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
16
v2/go.mod
16
v2/go.mod
@ -14,14 +14,13 @@ require (
|
|||||||
github.com/jackmordaunt/icns v1.0.0
|
github.com/jackmordaunt/icns v1.0.0
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e
|
||||||
github.com/labstack/echo/v4 v4.9.0
|
github.com/labstack/echo/v4 v4.9.0
|
||||||
github.com/leaanthony/clir v1.0.4
|
github.com/leaanthony/clir v1.3.0
|
||||||
github.com/leaanthony/debme v1.2.1
|
github.com/leaanthony/debme v1.2.1
|
||||||
github.com/leaanthony/go-ansi-parser v1.0.1
|
github.com/leaanthony/go-ansi-parser v1.0.1
|
||||||
github.com/leaanthony/gosod v1.0.3
|
github.com/leaanthony/gosod v1.0.3
|
||||||
github.com/leaanthony/slicer v1.5.0
|
github.com/leaanthony/slicer v1.5.0
|
||||||
github.com/leaanthony/winicon v1.0.0
|
github.com/leaanthony/winicon v1.0.0
|
||||||
github.com/matryer/is v1.4.0
|
github.com/matryer/is v1.4.0
|
||||||
github.com/olekukonko/tablewriter v0.0.5
|
|
||||||
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2
|
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/tc-hib/winres v0.1.5
|
github.com/tc-hib/winres v0.1.5
|
||||||
@ -41,25 +40,31 @@ require (
|
|||||||
github.com/charmbracelet/glamour v0.5.0
|
github.com/charmbracelet/glamour v0.5.0
|
||||||
github.com/go-ole/go-ole v1.2.6
|
github.com/go-ole/go-ole v1.2.6
|
||||||
github.com/labstack/gommon v0.3.1
|
github.com/labstack/gommon v0.3.1
|
||||||
|
github.com/pterm/pterm v0.12.49
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
|
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
|
||||||
github.com/samber/lo v1.27.1
|
github.com/samber/lo v1.27.1
|
||||||
github.com/stretchr/testify v1.7.1
|
github.com/stretchr/testify v1.8.0
|
||||||
golang.org/x/tools v0.1.12
|
golang.org/x/tools v0.1.12
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
atomicgo.dev/cursor v0.1.1 // indirect
|
||||||
|
atomicgo.dev/keyboard v0.2.8 // indirect
|
||||||
bitbucket.org/creachadair/shell v0.0.7 // indirect
|
bitbucket.org/creachadair/shell v0.0.7 // indirect
|
||||||
github.com/Microsoft/go-winio v0.4.16 // indirect
|
github.com/Microsoft/go-winio v0.4.16 // indirect
|
||||||
github.com/alecthomas/chroma v0.10.0 // indirect
|
github.com/alecthomas/chroma v0.10.0 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
|
github.com/containerd/console v1.0.3 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||||
github.com/emirpasic/gods v1.12.0 // indirect
|
github.com/emirpasic/gods v1.12.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.0 // indirect
|
github.com/go-git/gcfg v1.5.0 // indirect
|
||||||
|
github.com/gookit/color v1.5.2 // indirect
|
||||||
github.com/gorilla/css v1.0.0 // indirect
|
github.com/gorilla/css v1.0.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||||
github.com/kr/pretty v0.3.0 // indirect
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
|
github.com/lithammer/fuzzysearch v1.1.5 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
@ -69,9 +74,10 @@ require (
|
|||||||
github.com/muesli/reflow v0.3.0 // indirect
|
github.com/muesli/reflow v0.3.0 // indirect
|
||||||
github.com/muesli/termenv v0.9.0 // indirect
|
github.com/muesli/termenv v0.9.0 // indirect
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/sergi/go-diff v1.1.0 // indirect
|
github.com/sergi/go-diff v1.2.0 // indirect
|
||||||
github.com/tidwall/gjson v1.8.0 // indirect
|
github.com/tidwall/gjson v1.8.0 // indirect
|
||||||
github.com/tidwall/match v1.0.3 // indirect
|
github.com/tidwall/match v1.0.3 // indirect
|
||||||
github.com/tidwall/pretty v1.1.0 // indirect
|
github.com/tidwall/pretty v1.1.0 // indirect
|
||||||
@ -79,11 +85,13 @@ require (
|
|||||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae // indirect
|
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||||
github.com/yuin/goldmark v1.4.13 // indirect
|
github.com/yuin/goldmark v1.4.13 // indirect
|
||||||
github.com/yuin/goldmark-emoji v1.0.1 // indirect
|
github.com/yuin/goldmark-emoji v1.0.1 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
||||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect
|
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
54
v2/go.sum
54
v2/go.sum
@ -1,5 +1,17 @@
|
|||||||
|
atomicgo.dev/cursor v0.1.1 h1:0t9sxQomCTRh5ug+hAMCs59x/UmC9QL6Ci5uosINKD4=
|
||||||
|
atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU=
|
||||||
|
atomicgo.dev/keyboard v0.2.8 h1:Di09BitwZgdTV1hPyX/b9Cqxi8HVuJQwWivnZUEqlj4=
|
||||||
|
atomicgo.dev/keyboard v0.2.8/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ=
|
||||||
bitbucket.org/creachadair/shell v0.0.7 h1:Z96pB6DkSb7F3Y3BBnJeOZH2gazyMTWlvecSD4vDqfk=
|
bitbucket.org/creachadair/shell v0.0.7 h1:Z96pB6DkSb7F3Y3BBnJeOZH2gazyMTWlvecSD4vDqfk=
|
||||||
bitbucket.org/creachadair/shell v0.0.7/go.mod h1:oqtXSSvSYr4624lnnabXHaBsYW6RD80caLi2b3hJk0U=
|
bitbucket.org/creachadair/shell v0.0.7/go.mod h1:oqtXSSvSYr4624lnnabXHaBsYW6RD80caLi2b3hJk0U=
|
||||||
|
github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
|
||||||
|
github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
|
||||||
|
github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
|
||||||
|
github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k=
|
||||||
|
github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI=
|
||||||
|
github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c=
|
||||||
|
github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
|
||||||
|
github.com/MarvinJWendt/testza v0.4.3 h1:u2XaM4IqGp9dsdUmML8/Z791fu4yjQYzOiufOtJwTII=
|
||||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
@ -15,6 +27,7 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo
|
|||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
|
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
|
||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||||
@ -23,6 +36,8 @@ github.com/bitfield/script v0.19.0 h1:W24f+FQuPab9gXcW8bhcbo5qO8AtrXyu3XOnR4zhHN
|
|||||||
github.com/bitfield/script v0.19.0/go.mod h1:ana6F8YOSZ3ImT8SauIzuYSqXgFVkSUJ6kgja+WMmIY=
|
github.com/bitfield/script v0.19.0/go.mod h1:ana6F8YOSZ3ImT8SauIzuYSqXgFVkSUJ6kgja+WMmIY=
|
||||||
github.com/charmbracelet/glamour v0.5.0 h1:wu15ykPdB7X6chxugG/NNfDUbyyrCLV9XBalj5wdu3g=
|
github.com/charmbracelet/glamour v0.5.0 h1:wu15ykPdB7X6chxugG/NNfDUbyyrCLV9XBalj5wdu3g=
|
||||||
github.com/charmbracelet/glamour v0.5.0/go.mod h1:9ZRtG19AUIzcTm7FGLGbq3D5WKQ5UyZBbQsMQN0XIqc=
|
github.com/charmbracelet/glamour v0.5.0/go.mod h1:9ZRtG19AUIzcTm7FGLGbq3D5WKQ5UyZBbQsMQN0XIqc=
|
||||||
|
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||||
|
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
@ -58,6 +73,10 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU
|
|||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
||||||
|
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
|
||||||
|
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
|
||||||
|
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
|
||||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
@ -71,6 +90,10 @@ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEE
|
|||||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
@ -84,8 +107,9 @@ github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITV
|
|||||||
github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
|
github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
|
||||||
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
||||||
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||||
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
|
|
||||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||||
|
github.com/leaanthony/clir v1.3.0 h1:L9nPDWrmc/qU9UWZZvRaFajWYuO0np9V5p+5gxyYno0=
|
||||||
|
github.com/leaanthony/clir v1.3.0/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||||
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
||||||
@ -96,6 +120,8 @@ github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0H
|
|||||||
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||||
github.com/leaanthony/winicon v1.0.0 h1:ZNt5U5dY71oEoKZ97UVwJRT4e+5xo5o/ieKuHuk8NqQ=
|
github.com/leaanthony/winicon v1.0.0 h1:ZNt5U5dY71oEoKZ97UVwJRT4e+5xo5o/ieKuHuk8NqQ=
|
||||||
github.com/leaanthony/winicon v1.0.0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU=
|
github.com/leaanthony/winicon v1.0.0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU=
|
||||||
|
github.com/lithammer/fuzzysearch v1.1.5 h1:Ag7aKU08wp0R9QCfF4GoGST9HbmAIeLP7xwMrOBEp1c=
|
||||||
|
github.com/lithammer/fuzzysearch v1.1.5/go.mod h1:1R1LRNk7yKid1BaQkmuLQaHruxcC4HmAH30Dh61Ih1Q=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
@ -129,6 +155,15 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
|
||||||
|
github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg=
|
||||||
|
github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE=
|
||||||
|
github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU=
|
||||||
|
github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
|
||||||
|
github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
|
||||||
|
github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
|
||||||
|
github.com/pterm/pterm v0.12.49 h1:qeNm0wTWawy6WhKoY8ZKq6qTXFr0s2UtUyRW0yVztEg=
|
||||||
|
github.com/pterm/pterm v0.12.49/go.mod h1:D4OBoWNqAfXkm5QLTjIgjNiMXPHemLJHnIreGUsWzWg=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
@ -138,17 +173,20 @@ github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDj
|
|||||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
||||||
github.com/samber/lo v1.27.1 h1:sTXwkRiIFIQG+G0HeAvOEnGjqWeWtI9cg5/n51KrxPg=
|
github.com/samber/lo v1.27.1 h1:sTXwkRiIFIQG+G0HeAvOEnGjqWeWtI9cg5/n51KrxPg=
|
||||||
github.com/samber/lo v1.27.1/go.mod h1:it33p9UtPMS7z72fP4gw/EIfQB2eI8ke7GR2wc6+Rhg=
|
github.com/samber/lo v1.27.1/go.mod h1:it33p9UtPMS7z72fP4gw/EIfQB2eI8ke7GR2wc6+Rhg=
|
||||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
|
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||||
|
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/tc-hib/winres v0.1.5 h1:2dA5yfjdoEA3UyRaOC92HNMt3jap66pLzoW4MjpC/0M=
|
github.com/tc-hib/winres v0.1.5 h1:2dA5yfjdoEA3UyRaOC92HNMt3jap66pLzoW4MjpC/0M=
|
||||||
github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A=
|
github.com/tc-hib/winres v0.1.5/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A=
|
||||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||||
@ -174,6 +212,8 @@ github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae h1:tpXvBXC3hpQBDC
|
|||||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
||||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||||
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||||
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
|
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
|
||||||
@ -206,17 +246,25 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
@ -341,7 +341,7 @@ func (f *Frontend) WindowSetBackgroundColour(col *options.RGBA) {
|
|||||||
B: col.B,
|
B: col.B,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Webview2 only has 0 and 255 as valid values.
|
// WebView2 only has 0 and 255 as valid values.
|
||||||
if backgroundCol.A > 0 && backgroundCol.A < 255 {
|
if backgroundCol.A > 0 && backgroundCol.A < 255 {
|
||||||
backgroundCol.A = 255
|
backgroundCol.A = 255
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ func GetAvailableCoreWebView2BrowserVersionString(path string) (string, error) {
|
|||||||
// feature-complete and remove the use of the native DLL and go-winloader.
|
// feature-complete and remove the use of the native DLL and go-winloader.
|
||||||
version, err := goGetAvailableCoreWebView2BrowserVersionString(path)
|
version, err := goGetAvailableCoreWebView2BrowserVersionString(path)
|
||||||
if errors.Is(err, errNoClientDLLFound) {
|
if errors.Is(err, errNoClientDLLFound) {
|
||||||
// Webview2 is not found
|
// WebView2 is not found
|
||||||
return "", nil
|
return "", nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -105,7 +105,7 @@ func GetAvailableCoreWebView2BrowserVersionString(path string) (string, error) {
|
|||||||
|
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
if res == E_FILENOTFOUND {
|
if res == E_FILENOTFOUND {
|
||||||
// Webview2 is not installed
|
// WebView2 is not installed
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func GetAvailableCoreWebView2BrowserVersionString(browserExecutableFolder string
|
|||||||
if browserExecutableFolder != "" {
|
if browserExecutableFolder != "" {
|
||||||
clientPath, err := findEmbeddedClientDll(browserExecutableFolder)
|
clientPath, err := findEmbeddedClientDll(browserExecutableFolder)
|
||||||
if errors.Is(err, errNoClientDLLFound) {
|
if errors.Is(err, errNoClientDLLFound) {
|
||||||
// Webview2 is not found
|
// WebView2 is not found
|
||||||
return "", nil
|
return "", nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetReleaseNotes(tagVersion string) string {
|
func GetReleaseNotes(tagVersion string, noColour bool) string {
|
||||||
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/releases/tags/" + url.PathEscape(tagVersion))
|
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/releases/tags/" + url.PathEscape(tagVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "Unable to retrieve release notes. Please check your network connection"
|
return "Unable to retrieve release notes. Please check your network connection"
|
||||||
@ -34,11 +34,16 @@ func GetReleaseNotes(tagVersion string) string {
|
|||||||
|
|
||||||
result := "# Release Notes for " + tagVersion + "\n" + data["body"].(string)
|
result := "# Release Notes for " + tagVersion + "\n" + data["body"].(string)
|
||||||
var renderer *glamour.TermRenderer
|
var renderer *glamour.TermRenderer
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
renderer, err = glamour.NewTermRenderer(glamour.WithStyles(glamour.NoTTYStyleConfig))
|
var termRendererOpts []glamour.TermRendererOption
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" || noColour {
|
||||||
|
termRendererOpts = append(termRendererOpts, glamour.WithStyles(glamour.NoTTYStyleConfig))
|
||||||
} else {
|
} else {
|
||||||
renderer, err = glamour.NewTermRenderer(glamour.WithAutoStyle())
|
termRendererOpts = append(termRendererOpts, glamour.WithAutoStyle())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderer, err = glamour.NewTermRenderer(termRendererOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MinimumRuntimeVersion string = "94.0.992.31" // Webview2 SDK 1.0.992.28
|
const MinimumRuntimeVersion string = "94.0.992.31" // WebView2 SDK 1.0.992.28
|
||||||
|
|
||||||
type installationStatus int
|
type installationStatus int
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package build
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pterm/pterm"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -283,7 +284,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
cmd := exec.Command(compiler, commands.AsSlice()...)
|
cmd := exec.Command(compiler, commands.AsSlice()...)
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
if verbose {
|
if verbose {
|
||||||
println(" Build command:", compiler, commandPrettifier(commands.AsSlice()))
|
pterm.Info.Println("Build command:", compiler, commandPrettifier(commands.AsSlice()))
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
}
|
}
|
||||||
// Set the directory
|
// Set the directory
|
||||||
@ -359,7 +360,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
println(" Environment:", strings.Join(cmd.Env, " "))
|
printBulletPoint("Environment:", strings.Join(cmd.Env, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run command
|
// Run command
|
||||||
@ -373,7 +374,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
stdErr := string(output)
|
stdErr := string(output)
|
||||||
if strings.Contains(err.Error(), "ld: framework not found UniformTypeIdentifiers") ||
|
if strings.Contains(err.Error(), "ld: framework not found UniformTypeIdentifiers") ||
|
||||||
strings.Contains(stdErr, "ld: framework not found UniformTypeIdentifiers") {
|
strings.Contains(stdErr, "ld: framework not found UniformTypeIdentifiers") {
|
||||||
println(`
|
pterm.Warning.Println(`
|
||||||
NOTE: It would appear that you do not have the latest Xcode cli tools installed.
|
NOTE: It would appear that you do not have the latest Xcode cli tools installed.
|
||||||
Please reinstall by doing the following:
|
Please reinstall by doing the following:
|
||||||
1. Remove the current installation located at "xcode-select -p", EG: sudo rm -rf /Library/Developer/CommandLineTools
|
1. Remove the current installation located at "xcode-select -p", EG: sudo rm -rf /Library/Developer/CommandLineTools
|
||||||
@ -388,11 +389,11 @@ Please reinstall by doing the following:
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Compressing application: ")
|
printBulletPoint("Compressing application: ")
|
||||||
|
|
||||||
// Do we have upx installed?
|
// Do we have upx installed?
|
||||||
if !shell.CommandExists("upx") {
|
if !shell.CommandExists("upx") {
|
||||||
println("Warning: Cannot compress binary: upx not found")
|
pterm.Warning.Println("Warning: Cannot compress binary: upx not found")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,16 +405,16 @@ Please reinstall by doing the following:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
println("upx", strings.Join(args, " "))
|
pterm.Info.Println("upx", strings.Join(args, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := exec.Command("upx", args...).Output()
|
output, err := exec.Command("upx", args...).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Error during compression:")
|
return errors.Wrap(err, "Error during compression:")
|
||||||
}
|
}
|
||||||
println("Done.")
|
pterm.Println("Done.")
|
||||||
if verbose {
|
if verbose {
|
||||||
println(string(output))
|
pterm.Info.Println(string(output))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -488,7 +489,7 @@ func (b *BaseBuilder) NpmInstallUsingCommand(sourceDir string, installCommand st
|
|||||||
// Shortcut installation
|
// Shortcut installation
|
||||||
if install == false {
|
if install == false {
|
||||||
if verbose {
|
if verbose {
|
||||||
println("Skipping npm install")
|
pterm.Println("Skipping npm install")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -498,10 +499,10 @@ func (b *BaseBuilder) NpmInstallUsingCommand(sourceDir string, installCommand st
|
|||||||
stdout, stderr, err := shell.RunCommand(sourceDir, cmd[0], cmd[1:]...)
|
stdout, stderr, err := shell.RunCommand(sourceDir, cmd[0], cmd[1:]...)
|
||||||
if verbose || err != nil {
|
if verbose || err != nil {
|
||||||
for _, l := range strings.Split(stdout, "\n") {
|
for _, l := range strings.Split(stdout, "\n") {
|
||||||
fmt.Printf(" %s\n", l)
|
pterm.Printf(" %s\n", l)
|
||||||
}
|
}
|
||||||
for _, l := range strings.Split(stderr, "\n") {
|
for _, l := range strings.Split(stderr, "\n") {
|
||||||
fmt.Printf(" %s\n", l)
|
pterm.Printf(" %s\n", l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,10 +514,10 @@ func (b *BaseBuilder) NpmRun(projectDir, buildTarget string, verbose bool) error
|
|||||||
stdout, stderr, err := shell.RunCommand(projectDir, "npm", "run", buildTarget)
|
stdout, stderr, err := shell.RunCommand(projectDir, "npm", "run", buildTarget)
|
||||||
if verbose || err != nil {
|
if verbose || err != nil {
|
||||||
for _, l := range strings.Split(stdout, "\n") {
|
for _, l := range strings.Split(stdout, "\n") {
|
||||||
fmt.Printf(" %s\n", l)
|
pterm.Printf(" %s\n", l)
|
||||||
}
|
}
|
||||||
for _, l := range strings.Split(stderr, "\n") {
|
for _, l := range strings.Split(stderr, "\n") {
|
||||||
fmt.Printf(" %s\n", l)
|
pterm.Printf(" %s\n", l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@ -532,10 +533,10 @@ func (b *BaseBuilder) NpmRunWithEnvironment(projectDir, buildTarget string, verb
|
|||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if verbose || err != nil {
|
if verbose || err != nil {
|
||||||
for _, l := range strings.Split(stdo.String(), "\n") {
|
for _, l := range strings.Split(stdo.String(), "\n") {
|
||||||
fmt.Printf(" %s\n", l)
|
pterm.Printf(" %s\n", l)
|
||||||
}
|
}
|
||||||
for _, l := range strings.Split(stde.String(), "\n") {
|
for _, l := range strings.Split(stde.String(), "\n") {
|
||||||
fmt.Printf(" %s\n", l)
|
pterm.Printf(" %s\n", l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@ -558,13 +559,13 @@ func (b *BaseBuilder) BuildFrontend(outputLogger *clilogger.CLILogger) error {
|
|||||||
}
|
}
|
||||||
if installCommand == "" {
|
if installCommand == "" {
|
||||||
// No - don't install
|
// No - don't install
|
||||||
outputLogger.Println(" - No Install command. Skipping.")
|
printBulletPoint("No Install command. Skipping.")
|
||||||
} else {
|
} else {
|
||||||
// Do install if needed
|
// Do install if needed
|
||||||
outputLogger.Print(" - Installing frontend dependencies: ")
|
printBulletPoint("Installing frontend dependencies: ")
|
||||||
if verbose {
|
if verbose {
|
||||||
outputLogger.Println("")
|
pterm.Println("")
|
||||||
outputLogger.Println(" Install command: '" + installCommand + "'")
|
pterm.Info.Println("Install command: '" + installCommand + "'")
|
||||||
}
|
}
|
||||||
if err := b.NpmInstallUsingCommand(frontendDir, installCommand, verbose); err != nil {
|
if err := b.NpmInstallUsingCommand(frontendDir, installCommand, verbose); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -578,31 +579,31 @@ func (b *BaseBuilder) BuildFrontend(outputLogger *clilogger.CLILogger) error {
|
|||||||
buildCommand = b.projectData.GetDevBuildCommand()
|
buildCommand = b.projectData.GetDevBuildCommand()
|
||||||
}
|
}
|
||||||
if buildCommand == "" {
|
if buildCommand == "" {
|
||||||
outputLogger.Println(" - No Build command. Skipping.")
|
printBulletPoint("No Build command. Skipping.")
|
||||||
// No - ignore
|
// No - ignore
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
outputLogger.Print(" - Compiling frontend: ")
|
printBulletPoint("Compiling frontend: ")
|
||||||
cmd := strings.Split(buildCommand, " ")
|
cmd := strings.Split(buildCommand, " ")
|
||||||
if verbose {
|
if verbose {
|
||||||
outputLogger.Println("")
|
pterm.Println("")
|
||||||
outputLogger.Println(" Build command: '" + buildCommand + "'")
|
pterm.Info.Println("Build command: '" + buildCommand + "'")
|
||||||
}
|
}
|
||||||
stdout, stderr, err := shell.RunCommand(frontendDir, cmd[0], cmd[1:]...)
|
stdout, stderr, err := shell.RunCommand(frontendDir, cmd[0], cmd[1:]...)
|
||||||
if verbose || err != nil {
|
if verbose || err != nil {
|
||||||
for _, l := range strings.Split(stdout, "\n") {
|
for _, l := range strings.Split(stdout, "\n") {
|
||||||
fmt.Printf(" %s\n", l)
|
pterm.Printf(" %s\n", l)
|
||||||
}
|
}
|
||||||
for _, l := range strings.Split(stderr, "\n") {
|
for _, l := range strings.Split(stderr, "\n") {
|
||||||
fmt.Printf(" %s\n", l)
|
pterm.Printf(" %s\n", l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
outputLogger.Println("Done.")
|
pterm.Println("Done.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,14 +2,13 @@ package build
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"github.com/pterm/pterm"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"github.com/wailsapp/wails/v2/internal/colour"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/staticanalysis"
|
"github.com/wailsapp/wails/v2/internal/staticanalysis"
|
||||||
"github.com/wailsapp/wails/v2/pkg/commands/bindings"
|
"github.com/wailsapp/wails/v2/pkg/commands/bindings"
|
||||||
|
|
||||||
@ -185,14 +184,39 @@ func CreateEmbedDirectories(cwd string, buildOptions *Options) error {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fatal(message string) {
|
||||||
|
printer := pterm.PrefixPrinter{
|
||||||
|
MessageStyle: &pterm.ThemeDefault.FatalMessageStyle,
|
||||||
|
Prefix: pterm.Prefix{
|
||||||
|
Style: &pterm.ThemeDefault.FatalPrefixStyle,
|
||||||
|
Text: " FATAL ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
printer.Println(message)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printBulletPoint(text string, args ...any) {
|
||||||
|
item := pterm.BulletListItem{
|
||||||
|
Level: 2,
|
||||||
|
Text: text,
|
||||||
|
}
|
||||||
|
t, err := pterm.DefaultBulletList.WithItems([]pterm.BulletListItem{item}).Srender()
|
||||||
|
if err != nil {
|
||||||
|
fatal(err.Error())
|
||||||
|
}
|
||||||
|
t = strings.Trim(t, "\n\r")
|
||||||
|
pterm.Printf(t, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateBindings(buildOptions *Options) error {
|
func GenerateBindings(buildOptions *Options) error {
|
||||||
|
|
||||||
obfuscated := buildOptions.Obfuscated
|
obfuscated := buildOptions.Obfuscated
|
||||||
if obfuscated {
|
if obfuscated {
|
||||||
buildOptions.Logger.Print(" - Generating obfuscated bindings: ")
|
printBulletPoint("Generating obfuscated bindings: ")
|
||||||
buildOptions.UserTags = append(buildOptions.UserTags, "obfuscated")
|
buildOptions.UserTags = append(buildOptions.UserTags, "obfuscated")
|
||||||
} else {
|
} else {
|
||||||
buildOptions.Logger.Print(" - Generating bindings: ")
|
printBulletPoint("Generating bindings: ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate Bindings
|
// Generate Bindings
|
||||||
@ -207,39 +231,36 @@ func GenerateBindings(buildOptions *Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if buildOptions.Verbosity == VERBOSE {
|
if buildOptions.Verbosity == VERBOSE {
|
||||||
buildOptions.Logger.Println(output)
|
pterm.Info.Println(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildOptions.Logger.Println("Done.")
|
pterm.Println("Done.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func execBuildApplication(builder Builder, options *Options) (string, error) {
|
func execBuildApplication(builder Builder, options *Options) (string, error) {
|
||||||
// Extract logger
|
|
||||||
outputLogger := options.Logger
|
|
||||||
|
|
||||||
// If we are building for windows, we will need to generate the asset bundle before
|
// If we are building for windows, we will need to generate the asset bundle before
|
||||||
// compilation. This will be a .syso file in the project root
|
// compilation. This will be a .syso file in the project root
|
||||||
if options.Pack && options.Platform == "windows" {
|
if options.Pack && options.Platform == "windows" {
|
||||||
outputLogger.Print(" - Generating bundle assets: ")
|
printBulletPoint("Generating application assets: ")
|
||||||
err := packageApplicationForWindows(options)
|
err := packageApplicationForWindows(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
outputLogger.Println("Done.")
|
pterm.Println("Done.")
|
||||||
|
|
||||||
// When we finish, we will want to remove the syso file
|
// When we finish, we will want to remove the syso file
|
||||||
defer func() {
|
defer func() {
|
||||||
err := os.Remove(filepath.Join(options.ProjectData.Path, options.ProjectData.Name+"-res.syso"))
|
err := os.Remove(filepath.Join(options.ProjectData.Path, options.ProjectData.Name+"-res.syso"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
fatal(err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile the application
|
// Compile the application
|
||||||
outputLogger.Print(" - Compiling application: ")
|
printBulletPoint("Compiling application: ")
|
||||||
|
|
||||||
if options.Platform == "darwin" && options.Arch == "universal" {
|
if options.Platform == "darwin" && options.Arch == "universal" {
|
||||||
outputFile := builder.OutputFilename(options)
|
outputFile := builder.OutputFilename(options)
|
||||||
@ -251,7 +272,7 @@ func execBuildApplication(builder Builder, options *Options) (string, error) {
|
|||||||
options.OutputFile = amd64Filename
|
options.OutputFile = amd64Filename
|
||||||
options.CleanBinDirectory = false
|
options.CleanBinDirectory = false
|
||||||
if options.Verbosity == VERBOSE {
|
if options.Verbosity == VERBOSE {
|
||||||
outputLogger.Println("\nBuilding AMD64 Target: %s", filepath.Join(options.BinDirectory, options.OutputFile))
|
pterm.Println("Building AMD64 Target: " + filepath.Join(options.BinDirectory, options.OutputFile))
|
||||||
}
|
}
|
||||||
err := builder.CompileProject(options)
|
err := builder.CompileProject(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -262,7 +283,7 @@ func execBuildApplication(builder Builder, options *Options) (string, error) {
|
|||||||
options.OutputFile = arm64Filename
|
options.OutputFile = arm64Filename
|
||||||
options.CleanBinDirectory = false
|
options.CleanBinDirectory = false
|
||||||
if options.Verbosity == VERBOSE {
|
if options.Verbosity == VERBOSE {
|
||||||
outputLogger.Println("Building ARM64 Target: %s", filepath.Join(options.BinDirectory, options.OutputFile))
|
pterm.Println("Building ARM64 Target: " + filepath.Join(options.BinDirectory, options.OutputFile))
|
||||||
}
|
}
|
||||||
err = builder.CompileProject(options)
|
err = builder.CompileProject(options)
|
||||||
|
|
||||||
@ -271,7 +292,7 @@ func execBuildApplication(builder Builder, options *Options) (string, error) {
|
|||||||
}
|
}
|
||||||
// Run lipo
|
// Run lipo
|
||||||
if options.Verbosity == VERBOSE {
|
if options.Verbosity == VERBOSE {
|
||||||
outputLogger.Println(" Running lipo: lipo -create -output %s %s %s", outputFile, amd64Filename, arm64Filename)
|
pterm.Println("Running lipo: lipo -create -output %s %s %s", outputFile, amd64Filename, arm64Filename)
|
||||||
}
|
}
|
||||||
_, stderr, err := shell.RunCommand(options.BinDirectory, "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
|
_, stderr, err := shell.RunCommand(options.BinDirectory, "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -295,19 +316,19 @@ func execBuildApplication(builder Builder, options *Options) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outputLogger.Println("Done.")
|
pterm.Println("Done.")
|
||||||
|
|
||||||
// Do we need to pack the app for non-windows?
|
// Do we need to pack the app for non-windows?
|
||||||
if options.Pack && options.Platform != "windows" {
|
if options.Pack && options.Platform != "windows" {
|
||||||
|
|
||||||
outputLogger.Print(" - Packaging application: ")
|
printBulletPoint("Packaging application: ")
|
||||||
|
|
||||||
// TODO: Allow cross platform build
|
// TODO: Allow cross platform build
|
||||||
err := packageProject(options, runtime.GOOS)
|
err := packageProject(options, runtime.GOOS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
outputLogger.Println("Done.")
|
pterm.Println("Done.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.Platform == "windows" {
|
if options.Platform == "windows" {
|
||||||
@ -321,7 +342,7 @@ func execBuildApplication(builder Builder, options *Options) (string, error) {
|
|||||||
tags = append(tags, expWebView2Loader)
|
tags = append(tags, expWebView2Loader)
|
||||||
message = fmt.Sprintf("An experimental Go native WebView2Loader is available. We would love to hear your feedback about it and invite you to test it by building with `-tags %s`", strings.Join(tags, ","))
|
message = fmt.Sprintf("An experimental Go native WebView2Loader is available. We would love to hear your feedback about it and invite you to test it by building with `-tags %s`", strings.Join(tags, ","))
|
||||||
}
|
}
|
||||||
println(colour.Green(" - " + message))
|
pterm.Info.Println(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
return options.CompiledBinary, nil
|
return options.CompiledBinary, nil
|
||||||
@ -358,13 +379,13 @@ func executeBuildHook(outputLogger *clilogger.CLILogger, options *Options, hookI
|
|||||||
// The hook is for host platform
|
// The hook is for host platform
|
||||||
} else {
|
} else {
|
||||||
// Skip a hook which is not native
|
// Skip a hook which is not native
|
||||||
outputLogger.Println(" - Non native build hook '%s': Skipping.", hookIdentifier)
|
printBulletPoint(fmt.Sprintf("Non native build hook '%s': Skipping.", hookIdentifier))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outputLogger.Print(" - Executing %s build hook '%s': ", hookName, hookIdentifier)
|
printBulletPoint("Executing %s build hook '%s': ", hookName, hookIdentifier)
|
||||||
args := strings.Split(buildHook, " ")
|
args := strings.Split(buildHook, " ")
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
newArg := argReplacements[arg]
|
newArg := argReplacements[arg]
|
||||||
@ -375,17 +396,17 @@ func executeBuildHook(outputLogger *clilogger.CLILogger, options *Options, hookI
|
|||||||
}
|
}
|
||||||
|
|
||||||
if options.Verbosity == VERBOSE {
|
if options.Verbosity == VERBOSE {
|
||||||
outputLogger.Println("%s", strings.Join(args, " "))
|
pterm.Info.Println("%s", strings.Join(args, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, stderr, err := shell.RunCommand(options.BinDirectory, args[0], args[1:]...)
|
stdout, stderr, err := shell.RunCommand(options.BinDirectory, args[0], args[1:]...)
|
||||||
if options.Verbosity == VERBOSE {
|
if options.Verbosity == VERBOSE {
|
||||||
println(stdout)
|
pterm.Info.Println(stdout)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s - %s", err.Error(), stderr)
|
return fmt.Errorf("%s - %s", err.Error(), stderr)
|
||||||
}
|
}
|
||||||
outputLogger.Println("Done.")
|
pterm.Println("Done.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ func GenerateNSISInstaller(options *Options, amd64Binary string, arm64Binary str
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := webview2runtime.WriteInstallerToFile(webviewSetup); err != nil {
|
if err := webview2runtime.WriteInstallerToFile(webviewSetup); err != nil {
|
||||||
return fmt.Errorf("Unable to write Webview2 Bootstrapper Setup: %w", err)
|
return fmt.Errorf("Unable to write WebView2 Bootstrapper Setup: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !shell.CommandExists("makensis") {
|
if !shell.CommandExists("makensis") {
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
|
|
||||||
"github.com/leaanthony/debme"
|
"github.com/leaanthony/debme"
|
||||||
"github.com/leaanthony/gosod"
|
"github.com/leaanthony/gosod"
|
||||||
"github.com/olekukonko/tablewriter"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||||
)
|
)
|
||||||
@ -313,33 +312,6 @@ func gitclone(options *Options) (string, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutputList prints the list of available tempaltes to the given logger
|
|
||||||
func OutputList(logger *clilogger.CLILogger) error {
|
|
||||||
templates, err := List()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
table := tablewriter.NewWriter(logger.Writer)
|
|
||||||
table.SetHeader([]string{"Template", "Short Name", "Description"})
|
|
||||||
table.SetAutoWrapText(false)
|
|
||||||
table.SetAutoFormatHeaders(true)
|
|
||||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
|
||||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
|
||||||
table.SetCenterSeparator("")
|
|
||||||
table.SetColumnSeparator("")
|
|
||||||
table.SetRowSeparator("")
|
|
||||||
table.SetHeaderLine(false)
|
|
||||||
table.SetBorder(false)
|
|
||||||
table.SetTablePadding("\t") // pad with tabs
|
|
||||||
table.SetNoWhiteSpace(true)
|
|
||||||
for _, template := range templates {
|
|
||||||
table.Append([]string{template.Name, template.ShortName, template.Description})
|
|
||||||
}
|
|
||||||
table.Render()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateIDEFiles(options *Options) error {
|
func generateIDEFiles(options *Options) error {
|
||||||
|
|
||||||
switch options.IDE {
|
switch options.IDE {
|
||||||
|
Loading…
Reference in New Issue
Block a user