Go SDK¶
The Go package is the primary integration surface. It is a library, not a framework: no daemon, no required directory layout, no lifecycle hooks and no global state. Your application owns startup, UI, process exit and restart.
Design contract¶
The public API is intentionally two operations:
update, err := u.Check(ctx) // discover and select a release
result, err := u.Apply(ctx, update, wmlupdate.ApplyOptions{})
Check performs no writes to the application tree. Apply downloads, verifies
and installs a previously checked release. Progress is optional through a
callback; the terminal outcome is the return value.
The library also uses a small state directory for locks, downloads, backups and recovery. That is internal bookkeeping, not a requirement on your application structure.
Minimal integration¶
package main
import (
"context"
"fmt"
"os"
wmlupdate "github.com/yxxbc/wmlUpdate"
)
func checkForUpdates(ctx context.Context) error {
u, err := wmlupdate.New(wmlupdate.Options{
ConfigPath: "updater.json",
CurrentVersion: appVersion,
Events: func(e wmlupdate.Event) {
if e.Type == wmlupdate.EventProgress && e.Phase == "download" {
fmt.Printf("\r%d%%", int(e.Percent))
}
},
})
if err != nil {
return err
}
defer u.Close()
update, err := u.Check(ctx)
if err != nil {
return err
}
if !update.Available {
return nil
}
result, err := u.Apply(ctx, update, wmlupdate.ApplyOptions{})
if err != nil {
return err
}
fmt.Printf("\ninstalled %s (was %s)\n", result.Version, result.PreviousVersion)
return nil
}
That is the whole integration. Your UI decides whether to prompt, when to check, and when to restart.
Configuration¶
From updater.json¶
Options.ConfigPath loads the same configuration format used by the CLI,
including environment expansion, signature keys and all install strategies.
u, err := wmlupdate.New(wmlupdate.Options{
ConfigPath: "/path/to/updater.json",
CurrentVersion: "1.4.2",
})
Programmatic¶
For a dependency-only setup, avoid shipping a separate config file:
u, err := wmlupdate.New(wmlupdate.Options{
CurrentVersion: "1.4.2",
BaseDir: appDataDir, // resolves relative install/key paths
Config: &wmlupdate.Config{
AppID: "com.example.myapp",
Channel: "stable",
Source: wmlupdate.SourceConfig{
Type: wmlupdate.SourceGitHub,
Owner: "acme",
Repo: "myapp",
},
AssetRules: []wmlupdate.AssetRule{
{OS: "darwin", Arch: "arm64", Match: "myapp-{version}-macos-arm64.zip", Format: "zip"},
{OS: "windows", Arch: "amd64", Match: "myapp-{version}-windows-amd64.zip", Format: "zip"},
{OS: "linux", Arch: "amd64", Match: "myapp-{version}-linux-amd64.tar.gz", Format: "tar.gz"},
},
Install: wmlupdate.InstallConfig{
Type: wmlupdate.InstallDirectory,
Paths: map[string]string{
"darwin": "/Applications/MyApp.app",
"windows": `C:\Program Files\MyApp`,
"linux": "/opt/myapp",
},
Preserve: []string{"data/**", "config/**"},
},
},
})
Programmatic durations use time.Duration; use ConfigPath for the JSON string
form. BaseDir defaults to the process working directory for relative paths.
Chains, mirrors, proxy and macOS¶
SourceConfig.Sources supports ordered chains. SourceConfig.ManifestURLs,
SourceConfig.AssetMirrors and DownloadConfig.Proxy expose the same failover
and network options as the JSON configuration. InstallConfig.MacOS controls
optional quarantine removal, ad-hoc signing and signer-change policy. See the
configuration reference for semantics and security
trade-offs.
Current version¶
Pass the version compiled into the running application:
It is the only reliable source. If omitted, the SDK falls back to recorded
updater state and then Config.CurrentVersion. After an in-place successful Apply, the
Updater updates its internal current version so the next Check is correct.
Events¶
Options.Events receives:
| Type | Meaning |
|---|---|
EventLog |
Phase transition or diagnostic |
EventWarning |
Non-fatal security or recovery warning |
EventProgress |
Download bytes/total/percent |
The callback runs synchronously on the updater's goroutine. Marshal UI updates to your own event loop if necessary. No callback is required.
Applying¶
Result statuses:
| Status | Meaning |
|---|---|
StatusUpdated |
Installed in-process |
StatusDownloaded |
install.type=external; artifact path returned |
StatusApplyScheduled |
Deferred helper scheduled |
Windows / running executable¶
Use deferred apply when the target is running or when the updater is replacing itself:
result, err := u.Apply(ctx, update, wmlupdate.ApplyOptions{
Defer: true,
WaitPIDs: []int{os.Getpid()},
})
The call stages the update and starts a detached helper, then returns
StatusApplyScheduled. The host should exit promptly. The helper waits for the
listed PIDs, applies the journaled transaction and optionally relaunches via
Config.Install.RelaunchPath.
External installation¶
With InstallExternal, Apply downloads and verifies the artifact and returns
ArtifactPath; your application installs it. This keeps custom native
installers, package managers or platform-specific logic outside the library.
Errors¶
Use Code for stable branching:
if err != nil {
switch wmlupdate.Code(err) {
case "no_update":
case "integrity":
case "source", "network":
case "install":
}
}
errors.Is(err, wmlupdate.ErrNoUpdate) also works. Codes match the CLI/API
protocol: config, source, network, no_release, no_asset, integrity,
install, rollback, locked, state, io, cancelled, no_update.
Lifetime and concurrency¶
Newopens the state directory and configures an HTTP client.Closereleases idle HTTP connections. It does not cancel in-flight calls.Checkis read-only and safe to call concurrently.Applytakes a per-application file lock; mutating calls are serialized.- An
Updateis an opaque checked snapshot. CallCheckandApplyin the same process; do not serialize it or construct it manually. Applydoes not exit or restart the host. That remains your decision.- No daemon, service, web server or global registration is required.
Rollback¶
The library retains a backup according to Install.KeepBackups. The optional
CLI exposes:
The SDK intentionally does not expose rollback in its minimal surface; use the
CLI for operational recovery or keep an install.type=external path under your
own control.
Other languages¶
A Go library cannot be loaded directly by Python, Node.js or Java. Those applications use the same engine through the sidecar CLI's NDJSON protocol or the loopback HTTP API. See integration. This is an adapter, not a requirement for Go applications.