2018-12-16 18:28:18 +11:00
package cmd
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
2020-07-08 15:57:34 +02:00
"os"
2018-12-16 18:28:18 +11:00
"path/filepath"
2018-12-26 16:27:07 +11:00
"runtime"
2018-12-16 18:28:18 +11:00
"strconv"
"time"
)
2018-12-16 18:31:49 +11:00
// SystemHelper - Defines everything related to the system
2018-12-16 18:28:18 +11:00
type SystemHelper struct {
log * Logger
fs * FSHelper
configFilename string
homeDir string
wailsSystemDir string
wailsSystemConfig string
}
2018-12-16 18:31:49 +11:00
// NewSystemHelper - Creates a new System Helper
2018-12-16 18:28:18 +11:00
func NewSystemHelper () * SystemHelper {
result := & SystemHelper {
fs : NewFSHelper (),
log : NewLogger (),
configFilename : "wails.json" ,
}
result . setSystemDirs ()
return result
}
// Internal
// setSystemDirs calculates the system directories it is interested in
func ( s * SystemHelper ) setSystemDirs () {
var err error
2020-09-02 07:07:12 +10:00
s . homeDir , err = os . UserHomeDir ()
2018-12-16 18:28:18 +11:00
if err != nil {
log . Fatal ( "Cannot find home directory! Please file a bug report!" )
}
2020-07-09 01:36:38 +02:00
2018-12-16 18:28:18 +11:00
// TODO: A better config system
2020-09-02 07:07:12 +10:00
s . wailsSystemDir = filepath . Join ( s . homeDir , ".wails" )
2018-12-16 18:28:18 +11:00
s . wailsSystemConfig = filepath . Join ( s . wailsSystemDir , s . configFilename )
}
// ConfigFileExists - Returns true if it does!
func ( s * SystemHelper ) ConfigFileExists () bool {
return s . fs . FileExists ( s . wailsSystemConfig )
}
// SystemDirExists - Returns true if it does!
func ( s * SystemHelper ) systemDirExists () bool {
return s . fs . DirExists ( s . wailsSystemDir )
}
// LoadConfig attempts to load the Wails system config
func ( s * SystemHelper ) LoadConfig () ( * SystemConfig , error ) {
return NewSystemConfig ( s . wailsSystemConfig )
}
// ConfigFileIsValid checks if the config file is valid
func ( s * SystemHelper ) ConfigFileIsValid () bool {
_ , err := NewSystemConfig ( s . wailsSystemConfig )
return err == nil
}
2019-05-20 18:44:14 +10:00
// GetAuthor returns a formatted string of the user's name and email
func ( s * SystemHelper ) GetAuthor () ( string , error ) {
var config * SystemConfig
config , err := s . LoadConfig ()
if err != nil {
return "" , err
}
return fmt . Sprintf ( "%s <%s>" , config . Name , config . Email ), nil
}
2018-12-16 18:28:18 +11:00
// BackupConfig attempts to backup the system config file
func ( s * SystemHelper ) BackupConfig () ( string , error ) {
now := strconv . FormatInt ( time . Now (). UTC (). UnixNano (), 10 )
backupFilename := s . wailsSystemConfig + "." + now
err := s . fs . CopyFile ( s . wailsSystemConfig , backupFilename )
if err != nil {
return "" , err
}
return backupFilename , nil
}
func ( s * SystemHelper ) setup () error {
2019-03-29 08:25:09 +11:00
systemConfig := make ( map [ string ] string )
2018-12-16 18:28:18 +11:00
// Try to load current values - ignore errors
2019-03-29 08:25:09 +11:00
config , _ := s . LoadConfig ()
if config . Name != "" {
systemConfig [ "name" ] = PromptRequired ( "What is your name" , config . Name )
2021-03-27 21:06:02 +11:00
} else if n , err := getGitConfigValue ( "user.name" ); err == nil && n != "" {
systemConfig [ "name" ] = PromptRequired ( "What is your name" , n )
2019-03-29 08:25:09 +11:00
} else {
systemConfig [ "name" ] = PromptRequired ( "What is your name" )
}
2021-03-27 21:06:02 +11:00
2019-03-29 08:25:09 +11:00
if config . Email != "" {
systemConfig [ "email" ] = PromptRequired ( "What is your email address" , config . Email )
2021-03-27 21:06:02 +11:00
} else if e , err := getGitConfigValue ( "user.email" ); err == nil && e != "" {
systemConfig [ "email" ] = PromptRequired ( "What is your email address" , e )
2019-03-29 08:25:09 +11:00
} else {
systemConfig [ "email" ] = PromptRequired ( "What is your email address" )
2018-12-16 18:28:18 +11:00
}
// Create the directory
2019-03-29 08:25:09 +11:00
err := s . fs . MkDirs ( s . wailsSystemDir )
2018-12-16 18:28:18 +11:00
if err != nil {
return err
}
2019-02-19 19:37:45 +11:00
// Save
configData , err := json . Marshal ( & systemConfig )
if err != nil {
return err
}
err = ioutil . WriteFile ( s . wailsSystemConfig , configData , 0755 )
if err != nil {
return err
}
2018-12-16 18:28:18 +11:00
fmt . Println ()
s . log . White ( "Wails config saved to: " + s . wailsSystemConfig )
s . log . White ( "Feel free to customise these settings." )
fmt . Println ()
2019-02-19 19:37:45 +11:00
return nil
2018-12-16 18:28:18 +11:00
}
2018-12-23 17:33:44 +11:00
const introText = `
2020-07-08 15:57:34 +02:00
Wails is a lightweight framework for creating web-like desktop apps in Go.
2018-12-23 17:33:44 +11:00
I'll need to ask you a few questions so I can fill in your project templates and then I will try and see if you have the correct dependencies installed. If you don't have the right tools installed, I'll try and suggest how to install them.
`
2018-12-26 16:27:07 +11:00
// CheckInitialised checks if the system has been set up
// and if not, runs setup
func ( s * SystemHelper ) CheckInitialised () error {
if ! s . systemDirExists () {
s . log . Yellow ( "System not initialised. Running setup." )
return s . setup ()
}
return nil
}
2018-12-16 18:28:18 +11:00
// Initialise attempts to set up the Wails system.
// An error is returns if there is a problem
func ( s * SystemHelper ) Initialise () error {
// System dir doesn't exist
if ! s . systemDirExists () {
s . log . Green ( "Welcome to Wails!" )
2018-12-23 17:33:44 +11:00
s . log . Green ( introText )
2018-12-16 18:28:18 +11:00
return s . setup ()
}
// Config doesn't exist
if ! s . ConfigFileExists () {
s . log . Green ( "Looks like the system config is missing." )
s . log . Green ( "To get you back on track, I'll need to ask you a few things..." )
return s . setup ()
}
// Config exists but isn't valid.
if ! s . ConfigFileIsValid () {
s . log . Green ( "Looks like the system config got corrupted." )
backupFile , err := s . BackupConfig ()
if err != nil {
s . log . Green ( "I tried to backup your config file but got this error: %s" , err . Error ())
} else {
s . log . Green ( "Just in case you needed it, I backed up your config file here: %s" , backupFile )
}
s . log . Green ( "To get you back on track, I'll need to ask you a few things..." )
return s . setup ()
}
return s . setup ()
}
2021-03-27 21:06:02 +11:00
// SystemConfig - Defines system wide configuration data
2018-12-16 18:28:18 +11:00
type SystemConfig struct {
Name string `json:"name"`
Email string `json:"email"`
}
2018-12-16 18:31:49 +11:00
// NewSystemConfig - Creates a new SystemConfig helper object
2018-12-16 18:28:18 +11:00
func NewSystemConfig ( filename string ) ( * SystemConfig , error ) {
result := & SystemConfig {}
err := result . load ( filename )
return result , err
}
2018-12-16 18:31:49 +11:00
// Save - Saves the system config to the given filename
2018-12-16 18:28:18 +11:00
func ( sc * SystemConfig ) Save ( filename string ) error {
// Convert config to JSON string
theJSON , err := json . MarshalIndent ( sc , "" , " " )
if err != nil {
return err
}
// Write it out to the config file
return ioutil . WriteFile ( filename , theJSON , 0644 )
}
func ( sc * SystemConfig ) load ( filename string ) error {
configData , err := ioutil . ReadFile ( filename )
if err != nil {
return err
}
// Load and unmarshall!
err = json . Unmarshal ( configData , & sc )
if err != nil {
return err
}
return nil
}
2018-12-26 16:27:07 +11:00
2019-01-10 22:48:54 +11:00
// CheckDependenciesSilent checks for dependencies but
// only outputs if there's an error
2019-01-09 08:26:19 +11:00
func CheckDependenciesSilent ( logger * Logger ) ( bool , error ) {
logger . SetErrorOnly ( true )
result , err := CheckDependencies ( logger )
logger . SetErrorOnly ( false )
return result , err
}
2018-12-26 16:27:07 +11:00
// CheckDependencies will look for Wails dependencies on the system
// Errors are reported in error and the bool return value is whether
// the dependencies are all installed.
2019-01-07 22:58:25 +11:00
func CheckDependencies ( logger * Logger ) ( bool , error ) {
2018-12-26 16:27:07 +11:00
switch runtime . GOOS {
case "darwin" :
logger . Yellow ( "Detected Platform: OSX" )
case "windows" :
logger . Yellow ( "Detected Platform: Windows" )
case "linux" :
logger . Yellow ( "Detected Platform: Linux" )
default :
2019-01-07 22:58:25 +11:00
return false , fmt . Errorf ( "Platform %s is currently not supported" , runtime . GOOS )
2018-12-26 16:27:07 +11:00
}
logger . Yellow ( "Checking for prerequisites..." )
// Check we have a cgo capable environment
requiredPrograms , err := GetRequiredPrograms ()
if err != nil {
2019-01-07 22:58:25 +11:00
return false , nil
2018-12-26 16:27:07 +11:00
}
errors := false
programHelper := NewProgramHelper ()
for _ , program := range * requiredPrograms {
bin := programHelper . FindProgram ( program . Name )
if bin == nil {
errors = true
2019-05-09 19:31:07 +10:00
logger . Error ( "Program '%s' not found. %s" , program . Name , program . Help )
2018-12-26 16:27:07 +11:00
} else {
2019-01-07 22:58:25 +11:00
logger . Green ( "Program '%s' found: %s" , program . Name , bin . Path )
2018-12-26 16:27:07 +11:00
}
}
// Linux has library deps
if runtime . GOOS == "linux" {
// Check library prerequisites
requiredLibraries , err := GetRequiredLibraries ()
if err != nil {
2019-01-07 22:58:25 +11:00
return false , err
2018-12-26 16:27:07 +11:00
}
2019-10-08 06:12:08 +11:00
var libraryChecker CheckPkgInstalled
2018-12-26 16:27:07 +11:00
distroInfo := GetLinuxDistroInfo ()
2019-10-08 06:12:08 +11:00
switch distroInfo . Distribution {
2020-05-27 06:54:32 +10:00
case Ubuntu , Debian , Zorin , Parrot , Linuxmint , Elementary , Kali , Neon , Deepin , Raspbian , PopOS :
2019-10-08 06:12:08 +11:00
libraryChecker = DpkgInstalled
2021-10-11 17:16:24 +02:00
case Arch , ArcoLinux , ArchLabs , Ctlos , Manjaro , ManjaroARM , EndeavourOS , ArtixLinux :
2019-10-08 06:12:08 +11:00
libraryChecker = PacmanInstalled
2021-04-03 16:15:32 +11:00
case CentOS , Fedora , Tumbleweed , Leap , RHEL :
2019-10-08 06:12:08 +11:00
libraryChecker = RpmInstalled
case Gentoo :
libraryChecker = EqueryInstalled
case VoidLinux :
libraryChecker = XbpsInstalled
2020-05-27 10:16:44 +10:00
case Solus :
libraryChecker = EOpkgInstalled
2021-03-27 21:06:02 +11:00
case Crux :
libraryChecker = PrtGetInstalled
2021-08-30 19:15:10 +01:00
case NixOS :
libraryChecker = NixEnvInstalled
2019-10-08 06:12:08 +11:00
default :
return false , RequestSupportForDistribution ( distroInfo )
}
2018-12-26 16:27:07 +11:00
for _ , library := range * requiredLibraries {
2019-10-08 06:12:08 +11:00
installed , err := libraryChecker ( library . Name )
if err != nil {
return false , err
}
if ! installed {
errors = true
logger . Error ( "Library '%s' not found. %s" , library . Name , library . Help )
} else {
logger . Green ( "Library '%s' installed." , library . Name )
2018-12-26 16:27:07 +11:00
}
}
}
2019-01-09 08:26:19 +11:00
logger . White ( "" )
2018-12-26 16:27:07 +11:00
2019-01-07 22:58:25 +11:00
return ! errors , err
2018-12-26 16:27:07 +11:00
}