Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 25 additions & 32 deletions v2/cmd/wails/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,19 @@ import (
"strings"
"time"

"github.com/wailsapp/wails/v2/pkg/commands/buildtags"

"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/internal/tui"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/commands/build"
"github.com/wailsapp/wails/v2/pkg/commands/buildtags"
)

func buildApplication(f *flags.Build) error {
if f.NoColour {
pterm.DisableColor()
colour.ColourEnabled = false
tui.SetNoColour()
}

quiet := f.Verbosity == flags.Quiet
Expand All @@ -31,9 +28,7 @@ func buildApplication(f *flags.Build) error {
logger := clilogger.New(os.Stdout)
logger.Mute(quiet)

if quiet {
pterm.DisableOutput()
} else {
if !quiet {
app.PrintBanner()
}

Expand Down Expand Up @@ -98,7 +93,7 @@ func buildApplication(f *flags.Build) error {
InstallScope: f.InstallScope,
}

tableData := pterm.TableData{
tableData := [][]string{
{"Platform(s)", f.Platform},
{"Compiler", f.GetCompilerPath()},
{"Skip Bindings", bool2Str(f.SkipBindings)},
Expand All @@ -111,7 +106,7 @@ func buildApplication(f *flags.Build) error {
if f.Obfuscated {
tableData = append(tableData, []string{"Garble Args", f.GarbleArgs})
}
tableData = append(tableData, pterm.TableData{
tableData = append(tableData, [][]string{
{"Skip Frontend", bool2Str(f.SkipFrontend)},
{"Compress", bool2Str(f.Upx)},
{"Package", bool2Str(!f.NoPackage)},
Expand All @@ -123,12 +118,8 @@ func buildApplication(f *flags.Build) error {
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
}
tui.Section("Build Options")
tui.Table(tableData)

if !f.NoSyncGoMod {
err = gomod.SyncGoMod(logger, f.UpdateWailsVersionGoMod)
Expand All @@ -155,8 +146,7 @@ func buildApplication(f *flags.Build) error {

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.
// Allows cancelling the build after the first error.
var targetErr error
targets := f.GetTargets()
targets.Each(func(platform string) {
Expand All @@ -182,23 +172,22 @@ func buildApplication(f *flags.Build) error {
if len(platformSplit) > 1 {
buildOptions.Arch = platformSplit[1]
}
banner := "Building target: " + buildOptions.Platform + "/" + buildOptions.Arch
pterm.DefaultSection.Println(banner)
tui.Section("Building target: " + buildOptions.Platform + "/" + buildOptions.Arch)

if f.Upx && platform == "darwin/universal" {
pterm.Warning.Println("Warning: compress flag unsupported for universal binaries. Ignoring.")
tui.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.")
tui.Warning("Crosscompiling to Linux not currently supported.")
return
}
case "darwin":
if runtime.GOOS != "darwin" {
pterm.Warning.Println("Crosscompiling to Mac not currently supported.")
tui.Warning("Crosscompiling to Mac not currently supported.")
return
}
macTargets := targets.Filter(func(platform string) bool {
Expand All @@ -210,7 +199,6 @@ func buildApplication(f *flags.Build) error {
}

if targets.Length() > 1 {
// target filename
switch buildOptions.Platform {
case "windows":
desiredFilename = fmt.Sprintf("%s-%s", desiredFilename, buildOptions.Arch)
Expand All @@ -228,30 +216,35 @@ func buildApplication(f *flags.Build) error {
}

if f.Obfuscated && f.SkipBindings {
pterm.Warning.Println("obfuscated flag overrides skipbindings flag.")
tui.Warning("Obfuscated flag overrides skipbindings flag.")
buildOptions.SkipBindings = false
}

if !f.DryRun {
// Start Time
start := time.Now()

compiledBinary, err := build.Build(buildOptions)
var compiledBinary string
err := tui.WithSpinner(
fmt.Sprintf("Compiling %s/%s", buildOptions.Platform, buildOptions.Arch),
func() error {
var buildErr error
compiledBinary, buildErr = build.Build(buildOptions)
return buildErr
},
)
if err != nil {
pterm.Error.Println(err.Error())
tui.Error(err.Error())
targetErr = err
return
}

buildOptions.IgnoreFrontend = true
buildOptions.CleanBinDirectory = false

// Output stats
buildOptions.Logger.Println("%s", 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.")
tui.Info("Dry run: skipped build.")
}
Comment on lines 223 to 248
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f -e go . v2/internal/tui | xargs -r rg -nP -C5 '\bWithSpinner\b|NewInlineApp|\bRun\(|Pause|Suspend|Stop'

Repository: wailsapp/wails

Length of output: 1092


🏁 Script executed:

#!/bin/bash
# Find and read the complete WithSpinner function
fd -t f -e go . v2/internal/tui | head -5 | while read f; do
  if rg -q "func WithSpinner" "$f"; then
    echo "=== Found in: $f ==="
    # Get line number and read surrounding context
    line=$(rg -n "func WithSpinner" "$f" | cut -d: -f1)
    start=$((line - 5))
    [ $start -lt 1 ] && start=1
    end=$((line + 80))
    sed -n "${start},${end}p" "$f"
  fi
done

Repository: wailsapp/wails

Length of output: 2113


🏁 Script executed:

#!/bin/bash
# Look for glyph imports and understand what RunNonInteractive does
rg -A 20 "RunNonInteractive" v2/internal/tui/tui.go | head -30

Repository: wailsapp/wails

Length of output: 703


Spinner redraws race with build.Build's logger output on non-quiet verbosity.

The spinner animation loop in WithSpinner continuously redraws every 80ms via app.RequestRender() while fn() executes concurrently. Since buildOptions.Logger (initialized with os.Stdout) is unmuted when verbosity is not Quiet, the build pipeline's output and the spinner's terminal state management write to os.Stdout without synchronization. This causes visible artifacts: torn spinner frames, duplicated output, and misaligned text interleaved in interactive terminals.

Two reasonable options:

  • Only show the spinner when quiet is true (the only case where stdout is silent during the closure), and otherwise print a tui.Section or status line.
  • Have tui.WithSpinner pause spinner redraws while the closure runs, relying on the build's own progress output.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/cmd/wails/build.go` around lines 223 - 248, The spinner is racing with
build output because tui.WithSpinner redraws while build.Build writes to
buildOptions.Logger (os.Stdout) — fix by not running the spinner when build
output is unmuted: in the DryRun/real build block, check verbosity (or whether
buildOptions.Logger is os.Stdout) and if not Quiet, replace the WithSpinner call
with a simple status emit (e.g., tui.Section or tui.Info stating "Compiling
PLATFORM/ARCH...") and then call build.Build directly; alternatively, add a
boolean flag to tui.WithSpinner (e.g., pauseRedraw bool) and set it to true when
buildOptions.Logger is not Quiet so the spinner stops redrawing while the
closure runs; update references in this block: WithSpinner, build.Build,
buildOptions.Logger, and the status emit used.

})

Expand Down
10 changes: 3 additions & 7 deletions v2/cmd/wails/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ package main
import (
"os"

"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/internal/tui"
"github.com/wailsapp/wails/v2/pkg/clilogger"
)

func devApplication(f *flags.Dev) error {
if f.NoColour {
pterm.DisableColor()
colour.ColourEnabled = false
tui.SetNoColour()
}

quiet := f.Verbosity == flags.Quiet
Expand All @@ -22,9 +20,7 @@ func devApplication(f *flags.Dev) error {
logger := clilogger.New(os.Stdout)
logger.Mute(quiet)

if quiet {
pterm.DisableOutput()
} else {
if !quiet {
app.PrintBanner()
}

Expand Down
Loading
Loading