Compare commits
134 Commits
Port-Init
...
update-com
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fafd165de | ||
|
|
5ca7bfca66 | ||
|
|
3f32c45f77 | ||
|
|
f8c805649a | ||
|
|
3ac993b01f | ||
|
|
216c84b9cf | ||
|
|
e99fffe340 | ||
|
|
4cccb628c9 | ||
|
|
5d487347d4 | ||
|
|
fe8b7ac5c9 | ||
|
|
732c70777b | ||
|
|
753c5fd337 | ||
|
|
2dad29673d | ||
|
|
5e466893cf | ||
|
|
c15fd822c1 | ||
|
|
42b1c0befa | ||
|
|
6ef8744e02 | ||
|
|
cf916c8e8b | ||
|
|
cdc1d4be3e | ||
|
|
1c5284db3e | ||
|
|
073cdc3a55 | ||
|
|
fd9363e842 | ||
|
|
3051628fa2 | ||
|
|
cac97e8652 | ||
|
|
2ccabc772b | ||
|
|
ff91241592 | ||
|
|
2257b1cab1 | ||
|
|
bdcf98fc15 | ||
|
|
3025a94a77 | ||
|
|
d971495ad3 | ||
|
|
a4b1f469e9 | ||
|
|
b18f04b30d | ||
|
|
94e9447e1c | ||
|
|
03c479c890 | ||
|
|
c95a3a795e | ||
|
|
1d8e99d846 | ||
|
|
8e909fc9f4 | ||
|
|
3bc86a4f50 | ||
|
|
2c7913c202 | ||
|
|
d1c57ddb5f | ||
|
|
9ffb517183 | ||
|
|
27f852ac6a | ||
|
|
20c0b48634 | ||
|
|
6cf01b4239 | ||
|
|
3ae88f8822 | ||
|
|
5994eb605f | ||
|
|
9694dc57aa | ||
|
|
b5b78fddee | ||
|
|
c905185467 | ||
|
|
47ca7879cd | ||
|
|
6202b3bf3e | ||
|
|
ea94c2de1f | ||
|
|
eb0d4bc42f | ||
|
|
b323c3db20 | ||
|
|
1670ac6567 | ||
|
|
c941176018 | ||
|
|
a060d9dcc0 | ||
|
|
ba208dce44 | ||
|
|
9bbac46b3f | ||
|
|
d8c591e64c | ||
|
|
2c28a8f550 | ||
|
|
d6c5586159 | ||
|
|
08a7893b1d | ||
|
|
fa6cf17079 | ||
|
|
fe2a20f92a | ||
|
|
b713d57168 | ||
|
|
17ca06693e | ||
|
|
243d738d64 | ||
|
|
3f50b95f26 | ||
|
|
f0d8ce99a1 | ||
|
|
259eec97d6 | ||
|
|
8b2168abe7 | ||
|
|
a51e127309 | ||
|
|
c5cee79ff7 | ||
|
|
9393b08c3f | ||
|
|
0ca039e914 | ||
|
|
cd8b4f088f | ||
|
|
847842504b | ||
|
|
8ab91d31fe | ||
|
|
bb4d891549 | ||
|
|
4a316a76fa | ||
|
|
529e4cc07e | ||
|
|
579747d0f7 | ||
|
|
6880c53082 | ||
|
|
6e011e75c3 | ||
|
|
683ba7dc59 | ||
|
|
717e598330 | ||
|
|
a6489a1044 | ||
|
|
df911adcae | ||
|
|
d7c0b1ec58 | ||
|
|
7135d4fa27 | ||
|
|
83e063bf2b | ||
|
|
6e0773b355 | ||
|
|
60f34223b0 | ||
|
|
539be2ce84 | ||
|
|
561198b81b | ||
|
|
c823215eb6 | ||
|
|
93f890f6d9 | ||
|
|
8a3aec6866 | ||
|
|
1ef8ed73ab | ||
|
|
9004c3955e | ||
|
|
4c98ce7da1 | ||
|
|
0ae5381203 | ||
|
|
3f2f1b45f6 | ||
|
|
e6bec8f7cc | ||
|
|
f1f15fc1c5 | ||
|
|
bcca09563c | ||
|
|
ee355659ce | ||
|
|
a660e4a9da | ||
|
|
a44fd57e98 | ||
|
|
85de0bbf8a | ||
|
|
7274b6d19c | ||
|
|
c0371f141a | ||
|
|
5c96264234 | ||
|
|
a3c41d1740 | ||
|
|
7c15b780e2 | ||
|
|
fb081b4876 | ||
|
|
a28315f38b | ||
|
|
49e4f00b62 | ||
|
|
9167063976 | ||
|
|
aaa425724c | ||
|
|
ffdbb0af64 | ||
|
|
12dec650de | ||
|
|
d4b2563e9b | ||
|
|
55817b65b5 | ||
|
|
ab6e7531b4 | ||
|
|
1e4cf9b0ad | ||
|
|
13efa58c9a | ||
|
|
88b9b40bfe | ||
|
|
0011e39c55 | ||
|
|
aa6b67734b | ||
|
|
733258cc83 | ||
|
|
4742fd7ed2 | ||
|
|
96996431b4 |
6
.gitignore
vendored
@@ -10,3 +10,9 @@
|
|||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
|
examples/**/example*
|
||||||
|
!examples/**/*.*
|
||||||
|
cmd/wails/wails
|
||||||
|
.DS_Store
|
||||||
|
tmp
|
||||||
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018 wailsapp
|
Copyright (c) 2018-Present Lea Anthony
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
138
app.go
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -------------------------------- Compile time Flags ------------------------------
|
||||||
|
|
||||||
|
// BuildMode indicates what mode we are in
|
||||||
|
var BuildMode = cmd.BuildModeProd
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// App defines the main application struct
|
||||||
|
type App struct {
|
||||||
|
config *AppConfig // The Application configuration object
|
||||||
|
cli *cmd.Cli // In debug mode, we have a cli
|
||||||
|
renderer Renderer // The renderer is what we will render the app to
|
||||||
|
logLevel string // The log level of the app
|
||||||
|
ipc *ipcManager // Handles the IPC calls
|
||||||
|
log *CustomLogger // Logger
|
||||||
|
bindingManager *bindingManager // Handles binding of Go code to renderer
|
||||||
|
eventManager *eventManager // Handles all the events
|
||||||
|
runtime *Runtime // The runtime object for registered structs
|
||||||
|
|
||||||
|
// This is a list of all the JS/CSS that needs injecting
|
||||||
|
// It will get injected in order
|
||||||
|
jsCache []string
|
||||||
|
cssCache []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateApp creates the application window with the given configuration
|
||||||
|
// If none given, the defaults are used
|
||||||
|
func CreateApp(optionalConfig ...*AppConfig) *App {
|
||||||
|
var userConfig *AppConfig
|
||||||
|
if len(optionalConfig) > 0 {
|
||||||
|
userConfig = optionalConfig[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &App{
|
||||||
|
logLevel: "info",
|
||||||
|
renderer: &webViewRenderer{},
|
||||||
|
ipc: newIPCManager(),
|
||||||
|
bindingManager: newBindingManager(),
|
||||||
|
eventManager: newEventManager(),
|
||||||
|
log: newCustomLogger("App"),
|
||||||
|
}
|
||||||
|
|
||||||
|
appconfig, err := newAppConfig(userConfig)
|
||||||
|
if err != nil {
|
||||||
|
result.log.Fatalf("Cannot use custom HTML: %s", err.Error())
|
||||||
|
}
|
||||||
|
result.config = appconfig
|
||||||
|
|
||||||
|
// Set up the CLI if not in release mode
|
||||||
|
if BuildMode != cmd.BuildModeProd {
|
||||||
|
result.cli = result.setupCli()
|
||||||
|
} else {
|
||||||
|
// Disable Inspector in release mode
|
||||||
|
result.config.DisableInspector = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the app
|
||||||
|
func (a *App) Run() error {
|
||||||
|
if BuildMode != cmd.BuildModeProd {
|
||||||
|
return a.cli.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
a.logLevel = "error"
|
||||||
|
return a.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) start() error {
|
||||||
|
|
||||||
|
// Set the log level
|
||||||
|
setLogLevel(a.logLevel)
|
||||||
|
|
||||||
|
// Log starup
|
||||||
|
a.log.Info("Starting")
|
||||||
|
|
||||||
|
// Check if we are to run in headless mode
|
||||||
|
if BuildMode == cmd.BuildModeBridge {
|
||||||
|
a.renderer = &Headless{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the renderer
|
||||||
|
err := a.renderer.Initialise(a.config, a.ipc, a.eventManager)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start event manager and give it our renderer
|
||||||
|
a.eventManager.start(a.renderer)
|
||||||
|
|
||||||
|
// Start the IPC Manager and give it the event manager and binding manager
|
||||||
|
a.ipc.start(a.eventManager, a.bindingManager)
|
||||||
|
|
||||||
|
// Create the runtime
|
||||||
|
a.runtime = newRuntime(a.eventManager, a.renderer)
|
||||||
|
|
||||||
|
// Start binding manager and give it our renderer
|
||||||
|
err = a.bindingManager.start(a.renderer, a.runtime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject CSS
|
||||||
|
a.renderer.AddCSSList(a.cssCache)
|
||||||
|
|
||||||
|
// Inject JS
|
||||||
|
a.renderer.AddJSList(a.jsCache)
|
||||||
|
|
||||||
|
// Run the renderer
|
||||||
|
a.renderer.Run()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind allows the user to bind the given object
|
||||||
|
// with the application
|
||||||
|
func (a *App) Bind(object interface{}) {
|
||||||
|
a.bindingManager.bind(object)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddJS adds a piece of Javascript to a cache that
|
||||||
|
// gets injected at runtime
|
||||||
|
func (a *App) AddJS(js string) {
|
||||||
|
a.jsCache = append(a.jsCache, js)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCSS adds a CSS string to a cache that
|
||||||
|
// gets injected at runtime
|
||||||
|
func (a *App) AddCSS(js string) {
|
||||||
|
a.cssCache = append(a.cssCache, js)
|
||||||
|
}
|
||||||
31
app_cli.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupCli creates a new cli handler for the application
|
||||||
|
func (app *App) setupCli() *cmd.Cli {
|
||||||
|
|
||||||
|
// Create a new cli
|
||||||
|
result := cmd.NewCli(app.config.Title, "Debug build")
|
||||||
|
|
||||||
|
// Setup cli to handle loglevel and headless flags
|
||||||
|
result.
|
||||||
|
StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel).
|
||||||
|
// BoolFlag("headless", "Runs the app in headless mode", &app.headless).
|
||||||
|
Action(app.start)
|
||||||
|
|
||||||
|
// Banner
|
||||||
|
result.PreRun(func(cli *cmd.Cli) error {
|
||||||
|
log := cmd.NewLogger()
|
||||||
|
log.PrintSmallBanner()
|
||||||
|
fmt.Println()
|
||||||
|
log.YellowUnderline(app.config.Title + " - Debug Build")
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
97
app_config.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/dchest/htmlmin"
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AppConfig is the configuration structure used when creating a Wails App object
|
||||||
|
type AppConfig struct {
|
||||||
|
Width, Height int
|
||||||
|
Title string
|
||||||
|
defaultHTML string
|
||||||
|
HTML string
|
||||||
|
JS string
|
||||||
|
CSS string
|
||||||
|
Colour string
|
||||||
|
Resizable bool
|
||||||
|
DisableInspector bool
|
||||||
|
isHTMLFragment bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppConfig) merge(in *AppConfig) error {
|
||||||
|
if in.CSS != "" {
|
||||||
|
a.CSS = in.CSS
|
||||||
|
}
|
||||||
|
if in.Title != "" {
|
||||||
|
a.Title = in.Title
|
||||||
|
}
|
||||||
|
if in.HTML != "" {
|
||||||
|
minified, err := htmlmin.Minify([]byte(in.HTML), &htmlmin.Options{
|
||||||
|
MinifyScripts: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
inlineHTML := string(minified)
|
||||||
|
inlineHTML = strings.Replace(inlineHTML, "'", "\\'", -1)
|
||||||
|
inlineHTML = strings.Replace(inlineHTML, "\n", " ", -1)
|
||||||
|
a.HTML = strings.TrimSpace(inlineHTML)
|
||||||
|
|
||||||
|
// Deduce whether this is a full html page or a fragment
|
||||||
|
// The document is determined to be a fragment if an HMTL
|
||||||
|
// tag exists and is located before the first div tag
|
||||||
|
HTMLTagIndex := strings.Index(a.HTML, "<html")
|
||||||
|
DivTagIndex := strings.Index(a.HTML, "<div")
|
||||||
|
|
||||||
|
if HTMLTagIndex == -1 {
|
||||||
|
a.isHTMLFragment = true
|
||||||
|
} else {
|
||||||
|
if DivTagIndex < HTMLTagIndex {
|
||||||
|
a.isHTMLFragment = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.Colour != "" {
|
||||||
|
a.Colour = in.Colour
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.JS != "" {
|
||||||
|
a.JS = in.JS
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.Width != 0 {
|
||||||
|
a.Width = in.Width
|
||||||
|
}
|
||||||
|
if in.Height != 0 {
|
||||||
|
a.Height = in.Height
|
||||||
|
}
|
||||||
|
a.Resizable = in.Resizable
|
||||||
|
a.DisableInspector = in.DisableInspector
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the default configuration
|
||||||
|
func newAppConfig(userConfig *AppConfig) (*AppConfig, error) {
|
||||||
|
result := &AppConfig{
|
||||||
|
Width: 800,
|
||||||
|
Height: 600,
|
||||||
|
Resizable: true,
|
||||||
|
Title: "My Wails App",
|
||||||
|
Colour: "#FFF", // White by default
|
||||||
|
HTML: mewn.String("./wailsruntimeassets/default/default.html"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if userConfig != nil {
|
||||||
|
err := result.merge(userConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
160
binding_function.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type boundFunction struct {
|
||||||
|
fullName string
|
||||||
|
function reflect.Value
|
||||||
|
functionType reflect.Type
|
||||||
|
inputs []reflect.Type
|
||||||
|
returnTypes []reflect.Type
|
||||||
|
log *CustomLogger
|
||||||
|
hasErrorReturnType bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new bound function based on the given method + type
|
||||||
|
func newBoundFunction(object interface{}) (*boundFunction, error) {
|
||||||
|
|
||||||
|
objectValue := reflect.ValueOf(object)
|
||||||
|
objectType := reflect.TypeOf(object)
|
||||||
|
|
||||||
|
name := runtime.FuncForPC(objectValue.Pointer()).Name()
|
||||||
|
|
||||||
|
result := &boundFunction{
|
||||||
|
fullName: name,
|
||||||
|
function: objectValue,
|
||||||
|
functionType: objectType,
|
||||||
|
log: newCustomLogger(name),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := result.processParameters()
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *boundFunction) processParameters() error {
|
||||||
|
|
||||||
|
// Param processing
|
||||||
|
functionType := b.functionType
|
||||||
|
|
||||||
|
// Input parameters
|
||||||
|
inputParamCount := functionType.NumIn()
|
||||||
|
if inputParamCount > 0 {
|
||||||
|
b.inputs = make([]reflect.Type, inputParamCount)
|
||||||
|
// We start at 1 as the first param is the struct
|
||||||
|
for index := 0; index < inputParamCount; index++ {
|
||||||
|
param := functionType.In(index)
|
||||||
|
name := param.Name()
|
||||||
|
kind := param.Kind()
|
||||||
|
b.inputs[index] = param
|
||||||
|
typ := param
|
||||||
|
index := index
|
||||||
|
b.log.DebugFields("Input param", Fields{
|
||||||
|
"index": index,
|
||||||
|
"name": name,
|
||||||
|
"kind": kind,
|
||||||
|
"typ": typ,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process return/output declarations
|
||||||
|
returnParamsCount := functionType.NumOut()
|
||||||
|
// Guard against bad number of return types
|
||||||
|
switch returnParamsCount {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
// Check if it's an error type
|
||||||
|
param := functionType.Out(0)
|
||||||
|
paramName := param.Name()
|
||||||
|
if paramName == "error" {
|
||||||
|
b.hasErrorReturnType = true
|
||||||
|
}
|
||||||
|
// Save return type
|
||||||
|
b.returnTypes = append(b.returnTypes, param)
|
||||||
|
case 2:
|
||||||
|
// Check the second return type is an error
|
||||||
|
secondParam := functionType.Out(1)
|
||||||
|
secondParamName := secondParam.Name()
|
||||||
|
if secondParamName != "error" {
|
||||||
|
return fmt.Errorf("last return type of method '%s' must be an error (got %s)", b.fullName, secondParamName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the second return type is an error
|
||||||
|
firstParam := functionType.Out(0)
|
||||||
|
firstParamName := firstParam.Name()
|
||||||
|
if firstParamName == "error" {
|
||||||
|
return fmt.Errorf("first return type of method '%s' must not be an error", b.fullName)
|
||||||
|
}
|
||||||
|
b.hasErrorReturnType = true
|
||||||
|
|
||||||
|
// Save return types
|
||||||
|
b.returnTypes = append(b.returnTypes, firstParam)
|
||||||
|
b.returnTypes = append(b.returnTypes, secondParam)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cannot register method '%s' with %d return parameters. Please use up to 2", b.fullName, returnParamsCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the method with the given data
|
||||||
|
func (b *boundFunction) call(data string) ([]reflect.Value, error) {
|
||||||
|
|
||||||
|
// The data will be an array of values so we will decode the
|
||||||
|
// input data into
|
||||||
|
var jsArgs []interface{}
|
||||||
|
d := json.NewDecoder(bytes.NewBufferString(data))
|
||||||
|
// d.UseNumber()
|
||||||
|
err := d.Decode(&jsArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Invalid data passed to method call: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check correct number of inputs
|
||||||
|
if len(jsArgs) != len(b.inputs) {
|
||||||
|
return nil, fmt.Errorf("Invalid number of parameters given to %s. Expected %d but got %d", b.fullName, len(b.inputs), len(jsArgs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up call
|
||||||
|
args := make([]reflect.Value, len(b.inputs))
|
||||||
|
for index := 0; index < len(b.inputs); index++ {
|
||||||
|
|
||||||
|
// Set the input values
|
||||||
|
value, err := b.setInputValue(index, b.inputs[index], jsArgs[index])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args[index] = value
|
||||||
|
}
|
||||||
|
b.log.Debugf("Unmarshalled Args: %+v\n", jsArgs)
|
||||||
|
b.log.Debugf("Converted Args: %+v\n", args)
|
||||||
|
results := b.function.Call(args)
|
||||||
|
|
||||||
|
b.log.Debugf("results = %+v", results)
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to set the method input <typ> for parameter <index> with the given value <val>
|
||||||
|
func (b *boundFunction) setInputValue(index int, typ reflect.Type, val interface{}) (result reflect.Value, err error) {
|
||||||
|
|
||||||
|
// Catch type conversion panics thrown by convert
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
// Modify error
|
||||||
|
err = fmt.Errorf("%s for parameter %d of function %s", r.(string)[23:], index+1, b.fullName)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Do the conversion
|
||||||
|
result = reflect.ValueOf(val).Convert(typ)
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
282
binding_manager.go
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
binding:
|
||||||
|
Name() // Full name (package+name)
|
||||||
|
Call(params)
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
type bindingManager struct {
|
||||||
|
methods map[string]*boundMethod
|
||||||
|
functions map[string]*boundFunction
|
||||||
|
initMethods []*boundMethod
|
||||||
|
log *CustomLogger
|
||||||
|
renderer Renderer
|
||||||
|
runtime *Runtime // The runtime object to pass to bound structs
|
||||||
|
objectsToBind []interface{}
|
||||||
|
bindPackageNames bool // Package name should be considered when binding
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBindingManager() *bindingManager {
|
||||||
|
result := &bindingManager{
|
||||||
|
methods: make(map[string]*boundMethod),
|
||||||
|
functions: make(map[string]*boundFunction),
|
||||||
|
log: newCustomLogger("Bind"),
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets flag to indicate package names should be considered when binding
|
||||||
|
func (b *bindingManager) BindPackageNames() {
|
||||||
|
b.bindPackageNames = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error {
|
||||||
|
b.log.Info("Starting")
|
||||||
|
b.renderer = renderer
|
||||||
|
b.runtime = runtime
|
||||||
|
err := b.initialise()
|
||||||
|
if err != nil {
|
||||||
|
b.log.Errorf("Binding error: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = b.callWailsInitMethods()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bindingManager) initialise() error {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
// var binding *boundMethod
|
||||||
|
|
||||||
|
b.log.Info("Binding Go Functions/Methods")
|
||||||
|
|
||||||
|
// Create bindings for objects
|
||||||
|
for _, object := range b.objectsToBind {
|
||||||
|
|
||||||
|
// Safeguard against nils
|
||||||
|
if object == nil {
|
||||||
|
return fmt.Errorf("attempted to bind nil object")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine kind of object
|
||||||
|
objectType := reflect.TypeOf(object)
|
||||||
|
objectKind := objectType.Kind()
|
||||||
|
|
||||||
|
switch objectKind {
|
||||||
|
case reflect.Ptr:
|
||||||
|
err = b.bindMethod(object)
|
||||||
|
case reflect.Func:
|
||||||
|
// spew.Dump(result.objectType.String())
|
||||||
|
err = b.bindFunction(object)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("cannot bind object of type '%s'", objectKind.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return error if set
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind the given struct method
|
||||||
|
func (b *bindingManager) bindMethod(object interface{}) error {
|
||||||
|
|
||||||
|
objectType := reflect.TypeOf(object)
|
||||||
|
baseName := objectType.String()
|
||||||
|
|
||||||
|
// Strip pointer if there
|
||||||
|
if baseName[0] == '*' {
|
||||||
|
baseName = baseName[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
b.log.Debugf("Processing struct: %s", baseName)
|
||||||
|
|
||||||
|
// Iterate over method definitions
|
||||||
|
for i := 0; i < objectType.NumMethod(); i++ {
|
||||||
|
|
||||||
|
// Get method definition
|
||||||
|
methodDef := objectType.Method(i)
|
||||||
|
methodName := methodDef.Name
|
||||||
|
fullMethodName := baseName + "." + methodName
|
||||||
|
method := reflect.ValueOf(object).MethodByName(methodName)
|
||||||
|
|
||||||
|
// Skip unexported methods
|
||||||
|
if !unicode.IsUpper([]rune(methodName)[0]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new boundMethod
|
||||||
|
newMethod, err := newBoundMethod(methodName, fullMethodName, method, objectType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a wails init function
|
||||||
|
if newMethod.isWailsInit {
|
||||||
|
b.log.Debugf("Detected WailsInit function: %s", fullMethodName)
|
||||||
|
b.initMethods = append(b.initMethods, newMethod)
|
||||||
|
} else {
|
||||||
|
// Save boundMethod
|
||||||
|
b.log.Infof("Bound Method: %s()", fullMethodName)
|
||||||
|
b.methods[fullMethodName] = newMethod
|
||||||
|
|
||||||
|
// Inform renderer of new binding
|
||||||
|
b.renderer.NewBinding(fullMethodName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind the given function object
|
||||||
|
func (b *bindingManager) bindFunction(object interface{}) error {
|
||||||
|
|
||||||
|
newFunction, err := newBoundFunction(object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save method
|
||||||
|
b.log.Infof("Bound Function: %s()", newFunction.fullName)
|
||||||
|
b.functions[newFunction.fullName] = newFunction
|
||||||
|
|
||||||
|
// Register with Renderer
|
||||||
|
b.renderer.NewBinding(newFunction.fullName)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the given object to be bound at start time
|
||||||
|
func (b *bindingManager) bind(object interface{}) {
|
||||||
|
// Store binding
|
||||||
|
b.objectsToBind = append(b.objectsToBind, object)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
|
||||||
|
// Return values
|
||||||
|
var result []reflect.Value
|
||||||
|
var err error
|
||||||
|
|
||||||
|
function := b.functions[callData.BindingName]
|
||||||
|
if function == nil {
|
||||||
|
return nil, fmt.Errorf("Invalid function name '%s'", callData.BindingName)
|
||||||
|
}
|
||||||
|
result, err = function.call(callData.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have an error return type?
|
||||||
|
if function.hasErrorReturnType {
|
||||||
|
// We do - last result is an error type
|
||||||
|
// Check if the last result was nil
|
||||||
|
b.log.Debugf("# of return types: %d", len(function.returnTypes))
|
||||||
|
b.log.Debugf("# of results: %d", len(result))
|
||||||
|
errorResult := result[len(function.returnTypes)-1]
|
||||||
|
if !errorResult.IsNil() {
|
||||||
|
// It wasn't - we have an error
|
||||||
|
return nil, errorResult.Interface().(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result[0].Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bindingManager) processMethodCall(callData *callData) (interface{}, error) {
|
||||||
|
// Return values
|
||||||
|
var result []reflect.Value
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// do we have this method?
|
||||||
|
method := b.methods[callData.BindingName]
|
||||||
|
if method == nil {
|
||||||
|
return nil, fmt.Errorf("Invalid method name '%s'", callData.BindingName)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = method.call(callData.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have an error return type?
|
||||||
|
if method.hasErrorReturnType {
|
||||||
|
// We do - last result is an error type
|
||||||
|
// Check if the last result was nil
|
||||||
|
b.log.Debugf("# of return types: %d", len(method.returnTypes))
|
||||||
|
b.log.Debugf("# of results: %d", len(result))
|
||||||
|
errorResult := result[len(method.returnTypes)-1]
|
||||||
|
if !errorResult.IsNil() {
|
||||||
|
// It wasn't - we have an error
|
||||||
|
return nil, errorResult.Interface().(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if result != nil {
|
||||||
|
return result[0].Interface(), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// process an incoming call request
|
||||||
|
func (b *bindingManager) processCall(callData *callData) (result interface{}, err error) {
|
||||||
|
b.log.Debugf("Wanting to call %s", callData.BindingName)
|
||||||
|
|
||||||
|
// Determine if this is function call or method call by the number of
|
||||||
|
// dots in the binding name
|
||||||
|
dotCount := 0
|
||||||
|
for _, character := range callData.BindingName {
|
||||||
|
if character == '.' {
|
||||||
|
dotCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to catch reflect related panics and return
|
||||||
|
// a decent error message
|
||||||
|
// TODO: DEBUG THIS!
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = fmt.Errorf("%s", r.(string))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
switch dotCount {
|
||||||
|
case 1:
|
||||||
|
result, err = b.processFunctionCall(callData)
|
||||||
|
case 2:
|
||||||
|
result, err = b.processMethodCall(callData)
|
||||||
|
default:
|
||||||
|
result = nil
|
||||||
|
err = fmt.Errorf("Invalid binding name '%s'", callData.BindingName)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// callWailsInitMethods calls all of the WailsInit methods that were
|
||||||
|
// registered with the runtime object
|
||||||
|
func (b *bindingManager) callWailsInitMethods() error {
|
||||||
|
// Create reflect value for runtime object
|
||||||
|
runtimeValue := reflect.ValueOf(b.runtime)
|
||||||
|
params := []reflect.Value{runtimeValue}
|
||||||
|
|
||||||
|
// Iterate initMethods
|
||||||
|
for _, initMethod := range b.initMethods {
|
||||||
|
// Call
|
||||||
|
result := initMethod.method.Call(params)
|
||||||
|
// Check errors
|
||||||
|
err := result[0].Interface()
|
||||||
|
if err != nil {
|
||||||
|
return err.(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
211
binding_method.go
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type boundMethod struct {
|
||||||
|
Name string
|
||||||
|
fullName string
|
||||||
|
method reflect.Value
|
||||||
|
inputs []reflect.Type
|
||||||
|
returnTypes []reflect.Type
|
||||||
|
log *CustomLogger
|
||||||
|
hasErrorReturnType bool // Indicates if there is an error return type
|
||||||
|
isWailsInit bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new bound method based on the given method + type
|
||||||
|
func newBoundMethod(name string, fullName string, method reflect.Value, objectType reflect.Type) (*boundMethod, error) {
|
||||||
|
result := &boundMethod{
|
||||||
|
Name: name,
|
||||||
|
method: method,
|
||||||
|
fullName: fullName,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup logger
|
||||||
|
result.log = newCustomLogger(result.fullName)
|
||||||
|
|
||||||
|
// Check if Parameters are valid
|
||||||
|
err := result.processParameters()
|
||||||
|
|
||||||
|
// Are we a WailsInit method?
|
||||||
|
if result.Name == "WailsInit" {
|
||||||
|
err = result.processWailsInit()
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *boundMethod) processParameters() error {
|
||||||
|
|
||||||
|
// Param processing
|
||||||
|
methodType := b.method.Type()
|
||||||
|
|
||||||
|
// Input parameters
|
||||||
|
inputParamCount := methodType.NumIn()
|
||||||
|
if inputParamCount > 0 {
|
||||||
|
b.inputs = make([]reflect.Type, inputParamCount)
|
||||||
|
// We start at 1 as the first param is the struct
|
||||||
|
for index := 0; index < inputParamCount; index++ {
|
||||||
|
param := methodType.In(index)
|
||||||
|
name := param.Name()
|
||||||
|
kind := param.Kind()
|
||||||
|
b.inputs[index] = param
|
||||||
|
typ := param
|
||||||
|
index := index
|
||||||
|
b.log.DebugFields("Input param", Fields{
|
||||||
|
"index": index,
|
||||||
|
"name": name,
|
||||||
|
"kind": kind,
|
||||||
|
"typ": typ,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process return/output declarations
|
||||||
|
returnParamsCount := methodType.NumOut()
|
||||||
|
// Guard against bad number of return types
|
||||||
|
switch returnParamsCount {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
// Check if it's an error type
|
||||||
|
param := methodType.Out(0)
|
||||||
|
paramName := param.Name()
|
||||||
|
if paramName == "error" {
|
||||||
|
b.hasErrorReturnType = true
|
||||||
|
}
|
||||||
|
// Save return type
|
||||||
|
b.returnTypes = append(b.returnTypes, param)
|
||||||
|
case 2:
|
||||||
|
// Check the second return type is an error
|
||||||
|
secondParam := methodType.Out(1)
|
||||||
|
secondParamName := secondParam.Name()
|
||||||
|
if secondParamName != "error" {
|
||||||
|
return fmt.Errorf("last return type of method '%s' must be an error (got %s)", b.Name, secondParamName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the second return type is an error
|
||||||
|
firstParam := methodType.Out(0)
|
||||||
|
firstParamName := firstParam.Name()
|
||||||
|
if firstParamName == "error" {
|
||||||
|
return fmt.Errorf("first return type of method '%s' must not be an error", b.Name)
|
||||||
|
}
|
||||||
|
b.hasErrorReturnType = true
|
||||||
|
|
||||||
|
// Save return types
|
||||||
|
b.returnTypes = append(b.returnTypes, firstParam)
|
||||||
|
b.returnTypes = append(b.returnTypes, secondParam)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cannot register method '%s' with %d return parameters. Please use up to 2", b.Name, returnParamsCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the method with the given data
|
||||||
|
func (b *boundMethod) call(data string) ([]reflect.Value, error) {
|
||||||
|
|
||||||
|
// The data will be an array of values so we will decode the
|
||||||
|
// input data into
|
||||||
|
var jsArgs []interface{}
|
||||||
|
d := json.NewDecoder(bytes.NewBufferString(data))
|
||||||
|
// d.UseNumber()
|
||||||
|
err := d.Decode(&jsArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Invalid data passed to method call: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check correct number of inputs
|
||||||
|
if len(jsArgs) != len(b.inputs) {
|
||||||
|
return nil, fmt.Errorf("Invalid number of parameters given to %s. Expected %d but got %d", b.fullName, len(b.inputs), len(jsArgs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up call
|
||||||
|
args := make([]reflect.Value, len(b.inputs))
|
||||||
|
for index := 0; index < len(b.inputs); index++ {
|
||||||
|
|
||||||
|
// Set the input values
|
||||||
|
value, err := b.setInputValue(index, b.inputs[index], jsArgs[index])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args[index] = value
|
||||||
|
}
|
||||||
|
b.log.Debugf("Unmarshalled Args: %+v\n", jsArgs)
|
||||||
|
b.log.Debugf("Converted Args: %+v\n", args)
|
||||||
|
results := b.method.Call(args)
|
||||||
|
|
||||||
|
b.log.Debugf("results = %+v", results)
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to set the method input <typ> for parameter <index> with the given value <val>
|
||||||
|
func (b *boundMethod) setInputValue(index int, typ reflect.Type, val interface{}) (result reflect.Value, err error) {
|
||||||
|
|
||||||
|
// Catch type conversion panics thrown by convert
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
// Modify error
|
||||||
|
fmt.Printf("Recovery message: %+v\n", r)
|
||||||
|
err = fmt.Errorf("%s for parameter %d of method %s", r.(string)[23:], index+1, b.fullName)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Do the conversion
|
||||||
|
// Handle nil values
|
||||||
|
if val == nil {
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Chan,
|
||||||
|
reflect.Func,
|
||||||
|
reflect.Interface,
|
||||||
|
reflect.Map,
|
||||||
|
reflect.Ptr,
|
||||||
|
reflect.Slice:
|
||||||
|
logger.Debug("Converting nil to type")
|
||||||
|
result = reflect.ValueOf(val).Convert(typ)
|
||||||
|
default:
|
||||||
|
logger.Debug("Cannot convert nil to type, returning error")
|
||||||
|
return reflect.Zero(typ), fmt.Errorf("Unable to use null value for parameter %d of method %s", index+1, b.fullName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = reflect.ValueOf(val).Convert(typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *boundMethod) processWailsInit() error {
|
||||||
|
// We must have only 1 input, it must be *wails.Runtime
|
||||||
|
if len(b.inputs) != 1 {
|
||||||
|
return fmt.Errorf("Invalid WailsInit() definition. Expected 1 input, but got %d", len(b.inputs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// It must be *wails.Runtime
|
||||||
|
inputName := b.inputs[0].String()
|
||||||
|
b.log.Debugf("WailsInit input type: %s", inputName)
|
||||||
|
if inputName != "*wails.Runtime" {
|
||||||
|
return fmt.Errorf("Invalid WailsInit() definition. Expected input to be wails.Runtime, but got %s", inputName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We must have only 1 output, it must be error
|
||||||
|
if len(b.returnTypes) != 1 {
|
||||||
|
return fmt.Errorf("Invalid WailsInit() definition. Expected 1 return type, but got %d", len(b.returnTypes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// It must be *wails.Runtime
|
||||||
|
outputName := b.returnTypes[0].String()
|
||||||
|
b.log.Debugf("WailsInit output type: %s", outputName)
|
||||||
|
if outputName != "error" {
|
||||||
|
return fmt.Errorf("Invalid WailsInit() definition. Expected input to be error, but got %s", outputName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are indeed a wails Init method
|
||||||
|
b.isWailsInit = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
10
cmd/build.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
const (
|
||||||
|
// BuildModeProd indicates we are building for prod mode
|
||||||
|
BuildModeProd = "prod"
|
||||||
|
// BuildModeDebug indicates we are building for debug mode
|
||||||
|
BuildModeDebug = "debug"
|
||||||
|
// BuildModeBridge indicates we are building for bridge mode
|
||||||
|
BuildModeBridge = "bridge"
|
||||||
|
)
|
||||||
@@ -105,6 +105,7 @@ func NewCommand(name string, description string, app *Cli, parentCommandPath str
|
|||||||
Shortdescription: description,
|
Shortdescription: description,
|
||||||
SubCommandsMap: make(map[string]*Command),
|
SubCommandsMap: make(map[string]*Command),
|
||||||
App: app,
|
App: app,
|
||||||
|
log: NewLogger(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up command path
|
// Set up command path
|
||||||
@@ -181,6 +182,7 @@ func (c *Command) Run(args []string) error {
|
|||||||
|
|
||||||
// Nothing left we can do
|
// Nothing left we can do
|
||||||
c.PrintHelp()
|
c.PrintHelp()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,6 +194,7 @@ func (c *Command) Action(callback Action) *Command {
|
|||||||
|
|
||||||
// PrintHelp - Output the help text for this command
|
// PrintHelp - Output the help text for this command
|
||||||
func (c *Command) PrintHelp() {
|
func (c *Command) PrintHelp() {
|
||||||
|
c.log.PrintBanner()
|
||||||
versionString := c.AppVersion
|
versionString := c.AppVersion
|
||||||
if versionString != "" {
|
if versionString != "" {
|
||||||
versionString = " " + versionString
|
versionString = " " + versionString
|
||||||
@@ -209,7 +212,6 @@ func (c *Command) PrintHelp() {
|
|||||||
fmt.Println(c.Longdescription + "\n")
|
fmt.Println(c.Longdescription + "\n")
|
||||||
}
|
}
|
||||||
if len(c.SubCommands) > 0 {
|
if len(c.SubCommands) > 0 {
|
||||||
fmt.Println("")
|
|
||||||
c.log.White("Available commands:")
|
c.log.White("Available commands:")
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
for _, subcommand := range c.SubCommands {
|
for _, subcommand := range c.SubCommands {
|
||||||
@@ -220,9 +222,9 @@ func (c *Command) PrintHelp() {
|
|||||||
}
|
}
|
||||||
fmt.Printf(" %s%s%s %s\n", subcommand.Name, spacer, subcommand.Shortdescription, isDefault)
|
fmt.Printf(" %s%s%s %s\n", subcommand.Name, spacer, subcommand.Shortdescription, isDefault)
|
||||||
}
|
}
|
||||||
|
fmt.Println("")
|
||||||
}
|
}
|
||||||
if c.flagCount > 0 {
|
if c.flagCount > 0 {
|
||||||
fmt.Println("")
|
|
||||||
c.log.White("Flags:")
|
c.log.White("Flags:")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
c.Flags.SetOutput(os.Stdout)
|
c.Flags.SetOutput(os.Stdout)
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FrameworkMetadata contains information about a given framework
|
|
||||||
type FrameworkMetadata struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
BuildTag string `json:"buildtag"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility function for creating new FrameworkMetadata structs
|
|
||||||
func loadFrameworkMetadata(pathToMetadataJSON string) (*FrameworkMetadata, error) {
|
|
||||||
result := &FrameworkMetadata{}
|
|
||||||
configData, err := ioutil.ReadFile(pathToMetadataJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Load and unmarshall!
|
|
||||||
err = json.Unmarshal(configData, result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFrameworks returns information about all the available frameworks
|
|
||||||
func GetFrameworks() ([]*FrameworkMetadata, error) {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Calculate framework base dir
|
|
||||||
_, filename, _, _ := runtime.Caller(1)
|
|
||||||
frameworksBaseDir := filepath.Join(path.Dir(filename), "frameworks")
|
|
||||||
|
|
||||||
// Get the subdirectories
|
|
||||||
fs := NewFSHelper()
|
|
||||||
frameworkDirs, err := fs.GetSubdirs(frameworksBaseDir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare result
|
|
||||||
result := []*FrameworkMetadata{}
|
|
||||||
|
|
||||||
// Iterate framework directories, looking for metadata.json files
|
|
||||||
for _, frameworkDir := range frameworkDirs {
|
|
||||||
var frameworkMetadata FrameworkMetadata
|
|
||||||
metadataFile := filepath.Join(frameworkDir, "metadata.json")
|
|
||||||
jsonData, err := ioutil.ReadFile(metadataFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(jsonData, &frameworkMetadata)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result = append(result, &frameworkMetadata)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read in framework metadata
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// +build frameworkbootstrap4
|
|
||||||
|
|
||||||
package frameworks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gobuffalo/packr"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
assets := packr.NewBox("./bootstrap4default/assets")
|
|
||||||
FrameworkToUse = &Framework{
|
|
||||||
Name: "Bootstrap 4",
|
|
||||||
JS: assets.String("bootstrap.bundle.min.js"),
|
|
||||||
CSS: assets.String("bootstrap.min.css"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// +build frameworkbootstrap4
|
|
||||||
|
|
||||||
package bootstrap4
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gobuffalo/packr"
|
|
||||||
"github.com/wailsapp/wails/frameworks"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
assets := packr.NewBox("./assets")
|
|
||||||
frameworks.FrameworkToUse = &frameworks.Framework{
|
|
||||||
Name: "Bootstrap 4",
|
|
||||||
JS: assets.String("bootstrap.bundle.min.js"),
|
|
||||||
CSS: assets.String("bootstrap.min.css"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"Name": "Bootstrap 4",
|
|
||||||
"Description": "Standard Bootstrap 4 with default theme",
|
|
||||||
"BuildTag": "frameworkbootstrap4"
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// +build frameworkbootstrap4lux
|
|
||||||
|
|
||||||
package frameworks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gobuffalo/packr"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
assets := packr.NewBox("./bootstrap4lux/assets")
|
|
||||||
FrameworkToUse = &Framework{
|
|
||||||
Name: "Bootstrap 4 (Lux)",
|
|
||||||
JS: assets.String("bootstrap.bundle.min.js"),
|
|
||||||
CSS: assets.String("bootstrap.min.css"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// +build frameworkbootstrap4lux
|
|
||||||
|
|
||||||
package bootstrap4
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gobuffalo/packr"
|
|
||||||
"github.com/wailsapp/wails/frameworks"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
assets := packr.NewBox("./assets")
|
|
||||||
frameworks.FrameworkToUse = &frameworks.Framework{
|
|
||||||
Name: "Bootstrap 4 (Lux)",
|
|
||||||
JS: assets.String("bootstrap.bundle.min.js"),
|
|
||||||
CSS: assets.String("bootstrap.min.css"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"Name": "Bootstrap 4 (Lux)",
|
|
||||||
"Description": "Bootstrap with Lux theme",
|
|
||||||
"BuildTag": "frameworkbootstrap4lux"
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package frameworks
|
|
||||||
|
|
||||||
// Framework has details about a specific framework
|
|
||||||
type Framework struct {
|
|
||||||
Name string
|
|
||||||
JS string
|
|
||||||
CSS string
|
|
||||||
Options string
|
|
||||||
}
|
|
||||||
|
|
||||||
// FrameworkToUse is the framework we will use when building
|
|
||||||
// Set by `wails init`, used by `wails build`
|
|
||||||
var FrameworkToUse *Framework
|
|
||||||
16
cmd/fs.go
@@ -80,6 +80,22 @@ func (fs *FSHelper) Cwd() string {
|
|||||||
return cwd
|
return cwd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveFile removes the given filename
|
||||||
|
func (fs *FSHelper) RemoveFile(filename string) error {
|
||||||
|
return os.Remove(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveFiles removes the given filenames
|
||||||
|
func (fs *FSHelper) RemoveFiles(files []string) error {
|
||||||
|
for _, filename := range files {
|
||||||
|
err := os.Remove(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetSubdirs will return a list of FQPs to subdirectories in the given directory
|
// GetSubdirs will return a list of FQPs to subdirectories in the given directory
|
||||||
func (fs *FSHelper) GetSubdirs(dir string) (map[string]string, error) {
|
func (fs *FSHelper) GetSubdirs(dir string) (map[string]string, error) {
|
||||||
|
|
||||||
|
|||||||
279
cmd/helpers.go
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
|
"github.com/leaanthony/spinner"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateFrontendConfig checks if the frontend config is valid
|
||||||
|
func ValidateFrontendConfig(projectOptions *ProjectOptions) error {
|
||||||
|
if projectOptions.FrontEnd.Dir == "" {
|
||||||
|
return fmt.Errorf("Frontend directory not set in project.json")
|
||||||
|
}
|
||||||
|
if projectOptions.FrontEnd.Build == "" {
|
||||||
|
return fmt.Errorf("Frontend build command not set in project.json")
|
||||||
|
}
|
||||||
|
if projectOptions.FrontEnd.Install == "" {
|
||||||
|
return fmt.Errorf("Frontend install command not set in project.json")
|
||||||
|
}
|
||||||
|
if projectOptions.FrontEnd.Bridge == "" {
|
||||||
|
return fmt.Errorf("Frontend bridge config not set in project.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstallGoDependencies will run go get in the current directory
|
||||||
|
func InstallGoDependencies() error {
|
||||||
|
depSpinner := spinner.New("Installing Dependencies...")
|
||||||
|
depSpinner.SetSpinSpeed(50)
|
||||||
|
depSpinner.Start()
|
||||||
|
err := NewProgramHelper().RunCommand("go get")
|
||||||
|
if err != nil {
|
||||||
|
depSpinner.Error()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
depSpinner.Success()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildApplication will attempt to build the project based on the given inputs
|
||||||
|
func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error {
|
||||||
|
|
||||||
|
// Generate Windows assets if needed
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
cleanUp := !packageApp
|
||||||
|
err := NewPackageHelper().PackageWindows(projectOptions, cleanUp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Mewn is installed
|
||||||
|
err := CheckMewn()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
compileMessage := "Packing + Compiling project"
|
||||||
|
|
||||||
|
if buildMode == BuildModeDebug {
|
||||||
|
compileMessage += " (Debug Mode)"
|
||||||
|
}
|
||||||
|
|
||||||
|
packSpinner := spinner.New(compileMessage + "...")
|
||||||
|
packSpinner.SetSpinSpeed(50)
|
||||||
|
packSpinner.Start()
|
||||||
|
|
||||||
|
buildCommand := slicer.String()
|
||||||
|
buildCommand.AddSlice([]string{"mewn", "build"})
|
||||||
|
|
||||||
|
if binaryName != "" {
|
||||||
|
buildCommand.Add("-o")
|
||||||
|
buildCommand.Add(binaryName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are forcing a rebuild
|
||||||
|
if forceRebuild {
|
||||||
|
buildCommand.Add("-a")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup ld flags
|
||||||
|
ldflags := "-w -s "
|
||||||
|
if buildMode == BuildModeDebug {
|
||||||
|
ldflags = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add windows flags
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
ldflags += "-H windowsgui "
|
||||||
|
}
|
||||||
|
|
||||||
|
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
|
||||||
|
|
||||||
|
buildCommand.AddSlice([]string{"-ldflags", ldflags})
|
||||||
|
err = NewProgramHelper().RunCommandArray(buildCommand.AsSlice())
|
||||||
|
if err != nil {
|
||||||
|
packSpinner.Error()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
packSpinner.Success()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PackageApplication will attempt to package the application in a pltform dependent way
|
||||||
|
func PackageApplication(projectOptions *ProjectOptions) error {
|
||||||
|
// Package app
|
||||||
|
message := "Generating .app"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
err := CheckWindres()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
message = "Generating resource bundle"
|
||||||
|
}
|
||||||
|
packageSpinner := spinner.New(message)
|
||||||
|
packageSpinner.SetSpinSpeed(50)
|
||||||
|
packageSpinner.Start()
|
||||||
|
err := NewPackageHelper().Package(projectOptions)
|
||||||
|
if err != nil {
|
||||||
|
packageSpinner.Error()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
packageSpinner.Success()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildFrontend runs the given build command
|
||||||
|
func BuildFrontend(buildCommand string) error {
|
||||||
|
buildFESpinner := spinner.New("Building frontend...")
|
||||||
|
buildFESpinner.SetSpinSpeed(50)
|
||||||
|
buildFESpinner.Start()
|
||||||
|
err := NewProgramHelper().RunCommand(buildCommand)
|
||||||
|
if err != nil {
|
||||||
|
buildFESpinner.Error()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buildFESpinner.Success()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckMewn checks if mewn is installed and if not, attempts to fetch it
|
||||||
|
func CheckMewn() (err error) {
|
||||||
|
programHelper := NewProgramHelper()
|
||||||
|
if !programHelper.IsInstalled("mewn") {
|
||||||
|
buildSpinner := spinner.New()
|
||||||
|
buildSpinner.SetSpinSpeed(50)
|
||||||
|
buildSpinner.Start("Installing Mewn asset packer...")
|
||||||
|
err := programHelper.InstallGoPackage("github.com/leaanthony/mewn/cmd/mewn")
|
||||||
|
if err != nil {
|
||||||
|
buildSpinner.Error()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buildSpinner.Success()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckWindres checks if Windres is installed and if not, aborts
|
||||||
|
func CheckWindres() (err error) {
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
programHelper := NewProgramHelper()
|
||||||
|
if !programHelper.IsInstalled("windres") {
|
||||||
|
return fmt.Errorf("windres not installed. It comes by default with mingw. Ensure you have installed mingw correctly.")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstallFrontendDeps attempts to install the frontend dependencies based on the given options
|
||||||
|
func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forceRebuild bool, caller string) error {
|
||||||
|
|
||||||
|
// Install frontend deps
|
||||||
|
err := os.Chdir(projectOptions.FrontEnd.Dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if frontend deps have been updated
|
||||||
|
feSpinner := spinner.New("Installing frontend dependencies (This may take a while)...")
|
||||||
|
feSpinner.SetSpinSpeed(50)
|
||||||
|
feSpinner.Start()
|
||||||
|
|
||||||
|
requiresNPMInstall := true
|
||||||
|
|
||||||
|
// Read in package.json MD5
|
||||||
|
fs := NewFSHelper()
|
||||||
|
packageJSONMD5, err := fs.FileMD5("package.json")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const md5sumFile = "package.json.md5"
|
||||||
|
|
||||||
|
// If we aren't forcing the install and the md5sum file exists
|
||||||
|
if !forceRebuild && fs.FileExists(md5sumFile) {
|
||||||
|
// Yes - read contents
|
||||||
|
savedMD5sum, err := fs.LoadAsString(md5sumFile)
|
||||||
|
// File exists
|
||||||
|
if err == nil {
|
||||||
|
// Compare md5
|
||||||
|
if savedMD5sum == packageJSONMD5 {
|
||||||
|
// Same - no need for reinstall
|
||||||
|
requiresNPMInstall = false
|
||||||
|
feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Md5 sum package.json
|
||||||
|
// Different? Build
|
||||||
|
if requiresNPMInstall || forceRebuild {
|
||||||
|
// Install dependencies
|
||||||
|
err = NewProgramHelper().RunCommand(projectOptions.FrontEnd.Install)
|
||||||
|
if err != nil {
|
||||||
|
feSpinner.Error()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
feSpinner.Success()
|
||||||
|
|
||||||
|
// Update md5sum file
|
||||||
|
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
bridgeFile := "wailsbridge.prod.js"
|
||||||
|
if caller == "serve" {
|
||||||
|
bridgeFile = "wailsbridge.js"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy bridge to project
|
||||||
|
_, filename, _, _ := runtime.Caller(1)
|
||||||
|
bridgeFileSource := filepath.Join(path.Dir(filename), "..", "..", "wailsruntimeassets", "bridge", bridgeFile)
|
||||||
|
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js")
|
||||||
|
err = fs.CopyFile(bridgeFileSource, bridgeFileTarget)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build frontend
|
||||||
|
err = BuildFrontend(projectOptions.FrontEnd.Build)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServeProject attempts to serve up the current project so that it may be connected to
|
||||||
|
// via the Wails bridge
|
||||||
|
func ServeProject(projectOptions *ProjectOptions, logger *Logger) error {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<")
|
||||||
|
}()
|
||||||
|
location, err := filepath.Abs(projectOptions.BinaryName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Yellow("Serving Application: " + location)
|
||||||
|
cmd := exec.Command(location)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
48
cmd/log.go
@@ -9,52 +9,88 @@ import (
|
|||||||
|
|
||||||
// Logger struct
|
// Logger struct
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
|
errorOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogger creates a new logger!
|
// NewLogger creates a new logger!
|
||||||
func NewLogger() *Logger {
|
func NewLogger() *Logger {
|
||||||
return &Logger{}
|
return &Logger{errorOnly: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) SetErrorOnly(errorOnly bool) {
|
||||||
|
l.errorOnly = errorOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yellow - Outputs yellow text
|
// Yellow - Outputs yellow text
|
||||||
func (l *Logger) Yellow(format string, a ...interface{}) {
|
func (l *Logger) Yellow(format string, a ...interface{}) {
|
||||||
|
if l.errorOnly {
|
||||||
|
return
|
||||||
|
}
|
||||||
color.New(color.FgHiYellow).PrintfFunc()(format+"\n", a...)
|
color.New(color.FgHiYellow).PrintfFunc()(format+"\n", a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yellowf - Outputs yellow text without the newline
|
// Yellowf - Outputs yellow text without the newline
|
||||||
func (l *Logger) Yellowf(format string, a ...interface{}) {
|
func (l *Logger) Yellowf(format string, a ...interface{}) {
|
||||||
|
if l.errorOnly {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
color.New(color.FgHiYellow).PrintfFunc()(format, a...)
|
color.New(color.FgHiYellow).PrintfFunc()(format, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Green - Outputs Green text
|
// Green - Outputs Green text
|
||||||
func (l *Logger) Green(format string, a ...interface{}) {
|
func (l *Logger) Green(format string, a ...interface{}) {
|
||||||
|
if l.errorOnly {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
color.New(color.FgHiGreen).PrintfFunc()(format+"\n", a...)
|
color.New(color.FgHiGreen).PrintfFunc()(format+"\n", a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// White - Outputs White text
|
// White - Outputs White text
|
||||||
func (l *Logger) White(format string, a ...interface{}) {
|
func (l *Logger) White(format string, a ...interface{}) {
|
||||||
|
if l.errorOnly {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
color.New(color.FgHiWhite).PrintfFunc()(format+"\n", a...)
|
color.New(color.FgHiWhite).PrintfFunc()(format+"\n", a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WhiteUnderline - Outputs White text with underline
|
// WhiteUnderline - Outputs White text with underline
|
||||||
func (l *Logger) WhiteUnderline(format string, a ...interface{}) {
|
func (l *Logger) WhiteUnderline(format string, a ...interface{}) {
|
||||||
|
if l.errorOnly {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
l.White(format, a...)
|
l.White(format, a...)
|
||||||
l.White(l.underline(format))
|
l.White(l.underline(format))
|
||||||
}
|
}
|
||||||
|
|
||||||
// YellowUnderline - Outputs Yellow text with underline
|
// YellowUnderline - Outputs Yellow text with underline
|
||||||
func (l *Logger) YellowUnderline(format string, a ...interface{}) {
|
func (l *Logger) YellowUnderline(format string, a ...interface{}) {
|
||||||
|
if l.errorOnly {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
l.Yellow(format, a...)
|
l.Yellow(format, a...)
|
||||||
l.Yellow(l.underline(format))
|
l.Yellow(l.underline(format))
|
||||||
}
|
}
|
||||||
|
|
||||||
// underline returns a string of a line, the length of the message given to it
|
// underline returns a string of a line, the length of the message given to it
|
||||||
func (l *Logger) underline(message string) string {
|
func (l *Logger) underline(message string) string {
|
||||||
|
if l.errorOnly {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
return strings.Repeat("-", len(message))
|
return strings.Repeat("-", len(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Red - Outputs Red text
|
// Red - Outputs Red text
|
||||||
func (l *Logger) Red(format string, a ...interface{}) {
|
func (l *Logger) Red(format string, a ...interface{}) {
|
||||||
|
if l.errorOnly {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
color.New(color.FgHiRed).PrintfFunc()(format+"\n", a...)
|
color.New(color.FgHiRed).PrintfFunc()(format+"\n", a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +99,16 @@ func (l *Logger) Error(format string, a ...interface{}) {
|
|||||||
color.New(color.FgHiRed).PrintfFunc()("Error: "+format+"\n", a...)
|
color.New(color.FgHiRed).PrintfFunc()("Error: "+format+"\n", a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Logger) PrintSmallBanner(message ...string) {
|
||||||
|
yellow := color.New(color.FgYellow).SprintFunc()
|
||||||
|
red := color.New(color.FgRed).SprintFunc()
|
||||||
|
msg := ""
|
||||||
|
if len(message) > 0 {
|
||||||
|
msg = " - " + message[0]
|
||||||
|
}
|
||||||
|
fmt.Printf("%s %s%s\n", yellow("Wails"), red(Version), msg)
|
||||||
|
}
|
||||||
|
|
||||||
// PrintBanner prints the Wails banner before running commands
|
// PrintBanner prints the Wails banner before running commands
|
||||||
func (l *Logger) PrintBanner() error {
|
func (l *Logger) PrintBanner() error {
|
||||||
banner1 := ` _ __ _ __
|
banner1 := ` _ __ _ __
|
||||||
|
|||||||
262
cmd/package.go
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jackmordaunt/icns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PackageHelper helps with the 'wails package' command
|
||||||
|
type PackageHelper struct {
|
||||||
|
fs *FSHelper
|
||||||
|
log *Logger
|
||||||
|
system *SystemHelper
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPackageHelper creates a new PackageHelper!
|
||||||
|
func NewPackageHelper() *PackageHelper {
|
||||||
|
return &PackageHelper{
|
||||||
|
fs: NewFSHelper(),
|
||||||
|
log: NewLogger(),
|
||||||
|
system: NewSystemHelper(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type plistData struct {
|
||||||
|
Title string
|
||||||
|
Exe string
|
||||||
|
PackageID string
|
||||||
|
Version string
|
||||||
|
Author string
|
||||||
|
Date string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPlistData(title, exe, packageID, version, author string) *plistData {
|
||||||
|
now := time.Now().Format(time.RFC822)
|
||||||
|
return &plistData{
|
||||||
|
Title: title,
|
||||||
|
Exe: exe,
|
||||||
|
Version: version,
|
||||||
|
PackageID: packageID,
|
||||||
|
Author: author,
|
||||||
|
Date: now,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultString(val string, defaultVal string) string {
|
||||||
|
if val != "" {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *PackageHelper) getPackageFileBaseDir() string {
|
||||||
|
// Calculate template base dir
|
||||||
|
_, filename, _, _ := runtime.Caller(1)
|
||||||
|
return filepath.Join(path.Dir(filename), "packages", runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Package the application into a platform specific package
|
||||||
|
func (b *PackageHelper) Package(po *ProjectOptions) error {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
// Check we have the exe
|
||||||
|
if !b.fs.FileExists(po.BinaryName) {
|
||||||
|
return fmt.Errorf("cannot bundle non-existant binary file '%s'. Please build with 'wails build' first", po.BinaryName)
|
||||||
|
}
|
||||||
|
return b.packageOSX(po)
|
||||||
|
case "windows":
|
||||||
|
return b.PackageWindows(po, true)
|
||||||
|
case "linux":
|
||||||
|
return fmt.Errorf("linux is not supported at this time. Please see https://github.com/wailsapp/wails/issues/2")
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("platform '%s' not supported for bundling yet", runtime.GOOS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Package the application for OSX
|
||||||
|
func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
|
||||||
|
|
||||||
|
system := NewSystemHelper()
|
||||||
|
config, err := system.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
name := defaultString(po.Name, "WailsTest")
|
||||||
|
exe := defaultString(po.BinaryName, name)
|
||||||
|
version := defaultString(po.Version, "0.1.0")
|
||||||
|
author := defaultString(config.Name, "Anonymous")
|
||||||
|
packageID := strings.Join([]string{"wails", name, version}, ".")
|
||||||
|
plistData := newPlistData(name, exe, packageID, version, author)
|
||||||
|
appname := po.Name + ".app"
|
||||||
|
|
||||||
|
// Check binary exists
|
||||||
|
source := path.Join(b.fs.Cwd(), exe)
|
||||||
|
if !b.fs.FileExists(source) {
|
||||||
|
// We need to build!
|
||||||
|
return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", exe)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the existing package
|
||||||
|
os.RemoveAll(appname)
|
||||||
|
|
||||||
|
exeDir := path.Join(b.fs.Cwd(), appname, "/Contents/MacOS")
|
||||||
|
b.fs.MkDirs(exeDir, 0755)
|
||||||
|
resourceDir := path.Join(b.fs.Cwd(), appname, "/Contents/Resources")
|
||||||
|
b.fs.MkDirs(resourceDir, 0755)
|
||||||
|
tmpl := template.New("infoPlist")
|
||||||
|
plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist")
|
||||||
|
infoPlist, err := ioutil.ReadFile(plistFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tmpl.Parse(string(infoPlist))
|
||||||
|
|
||||||
|
// Write the template to a buffer
|
||||||
|
var tpl bytes.Buffer
|
||||||
|
err = tmpl.Execute(&tpl, plistData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
filename := path.Join(b.fs.Cwd(), appname, "Contents", "Info.plist")
|
||||||
|
err = ioutil.WriteFile(filename, tpl.Bytes(), 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy executable
|
||||||
|
target := path.Join(exeDir, exe)
|
||||||
|
err = b.fs.CopyFile(source, target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chmod(target, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = b.packageIconOSX(resourceDir)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
|
||||||
|
basename := strings.TrimSuffix(po.BinaryName, ".exe")
|
||||||
|
|
||||||
|
// Copy icon
|
||||||
|
tgtIconFile := filepath.Join(b.fs.Cwd(), basename+".ico")
|
||||||
|
if !b.fs.FileExists(tgtIconFile) {
|
||||||
|
srcIconfile := filepath.Join(b.getPackageFileBaseDir(), "wails.ico")
|
||||||
|
err := b.fs.CopyFile(srcIconfile, tgtIconFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy manifest
|
||||||
|
tgtManifestFile := filepath.Join(b.fs.Cwd(), basename+".exe.manifest")
|
||||||
|
if !b.fs.FileExists(tgtManifestFile) {
|
||||||
|
srcManifestfile := filepath.Join(b.getPackageFileBaseDir(), "wails.exe.manifest")
|
||||||
|
err := b.fs.CopyFile(srcManifestfile, tgtManifestFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy rc file
|
||||||
|
tgtRCFile := filepath.Join(b.fs.Cwd(), basename+".rc")
|
||||||
|
if !b.fs.FileExists(tgtRCFile) {
|
||||||
|
srcRCfile := filepath.Join(b.getPackageFileBaseDir(), "wails.rc")
|
||||||
|
rcfilebytes, err := ioutil.ReadFile(srcRCfile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rcfiledata := strings.Replace(string(rcfilebytes), "$NAME$", basename, -1)
|
||||||
|
err = ioutil.WriteFile(tgtRCFile, []byte(rcfiledata), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build syso
|
||||||
|
sysofile := filepath.Join(b.fs.Cwd(), basename+"-res.syso")
|
||||||
|
windresCommand := []string{"windres", "-o", sysofile, tgtRCFile}
|
||||||
|
err := NewProgramHelper().RunCommandArray(windresCommand)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
if cleanUp {
|
||||||
|
filesToDelete := []string{tgtIconFile, tgtManifestFile, tgtRCFile}
|
||||||
|
err := b.fs.RemoveFiles(filesToDelete)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *PackageHelper) copyIcon(resourceDir string) (string, error) {
|
||||||
|
|
||||||
|
// TODO: Read this from project.json
|
||||||
|
const appIconFilename = "appicon.png"
|
||||||
|
srcIcon := path.Join(b.fs.Cwd(), appIconFilename)
|
||||||
|
|
||||||
|
// Check if appicon.png exists
|
||||||
|
if !b.fs.FileExists(srcIcon) {
|
||||||
|
|
||||||
|
// Install default icon
|
||||||
|
iconfile := filepath.Join(b.getPackageFileBaseDir(), "icon.png")
|
||||||
|
iconData, err := ioutil.ReadFile(iconfile)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(srcIcon, iconData, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return srcIcon, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *PackageHelper) packageIconOSX(resourceDir string) error {
|
||||||
|
|
||||||
|
srcIcon, err := b.copyIcon(resourceDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tgtBundle := path.Join(resourceDir, "iconfile.icns")
|
||||||
|
imageFile, err := os.Open(srcIcon)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer imageFile.Close()
|
||||||
|
srcImg, _, err := image.Decode(imageFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
dest, err := os.Create(tgtBundle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
defer dest.Close()
|
||||||
|
if err := icns.Encode(dest, srcImg); err != nil {
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
BIN
cmd/packages/darwin/icon.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
11
cmd/packages/darwin/info.plist
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0"><dict>
|
||||||
|
<key>CFBundleName</key><string>{{.Title}}</string>
|
||||||
|
<key>CFBundleExecutable</key><string>{{.Exe}}</string>
|
||||||
|
<key>CFBundleIdentifier</key><string>{{.PackageID}}</string>
|
||||||
|
<key>CFBundleVersion</key><string>{{.Version}}</string>
|
||||||
|
<key>CFBundleGetInfoString</key><string>Built by {{.Author}} at {{.Date}} using Wails (https://wails.app)</string>
|
||||||
|
<key>CFBundleShortVersionString</key><string>{{.Version}}</string>
|
||||||
|
<key>CFBundleIconFile</key><string>iconfile</string>
|
||||||
|
<key>NSHighResolutionCapable</key><string>true</string>
|
||||||
|
</dict></plist>
|
||||||
BIN
cmd/packages/windows/icon.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
12
cmd/packages/windows/wails.exe.manifest
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<assemblyIdentity type="win32" name="MyApplication" version="1.0.0.0" processorArchitecture="amd64"/>
|
||||||
|
|
||||||
|
<asmv3:application>
|
||||||
|
<asmv3:windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- fallback for Windows 7 and 8 -->
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness> <!-- falls back to per-monitor if per-monitor v2 is not supported -->
|
||||||
|
<gdiScaling xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">true</gdiScaling> <!-- enables GDI DPI scaling -->
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
|
</assembly>
|
||||||
BIN
cmd/packages/windows/wails.ico
Normal file
|
After Width: | Height: | Size: 315 KiB |
2
cmd/packages/windows/wails.rc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
100 ICON "$NAME$.ico"
|
||||||
|
100 24 "$NAME$.exe.manifest"
|
||||||
@@ -2,17 +2,23 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProgramHelper - Utility functions around installed applications
|
// ProgramHelper - Utility functions around installed applications
|
||||||
type ProgramHelper struct{}
|
type ProgramHelper struct {
|
||||||
|
shell *ShellHelper
|
||||||
|
}
|
||||||
|
|
||||||
// NewProgramHelper - Creates a new ProgramHelper
|
// NewProgramHelper - Creates a new ProgramHelper
|
||||||
func NewProgramHelper() *ProgramHelper {
|
func NewProgramHelper() *ProgramHelper {
|
||||||
return &ProgramHelper{}
|
return &ProgramHelper{
|
||||||
|
shell: NewShellHelper(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsInstalled tries to determine if the given binary name is installed
|
// IsInstalled tries to determine if the given binary name is installed
|
||||||
@@ -83,3 +89,46 @@ func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InstallGoPackage installs the given Go package
|
||||||
|
func (p *ProgramHelper) InstallGoPackage(packageName string) error {
|
||||||
|
args := strings.Split("get -u "+packageName, " ")
|
||||||
|
_, stderr, err := p.shell.Run("go", args...)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(stderr)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunCommand runs the given command
|
||||||
|
func (p *ProgramHelper) RunCommand(command string) error {
|
||||||
|
args := strings.Split(command, " ")
|
||||||
|
return p.RunCommandArray(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProgramHelper) GetOutputFromCommand(command string) (string, string, error) {
|
||||||
|
args := strings.Split(command, " ")
|
||||||
|
if len(args) > 1 {
|
||||||
|
return p.shell.Run(args[0], args[1:]...)
|
||||||
|
} else {
|
||||||
|
return p.shell.Run(args[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunCommandArray runs the command specified in the array
|
||||||
|
func (p *ProgramHelper) RunCommandArray(args []string) error {
|
||||||
|
program := args[0]
|
||||||
|
// TODO: Run FindProgram here and get the full path to the exe
|
||||||
|
program, err := exec.LookPath(program)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR: Looks like '%s' isn't installed. Please install and try again.", program)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
args = args[1:]
|
||||||
|
// fmt.Printf("RunCommandArray = %s %+v\n", program, args)
|
||||||
|
_, stderr, err := p.shell.Run(program, args...)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(stderr)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
259
cmd/project.go
@@ -5,9 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/AlecAivazis/survey"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type author struct {
|
type author struct {
|
||||||
@@ -19,6 +18,8 @@ type frontend struct {
|
|||||||
Dir string `json:"dir"`
|
Dir string `json:"dir"`
|
||||||
Install string `json:"install"`
|
Install string `json:"install"`
|
||||||
Build string `json:"build"`
|
Build string `json:"build"`
|
||||||
|
Bridge string `json:"bridge"`
|
||||||
|
Serve string `json:"serve"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type framework struct {
|
type framework struct {
|
||||||
@@ -82,11 +83,27 @@ func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // If we are on windows, dump a windows_resource.json
|
||||||
|
// if runtime.GOOS == "windows" {
|
||||||
|
// ph.GenerateWindowsResourceConfig(projectOptions)
|
||||||
|
// }
|
||||||
|
|
||||||
ph.log.Yellow("Project '%s' generated in directory '%s'!", projectOptions.Name, projectOptions.OutputDirectory)
|
ph.log.Yellow("Project '%s' generated in directory '%s'!", projectOptions.Name, projectOptions.OutputDirectory)
|
||||||
ph.log.Yellow("To compile the project, run 'wails build' in the project directory.")
|
ph.log.Yellow("To compile the project, run 'wails build' in the project directory.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // GenerateWindowsResourceConfig generates the default windows resource file
|
||||||
|
// func (ph *ProjectHelper) GenerateWindowsResourceConfig(po *ProjectOptions) {
|
||||||
|
|
||||||
|
// fmt.Println(buffer.String())
|
||||||
|
|
||||||
|
// // vi.Build()
|
||||||
|
// // vi.Walk()
|
||||||
|
// // err := vi.WriteSyso(outPath, runtime.GOARCH)
|
||||||
|
// }
|
||||||
|
|
||||||
// LoadProjectConfig loads the project config from the given directory
|
// LoadProjectConfig loads the project config from the given directory
|
||||||
func (ph *ProjectHelper) LoadProjectConfig(dir string) (*ProjectOptions, error) {
|
func (ph *ProjectHelper) LoadProjectConfig(dir string) (*ProjectOptions, error) {
|
||||||
po := ph.NewProjectOptions()
|
po := ph.NewProjectOptions()
|
||||||
@@ -118,50 +135,18 @@ func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
|
|||||||
return &result
|
return &result
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectQuestion creates a new select type question for Survey
|
|
||||||
func SelectQuestion(name, message string, options []string, defaultValue string, required bool) *survey.Question {
|
|
||||||
result := survey.Question{
|
|
||||||
Name: name,
|
|
||||||
Prompt: &survey.Select{
|
|
||||||
Message: message,
|
|
||||||
Options: options,
|
|
||||||
Default: defaultValue,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if required {
|
|
||||||
result.Validate = survey.Required
|
|
||||||
}
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputQuestion creates a new input type question for Survey
|
|
||||||
func InputQuestion(name, message string, defaultValue string, required bool) *survey.Question {
|
|
||||||
result := survey.Question{
|
|
||||||
Name: name,
|
|
||||||
Prompt: &survey.Input{
|
|
||||||
Message: message + ":",
|
|
||||||
Default: defaultValue,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if required {
|
|
||||||
result.Validate = survey.Required
|
|
||||||
}
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectOptions holds all the options available for a project
|
// ProjectOptions holds all the options available for a project
|
||||||
type ProjectOptions struct {
|
type ProjectOptions struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Author *author `json:"author,omitempty"`
|
Author *author `json:"author,omitempty"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
OutputDirectory string `json:"-"`
|
OutputDirectory string `json:"-"`
|
||||||
UseDefaults bool `json:"-"`
|
UseDefaults bool `json:"-"`
|
||||||
Template string `json:"-"`
|
Template string `json:"-"`
|
||||||
BinaryName string `json:"binaryname"`
|
BinaryName string `json:"binaryname"`
|
||||||
FrontEnd *frontend `json:"frontend,omitempty"`
|
FrontEnd *frontend `json:"frontend,omitempty"`
|
||||||
NPMProjectName string `json:"-"`
|
NPMProjectName string `json:"-"`
|
||||||
Framework *framework `json:"framework,omitempty"`
|
|
||||||
system *SystemHelper
|
system *SystemHelper
|
||||||
log *Logger
|
log *Logger
|
||||||
templates *TemplateHelper
|
templates *TemplateHelper
|
||||||
@@ -176,41 +161,13 @@ func (po *ProjectOptions) Defaults() {
|
|||||||
// PromptForInputs asks the user to input project details
|
// PromptForInputs asks the user to input project details
|
||||||
func (po *ProjectOptions) PromptForInputs() error {
|
func (po *ProjectOptions) PromptForInputs() error {
|
||||||
|
|
||||||
var questions []*survey.Question
|
processProjectName(po)
|
||||||
fs := NewFSHelper()
|
|
||||||
|
|
||||||
if po.Name == "" {
|
processBinaryName(po)
|
||||||
questions = append(questions, InputQuestion("Name", "The name of the project", "My Project", true))
|
|
||||||
} else {
|
|
||||||
fmt.Println("Project Name: " + po.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if po.BinaryName == "" {
|
err := processOutputDirectory(po)
|
||||||
var binaryNameComputed string
|
if err != nil {
|
||||||
if po.Name != "" {
|
return err
|
||||||
binaryNameComputed = strings.ToLower(po.Name)
|
|
||||||
binaryNameComputed = strings.Replace(binaryNameComputed, " ", "-", -1)
|
|
||||||
binaryNameComputed = strings.Replace(binaryNameComputed, string(filepath.Separator), "-", -1)
|
|
||||||
binaryNameComputed = strings.Replace(binaryNameComputed, ":", "-", -1)
|
|
||||||
}
|
|
||||||
questions = append(questions, InputQuestion("BinaryName", "The output binary name", binaryNameComputed, true))
|
|
||||||
} else {
|
|
||||||
fmt.Println("Output binary Name: " + po.BinaryName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if po.OutputDirectory != "" {
|
|
||||||
projectPath, err := filepath.Abs(po.OutputDirectory)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if fs.DirExists(projectPath) {
|
|
||||||
return fmt.Errorf("directory '%s' already exists", projectPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Project Directory: " + po.OutputDirectory)
|
|
||||||
} else {
|
|
||||||
questions = append(questions, InputQuestion("OutputDirectory", "Project directory name", "", true))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templateDetails, err := po.templates.GetTemplateDetails()
|
templateDetails, err := po.templates.GetTemplateDetails()
|
||||||
@@ -237,51 +194,16 @@ func (po *ProjectOptions) PromptForInputs() error {
|
|||||||
if po.Template != "" {
|
if po.Template != "" {
|
||||||
if _, ok := templateDetails[po.Template]; !ok {
|
if _, ok := templateDetails[po.Template]; !ok {
|
||||||
po.log.Error("Template '%s' invalid.", po.Template)
|
po.log.Error("Template '%s' invalid.", po.Template)
|
||||||
questions = append(questions, SelectQuestion("Template", "Select template", templates, templates[0], true))
|
templateSelected := PromptSelection("Select template", templates)
|
||||||
|
po.Template = templates[templateSelected]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
questions = append(questions, SelectQuestion("Template", "Select template", templates, templates[0], true))
|
templateSelected := PromptSelection("Select template", templates)
|
||||||
}
|
po.Template = templates[templateSelected]
|
||||||
|
|
||||||
err = survey.Ask(questions, po)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup NPM Project name
|
// Setup NPM Project name
|
||||||
po.NPMProjectName = strings.Replace(po.Name, " ", "_", -1)
|
po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1))
|
||||||
|
|
||||||
// If we selected custom, prompt for framework
|
|
||||||
if po.Template == "custom - Choose your own CSS Framework" {
|
|
||||||
// Ask for the framework
|
|
||||||
var frameworkName string
|
|
||||||
frameworks, err := GetFrameworks()
|
|
||||||
frameworkNames := []string{}
|
|
||||||
metadataMap := make(map[string]*FrameworkMetadata)
|
|
||||||
for _, frameworkMetadata := range frameworks {
|
|
||||||
frameworkDetails := fmt.Sprintf("%s - %s", frameworkMetadata.Name, frameworkMetadata.Description)
|
|
||||||
metadataMap[frameworkDetails] = frameworkMetadata
|
|
||||||
frameworkNames = append(frameworkNames, frameworkDetails)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var frameworkQuestion []*survey.Question
|
|
||||||
frameworkQuestion = append(frameworkQuestion, SelectQuestion("Framework", "Select framework", frameworkNames, frameworkNames[0], true))
|
|
||||||
err = survey.Ask(frameworkQuestion, &frameworkName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Get metadata
|
|
||||||
metadata := metadataMap[frameworkName]
|
|
||||||
|
|
||||||
// Add to project config
|
|
||||||
po.Framework = &framework{
|
|
||||||
Name: metadata.Name,
|
|
||||||
BuildTag: metadata.BuildTag,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix template name
|
// Fix template name
|
||||||
if po.templateNameMap[po.Template] != "" {
|
if po.templateNameMap[po.Template] != "" {
|
||||||
@@ -290,21 +212,10 @@ func (po *ProjectOptions) PromptForInputs() error {
|
|||||||
|
|
||||||
// Populate template details
|
// Populate template details
|
||||||
templateMetadata := templateDetails[po.Template].Metadata
|
templateMetadata := templateDetails[po.Template].Metadata
|
||||||
if templateMetadata["frontenddir"] != nil {
|
|
||||||
po.FrontEnd = &frontend{}
|
err = processTemplateMetadata(templateMetadata, po)
|
||||||
po.FrontEnd.Dir = templateMetadata["frontenddir"].(string)
|
if err != nil {
|
||||||
}
|
return err
|
||||||
if templateMetadata["install"] != nil {
|
|
||||||
if po.FrontEnd == nil {
|
|
||||||
return fmt.Errorf("install set in template metadata but not frontenddir")
|
|
||||||
}
|
|
||||||
po.FrontEnd.Install = templateMetadata["install"].(string)
|
|
||||||
}
|
|
||||||
if templateMetadata["build"] != nil {
|
|
||||||
if po.FrontEnd == nil {
|
|
||||||
return fmt.Errorf("build set in template metadata but not frontenddir")
|
|
||||||
}
|
|
||||||
po.FrontEnd.Build = templateMetadata["build"].(string)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -337,3 +248,87 @@ func (po *ProjectOptions) LoadConfig(projectDir string) error {
|
|||||||
}
|
}
|
||||||
return json.Unmarshal(rawBytes, po)
|
return json.Unmarshal(rawBytes, po)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func computeBinaryName(projectName string) string {
|
||||||
|
if projectName == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var binaryNameComputed = strings.ToLower(projectName)
|
||||||
|
binaryNameComputed = strings.Replace(binaryNameComputed, " ", "-", -1)
|
||||||
|
binaryNameComputed = strings.Replace(binaryNameComputed, string(filepath.Separator), "-", -1)
|
||||||
|
binaryNameComputed = strings.Replace(binaryNameComputed, ":", "-", -1)
|
||||||
|
return binaryNameComputed
|
||||||
|
}
|
||||||
|
|
||||||
|
func processOutputDirectory(po *ProjectOptions) error {
|
||||||
|
// po.OutputDirectory
|
||||||
|
if po.OutputDirectory == "" {
|
||||||
|
po.OutputDirectory = PromptRequired("Project directory name", computeBinaryName(po.Name))
|
||||||
|
}
|
||||||
|
projectPath, err := filepath.Abs(po.OutputDirectory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if NewFSHelper().DirExists(projectPath) {
|
||||||
|
return fmt.Errorf("directory '%s' already exists", projectPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Project Directory: " + po.OutputDirectory)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processProjectName(po *ProjectOptions) {
|
||||||
|
if po.Name == "" {
|
||||||
|
po.Name = Prompt("The name of the project", "My Project")
|
||||||
|
}
|
||||||
|
fmt.Println("Project Name: " + po.Name)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func processBinaryName(po *ProjectOptions) {
|
||||||
|
if po.BinaryName == "" {
|
||||||
|
var binaryNameComputed = computeBinaryName(po.Name)
|
||||||
|
po.BinaryName = Prompt("The output binary name", binaryNameComputed)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
if !strings.HasSuffix(po.BinaryName, ".exe") {
|
||||||
|
po.BinaryName += ".exe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Output binary Name: " + po.BinaryName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processTemplateMetadata(templateMetadata map[string]interface{}, po *ProjectOptions) error {
|
||||||
|
if templateMetadata["frontenddir"] != nil {
|
||||||
|
po.FrontEnd = &frontend{}
|
||||||
|
po.FrontEnd.Dir = templateMetadata["frontenddir"].(string)
|
||||||
|
}
|
||||||
|
if templateMetadata["install"] != nil {
|
||||||
|
if po.FrontEnd == nil {
|
||||||
|
return fmt.Errorf("install set in template metadata but not frontenddir")
|
||||||
|
}
|
||||||
|
po.FrontEnd.Install = templateMetadata["install"].(string)
|
||||||
|
}
|
||||||
|
if templateMetadata["build"] != nil {
|
||||||
|
if po.FrontEnd == nil {
|
||||||
|
return fmt.Errorf("build set in template metadata but not frontenddir")
|
||||||
|
}
|
||||||
|
po.FrontEnd.Build = templateMetadata["build"].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if templateMetadata["bridge"] != nil {
|
||||||
|
if po.FrontEnd == nil {
|
||||||
|
return fmt.Errorf("bridge set in template metadata but not frontenddir")
|
||||||
|
}
|
||||||
|
po.FrontEnd.Bridge = templateMetadata["bridge"].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if templateMetadata["serve"] != nil {
|
||||||
|
if po.FrontEnd == nil {
|
||||||
|
return fmt.Errorf("serve set in template metadata but not frontenddir")
|
||||||
|
}
|
||||||
|
po.FrontEnd.Serve = templateMetadata["serve"].(string)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
64
cmd/prompt.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Prompt asks the user for a value
|
||||||
|
func Prompt(question string, defaultValue ...string) string {
|
||||||
|
var answer string
|
||||||
|
haveDefault := len(defaultValue) > 0 && defaultValue[0] != ""
|
||||||
|
|
||||||
|
if haveDefault {
|
||||||
|
question = fmt.Sprintf("%s (%s)", question, defaultValue[0])
|
||||||
|
}
|
||||||
|
fmt.Printf(question + ": ")
|
||||||
|
fmt.Scanln(&answer)
|
||||||
|
if haveDefault {
|
||||||
|
if len(answer) == 0 {
|
||||||
|
answer = defaultValue[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
// PromptRequired calls Prompt repeatedly until a value is given
|
||||||
|
func PromptRequired(question string, defaultValue ...string) string {
|
||||||
|
for {
|
||||||
|
result := Prompt(question, defaultValue...)
|
||||||
|
if result != "" {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PromptSelection asks the user to choose an option
|
||||||
|
func PromptSelection(question string, options []string) int {
|
||||||
|
|
||||||
|
fmt.Println(question + ":")
|
||||||
|
for index, option := range options {
|
||||||
|
fmt.Printf(" %d: %s\n", index+1, option)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
selectedValue := -1
|
||||||
|
|
||||||
|
for {
|
||||||
|
choice := Prompt("Please choose an option")
|
||||||
|
|
||||||
|
// index
|
||||||
|
number, err := strconv.Atoi(choice)
|
||||||
|
if err == nil {
|
||||||
|
if number > 0 && number <= len(options) {
|
||||||
|
selectedValue = number - 1
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedValue
|
||||||
|
}
|
||||||
27
cmd/shell.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ShellHelper helps with Shell commands
|
||||||
|
type ShellHelper struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewShellHelper creates a new ShellHelper!
|
||||||
|
func NewShellHelper() *ShellHelper {
|
||||||
|
return &ShellHelper{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the given command
|
||||||
|
func (sh *ShellHelper) Run(command string, vars ...string) (stdout, stderr string, err error) {
|
||||||
|
cmd := exec.Command(command, vars...)
|
||||||
|
var stdo, stde bytes.Buffer
|
||||||
|
cmd.Stdout = &stdo
|
||||||
|
cmd.Stderr = &stde
|
||||||
|
err = cmd.Run()
|
||||||
|
stdout = string(stdo.Bytes())
|
||||||
|
stderr = string(stde.Bytes())
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AlecAivazis/survey"
|
|
||||||
homedir "github.com/mitchellh/go-homedir"
|
homedir "github.com/mitchellh/go-homedir"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -82,9 +81,6 @@ func (s *SystemHelper) BackupConfig() (string, error) {
|
|||||||
|
|
||||||
func (s *SystemHelper) setup() error {
|
func (s *SystemHelper) setup() error {
|
||||||
|
|
||||||
// Answers. We all need them.
|
|
||||||
answers := &SystemConfig{}
|
|
||||||
|
|
||||||
// Try to load current values - ignore errors
|
// Try to load current values - ignore errors
|
||||||
config, err := s.LoadConfig()
|
config, err := s.LoadConfig()
|
||||||
defaultName := ""
|
defaultName := ""
|
||||||
@@ -93,31 +89,10 @@ func (s *SystemHelper) setup() error {
|
|||||||
defaultName = config.Name
|
defaultName = config.Name
|
||||||
defaultEmail = config.Email
|
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
|
systemConfig := make(map[string]string)
|
||||||
err = survey.Ask(simpleQs, answers)
|
systemConfig["name"] = PromptRequired("What is your name", defaultName)
|
||||||
if err != nil {
|
systemConfig["email"] = PromptRequired("What is your email address", defaultEmail)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the directory
|
// Create the directory
|
||||||
err = s.fs.MkDirs(s.wailsSystemDir)
|
err = s.fs.MkDirs(s.wailsSystemDir)
|
||||||
@@ -125,12 +100,21 @@ func (s *SystemHelper) setup() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save
|
||||||
|
configData, err := json.Marshal(&systemConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(s.wailsSystemConfig, configData, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
s.log.White("Wails config saved to: " + s.wailsSystemConfig)
|
s.log.White("Wails config saved to: " + s.wailsSystemConfig)
|
||||||
s.log.White("Feel free to customise these settings.")
|
s.log.White("Feel free to customise these settings.")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
return answers.Save(s.wailsSystemConfig)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const introText = `
|
const introText = `
|
||||||
@@ -220,6 +204,15 @@ func (sc *SystemConfig) load(filename string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckDependenciesSilent checks for dependencies but
|
||||||
|
// only outputs if there's an error
|
||||||
|
func CheckDependenciesSilent(logger *Logger) (bool, error) {
|
||||||
|
logger.SetErrorOnly(true)
|
||||||
|
result, err := CheckDependencies(logger)
|
||||||
|
logger.SetErrorOnly(false)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
// CheckDependencies will look for Wails dependencies on the system
|
// CheckDependencies will look for Wails dependencies on the system
|
||||||
// Errors are reported in error and the bool return value is whether
|
// Errors are reported in error and the bool return value is whether
|
||||||
// the dependencies are all installed.
|
// the dependencies are all installed.
|
||||||
@@ -281,6 +274,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logger.White("")
|
||||||
|
|
||||||
return !errors, err
|
return !errors, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
"github.com/alecthomas/template"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const templateSuffix = ".template"
|
const templateSuffix = ".template"
|
||||||
|
|
||||||
|
// TemplateHelper helps with creating projects
|
||||||
type TemplateHelper struct {
|
type TemplateHelper struct {
|
||||||
system *SystemHelper
|
system *SystemHelper
|
||||||
fs *FSHelper
|
fs *FSHelper
|
||||||
@@ -25,12 +25,14 @@ type TemplateHelper struct {
|
|||||||
metadataFilename string
|
metadataFilename string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Template defines a single template
|
||||||
type Template struct {
|
type Template struct {
|
||||||
Name string
|
Name string
|
||||||
Dir string
|
Dir string
|
||||||
Metadata map[string]interface{}
|
Metadata map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTemplateHelper creates a new template helper
|
||||||
func NewTemplateHelper() *TemplateHelper {
|
func NewTemplateHelper() *TemplateHelper {
|
||||||
result := TemplateHelper{
|
result := TemplateHelper{
|
||||||
system: NewSystemHelper(),
|
system: NewSystemHelper(),
|
||||||
@@ -45,6 +47,7 @@ func NewTemplateHelper() *TemplateHelper {
|
|||||||
return &result
|
return &result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTemplateNames returns a map of all available templates
|
||||||
func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) {
|
func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) {
|
||||||
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
|
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -53,6 +56,8 @@ func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) {
|
|||||||
return templateDirs, nil
|
return templateDirs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTemplateDetails returns a map of Template structs containing details
|
||||||
|
// of the found templates
|
||||||
func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) {
|
func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) {
|
||||||
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
|
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -81,6 +86,7 @@ func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadMetadata loads the template's 'metadata.json' file
|
||||||
func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error) {
|
func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error) {
|
||||||
templateFile := filepath.Join(dir, t.metadataFilename)
|
templateFile := filepath.Join(dir, t.metadataFilename)
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
@@ -95,6 +101,7 @@ func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TemplateExists returns true if the given template name exists
|
||||||
func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) {
|
func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) {
|
||||||
templates, err := t.GetTemplateNames()
|
templates, err := t.GetTemplateNames()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,6 +111,8 @@ func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) {
|
|||||||
return exists, nil
|
return exists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InstallTemplate installs the template given in the project options to the
|
||||||
|
// project path given
|
||||||
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
|
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
|
||||||
|
|
||||||
// Get template files
|
// Get template files
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
wails "github.com/wailsapp/wails"
|
|
||||||
)
|
|
||||||
|
|
||||||
var html = `<h1> Basic Template </h1>`
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
// Initialise the app
|
|
||||||
app := wails.CreateApp(&wails.AppConfig{
|
|
||||||
Width: 1024,
|
|
||||||
Height: 768,
|
|
||||||
Title: "My Project",
|
|
||||||
HTML: html,
|
|
||||||
})
|
|
||||||
app.Run()
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Basic",
|
|
||||||
"shortdescription": "A basic template",
|
|
||||||
"description": "A basic template using vanilla JS",
|
|
||||||
"author": "Lea Anthony<lea.anthony@gmail.com>",
|
|
||||||
"created": "2018-10-18"
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
wails "github.com/wailsapp/wails"
|
|
||||||
)
|
|
||||||
|
|
||||||
var html = `<h1> Custom Project </h1>`
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
// Initialise the app
|
|
||||||
app := wails.CreateApp(&wails.AppConfig{
|
|
||||||
Width: 800,
|
|
||||||
Height: 600,
|
|
||||||
Title: "My Project",
|
|
||||||
HTML: html,
|
|
||||||
})
|
|
||||||
app.Run()
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Custom",
|
|
||||||
"shortdescription": "Choose your own CSS Framework",
|
|
||||||
"description": "A basic template allowing use of CSS Frameworks",
|
|
||||||
"author": "Lea Anthony<lea.anthony@gmail.com>",
|
|
||||||
"created": "2018-10-22"
|
|
||||||
}
|
|
||||||
@@ -1,29 +1,35 @@
|
|||||||
# frontend
|
# vue basic
|
||||||
|
|
||||||
## Project setup
|
## Project setup
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and hot-reloads for development
|
### Compiles and hot-reloads for development
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run serve
|
npm run serve
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and minifies for production
|
### Compiles and minifies for production
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run your tests
|
### Run your tests
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run test
|
npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
### Lints and fixes files
|
### Lints and fixes files
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run lint
|
npm run lint
|
||||||
```
|
```
|
||||||
|
|
||||||
### Customize configuration
|
### Customize configuration
|
||||||
|
|
||||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||||
11109
cmd/templates/vuebasic/frontend/package-lock.json
generated
Normal file
1
cmd/templates/vuebasic/frontend/package.json.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2b79f883dc856221fc3265755d610e40
|
||||||
49
cmd/templates/vuebasic/frontend/package.json.template
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "{{.NPMProjectName}}",
|
||||||
|
"author": "{{.Author.Name}}<{{.Author.Email}}>",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"core-js": "^2.6.4",
|
||||||
|
"vue": "^2.5.22"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "^3.4.0",
|
||||||
|
"@vue/cli-plugin-eslint": "^3.4.0",
|
||||||
|
"@vue/cli-service": "^3.4.0",
|
||||||
|
"babel-eslint": "^10.0.1",
|
||||||
|
"eslint": "^5.8.0",
|
||||||
|
"eslint-plugin-vue": "^5.0.0",
|
||||||
|
"eventsource-polyfill": "^0.9.6",
|
||||||
|
"vue-template-compiler": "^2.5.21",
|
||||||
|
"webpack-hot-middleware": "^2.24.3"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"rules": {},
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"plugins": {
|
||||||
|
"autoprefixer": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -5,11 +5,11 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
<title>frontend</title>
|
<title>my-vue-app-01</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<strong>We're sorry but frontend doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
<strong>We're sorry but my-vue-app-01 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
@@ -1,22 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<img alt="Wails logo" src="./assets/images/logo.png" class="logo zoomIn">
|
<img alt="Wails logo" src="./assets/images/logo.png" class="logo zoomIn">
|
||||||
<HelloWorld msg="Welcome to Your Wails App!"/>
|
<HelloWorld/>
|
||||||
<Quote/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import HelloWorld from "./components/HelloWorld.vue";
|
import HelloWorld from "./components/HelloWorld.vue";
|
||||||
import Quote from "./components/Quote.vue";
|
|
||||||
import "./assets/css/main.css";
|
import "./assets/css/main.css";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "app",
|
name: "app",
|
||||||
components: {
|
components: {
|
||||||
HelloWorld,
|
HelloWorld
|
||||||
Quote
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -10,21 +10,6 @@
|
|||||||
html {
|
html {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
/* https://leaverou.github.io/css3patterns/#carbon */
|
|
||||||
background: linear-gradient(27deg, #151515 5px, transparent 5px) 0 5px,
|
|
||||||
linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0px,
|
|
||||||
linear-gradient(27deg, #222 5px, transparent 5px) 0px 10px,
|
|
||||||
linear-gradient(207deg, #222 5px, transparent 5px) 10px 5px,
|
|
||||||
linear-gradient(90deg, #1b1b1b 10px, transparent 10px),
|
|
||||||
linear-gradient(
|
|
||||||
#1d1d1d 25%,
|
|
||||||
#1a1a1a 25%,
|
|
||||||
#1a1a1a 50%,
|
|
||||||
transparent 50%,
|
|
||||||
transparent 75%,
|
|
||||||
#242424 75%,
|
|
||||||
#242424
|
|
||||||
);
|
|
||||||
background-color: #131313;
|
background-color: #131313;
|
||||||
background-size: 20px 20px;
|
background-size: 20px 20px;
|
||||||
}
|
}
|
||||||
@@ -46,10 +31,8 @@ html {
|
|||||||
format("woff2"),
|
format("woff2"),
|
||||||
/* Super Modern Browsers */
|
/* Super Modern Browsers */
|
||||||
url("../fonts/roboto/roboto-v18-latin-regular.woff") format("woff"),
|
url("../fonts/roboto/roboto-v18-latin-regular.woff") format("woff"),
|
||||||
/* Modern Browsers */
|
/* Modern Browsers */ url("../fonts/roboto/roboto-v18-latin-regular.ttf")
|
||||||
url("../fonts/roboto/roboto-v18-latin-regular.ttf")
|
|
||||||
format("truetype"),
|
format("truetype"),
|
||||||
/* Safari, Android, iOS */
|
/* Safari, Android, iOS */
|
||||||
url("../fonts/roboto/roboto-v18-latin-regular.svg#Roboto")
|
url("../fonts/roboto/roboto-v18-latin-regular.svg#Roboto") format("svg"); /* Legacy iOS */
|
||||||
format("svg"); /* Legacy iOS */
|
}
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 301 KiB After Width: | Height: | Size: 301 KiB |
@@ -0,0 +1,55 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<h1>{{message}}</h1>
|
||||||
|
<a @click="getMessage">Press Me!</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
message: " "
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMessage: function() {
|
||||||
|
var self = this;
|
||||||
|
window.backend.basic().then(result => {
|
||||||
|
self.message = result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
h1 {
|
||||||
|
margin-top: 2em;
|
||||||
|
position: relative;
|
||||||
|
min-height: 5rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
font-size: 1.7em;
|
||||||
|
border-color: blue;
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
border: 3px solid white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: 500ms;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
font-size: 1.7em;
|
||||||
|
border-color: white;
|
||||||
|
background-color: #121212;
|
||||||
|
color: white;
|
||||||
|
border: 3px solid white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
12
cmd/templates/vuebasic/frontend/src/main.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import App from "./App.vue";
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
|
import Bridge from "./wailsbridge";
|
||||||
|
|
||||||
|
Bridge.Start(() => {
|
||||||
|
new Vue({
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount("#app");
|
||||||
|
});
|
||||||
17
cmd/templates/vuebasic/frontend/src/wailsbridge.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Wails Bridge (c) 2019-present Lea Anthony
|
||||||
|
|
||||||
|
This prod version is to get around having to rewrite your code
|
||||||
|
for production. When doing a release build, this file will be used
|
||||||
|
instead of the full version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// The main function
|
||||||
|
// Passes the main Wails object to the callback if given.
|
||||||
|
Start: function(callback) {
|
||||||
|
if (callback) {
|
||||||
|
window.wails.events.on("wails:ready", callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
43
cmd/templates/vuebasic/frontend/vue.config.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
let cssConfig = {};
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV == "production") {
|
||||||
|
cssConfig = {
|
||||||
|
extract: {
|
||||||
|
filename: "[name].css",
|
||||||
|
chunkFilename: "[name].css"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
chainWebpack: config => {
|
||||||
|
let limit = 9999999999999999;
|
||||||
|
config.module
|
||||||
|
.rule("images")
|
||||||
|
.test(/\.(png|gif|jpg)(\?.*)?$/i)
|
||||||
|
.use("url-loader")
|
||||||
|
.loader("url-loader")
|
||||||
|
.tap(options => Object.assign(options, { limit: limit }));
|
||||||
|
config.module
|
||||||
|
.rule("fonts")
|
||||||
|
.test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i)
|
||||||
|
.use("url-loader")
|
||||||
|
.loader("url-loader")
|
||||||
|
.options({
|
||||||
|
limit: limit
|
||||||
|
});
|
||||||
|
},
|
||||||
|
css: cssConfig,
|
||||||
|
configureWebpack: {
|
||||||
|
output: {
|
||||||
|
filename: "[name].js"
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
splitChunks: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
disableHostCheck: true,
|
||||||
|
host: "localhost"
|
||||||
|
}
|
||||||
|
};
|
||||||
1
cmd/templates/vuebasic/go.mod.template
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module {{.BinaryName}}
|
||||||
24
cmd/templates/vuebasic/main.go.template
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/wailsapp/wails"
|
||||||
|
)
|
||||||
|
|
||||||
|
func basic() string {
|
||||||
|
return "Hello World!"
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
app := wails.CreateApp(&wails.AppConfig{
|
||||||
|
Width: 1024,
|
||||||
|
Height: 768,
|
||||||
|
Title: "{{.Name}}",
|
||||||
|
JS: mewn.String("./frontend/dist/app.js"),
|
||||||
|
CSS: mewn.String("./frontend/dist/app.css"),
|
||||||
|
Colour: "#131313",
|
||||||
|
})
|
||||||
|
app.Bind(basic)
|
||||||
|
app.Run()
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "Vue2/Webpack",
|
"name": "Vue2/Webpack Basic",
|
||||||
"shortdescription": "A basic Vue2/WebPack4 template",
|
"shortdescription": "A basic Vue2/WebPack4 template",
|
||||||
"description": "A basic template using Vue 2 and bundled using Webpack 4",
|
"description": "A basic template using Vue 2 and bundled using Webpack 4",
|
||||||
"author": "Lea Anthony<lea.anthony@gmail.com>",
|
"author": "Lea Anthony<lea.anthony@gmail.com>",
|
||||||
"created": "2018-12-01",
|
"created": "2018-12-01",
|
||||||
"frontenddir": "frontend",
|
"frontenddir": "frontend",
|
||||||
"install": "npm install",
|
"install": "npm install",
|
||||||
"build": "npm run build"
|
"build": "npm run build",
|
||||||
}
|
"serve": "npm run serve",
|
||||||
|
"bridge": "src"
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
> 1%
|
|
||||||
last 2 versions
|
|
||||||
not ie <= 8
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "frontend",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"serve": "vue-cli-service serve",
|
|
||||||
"build": "vue-cli-service build"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"vue": "^2.5.17"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@vue/cli-plugin-babel": "^3.1.1",
|
|
||||||
"@vue/cli-service": "^3.1.4",
|
|
||||||
"vue-template-compiler": "^2.5.17"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
autoprefixer: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
Credit: https://codepen.io/harmputman/pen/IpAnb
|
|
||||||
**/
|
|
||||||
|
|
||||||
body {
|
|
||||||
font: normal 300 1em/1.5em sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
background: #fff;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 480px;
|
|
||||||
min-width: 320px;
|
|
||||||
margin: 2em auto 0;
|
|
||||||
padding: 1.5em;
|
|
||||||
opacity: 0.8;
|
|
||||||
border-radius: 1em;
|
|
||||||
border-color: #117;
|
|
||||||
}
|
|
||||||
|
|
||||||
p { margin-bottom: 1.5em; }
|
|
||||||
p:last-child { margin-bottom: 0; }
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
display: block;
|
|
||||||
border-width: 2px 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: #eee;
|
|
||||||
padding: 1.5em 0 0.5em;
|
|
||||||
margin: 1.5em 0;
|
|
||||||
position: relative;
|
|
||||||
color: #117;
|
|
||||||
}
|
|
||||||
blockquote:before {
|
|
||||||
content: '\201C';
|
|
||||||
position: absolute;
|
|
||||||
top: 0em;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
background: #fff;
|
|
||||||
width: 3rem;
|
|
||||||
height: 2rem;
|
|
||||||
font: 6em/1.08em sans-serif;
|
|
||||||
color: #666;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
blockquote:after {
|
|
||||||
content: "\2013 \2003" attr(cite);
|
|
||||||
display: block;
|
|
||||||
text-align: right;
|
|
||||||
font-size: 0.875em;
|
|
||||||
color: #e70000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* https://fdossena.com/?p=html5cool/buttons/i.frag */
|
|
||||||
button {
|
|
||||||
display:inline-block;
|
|
||||||
padding:0.35em 1.2em;
|
|
||||||
border:0.1em solid #000;
|
|
||||||
margin:0 0.3em 0.3em 0;
|
|
||||||
border-radius:0.12em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
text-decoration:none;
|
|
||||||
font-family:'Roboto',sans-serif;
|
|
||||||
font-weight:300;
|
|
||||||
font-size: 1em;
|
|
||||||
color:#000;
|
|
||||||
text-align:center;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
button:hover{
|
|
||||||
color:#FFF;
|
|
||||||
background-color:#000;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="hello">
|
|
||||||
<h1>{{ msg }}</h1>
|
|
||||||
<p></p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "HelloWorld",
|
|
||||||
props: {
|
|
||||||
msg: String
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
||||||
<style scoped>
|
|
||||||
.hello {
|
|
||||||
margin-top: 2em;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
margin: 40px 0 0;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: gold;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<blockquote v-if="quote != null" :cite="quote.person">{{ quote.text }}</blockquote>
|
|
||||||
<p></p>
|
|
||||||
<button @click="getNewQuote()">Get new Quote</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import "../assets/css/quote.css";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
quote: null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getNewQuote: function() {
|
|
||||||
var self = this;
|
|
||||||
wails.$.main.QuotesCollection.GetQuote().then(result => {
|
|
||||||
console.log(result);
|
|
||||||
self.quote = result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.getNewQuote();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
||||||
<style scoped>
|
|
||||||
.hello {
|
|
||||||
margin-top: 2em;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
margin: 40px 0 0;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: gold;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import App from './App.vue'
|
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
|
||||||
|
|
||||||
new Vue({
|
|
||||||
render: h => h(App),
|
|
||||||
}).$mount('#app')
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
|
|
||||||
module.exports = {
|
|
||||||
chainWebpack: (config) => {
|
|
||||||
let limit = 9999999999999999;
|
|
||||||
config.module
|
|
||||||
.rule('images')
|
|
||||||
.test(/\.(png|gif|jpg)(\?.*)?$/i)
|
|
||||||
.use('url-loader')
|
|
||||||
.loader('url-loader')
|
|
||||||
.tap(options => Object.assign(options, { limit: limit }));
|
|
||||||
config.module
|
|
||||||
.rule('fonts')
|
|
||||||
.test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i)
|
|
||||||
.use('url-loader')
|
|
||||||
.loader('url-loader')
|
|
||||||
.options({
|
|
||||||
limit: limit,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
css: {
|
|
||||||
extract: {
|
|
||||||
filename: '[name].css',
|
|
||||||
chunkFilename: '[name].css',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
configureWebpack: {
|
|
||||||
output: {
|
|
||||||
filename: '[name].js',
|
|
||||||
},
|
|
||||||
optimization: {
|
|
||||||
splitChunks: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gobuffalo/packr"
|
|
||||||
"github.com/wailsapp/wails"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
assets := packr.NewBox("./frontend/dist")
|
|
||||||
|
|
||||||
app := wails.CreateApp(&wails.AppConfig{
|
|
||||||
Width: 1024,
|
|
||||||
Height: 768,
|
|
||||||
Title: "Vue Simple",
|
|
||||||
JS: assets.String("app.js"),
|
|
||||||
CSS: assets.String("app.css"),
|
|
||||||
})
|
|
||||||
app.Bind(newQuotesCollection())
|
|
||||||
app.Run()
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Quote holds a single quote and the person who said it
|
|
||||||
type Quote struct {
|
|
||||||
Text string `json:"text"`
|
|
||||||
Person string `json:"person"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// QuotesCollection holds a collection of quotes!
|
|
||||||
type QuotesCollection struct {
|
|
||||||
quotes []*Quote
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddQuote creates a Quote object with the given inputs and
|
|
||||||
// adds it to the Quotes collection
|
|
||||||
func (Q *QuotesCollection) AddQuote(text, person string) {
|
|
||||||
Q.quotes = append(Q.quotes, &Quote{Text: text, Person: person})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetQuote returns a random Quote object from the Quotes collection
|
|
||||||
func (Q *QuotesCollection) GetQuote() *Quote {
|
|
||||||
return Q.quotes[rand.Intn(len(Q.quotes))]
|
|
||||||
}
|
|
||||||
|
|
||||||
// newQuotesCollection creates a new QuotesCollection
|
|
||||||
func newQuotesCollection() *QuotesCollection {
|
|
||||||
result := &QuotesCollection{}
|
|
||||||
rand.Seed(time.Now().Unix())
|
|
||||||
result.AddQuote("Age is an issue of mind over matter. If you don't mind, it doesn't matter", "Mark Twain")
|
|
||||||
result.AddQuote("Anyone who stops learning is old, whether at twenty or eighty. Anyone who keeps learning stays young. The greatest thing in life is to keep your mind young", "Henry Ford")
|
|
||||||
result.AddQuote("Wrinkles should merely indicate where smiles have been", "Mark Twain")
|
|
||||||
result.AddQuote("True terror is to wake up one morning and discover that your high school class is running the country", "Kurt Vonnegut")
|
|
||||||
result.AddQuote("A diplomat is a man who always remembers a woman's birthday but never remembers her age", "Robert Frost")
|
|
||||||
result.AddQuote("As I grow older, I pay less attention to what men say. I just watch what they do", "Andrew Carnegie")
|
|
||||||
result.AddQuote("How incessant and great are the ills with which a prolonged old age is replete", "C. S. Lewis")
|
|
||||||
result.AddQuote("Old age, believe me, is a good and pleasant thing. It is true you are gently shouldered off the stage, but then you are given such a comfortable front stall as spectator", "Confucius")
|
|
||||||
result.AddQuote("Old age has deformities enough of its own. It should never add to them the deformity of vice", "Eleanor Roosevelt")
|
|
||||||
result.AddQuote("Nobody grows old merely by living a number of years. We grow old by deserting our ideals. Years may wrinkle the skin, but to give up enthusiasm wrinkles the soul", "Samuel Ullman")
|
|
||||||
result.AddQuote("An archaeologist is the best husband a woman can have. The older she gets the more interested he is in her", "Agatha Christie")
|
|
||||||
result.AddQuote("All diseases run into one, old age", "Ralph Waldo Emerson")
|
|
||||||
result.AddQuote("Bashfulness is an ornament to youth, but a reproach to old age", "Aristotle")
|
|
||||||
result.AddQuote("Like everyone else who makes the mistake of getting older, I begin each day with coffee and obituaries", "Bill Cosby")
|
|
||||||
result.AddQuote("Age appears to be best in four things old wood best to burn, old wine to drink, old friends to trust, and old authors to read", "Francis Bacon")
|
|
||||||
result.AddQuote("None are so old as those who have outlived enthusiasm", "Henry David Thoreau")
|
|
||||||
result.AddQuote("Every man over forty is a scoundrel", "George Bernard Shaw")
|
|
||||||
result.AddQuote("Forty is the old age of youth fifty the youth of old age", "Victor Hugo")
|
|
||||||
result.AddQuote("You can't help getting older, but you don't have to get old", "George Burns")
|
|
||||||
result.AddQuote("Alas, after a certain age every man is responsible for his face", "Albert Camus")
|
|
||||||
result.AddQuote("Youth is when you're allowed to stay up late on New Year's Eve. Middle age is when you're forced to", "Bill Vaughan")
|
|
||||||
result.AddQuote("Old age is like everything else. To make a success of it, you've got to start young", "Theodore Roosevelt")
|
|
||||||
result.AddQuote("A comfortable old age is the reward of a well-spent youth. Instead of its bringing sad and melancholy prospects of decay, it would give us hopes of eternal youth in a better world", "Maurice Chevalier")
|
|
||||||
result.AddQuote("A man growing old becomes a child again", "Sophocles")
|
|
||||||
result.AddQuote("I will never be an old man. To me, old age is always 15 years older than I am", "Francis Bacon")
|
|
||||||
result.AddQuote("Age considers youth ventures", "Rabindranath Tagore")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
@@ -2,4 +2,4 @@ package cmd
|
|||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
// ...oO(There must be a better way)
|
// ...oO(There must be a better way)
|
||||||
const Version = "v0.5.0"
|
const Version = "v0.9.5"
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ func init() {
|
|||||||
|
|
||||||
setupCommand.Action(func() error {
|
setupCommand.Action(func() error {
|
||||||
|
|
||||||
|
logger.PrintBanner();
|
||||||
|
|
||||||
system := cmd.NewSystemHelper()
|
system := cmd.NewSystemHelper()
|
||||||
err := system.Initialise()
|
err := system.Initialise()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -29,61 +31,29 @@ Create your first project by running 'wails init'.`
|
|||||||
if runtime.GOOS != "windows" {
|
if runtime.GOOS != "windows" {
|
||||||
successMessage = "🚀 " + successMessage
|
successMessage = "🚀 " + successMessage
|
||||||
}
|
}
|
||||||
switch runtime.GOOS {
|
// Platform check
|
||||||
case "darwin":
|
err = platformCheck()
|
||||||
logger.Yellow("Detected Platform: OSX")
|
|
||||||
case "windows":
|
|
||||||
logger.Yellow("Detected Platform: Windows")
|
|
||||||
case "linux":
|
|
||||||
logger.Yellow("Detected Platform: Linux")
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Platform %s is currently not supported", runtime.GOOS)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Yellow("Checking for prerequisites...")
|
|
||||||
// Check we have a cgo capable environment
|
|
||||||
|
|
||||||
requiredPrograms, err := cmd.GetRequiredPrograms()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
errors := false
|
|
||||||
programHelper := cmd.NewProgramHelper()
|
// Check we have a cgo capable environment
|
||||||
for _, program := range *requiredPrograms {
|
logger.Yellow("Checking for prerequisites...")
|
||||||
bin := programHelper.FindProgram(program.Name)
|
errors, err := checkRequiredPrograms()
|
||||||
if bin == nil {
|
if err != nil {
|
||||||
errors = true
|
return err
|
||||||
logger.Red("Program '%s' not found. %s", program.Name, program.Help)
|
|
||||||
} else {
|
|
||||||
logger.Green("Program '%s' found: %s", program.Name, bin.Path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linux has library deps
|
// Linux has library deps
|
||||||
if runtime.GOOS == "linux" {
|
errors, err = checkLibraries()
|
||||||
// Check library prerequisites
|
if err != nil {
|
||||||
requiredLibraries, err := cmd.GetRequiredLibraries()
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
// Check Mewn
|
||||||
distroInfo := cmd.GetLinuxDistroInfo()
|
err = cmd.CheckMewn()
|
||||||
for _, library := range *requiredLibraries {
|
if err != nil {
|
||||||
switch distroInfo.Distribution {
|
return err
|
||||||
case cmd.Ubuntu:
|
|
||||||
installed, err := cmd.DpkgInstalled(library.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !installed {
|
|
||||||
errors = true
|
|
||||||
logger.Red("Library '%s' not found. %s", library.Name, library.Help)
|
|
||||||
} else {
|
|
||||||
logger.Green("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("")
|
logger.White("")
|
||||||
@@ -95,3 +65,65 @@ Create your first project by running 'wails init'.`
|
|||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func platformCheck() error {
|
||||||
|
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:
|
||||||
|
return fmt.Errorf("Platform %s is currently not supported", runtime.GOOS)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkLibraries() (errors bool, err error) {
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
// Check library prerequisites
|
||||||
|
requiredLibraries, err := cmd.GetRequiredLibraries()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
distroInfo := cmd.GetLinuxDistroInfo()
|
||||||
|
for _, library := range *requiredLibraries {
|
||||||
|
switch distroInfo.Distribution {
|
||||||
|
case cmd.Ubuntu:
|
||||||
|
installed, err := cmd.DpkgInstalled(library.Name)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !installed {
|
||||||
|
errors = true
|
||||||
|
logger.Red("Library '%s' not found. %s", library.Name, library.Help)
|
||||||
|
} else {
|
||||||
|
logger.Green("Library '%s' installed.", library.Name)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRequiredPrograms() (errors bool, err error) {
|
||||||
|
requiredPrograms, err := cmd.GetRequiredPrograms()
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
errors = false
|
||||||
|
programHelper := cmd.NewProgramHelper()
|
||||||
|
for _, program := range *requiredPrograms {
|
||||||
|
bin := programHelper.FindProgram(program.Name)
|
||||||
|
if bin == nil {
|
||||||
|
errors = true
|
||||||
|
logger.Red("Program '%s' not found. %s", program.Name, program.Help)
|
||||||
|
} else {
|
||||||
|
logger.Green("Program '%s' found: %s", program.Name, bin.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
20
cmd/wails/10_version.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
commandDescription := `Outputs the current version of the wails cli tool.`
|
||||||
|
|
||||||
|
versionCommand := app.Command("version", "Print Wails cli version").
|
||||||
|
LongDescription(commandDescription)
|
||||||
|
|
||||||
|
versionCommand.Action(func() error {
|
||||||
|
fmt.Println(cmd.Version)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
49
cmd/wails/12_report.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
commandDescription := `Generates a report to help resolve issues.`
|
||||||
|
|
||||||
|
versionCommand := app.Command("report", "Generates Report").
|
||||||
|
LongDescription(commandDescription)
|
||||||
|
|
||||||
|
versionCommand.Action(func() error {
|
||||||
|
modules := os.Getenv("GO111MODULE")
|
||||||
|
if modules == "" {
|
||||||
|
modules = "(Not set)"
|
||||||
|
}
|
||||||
|
fmt.Println("Please copy and paste this report when creating issues")
|
||||||
|
fmt.Println("------------------------------------------------------")
|
||||||
|
fmt.Printf("Wails Version: %s\n", cmd.Version)
|
||||||
|
fmt.Println("Go:")
|
||||||
|
fmt.Printf(" GOOS : %s\n", runtime.GOOS)
|
||||||
|
fmt.Printf(" GOARCH : %s\n", runtime.GOARCH)
|
||||||
|
fmt.Printf(" Version : %s\n", runtime.Version())
|
||||||
|
fmt.Println("Environment:")
|
||||||
|
fmt.Printf(" Shell : %s\n", getShell())
|
||||||
|
fmt.Printf(" GO111MODULE: %s\n", modules)
|
||||||
|
fmt.Println("------------------------------------------------------")
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getShell() string {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
return os.Getenv("COMSPEC")
|
||||||
|
case "linux":
|
||||||
|
return os.Getenv("SHELL")
|
||||||
|
case "darwin":
|
||||||
|
return os.Getenv("SHELL")
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ Any flags that are required and not given will be prompted for.`
|
|||||||
|
|
||||||
initCommand.Action(func() error {
|
initCommand.Action(func() error {
|
||||||
|
|
||||||
logger.WhiteUnderline("Initialising project")
|
logger.PrintSmallBanner("Initialising project")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
// Check if the system is initialised
|
// Check if the system is initialised
|
||||||
@@ -34,13 +34,11 @@ Any flags that are required and not given will be prompted for.`
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
success, err := cmd.CheckDependencies(logger)
|
success, err := cmd.CheckDependenciesSilent(logger)
|
||||||
if !success {
|
if !success {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.White("")
|
|
||||||
|
|
||||||
// Do we want to just force defaults?
|
// Do we want to just force defaults?
|
||||||
if projectOptions.UseDefaults {
|
if projectOptions.UseDefaults {
|
||||||
// Use defaults
|
// Use defaults
|
||||||
102
cmd/wails/4_build.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/leaanthony/spinner"
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
var packageApp = false
|
||||||
|
var forceRebuild = false
|
||||||
|
var debugMode = false
|
||||||
|
buildSpinner := spinner.NewSpinner()
|
||||||
|
buildSpinner.SetSpinSpeed(50)
|
||||||
|
|
||||||
|
commandDescription := `This command will check to ensure all pre-requistes are installed prior to building. If not, it will attempt to install them. Building comprises of a number of steps: install frontend dependencies, build frontend, pack frontend, compile main application.`
|
||||||
|
initCmd := app.Command("build", "Builds your Wails project").
|
||||||
|
LongDescription(commandDescription).
|
||||||
|
BoolFlag("p", "Package application on successful build", &packageApp).
|
||||||
|
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
||||||
|
BoolFlag("d", "Build in Debug mode", &debugMode)
|
||||||
|
|
||||||
|
initCmd.Action(func() error {
|
||||||
|
|
||||||
|
message := "Building Application"
|
||||||
|
if forceRebuild {
|
||||||
|
message += " (force rebuild)"
|
||||||
|
}
|
||||||
|
logger.PrintSmallBanner(message)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Project options
|
||||||
|
projectOptions := &cmd.ProjectOptions{}
|
||||||
|
|
||||||
|
// Check we are in project directory
|
||||||
|
// Check project.json loads correctly
|
||||||
|
fs := cmd.NewFSHelper()
|
||||||
|
err := projectOptions.LoadConfig(fs.Cwd())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate config
|
||||||
|
// Check if we have a frontend
|
||||||
|
err = cmd.ValidateFrontendConfig(projectOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Program checker
|
||||||
|
program := cmd.NewProgramHelper()
|
||||||
|
|
||||||
|
if projectOptions.FrontEnd != nil {
|
||||||
|
// npm
|
||||||
|
if !program.IsInstalled("npm") {
|
||||||
|
return fmt.Errorf("it appears npm is not installed. Please install and run again")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save project directory
|
||||||
|
projectDir := fs.Cwd()
|
||||||
|
|
||||||
|
// Install deps
|
||||||
|
if projectOptions.FrontEnd != nil {
|
||||||
|
err = cmd.InstallFrontendDeps(projectDir, projectOptions, forceRebuild, "build")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to project directory
|
||||||
|
err = os.Chdir(projectDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install dependencies
|
||||||
|
err = cmd.InstallGoDependencies()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build application
|
||||||
|
buildMode := cmd.BuildModeProd
|
||||||
|
if debugMode {
|
||||||
|
buildMode = cmd.BuildModeDebug
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, packageApp, projectOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
59
cmd/wails/6_serve.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/leaanthony/spinner"
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
var forceRebuild = false
|
||||||
|
buildSpinner := spinner.NewSpinner()
|
||||||
|
buildSpinner.SetSpinSpeed(50)
|
||||||
|
|
||||||
|
commandDescription := `This command builds then serves your application in bridge mode. Useful for developing your app in a browser.`
|
||||||
|
initCmd := app.Command("serve", "Run your Wails project in bridge mode.").
|
||||||
|
LongDescription(commandDescription).
|
||||||
|
BoolFlag("f", "Force rebuild of application components", &forceRebuild)
|
||||||
|
|
||||||
|
initCmd.Action(func() error {
|
||||||
|
|
||||||
|
message := "Serving Application"
|
||||||
|
logger.PrintSmallBanner(message)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Project options
|
||||||
|
projectOptions := &cmd.ProjectOptions{}
|
||||||
|
|
||||||
|
// Check we are in project directory
|
||||||
|
// Check project.json loads correctly
|
||||||
|
fs := cmd.NewFSHelper()
|
||||||
|
err := projectOptions.LoadConfig(fs.Cwd())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Mewn is installed
|
||||||
|
err = cmd.CheckMewn()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install dependencies
|
||||||
|
err = cmd.InstallGoDependencies()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buildMode := cmd.BuildModeBridge
|
||||||
|
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, false, projectOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
||||||
|
return cmd.ServeProject(projectOptions, logger)
|
||||||
|
})
|
||||||
|
}
|
||||||
81
cmd/wails/8_update.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/leaanthony/spinner"
|
||||||
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
// var forceRebuild = false
|
||||||
|
checkSpinner := spinner.NewSpinner()
|
||||||
|
checkSpinner.SetSpinSpeed(50)
|
||||||
|
|
||||||
|
commandDescription := `This command checks if there are updates to Wails.`
|
||||||
|
updateCmd := app.Command("update", "Check for Updates.").
|
||||||
|
LongDescription(commandDescription)
|
||||||
|
|
||||||
|
updateCmd.Action(func() error {
|
||||||
|
|
||||||
|
message := "Checking for updates..."
|
||||||
|
logger.PrintSmallBanner(message)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Get versions
|
||||||
|
checkSpinner.Start(message)
|
||||||
|
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/tags")
|
||||||
|
if err != nil {
|
||||||
|
checkSpinner.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
checkSpinner.Success()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
checkSpinner.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data := []map[string]interface{}{}
|
||||||
|
err = json.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
latestVersion := data[0]["name"].(string)
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Current Version: " + cmd.Version)
|
||||||
|
fmt.Println(" Latest Version: " + latestVersion)
|
||||||
|
if latestVersion != cmd.Version {
|
||||||
|
updateSpinner := spinner.NewSpinner()
|
||||||
|
updateSpinner.SetSpinSpeed(40)
|
||||||
|
updateSpinner.Start("Updating to : " + latestVersion)
|
||||||
|
err = cmd.NewProgramHelper().RunCommandArray([]string{"go", "get", "-u", "-a", "github.com/wailsapp/wails/cmd/wails"})
|
||||||
|
if err != nil {
|
||||||
|
updateSpinner.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
version, _, err := cmd.NewProgramHelper().GetOutputFromCommand("wails version")
|
||||||
|
version = strings.TrimSpace(version)
|
||||||
|
if err != nil {
|
||||||
|
updateSpinner.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if version != latestVersion {
|
||||||
|
updateSpinner.Error()
|
||||||
|
logger.Yellow("Weird! Wails was supposed to update to %s but seems to be at %s instead.", latestVersion, version)
|
||||||
|
} else {
|
||||||
|
updateSpinner.Success()
|
||||||
|
logger.Green("Success! Wails updated to " + version)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.Yellow("Looks like you're up to date!")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -10,15 +10,8 @@ var logger = cmd.NewLogger()
|
|||||||
// Create main app
|
// Create main app
|
||||||
var app = cmd.NewCli("wails", "A cli tool for building Wails applications.")
|
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!
|
// Main!
|
||||||
func main() {
|
func main() {
|
||||||
app.PreRun(printBanner)
|
|
||||||
err := app.Run()
|
err := app.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err.Error())
|
logger.Error(err.Error())
|
||||||
|
|||||||
148
event_manager.go
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// eventManager handles and processes events
|
||||||
|
type eventManager struct {
|
||||||
|
incomingEvents chan *eventData
|
||||||
|
listeners map[string][]*eventListener
|
||||||
|
exit bool
|
||||||
|
log *CustomLogger
|
||||||
|
renderer Renderer // Messages will be dispatched to the frontend
|
||||||
|
}
|
||||||
|
|
||||||
|
// newEventManager creates a new event manager with a 100 event buffer
|
||||||
|
func newEventManager() *eventManager {
|
||||||
|
return &eventManager{
|
||||||
|
incomingEvents: make(chan *eventData, 100),
|
||||||
|
listeners: make(map[string][]*eventListener),
|
||||||
|
exit: false,
|
||||||
|
log: newCustomLogger("Events"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushEvent places the given event on to the event queue
|
||||||
|
func (e *eventManager) PushEvent(eventData *eventData) {
|
||||||
|
e.incomingEvents <- eventData
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventListener holds a callback function which is invoked when
|
||||||
|
// the event listened for is emitted. It has a counter which indicates
|
||||||
|
// how the total number of events it is interested in. A value of zero
|
||||||
|
// means it does not expire (default).
|
||||||
|
type eventListener struct {
|
||||||
|
callback func(...interface{}) // Function to call with emitted event data
|
||||||
|
counter int // Expire after counter callbacks. 0 = infinite
|
||||||
|
expired bool // Indicates if the listener has expired
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new event listener from the given callback function
|
||||||
|
func (e *eventManager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
|
||||||
|
|
||||||
|
// Sanity check inputs
|
||||||
|
if callback == nil {
|
||||||
|
return fmt.Errorf("nil callback bassed to addEventListener")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check event has been registered before
|
||||||
|
if e.listeners[eventName] == nil {
|
||||||
|
e.listeners[eventName] = []*eventListener{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the callback
|
||||||
|
listener := &eventListener{
|
||||||
|
callback: callback,
|
||||||
|
counter: counter,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register listener
|
||||||
|
e.listeners[eventName] = append(e.listeners[eventName], listener)
|
||||||
|
|
||||||
|
// All good mate
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *eventManager) On(eventName string, callback func(...interface{})) {
|
||||||
|
// Add a persistent eventListener (counter = 0)
|
||||||
|
e.addEventListener(eventName, callback, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit broadcasts the given event to the subscribed listeners
|
||||||
|
func (e *eventManager) Emit(eventName string, optionalData ...interface{}) {
|
||||||
|
e.incomingEvents <- &eventData{Name: eventName, Data: optionalData}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts the event manager's queue processing
|
||||||
|
func (e *eventManager) start(renderer Renderer) {
|
||||||
|
|
||||||
|
e.log.Info("Starting")
|
||||||
|
|
||||||
|
// Store renderer
|
||||||
|
e.renderer = renderer
|
||||||
|
|
||||||
|
// Set up waitgroup so we can wait for goroutine to start
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
// Run main loop in seperate goroutine
|
||||||
|
go func() {
|
||||||
|
wg.Done()
|
||||||
|
e.log.Info("Listening")
|
||||||
|
for e.exit == false {
|
||||||
|
// TODO: Listen for application exit
|
||||||
|
select {
|
||||||
|
case event := <-e.incomingEvents:
|
||||||
|
e.log.DebugFields("Got Event", Fields{
|
||||||
|
"data": event.Data,
|
||||||
|
"name": event.Name,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Notify renderer
|
||||||
|
e.renderer.NotifyEvent(event)
|
||||||
|
|
||||||
|
// Notify Go listeners
|
||||||
|
var listenersToRemove []*eventListener
|
||||||
|
|
||||||
|
// Iterate listeners
|
||||||
|
for _, listener := range e.listeners[event.Name] {
|
||||||
|
|
||||||
|
// Call listener, perhaps with data
|
||||||
|
if event.Data == nil {
|
||||||
|
go listener.callback()
|
||||||
|
} else {
|
||||||
|
unpacked := event.Data.([]interface{})
|
||||||
|
go listener.callback(unpacked...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update listen counter
|
||||||
|
if listener.counter > 0 {
|
||||||
|
listener.counter = listener.counter - 1
|
||||||
|
if listener.counter == 0 {
|
||||||
|
listener.expired = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove expired listners in place
|
||||||
|
if len(listenersToRemove) > 0 {
|
||||||
|
listeners := e.listeners[event.Name][:0]
|
||||||
|
for _, listener := range listeners {
|
||||||
|
if !listener.expired {
|
||||||
|
listeners = append(listeners, listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for goroutine to start
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *eventManager) stop() {
|
||||||
|
e.exit = true
|
||||||
|
}
|
||||||
31
go.mod
@@ -1,17 +1,24 @@
|
|||||||
module github.com/wailsapp/wails
|
module github.com/wailsapp/wails
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AlecAivazis/survey v1.7.1
|
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc
|
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac
|
||||||
|
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect
|
||||||
github.com/fatih/color v1.7.0
|
github.com/fatih/color v1.7.0
|
||||||
github.com/gobuffalo/packr v1.21.9
|
github.com/go-playground/colors v1.2.0
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/gorilla/websocket v1.4.0
|
||||||
github.com/leaanthony/spinner v0.4.0
|
github.com/jackmordaunt/icns v1.0.0
|
||||||
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 // indirect
|
github.com/leaanthony/mewn v0.9.1
|
||||||
github.com/leaanthony/wincursor v0.0.0-20180705115120-056510f32d15 // indirect
|
github.com/leaanthony/slicer v1.0.0
|
||||||
github.com/mattn/go-colorable v0.0.9 // indirect
|
github.com/leaanthony/spinner v0.5.0
|
||||||
github.com/mattn/go-isatty v0.0.4 // indirect
|
github.com/mattn/go-colorable v0.1.1 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/go-homedir v1.0.0
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.7.1 // indirect
|
github.com/pkg/errors v0.8.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.3.0
|
||||||
|
github.com/stretchr/testify v1.3.0 // indirect
|
||||||
|
github.com/wailsapp/webview v0.2.5
|
||||||
|
golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f // indirect
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20190222171317-cd391775e71e // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
419
go.sum
@@ -1,371 +1,76 @@
|
|||||||
github.com/AlecAivazis/survey v1.7.1 h1:a84v5MG2296rBkTP0e+dd4l7NxFQ69v4jzMpErkjVxc=
|
|
||||||
github.com/AlecAivazis/survey v1.7.1/go.mod h1:MVECab6WqEH1aXhj8nKIwF7HEAJAj2bhhGiSjNy3wII=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
|
||||||
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
|
||||||
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
|
||||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc h1:VBS1z48BFEe00G81z8MKOtwX7f/ISkuH38NscT8iVPw=
|
||||||
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc/go.mod h1:ABJPuor7YlcsHmvJ1QxX38e2NcufLY3hm0yXv+cy9sI=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac h1:DpMwFluHWoZpV9ex5XjkWO4HyCz5HLVI8XbHw0FhHi4=
|
||||||
|
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac/go.mod h1:XsAE+b4rOZc8gvgsgF+wU75mNBvBcyED1wdd9PBLlJ0=
|
||||||
|
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 h1:Fm10/KNuoAyBm2P5P5H91Xy21hGcZnBdjR+cMdytv1M=
|
||||||
|
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947/go.mod h1:Dv9D0NUlAsaQcGQZa5kc5mqR9ua72SmA8VXi4cd+cBw=
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
github.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M=
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
github.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY=
|
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||||
github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs=
|
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=
|
||||||
github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4=
|
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||||
github.com/gobuffalo/buffalo-plugins v1.4.3/go.mod h1:uCzTY0woez4nDMdQjkcOYKanngeUVRO2HZi7ezmAjWY=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
github.com/gobuffalo/buffalo-plugins v1.5.1/go.mod h1:jbmwSZK5+PiAP9cC09VQOrGMZFCa/P0UMlIS3O12r5w=
|
|
||||||
github.com/gobuffalo/buffalo-plugins v1.6.4/go.mod h1:/+N1aophkA2jZ1ifB2O3Y9yGwu6gKOVMtUmJnbg+OZI=
|
|
||||||
github.com/gobuffalo/buffalo-plugins v1.6.5/go.mod h1:0HVkbgrVs/MnPZ/FOseDMVanCTm2RNcdM0PuXcL1NNI=
|
|
||||||
github.com/gobuffalo/buffalo-plugins v1.6.7/go.mod h1:ZGZRkzz2PiKWHs0z7QsPBOTo2EpcGRArMEym6ghKYgk=
|
|
||||||
github.com/gobuffalo/buffalo-plugins v1.6.9/go.mod h1:yYlYTrPdMCz+6/+UaXg5Jm4gN3xhsvsQ2ygVatZV5vw=
|
|
||||||
github.com/gobuffalo/buffalo-plugins v1.6.11/go.mod h1:eAA6xJIL8OuynJZ8amXjRmHND6YiusVAaJdHDN1Lu8Q=
|
|
||||||
github.com/gobuffalo/buffalo-plugins v1.8.2/go.mod h1:9te6/VjEQ7pKp7lXlDIMqzxgGpjlKoAcAANdCgoR960=
|
|
||||||
github.com/gobuffalo/buffalo-plugins v1.8.3/go.mod h1:IAWq6vjZJVXebIq2qGTLOdlXzmpyTZ5iJG5b59fza5U=
|
|
||||||
github.com/gobuffalo/buffalo-pop v1.0.5/go.mod h1:Fw/LfFDnSmB/vvQXPvcXEjzP98Tc+AudyNWUBWKCwQ8=
|
|
||||||
github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc=
|
|
||||||
github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
|
|
||||||
github.com/gobuffalo/envy v1.6.6/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
|
|
||||||
github.com/gobuffalo/envy v1.6.7/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
|
|
||||||
github.com/gobuffalo/envy v1.6.8/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
|
|
||||||
github.com/gobuffalo/envy v1.6.9/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
|
|
||||||
github.com/gobuffalo/envy v1.6.10/go.mod h1:X0CFllQjTV5ogsnUrg+Oks2yTI+PU2dGYBJOEI2D1Uo=
|
|
||||||
github.com/gobuffalo/envy v1.6.11 h1:dCKSFypLRvqaaUtyzkfKKF2j35ce5agsqfyIrRmm02E=
|
|
||||||
github.com/gobuffalo/envy v1.6.11/go.mod h1:Fiq52W7nrHGDggFPhn2ZCcHw4u/rqXkqo+i7FB6EAcg=
|
|
||||||
github.com/gobuffalo/events v1.0.3/go.mod h1:Txo8WmqScapa7zimEQIwgiJBvMECMe9gJjsKNPN3uZw=
|
|
||||||
github.com/gobuffalo/events v1.0.7/go.mod h1:z8txf6H9jWhQ5Scr7YPLWg/cgXBRj8Q4uYI+rsVCCSQ=
|
|
||||||
github.com/gobuffalo/events v1.0.8/go.mod h1:A5KyqT1sA+3GJiBE4QKZibse9mtOcI9nw8gGrDdqYGs=
|
|
||||||
github.com/gobuffalo/events v1.1.3/go.mod h1:9yPGWYv11GENtzrIRApwQRMYSbUgCsZ1w6R503fCfrk=
|
|
||||||
github.com/gobuffalo/events v1.1.4/go.mod h1:09/YRRgZHEOts5Isov+g9X2xajxdvOAcUuAHIX/O//A=
|
|
||||||
github.com/gobuffalo/events v1.1.5/go.mod h1:3YUSzgHfYctSjEjLCWbkXP6djH2M+MLaVRzb4ymbAK0=
|
|
||||||
github.com/gobuffalo/events v1.1.7/go.mod h1:6fGqxH2ing5XMb3EYRq9LEkVlyPGs4oO/eLzh+S8CxY=
|
|
||||||
github.com/gobuffalo/events v1.1.8/go.mod h1:UFy+W6X6VbCWS8k2iT81HYX65dMtiuVycMy04cplt/8=
|
|
||||||
github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc=
|
|
||||||
github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
|
|
||||||
github.com/gobuffalo/flect v0.0.0-20181002182613-4571df4b1daf/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
|
|
||||||
github.com/gobuffalo/flect v0.0.0-20181007231023-ae7ed6bfe683/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
|
|
||||||
github.com/gobuffalo/flect v0.0.0-20181018182602-fd24a256709f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
|
|
||||||
github.com/gobuffalo/flect v0.0.0-20181019110701-3d6f0b585514/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
|
|
||||||
github.com/gobuffalo/flect v0.0.0-20181024204909-8f6be1a8c6c2/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
|
|
||||||
github.com/gobuffalo/flect v0.0.0-20181104133451-1f6e9779237a/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
|
|
||||||
github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328/go.mod h1:0HvNbHdfh+WOvDSIASqJOSxTOWSxCCUF++k/Y53v9rI=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181005145118-318a41a134cc/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181007153042-b8de7d566757/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181012161047-33e5f43d83a6/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181017160347-90a774534246/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181024195656-51392254bf53/go.mod h1:o9GEH5gn5sCKLVB5rHFC4tq40rQ3VRUzmx6WwmaqISE=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181025145300-af3f81d526b8/go.mod h1:uZ1fFYvdcP8mu0B/Ynarf6dsGvp7QFIpk/QACUuFUVI=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181027191429-94d6cfb5c7fc/go.mod h1:x7SkrQQBx204Y+O9EwRXeszLJDTaWN0GnEasxgLrQTA=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181027195209-3887b7171c4f/go.mod h1:JbKx8HSWICu5zyqWOa0dVV1pbbXOHusrSzQUprW6g+w=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181106193839-7dcb0924caf1/go.mod h1:x61yHxvbDCgQ/7cOAbJCacZQuHgB0KMSzoYcw5debjU=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181107223128-f18346459dbe/go.mod h1:utQD3aKKEsdb03oR+Vi/6ztQb1j7pO10N3OBoowRcSU=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181114215459-0a4decd77f5d/go.mod h1:kN2KZ8VgXF9VIIOj/GM0Eo7YK+un4Q3tTreKOf0q1ng=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181119162812-e8ff4adce8bb/go.mod h1:BA9htSe4bZwBDJLe8CUkoqkypq3hn3+CkoHqVOW718E=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181127225641-2d959acc795b/go.mod h1:l54xLXNkteX/PdZ+HlgPk1qtcrgeOr3XUBBPDbH+7CQ=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181128191930-77e34f71ba2a/go.mod h1:FW/D9p7cEEOqxYA71/hnrkOWm62JZ5ZNxcNIVJEaWBU=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181203165245-fda8bcce96b1/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181203201232-849d2c9534ea/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181206121324-d6fb8a0dbe36/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181207164119-84844398a37d/go.mod h1:y0ysCHGGQf2T3vOhCrGHheYN54Y/REj0ayd0Suf4C/8=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20181211165820-e26c8466f14d/go.mod h1:sHnK+ZSU4e2feXP3PA29ouij6PUEiN+RCwECjCTB3yM=
|
|
||||||
github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I=
|
|
||||||
github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY=
|
|
||||||
github.com/gobuffalo/github_flavored_markdown v1.0.7/go.mod h1:w93Pd9Lz6LvyQXEG6DktTPHkOtCbr+arAD5mkwMzXLI=
|
|
||||||
github.com/gobuffalo/httptest v1.0.2/go.mod h1:7T1IbSrg60ankme0aDLVnEY0h056g9M1/ZvpVThtB7E=
|
|
||||||
github.com/gobuffalo/licenser v0.0.0-20180924033006-eae28e638a42/go.mod h1:Ubo90Np8gpsSZqNScZZkVXXAo5DGhTb+WYFIjlnog8w=
|
|
||||||
github.com/gobuffalo/licenser v0.0.0-20181025145548-437d89de4f75/go.mod h1:x3lEpYxkRG/XtGCUNkio+6RZ/dlOvLzTI9M1auIwFcw=
|
|
||||||
github.com/gobuffalo/licenser v0.0.0-20181027200154-58051a75da95/go.mod h1:BzhaaxGd1tq1+OLKObzgdCV9kqVhbTulxOpYbvMQWS0=
|
|
||||||
github.com/gobuffalo/licenser v0.0.0-20181109171355-91a2a7aac9a7/go.mod h1:m+Ygox92pi9bdg+gVaycvqE8RVSjZp7mWw75+K5NPHk=
|
|
||||||
github.com/gobuffalo/licenser v0.0.0-20181128165715-cc7305f8abed/go.mod h1:oU9F9UCE+AzI/MueCKZamsezGOOHfSirltllOVeRTAE=
|
|
||||||
github.com/gobuffalo/licenser v0.0.0-20181203160806-fe900bbede07/go.mod h1:ph6VDNvOzt1CdfaWC+9XwcBnlSTBz2j49PBwum6RFaU=
|
|
||||||
github.com/gobuffalo/logger v0.0.0-20181022175615-46cfb361fc27/go.mod h1:8sQkgyhWipz1mIctHF4jTxmJh1Vxhp7mP8IqbljgJZo=
|
|
||||||
github.com/gobuffalo/logger v0.0.0-20181027144941-73d08d2bb969/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8=
|
|
||||||
github.com/gobuffalo/logger v0.0.0-20181027193913-9cf4dd0efe46/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8=
|
|
||||||
github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17/go.mod h1:oNErH0xLe+utO+OW8ptXMSA5DkiSEDW1u3zGIt8F9Ew=
|
|
||||||
github.com/gobuffalo/logger v0.0.0-20181117211126-8e9b89b7c264/go.mod h1:5etB91IE0uBlw9k756fVKZJdS+7M7ejVhmpXXiSFj0I=
|
|
||||||
github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c/go.mod h1:+HxKANrR9VGw9yN3aOAppJKvhO05ctDi63w4mDnKv2U=
|
|
||||||
github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw=
|
|
||||||
github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
|
||||||
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
|
||||||
github.com/gobuffalo/meta v0.0.0-20181018155829-df62557efcd3/go.mod h1:XTTOhwMNryif3x9LkTTBO/Llrveezd71u3quLd0u7CM=
|
|
||||||
github.com/gobuffalo/meta v0.0.0-20181018192820-8c6cef77dab3/go.mod h1:E94EPzx9NERGCY69UWlcj6Hipf2uK/vnfrF4QD0plVE=
|
|
||||||
github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a/go.mod h1:YDAKBud2FP7NZdruCSlmTmDOZbVSa6bpK7LJ/A/nlKg=
|
|
||||||
github.com/gobuffalo/meta v0.0.0-20181114191255-b130ebedd2f7/go.mod h1:K6cRZ29ozr4Btvsqkjvg5nDFTLOgTqf03KA70Ks0ypE=
|
|
||||||
github.com/gobuffalo/meta v0.0.0-20181127070345-0d7e59dd540b/go.mod h1:RLO7tMvE0IAKAM8wny1aN12pvEKn7EtkBLkUZR00Qf8=
|
|
||||||
github.com/gobuffalo/mw-basicauth v1.0.3/go.mod h1:dg7+ilMZOKnQFHDefUzUHufNyTswVUviCBgF244C1+0=
|
|
||||||
github.com/gobuffalo/mw-contenttype v0.0.0-20180802152300-74f5a47f4d56/go.mod h1:7EvcmzBbeCvFtQm5GqF9ys6QnCxz2UM1x0moiWLq1No=
|
|
||||||
github.com/gobuffalo/mw-csrf v0.0.0-20180802151833-446ff26e108b/go.mod h1:sbGtb8DmDZuDUQoxjr8hG1ZbLtZboD9xsn6p77ppcHo=
|
|
||||||
github.com/gobuffalo/mw-forcessl v0.0.0-20180802152810-73921ae7a130/go.mod h1:JvNHRj7bYNAMUr/5XMkZaDcw3jZhUZpsmzhd//FFWmQ=
|
|
||||||
github.com/gobuffalo/mw-i18n v0.0.0-20180802152014-e3060b7e13d6/go.mod h1:91AQfukc52A6hdfIfkxzyr+kpVYDodgAeT5cjX1UIj4=
|
|
||||||
github.com/gobuffalo/mw-paramlogger v0.0.0-20181005191442-d6ee392ec72e/go.mod h1:6OJr6VwSzgJMqWMj7TYmRUqzNe2LXu/W1rRW4MAz/ME=
|
|
||||||
github.com/gobuffalo/mw-tokenauth v0.0.0-20181001105134-8545f626c189/go.mod h1:UqBF00IfKvd39ni5+yI5MLMjAf4gX7cDKN/26zDOD6c=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181027182251-01ad393492c8/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181027190505-aafc0d02c411/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181027194105-7ae579e6d213/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181104210303-d376b15f8e96/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181111195323-b2e760a5f0ff/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181114190715-f25c5d2471d7/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181124090624-311c6248e5fb/go.mod h1:Foenia9ZvITEvG05ab6XpiD5EfBHPL8A6hush8SJ0o8=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181207120301-c49825f8f6f4/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687 h1:uZ+G4JprR0UEq0aHZs+6eP7TEZuFfrIkmQWejIBV/QQ=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA=
|
|
||||||
github.com/gobuffalo/packr v1.13.7/go.mod h1:KkinLIn/n6+3tVXMwg6KkNvWwVsrRAz4ph+jgpk3Z24=
|
|
||||||
github.com/gobuffalo/packr v1.15.0/go.mod h1:t5gXzEhIviQwVlNx/+3SfS07GS+cZ2hn76WLzPp6MGI=
|
|
||||||
github.com/gobuffalo/packr v1.15.1/go.mod h1:IeqicJ7jm8182yrVmNbM6PR4g79SjN9tZLH8KduZZwE=
|
|
||||||
github.com/gobuffalo/packr v1.19.0/go.mod h1:MstrNkfCQhd5o+Ct4IJ0skWlxN8emOq8DsoT1G98VIU=
|
|
||||||
github.com/gobuffalo/packr v1.20.0/go.mod h1:JDytk1t2gP+my1ig7iI4NcVaXr886+N0ecUga6884zw=
|
|
||||||
github.com/gobuffalo/packr v1.21.0/go.mod h1:H00jGfj1qFKxscFJSw8wcL4hpQtPe1PfU2wa6sg/SR0=
|
|
||||||
github.com/gobuffalo/packr v1.21.9 h1:zBaEhCmJpYy/UdHGAGIC3vO5Uh7RW091le41+Ydcg4E=
|
|
||||||
github.com/gobuffalo/packr v1.21.9/go.mod h1:GC76q6nMzRtR+AEN/VV4w0z2/4q7SOaEmXh3Ooa8sOE=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.0.0-rc.8/go.mod h1:y60QCdzwuMwO2R49fdQhsjCPv7tLQFR0ayzxxla9zes=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.0.0-rc.9/go.mod h1:fQqADRfZpEsgkc7c/K7aMew3n4aF1Kji7+lIZeR98Fc=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.0.0-rc.10/go.mod h1:4CWWn4I5T3v4c1OsJ55HbHlUEKNWMITG5iIkdr4Px4w=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.0.0-rc.11/go.mod h1:JoieH/3h3U4UmatmV93QmqyPUdf4wVM9HELaHEu+3fk=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.0.0-rc.12/go.mod h1:FV1zZTsVFi1DSCboO36Xgs4pzCZBjB/tDV9Cz/lSaR8=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.0.0-rc.13/go.mod h1:2Mp7GhBFMdJlOK8vGfl7SYtfMP3+5roE39ejlfjw0rA=
|
|
||||||
github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
|
||||||
github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
|
||||||
github.com/gobuffalo/plush v3.7.21+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
|
||||||
github.com/gobuffalo/plush v3.7.22+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
|
||||||
github.com/gobuffalo/plush v3.7.23+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
|
||||||
github.com/gobuffalo/plush v3.7.30+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
|
||||||
github.com/gobuffalo/plush v3.7.31+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
|
||||||
github.com/gobuffalo/plush v3.7.32+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
|
||||||
github.com/gobuffalo/plushgen v0.0.0-20181128164830-d29dcb966cb2/go.mod h1:r9QwptTFnuvSaSRjpSp4S2/4e2D3tJhARYbvEBcKSb4=
|
|
||||||
github.com/gobuffalo/plushgen v0.0.0-20181203163832-9fc4964505c2/go.mod h1:opEdT33AA2HdrIwK1aibqnTJDVVKXC02Bar/GT1YRVs=
|
|
||||||
github.com/gobuffalo/plushgen v0.0.0-20181207152837-eedb135bd51b/go.mod h1:Lcw7HQbEVm09sAQrCLzIxuhFbB3nAgp4c55E+UlynR0=
|
|
||||||
github.com/gobuffalo/pop v4.8.2+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
|
|
||||||
github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
|
|
||||||
github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
|
|
||||||
github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4=
|
|
||||||
github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4=
|
|
||||||
github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug=
|
|
||||||
github.com/gobuffalo/release v1.0.52/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug=
|
|
||||||
github.com/gobuffalo/release v1.0.53/go.mod h1:FdF257nd8rqhNaqtDWFGhxdJ/Ig4J7VcS3KL7n/a+aA=
|
|
||||||
github.com/gobuffalo/release v1.0.54/go.mod h1:Pe5/RxRa/BE8whDpGfRqSI7D1a0evGK1T4JDm339tJc=
|
|
||||||
github.com/gobuffalo/release v1.0.61/go.mod h1:mfIO38ujUNVDlBziIYqXquYfBF+8FDHUjKZgYC1Hj24=
|
|
||||||
github.com/gobuffalo/release v1.0.72/go.mod h1:NP5NXgg/IX3M5XmHmWR99D687/3Dt9qZtTK/Lbwc1hU=
|
|
||||||
github.com/gobuffalo/release v1.1.1/go.mod h1:Sluak1Xd6kcp6snkluR1jeXAogdJZpFFRzTYRs/2uwg=
|
|
||||||
github.com/gobuffalo/release v1.1.3/go.mod h1:CuXc5/m+4zuq8idoDt1l4va0AXAn/OSs08uHOfMVr8E=
|
|
||||||
github.com/gobuffalo/shoulders v1.0.1/go.mod h1:V33CcVmaQ4gRUmHKwq1fiTXuf8Gp/qjQBUL5tHPmvbA=
|
|
||||||
github.com/gobuffalo/syncx v0.0.0-20181120191700-98333ab04150/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
|
||||||
github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f h1:S5EeH1reN93KR0L6TQvkRpu9YggCYXrUqFh1iEgvdC0=
|
|
||||||
github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
|
||||||
github.com/gobuffalo/tags v2.0.11+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY=
|
|
||||||
github.com/gobuffalo/tags v2.0.14+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY=
|
|
||||||
github.com/gobuffalo/uuid v2.0.3+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
|
|
||||||
github.com/gobuffalo/uuid v2.0.4+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
|
|
||||||
github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
|
|
||||||
github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM=
|
|
||||||
github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc=
|
|
||||||
github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY=
|
|
||||||
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
|
||||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
|
||||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
|
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
|
||||||
github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
|
||||||
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
|
||||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
|
||||||
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
|
||||||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
|
|
||||||
github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
|
||||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
|
||||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
|
||||||
github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
|
|
||||||
github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
|
|
||||||
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/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/leaanthony/mewn v0.9.1 h1:+qmAnR5nETU/00o5wvYJ7w9Y36R9uIBRB9I15E9Ru8A=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/leaanthony/mewn v0.9.1/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
||||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/leaanthony/slicer v1.0.0 h1:BV2CySexcZ20qyHp5qBTxQhsazR6e8MBTF1EHmGu1xw=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/leaanthony/slicer v1.0.0/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
||||||
github.com/leaanthony/spinner v0.4.0 h1:y/7FqQqqObRKYI+33bg9DGhHIY7cQHicm+Vz0Uda0Ik=
|
github.com/leaanthony/spinner v0.5.0 h1:HQykt/iTy7fmINEREtRbWrt+8j4MxC8dtvWBxEWM9oA=
|
||||||
github.com/leaanthony/spinner v0.4.0/go.mod h1:2Mmv+8Brcw3NwPT1DdOLmW6+zWpSamDDFFsUvVHo2cc=
|
github.com/leaanthony/spinner v0.5.0/go.mod h1:8TSFz9SL1AUC4XSbEFYE6SfN5Mlus51qYluVGrie9ww=
|
||||||
github.com/leaanthony/spinner v0.5.0 h1:OJKn+0KP6ilHxwCEOv5Lo0wPM4PgWZWLJTeUprGJK0g=
|
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
||||||
github.com/leaanthony/spinner v0.5.0/go.mod h1:2Mmv+8Brcw3NwPT1DdOLmW6+zWpSamDDFFsUvVHo2cc=
|
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
||||||
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 h1:1bGojw4YacLY5bqQalojiQ7mSfQbe4WIWCEgPZagowU=
|
github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
|
||||||
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
||||||
github.com/leaanthony/wincursor v0.0.0-20180705115120-056510f32d15 h1:166LIty6ldcyOc7tbgfu5smsGATvEo0JZV6bnbzyEc4=
|
|
||||||
github.com/leaanthony/wincursor v0.0.0-20180705115120-056510f32d15/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
|
||||||
github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
|
|
||||||
github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
|
|
||||||
github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c=
|
|
||||||
github.com/markbates/grift v1.0.4/go.mod h1:wbmtW74veyx+cgfwFhlnnMWqhoz55rnHR47oMXzsyVs=
|
|
||||||
github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c=
|
|
||||||
github.com/markbates/inflect v1.0.0/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88=
|
|
||||||
github.com/markbates/inflect v1.0.1/go.mod h1:uv3UVNBe5qBIfCm8O8Q+DW+S1EopeyINj+Ikhc7rnCk=
|
|
||||||
github.com/markbates/inflect v1.0.3/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
|
|
||||||
github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
|
|
||||||
github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
|
||||||
github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
|
||||||
github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
|
||||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2 h1:JgVTCPf0uBVcUSWpyXmGpgOc62nK5HWUBKAGc3Qqa5k=
|
|
||||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
|
||||||
github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc=
|
|
||||||
github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
|
||||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
|
||||||
github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc=
|
|
||||||
github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w=
|
|
||||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
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-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
||||||
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
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/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
|
||||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
|
||||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rogpeppe/go-internal v1.0.0 h1:o4VLZ5jqHE+HahLT6drNtSGTrrUA3wPBmtpgqtdbClo=
|
github.com/ribice/glice v0.0.0-20181011133736-685f13fa9b12/go.mod h1:A+ednilkKNW0CJGLsrLkq0D49M4EhlCi8gvnkwoZFn0=
|
||||||
github.com/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
|
||||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
|
||||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
|
||||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
|
||||||
github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
|
||||||
github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
|
||||||
github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
|
|
||||||
github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
|
||||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
|
||||||
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
|
||||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
|
|
||||||
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
github.com/wailsapp/webview v0.2.5 h1:/VacryPEUeMBb2VHHOjpoIze6ki8tW3qYX04MnI0b7o=
|
||||||
github.com/wailsapp/wails v0.0.0-20181215232634-5de8efff325d h1:lk91T4sKD98eGcaz/xC6ER+3o9Kaun7Mk8e/cNZOPMc=
|
github.com/wailsapp/webview v0.2.5/go.mod h1:XO9HJbKWokDxUYTWQEBCYg95n/To1v7PxvanDNVf8hY=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb/go.mod h1:a1CV8KR4Dd1eP2g+mEijGOp+HKczwdKHWyx0aPHKvo4=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f h1:qWFY9ZxP3tfI37wYIs/MnIAqK0vlXp1xnYEa5HxFSSY=
|
||||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
|
||||||
golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/crypto v0.0.0-20181024171144-74cb1d3d52f4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU=
|
||||||
golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180921163948-d47a0f339242/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||||
golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222171317-cd391775e71e h1:oF7qaQxUH6KzFdKN4ww7NpPdo53SZi4UlcksLrb2y/o=
|
||||||
golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222171317-cd391775e71e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181022134430-8a28ead16f52/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181024145615-5cd93ef61a7c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181026064943-731415f00dce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181008205924-a2b3f7f249e9/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181013182035-5e66757b835f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181024171208-a2dc47679d30/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181026183834-f60e5f99f081/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181107215632-34b416bd17b3/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181114190951-94339b83286c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181119130350-139d099f6620/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181127195227-b4e97c0ed882/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181127232545-e782529d0ddd/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181203210056-e5f3ab76ea4b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181205224935-3576414c54a4/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181206194817-bcd4e47d0288/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181207183836-8bc39b988060/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181212172921-837e80568c09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.7.1 h1:mzQIVyOPSXJaQWi1m6AFCjrCEPIwQBSOn48Ri8ZpzAg=
|
|
||||||
gopkg.in/AlecAivazis/survey.v1 v1.7.1/go.mod h1:2Ehl7OqkBl3Xb8VmC4oFW2bItAhnUfzIjrOzwRxCrOU=
|
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
|
||||||
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
|
|||||||
38
ipc_call.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type callData struct {
|
||||||
|
BindingName string `json:"bindingName"`
|
||||||
|
Data string `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
messageProcessors["call"] = processCallData
|
||||||
|
}
|
||||||
|
|
||||||
|
func processCallData(message *ipcMessage) (*ipcMessage, error) {
|
||||||
|
|
||||||
|
var payload callData
|
||||||
|
|
||||||
|
// Decode binding call data
|
||||||
|
payloadMap := message.Payload.(map[string]interface{})
|
||||||
|
|
||||||
|
// Check for binding name
|
||||||
|
if payloadMap["bindingName"] == nil {
|
||||||
|
return nil, fmt.Errorf("bindingName not given in call")
|
||||||
|
}
|
||||||
|
payload.BindingName = payloadMap["bindingName"].(string)
|
||||||
|
|
||||||
|
// Check for data
|
||||||
|
if payloadMap["data"] != nil {
|
||||||
|
payload.Data = payloadMap["data"].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reassign payload to decoded data
|
||||||
|
message.Payload = &payload
|
||||||
|
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
40
ipc_event.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventData struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the message handler
|
||||||
|
func init() {
|
||||||
|
messageProcessors["event"] = processEventData
|
||||||
|
}
|
||||||
|
|
||||||
|
// This processes the given event message
|
||||||
|
func processEventData(message *ipcMessage) (*ipcMessage, error) {
|
||||||
|
|
||||||
|
// TODO: Is it worth double checking this is actually an event message,
|
||||||
|
// even though that's done by the caller?
|
||||||
|
var payload eventData
|
||||||
|
|
||||||
|
// Decode event data
|
||||||
|
payloadMap := message.Payload.(map[string]interface{})
|
||||||
|
payload.Name = payloadMap["name"].(string)
|
||||||
|
|
||||||
|
// decode the payload data
|
||||||
|
var data []interface{}
|
||||||
|
err := json.Unmarshal([]byte(payloadMap["data"].(string)), &data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
payload.Data = data
|
||||||
|
|
||||||
|
// Reassign payload to decoded data
|
||||||
|
message.Payload = &payload
|
||||||
|
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
27
ipc_log.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
type logData struct {
|
||||||
|
Level string `json:"level"`
|
||||||
|
Message string `json:"string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the message handler
|
||||||
|
func init() {
|
||||||
|
messageProcessors["log"] = processLogData
|
||||||
|
}
|
||||||
|
|
||||||
|
// This processes the given log message
|
||||||
|
func processLogData(message *ipcMessage) (*ipcMessage, error) {
|
||||||
|
|
||||||
|
var payload logData
|
||||||
|
|
||||||
|
// Decode event data
|
||||||
|
payloadMap := message.Payload.(map[string]interface{})
|
||||||
|
payload.Level = payloadMap["level"].(string)
|
||||||
|
payload.Message = payloadMap["message"].(string)
|
||||||
|
|
||||||
|
// Reassign payload to decoded data
|
||||||
|
message.Payload = &payload
|
||||||
|
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
162
ipc_manager.go
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ipcManager struct {
|
||||||
|
renderer Renderer // The renderer
|
||||||
|
messageQueue chan *ipcMessage
|
||||||
|
// quitChannel chan struct{}
|
||||||
|
// signals chan os.Signal
|
||||||
|
log *CustomLogger
|
||||||
|
eventManager *eventManager
|
||||||
|
bindingManager *bindingManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func newIPCManager() *ipcManager {
|
||||||
|
result := &ipcManager{
|
||||||
|
messageQueue: make(chan *ipcMessage, 100),
|
||||||
|
// quitChannel: make(chan struct{}),
|
||||||
|
// signals: make(chan os.Signal, 1),
|
||||||
|
log: newCustomLogger("IPC"),
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the renderer, returns the dispatch function
|
||||||
|
func (i *ipcManager) bindRenderer(renderer Renderer) {
|
||||||
|
i.renderer = renderer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingManager) {
|
||||||
|
|
||||||
|
// Store manager references
|
||||||
|
i.eventManager = eventManager
|
||||||
|
i.bindingManager = bindingManager
|
||||||
|
|
||||||
|
i.log.Info("Starting")
|
||||||
|
// signal.Notify(manager.signals, os.Interrupt)
|
||||||
|
go func() {
|
||||||
|
running := true
|
||||||
|
for running {
|
||||||
|
select {
|
||||||
|
case incomingMessage := <-i.messageQueue:
|
||||||
|
i.log.DebugFields("Processing message", Fields{
|
||||||
|
"1D": &incomingMessage,
|
||||||
|
})
|
||||||
|
switch incomingMessage.Type {
|
||||||
|
case "call":
|
||||||
|
callData := incomingMessage.Payload.(*callData)
|
||||||
|
i.log.DebugFields("Processing call", Fields{
|
||||||
|
"1D": &incomingMessage,
|
||||||
|
"bindingName": callData.BindingName,
|
||||||
|
"data": callData.Data,
|
||||||
|
})
|
||||||
|
go func() {
|
||||||
|
result, err := bindingManager.processCall(callData)
|
||||||
|
i.log.DebugFields("processed call", Fields{"result": result, "err": err})
|
||||||
|
if err != nil {
|
||||||
|
incomingMessage.ReturnError(err.Error())
|
||||||
|
} else {
|
||||||
|
incomingMessage.ReturnSuccess(result)
|
||||||
|
}
|
||||||
|
i.log.DebugFields("Finished processing call", Fields{
|
||||||
|
"1D": &incomingMessage,
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
case "event":
|
||||||
|
|
||||||
|
// Extract event data
|
||||||
|
eventData := incomingMessage.Payload.(*eventData)
|
||||||
|
|
||||||
|
// Log
|
||||||
|
i.log.DebugFields("Processing event", Fields{
|
||||||
|
"name": eventData.Name,
|
||||||
|
"data": eventData.Data,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Push the event to the event manager
|
||||||
|
i.eventManager.PushEvent(eventData)
|
||||||
|
|
||||||
|
// Log
|
||||||
|
i.log.DebugFields("Finished processing event", Fields{
|
||||||
|
"name": eventData.Name,
|
||||||
|
})
|
||||||
|
case "log":
|
||||||
|
logdata := incomingMessage.Payload.(*logData)
|
||||||
|
switch logdata.Level {
|
||||||
|
case "info":
|
||||||
|
logger.Info(logdata.Message)
|
||||||
|
case "debug":
|
||||||
|
logger.Debug(logdata.Message)
|
||||||
|
case "warning":
|
||||||
|
logger.Warning(logdata.Message)
|
||||||
|
case "error":
|
||||||
|
logger.Error(logdata.Message)
|
||||||
|
case "fatal":
|
||||||
|
logger.Fatal(logdata.Message)
|
||||||
|
default:
|
||||||
|
i.log.ErrorFields("Invalid log level sent", Fields{
|
||||||
|
"level": logdata.Level,
|
||||||
|
"message": logdata.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
i.log.Debugf("bad message sent to MessageQueue! Unknown type: %s", incomingMessage.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log
|
||||||
|
i.log.DebugFields("Finished processing message", Fields{
|
||||||
|
"1D": &incomingMessage,
|
||||||
|
})
|
||||||
|
// case <-manager.quitChannel:
|
||||||
|
// Debug("[MessageQueue] Quit caught")
|
||||||
|
// running = false
|
||||||
|
// case <-manager.signals:
|
||||||
|
// Debug("[MessageQueue] Signal caught")
|
||||||
|
// running = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i.log.Debug("Stopping")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatch receives JSON encoded messages from the renderer.
|
||||||
|
// It processes the message to ensure that it is valid and places
|
||||||
|
// the processed message on the message queue
|
||||||
|
func (i *ipcManager) Dispatch(message string) {
|
||||||
|
|
||||||
|
// Create a new IPC Message
|
||||||
|
incomingMessage, err := newIPCMessage(message, i.SendResponse)
|
||||||
|
if err != nil {
|
||||||
|
i.log.ErrorFields("Could not understand incoming message! ", map[string]interface{}{
|
||||||
|
"message": message,
|
||||||
|
"error": err,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put message on queue
|
||||||
|
i.log.DebugFields("Message received", map[string]interface{}{
|
||||||
|
"type": incomingMessage.Type,
|
||||||
|
"payload": incomingMessage.Payload,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Put incoming message on the message queue
|
||||||
|
i.messageQueue <- incomingMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendResponse sends the given response back to the frontend
|
||||||
|
func (i *ipcManager) SendResponse(response *ipcResponse) error {
|
||||||
|
|
||||||
|
// Serialise the Message
|
||||||
|
data, err := response.Serialise()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call back to the front end
|
||||||
|
return i.renderer.Callback(data)
|
||||||
|
}
|
||||||
93
ipc_message.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Message handler
|
||||||
|
type messageProcessorFunc func(*ipcMessage) (*ipcMessage, error)
|
||||||
|
|
||||||
|
var messageProcessors = make(map[string]messageProcessorFunc)
|
||||||
|
|
||||||
|
// ipcMessage is the struct version of the Message sent from the frontend.
|
||||||
|
// The payload has the specialised message data
|
||||||
|
type ipcMessage struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Payload interface{} `json:"payload"`
|
||||||
|
CallbackID string `json:"callbackid,omitempty"`
|
||||||
|
sendResponse func(*ipcResponse) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMessage(incomingMessage string) (*ipcMessage, error) {
|
||||||
|
// Parse message
|
||||||
|
var message ipcMessage
|
||||||
|
err := json.Unmarshal([]byte(incomingMessage), &message)
|
||||||
|
return &message, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func newIPCMessage(incomingMessage string, responseFunction func(*ipcResponse) error) (*ipcMessage, error) {
|
||||||
|
|
||||||
|
// Parse the Message
|
||||||
|
message, err := parseMessage(incomingMessage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check message type is valid
|
||||||
|
messageProcessor := messageProcessors[message.Type]
|
||||||
|
if messageProcessor == nil {
|
||||||
|
return nil, fmt.Errorf("unknown message type: %s", message.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process message payload
|
||||||
|
message, err = messageProcessor(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the response function
|
||||||
|
message.sendResponse = responseFunction
|
||||||
|
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasCallbackID checks if the message can send an error back to the frontend
|
||||||
|
func (m *ipcMessage) hasCallbackID() error {
|
||||||
|
if m.CallbackID == "" {
|
||||||
|
return fmt.Errorf("attempted to return error to message with no Callback ID")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReturnError returns an error back to the frontend
|
||||||
|
func (m *ipcMessage) ReturnError(format string, args ...interface{}) error {
|
||||||
|
|
||||||
|
// Ignore ReturnError if no callback ID given
|
||||||
|
err := m.hasCallbackID()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create response
|
||||||
|
response := newErrorResponse(m.CallbackID, fmt.Sprintf(format, args...))
|
||||||
|
|
||||||
|
// Send response
|
||||||
|
return m.sendResponse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReturnSuccess returns a success message back with the given data
|
||||||
|
func (m *ipcMessage) ReturnSuccess(data interface{}) error {
|
||||||
|
|
||||||
|
// Ignore ReturnSuccess if no callback ID given
|
||||||
|
err := m.hasCallbackID()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the response
|
||||||
|
response := newSuccessResponse(m.CallbackID, data)
|
||||||
|
|
||||||
|
// Send response
|
||||||
|
return m.sendResponse(response)
|
||||||
|
}
|
||||||
43
ipc_response.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ipcResponse contains the response data from an RPC call
|
||||||
|
type ipcResponse struct {
|
||||||
|
CallbackID string `json:"callbackid"`
|
||||||
|
ErrorMessage string `json:"error,omitempty"`
|
||||||
|
Data interface{} `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// newErrorResponse returns the given error message to the frontend with the callbackid
|
||||||
|
func newErrorResponse(callbackID string, errorMessage string) *ipcResponse {
|
||||||
|
// Create response object
|
||||||
|
result := &ipcResponse{
|
||||||
|
CallbackID: callbackID,
|
||||||
|
ErrorMessage: errorMessage,
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// newSuccessResponse returns the given data to the frontend with the callbackid
|
||||||
|
func newSuccessResponse(callbackID string, data interface{}) *ipcResponse {
|
||||||
|
|
||||||
|
// Create response object
|
||||||
|
result := &ipcResponse{
|
||||||
|
CallbackID: callbackID,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialise formats the response to a string
|
||||||
|
func (i *ipcResponse) Serialise() (string, error) {
|
||||||
|
b, err := json.Marshal(i)
|
||||||
|
result := strings.Replace(string(b), "\\", "\\\\", -1)
|
||||||
|
result = strings.Replace(result, "'", "\\'", -1)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
29
licenses/github.com/dchest/cssmin/LICENSE
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
Go Port:
|
||||||
|
Copyright (c) 2013 Dmitry Chestnykh <dmitry@codingrobots.com>
|
||||||
|
|
||||||
|
Original:
|
||||||
|
Copyright (c) 2008 Ryan Grove <ryan@wonko.com>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of this project nor the names of its contributors may be
|
||||||
|
used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
24
licenses/github.com/dchest/htmlmin/LICENSE
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Copyright (c) 2013 Dmitry Chestnykh. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
20
licenses/github.com/fatih/color/LICENSE.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 Fatih Arslan
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||