diff --git a/docs/public/sponsors/zsa.png b/docs/public/sponsors/zsa.png new file mode 100644 index 000000000..507e983fa Binary files /dev/null and b/docs/public/sponsors/zsa.png differ diff --git a/docs/src/content/docs/changelog.mdx b/docs/src/content/docs/changelog.mdx index bc612c4af..91f828eb7 100644 --- a/docs/src/content/docs/changelog.mdx +++ b/docs/src/content/docs/changelog.mdx @@ -23,7 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 */ - ## [Unreleased] ### Added @@ -34,8 +33,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `init()` method in runtime to allow manual initialisation of the runtime by [@leaanthony](https://github.com/leaanthony) - Added `WindowDidMoveDebounceMS` option to Window's WindowOptions by [@leaanthony](https://github.com/leaanthony) - Added Single Instance feature by [@leaanthony](https://github.com/leaanthony). Based on the [v2 PR](https://github.com/wailsapp/wails/pull/2951) by @APshenkin. -- Added template generation using `wails3 generate template` command by [@leaanthony](https://github.com/leaanthony) -- Added `wails3 releasenotes` command by [@leaanthony](https://github.com/leaanthony) +- `wails3 generate template` command by [@leaanthony](https://github.com/leaanthony) +- `wails3 releasenotes` command by [@leaanthony](https://github.com/leaanthony) +- `wails3 update cli` command by [@leaanthony](https://github.com/leaanthony) ### Fixed @@ -64,7 +64,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `Window.Destroy` as this was intended to be an internal function by [@leaanthony](https://github.com/leaanthony) - Renamed `WindowClose` events to `WindowClosing` by [@leaanthony](https://github.com/leaanthony) - ## v3.0.0-alpha.8.3 - 2024-12-07 ### Changed diff --git a/docs/src/content/docs/credits.mdx b/docs/src/content/docs/credits.mdx index bf6717a74..5ed2ed9f4 100644 --- a/docs/src/content/docs/credits.mdx +++ b/docs/src/content/docs/credits.mdx @@ -16,7 +16,14 @@ import Contributors from "../../assets/contributors.html"; - [Lyimmi](https://github.com/Lyimmi) - All things Linux ## Sponsors - +
+ + ZSA + `. +### `update cli` +Updates the Wails CLI to a new version. + +```bash +wails3 update cli [flags] +``` + +#### Flags +| Flag | Description | Default | +|-------------|---------------------------------|---------| +| `-pre` | Update to latest pre-release | `false` | +| `-version` | Update to specific version | | +| `-nocolour` | Disable colored output | `false` | + +The update cli command allows you to update your Wails CLI installation. By default, it updates to the latest stable release. +You can use the `-pre` flag to update to the latest pre-release version, or specify a particular version using the `-version` flag. + +After updating, remember to update your project's go.mod file to use the same version: +```bash +require github.com/wailsapp/wails/v3 v3.x.x +``` + ### `update build-assets` Updates the build assets using the given config file. @@ -413,4 +435,3 @@ Opens the Wails sponsorship page in your default browser. ```bash wails3 sponsor - diff --git a/v3/cmd/wails3/main.go b/v3/cmd/wails3/main.go index a1684cc33..56017cf49 100644 --- a/v3/cmd/wails3/main.go +++ b/v3/cmd/wails3/main.go @@ -57,6 +57,7 @@ func main() { update := app.NewSubCommand("update", "Update tools") update.NewSubCommandFunction("build-assets", "Updates the build assets using the given config file", commands.UpdateBuildAssets) + update.NewSubCommandFunction("cli", "Updates the Wails CLI", commands.UpdateCLI) bindgen := generate.NewSubCommand("bindings", "Generate bindings + models") var bindgenFlags flags.GenerateBindingsOptions diff --git a/v3/internal/commands/appimage.go b/v3/internal/commands/appimage.go index b2a148651..7c43ba856 100644 --- a/v3/internal/commands/appimage.go +++ b/v3/internal/commands/appimage.go @@ -4,6 +4,7 @@ import ( _ "embed" "errors" "fmt" + "github.com/wailsapp/wails/v3/internal/term" "os" "path/filepath" "runtime" @@ -19,7 +20,7 @@ var gtkPlugin []byte func log(p *pterm.ProgressbarPrinter, message string) { p.UpdateTitle(message) - pterm.Info.Println(message) + term.Infof(message) p.Increment() } @@ -61,7 +62,7 @@ func GenerateAppImage(options *GenerateAppImageOptions) error { return err } - pterm.Println(pterm.LightYellow("AppImage Generator v1.0.0")) + term.Header("AppImage Generator") return generateAppImage(options) } diff --git a/v3/internal/commands/bindings.go b/v3/internal/commands/bindings.go index 94833f881..89ce70376 100644 --- a/v3/internal/commands/bindings.go +++ b/v3/internal/commands/bindings.go @@ -3,28 +3,29 @@ package commands import ( "errors" "fmt" - "os" "path/filepath" "github.com/pterm/pterm" - "golang.org/x/term" "github.com/wailsapp/wails/v3/internal/flags" "github.com/wailsapp/wails/v3/internal/generator" "github.com/wailsapp/wails/v3/internal/generator/config" + "github.com/wailsapp/wails/v3/internal/term" ) func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) error { DisableFooter = true if options.Silent { - pterm.DisableOutput() - defer pterm.EnableOutput() + term.DisableOutput() + defer term.EnableOutput() } else if options.Verbose { pterm.EnableDebugMessages() defer pterm.DisableDebugMessages() } + term.Header("Generate Bindings") + if len(patterns) == 0 { // No input pattern, load package from current directory. patterns = []string{"."} @@ -44,7 +45,7 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) // Start a spinner for progress messages. var spinner *pterm.SpinnerPrinter - if term.IsTerminal(int(os.Stdout.Fd())) && (os.Getenv("CI") != "true") { + if term.IsTerminal() { spinner, _ = pterm.DefaultSpinner.Start("Initialising...") } @@ -68,11 +69,11 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) if spinner != nil { spinner.Info(resultMessage) } else { - pterm.Info.Println(resultMessage) + term.Infofln(resultMessage) } // Report output directory. - pterm.Info.Printfln("Output directory: %s", absPath) + term.Infofln("Output directory: %s", absPath) // Process generator error. if err != nil { @@ -80,14 +81,14 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) switch { case errors.Is(err, generator.ErrNoPackages): // Convert to warning message. - pterm.Warning.Println(err) + term.Warning(err) case errors.As(err, &report): if report.HasErrors() { // Report error count. return err } else if report.HasWarnings() { // Report warning count. - pterm.Warning.Println(report) + term.Warning(report) } default: // Report error. diff --git a/v3/internal/commands/generate_webview2.go b/v3/internal/commands/generate_webview2.go index affbb4519..146f72bff 100644 --- a/v3/internal/commands/generate_webview2.go +++ b/v3/internal/commands/generate_webview2.go @@ -3,10 +3,9 @@ package commands import ( _ "embed" "fmt" + "github.com/wailsapp/wails/v3/internal/term" "os" "path/filepath" - - "github.com/pterm/pterm" ) //go:embed webview2/MicrosoftEdgeWebview2Setup.exe @@ -35,6 +34,6 @@ func GenerateWebView2Bootstrapper(options *GenerateWebView2Options) error { return fmt.Errorf("failed to write WebView2 bootstrapper: %w", err) } - pterm.Success.Printf("Generated WebView2 bootstrapper at: %s\n", targetPath) + term.Success("Generated WebView2 bootstrapper at: " + targetPath + "\n") return nil } diff --git a/v3/internal/commands/init.go b/v3/internal/commands/init.go index c9aa42e4b..8a346f888 100644 --- a/v3/internal/commands/init.go +++ b/v3/internal/commands/init.go @@ -3,6 +3,7 @@ package commands import ( "fmt" "github.com/go-git/go-git/v5/config" + "github.com/wailsapp/wails/v3/internal/term" "os" "path/filepath" "regexp" @@ -103,12 +104,14 @@ func initGitRepository(projectDir string, gitURL string) error { func Init(options *flags.Init) error { if options.List { + term.Header("Available templates") return printTemplates() } if options.Quiet { - pterm.DisableOutput() + term.DisableOutput() } + term.Header("Init project") // Check if the template is a typescript template isTypescript := false @@ -158,7 +161,7 @@ func Init(options *flags.Init) error { return err } if !options.Quiet { - pterm.Info.Printf("Initialized git repository with remote: %s\n", options.Git) + term.Infof("Initialized git repository with remote: %s\n", options.Git) } } return nil @@ -167,8 +170,7 @@ func Init(options *flags.Init) error { func printTemplates() error { defaultTemplates := templates.GetDefaultTemplates() - pterm.DefaultSection.Println("Available templates") - + pterm.Println() table := pterm.TableData{{"Name", "Description"}} for _, template := range defaultTemplates { table = append(table, []string{template.Name, template.Description}) diff --git a/v3/internal/commands/releasenotes.go b/v3/internal/commands/releasenotes.go index 6dbb5a6cf..a90c7cb1b 100644 --- a/v3/internal/commands/releasenotes.go +++ b/v3/internal/commands/releasenotes.go @@ -1,8 +1,8 @@ package commands import ( - "github.com/pterm/pterm" "github.com/wailsapp/wails/v3/internal/github" + "github.com/wailsapp/wails/v3/internal/term" "github.com/wailsapp/wails/v3/internal/version" ) @@ -13,15 +13,22 @@ type ReleaseNotesOptions struct { func ReleaseNotes(options *ReleaseNotesOptions) error { if options.NoColour { - pterm.DisableColor() + term.DisableColor() } - currentVersion := version.VersionString + term.Header("Release Notes") + + if version.IsDev() { + term.Println("Release notes are not available for development builds") + return nil + } + + currentVersion := version.String() if options.Version != "" { currentVersion = options.Version } releaseNotes := github.GetReleaseNotes(currentVersion, options.NoColour) - pterm.Println(releaseNotes) + term.Println(releaseNotes) return nil } diff --git a/v3/internal/commands/service.go b/v3/internal/commands/service.go index 8babf87f3..8f5a6bd0a 100644 --- a/v3/internal/commands/service.go +++ b/v3/internal/commands/service.go @@ -3,9 +3,8 @@ package commands import ( "github.com/wailsapp/wails/v3/internal/flags" "github.com/wailsapp/wails/v3/internal/service" + "github.com/wailsapp/wails/v3/internal/term" "strings" - - "github.com/pterm/pterm" ) func toCamelCasePlugin(s string) string { @@ -34,7 +33,7 @@ func toCamelCasePlugin(s string) string { func ServiceInit(options *flags.ServiceInit) error { if options.Quiet { - pterm.DisableOutput() + term.DisableOutput() } if options.PackageName == "" { diff --git a/v3/internal/commands/task.go b/v3/internal/commands/task.go index 5b1743134..9672b2f27 100644 --- a/v3/internal/commands/task.go +++ b/v3/internal/commands/task.go @@ -3,13 +3,12 @@ package commands import ( "context" "fmt" + "github.com/wailsapp/wails/v3/internal/term" "os" "path/filepath" "strings" "time" - "github.com/pterm/pterm" - "github.com/wailsapp/task/v3" "github.com/wailsapp/task/v3/taskfile/ast" ) @@ -18,7 +17,7 @@ import ( var BuildSettings = map[string]string{} func fatal(message string) { - pterm.Error.Println(message) + term.Error(message) os.Exit(1) } diff --git a/v3/internal/commands/task_wrapper.go b/v3/internal/commands/task_wrapper.go index 896be3550..c4e55855e 100644 --- a/v3/internal/commands/task_wrapper.go +++ b/v3/internal/commands/task_wrapper.go @@ -1,9 +1,9 @@ package commands import ( + "github.com/wailsapp/wails/v3/internal/term" "os" - "github.com/pterm/pterm" "github.com/wailsapp/wails/v3/internal/flags" ) @@ -16,7 +16,7 @@ func Package(_ *flags.Package) error { } func wrapTask(command string) error { - pterm.Warning.Printf("`wails3 %s` is an alias for `wails3 task %s`. Use `wails task` for better control and more options.\n", command, command) + term.Warningf("`wails3 %s` is an alias for `wails3 task %s`. Use `wails task` for better control and more options.\n", command, command) os.Args = []string{"wails3", "task", command} return RunTask(&RunTaskOptions{}, []string{}) } diff --git a/v3/internal/commands/update_cli.go b/v3/internal/commands/update_cli.go new file mode 100644 index 000000000..a910622b4 --- /dev/null +++ b/v3/internal/commands/update_cli.go @@ -0,0 +1,177 @@ +package commands + +import ( + "fmt" + "github.com/pterm/pterm" + "github.com/wailsapp/wails/v3/internal/debug" + "github.com/wailsapp/wails/v3/internal/github" + "github.com/wailsapp/wails/v3/internal/term" + "github.com/wailsapp/wails/v3/internal/version" + "os" + "os/exec" + "path/filepath" +) + +type UpdateCLIOptions struct { + NoColour bool `name:"n" description:"Disable colour output"` + PreRelease bool `name:"pre" description:"Update to the latest pre-release (eg beta)"` + Version string `name:"version" description:"Update to a specific version (eg v3.0.0)"` + Latest bool `name:"latest" description:"Install the latest stable release"` +} + +func UpdateCLI(options *UpdateCLIOptions) error { + if options.NoColour { + term.DisableColor() + } + + term.Header("Update CLI") + + // Check if this CLI has been installed from vcs + if debug.LocalModulePath != "" && !options.Latest { + v3Path := filepath.ToSlash(debug.LocalModulePath + "/v3") + term.Println("This Wails CLI has been installed from source. To update to the latest stable release, run the following commands in the `" + v3Path + "` directory:") + term.Println(" - git pull") + term.Println(" - go install") + term.Println("") + term.Println("If you want to install the latest release, please run `wails update cli -latest`") + return nil + } + + if options.Latest { + latestVersion, err := github.GetLatestStableRelease() + if err != nil { + return err + } + return updateToVersion(latestVersion, true, version.String()) + } + + term.Println("Checking for updates...") + + var desiredVersion *github.SemanticVersion + var err error + var valid bool + + if len(options.Version) > 0 { + // Check if this is a valid version + valid, err = github.IsValidTag(options.Version) + if err == nil { + if !valid { + err = fmt.Errorf("version '%s' is invalid", options.Version) + } else { + desiredVersion, err = github.NewSemanticVersion(options.Version) + } + } + } else { + if options.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() + + currentVersion := version.String() + pterm.Printf(" Current Version : %s\n", currentVersion) + + if len(options.Version) > 0 { + fmt.Printf(" Desired Version : v%s\n", desiredVersion) + } else { + if options.PreRelease { + fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion) + } else { + fmt.Printf(" Latest Release : v%s\n", desiredVersion) + } + } + + return updateToVersion(desiredVersion, len(options.Version) > 0, currentVersion) +} + +func updateToVersion(targetVersion *github.SemanticVersion, force bool, currentVersion string) error { + targetVersionString := "v" + targetVersion.String() + + if targetVersionString == currentVersion { + pterm.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() { + 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.Printf("If this is what you really want to do, use `wails update -version %s`\n", 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 { + return fmt.Errorf("cannot find home directory: %w", err) + } + + cmd := exec.Command("go", "install", "github.com/wailsapp/wails/v3/cmd/wails@"+desiredVersion) + cmd.Dir = homeDir + sout, serr := cmd.CombinedOutput() + if err := cmd.Run(); err != nil { + pterm.Println("Failed.") + pterm.Error.Println(string(sout) + "\n" + serr.Error()) + return err + } + pterm.Println("Done.") + pterm.Println("\nMake sure you update your project go.mod file to use " + desiredVersion + ":") + pterm.Println(" require github.com/wailsapp/wails/v3 " + desiredVersion) + pterm.Println("\nTo view the release notes, please run `wails3 releasenotes`") + + return nil +} diff --git a/v3/internal/commands/version.go b/v3/internal/commands/version.go index 6ff58879b..65bf66113 100644 --- a/v3/internal/commands/version.go +++ b/v3/internal/commands/version.go @@ -9,6 +9,6 @@ type VersionOptions struct{} func Version(_ *VersionOptions) error { DisableFooter = true - println(version.VersionString) + println(version.String()) return nil } diff --git a/v3/internal/doctor/doctor.go b/v3/internal/doctor/doctor.go index dcf4dd7ac..234c33ec5 100644 --- a/v3/internal/doctor/doctor.go +++ b/v3/internal/doctor/doctor.go @@ -3,6 +3,7 @@ package doctor import ( "bytes" "fmt" + "github.com/wailsapp/wails/v3/internal/term" "os/exec" "path/filepath" "regexp" @@ -30,13 +31,7 @@ func Run() (err error) { } _ = get - pterm.DefaultSection = *pterm.DefaultSection. - WithBottomPadding(0). - WithStyle(pterm.NewStyle(pterm.FgBlue, pterm.Bold)) - - pterm.Println() // Spacer - pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Println("Wails Doctor") - pterm.Println() // Spacer + term.Header("Wails Doctor") spinner, _ := pterm.DefaultSpinner.WithRemoveWhenDone().Start("Scanning system - Please wait (this may take a long time)...") @@ -68,7 +63,7 @@ func Run() (err error) { // Get system info info, err := operatingsystem.Info() if err != nil { - pterm.Error.Println("Failed to get system information") + term.Error("Failed to get system information") return err } @@ -77,7 +72,7 @@ func Run() (err error) { return dep.Path == "github.com/wailsapp/wails/v3" }) - wailsVersion := strings.TrimSpace(version.VersionString) + wailsVersion := strings.TrimSpace(version.String()) if wailsPackage != nil && wailsPackage.Replace != nil { wailsVersion = "(local) => " + filepath.ToSlash(wailsPackage.Replace.Path) // Get the latest commit hash @@ -99,7 +94,7 @@ func Run() (err error) { /** Output **/ - pterm.DefaultSection.Println("System") + term.Section("System") systemTabledata := pterm.TableData{ {pterm.Sprint("Name"), info.Name}, @@ -195,7 +190,7 @@ func Run() (err error) { // Build Environment - pterm.DefaultSection.Println("Build Environment") + term.Section("Build Environment") tableData := pterm.TableData{ {"Wails CLI", wailsVersion}, @@ -228,7 +223,7 @@ func Run() (err error) { } // Dependencies - pterm.DefaultSection.Println("Dependencies") + term.Section("Dependencies") dependenciesBox := pterm.DefaultBox.WithTitleBottomCenter().WithTitle(pterm.Gray("*") + " - Optional Dependency") dependencyTableData := pterm.TableData{} if len(dependencies) == 0 { @@ -248,11 +243,11 @@ func Run() (err error) { dependenciesBox.Println(dependenciesTableString) } - pterm.DefaultSection.Println("Diagnosis") + term.Section("Diagnosis") if !ok { - pterm.Warning.Println("There are some items above that need addressing!") + term.Warning("There are some items above that need addressing!") } else { - pterm.Success.Println("Your system is ready for Wails development!") + term.Success("Your system is ready for Wails development!") } return nil diff --git a/v3/internal/templates/templates.go b/v3/internal/templates/templates.go index 62206d2e3..5d9aa49d2 100644 --- a/v3/internal/templates/templates.go +++ b/v3/internal/templates/templates.go @@ -260,7 +260,7 @@ func Install(options *flags.Init) error { Init: options, LocalModulePath: localModulePath, UseTypescript: UseTypescript, - WailsVersion: version.VersionString, + WailsVersion: version.String(), } defer func() { diff --git a/v3/internal/term/term.go b/v3/internal/term/term.go new file mode 100644 index 000000000..f973bc667 --- /dev/null +++ b/v3/internal/term/term.go @@ -0,0 +1,105 @@ +package term + +import ( + "fmt" + "github.com/pterm/pterm" + "github.com/wailsapp/wails/v3/internal/generator/config" + "github.com/wailsapp/wails/v3/internal/version" + "golang.org/x/term" + "os" +) + +func Header(header string) { + // Print Wails with the current version in white on red background with the header in white with a green background + pterm.BgLightRed.Print(pterm.LightWhite(" Wails (" + version.String() + ") ")) + pterm.BgLightGreen.Println(pterm.LightWhite(" " + header + " ")) +} + +func Infof(format string, args ...interface{}) { + pterm.Info.Printf(format, args...) +} +func Infofln(format string, args ...interface{}) { + pterm.Info.Printfln(format, args...) +} + +func IsTerminal() bool { + return term.IsTerminal(int(os.Stdout.Fd())) && (os.Getenv("CI") != "true") +} + +type Spinner struct { + spinner *pterm.SpinnerPrinter +} + +func (s *Spinner) Logger() config.Logger { + if s == nil { + return nil + } + return config.DefaultPtermLogger(s.spinner) +} + +func StartSpinner(text string) *Spinner { + if !IsTerminal() { + return nil + } + spin, err := pterm.DefaultSpinner.Start(text) + if err != nil { + return nil + } + return &Spinner{ + spinner: spin, + } +} + +func StopSpinner(s *Spinner) { + if s == nil { + return + } + _ = s.spinner.Stop() +} + +func output(input any, printer pterm.PrefixPrinter, args ...any) { + switch v := input.(type) { + case string: + printer.Println(fmt.Sprintf(input.(string), args...)) + case error: + printer.Println(v.Error()) + default: + printer.Printfln("%v", v) + } +} + +func Warning(input any) { + output(input, pterm.Warning) +} + +func Warningf(input any, args ...any) { + output(input, pterm.Warning, args) +} + +func Error(input any) { + output(input, pterm.Error) +} + +func Success(input any) { + output(input, pterm.Success) +} + +func Section(s string) { + style := pterm.NewStyle(pterm.BgDefault, pterm.FgLightBlue, pterm.Bold) + style.Println("\n# " + s + " \n") +} + +func DisableColor() { + pterm.DisableColor() +} +func EnableOutput() { + pterm.EnableOutput() +} + +func DisableOutput() { + pterm.DisableOutput() +} + +func Println(s string) { + pterm.Println(s) +} diff --git a/v3/internal/version/version.go b/v3/internal/version/version.go index d8b4b0c2b..048fe1378 100644 --- a/v3/internal/version/version.go +++ b/v3/internal/version/version.go @@ -2,7 +2,23 @@ package version import ( _ "embed" + "github.com/wailsapp/wails/v3/internal/debug" ) //go:embed version.txt -var VersionString string +var versionString string + +func String() string { + if !IsDev() { + return versionString + } + return "v3 dev" +} + +func LatestStable() string { + return versionString +} + +func IsDev() bool { + return debug.LocalModulePath != "" +}