From 807f77205594435d1627a07dc6f92816d62964aa Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sat, 22 Dec 2018 18:40:36 -0800 Subject: [PATCH] feat: support checking prerequisites --- cmd/linux.go | 32 ++++++++-- cmd/prerequisites.go | 140 +++++++++++++++++++++++-------------------- cmd/wails/0_setup.go | 57 +++++++++++++----- 3 files changed, 144 insertions(+), 85 deletions(-) diff --git a/cmd/linux.go b/cmd/linux.go index baecd48e4..b812d3fb6 100644 --- a/cmd/linux.go +++ b/cmd/linux.go @@ -1,6 +1,7 @@ package cmd import ( + "fmt" "strings" ) @@ -8,8 +9,9 @@ import ( type LinuxDistribution int const ( - // Ubuntu distro - Ubuntu LinuxDistribution = 0 + // Unknown is the catch-all distro + Unknown LinuxDistribution = 0 + Ubuntu LinuxDistribution = 1 ) // DistroInfo contains all the information relating to a linux distribution @@ -18,11 +20,12 @@ type DistroInfo struct { Description string Release string Codename string - DistributorId string + DistributorID string } +// GetLinuxDistroInfo returns information about the running linux distribution func GetLinuxDistroInfo() *DistroInfo { - result := &DistroInfo{} + result := &DistroInfo{Distribution: Unknown} program := NewProgramHelper() // Does lsb_release exist? @@ -30,7 +33,7 @@ func GetLinuxDistroInfo() *DistroInfo { if lsbRelease != nil { stdout, _, err, _ := lsbRelease.Run("-a") if err != nil { - return nil + return result } for _, line := range strings.Split(stdout, "\n") { @@ -41,7 +44,11 @@ func GetLinuxDistroInfo() *DistroInfo { value := strings.TrimSpace(details[1]) switch key { case "Distributor ID": - result.DistributorId = value + result.DistributorID = value + switch value { + case "Ubuntu": + result.Distribution = Ubuntu + } case "Description": result.Description = value case "Release": @@ -56,3 +63,16 @@ func GetLinuxDistroInfo() *DistroInfo { } return result } + +// DpkgInstalled uses dpkg to see if a package is installed +func DpkgInstalled(packageName string) (bool, error) { + result := false + program := NewProgramHelper() + dpkg := program.FindProgram("dpkg") + if dpkg == nil { + return false, fmt.Errorf("cannot check dependencies: dpkg not found") + } + _, _, _, exitCode := dpkg.Run("-L", packageName) + result = exitCode == 0 + return result, nil +} diff --git a/cmd/prerequisites.go b/cmd/prerequisites.go index d5dcd2c78..9b78bc8b2 100644 --- a/cmd/prerequisites.go +++ b/cmd/prerequisites.go @@ -5,88 +5,100 @@ import ( "runtime" ) -// binaryPrerequisite defines a binaryPrerequisite -type binaryPrerequisite struct { +// Prerequisite defines a Prerequisite! +type Prerequisite struct { Name string Help string Path string } -func newBinaryPrerequisite(name, help string) *binaryPrerequisite { - return &binaryPrerequisite{Name: name, Help: help} +func newPrerequisite(name, help string) *Prerequisite { + return &Prerequisite{Name: name, Help: help} } -// binaryPrerequisites is a list of binaryPrerequisites -type binaryPrerequisites []*binaryPrerequisite +// Prerequisites is a list of things required to use Wails +type Prerequisites []*Prerequisite // Add given prereq object to list -func (p *binaryPrerequisites) Add(prereq *binaryPrerequisite) { +func (p *Prerequisites) Add(prereq *Prerequisite) { *p = append(*p, prereq) } -func (p *binaryPrerequisites) check() (success *binaryPrerequisites, failed *binaryPrerequisites) { - success = &binaryPrerequisites{} - failed = &binaryPrerequisites{} - programHelper := NewProgramHelper() - for _, prereq := range *p { - bin := programHelper.FindProgram(prereq.Name) - if bin == nil { - failed.Add(prereq) - } else { - path, err := bin.GetFullPathToBinary() - if err != nil { - failed.Add(prereq) - } else { - prereq.Path = path - success.Add(prereq) - } - } - } - - return success, failed -} - -var platformbinaryPrerequisites = make(map[string]*binaryPrerequisites) - -func init() { - platformbinaryPrerequisites["darwin"] = &binaryPrerequisites{} - newDarwinbinaryPrerequisite("clang", "Please install with `xcode-select --install` and try again") - platformbinaryPrerequisites["linux"] = &binaryPrerequisites{} - linuxInfo := GetLinuxDistroInfo() - switch linuxInfo.Distribution { - case Ubuntu: - newLinuxbinaryPrerequisite("gcc", "Please install with 'sudo apt install build-essential' ") +// GetRequiredPrograms returns a list of programs required for the platform +func GetRequiredPrograms() (*Prerequisites, error) { + switch runtime.GOOS { + case "darwin": + return getRequiredProgramsOSX(), nil + case "linux": + return getRequiredProgramsLinux(), nil + case "windows": + return getRequiredProgramsWindows(), nil default: - newLinuxbinaryPrerequisite("gcc", "Please install with your system package manager.") + return nil, fmt.Errorf("platform '%s' not supported at this time", runtime.GOOS) } } -func newDarwinbinaryPrerequisite(name, help string) { - prereq := newBinaryPrerequisite(name, help) - platformbinaryPrerequisites["darwin"].Add(prereq) +func getRequiredProgramsOSX() *Prerequisites { + result := &Prerequisites{} + result.Add(newPrerequisite("clang", "Please install with `xcode-select --install` and try again")) + return result } -func newLinuxbinaryPrerequisite(name, help string) { - prereq := newBinaryPrerequisite(name, help) - platformbinaryPrerequisites["linux"].Add(prereq) -} - -func CheckBinaryPrerequisites() (*binaryPrerequisites, *binaryPrerequisites, error) { - platformPreReqs := platformbinaryPrerequisites[runtime.GOOS] - if platformPreReqs == nil { - return nil, nil, fmt.Errorf("Platform '%s' is not supported at this time", runtime.GOOS) - } - success, failed := platformPreReqs.check() - return success, failed, nil -} - -func CheckNonBinaryPrerequisites() error { - - var err error - - // Check non-binaries - if runtime.GOOS == "linux" { +func getRequiredProgramsLinux() *Prerequisites { + result := &Prerequisites{} + distroInfo := GetLinuxDistroInfo() + switch distroInfo.Distribution { + case Ubuntu: + result.Add(newPrerequisite("gcc", "Please install with `sudo apt install build-essentials` and try again")) + result.Add(newPrerequisite("pkg-config", "Please install with `sudo apt install pkg-config` and try again")) + default: + result.Add(newPrerequisite("gcc", "Please install with your system package manager and try again")) + result.Add(newPrerequisite("pkg-config", "Please install with your system package manager and try again")) } - return err + return result +} + +// TODO: Test this on Windows +func getRequiredProgramsWindows() *Prerequisites { + result := &Prerequisites{} + return result +} + +// GetRequiredLibraries returns a list of libraries (packages) required for the platform +func GetRequiredLibraries() (*Prerequisites, error) { + switch runtime.GOOS { + case "darwin": + return getRequiredLibrariesOSX() + case "linux": + return getRequiredLibrariesLinux() + case "windows": + return getRequiredLibrariesWindows() + default: + return nil, fmt.Errorf("platform '%s' not supported at this time", runtime.GOOS) + } +} + +func getRequiredLibrariesOSX() (*Prerequisites, error) { + result := &Prerequisites{} + return result, nil +} + +func getRequiredLibrariesLinux() (*Prerequisites, error) { + result := &Prerequisites{} + distroInfo := GetLinuxDistroInfo() + switch distroInfo.Distribution { + case Ubuntu: + result.Add(newPrerequisite("libgtk-3-dev", "Please install with `sudo apt install libgtk-3-dev` and try again")) + result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with `sudo apt install libwebkit2gtk-4.0-dev` and try again")) + default: + result.Add(newPrerequisite("libgtk-3-dev", "Please install with your system package manager and try again")) + result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with your system package manager and try again")) + } + return result, nil +} + +func getRequiredLibrariesWindows() (*Prerequisites, error) { + result := &Prerequisites{} + return result, nil } diff --git a/cmd/wails/0_setup.go b/cmd/wails/0_setup.go index 9af45f971..d90328ed4 100644 --- a/cmd/wails/0_setup.go +++ b/cmd/wails/0_setup.go @@ -4,6 +4,7 @@ import ( "fmt" "runtime" + "github.com/leaanthony/spinner" "github.com/wailsapp/wails/cmd" ) @@ -41,29 +42,55 @@ Create your first project by running 'wails init'.` logger.Yellow("Checking for prerequisites...") // Check we have a cgo capable environment - successDeps, failedDeps, err := cmd.CheckBinaryPrerequisites() + requiredPrograms, err := cmd.GetRequiredPrograms() if err != nil { return err } + errors := false + spinner := spinner.New() + programHelper := cmd.NewProgramHelper() + for _, program := range *requiredPrograms { + spinner.Start("Looking for program '%s'", program.Name) + bin := programHelper.FindProgram(program.Name) + if bin == nil { + errors = true + spinner.Errorf("Program '%s' not found. %s", program.Name, program.Help) + } else { + spinner.Successf("Program '%s' found: %s", program.Name, bin.Path) + } + } - for _, dep := range *successDeps { - logger.Green("Found '%s' at '%s'", dep.Name, dep.Path) + // Linux has library deps + if runtime.GOOS == "linux" { + // Check library prerequisites + requiredLibraries, err := cmd.GetRequiredLibraries() + if err != nil { + return err + } + distroInfo := cmd.GetLinuxDistroInfo() + for _, library := range *requiredLibraries { + spinner.Start() + switch distroInfo.Distribution { + case cmd.Ubuntu: + installed, err := cmd.DpkgInstalled(library.Name) + if err != nil { + return err + } + if !installed { + errors = true + spinner.Errorf("Library '%s' not found. %s", library.Name, library.Help) + } else { + spinner.Successf("Library '%s' installed.", library.Name) + } + default: + return fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name) + } + } } logger.White("") - for _, dep := range *failedDeps { - logger.Red("PreRequisite '%s' missing. %s", dep.Name, dep.Help) - } - - // Check non-binary prerequisites - err = cmd.CheckNonBinaryPrerequisites() - - if err != nil { - return err - } - - if len(*failedDeps) == 0 { + if !errors { logger.Yellow(successMessage) }