Compare commits

...

142 Commits

Author SHA1 Message Date
Lea Anthony
69067e85f5 Merge pull request #62 from wailsapp/Default-Prompts-not-populating
Default prompts not populating
2019-03-07 05:48:15 +11:00
Lea Anthony
c8db58e00e Version bump 2019-03-07 05:47:13 +11:00
Lea Anthony
e96e0e0999 fix default prompts 2019-03-07 05:46:20 +11:00
Lea Anthony
2da21ec528 Merge pull request #60 from wailsapp/0.9.97
0.9.7
2019-03-06 19:14:46 +11:00
Lea Anthony
cda0b40414 Version bump 2019-03-06 19:12:38 +11:00
Lea Anthony
7f4229dd6b Add issue command 2019-03-06 19:12:12 +11:00
Lea Anthony
68651b77f4 use os specific path seperator 2019-03-06 19:11:46 +11:00
Lea Anthony
bf001f5ad2 Improve prompt handling 2019-03-06 19:11:03 +11:00
Lea Anthony
d1907b4ce5 Update issue templates 2019-03-06 07:59:24 +11:00
Lea Anthony
56363d193d Update issue templates 2019-03-04 22:36:00 +11:00
Lea Anthony
8553f43080 Misc linting fixes and version bump 2019-03-03 11:34:00 +11:00
Lea Anthony
587681bb8d Bump version 2019-03-02 12:56:56 +11:00
Lea Anthony
afbf80ea4a Merge pull request #59 from wailsapp/0.9.5
use mewn for templates
2019-03-02 12:55:36 +11:00
Lea Anthony
c180d7dccb use mewn for templates
massively improve template handling
2019-03-02 12:54:10 +11:00
Lea Anthony
c20aabc8f8 Merge pull request #58 from wailsapp/update-command
initial update command
2019-02-23 10:23:32 +11:00
Lea Anthony
4cccb628c9 initial update command 2019-02-23 10:20:37 +11:00
Lea Anthony
5d487347d4 Merge pull request #57 from wailsapp/#55-default-directory
default directory option
2019-02-22 09:04:12 +11:00
Lea Anthony
fe8b7ac5c9 default directory option 2019-02-22 09:03:41 +11:00
Lea Anthony
732c70777b Merge pull request #56 from wailsapp/minimise-console-spam
Big banner for Setup/Help. Small banner for commands.
2019-02-22 08:45:13 +11:00
Lea Anthony
753c5fd337 Big banner for Setup/Help. Small banner for commands. 2019-02-22 08:44:30 +11:00
Lea Anthony
2dad29673d Merge pull request #53 from wailsapp/adjust-windows-build-behaviour
package by default. -p  leaves resource artefacts
2019-02-22 05:17:54 +11:00
Lea Anthony
5e466893cf package by default. -p leaves resource artifacts 2019-02-22 05:17:23 +11:00
Lea Anthony
c15fd822c1 Merge pull request #52 from wailsapp/minor-fixes
remove frontend build from serve
2019-02-21 21:22:54 +11:00
Lea Anthony
42b1c0befa remove frontend build from serve 2019-02-21 21:21:05 +11:00
Lea Anthony
6ef8744e02 Merge pull request #51 from wailsapp/minor-fixes
Minor fixes
2019-02-21 08:25:10 +11:00
Lea Anthony
cf916c8e8b Updated sums 2019-02-21 08:24:30 +11:00
Lea Anthony
cdc1d4be3e Remove debug line 2019-02-21 08:23:44 +11:00
Lea Anthony
1c5284db3e Set window colour 2019-02-21 08:23:35 +11:00
Lea Anthony
073cdc3a55 Merge pull request #50 from wailsapp/window-debugging
minor bugfix
2019-02-20 23:04:35 +11:00
Lea Anthony
fd9363e842 minor bugfix 2019-02-20 23:04:11 +11:00
Lea Anthony
3051628fa2 Merge pull request #49 from wailsapp/window-debugging
Window debugging
2019-02-20 23:01:56 +11:00
Lea Anthony
cac97e8652 small refactor 2019-02-20 23:01:33 +11:00
Lea Anthony
2ccabc772b try and simplify 2019-02-20 22:54:06 +11:00
Lea Anthony
ff91241592 updated licenses + gomod 2019-02-20 22:48:59 +11:00
Lea Anthony
2257b1cab1 remove bad xml error 2019-02-20 22:41:33 +11:00
Lea Anthony
bdcf98fc15 Significant support for Windows builds 2019-02-20 22:24:47 +11:00
Lea Anthony
3025a94a77 use wails.min.js 2019-02-19 23:37:02 +11:00
Lea Anthony
d971495ad3 basics working 2019-02-19 21:06:24 +11:00
Lea Anthony
a4b1f469e9 Merge pull request #48 from wailsapp/move-to-new-prompt-library
Move to new prompt library
2019-02-19 19:38:29 +11:00
Lea Anthony
b18f04b30d removed survey 2019-02-19 19:37:45 +11:00
Lea Anthony
94e9447e1c Removed prompt library requirements 2019-02-19 19:25:33 +11:00
Lea Anthony
03c479c890 Fix vue template 2019-02-19 00:18:08 +11:00
Lea Anthony
c95a3a795e Merge pull request #47 from wailsapp/move-to-mewn
Move to mewn
2019-02-18 21:07:47 +11:00
Lea Anthony
1d8e99d846 Move to mewn 2019-02-18 21:06:53 +11:00
Lea Anthony
8e909fc9f4 Move to mewn 2019-02-18 08:31:22 +11:00
Lea Anthony
3bc86a4f50 Move bridge runtimes out of bundled assets 2019-02-17 06:12:05 +11:00
Lea Anthony
2c7913c202 use latest webview 2019-02-16 15:15:27 +11:00
Lea Anthony
d1c57ddb5f Merge pull request #46 from wailsapp/ignore-packr-findstring-errors-in-bridge-mode
Ignore packr findstring errors in bridge mode
2019-02-16 07:03:16 +11:00
Lea Anthony
9ffb517183 minor fixes 2019-02-16 07:02:16 +11:00
Lea Anthony
27f852ac6a ignoring findstring errors for bridge mode
refactored build mode strings
2019-02-16 06:58:30 +11:00
Lea Anthony
20c0b48634 version bump 2019-02-15 21:15:16 +11:00
Lea Anthony
6cf01b4239 Merge pull request #44 from wailsapp/get-vue-HMR-working
removed quote db for now. added vue basic
2019-02-15 21:12:24 +11:00
Lea Anthony
3ae88f8822 removed quote db for now. added vue basic 2019-02-15 21:11:42 +11:00
Lea Anthony
5994eb605f minor fixes to serve/build 2019-02-13 08:44:53 +11:00
Lea Anthony
9694dc57aa Merge pull request #43 from wailsapp/port-to-custom-webview
move webview out to seperate project
2019-02-11 08:30:33 +11:00
Lea Anthony
b5b78fddee move webview out to seperate project 2019-02-11 08:28:07 +11:00
Lea Anthony
c905185467 Merge pull request #42 from wailsapp/improve-build-output
Reduce output of prod build by ~30%
2019-02-06 06:27:38 +11:00
Lea Anthony
47ca7879cd Reduce output of prod build by ~30% 2019-02-06 06:26:54 +11:00
Lea Anthony
6202b3bf3e Merge pull request #41 from wailsapp/fix-linting-issues
simplified PromptForInputs
2019-02-05 18:53:32 +11:00
Lea Anthony
ea94c2de1f simplified PromptForInputs 2019-02-05 18:51:08 +11:00
Lea Anthony
eb0d4bc42f Merge pull request #40 from wailsapp/fix-linting-issues
Fix linting issues
2019-02-05 08:45:08 +11:00
Lea Anthony
b323c3db20 refactor promptforinputs 2019-02-05 08:43:50 +11:00
Lea Anthony
1670ac6567 add comments 2019-02-05 08:11:02 +11:00
Lea Anthony
c941176018 simplify Serve 2019-02-05 08:06:18 +11:00
Lea Anthony
a060d9dcc0 fix bridge installation path 2019-02-05 08:03:07 +11:00
Lea Anthony
ba208dce44 Merge pull request #39 from wailsapp/fix-linting-issues
Fix linting issues
2019-02-04 21:10:46 +11:00
Lea Anthony
9bbac46b3f Misc refactors 2019-02-04 21:09:56 +11:00
Lea Anthony
d8c591e64c refactored processCall 2019-02-04 19:50:26 +11:00
Lea Anthony
2c28a8f550 Fix css 2019-02-04 19:31:37 +11:00
Lea Anthony
d6c5586159 Merge pull request #38 from wailsapp/Improve-build/serve
Improve build/serve
2019-02-04 19:27:12 +11:00
Lea Anthony
08a7893b1d refactored build/serve 2019-02-04 18:49:56 +11:00
Lea Anthony
fa6cf17079 Fixed wails serve. Improved code structure. 2019-02-04 08:45:12 +11:00
Lea Anthony
fe2a20f92a Merge pull request #36 from wailsapp/Improve-build/serve
Improve build/serve
2019-02-02 14:07:14 +11:00
Lea Anthony
b713d57168 Tidy up serve. 2019-02-02 13:58:55 +11:00
Lea Anthony
17ca06693e add debug mode to build 2019-02-02 09:29:14 +11:00
Lea Anthony
243d738d64 Merge pull request #35 from wailsapp/Make-Serve-command
Add helpful message after serving
2019-01-31 18:59:37 +11:00
Lea Anthony
3f50b95f26 Add helpful message after serving 2019-01-31 18:59:07 +11:00
Lea Anthony
f0d8ce99a1 Merge pull request #34 from wailsapp/Make-Serve-command
Make serve command
2019-01-31 18:49:18 +11:00
Lea Anthony
259eec97d6 Added serve.
Serve only builds backend.
Build is always release build.
2019-01-31 18:48:12 +11:00
Lea Anthony
8b2168abe7 upgraded spinner to 0.5.0 2019-01-31 18:47:27 +11:00
Lea Anthony
a51e127309 Merge pull request #32 from wailsapp/Massively-Simplify
add webview license
2019-01-30 20:28:49 +11:00
Lea Anthony
c5cee79ff7 add webview license 2019-01-30 20:28:21 +11:00
Lea Anthony
9393b08c3f Merge pull request #31 from wailsapp/Massively-Simplify
Initial commit of simplification
2019-01-30 19:05:52 +11:00
Lea Anthony
0ca039e914 Initial commit of simplification 2019-01-30 09:00:46 +11:00
Lea Anthony
cd8b4f088f Merge pull request #29 from wailsapp/Move-headless-capability-into-own-library
Move headless capability into own library
2019-01-29 08:37:33 +11:00
Lea Anthony
847842504b Merge branch 'master' into Move-headless-capability-into-own-library 2019-01-29 08:36:27 +11:00
Lea Anthony
8ab91d31fe reduce function complexity 2019-01-29 08:36:21 +11:00
Lea Anthony
bb4d891549 Merge pull request #28 from wailsapp/Create-consistent-templates
Updated custom html
2019-01-29 08:31:21 +11:00
Lea Anthony
4a316a76fa Updated custom html 2019-01-29 08:30:38 +11:00
Lea Anthony
529e4cc07e Merge pull request #27 from wailsapp/Create-consistent-templates
update basic templates to use a frontend dir
2019-01-29 08:29:40 +11:00
Lea Anthony
579747d0f7 update basic templates to use a frontend dir 2019-01-29 08:28:59 +11:00
Lea Anthony
6880c53082 Merge pull request #26 from wailsapp/Move-headless-capability-into-own-library
Move headless capability into own library
2019-01-23 08:36:02 +11:00
Lea Anthony
6e011e75c3 updated vue template 2019-01-23 08:35:12 +11:00
Lea Anthony
683ba7dc59 support bridge mode
streamline some messaging
2019-01-23 06:01:45 +11:00
Lea Anthony
717e598330 Linter fix 2019-01-16 08:19:30 +11:00
Lea Anthony
a6489a1044 Merge pull request #25 from wailsapp/create-wails-css
Update basic template to use default CSS
2019-01-15 18:53:12 +11:00
Lea Anthony
df911adcae Update basic template to use default CSS 2019-01-15 18:52:18 +11:00
Lea Anthony
d7c0b1ec58 Merge pull request #24 from wailsapp/create-wails-css
inject default css if none given
2019-01-15 18:51:08 +11:00
Lea Anthony
7135d4fa27 inject default css if none given 2019-01-15 18:50:26 +11:00
Lea Anthony
83e063bf2b Merge pull request #23 from wailsapp/Update-execution-order-in-Headless-mode
Update execution order in headless mode
2019-01-15 08:36:10 +11:00
Lea Anthony
6e0773b355 fix for rendering fragments via headless 2019-01-15 08:34:32 +11:00
Lea Anthony
60f34223b0 bugfix for force rebuild 2019-01-15 08:33:48 +11:00
Lea Anthony
539be2ce84 Updated comments 2019-01-14 22:46:45 +11:00
Lea Anthony
561198b81b Fix unicode escaping 2019-01-14 19:18:03 +11:00
Lea Anthony
c823215eb6 Merge pull request #21 from wailsapp/Fix-npm-project-name
Fix npm package name
2019-01-13 18:04:39 +11:00
Lea Anthony
93f890f6d9 Fix npm package name 2019-01-13 18:02:51 +11:00
Lea Anthony
8a3aec6866 Merge pull request #20 from wailsapp/Update-execution-order-in-Headless-mode
Numerous fixes for headless mode.
2019-01-13 17:58:34 +11:00
Lea Anthony
1ef8ed73ab Remove debug statements 2019-01-13 17:57:21 +11:00
Lea Anthony
9004c3955e Numerous fixes for headless mode.
Remove script dom elements for internal calls.
2019-01-13 17:54:38 +11:00
Lea Anthony
4c98ce7da1 Merge pull request #19 from wailsapp/Update-execution-order-in-Headless-mode
fix for ipc binding
2019-01-12 16:00:44 +11:00
Lea Anthony
0ae5381203 fix for ipc binding
made reconnect modal a bit better
2019-01-12 15:56:49 +11:00
Lea Anthony
3f2f1b45f6 Merge pull request #18 from wailsapp/Support-Packaging
Add Licenses
2019-01-12 09:37:27 +11:00
Lea Anthony
e6bec8f7cc Add Licenses 2019-01-12 09:26:51 +11:00
Lea Anthony
f1f15fc1c5 Merge pull request #17 from wailsapp/Support-Packaging
Initial port of packager
2019-01-11 21:17:53 +11:00
Lea Anthony
bcca09563c Initial port of packager 2019-01-11 21:16:52 +11:00
Lea Anthony
ee355659ce Merge pull request #16 from wailsapp/change-code-mount-point
now binds go code to window.backend
2019-01-11 20:03:20 +11:00
Lea Anthony
a660e4a9da now binds go code to window.backend 2019-01-11 20:02:43 +11:00
Lea Anthony
a44fd57e98 Merge pull request #15 from wailsapp/Port-Build
Port build
2019-01-11 07:01:18 +11:00
Lea Anthony
85de0bbf8a remove console.log 2019-01-11 07:00:40 +11:00
Lea Anthony
7274b6d19c Args messages to debug 2019-01-11 06:53:34 +11:00
Lea Anthony
c0371f141a Merge pull request #14 from wailsapp/Port-Build
Update vue template to use BoxString
2019-01-11 06:49:31 +11:00
Lea Anthony
5c96264234 Update vue template to use BoxString
Made arg marshalling messages Debug rather than Info
2019-01-11 06:39:42 +11:00
Lea Anthony
a3c41d1740 Merge pull request #13 from wailsapp/Port-Build
Fix frameworkspinner
2019-01-11 06:32:41 +11:00
Lea Anthony
7c15b780e2 Fix frameworkspinner
Fix BoxString for frameworks
2019-01-11 06:32:13 +11:00
Lea Anthony
fb081b4876 Merge pull request #12 from wailsapp/Port-Build
Port build
2019-01-11 06:16:30 +11:00
Lea Anthony
a28315f38b Fix Packr deprecation errors
Improved comments
2019-01-11 06:15:49 +11:00
Lea Anthony
49e4f00b62 Added release mode flag
fixed logging
logging info level by default
2019-01-10 22:48:54 +11:00
Lea Anthony
9167063976 Merge pull request #11 from wailsapp/Port-Build
Made init less verbose
2019-01-09 08:26:56 +11:00
Lea Anthony
aaa425724c Made init less verbose 2019-01-09 08:26:19 +11:00
Lea Anthony
ffdbb0af64 Merge pull request #10 from wailsapp/Port-Build
updated runtime assets
2019-01-09 08:10:14 +11:00
Lea Anthony
12dec650de updated runtime assets 2019-01-09 06:36:34 +11:00
Lea Anthony
d4b2563e9b Merge pull request #9 from wailsapp/Port-Build
mute logging of injected scripts
2019-01-09 06:35:52 +11:00
Lea Anthony
55817b65b5 mute logging of injected scripts 2019-01-09 06:35:22 +11:00
Lea Anthony
ab6e7531b4 Merge pull request #8 from wailsapp/Port-Build
Add assets
2019-01-08 21:33:04 +11:00
Lea Anthony
1e4cf9b0ad Add assets 2019-01-08 21:31:50 +11:00
Lea Anthony
13efa58c9a Merge pull request #7 from wailsapp/Port-Build
fixes building on linux
2019-01-08 21:04:35 +11:00
Lea Anthony
88b9b40bfe fixes building on linux
install packr on setup
2019-01-08 21:03:40 +11:00
Lea Anthony
0011e39c55 Merge pull request #6 from wailsapp/Port-Build
Initial Port
2019-01-08 20:15:49 +11:00
Lea Anthony
aa6b67734b Initial Port
Updated templates
2019-01-08 17:48:37 +11:00
Lea Anthony
733258cc83 Merge pull request #5 from wailsapp/Port-Build
Initial commit of wails build
2019-01-08 07:59:22 +11:00
Lea Anthony
4742fd7ed2 Initial commit of wails build 2019-01-08 07:58:46 +11:00
Lea Anthony
96996431b4 Merge pull request #4 from wailsapp/Port-Init
Port init
2019-01-07 22:59:27 +11:00
136 changed files with 16394 additions and 1505 deletions

30
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Description**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behaviour:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behaviour**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**System Details**
Please paste the output of `wails report` here.
**Additional context**
Add any other context about the problem here.

6
.gitignore vendored
View File

@@ -10,3 +10,9 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
examples/**/example*
!examples/**/*.*
cmd/wails/wails
.DS_Store
tmp

138
app.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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"
)

View File

@@ -105,6 +105,7 @@ func NewCommand(name string, description string, app *Cli, parentCommandPath str
Shortdescription: description,
SubCommandsMap: make(map[string]*Command),
App: app,
log: NewLogger(),
}
// Set up command path
@@ -181,6 +182,7 @@ func (c *Command) Run(args []string) error {
// Nothing left we can do
c.PrintHelp()
return nil
}
@@ -192,6 +194,7 @@ func (c *Command) Action(callback Action) *Command {
// PrintHelp - Output the help text for this command
func (c *Command) PrintHelp() {
c.log.PrintBanner()
versionString := c.AppVersion
if versionString != "" {
versionString = " " + versionString
@@ -209,7 +212,6 @@ func (c *Command) PrintHelp() {
fmt.Println(c.Longdescription + "\n")
}
if len(c.SubCommands) > 0 {
fmt.Println("")
c.log.White("Available commands:")
fmt.Println("")
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.Println("")
}
if c.flagCount > 0 {
fmt.Println("")
c.log.White("Flags:")
fmt.Println()
c.Flags.SetOutput(os.Stdout)

30
cmd/cmd-mewn.go Normal file

File diff suppressed because one or more lines are too long

View File

@@ -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
}

File diff suppressed because one or more lines are too long

View File

@@ -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"),
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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"),
}
}

View File

@@ -1,5 +0,0 @@
{
"Name": "Bootstrap 4",
"Description": "Standard Bootstrap 4 with default theme",
"BuildTag": "frameworkbootstrap4"
}

View File

@@ -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"),
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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"),
}
}

View File

@@ -1,5 +0,0 @@
{
"Name": "Bootstrap 4 (Lux)",
"Description": "Bootstrap with Lux theme",
"BuildTag": "frameworkbootstrap4lux"
}

View File

@@ -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

View File

@@ -41,6 +41,14 @@ func (fs *FSHelper) FileExists(path string) bool {
return fi.Mode().IsRegular()
}
// CreateFile creates a file at the given filename location with the contents
// set to the given data. It will create intermediary directories if needed.
func (fs *FSHelper) CreateFile(filename string, data []byte) error {
// Ensure directory exists
fs.MkDirs(filepath.Dir(filename))
return ioutil.WriteFile(filename, data, 0644)
}
// MkDirs creates the given nested directories.
// Returns error on failure
func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error {
@@ -80,6 +88,22 @@ func (fs *FSHelper) Cwd() string {
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
func (fs *FSHelper) GetSubdirs(dir string) (map[string]string, error) {

281
cmd/helpers.go Normal file
View File

@@ -0,0 +1,281 @@
package cmd
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"time"
"github.com/leaanthony/slicer"
"github.com/leaanthony/spinner"
)
var fs = NewFSHelper()
// 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
}

View File

@@ -9,52 +9,89 @@ import (
// Logger struct
type Logger struct {
errorOnly bool
}
// NewLogger creates a new logger!
func NewLogger() *Logger {
return &Logger{}
return &Logger{errorOnly: false}
}
// SetErrorOnly ensures that only errors are logged out
func (l *Logger) SetErrorOnly(errorOnly bool) {
l.errorOnly = errorOnly
}
// Yellow - Outputs yellow text
func (l *Logger) Yellow(format string, a ...interface{}) {
if l.errorOnly {
return
}
color.New(color.FgHiYellow).PrintfFunc()(format+"\n", a...)
}
// Yellowf - Outputs yellow text without the newline
func (l *Logger) Yellowf(format string, a ...interface{}) {
if l.errorOnly {
return
}
color.New(color.FgHiYellow).PrintfFunc()(format, a...)
}
// Green - Outputs Green text
func (l *Logger) Green(format string, a ...interface{}) {
if l.errorOnly {
return
}
color.New(color.FgHiGreen).PrintfFunc()(format+"\n", a...)
}
// White - Outputs White text
func (l *Logger) White(format string, a ...interface{}) {
if l.errorOnly {
return
}
color.New(color.FgHiWhite).PrintfFunc()(format+"\n", a...)
}
// WhiteUnderline - Outputs White text with underline
func (l *Logger) WhiteUnderline(format string, a ...interface{}) {
if l.errorOnly {
return
}
l.White(format, a...)
l.White(l.underline(format))
}
// YellowUnderline - Outputs Yellow text with underline
func (l *Logger) YellowUnderline(format string, a ...interface{}) {
if l.errorOnly {
return
}
l.Yellow(format, a...)
l.Yellow(l.underline(format))
}
// underline returns a string of a line, the length of the message given to it
func (l *Logger) underline(message string) string {
if l.errorOnly {
return ""
}
return strings.Repeat("-", len(message))
}
// Red - Outputs Red text
func (l *Logger) Red(format string, a ...interface{}) {
if l.errorOnly {
return
}
color.New(color.FgHiRed).PrintfFunc()(format+"\n", a...)
}
@@ -63,6 +100,17 @@ func (l *Logger) Error(format string, a ...interface{}) {
color.New(color.FgHiRed).PrintfFunc()("Error: "+format+"\n", a...)
}
// PrintSmallBanner prints a condensed banner
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
func (l *Logger) PrintBanner() error {
banner1 := ` _ __ _ __

263
cmd/package.go Normal file
View File

@@ -0,0 +1,263 @@
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
}
// PackageWindows packages the application for windows platforms
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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

View File

@@ -0,0 +1,2 @@
100 ICON "$NAME$.ico"
100 24 "$NAME$.exe.manifest"

View File

@@ -2,17 +2,23 @@ package cmd
import (
"bytes"
"fmt"
"os/exec"
"path/filepath"
"strings"
"syscall"
)
// ProgramHelper - Utility functions around installed applications
type ProgramHelper struct{}
type ProgramHelper struct {
shell *ShellHelper
}
// NewProgramHelper - Creates a new ProgramHelper
func NewProgramHelper() *ProgramHelper {
return &ProgramHelper{}
return &ProgramHelper{
shell: NewShellHelper(),
}
}
// IsInstalled tries to determine if the given binary name is installed
@@ -83,3 +89,37 @@ func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err
}
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)
}
// 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
}

View File

@@ -4,10 +4,12 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/AlecAivazis/survey"
"github.com/leaanthony/slicer"
)
type author struct {
@@ -19,6 +21,8 @@ type frontend struct {
Dir string `json:"dir"`
Install string `json:"install"`
Build string `json:"build"`
Bridge string `json:"bridge"`
Serve string `json:"serve"`
}
type framework struct {
@@ -46,15 +50,11 @@ func NewProjectHelper() *ProjectHelper {
// GenerateProject generates a new project using the options given
func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
fs := NewFSHelper()
exists, err := ph.templates.TemplateExists(projectOptions.Template)
if err != nil {
return err
}
// exists := ph.templates.TemplateExists(projectOptions.Template)
if !exists {
return fmt.Errorf("template '%s' is invalid", projectOptions.Template)
}
// if !exists {
// return fmt.Errorf("template '%s' is invalid", projectOptions.Template)
// }
// Calculate project path
projectPath, err := filepath.Abs(projectOptions.OutputDirectory)
@@ -62,6 +62,8 @@ func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
return err
}
_ = projectPath
if fs.DirExists(projectPath) {
return fmt.Errorf("directory '%s' already exists", projectPath)
}
@@ -82,11 +84,27 @@ func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
if err != nil {
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("To compile the project, run 'wails build' in the project directory.")
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
func (ph *ProjectHelper) LoadProjectConfig(dir string) (*ProjectOptions, error) {
po := ph.NewProjectOptions()
@@ -97,15 +115,14 @@ func (ph *ProjectHelper) LoadProjectConfig(dir string) (*ProjectOptions, error)
// NewProjectOptions creates a new default set of project options
func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
result := ProjectOptions{
Name: "",
Description: "Enter your project description",
Version: "0.1.0",
BinaryName: "",
system: NewSystemHelper(),
log: NewLogger(),
templates: NewTemplateHelper(),
templateNameMap: make(map[string]string),
Author: &author{},
Name: "",
Description: "Enter your project description",
Version: "0.1.0",
BinaryName: "",
system: NewSystemHelper(),
log: NewLogger(),
templates: NewTemplateHelper(),
Author: &author{},
}
// Populate system config
@@ -118,193 +135,70 @@ func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
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
type ProjectOptions struct {
Name string `json:"name"`
Description string `json:"description"`
Author *author `json:"author,omitempty"`
Version string `json:"version"`
OutputDirectory string `json:"-"`
UseDefaults bool `json:"-"`
Template string `json:"-"`
BinaryName string `json:"binaryname"`
FrontEnd *frontend `json:"frontend,omitempty"`
NPMProjectName string `json:"-"`
Framework *framework `json:"framework,omitempty"`
system *SystemHelper
log *Logger
templates *TemplateHelper
templateNameMap map[string]string // Converts template prompt text to template name
Name string `json:"name"`
Description string `json:"description"`
Author *author `json:"author,omitempty"`
Version string `json:"version"`
OutputDirectory string `json:"-"`
UseDefaults bool `json:"-"`
Template string `json:"-"`
BinaryName string `json:"binaryname"`
FrontEnd *frontend `json:"frontend,omitempty"`
NPMProjectName string `json:"-"`
system *SystemHelper
log *Logger
templates *TemplateHelper
selectedTemplate *TemplateDetails
}
// Defaults sets the default project template
func (po *ProjectOptions) Defaults() {
po.Template = "basic"
po.Template = "vuebasic"
}
// PromptForInputs asks the user to input project details
func (po *ProjectOptions) PromptForInputs() error {
var questions []*survey.Question
fs := NewFSHelper()
processProjectName(po)
if po.Name == "" {
questions = append(questions, InputQuestion("Name", "The name of the project", "My Project", true))
} else {
fmt.Println("Project Name: " + po.Name)
}
processBinaryName(po)
if po.BinaryName == "" {
var binaryNameComputed string
if po.Name != "" {
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()
err := processOutputDirectory(po)
if err != nil {
return err
}
templates := []string{}
// Add a Custom Template
// templates = append(templates, "Custom - Choose your own CSS framework")
for templateName, templateDetails := range templateDetails {
templateText := templateName
// Check if metadata json exists
if templateDetails.Metadata != nil {
shortdescription := templateDetails.Metadata["shortdescription"]
if shortdescription != "" {
templateText += " - " + shortdescription.(string)
}
}
templates = append(templates, templateText)
po.templateNameMap[templateText] = templateName
// Process Templates
templateList := slicer.Interface()
options := slicer.String()
for _, templateDetails := range po.templates.TemplateList.details {
templateList.Add(templateDetails)
options.Add(fmt.Sprintf("%s - %s", templateDetails.Metadata.Name, templateDetails.Metadata.ShortDescription))
}
if po.Template != "" {
if _, ok := templateDetails[po.Template]; !ok {
po.log.Error("Template '%s' invalid.", po.Template)
questions = append(questions, SelectQuestion("Template", "Select template", templates, templates[0], true))
}
} else {
questions = append(questions, SelectQuestion("Template", "Select template", templates, templates[0], true))
templateIndex := 0
if len(options.AsSlice()) > 1 {
templateIndex = PromptSelection("Please select a template", options.AsSlice(), 0)
}
err = survey.Ask(questions, po)
if err != nil {
return err
}
// After selection do this....
po.selectedTemplate = templateList.AsSlice()[templateIndex].(*TemplateDetails)
// Setup NPM Project name
po.NPMProjectName = 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,
}
}
po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1))
// Fix template name
if po.templateNameMap[po.Template] != "" {
po.Template = po.templateNameMap[po.Template]
}
po.Template = strings.Split(po.selectedTemplate.Path, string(os.PathSeparator))[0]
// Populate template details
templateMetadata := templateDetails[po.Template].Metadata
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)
// // Populate template details
templateMetadata := po.selectedTemplate.Metadata
err = processTemplateMetadata(templateMetadata, po)
if err != nil {
return err
}
return nil
@@ -337,3 +231,87 @@ func (po *ProjectOptions) LoadConfig(projectDir string) error {
}
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 *TemplateMetadata, po *ProjectOptions) error {
if templateMetadata.FrontendDir != "" {
po.FrontEnd = &frontend{}
po.FrontEnd.Dir = templateMetadata.FrontendDir
}
if templateMetadata.Install != "" {
if po.FrontEnd == nil {
return fmt.Errorf("install set in template metadata but not frontenddir")
}
po.FrontEnd.Install = templateMetadata.Install
}
if templateMetadata.Build != "" {
if po.FrontEnd == nil {
return fmt.Errorf("build set in template metadata but not frontenddir")
}
po.FrontEnd.Build = templateMetadata.Build
}
if templateMetadata.Bridge != "" {
if po.FrontEnd == nil {
return fmt.Errorf("bridge set in template metadata but not frontenddir")
}
po.FrontEnd.Bridge = templateMetadata.Bridge
}
if templateMetadata.Serve != "" {
if po.FrontEnd == nil {
return fmt.Errorf("serve set in template metadata but not frontenddir")
}
po.FrontEnd.Serve = templateMetadata.Serve
}
return nil
}

85
cmd/prompt.go Normal file
View File

@@ -0,0 +1,85 @@
package cmd
import (
"bufio"
"fmt"
"os"
"runtime"
"strconv"
"strings"
)
// Prompt asks the user for a value
func Prompt(question string, defaultValue ...string) string {
var answer string
if len(defaultValue) > 0 {
answer = defaultValue[0]
question = fmt.Sprintf("%s (%s)", question, answer)
}
fmt.Printf(question + ": ")
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
EOL := "\n"
if runtime.GOOS == "windows" {
EOL = "\r\n"
}
input = strings.Replace(input, EOL, "", -1)
if input != "" {
answer = input
}
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, optionalDefaultValue ...int) int {
defaultValue := -1
message := "Please choose an option"
fmt.Println(question + ":")
if len(optionalDefaultValue) > 0 {
defaultValue = optionalDefaultValue[0] + 1
message = fmt.Sprintf("%s [%d]", message, defaultValue)
}
for index, option := range options {
fmt.Printf(" %d: %s\n", index+1, option)
}
selectedValue := -1
for {
choice := Prompt(message)
if choice == "" && defaultValue > -1 {
selectedValue = defaultValue - 1
break
}
// 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
View 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
}

View File

@@ -10,7 +10,6 @@ import (
"strconv"
"time"
"github.com/AlecAivazis/survey"
homedir "github.com/mitchellh/go-homedir"
)
@@ -82,9 +81,6 @@ func (s *SystemHelper) BackupConfig() (string, error) {
func (s *SystemHelper) setup() error {
// Answers. We all need them.
answers := &SystemConfig{}
// Try to load current values - ignore errors
config, err := s.LoadConfig()
defaultName := ""
@@ -93,31 +89,10 @@ func (s *SystemHelper) setup() error {
defaultName = config.Name
defaultEmail = config.Email
}
// Questions
var simpleQs = []*survey.Question{
{
Name: "Name",
Prompt: &survey.Input{
Message: "What is your name:",
Default: defaultName,
},
Validate: survey.Required,
},
{
Name: "Email",
Prompt: &survey.Input{
Message: "What is your email address:",
Default: defaultEmail,
},
Validate: survey.Required,
},
}
// ask the questions
err = survey.Ask(simpleQs, answers)
if err != nil {
return err
}
systemConfig := make(map[string]string)
systemConfig["name"] = PromptRequired("What is your name", defaultName)
systemConfig["email"] = PromptRequired("What is your email address", defaultEmail)
// Create the directory
err = s.fs.MkDirs(s.wailsSystemDir)
@@ -125,12 +100,21 @@ func (s *SystemHelper) setup() error {
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()
s.log.White("Wails config saved to: " + s.wailsSystemConfig)
s.log.White("Feel free to customise these settings.")
fmt.Println()
return answers.Save(s.wailsSystemConfig)
return nil
}
const introText = `
@@ -220,6 +204,15 @@ func (sc *SystemConfig) load(filename string) error {
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
// Errors are reported in error and the bool return value is whether
// the dependencies are all installed.
@@ -281,6 +274,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
}
}
}
logger.White("")
return !errors, err
}

View File

@@ -3,265 +3,151 @@ package cmd
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"log"
"path/filepath"
"runtime"
"regexp"
"strings"
"text/template"
"github.com/alecthomas/template"
mewn "github.com/leaanthony/mewn"
mewnlib "github.com/leaanthony/mewn/lib"
"github.com/leaanthony/slicer"
)
const templateSuffix = ".template"
type TemplateHelper struct {
system *SystemHelper
fs *FSHelper
templateDir string
// templates map[string]string
templateSuffix string
metadataFilename string
// TemplateMetadata holds all the metadata for a Wails template
type TemplateMetadata struct {
Name string `json:"name"`
ShortDescription string `json:"shortdescription"`
Description string `json:"description"`
Install string `json:"install"`
Build string `json:"build"`
Author string `json:"author"`
Created string `json:"created"`
FrontendDir string `json:"frontenddir"`
Serve string `json:"serve"`
Bridge string `json:"bridge"`
}
type Template struct {
Name string
Dir string
Metadata map[string]interface{}
// TemplateDetails holds information about a specific template
type TemplateDetails struct {
BasePath string
Path string
Metadata *TemplateMetadata
}
func NewTemplateHelper() *TemplateHelper {
result := TemplateHelper{
system: NewSystemHelper(),
fs: NewFSHelper(),
templateSuffix: ".template",
metadataFilename: "template.json",
}
// Calculate template base dir
_, filename, _, _ := runtime.Caller(1)
result.templateDir = filepath.Join(path.Dir(filename), "templates")
// result.templateDir = filepath.Join(result.system.homeDir, "go", "src", "github.com", "wailsapp", "wails", "cmd", "templates")
return &result
// TemplateList is a list of available templates
type TemplateList struct {
details map[string]*TemplateDetails
}
func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) {
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
if err != nil {
return nil, err
}
return templateDirs, nil
}
// NewTemplateList creates a new TemplateList object
func NewTemplateList(filenames *mewnlib.FileGroup) *TemplateList {
// Iterate each template and store information
func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) {
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
if err != nil {
return nil, err
}
result := &TemplateList{details: make(map[string]*TemplateDetails)}
result := make(map[string]*Template)
entries := slicer.String()
entries.AddSlice(filenames.Entries())
for name, dir := range templateDirs {
result[name] = &Template{
Dir: dir,
}
metadata, err := t.LoadMetadata(dir)
// Find all template.json files
metadataFiles := entries.Filter(func(filename string) bool {
match, _ := regexp.MatchString("(.)+template.json$", filename)
return match
})
// Load each metadata file
metadataFiles.Each(func(filename string) {
fileData := filenames.Bytes(filename)
var metadata TemplateMetadata
err := json.Unmarshal(fileData, &metadata)
if err != nil {
return nil, err
log.Fatalf("corrupt metadata for template: %s", filename)
}
result[name].Metadata = metadata
if metadata["name"] != nil {
result[name].Name = metadata["name"].(string)
} else {
// Ignore bad templates?
result[name] = nil
}
}
path := strings.Split(filename, string(filepath.Separator))[0]
thisTemplate := &TemplateDetails{Path: path, Metadata: &metadata}
result.details[filename] = thisTemplate
})
return result, nil
return result
}
func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error) {
templateFile := filepath.Join(dir, t.metadataFilename)
result := make(map[string]interface{})
if !t.fs.FileExists(templateFile) {
return nil, nil
}
rawJSON, err := ioutil.ReadFile(templateFile)
if err != nil {
return nil, err
}
err = json.Unmarshal(rawJSON, &result)
return result, err
// Template holds details about a Wails template
type Template struct {
Name string
Path string
Description string
}
func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) {
templates, err := t.GetTemplateNames()
if err != nil {
return false, err
}
_, exists := templates[templateName]
return exists, nil
// TemplateHelper is a utility object to help with processing templates
type TemplateHelper struct {
TemplateList *TemplateList
Files *mewnlib.FileGroup
}
// NewTemplateHelper creates a new template helper
func NewTemplateHelper() *TemplateHelper {
files := mewn.Group("./templates")
return &TemplateHelper{
TemplateList: NewTemplateList(files),
Files: files,
}
}
// InstallTemplate installs the template given in the project options to the
// project path given
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
// Get template files
template, err := t.getTemplateFiles(projectOptions.Template)
if err != nil {
return err
}
templatePath := projectOptions.selectedTemplate.Path
// Copy files to target
err = template.Install(projectPath, projectOptions)
if err != nil {
return err
}
templateFilenames := slicer.String()
templateFilenames.AddSlice(projectOptions.templates.Files.Entries())
return nil
}
templateJSONFilename := filepath.Join(templatePath, "template.json")
// templateFiles categorises files found in a template
type templateFiles struct {
BaseDir string
StandardFiles []string
Templates []string
Dirs []string
}
// newTemplateFiles returns a new TemplateFiles struct
func (t *TemplateHelper) newTemplateFiles(dir string) *templateFiles {
pathsep := string(os.PathSeparator)
// Ensure base directory has trailing slash
if !strings.HasSuffix(dir, pathsep) {
dir = dir + pathsep
}
return &templateFiles{
BaseDir: dir,
}
}
// AddStandardFile adds the given file to the list of standard files
func (t *templateFiles) AddStandardFile(filename string) {
localPath := strings.TrimPrefix(filename, t.BaseDir)
t.StandardFiles = append(t.StandardFiles, localPath)
}
// AddTemplate adds the given file to the list of template files
func (t *templateFiles) AddTemplate(filename string) {
localPath := strings.TrimPrefix(filename, t.BaseDir)
t.Templates = append(t.Templates, localPath)
}
// AddDir adds the given directory to the list of template dirs
func (t *templateFiles) AddDir(dir string) {
localPath := strings.TrimPrefix(dir, t.BaseDir)
t.Dirs = append(t.Dirs, localPath)
}
// getTemplateFiles returns a struct categorising files in
// the template directory
func (t *TemplateHelper) getTemplateFiles(templateName string) (*templateFiles, error) {
templates, err := t.GetTemplateNames()
if err != nil {
return nil, err
}
templateDir := templates[templateName]
result := t.newTemplateFiles(templateDir)
var localPath string
err = filepath.Walk(templateDir, func(dir string, info os.FileInfo, err error) error {
if dir == templateDir {
return nil
}
if err != nil {
return err
}
// Don't copy template metadata
localPath = strings.TrimPrefix(dir, templateDir+string(filepath.Separator))
if localPath == t.metadataFilename {
return nil
}
// Categorise the file
switch {
case info.IsDir():
result.AddDir(dir)
case strings.HasSuffix(info.Name(), templateSuffix):
result.AddTemplate(dir)
default:
result.AddStandardFile(dir)
}
return nil
templateFiles := templateFilenames.Filter(func(filename string) bool {
return strings.HasPrefix(filename, templatePath) && filename != templateJSONFilename
})
if err != nil {
return nil, fmt.Errorf("error processing template '%s' in path '%q': %v", templateName, templateDir, err)
}
return result, err
}
// Install the template files into the given project path
func (t *templateFiles) Install(projectPath string, projectOptions *ProjectOptions) error {
fs := NewFSHelper()
// Create directories
var targetDir string
for _, dirname := range t.Dirs {
targetDir = filepath.Join(projectPath, dirname)
fs.MkDir(targetDir)
}
// Copy standard files
var targetFile, sourceFile string
var err error
for _, filename := range t.StandardFiles {
sourceFile = filepath.Join(t.BaseDir, filename)
targetFile = filepath.Join(projectPath, filename)
templateFiles.Each(func(templateFile string) {
err = fs.CopyFile(sourceFile, targetFile)
// Setup filenames
relativeFilename := strings.TrimPrefix(templateFile, templatePath)[1:]
targetFilename, err := filepath.Abs(filepath.Join(projectOptions.OutputDirectory, relativeFilename))
if err != nil {
return err
return
}
}
filedata := projectOptions.templates.Files.Bytes(templateFile)
// Do we have template files?
if len(t.Templates) > 0 {
// Iterate over the templates
var templateFile string
var tmpl *template.Template
for _, filename := range t.Templates {
// Load template text
templateFile = filepath.Join(t.BaseDir, filename)
templateText, err := fs.LoadAsString(templateFile)
if err != nil {
return err
}
// Apply template
tmpl = template.New(templateFile)
tmpl.Parse(templateText)
// Write the template to a buffer
// If file is a template, process it
if strings.HasSuffix(templateFile, ".template") {
templateData := projectOptions.templates.Files.String(templateFile)
tmpl := template.New(templateFile)
tmpl.Parse(templateData)
var tpl bytes.Buffer
err = tmpl.Execute(&tpl, projectOptions)
if err != nil {
fmt.Println("ERROR!!! " + err.Error())
return err
return
}
// Save buffer to disk
targetFilename := strings.TrimSuffix(filename, templateSuffix)
targetFile = filepath.Join(projectPath, targetFilename)
err = ioutil.WriteFile(targetFile, tpl.Bytes(), 0644)
if err != nil {
return err
}
// Remove template suffix
targetFilename = strings.TrimSuffix(targetFilename, ".template")
// Set the filedata to the template result
filedata = tpl.Bytes()
}
// Normal file, just copy it
err = fs.CreateFile(targetFilename, filedata)
if err != nil {
return
}
})
if err != nil {
return err
}
return nil

View File

@@ -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()
}

View File

@@ -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"
}

View File

@@ -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()
}

View File

@@ -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"
}

View File

@@ -1,29 +1,35 @@
# frontend
# vue basic
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your tests
```
npm run test
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

File diff suppressed because it is too large Load Diff

View 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"
]
}

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -5,11 +5,11 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>frontend</title>
<title>my-vue-app-01</title>
</head>
<body>
<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>
<div id="app"></div>
<!-- built files will be auto injected -->

View File

@@ -1,22 +1,18 @@
<template>
<div id="app">
<img alt="Wails logo" src="./assets/images/logo.png" class="logo zoomIn">
<HelloWorld msg="Welcome to Your Wails App!"/>
<Quote/>
<HelloWorld/>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
import Quote from "./components/Quote.vue";
import "./assets/css/main.css";
export default {
name: "app",
components: {
HelloWorld,
Quote
HelloWorld
}
};
</script>

View File

@@ -10,21 +10,6 @@
html {
height: 100%;
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-size: 20px 20px;
}
@@ -46,10 +31,8 @@ html {
format("woff2"),
/* Super Modern Browsers */
url("../fonts/roboto/roboto-v18-latin-regular.woff") format("woff"),
/* Modern Browsers */
url("../fonts/roboto/roboto-v18-latin-regular.ttf")
/* Modern Browsers */ url("../fonts/roboto/roboto-v18-latin-regular.ttf")
format("truetype"),
/* Safari, Android, iOS */
url("../fonts/roboto/roboto-v18-latin-regular.svg#Roboto")
format("svg"); /* Legacy iOS */
}
url("../fonts/roboto/roboto-v18-latin-regular.svg#Roboto") format("svg"); /* Legacy iOS */
}

View File

Before

Width:  |  Height:  |  Size: 301 KiB

After

Width:  |  Height:  |  Size: 301 KiB

View File

@@ -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>

View 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");
});

View 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);
}
}
};

View 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"
}
};

View File

@@ -0,0 +1 @@
module {{.BinaryName}}

View 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()
}

View File

@@ -1,10 +1,12 @@
{
"name": "Vue2/Webpack",
"name": "Vue2/Webpack Basic",
"shortdescription": "A basic Vue2/WebPack4 template",
"description": "A basic template using Vue 2 and bundled using Webpack 4",
"author": "Lea Anthony<lea.anthony@gmail.com>",
"created": "2018-12-01",
"frontenddir": "frontend",
"install": "npm install",
"build": "npm run build"
}
"build": "npm run build",
"serve": "npm run serve",
"bridge": "src"
}

View File

@@ -1,3 +0,0 @@
> 1%
last 2 versions
not ie <= 8

View File

@@ -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"
}
}

View File

@@ -1,5 +0,0 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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')

View File

@@ -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
}
},
}

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -2,4 +2,4 @@ package cmd
// Version - Wails version
// ...oO(There must be a better way)
const Version = "v0.5.0"
const Version = "v0.9.8"

View File

@@ -18,6 +18,8 @@ func init() {
setupCommand.Action(func() error {
logger.PrintBanner();
system := cmd.NewSystemHelper()
err := system.Initialise()
if err != nil {
@@ -29,61 +31,29 @@ Create your first project by running 'wails init'.`
if runtime.GOOS != "windows" {
successMessage = "🚀 " + successMessage
}
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)
}
logger.Yellow("Checking for prerequisites...")
// Check we have a cgo capable environment
requiredPrograms, err := cmd.GetRequiredPrograms()
// Platform check
err = platformCheck()
if err != nil {
return 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)
}
// Check we have a cgo capable environment
logger.Yellow("Checking for prerequisites...")
errors, err := checkRequiredPrograms()
if err != nil {
return err
}
// Linux has library deps
if runtime.GOOS == "linux" {
// Check library prerequisites
requiredLibraries, err := cmd.GetRequiredLibraries()
if err != nil {
return err
}
distroInfo := cmd.GetLinuxDistroInfo()
for _, library := range *requiredLibraries {
switch distroInfo.Distribution {
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)
}
}
errors, err = checkLibraries()
if err != nil {
return err
}
// Check Mewn
err = cmd.CheckMewn()
if err != nil {
return err
}
logger.White("")
@@ -95,3 +65,65 @@ Create your first project by running 'wails init'.`
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
}

View File

@@ -17,14 +17,14 @@ Any flags that are required and not given will be prompted for.`
LongDescription(commandDescription).
BoolFlag("f", "Use defaults", &projectOptions.UseDefaults).
StringFlag("dir", "Directory to create project in", &projectOptions.OutputDirectory).
StringFlag("template", "Template name", &projectOptions.Template).
// StringFlag("template", "Template name", &projectOptions.Template).
StringFlag("name", "Project name", &projectOptions.Name).
StringFlag("description", "Project description", &projectOptions.Description).
StringFlag("output", "Output binary name", &projectOptions.BinaryName)
initCommand.Action(func() error {
logger.WhiteUnderline("Initialising project")
logger.PrintSmallBanner("Initialising project")
fmt.Println()
// Check if the system is initialised
@@ -34,13 +34,11 @@ Any flags that are required and not given will be prompted for.`
return err
}
success, err := cmd.CheckDependencies(logger)
success, err := cmd.CheckDependenciesSilent(logger)
if !success {
return err
}
logger.White("")
// Do we want to just force defaults?
if projectOptions.UseDefaults {
// Use defaults

102
cmd/wails/4_build.go Normal file
View 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
View 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)
})
}

69
cmd/wails/8_update.go Normal file
View File

@@ -0,0 +1,69 @@
package main
import (
"fmt"
"net/http"
"io/ioutil"
"encoding/json"
"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","github.com/wailsapp/wails/cmd/wails"})
if err != nil {
updateSpinner.Error(err.Error())
return err
}
updateSpinner.Success()
logger.Yellow("Wails updated to " + latestVersion)
} else {
logger.Yellow("Looks like you're up to date!")
}
return nil
})
}

74
cmd/wails/9_issue.go Normal file
View File

@@ -0,0 +1,74 @@
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"runtime"
"strings"
"github.com/pkg/browser"
"github.com/wailsapp/wails/cmd"
)
func init() {
commandDescription := `Generates an issue in Github using the given title, description and system report.`
initCommand := app.Command("issue", "Generates an issue in Github.").
LongDescription(commandDescription)
initCommand.Action(func() error {
logger.PrintSmallBanner("Generate Issue")
fmt.Println()
message := `Thanks for taking the time to submit an issue!
To help you in this process, we will ask for some information, add Go/Wails details automatically, then prepare the issue for your editing and submission.
`
logger.Yellow(message)
title := cmd.Prompt("Issue Title")
description := cmd.Prompt("Issue Description")
var str strings.Builder
gomodule, exists := os.LookupEnv("GO111MODULE")
if !exists {
gomodule = "(Not Set)"
}
str.WriteString("\n| Name | Value |\n| ----- | ----- |\n")
str.WriteString(fmt.Sprintf("| Wails Version | %s |\n", cmd.Version))
str.WriteString(fmt.Sprintf("| Go Version | %s |\n", runtime.Version()))
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
fmt.Println()
fmt.Println("Processing template and preparing for upload.")
// Grab issue template
resp, err := http.Get("https://raw.githubusercontent.com/wailsapp/wails/master/.github/ISSUE_TEMPLATE/bug_report.md")
if err != nil {
logger.Red("Unable to read in issue template. Are you online?")
os.Exit(1)
}
defer resp.Body.Close()
template, _ := ioutil.ReadAll(resp.Body)
body := string(template)
body = "**Description**\n" + (strings.Split(body, "**Description**")[1])
fullURL := "https://github.com/wailsapp/wails/issues/new?"
body = strings.Replace(body, "A clear and concise description of what the bug is.", description, -1)
body = strings.Replace(body, "Please paste the output of `wails report` here.", str.String(), -1)
params := "title=" + title + "&body=" + body
fmt.Println("Opening browser to file issue.")
browser.OpenURL(fullURL + url.PathEscape(params))
return nil
})
}

View File

@@ -10,15 +10,8 @@ var logger = cmd.NewLogger()
// Create main app
var app = cmd.NewCli("wails", "A cli tool for building Wails applications.")
// Prints the cli banner
func printBanner(app *cmd.Cli) error {
logger.PrintBanner()
return nil
}
// Main!
func main() {
app.PreRun(printBanner)
err := app.Run()
if err != nil {
logger.Error(err.Error())

148
event_manager.go Normal file
View 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
}

32
go.mod
View File

@@ -1,17 +1,25 @@
module github.com/wailsapp/wails
require (
github.com/AlecAivazis/survey v1.7.1
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect
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/gobuffalo/packr v1.21.9
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/leaanthony/spinner v0.4.0
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 // indirect
github.com/leaanthony/wincursor v0.0.0-20180705115120-056510f32d15 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.4 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mitchellh/go-homedir v1.0.0
gopkg.in/AlecAivazis/survey.v1 v1.7.1 // indirect
github.com/go-playground/colors v1.2.0
github.com/gorilla/websocket v1.4.0
github.com/jackmordaunt/icns v1.0.0
github.com/leaanthony/mewn v0.9.4
github.com/leaanthony/slicer v1.2.0
github.com/leaanthony/spinner v0.5.0
github.com/mattn/go-colorable v0.1.0 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
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-20190219172222-a4c6cb3142f2 // indirect
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd // indirect
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 // indirect
)

417
go.sum
View File

@@ -1,371 +1,74 @@
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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
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/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc h1:VBS1z48BFEe00G81z8MKOtwX7f/ISkuH38NscT8iVPw=
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc/go.mod h1:ABJPuor7YlcsHmvJ1QxX38e2NcufLY3hm0yXv+cy9sI=
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/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY=
github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4=
github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs=
github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4=
github.com/gobuffalo/buffalo-plugins v1.4.3/go.mod h1:uCzTY0woez4nDMdQjkcOYKanngeUVRO2HZi7ezmAjWY=
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/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M=
github.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
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/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leaanthony/spinner v0.4.0 h1:y/7FqQqqObRKYI+33bg9DGhHIY7cQHicm+Vz0Uda0Ik=
github.com/leaanthony/spinner v0.4.0/go.mod h1:2Mmv+8Brcw3NwPT1DdOLmW6+zWpSamDDFFsUvVHo2cc=
github.com/leaanthony/spinner v0.5.0 h1:OJKn+0KP6ilHxwCEOv5Lo0wPM4PgWZWLJTeUprGJK0g=
github.com/leaanthony/spinner v0.5.0/go.mod h1:2Mmv+8Brcw3NwPT1DdOLmW6+zWpSamDDFFsUvVHo2cc=
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 h1:1bGojw4YacLY5bqQalojiQ7mSfQbe4WIWCEgPZagowU=
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
github.com/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/leaanthony/mewn v0.9.4 h1:thDAdV8DkCwqHcFLnfMLQtTHqK1N8leF7sD/SPsLMHI=
github.com/leaanthony/mewn v0.9.4/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
github.com/leaanthony/slicer v1.2.0 h1:XZ+1l7cCO36j238iv5ZXkJAcM3hPtD0xb41/WE+QmuU=
github.com/leaanthony/slicer v1.2.0/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
github.com/leaanthony/spinner v0.5.0 h1:HQykt/iTy7fmINEREtRbWrt+8j4MxC8dtvWBxEWM9oA=
github.com/leaanthony/spinner v0.5.0/go.mod h1:8TSFz9SL1AUC4XSbEFYE6SfN5Mlus51qYluVGrie9ww=
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
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.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o=
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
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/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
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/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
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/ribice/glice v0.0.0-20181011133736-685f13fa9b12/go.mod h1:A+ednilkKNW0CJGLsrLkq0D49M4EhlCi8gvnkwoZFn0=
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.0/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/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
github.com/wailsapp/wails v0.0.0-20181215232634-5de8efff325d h1:lk91T4sKD98eGcaz/xC6ER+3o9Kaun7Mk8e/cNZOPMc=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/wailsapp/webview v0.2.5 h1:/VacryPEUeMBb2VHHOjpoIze6ki8tW3qYX04MnI0b7o=
github.com/wailsapp/webview v0.2.5/go.mod h1:XO9HJbKWokDxUYTWQEBCYg95n/To1v7PxvanDNVf8hY=
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-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181024171144-74cb1d3d52f4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
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/crypto v0.0.0-20190219172222-a4c6cb3142f2 h1:NwxKRvbkH5MsNkvOtPZi3/3kmI8CAzs3mtv+GLQMkNo=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
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-20180909124046-d0be0721c37e/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-20180927150500-dad3d9fb7b6e/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-20181011152604-fa43e7bc11ba/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=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

38
ipc_call.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
}

View 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.

View 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.

View 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.

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Dean Karn
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.

Some files were not shown because too many files have changed in this diff Show More