mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 19:50:15 +08:00
Initial commit of the Setup command
This commit is contained in:
parent
5de8efff32
commit
db550f81cd
268
cmd/cli.go
Normal file
268
cmd/cli.go
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCli - Creates a new Cli application object
|
||||||
|
func NewCli(name, description string) *Cli {
|
||||||
|
result := &Cli{}
|
||||||
|
result.rootCommand = NewCommand(name, description, result, "")
|
||||||
|
result.log = NewLogger()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cli - The main application object
|
||||||
|
type Cli struct {
|
||||||
|
rootCommand *Command
|
||||||
|
defaultCommand *Command
|
||||||
|
preRunCommand func(*Cli) error
|
||||||
|
log *Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version - Set the Application version string
|
||||||
|
func (c *Cli) Version(version string) {
|
||||||
|
c.rootCommand.AppVersion = version
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintHelp - Prints the application's help
|
||||||
|
func (c *Cli) PrintHelp() {
|
||||||
|
c.rootCommand.PrintHelp()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run - Runs the application with the given arguments
|
||||||
|
func (c *Cli) Run(args ...string) error {
|
||||||
|
if c.preRunCommand != nil {
|
||||||
|
err := c.preRunCommand(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(args) == 0 {
|
||||||
|
args = os.Args[1:]
|
||||||
|
}
|
||||||
|
return c.rootCommand.Run(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultCommand - Sets the given command as the command to run when
|
||||||
|
// no other commands given
|
||||||
|
func (c *Cli) DefaultCommand(defaultCommand *Command) *Cli {
|
||||||
|
c.defaultCommand = defaultCommand
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command - Adds a command to the application
|
||||||
|
func (c *Cli) Command(name, description string) *Command {
|
||||||
|
return c.rootCommand.Command(name, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreRun - Calls the given function before running the specific command
|
||||||
|
func (c *Cli) PreRun(callback func(*Cli) error) {
|
||||||
|
c.preRunCommand = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolFlag - Adds a boolean flag to the root command
|
||||||
|
func (c *Cli) BoolFlag(name, description string, variable *bool) *Command {
|
||||||
|
c.rootCommand.BoolFlag(name, description, variable)
|
||||||
|
return c.rootCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringFlag - Adds a string flag to the root command
|
||||||
|
func (c *Cli) StringFlag(name, description string, variable *string) *Command {
|
||||||
|
c.rootCommand.StringFlag(name, description, variable)
|
||||||
|
return c.rootCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action represents a function that gets calls when the command is called by
|
||||||
|
// the user
|
||||||
|
type Action func() error
|
||||||
|
|
||||||
|
// Command represents a command that may be run by the user
|
||||||
|
type Command struct {
|
||||||
|
Name string
|
||||||
|
CommandPath string
|
||||||
|
Shortdescription string
|
||||||
|
Longdescription string
|
||||||
|
AppVersion string
|
||||||
|
SubCommands []*Command
|
||||||
|
SubCommandsMap map[string]*Command
|
||||||
|
longestSubcommand int
|
||||||
|
ActionCallback Action
|
||||||
|
App *Cli
|
||||||
|
Flags *flag.FlagSet
|
||||||
|
flagCount int
|
||||||
|
log *Logger
|
||||||
|
helpFlag bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCommand creates a new Command
|
||||||
|
func NewCommand(name string, description string, app *Cli, parentCommandPath string) *Command {
|
||||||
|
result := &Command{
|
||||||
|
Name: name,
|
||||||
|
Shortdescription: description,
|
||||||
|
SubCommandsMap: make(map[string]*Command),
|
||||||
|
App: app,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up command path
|
||||||
|
if parentCommandPath != "" {
|
||||||
|
result.CommandPath += parentCommandPath + " "
|
||||||
|
}
|
||||||
|
result.CommandPath += name
|
||||||
|
|
||||||
|
// Set up flag set
|
||||||
|
result.Flags = flag.NewFlagSet(result.CommandPath, flag.ContinueOnError)
|
||||||
|
result.BoolFlag("help", "Get help on the '"+result.CommandPath+"' command.", &result.helpFlag)
|
||||||
|
|
||||||
|
// result.Flags.Usage = result.PrintHelp
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseFlags parses the given flags
|
||||||
|
func (c *Command) parseFlags(args []string) error {
|
||||||
|
// Parse flags
|
||||||
|
tmp := os.Stderr
|
||||||
|
os.Stderr = nil
|
||||||
|
err := c.Flags.Parse(args)
|
||||||
|
os.Stderr = tmp
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %s\n\n", err.Error())
|
||||||
|
c.PrintHelp()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run - Runs the Command with the given arguments
|
||||||
|
func (c *Command) Run(args []string) error {
|
||||||
|
|
||||||
|
// If we have arguments, process them
|
||||||
|
if len(args) > 0 {
|
||||||
|
// Check for subcommand
|
||||||
|
subcommand := c.SubCommandsMap[args[0]]
|
||||||
|
if subcommand != nil {
|
||||||
|
return subcommand.Run(args[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse flags
|
||||||
|
err := c.parseFlags(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %s\n\n", err.Error())
|
||||||
|
c.PrintHelp()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help takes precedence
|
||||||
|
if c.helpFlag {
|
||||||
|
c.PrintHelp()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have an action?
|
||||||
|
if c.ActionCallback != nil {
|
||||||
|
return c.ActionCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven't specified a subcommand
|
||||||
|
// check for an app level default command
|
||||||
|
if c.App.defaultCommand != nil {
|
||||||
|
// Prevent recursion!
|
||||||
|
if c.App.defaultCommand != c {
|
||||||
|
return c.App.defaultCommand.Run(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing left we can do
|
||||||
|
c.PrintHelp()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action - Define an action from this command
|
||||||
|
func (c *Command) Action(callback Action) *Command {
|
||||||
|
c.ActionCallback = callback
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintHelp - Output the help text for this command
|
||||||
|
func (c *Command) PrintHelp() {
|
||||||
|
versionString := c.AppVersion
|
||||||
|
if versionString != "" {
|
||||||
|
versionString = " " + versionString
|
||||||
|
}
|
||||||
|
commandTitle := c.CommandPath
|
||||||
|
if c.Shortdescription != "" {
|
||||||
|
commandTitle += " - " + c.Shortdescription
|
||||||
|
}
|
||||||
|
// Ignore root command
|
||||||
|
if c.CommandPath != c.Name {
|
||||||
|
c.log.Yellow(commandTitle)
|
||||||
|
}
|
||||||
|
if c.Longdescription != "" {
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(c.Longdescription + "\n")
|
||||||
|
}
|
||||||
|
if len(c.SubCommands) > 0 {
|
||||||
|
fmt.Println("")
|
||||||
|
c.log.White("Available commands:")
|
||||||
|
fmt.Println("")
|
||||||
|
for _, subcommand := range c.SubCommands {
|
||||||
|
spacer := strings.Repeat(" ", 3+c.longestSubcommand-len(subcommand.Name))
|
||||||
|
isDefault := ""
|
||||||
|
if subcommand.isDefaultCommand() {
|
||||||
|
isDefault = "[default]"
|
||||||
|
}
|
||||||
|
fmt.Printf(" %s%s%s %s\n", subcommand.Name, spacer, subcommand.Shortdescription, isDefault)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.flagCount > 0 {
|
||||||
|
fmt.Println("")
|
||||||
|
c.log.White("Flags:")
|
||||||
|
fmt.Println()
|
||||||
|
c.Flags.SetOutput(os.Stdout)
|
||||||
|
c.Flags.PrintDefaults()
|
||||||
|
c.Flags.SetOutput(os.Stderr)
|
||||||
|
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDefaultCommand returns true if called on the default command
|
||||||
|
func (c *Command) isDefaultCommand() bool {
|
||||||
|
return c.App.defaultCommand == c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command - Defines a subcommand
|
||||||
|
func (c *Command) Command(name, description string) *Command {
|
||||||
|
result := NewCommand(name, description, c.App, c.CommandPath)
|
||||||
|
result.log = c.log
|
||||||
|
c.SubCommands = append(c.SubCommands, result)
|
||||||
|
c.SubCommandsMap[name] = result
|
||||||
|
if len(name) > c.longestSubcommand {
|
||||||
|
c.longestSubcommand = len(name)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolFlag - Adds a boolean flag to the command
|
||||||
|
func (c *Command) BoolFlag(name, description string, variable *bool) *Command {
|
||||||
|
c.Flags.BoolVar(variable, name, *variable, description)
|
||||||
|
c.flagCount++
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringFlag - Adds a string flag to the command
|
||||||
|
func (c *Command) StringFlag(name, description string, variable *string) *Command {
|
||||||
|
c.Flags.StringVar(variable, name, *variable, description)
|
||||||
|
c.flagCount++
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// LongDescription - Sets the long description for the command
|
||||||
|
func (c *Command) LongDescription(Longdescription string) *Command {
|
||||||
|
c.Longdescription = Longdescription
|
||||||
|
return c
|
||||||
|
}
|
130
cmd/fs.go
Normal file
130
cmd/fs.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FSHelper struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFSHelper() *FSHelper {
|
||||||
|
result := &FSHelper{}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the given path resolves to a directory on the filesystem
|
||||||
|
func (fs *FSHelper) DirExists(path string) bool {
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return fi.Mode().IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileExists returns a boolean value indicating whether
|
||||||
|
// the given file exists
|
||||||
|
func (fs *FSHelper) FileExists(path string) bool {
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return fi.Mode().IsRegular()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkDirs creates the given nested directories.
|
||||||
|
// Returns error on failure
|
||||||
|
func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error {
|
||||||
|
var perms os.FileMode
|
||||||
|
perms = 0700
|
||||||
|
if len(mode) == 1 {
|
||||||
|
perms = mode[0]
|
||||||
|
}
|
||||||
|
return os.MkdirAll(fullPath, perms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFile from source to target
|
||||||
|
func (fs *FSHelper) CopyFile(source, target string) error {
|
||||||
|
s, err := os.Open(source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
d, err := os.Create(target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(d, s); err != nil {
|
||||||
|
d.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return d.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cwd returns the current working directory
|
||||||
|
// Aborts on Failure
|
||||||
|
func (fs *FSHelper) Cwd() string {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Unable to get working directory!")
|
||||||
|
}
|
||||||
|
return cwd
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSubdirs will return a list of FQPs to subdirectories in the given directory
|
||||||
|
func (fs *FSHelper) GetSubdirs(dir string) (map[string]string, error) {
|
||||||
|
|
||||||
|
// Read in the directory information
|
||||||
|
fileInfo, err := ioutil.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate space for the list
|
||||||
|
subdirs := make(map[string]string)
|
||||||
|
|
||||||
|
// Pull out the directories and store in the map as
|
||||||
|
// map["directoryName"] = "path/to/directoryName"
|
||||||
|
for _, file := range fileInfo {
|
||||||
|
if file.IsDir() {
|
||||||
|
subdirs[file.Name()] = filepath.Join(dir, file.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subdirs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkDir creates the given directory.
|
||||||
|
// Returns error on failure
|
||||||
|
func (fs *FSHelper) MkDir(dir string) error {
|
||||||
|
return os.Mkdir(dir, 0700)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadAsString will attempt to load the given file and return
|
||||||
|
// its contents as a string
|
||||||
|
func (fs *FSHelper) LoadAsString(filename string) (string, error) {
|
||||||
|
bytes, err := ioutil.ReadFile(filename)
|
||||||
|
return string(bytes), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileMD5 returns the md5sum of the given file
|
||||||
|
func (fs *FSHelper) FileMD5(filename string) (string, error) {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||||
|
}
|
82
cmd/log.go
Normal file
82
cmd/log.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Logger struct
|
||||||
|
type Logger struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLogger creates a new logger!
|
||||||
|
func NewLogger() *Logger {
|
||||||
|
return &Logger{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yellow - Outputs yellow text
|
||||||
|
func (l *Logger) Yellow(format string, a ...interface{}) {
|
||||||
|
color.New(color.FgHiYellow).PrintfFunc()(format+"\n", a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yellowf - Outputs yellow text without the newline
|
||||||
|
func (l *Logger) Yellowf(format string, a ...interface{}) {
|
||||||
|
color.New(color.FgHiYellow).PrintfFunc()(format, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Green - Outputs Green text
|
||||||
|
func (l *Logger) Green(format string, a ...interface{}) {
|
||||||
|
color.New(color.FgHiGreen).PrintfFunc()(format+"\n", a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// White - Outputs White text
|
||||||
|
func (l *Logger) White(format string, a ...interface{}) {
|
||||||
|
color.New(color.FgHiWhite).PrintfFunc()(format+"\n", a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WhiteUnderline - Outputs White text with underline
|
||||||
|
func (l *Logger) WhiteUnderline(format string, a ...interface{}) {
|
||||||
|
l.White(format, a...)
|
||||||
|
l.White(l.underline(format))
|
||||||
|
}
|
||||||
|
|
||||||
|
// YellowUnderline - Outputs Yellow text with underline
|
||||||
|
func (l *Logger) YellowUnderline(format string, a ...interface{}) {
|
||||||
|
l.Yellow(format, a...)
|
||||||
|
l.Yellow(l.underline(format))
|
||||||
|
}
|
||||||
|
|
||||||
|
// underline returns a string of a line, the length of the message given to it
|
||||||
|
func (l *Logger) underline(message string) string {
|
||||||
|
return strings.Repeat("-", len(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Red - Outputs Red text
|
||||||
|
func (l *Logger) Red(format string, a ...interface{}) {
|
||||||
|
color.New(color.FgHiRed).PrintfFunc()(format+"\n", a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error - Outputs an Error message
|
||||||
|
func (l *Logger) Error(format string, a ...interface{}) {
|
||||||
|
color.New(color.FgHiRed).PrintfFunc()("Error: "+format+"\n", a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintBanner prints the Wails banner before running commands
|
||||||
|
func (l *Logger) PrintBanner() error {
|
||||||
|
banner1 := ` _ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ ` + "`" + `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ ) `
|
||||||
|
banner2 := `|__/|__/\__,_/_/_/____/ `
|
||||||
|
|
||||||
|
l.Yellowf(banner1)
|
||||||
|
l.Red(Version)
|
||||||
|
l.Yellowf(banner2)
|
||||||
|
l.Green("https://wails.app")
|
||||||
|
l.White("The lightweight framework for web-like apps")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
43
cmd/program.go
Normal file
43
cmd/program.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProgramHelper - Utility functions around installed applications
|
||||||
|
type ProgramHelper struct{}
|
||||||
|
|
||||||
|
// NewProgramHelper - Creates a new ProgramHelper
|
||||||
|
func NewProgramHelper() *ProgramHelper {
|
||||||
|
return &ProgramHelper{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInstalled tries to determine if the given binary name is installed
|
||||||
|
func (p *ProgramHelper) IsInstalled(programName string) bool {
|
||||||
|
_, err := exec.LookPath(programName)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Program - A struct to define an installed application/binary
|
||||||
|
type Program struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindProgram attempts to find the given program on the system.FindProgram
|
||||||
|
// Returns a struct with the name and path to the program
|
||||||
|
func (p *ProgramHelper) FindProgram(programName string) *Program {
|
||||||
|
path, err := exec.LookPath(programName)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
path, err = filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Program{
|
||||||
|
Name: programName,
|
||||||
|
Path: path,
|
||||||
|
}
|
||||||
|
}
|
1
cmd/setup.go
Normal file
1
cmd/setup.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package cmd
|
200
cmd/system.go
Normal file
200
cmd/system.go
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/AlecAivazis/survey"
|
||||||
|
homedir "github.com/mitchellh/go-homedir"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SystemHelper struct {
|
||||||
|
log *Logger
|
||||||
|
fs *FSHelper
|
||||||
|
configFilename string
|
||||||
|
homeDir string
|
||||||
|
wailsSystemDir string
|
||||||
|
wailsSystemConfig string
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
s.homeDir, err = homedir.Dir()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Cannot find home directory! Please file a bug report!")
|
||||||
|
}
|
||||||
|
// TODO: A better config system
|
||||||
|
s.wailsSystemDir = filepath.Join(s.homeDir, ".wails")
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
|
||||||
|
// Answers. We all need them.
|
||||||
|
answers := &SystemConfig{}
|
||||||
|
|
||||||
|
// Try to load current values - ignore errors
|
||||||
|
config, err := s.LoadConfig()
|
||||||
|
defaultName := ""
|
||||||
|
defaultEmail := ""
|
||||||
|
if config != nil {
|
||||||
|
defaultName = config.Name
|
||||||
|
defaultEmail = config.Email
|
||||||
|
}
|
||||||
|
// Questions
|
||||||
|
var simpleQs = []*survey.Question{
|
||||||
|
{
|
||||||
|
Name: "Name",
|
||||||
|
Prompt: &survey.Input{
|
||||||
|
Message: "What is your name:",
|
||||||
|
Default: defaultName,
|
||||||
|
},
|
||||||
|
Validate: survey.Required,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Email",
|
||||||
|
Prompt: &survey.Input{
|
||||||
|
Message: "What is your email address:",
|
||||||
|
Default: defaultEmail,
|
||||||
|
},
|
||||||
|
Validate: survey.Required,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// ask the questions
|
||||||
|
err = survey.Ask(simpleQs, answers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the directory
|
||||||
|
err = s.fs.MkDirs(s.wailsSystemDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
s.log.White("Wails config saved to: " + s.wailsSystemConfig)
|
||||||
|
s.log.White("Feel free to customise these settings.")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
return answers.Save(s.wailsSystemConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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!")
|
||||||
|
s.log.Green("To get you set up, I'll need to ask you a few things...")
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
type SystemConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSystemConfig(filename string) (*SystemConfig, error) {
|
||||||
|
result := &SystemConfig{}
|
||||||
|
err := result.load(filename)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
5
cmd/version.go
Normal file
5
cmd/version.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
// Version - Wails version
|
||||||
|
// ...oO(There must be a better way)
|
||||||
|
const Version = "v0.5 Alpha"
|
60
cmd/wails/0_setup.go
Normal file
60
cmd/wails/0_setup.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
commandDescription := `Sets up your local environment to develop Wails apps.`
|
||||||
|
|
||||||
|
initCommand := app.Command("setup", "Setup the Wails environment").
|
||||||
|
LongDescription(commandDescription)
|
||||||
|
|
||||||
|
initCommand.Action(func() error {
|
||||||
|
|
||||||
|
system := cmd.NewSystemHelper()
|
||||||
|
err := system.Initialise()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var successMessage string
|
||||||
|
|
||||||
|
logger.Yellow("Checking for prerequisites...")
|
||||||
|
// Check we have a cgo capable environment
|
||||||
|
programHelper := cmd.NewProgramHelper()
|
||||||
|
prerequisites := make(map[string]map[string]string)
|
||||||
|
prerequisites["darwin"] = make(map[string]string)
|
||||||
|
prerequisites["darwin"]["clang"] = "Please install with `xcode-select --install` and try again"
|
||||||
|
prerequisites["darwin"]["npm"] = "Please download and install npm + node from here: https://nodejs.org/en/"
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
successMessage = "🚀 Awesome! We are going to the moon! 🚀"
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("platform '%s' is unsupported at this time", runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
|
errors := false
|
||||||
|
for name, help := range prerequisites[runtime.GOOS] {
|
||||||
|
bin := programHelper.FindProgram(name)
|
||||||
|
if bin == nil {
|
||||||
|
errors = true
|
||||||
|
logger.Red("Unable to find '%s' - %s", name, help)
|
||||||
|
} else {
|
||||||
|
logger.Green("Found program '%s' at '%s'", name, bin.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors {
|
||||||
|
err = fmt.Errorf("There were missing dependencies")
|
||||||
|
} else {
|
||||||
|
logger.Yellow(successMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
26
cmd/wails/main.go
Normal file
26
cmd/wails/main.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create Logger
|
||||||
|
var logger = cmd.NewLogger()
|
||||||
|
|
||||||
|
// Create main app
|
||||||
|
var app = cmd.NewCli("wails", "A cli tool for building Wails applications.")
|
||||||
|
|
||||||
|
// Prints the cli banner
|
||||||
|
func printBanner(app *cmd.Cli) error {
|
||||||
|
logger.PrintBanner()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main!
|
||||||
|
func main() {
|
||||||
|
app.PreRun(printBanner)
|
||||||
|
err := app.Run()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
14
go.mod
Normal file
14
go.mod
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module github.com/wailsapp/wails
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/AlecAivazis/survey v1.7.1
|
||||||
|
github.com/fatih/color v1.7.0
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
|
github.com/leaanthony/spinner v0.5.0
|
||||||
|
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.0.9 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.4 // indirect
|
||||||
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||||
|
github.com/mitchellh/go-homedir v1.0.0
|
||||||
|
gopkg.in/AlecAivazis/survey.v1 v1.7.1 // indirect
|
||||||
|
)
|
21
go.sum
Normal file
21
go.sum
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
github.com/AlecAivazis/survey v1.7.1 h1:a84v5MG2296rBkTP0e+dd4l7NxFQ69v4jzMpErkjVxc=
|
||||||
|
github.com/AlecAivazis/survey v1.7.1/go.mod h1:MVECab6WqEH1aXhj8nKIwF7HEAJAj2bhhGiSjNy3wII=
|
||||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
|
github.com/leaanthony/spinner v0.5.0 h1:OJKn+0KP6ilHxwCEOv5Lo0wPM4PgWZWLJTeUprGJK0g=
|
||||||
|
github.com/leaanthony/spinner v0.5.0/go.mod h1:2Mmv+8Brcw3NwPT1DdOLmW6+zWpSamDDFFsUvVHo2cc=
|
||||||
|
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 h1:1bGojw4YacLY5bqQalojiQ7mSfQbe4WIWCEgPZagowU=
|
||||||
|
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
||||||
|
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||||
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||||
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||||
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
|
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
||||||
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/wailsapp/wails v0.0.0-20181215232634-5de8efff325d h1:lk91T4sKD98eGcaz/xC6ER+3o9Kaun7Mk8e/cNZOPMc=
|
||||||
|
gopkg.in/AlecAivazis/survey.v1 v1.7.1 h1:mzQIVyOPSXJaQWi1m6AFCjrCEPIwQBSOn48Ri8ZpzAg=
|
||||||
|
gopkg.in/AlecAivazis/survey.v1 v1.7.1/go.mod h1:2Ehl7OqkBl3Xb8VmC4oFW2bItAhnUfzIjrOzwRxCrOU=
|
Loading…
Reference in New Issue
Block a user