2018-12-16 20:16:40 +11:00
package cmd
2018-12-19 12:49:04 -08:00
import (
2018-12-22 18:40:36 -08:00
"fmt"
2019-05-10 17:41:30 +12:00
"io/ioutil"
2019-06-24 09:11:06 +10:00
"net/url"
2019-05-10 17:41:30 +12:00
"os"
2019-06-25 08:13:20 +10:00
"runtime"
2018-12-19 12:49:04 -08:00
"strings"
2019-06-24 09:11:06 +10:00
"github.com/pkg/browser"
2018-12-19 12:49:04 -08:00
)
2018-12-16 20:16:40 +11:00
// LinuxDistribution is of type int
type LinuxDistribution int
const (
2018-12-22 18:40:36 -08:00
// Unknown is the catch-all distro
2019-05-02 13:35:34 +10:00
Unknown LinuxDistribution = iota
2019-10-08 06:12:08 +11:00
// Debian distribution
Debian
2018-12-23 15:37:51 +11:00
// Ubuntu distribution
2019-05-02 13:35:34 +10:00
Ubuntu
// Arch linux distribution
Arch
2019-10-08 06:12:08 +11:00
// CentOS linux distribution
CentOS
// Fedora linux distribution
Fedora
// Gentoo distribution
Gentoo
// Zorin distribution
Zorin
// Parrot distribution
Parrot
// Linuxmint distribution
Linuxmint
// VoidLinux distribution
VoidLinux
// Elementary distribution
Elementary
// Kali distribution
Kali
// Neon distribution
Neon
2020-01-01 23:14:22 +02:00
// ArcoLinux distribution
ArcoLinux
2019-10-08 06:12:08 +11:00
// Manjaro distribution
Manjaro
2020-01-08 23:38:05 +02:00
// ManjaroARM distribution
ManjaroARM
// Deepin distribution
Deepin
2020-01-10 05:07:42 -06:00
// Raspbian distribution
Raspbian
2020-05-17 20:17:00 +10:00
// Tumbleweed (OpenSUSE) distribution
2020-04-19 12:20:27 +02:00
Tumbleweed
2020-05-17 20:17:00 +10:00
// Leap (OpenSUSE) distribution
2020-04-19 12:20:27 +02:00
Leap
2020-05-17 20:17:00 +10:00
// ArchLabs distribution
ArchLabs
2020-05-27 06:54:32 +10:00
// PopOS distribution
PopOS
2020-05-27 10:16:44 +10:00
// Solus distribution
Solus
2020-09-03 14:42:03 +05:00
// Ctlos Linux distribution
Ctlos
2020-11-26 20:44:42 +11:00
// EndeavourOS linux distribution
EndeavourOS
2021-03-27 21:06:02 +11:00
// Crux linux distribution
Crux
2021-04-03 16:15:32 +11:00
// RHEL distribution
RHEL
2021-08-30 19:15:10 +01:00
// NixOS distribution
NixOS
2021-10-11 17:16:24 +02:00
// Artix linux distribution
ArtixLinux
2021-10-26 19:35:18 +11:00
2018-12-16 20:16:40 +11:00
)
// DistroInfo contains all the information relating to a linux distribution
type DistroInfo struct {
2019-10-08 06:12:08 +11:00
Distribution LinuxDistribution
Name string
ID string
Description string
Release string
2018-12-16 20:16:40 +11:00
}
2018-12-22 18:40:36 -08:00
// GetLinuxDistroInfo returns information about the running linux distribution
2018-12-19 12:49:04 -08:00
func GetLinuxDistroInfo () * DistroInfo {
2019-10-08 06:12:08 +11:00
result := & DistroInfo {
Distribution : Unknown ,
ID : "unknown" ,
Name : "Unknown" ,
}
_ , err := os . Stat ( "/etc/os-release" )
if ! os . IsNotExist ( err ) {
2019-05-10 17:41:30 +12:00
osRelease , _ := ioutil . ReadFile ( "/etc/os-release" )
2019-10-08 06:12:08 +11:00
result = parseOsRelease ( string ( osRelease ))
2018-12-16 20:16:40 +11:00
}
return result
}
2018-12-22 18:40:36 -08:00
2019-10-08 06:12:08 +11:00
// parseOsRelease parses the given os-release data and returns
// a DistroInfo struct with the details
func parseOsRelease ( osRelease string ) * DistroInfo {
result := & DistroInfo { Distribution : Unknown }
// Default value
osID := "unknown"
osNAME := "Unknown"
version := ""
// Split into lines
lines := strings . Split ( osRelease , "\n" )
// Iterate lines
for _ , line := range lines {
// Split each line by the equals char
splitLine := strings . SplitN ( line , "=" , 2 )
// Check we have
if len ( splitLine ) != 2 {
continue
}
switch splitLine [ 0 ] {
case "ID" :
2020-05-27 12:48:28 +10:00
osID = strings . ToLower ( strings . Trim ( splitLine [ 1 ], "\"" ))
2019-10-08 06:12:08 +11:00
case "NAME" :
osNAME = strings . Trim ( splitLine [ 1 ], "\"" )
case "VERSION_ID" :
version = strings . Trim ( splitLine [ 1 ], "\"" )
}
}
2020-01-10 05:07:42 -06:00
2019-10-08 06:12:08 +11:00
// Check distro name against list of distros
2020-05-27 12:48:28 +10:00
switch osID {
2019-10-08 06:12:08 +11:00
case "fedora" :
result . Distribution = Fedora
case "centos" :
result . Distribution = CentOS
2021-04-03 16:15:32 +11:00
case "rhel" :
result . Distribution = RHEL
2019-10-08 06:12:08 +11:00
case "arch" :
result . Distribution = Arch
2020-05-17 20:17:00 +10:00
case "archlabs" :
result . Distribution = ArchLabs
2020-09-03 14:42:03 +05:00
case "ctlos" :
2020-11-26 20:44:42 +11:00
result . Distribution = Ctlos
2019-10-08 06:12:08 +11:00
case "debian" :
result . Distribution = Debian
case "ubuntu" :
result . Distribution = Ubuntu
case "gentoo" :
result . Distribution = Gentoo
case "zorin" :
result . Distribution = Zorin
case "parrot" :
result . Distribution = Parrot
case "linuxmint" :
result . Distribution = Linuxmint
case "void" :
result . Distribution = VoidLinux
case "elementary" :
result . Distribution = Elementary
case "kali" :
result . Distribution = Kali
case "neon" :
result . Distribution = Neon
2020-01-01 23:14:22 +02:00
case "arcolinux" :
result . Distribution = ArcoLinux
2019-10-08 06:12:08 +11:00
case "manjaro" :
result . Distribution = Manjaro
2020-01-08 23:38:05 +02:00
case "manjaro-arm" :
result . Distribution = ManjaroARM
case "deepin" :
result . Distribution = Deepin
2020-01-10 05:07:42 -06:00
case "raspbian" :
result . Distribution = Raspbian
2020-04-19 12:20:27 +02:00
case "opensuse-tumbleweed" :
result . Distribution = Tumbleweed
case "opensuse-leap" :
result . Distribution = Leap
2020-05-27 06:54:32 +10:00
case "pop" :
result . Distribution = PopOS
2020-05-27 10:16:44 +10:00
case "solus" :
result . Distribution = Solus
2020-11-26 20:44:42 +11:00
case "endeavouros" :
result . Distribution = EndeavourOS
2021-03-27 21:06:02 +11:00
case "crux" :
result . Distribution = Crux
2021-08-30 19:15:10 +01:00
case "nixos" :
result . Distribution = NixOS
2021-10-11 17:16:24 +02:00
case "artix" :
result . Distribution = ArtixLinux
2019-10-08 06:12:08 +11:00
default :
result . Distribution = Unknown
}
result . Name = osNAME
result . ID = osID
result . Release = version
return result
}
// CheckPkgInstalled is all functions that use local programs to see if a package is installed
type CheckPkgInstalled func ( string ) ( bool , error )
// EqueryInstalled uses equery to see if a package is installed
func EqueryInstalled ( packageName string ) ( bool , error ) {
program := NewProgramHelper ()
equery := program . FindProgram ( "equery" )
if equery == nil {
return false , fmt . Errorf ( "cannont check dependencies: equery not found" )
}
_ , _ , exitCode , _ := equery . Run ( "l" , packageName )
return exitCode == 0 , nil
}
2018-12-22 18:40:36 -08:00
// DpkgInstalled uses dpkg to see if a package is installed
func DpkgInstalled ( packageName string ) ( bool , error ) {
program := NewProgramHelper ()
dpkg := program . FindProgram ( "dpkg" )
if dpkg == nil {
return false , fmt . Errorf ( "cannot check dependencies: dpkg not found" )
}
2018-12-23 15:37:51 +11:00
_ , _ , exitCode , _ := dpkg . Run ( "-L" , packageName )
2019-04-10 08:38:46 +10:00
return exitCode == 0 , nil
2018-12-22 18:40:36 -08:00
}
2019-05-02 13:35:34 +10:00
2020-05-27 10:16:44 +10:00
// EOpkgInstalled uses dpkg to see if a package is installed
func EOpkgInstalled ( packageName string ) ( bool , error ) {
program := NewProgramHelper ()
eopkg := program . FindProgram ( "eopkg" )
if eopkg == nil {
return false , fmt . Errorf ( "cannot check dependencies: eopkg not found" )
}
2020-05-27 10:33:00 +10:00
stdout , _ , _ , _ := eopkg . Run ( "info" , packageName )
return strings . HasPrefix ( stdout , "Installed" ), nil
2020-05-27 10:16:44 +10:00
}
2019-05-02 13:35:34 +10:00
// PacmanInstalled uses pacman to see if a package is installed.
func PacmanInstalled ( packageName string ) ( bool , error ) {
program := NewProgramHelper ()
pacman := program . FindProgram ( "pacman" )
if pacman == nil {
return false , fmt . Errorf ( "cannot check dependencies: pacman not found" )
}
_ , _ , exitCode , _ := pacman . Run ( "-Qs" , packageName )
return exitCode == 0 , nil
}
2019-05-10 17:41:30 +12:00
2019-10-08 06:12:08 +11:00
// XbpsInstalled uses pacman to see if a package is installed.
func XbpsInstalled ( packageName string ) ( bool , error ) {
program := NewProgramHelper ()
xbpsQuery := program . FindProgram ( "xbps-query" )
if xbpsQuery == nil {
return false , fmt . Errorf ( "cannot check dependencies: xbps-query not found" )
}
_ , _ , exitCode , _ := xbpsQuery . Run ( "-S" , packageName )
return exitCode == 0 , nil
}
2019-05-11 12:19:18 +12:00
// RpmInstalled uses rpm to see if a package is installed
func RpmInstalled ( packageName string ) ( bool , error ) {
2019-05-10 17:41:30 +12:00
program := NewProgramHelper ()
2019-05-11 12:19:18 +12:00
rpm := program . FindProgram ( "rpm" )
if rpm == nil {
return false , fmt . Errorf ( "cannot check dependencies: rpm not found" )
2019-05-10 17:41:30 +12:00
}
2019-05-11 12:19:18 +12:00
_ , _ , exitCode , _ := rpm . Run ( "--query" , packageName )
2019-05-10 17:41:30 +12:00
return exitCode == 0 , nil
}
2019-06-24 09:11:06 +10:00
2021-03-27 21:06:02 +11:00
// PrtGetInstalled uses prt-get to see if a package is installed
func PrtGetInstalled ( packageName string ) ( bool , error ) {
program := NewProgramHelper ()
prtget := program . FindProgram ( "prt-get" )
if prtget == nil {
return false , fmt . Errorf ( "cannot check dependencies: prt-get not found" )
}
_ , _ , exitCode , _ := prtget . Run ( "isinst" , packageName )
return exitCode == 0 , nil
}
2021-08-30 19:15:10 +01:00
// NixEnvInstalled uses nix-env to see if a package is installed
func NixEnvInstalled ( packageName string ) ( bool , error ) {
program := NewProgramHelper ()
nixEnv := program . FindProgram ( "nix-env" )
if nixEnv == nil {
return false , fmt . Errorf ( "cannot check dependencies: nix-env not found" )
}
packageName = strings . ReplaceAll ( packageName , "+" , `\+` )
_ , _ , exitCode , _ := nixEnv . Run ( "-q" , packageName )
return exitCode == 0 , nil
}
2019-06-24 09:11:06 +10:00
// RequestSupportForDistribution promts the user to submit a request to support their
// currently unsupported distribution
2019-10-08 06:12:08 +11:00
func RequestSupportForDistribution ( distroInfo * DistroInfo ) error {
2019-06-24 09:11:06 +10:00
var logger = NewLogger ()
2019-10-08 06:12:08 +11:00
defaultError := fmt . Errorf ( "unable to check libraries on distribution '%s'" , distroInfo . Name )
2019-06-24 09:11:06 +10:00
2019-10-08 06:12:08 +11:00
logger . Yellow ( "Distribution '%s' is not currently supported, but we would love to!" , distroInfo . Name )
q := fmt . Sprintf ( "Would you like to submit a request to support distribution '%s'?" , distroInfo . Name )
2019-06-24 09:11:06 +10:00
result := Prompt ( q , "yes" )
if strings . ToLower ( result ) != "yes" {
return defaultError
}
2019-10-08 06:12:08 +11:00
title := fmt . Sprintf ( "Support Distribution '%s'" , distroInfo . Name )
2019-06-24 09:11:06 +10:00
2019-06-25 08:13:20 +10:00
var str strings . Builder
gomodule , exists := os . LookupEnv ( "GO111MODULE" )
if ! exists {
gomodule = "(Not Set)"
}
str . WriteString ( "\n| Name | Value |\n| ----- | ----- |\n" )
str . WriteString ( fmt . Sprintf ( "| Wails Version | %s |\n" , Version ))
str . WriteString ( fmt . Sprintf ( "| Go Version | %s |\n" , runtime . Version ()))
str . WriteString ( fmt . Sprintf ( "| Platform | %s |\n" , runtime . GOOS ))
str . WriteString ( fmt . Sprintf ( "| Arch | %s |\n" , runtime . GOARCH ))
str . WriteString ( fmt . Sprintf ( "| GO111MODULE | %s |\n" , gomodule ))
2019-10-08 06:12:08 +11:00
str . WriteString ( fmt . Sprintf ( "| Distribution ID | %s |\n" , distroInfo . ID ))
str . WriteString ( fmt . Sprintf ( "| Distribution Name | %s |\n" , distroInfo . Name ))
2019-06-25 08:13:20 +10:00
str . WriteString ( fmt . Sprintf ( "| Distribution Version | %s |\n" , distroInfo . Release ))
2019-10-08 06:12:08 +11:00
body := fmt . Sprintf ( "**Description**\nDistribution '%s' is currently unsupported.\n\n**Further Information**\n\n%s\n\n*Please add any extra information here, EG: libraries that are needed to make the distribution work, or commands to install them*" , distroInfo . ID , str . String ())
2019-06-24 09:11:06 +10:00
fullURL := "https://github.com/wailsapp/wails/issues/new?"
params := "title=" + title + "&body=" + body
fmt . Println ( "Opening browser to file request." )
browser . OpenURL ( fullURL + url . PathEscape ( params ))
2020-05-27 06:54:32 +10:00
result = Prompt ( "We have a guide for adding support for your distribution. Would you like to view it?" , "yes" )
if strings . ToLower ( result ) == "yes" {
browser . OpenURL ( "https://wails.app/guides/distro/" )
}
2019-06-24 09:11:06 +10:00
return nil
}