diff --git a/v2/cmd/wails/internal/commands/doctor/doctor.go b/v2/cmd/wails/internal/commands/doctor/doctor.go index a9faeb17..1b6d2f89 100644 --- a/v2/cmd/wails/internal/commands/doctor/doctor.go +++ b/v2/cmd/wails/internal/commands/doctor/doctor.go @@ -68,7 +68,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { // Output Dependencies Status var dependenciesMissing = []string{} - var externalPackages = []*packagemanager.Dependancy{} + var externalPackages = []*packagemanager.Dependency{} var dependenciesAvailableRequired = 0 var dependenciesAvailableOptional = 0 fmt.Fprintf(w, "\n") diff --git a/v2/internal/system/packagemanager/nixpkgs.go b/v2/internal/system/packagemanager/nixpkgs.go new file mode 100644 index 00000000..360473d2 --- /dev/null +++ b/v2/internal/system/packagemanager/nixpkgs.go @@ -0,0 +1,159 @@ +//go:build linux +// +build linux + +package packagemanager + +import ( + "encoding/json" + "github.com/wailsapp/wails/v2/internal/shell" +) + +// Nixpkgs represents the Nixpkgs manager +type Nixpkgs struct { + name string + osid string +} + +type NixPackageDetail struct { + Name string + Pname string + Version string +} + +var available map[string]NixPackageDetail + +// NewNixpkgs creates a new Nixpkgs instance +func NewNixpkgs(osid string) *Nixpkgs { + available = map[string]NixPackageDetail{} + + return &Nixpkgs{ + name: "nixpkgs", + osid: osid, + } +} + +// Packages returns the libraries that we need for Wails to compile +// They will potentially differ on different distributions or versions +func (n *Nixpkgs) Packages() packagemap { + // Currently, only support checking the default channel. + channel := "nixpkgs" + if n.osid == "nixos" { + channel = "nixos" + } + + return packagemap{ + "libgtk-3": []*Package{ + {Name: channel + ".gtk3", SystemPackage: true, Library: true}, + }, + "libwebkit": []*Package{ + {Name: channel + ".webkitgtk", SystemPackage: true, Library: true}, + }, + "gcc": []*Package{ + {Name: channel + ".gcc", SystemPackage: true}, + }, + "pkg-config": []*Package{ + {Name: channel + ".pkg-config", SystemPackage: true}, + }, + "npm": []*Package{ + {Name: channel + ".nodejs", SystemPackage: true}, + }, + "upx": []*Package{ + {Name: channel + ".upx", SystemPackage: true, Optional: true}, + }, + "docker": []*Package{ + {Name: channel + ".docker", SystemPackage: true, Optional: true}, + }, + "nsis": []*Package{ + {Name: channel + ".nsis", SystemPackage: true, Optional: true}, + }, + } +} + +// Name returns the name of the package manager +func (n *Nixpkgs) Name() string { + return n.name +} + +// PackageInstalled tests if the given package name is installed +func (n *Nixpkgs) PackageInstalled(pkg *Package) (bool, error) { + if pkg.SystemPackage == false { + return false, nil + } + + stdout, _, err := shell.RunCommand(".", "nix-env", "--json", "-qA", pkg.Name) + if err != nil { + return false, nil + } + + var attributes map[string]NixPackageDetail + err = json.Unmarshal([]byte(stdout), &attributes) + if err != nil { + return false, err + } + + // Did we get one? + installed := false + for attribute, detail := range attributes { + if attribute == pkg.Name { + installed = true + pkg.Version = detail.Version + } + break + } + + // If on NixOS, package may be installed via system config, so check the nix store. + detail, ok := available[pkg.Name] + if !installed && n.osid == "nixos" && ok { + cmd := "nix-store --query --requisites /run/current-system | cut -d- -f2- | sort | uniq | grep '^" + detail.Pname + "'" + + if pkg.Library { + cmd += " | grep 'dev$'" + } + + stdout, _, err = shell.RunCommand(".", "sh", "-c", cmd) + if err != nil { + return false, nil + } + + if len(stdout) > 0 { + installed = true + } + } + + return installed, nil +} + +// PackageAvailable tests if the given package is available for installation +func (n *Nixpkgs) PackageAvailable(pkg *Package) (bool, error) { + if pkg.SystemPackage == false { + return false, nil + } + + stdout, _, err := shell.RunCommand(".", "nix-env", "--json", "-qaA", pkg.Name) + if err != nil { + return false, nil + } + + var attributes map[string]NixPackageDetail + err = json.Unmarshal([]byte(stdout), &attributes) + if err != nil { + return false, err + } + + // Grab first version. + for attribute, detail := range attributes { + pkg.Version = detail.Version + available[attribute] = detail + break + } + + return len(pkg.Version) > 0, nil +} + +// InstallCommand returns the package manager specific command to install a package +func (n *Nixpkgs) InstallCommand(pkg *Package) string { + if pkg.SystemPackage == false { + return pkg.InstallCommand[n.osid] + } + return "nix-env -iA " + pkg.Name +} diff --git a/v2/internal/system/packagemanager/packagemanager.go b/v2/internal/system/packagemanager/packagemanager.go index 6bc6784d..043c8e3c 100644 --- a/v2/internal/system/packagemanager/packagemanager.go +++ b/v2/internal/system/packagemanager/packagemanager.go @@ -18,6 +18,7 @@ var pmcommands = []string{ "pacman", "emerge", "zypper", + "nix-env", } // Find will attempt to find the system package manager @@ -46,19 +47,21 @@ func newPackageManager(pmname string, osid string) PackageManager { return NewEmerge(osid) case "zypper": return NewZypper(osid) + case "nix-env": + return NewNixpkgs(osid) } return nil } -// Dependancies scans the system for required dependancies -// Returns a list of dependancies search for, whether they were found +// Dependencies scans the system for required dependencies +// Returns a list of dependencies search for, whether they were found // and whether they were installed -func Dependancies(p PackageManager) (DependencyList, error) { +func Dependencies(p PackageManager) (DependencyList, error) { var dependencies DependencyList for name, packages := range p.Packages() { - dependency := &Dependancy{Name: name} + dependency := &Dependency{Name: name} for _, pkg := range packages { dependency.Optional = pkg.Optional dependency.External = !pkg.SystemPackage diff --git a/v2/internal/system/packagemanager/pm.go b/v2/internal/system/packagemanager/pm.go index c66d0d36..dfd39429 100644 --- a/v2/internal/system/packagemanager/pm.go +++ b/v2/internal/system/packagemanager/pm.go @@ -21,8 +21,8 @@ type PackageManager interface { InstallCommand(*Package) string } -// Dependancy represents a system package that we require -type Dependancy struct { +// Dependency represents a system package that we require +type Dependency struct { Name string PackageName string Installed bool @@ -33,7 +33,7 @@ type Dependancy struct { } // DependencyList is a list of Dependency instances -type DependencyList []*Dependancy +type DependencyList []*Dependency // InstallAllRequiredCommand returns the command you need to use to install all required dependencies func (d DependencyList) InstallAllRequiredCommand() string { diff --git a/v2/internal/system/system.go b/v2/internal/system/system.go index 98f7f7f0..455f171e 100644 --- a/v2/internal/system/system.go +++ b/v2/internal/system/system.go @@ -32,7 +32,7 @@ func GetInfo() (*Info, error) { return &result, nil } -func checkNPM() *packagemanager.Dependancy { +func checkNPM() *packagemanager.Dependency { // Check for npm output, err := exec.Command("npm", "-version").Output() @@ -43,7 +43,7 @@ func checkNPM() *packagemanager.Dependancy { } else { version = strings.TrimSpace(strings.Split(string(output), "\n")[0]) } - return &packagemanager.Dependancy{ + return &packagemanager.Dependency{ Name: "npm ", PackageName: "N/A", Installed: installed, @@ -54,7 +54,7 @@ func checkNPM() *packagemanager.Dependancy { } } -func checkUPX() *packagemanager.Dependancy { +func checkUPX() *packagemanager.Dependency { // Check for npm output, err := exec.Command("upx", "-V").Output() @@ -65,7 +65,7 @@ func checkUPX() *packagemanager.Dependancy { } else { version = strings.TrimSpace(strings.Split(string(output), "\n")[0]) } - return &packagemanager.Dependancy{ + return &packagemanager.Dependency{ Name: "upx ", PackageName: "N/A", Installed: installed, @@ -76,7 +76,7 @@ func checkUPX() *packagemanager.Dependancy { } } -func checkNSIS() *packagemanager.Dependancy { +func checkNSIS() *packagemanager.Dependency { // Check for nsis installer output, err := exec.Command("makensis", "-VERSION").Output() @@ -87,7 +87,7 @@ func checkNSIS() *packagemanager.Dependancy { } else { version = strings.TrimSpace(strings.Split(string(output), "\n")[0]) } - return &packagemanager.Dependancy{ + return &packagemanager.Dependency{ Name: "nsis ", PackageName: "N/A", Installed: installed, @@ -98,12 +98,12 @@ func checkNSIS() *packagemanager.Dependancy { } } -func checkLibrary(name string) func() *packagemanager.Dependancy { - return func() *packagemanager.Dependancy { +func checkLibrary(name string) func() *packagemanager.Dependency { + return func() *packagemanager.Dependency { output, _, _ := shell.RunCommand(".", "pkg-config", "--cflags", name) installed := len(strings.TrimSpace(output)) > 0 - return &packagemanager.Dependancy{ + return &packagemanager.Dependency{ Name: "lib" + name + " ", PackageName: "N/A", Installed: installed, @@ -115,7 +115,7 @@ func checkLibrary(name string) func() *packagemanager.Dependancy { } } -func checkDocker() *packagemanager.Dependancy { +func checkDocker() *packagemanager.Dependency { // Check for npm output, err := exec.Command("docker", "version").Output() @@ -139,7 +139,7 @@ func checkDocker() *packagemanager.Dependancy { } } } - return &packagemanager.Dependancy{ + return &packagemanager.Dependency{ Name: "docker ", PackageName: "N/A", Installed: installed, diff --git a/v2/internal/system/system_darwin.go b/v2/internal/system/system_darwin.go index b683f4fd..6d524603 100644 --- a/v2/internal/system/system_darwin.go +++ b/v2/internal/system/system_darwin.go @@ -42,7 +42,7 @@ func (i *Info) discover() error { version = strings.TrimSpace(version) version = strings.TrimSuffix(version, ".") } - xcodeDep := &packagemanager.Dependancy{ + xcodeDep := &packagemanager.Dependency{ Name: "xcode command line tools ", PackageName: "N/A", Installed: installed, diff --git a/v2/internal/system/system_linux.go b/v2/internal/system/system_linux.go index 23775ec2..8c51c4ab 100644 --- a/v2/internal/system/system_linux.go +++ b/v2/internal/system/system_linux.go @@ -8,11 +8,11 @@ import ( "github.com/wailsapp/wails/v2/internal/system/packagemanager" ) -func checkGCC() *packagemanager.Dependancy { +func checkGCC() *packagemanager.Dependency { version := packagemanager.AppVersion("gcc") - return &packagemanager.Dependancy{ + return &packagemanager.Dependency{ Name: "gcc ", PackageName: "N/A", Installed: version != "", @@ -23,11 +23,11 @@ func checkGCC() *packagemanager.Dependancy { } } -func checkPkgConfig() *packagemanager.Dependancy { +func checkPkgConfig() *packagemanager.Dependency { version := packagemanager.AppVersion("pkg-config") - return &packagemanager.Dependancy{ + return &packagemanager.Dependency{ Name: "pkg-config ", PackageName: "N/A", Installed: version != "", @@ -38,7 +38,7 @@ func checkPkgConfig() *packagemanager.Dependancy { } } -func checkLocallyInstalled(checker func() *packagemanager.Dependancy, dependency *packagemanager.Dependancy) { +func checkLocallyInstalled(checker func() *packagemanager.Dependency, dependency *packagemanager.Dependency) { if !dependency.Installed { locallyInstalled := checker() if locallyInstalled.Installed { @@ -48,7 +48,7 @@ func checkLocallyInstalled(checker func() *packagemanager.Dependancy, dependency } } -var checkerFunctions = map[string]func() *packagemanager.Dependancy{ +var checkerFunctions = map[string]func() *packagemanager.Dependency{ "npm": checkNPM, "docker": checkDocker, "upx": checkUPX, @@ -69,7 +69,7 @@ func (i *Info) discover() error { i.PM = packagemanager.Find(osinfo.ID) if i.PM != nil { - dependencies, err := packagemanager.Dependancies(i.PM) + dependencies, err := packagemanager.Dependencies(i.PM) if err != nil { return err } diff --git a/v2/internal/system/system_windows.go b/v2/internal/system/system_windows.go index 3d1b8dc7..d75bdf9e 100644 --- a/v2/internal/system/system_windows.go +++ b/v2/internal/system/system_windows.go @@ -22,16 +22,16 @@ func (i *Info) discover() error { i.Dependencies = append(i.Dependencies, checkNPM()) i.Dependencies = append(i.Dependencies, checkUPX()) i.Dependencies = append(i.Dependencies, checkNSIS()) - //i.Dependencies = append(i.Dependencies, checkDocker()) + // i.Dependencies = append(i.Dependencies, checkDocker()) return nil } -func checkWebView2() *packagemanager.Dependancy { +func checkWebView2() *packagemanager.Dependency { version, _ := webviewloader.GetWebviewVersion("") installed := version != "" - return &packagemanager.Dependancy{ + return &packagemanager.Dependency{ Name: "WebView2 ", PackageName: "N/A", Installed: installed, diff --git a/website/docs/guides/linux-distro-support.mdx b/website/docs/guides/linux-distro-support.mdx index 36649fc1..db9dde55 100644 --- a/website/docs/guides/linux-distro-support.mdx +++ b/website/docs/guides/linux-distro-support.mdx @@ -11,6 +11,7 @@ manager. Currently, we support the following package managers: - dnf - emerge - eopkg +- nixpkgs - pacman - zypper