Compare commits

..

7 Commits

Author SHA1 Message Date
Lea Anthony
6fafd165de Updated update command :-) 2019-02-23 18:26:36 +11:00
Lea Anthony
5ca7bfca66 improve messages 2019-02-23 15:53:19 +11:00
Lea Anthony
3f32c45f77 Try pulling in module at latest version 2019-02-23 15:25:14 +11:00
Lea Anthony
f8c805649a add report command 2019-02-23 15:24:26 +11:00
Lea Anthony
3ac993b01f Version bump 2019-02-23 13:26:03 +11:00
Lea Anthony
216c84b9cf Added version command to check after update 2019-02-23 12:56:40 +11:00
Lea Anthony
e99fffe340 Version bump 2019-02-23 10:25:31 +11:00
60 changed files with 612 additions and 1345 deletions

View File

@@ -1,42 +0,0 @@
{{ if .Versions -}}
<a name="unreleased"></a>
## [Unreleased]
{{ if .Unreleased.CommitGroups -}}
{{ range .Unreleased.CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}
{{ range .Versions }}
<a name="{{ .Tag.Name }}"></a>
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
{{ range .CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
{{ end }}
{{ end -}}
{{- if .NoteGroups -}}
{{ range .NoteGroups -}}
### {{ .Title }}
{{ range .Notes }}
{{ .Body }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}
{{- if .Versions }}
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
{{ range .Versions -}}
{{ if .Tag.Previous -}}
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
{{ end -}}
{{ end -}}
{{ end -}}

View File

@@ -1,27 +0,0 @@
style: github
template: CHANGELOG.tpl.md
info:
title: CHANGELOG
repository_url: https://github.com/wailsapp/wails
options:
commits:
# filters:
# Type:
# - feat
# - fix
# - perf
# - refactor
commit_groups:
# title_maps:
# feat: Features
# fix: Bug Fixes
# perf: Performance Improvements
# refactor: Code Refactoring
header:
pattern: "^(\\w*)\\:\\s(.*)$"
pattern_maps:
- Type
- Subject
notes:
keywords:
- BREAKING CHANGE

View File

@@ -1,30 +0,0 @@
---
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.

3
.gitignore vendored
View File

@@ -15,5 +15,4 @@ examples/**/example*
!examples/**/*.* !examples/**/*.*
cmd/wails/wails cmd/wails/wails
.DS_Store .DS_Store
tmp tmp
dist

View File

@@ -1,34 +0,0 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
builds:
- env:
- CGO_ENABLED=0
goos:
- windows
- linux
- darwin
goarch:
- 386
- amd64
ignore:
- goos: darwin
goarch: 386
main: ./cmd/wails/main.go
archive:
replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'

View File

@@ -1,3 +0,0 @@
{
"go.formatTool": "goimports"
}

View File

@@ -1,19 +0,0 @@
<a name="v0.13.0"></a>
## [v0.13.0] - 2019-05-12
### Feat
- revamped 'update' system
- no need for explicit GO111MODULE=on
### Fix
- documentation typo fixes
- windows init project
- windows 10 colour
- leave windows assets on -p flag
- show prerequisite errors
### Docs
- updated contributors
- added awesomego logo
- added Redhat distro

View File

@@ -1,12 +0,0 @@
# Contributors
Wails is what it is because of the time and effort given by these great people. A huge thank you to each and every one!
* [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot)
* [Qais Patankar](https://github.com/qaisjp)
* [Anthony Lee](https://github.com/alee792)
* [Adrian Lanzafame](https://github.com/lanzafame)
* [0xflotus](https://github.com/0xflotus)
* [Michael D Henderson](https://github.com/mdhender)
* [fred2104] (https://github.com/fishfishfish2104)
* [intelwalk] (https://github.com/intelwalk)

121
README.md
View File

@@ -1,120 +1 @@
<p align="center" style="text-align: center"> # Coming Soon
<img src="https://github.com/wailsapp/docs/raw/master/.vuepress/public/media/logo_cropped.png" width="40%"><br/>
</p>
<p align="center">
A framework for building desktop applications using Go & Web Technologies.<br/><br/>
<a href="https://github.com/wailsapp/wails/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
<a href="https://goreportcard.com/report/github.com/wailsapp/wails"><img src="https://goreportcard.com/badge/github.com/wailsapp/wails"/></a>
<a href="http://godoc.org/github.com/wailsapp/wails"><img src="https://img.shields.io/badge/godoc-reference-blue.svg"/></a>
<a href="https://www.codefactor.io/repository/github/wailsapp/wails"><img src="https://www.codefactor.io/repository/github/wailsapp/wails/badge" alt="CodeFactor" /></a>
<a href="https://github.com/wailsapp/wails/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat" alt="CodeFactor" /></a>
<a href="https://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></a>
<a href="https://github.com/sindresorhus/awesome" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>-
</p>
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
## Features
- Use standard Go libraries/frameworks for the backend
- Use any frontend technology to build your UI
- Expose Go methods/functions to the frontend via a single bind command
- Uses native rendering engines - no embedded browser
- Shared events system
- Native file dialogs
- Powerful cli tool
- Multiplatform
## Project Status
Wails is currently in Beta. Please make sure you read the [Project Status](https://wails.app/project_status.html) if you are interested in using this project.
## Installation
Wails uses cgo to bind to the native rendering engines so a number of platform dependent libraries are needed as well as an installation of Go. The basic requirements are:
- Go 1.11 or above
- npm
### MacOS
Make sure you have the xcode command line tools installed. This can be done by running:
`xcode-select --install`
### Linux
#### Ubuntu 18.04
`sudo apt install pkg-config build-essential libgtk-3-dev libwebkit2gtk-4.0-dev`
#### Arch Linux
`sudo pacman -S webkit2gtk gtk3`
#### Red Hat Based Distros
`sudo yum install webkit2gtk-devel gtk3-devel`
Note: If you have successfully installed these dependencies on a different flavour of Linux, please consider submitting a PR.
### Windows
Windows requires gcc and related tooling. The recommended download is from [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download). Once this is installed, you are good to go.
## Installation
Installation is as simple as running the following command:
<pre style='color:white'>
go get github.com/wailsapp/wails/cmd/wails
</pre>
## Next Steps
It is recommended at this stage to read the comprehensive documentation at [https://wails.app](https://wails.app).
## FAQ
* Is this an alternative to Electron?
Depends on your requirements. It's designed to make it easy for Go programmers to make lightweight desktop applications or add a frontend to their existing applications. Whilst Wails does not currently offer hooks into native elements such as menus, this may change in the future.
* Who is this project aimed at?
Go programmers who want to bundle an HTML/JS/CSS frontend with their applications, without resorting to creating a server and opening a browser to view it.
* What's with the name?
When I saw WebView, I thought "What I really want is tooling around building a WebView app, a bit like Rails is to Ruby". So initially it was a play on words (Webview on Rails). It just so happened to also be a homophone of the English name for the [Country](https://en.wikipedia.org/wiki/Wales) I am from. So it stuck.
## Shoulders of Giants
Without the following people, this project would never have existed:
* [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - His support and feedback has been immense. More patience than you can throw a stick at (Not long now Dustin!).
* [Serge Zaitsev](https://github.com/zserge) - Creator of [Webview](https://github.com/zserge/webview) which Wails uses for the windowing.
And without [these people](CONTRIBUTORS.md), it wouldn't be what it is today.
Special Mentions:
* [Bill Kennedy](https://twitter.com/goinggodotnet) - Go guru, encourager and all-round nice guy, whose infectious energy and inspiration powered me on when I had none left.
* [Mark Bates](https://github.com/markbates) - Creator of [Packr](https://github.com/gobuffalo/packr), inspiration for packing strategies which fed into some of the tooling.
This project was mainly coded to the following albums:
* [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA)
* [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN)
* [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8)
* [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr)
* [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m)
* [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle)
* [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs)
* [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM)
* [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm)
* [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug)
* [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB)
* [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF)
* [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v)

10
app.go
View File

@@ -70,11 +70,7 @@ func (a *App) Run() error {
} }
a.logLevel = "error" a.logLevel = "error"
err := a.start() return a.start()
if err != nil {
a.log.Error(err.Error())
}
return err
} }
func (a *App) start() error { func (a *App) start() error {
@@ -118,7 +114,9 @@ func (a *App) start() error {
a.renderer.AddJSList(a.jsCache) a.renderer.AddJSList(a.jsCache)
// Run the renderer // Run the renderer
return a.renderer.Run() a.renderer.Run()
return nil
} }
// Bind allows the user to bind the given object // Bind allows the user to bind the given object

View File

@@ -1,6 +1,8 @@
package wails package wails
import ( import (
"fmt"
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
) )
@@ -9,7 +11,6 @@ func (app *App) setupCli() *cmd.Cli {
// Create a new cli // Create a new cli
result := cmd.NewCli(app.config.Title, "Debug build") result := cmd.NewCli(app.config.Title, "Debug build")
result.Version(cmd.Version)
// Setup cli to handle loglevel and headless flags // Setup cli to handle loglevel and headless flags
result. result.
@@ -20,6 +21,8 @@ func (app *App) setupCli() *cmd.Cli {
// Banner // Banner
result.PreRun(func(cli *cmd.Cli) error { result.PreRun(func(cli *cmd.Cli) error {
log := cmd.NewLogger() log := cmd.NewLogger()
log.PrintSmallBanner()
fmt.Println()
log.YellowUnderline(app.config.Title + " - Debug Build") log.YellowUnderline(app.config.Title + " - Debug Build")
return nil return nil
}) })

View File

@@ -41,7 +41,7 @@ func (a *AppConfig) merge(in *AppConfig) error {
a.HTML = strings.TrimSpace(inlineHTML) a.HTML = strings.TrimSpace(inlineHTML)
// Deduce whether this is a full html page or a fragment // Deduce whether this is a full html page or a fragment
// The document is determined to be a fragment if an HTML // The document is determined to be a fragment if an HMTL
// tag exists and is located before the first div tag // tag exists and is located before the first div tag
HTMLTagIndex := strings.Index(a.HTML, "<html") HTMLTagIndex := strings.Index(a.HTML, "<html")
DivTagIndex := strings.Index(a.HTML, "<div") DivTagIndex := strings.Index(a.HTML, "<div")

View File

@@ -153,11 +153,8 @@ func (b *boundFunction) setInputValue(index int, typ reflect.Type, val interface
} }
}() }()
// Translate javascript null values // Do the conversion
if val == nil { result = reflect.ValueOf(val).Convert(typ)
result = reflect.Zero(typ)
} else {
result = reflect.ValueOf(val).Convert(typ)
}
return result, err return result, err
} }

View File

@@ -195,7 +195,10 @@ func (c *Command) Action(callback Action) *Command {
// PrintHelp - Output the help text for this command // PrintHelp - Output the help text for this command
func (c *Command) PrintHelp() { func (c *Command) PrintHelp() {
c.log.PrintBanner() c.log.PrintBanner()
versionString := c.AppVersion
if versionString != "" {
versionString = " " + versionString
}
commandTitle := c.CommandPath commandTitle := c.CommandPath
if c.Shortdescription != "" { if c.Shortdescription != "" {
commandTitle += " - " + c.Shortdescription commandTitle += " - " + c.Shortdescription

File diff suppressed because one or more lines are too long

View File

@@ -41,14 +41,6 @@ func (fs *FSHelper) FileExists(path string) bool {
return fi.Mode().IsRegular() 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. // MkDirs creates the given nested directories.
// Returns error on failure // Returns error on failure
func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error { func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error {

View File

@@ -1,108 +0,0 @@
package cmd
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sort"
)
// GitHubHelper is a utility class for interacting with GitHub
type GitHubHelper struct {
}
// NewGitHubHelper returns a new GitHub Helper
func NewGitHubHelper() *GitHubHelper {
return &GitHubHelper{}
}
// GetVersionTags gets the list of tags on the Wails repo
// It retuns a list of sorted tags in descending order
func (g *GitHubHelper) GetVersionTags() ([]*SemanticVersion, error) {
result := []*SemanticVersion{}
var err error
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/tags")
if err != nil {
return result, err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return result, err
}
data := []map[string]interface{}{}
err = json.Unmarshal(body, &data)
if err != nil {
return result, err
}
// Convert tag data to Version structs
for _, tag := range data {
version := tag["name"].(string)
semver, err := NewSemanticVersion(version)
if err != nil {
return result, err
}
result = append(result, semver)
}
// Reverse Sort
sort.Sort(sort.Reverse(SemverCollection(result)))
return result, err
}
// GetLatestStableRelease gets the latest stable release on GitHub
func (g *GitHubHelper) GetLatestStableRelease() (result *SemanticVersion, err error) {
tags, err := g.GetVersionTags()
if err != nil {
return nil, err
}
for _, tag := range tags {
if tag.IsRelease() {
return tag, nil
}
}
return nil, fmt.Errorf("no release tag found")
}
// GetLatestPreRelease gets the latest prerelease on GitHub
func (g *GitHubHelper) GetLatestPreRelease() (result *SemanticVersion, err error) {
tags, err := g.GetVersionTags()
if err != nil {
return nil, err
}
for _, tag := range tags {
if tag.IsPreRelease() {
return tag, nil
}
}
return nil, fmt.Errorf("no prerelease tag found")
}
// IsValidTag returns true if the given string is a valid tag
func (g *GitHubHelper) IsValidTag(tagVersion string) (bool, error) {
if tagVersion[0] == 'v' {
tagVersion = tagVersion[1:]
}
tags, err := g.GetVersionTags()
if err != nil {
return false, err
}
for _, tag := range tags {
if tag.String() == tagVersion {
return true, nil
}
}
return false, nil
}

View File

@@ -5,17 +5,15 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"time" "time"
mewn "github.com/leaanthony/mewn"
"github.com/leaanthony/slicer" "github.com/leaanthony/slicer"
"github.com/leaanthony/spinner" "github.com/leaanthony/spinner"
) )
var fs = NewFSHelper()
// ValidateFrontendConfig checks if the frontend config is valid // ValidateFrontendConfig checks if the frontend config is valid
func ValidateFrontendConfig(projectOptions *ProjectOptions) error { func ValidateFrontendConfig(projectOptions *ProjectOptions) error {
if projectOptions.FrontEnd.Dir == "" { if projectOptions.FrontEnd.Dir == "" {
@@ -36,7 +34,7 @@ func ValidateFrontendConfig(projectOptions *ProjectOptions) error {
// InstallGoDependencies will run go get in the current directory // InstallGoDependencies will run go get in the current directory
func InstallGoDependencies() error { func InstallGoDependencies() error {
depSpinner := spinner.New("Ensuring Dependencies are up to date...") depSpinner := spinner.New("Installing Dependencies...")
depSpinner.SetSpinSpeed(50) depSpinner.SetSpinSpeed(50)
depSpinner.Start() depSpinner.Start()
err := NewProgramHelper().RunCommand("go get") err := NewProgramHelper().RunCommand("go get")
@@ -77,14 +75,7 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
packSpinner.Start() packSpinner.Start()
buildCommand := slicer.String() buildCommand := slicer.String()
buildCommand.Add("mewn") buildCommand.AddSlice([]string{"mewn", "build"})
if buildMode == BuildModeBridge {
// Ignore errors
buildCommand.Add("-i")
}
buildCommand.Add("build")
if binaryName != "" { if binaryName != "" {
buildCommand.Add("-o") buildCommand.Add("-o")
@@ -117,18 +108,10 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
} }
packSpinner.Success() packSpinner.Success()
// packageApp
if packageApp {
err = PackageApplication(projectOptions)
if err != nil {
return err
}
}
return nil return nil
} }
// PackageApplication will attempt to package the application in a platform dependent way // PackageApplication will attempt to package the application in a pltform dependent way
func PackageApplication(projectOptions *ProjectOptions) error { func PackageApplication(projectOptions *ProjectOptions) error {
// Package app // Package app
message := "Generating .app" message := "Generating .app"
@@ -189,7 +172,7 @@ func CheckWindres() (err error) {
} }
programHelper := NewProgramHelper() programHelper := NewProgramHelper()
if !programHelper.IsInstalled("windres") { if !programHelper.IsInstalled("windres") {
return fmt.Errorf("windres not installed. It comes by default with mingw. Ensure you have installed mingw correctly") return fmt.Errorf("windres not installed. It comes by default with mingw. Ensure you have installed mingw correctly.")
} }
return nil return nil
} }
@@ -204,7 +187,7 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
} }
// Check if frontend deps have been updated // Check if frontend deps have been updated
feSpinner := spinner.New("Ensuring frontend dependencies are up to date (This may take a while)") feSpinner := spinner.New("Installing frontend dependencies (This may take a while)...")
feSpinner.SetSpinSpeed(50) feSpinner.SetSpinSpeed(50)
feSpinner.Start() feSpinner.Start()
@@ -249,32 +232,22 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644) ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
} }
// Install the bridge library
err = InstallBridge(caller, projectDir, projectOptions)
if err != nil {
return err
}
// Build frontend
err = BuildFrontend(projectOptions.FrontEnd.Build)
if err != nil {
return err
}
return nil
}
// InstallBridge installs the relevant bridge javascript library
func InstallBridge(caller string, projectDir string, projectOptions *ProjectOptions) error {
bridgeFile := "wailsbridge.prod.js" bridgeFile := "wailsbridge.prod.js"
if caller == "serve" { if caller == "serve" {
bridgeFile = "wailsbridge.js" bridgeFile = "wailsbridge.js"
} }
// Copy bridge to project // Copy bridge to project
bridgeAssets := mewn.Group("../wailsruntimeassets/bridge/") _, filename, _, _ := runtime.Caller(1)
bridgeFileData := bridgeAssets.Bytes(bridgeFile) bridgeFileSource := filepath.Join(path.Dir(filename), "..", "..", "wailsruntimeassets", "bridge", bridgeFile)
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js") bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js")
err := fs.CreateFile(bridgeFileTarget, bridgeFileData) err = fs.CopyFile(bridgeFileSource, bridgeFileTarget)
if err != nil {
return err
}
// Build frontend
err = BuildFrontend(projectOptions.FrontEnd.Build)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,9 +2,6 @@ package cmd
import ( import (
"fmt" "fmt"
"io/ioutil"
"os"
"regexp"
"strings" "strings"
) )
@@ -13,13 +10,9 @@ type LinuxDistribution int
const ( const (
// Unknown is the catch-all distro // Unknown is the catch-all distro
Unknown LinuxDistribution = iota Unknown LinuxDistribution = 0
// Ubuntu distribution // Ubuntu distribution
Ubuntu Ubuntu LinuxDistribution = 1
// Arch linux distribution
Arch
// RedHat linux distribution
RedHat
) )
// DistroInfo contains all the information relating to a linux distribution // DistroInfo contains all the information relating to a linux distribution
@@ -56,8 +49,6 @@ func GetLinuxDistroInfo() *DistroInfo {
switch value { switch value {
case "Ubuntu": case "Ubuntu":
result.Distribution = Ubuntu result.Distribution = Ubuntu
case "Arch":
result.Distribution = Arch
} }
case "Description": case "Description":
result.Description = value result.Description = value
@@ -69,52 +60,20 @@ func GetLinuxDistroInfo() *DistroInfo {
} }
} }
} }
// check if /etc/os-release exists
} else if _, err := os.Stat("/etc/os-release"); !os.IsNotExist(err) {
// read /etc/os-release
osRelease, _ := ioutil.ReadFile("/etc/os-release")
// compile a regex to find NAME=distro
re := regexp.MustCompile(`^NAME=(.*)\n`)
// extract the distro name
osName := string(re.FindSubmatch(osRelease)[1])
// Check distro name against list of RedHat distros
if osName == "Fedora" || osName == "CentOS" {
//if it matches set result.Distribution to RedHat
result.Distribution = RedHat
}
} }
return result return result
} }
// DpkgInstalled uses dpkg to see if a package is installed // DpkgInstalled uses dpkg to see if a package is installed
func DpkgInstalled(packageName string) (bool, error) { func DpkgInstalled(packageName string) (bool, error) {
result := false
program := NewProgramHelper() program := NewProgramHelper()
dpkg := program.FindProgram("dpkg") dpkg := program.FindProgram("dpkg")
if dpkg == nil { if dpkg == nil {
return false, fmt.Errorf("cannot check dependencies: dpkg not found") return false, fmt.Errorf("cannot check dependencies: dpkg not found")
} }
_, _, exitCode, _ := dpkg.Run("-L", packageName) _, _, exitCode, _ := dpkg.Run("-L", packageName)
return exitCode == 0, nil result = exitCode == 0
} return result, nil
// PacmanInstalled uses pacman to see if a package is installed.
func PacmanInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
pacman := program.FindProgram("pacman")
if pacman == nil {
return false, fmt.Errorf("cannot check dependencies: pacman not found")
}
_, _, exitCode, _ := pacman.Run("-Qs", packageName)
return exitCode == 0, nil
}
// RpmInstalled uses rpm to see if a package is installed
func RpmInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
rpm := program.FindProgram("rpm")
if rpm == nil {
return false, fmt.Errorf("cannot check dependencies: rpm not found")
}
_, _, exitCode, _ := rpm.Run("--query", packageName)
return exitCode == 0, nil
} }

View File

@@ -17,7 +17,6 @@ func NewLogger() *Logger {
return &Logger{errorOnly: false} return &Logger{errorOnly: false}
} }
// SetErrorOnly ensures that only errors are logged out
func (l *Logger) SetErrorOnly(errorOnly bool) { func (l *Logger) SetErrorOnly(errorOnly bool) {
l.errorOnly = errorOnly l.errorOnly = errorOnly
} }
@@ -100,7 +99,6 @@ func (l *Logger) Error(format string, a ...interface{}) {
color.New(color.FgHiRed).PrintfFunc()("Error: "+format+"\n", a...) color.New(color.FgHiRed).PrintfFunc()("Error: "+format+"\n", a...)
} }
// PrintSmallBanner prints a condensed banner
func (l *Logger) PrintSmallBanner(message ...string) { func (l *Logger) PrintSmallBanner(message ...string) {
yellow := color.New(color.FgYellow).SprintFunc() yellow := color.New(color.FgYellow).SprintFunc()
red := color.New(color.FgRed).SprintFunc() red := color.New(color.FgRed).SprintFunc()

View File

@@ -72,11 +72,11 @@ func (b *PackageHelper) Package(po *ProjectOptions) error {
case "darwin": case "darwin":
// Check we have the exe // Check we have the exe
if !b.fs.FileExists(po.BinaryName) { if !b.fs.FileExists(po.BinaryName) {
return fmt.Errorf("cannot bundle non-existent binary file '%s'. Please build with 'wails build' first", po.BinaryName) return fmt.Errorf("cannot bundle non-existant binary file '%s'. Please build with 'wails build' first", po.BinaryName)
} }
return b.packageOSX(po) return b.packageOSX(po)
case "windows": case "windows":
return b.PackageWindows(po, false) return b.PackageWindows(po, true)
case "linux": case "linux":
return fmt.Errorf("linux is not supported at this time. Please see https://github.com/wailsapp/wails/issues/2") return fmt.Errorf("linux is not supported at this time. Please see https://github.com/wailsapp/wails/issues/2")
default: default:
@@ -150,7 +150,6 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
return err return err
} }
// PackageWindows packages the application for windows platforms
func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error { func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
basename := strings.TrimSuffix(po.BinaryName, ".exe") basename := strings.TrimSuffix(po.BinaryName, ".exe")
@@ -199,7 +198,7 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
// clean up // clean up
if cleanUp { if cleanUp {
filesToDelete := []string{tgtIconFile, tgtManifestFile, tgtRCFile, sysofile} filesToDelete := []string{tgtIconFile, tgtManifestFile, tgtRCFile}
err := b.fs.RemoveFiles(filesToDelete) err := b.fs.RemoveFiles(filesToDelete)
if err != nil { if err != nil {
return err return err
@@ -255,5 +254,9 @@ func (b *PackageHelper) packageIconOSX(resourceDir string) error {
} }
defer dest.Close() defer dest.Close()
return icns.Encode(dest, srcImg) if err := icns.Encode(dest, srcImg); err != nil {
return err
}
return nil
} }

View File

@@ -97,12 +97,6 @@ func getRequiredLibrariesLinux() (*Prerequisites, error) {
case Ubuntu: case Ubuntu:
result.Add(newPrerequisite("libgtk-3-dev", "Please install with `sudo apt install libgtk-3-dev` and try again")) result.Add(newPrerequisite("libgtk-3-dev", "Please install with `sudo apt install libgtk-3-dev` and try again"))
result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with `sudo apt install libwebkit2gtk-4.0-dev` and try again")) result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with `sudo apt install libwebkit2gtk-4.0-dev` and try again"))
case Arch:
result.Add(newPrerequisite("gtk3", "Please install with `sudo pacman -S gtk3` and try again"))
result.Add(newPrerequisite("webkit2gtk", "Please install with `sudo pacman -S webkit2gtk` and try again"))
case RedHat:
result.Add(newPrerequisite("gtk3-devel", "Please install with `sudo yum install gtk3-devel` and try again"))
result.Add(newPrerequisite("webkit2gtk3-devel", "Please install with `sudo yum install webkit2gtk3-devel` and try again"))
default: default:
result.Add(newPrerequisite("libgtk-3-dev", "Please install with your system package manager and try again")) result.Add(newPrerequisite("libgtk-3-dev", "Please install with your system package manager and try again"))
result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with your system package manager and try again")) result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with your system package manager and try again"))

View File

@@ -56,7 +56,7 @@ func (p *Program) GetFullPathToBinary() (string, error) {
} }
// Run will execute the program with the given parameters // Run will execute the program with the given parameters
// Returns stdout + stderr as strings and an error if one occurred // Returns stdout + stderr as strings and an error if one occured
func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err error) { func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err error) {
command, err := p.GetFullPathToBinary() command, err := p.GetFullPathToBinary()
if err != nil { if err != nil {
@@ -92,7 +92,7 @@ func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err
// InstallGoPackage installs the given Go package // InstallGoPackage installs the given Go package
func (p *ProgramHelper) InstallGoPackage(packageName string) error { func (p *ProgramHelper) InstallGoPackage(packageName string) error {
args := strings.Split("get "+packageName, " ") args := strings.Split("get -u "+packageName, " ")
_, stderr, err := p.shell.Run("go", args...) _, stderr, err := p.shell.Run("go", args...)
if err != nil { if err != nil {
fmt.Println(stderr) fmt.Println(stderr)
@@ -106,8 +106,17 @@ func (p *ProgramHelper) RunCommand(command string) error {
return p.RunCommandArray(args) return p.RunCommandArray(args)
} }
func (p *ProgramHelper) GetOutputFromCommand(command string) (string, string, error) {
args := strings.Split(command, " ")
if len(args) > 1 {
return p.shell.Run(args[0], args[1:]...)
} else {
return p.shell.Run(args[0])
}
}
// RunCommandArray runs the command specified in the array // RunCommandArray runs the command specified in the array
func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error { func (p *ProgramHelper) RunCommandArray(args []string) error {
program := args[0] program := args[0]
// TODO: Run FindProgram here and get the full path to the exe // TODO: Run FindProgram here and get the full path to the exe
program, err := exec.LookPath(program) program, err := exec.LookPath(program)
@@ -116,13 +125,8 @@ func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error {
return err return err
} }
args = args[1:] args = args[1:]
var stderr string
// fmt.Printf("RunCommandArray = %s %+v\n", program, args) // fmt.Printf("RunCommandArray = %s %+v\n", program, args)
if len(dir) > 0 { _, stderr, err := p.shell.Run(program, args...)
_, stderr, err = p.shell.RunInDirectory(dir[0], program, args...)
} else {
_, stderr, err = p.shell.Run(program, args...)
}
if err != nil { if err != nil {
fmt.Println(stderr) fmt.Println(stderr)
} }

View File

@@ -4,12 +4,9 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"github.com/leaanthony/slicer"
) )
type author struct { type author struct {
@@ -50,11 +47,15 @@ func NewProjectHelper() *ProjectHelper {
// GenerateProject generates a new project using the options given // GenerateProject generates a new project using the options given
func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error { func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
// exists := ph.templates.TemplateExists(projectOptions.Template) fs := NewFSHelper()
exists, err := ph.templates.TemplateExists(projectOptions.Template)
if err != nil {
return err
}
// if !exists { if !exists {
// return fmt.Errorf("template '%s' is invalid", projectOptions.Template) return fmt.Errorf("template '%s' is invalid", projectOptions.Template)
// } }
// Calculate project path // Calculate project path
projectPath, err := filepath.Abs(projectOptions.OutputDirectory) projectPath, err := filepath.Abs(projectOptions.OutputDirectory)
@@ -62,8 +63,6 @@ func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
return err return err
} }
_ = projectPath
if fs.DirExists(projectPath) { if fs.DirExists(projectPath) {
return fmt.Errorf("directory '%s' already exists", projectPath) return fmt.Errorf("directory '%s' already exists", projectPath)
} }
@@ -115,14 +114,15 @@ func (ph *ProjectHelper) LoadProjectConfig(dir string) (*ProjectOptions, error)
// NewProjectOptions creates a new default set of project options // NewProjectOptions creates a new default set of project options
func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions { func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
result := ProjectOptions{ result := ProjectOptions{
Name: "", Name: "",
Description: "Enter your project description", Description: "Enter your project description",
Version: "0.1.0", Version: "0.1.0",
BinaryName: "", BinaryName: "",
system: NewSystemHelper(), system: NewSystemHelper(),
log: NewLogger(), log: NewLogger(),
templates: NewTemplateHelper(), templates: NewTemplateHelper(),
Author: &author{}, templateNameMap: make(map[string]string),
Author: &author{},
} }
// Populate system config // Populate system config
@@ -137,25 +137,25 @@ func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
// ProjectOptions holds all the options available for a project // ProjectOptions holds all the options available for a project
type ProjectOptions struct { type ProjectOptions struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Author *author `json:"author,omitempty"` Author *author `json:"author,omitempty"`
Version string `json:"version"` Version string `json:"version"`
OutputDirectory string `json:"-"` OutputDirectory string `json:"-"`
UseDefaults bool `json:"-"` UseDefaults bool `json:"-"`
Template string `json:"-"` Template string `json:"-"`
BinaryName string `json:"binaryname"` BinaryName string `json:"binaryname"`
FrontEnd *frontend `json:"frontend,omitempty"` FrontEnd *frontend `json:"frontend,omitempty"`
NPMProjectName string `json:"-"` NPMProjectName string `json:"-"`
system *SystemHelper system *SystemHelper
log *Logger log *Logger
templates *TemplateHelper templates *TemplateHelper
selectedTemplate *TemplateDetails templateNameMap map[string]string // Converts template prompt text to template name
} }
// Defaults sets the default project template // Defaults sets the default project template
func (po *ProjectOptions) Defaults() { func (po *ProjectOptions) Defaults() {
po.Template = "vuebasic" po.Template = "basic"
} }
// PromptForInputs asks the user to input project details // PromptForInputs asks the user to input project details
@@ -170,31 +170,48 @@ func (po *ProjectOptions) PromptForInputs() error {
return err return err
} }
// Process Templates templateDetails, err := po.templates.GetTemplateDetails()
templateList := slicer.Interface() if err != nil {
options := slicer.String() return err
for _, templateDetails := range po.templates.TemplateList.details {
templateList.Add(templateDetails)
options.Add(fmt.Sprintf("%s - %s", templateDetails.Metadata.Name, templateDetails.Metadata.ShortDescription))
} }
templateIndex := 0 templates := []string{}
// Add a Custom Template
if len(options.AsSlice()) > 1 { // templates = append(templates, "Custom - Choose your own CSS framework")
templateIndex = PromptSelection("Please select a template", options.AsSlice(), 0) 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
} }
// After selection do this.... if po.Template != "" {
po.selectedTemplate = templateList.AsSlice()[templateIndex].(*TemplateDetails) if _, ok := templateDetails[po.Template]; !ok {
po.log.Error("Template '%s' invalid.", po.Template)
templateSelected := PromptSelection("Select template", templates)
po.Template = templates[templateSelected]
}
} else {
templateSelected := PromptSelection("Select template", templates)
po.Template = templates[templateSelected]
}
// Setup NPM Project name // Setup NPM Project name
po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1)) po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1))
// Fix template name // Fix template name
po.Template = strings.Split(po.selectedTemplate.Path, string(os.PathSeparator))[0] if po.templateNameMap[po.Template] != "" {
po.Template = po.templateNameMap[po.Template]
}
// // Populate template details // Populate template details
templateMetadata := po.selectedTemplate.Metadata templateMetadata := templateDetails[po.Template].Metadata
err = processTemplateMetadata(templateMetadata, po) err = processTemplateMetadata(templateMetadata, po)
if err != nil { if err != nil {
@@ -282,36 +299,36 @@ func processBinaryName(po *ProjectOptions) {
fmt.Println("Output binary Name: " + po.BinaryName) fmt.Println("Output binary Name: " + po.BinaryName)
} }
func processTemplateMetadata(templateMetadata *TemplateMetadata, po *ProjectOptions) error { func processTemplateMetadata(templateMetadata map[string]interface{}, po *ProjectOptions) error {
if templateMetadata.FrontendDir != "" { if templateMetadata["frontenddir"] != nil {
po.FrontEnd = &frontend{} po.FrontEnd = &frontend{}
po.FrontEnd.Dir = templateMetadata.FrontendDir po.FrontEnd.Dir = templateMetadata["frontenddir"].(string)
} }
if templateMetadata.Install != "" { if templateMetadata["install"] != nil {
if po.FrontEnd == nil { if po.FrontEnd == nil {
return fmt.Errorf("install set in template metadata but not frontenddir") return fmt.Errorf("install set in template metadata but not frontenddir")
} }
po.FrontEnd.Install = templateMetadata.Install po.FrontEnd.Install = templateMetadata["install"].(string)
} }
if templateMetadata.Build != "" { if templateMetadata["build"] != nil {
if po.FrontEnd == nil { if po.FrontEnd == nil {
return fmt.Errorf("build set in template metadata but not frontenddir") return fmt.Errorf("build set in template metadata but not frontenddir")
} }
po.FrontEnd.Build = templateMetadata.Build po.FrontEnd.Build = templateMetadata["build"].(string)
} }
if templateMetadata.Bridge != "" { if templateMetadata["bridge"] != nil {
if po.FrontEnd == nil { if po.FrontEnd == nil {
return fmt.Errorf("bridge set in template metadata but not frontenddir") return fmt.Errorf("bridge set in template metadata but not frontenddir")
} }
po.FrontEnd.Bridge = templateMetadata.Bridge po.FrontEnd.Bridge = templateMetadata["bridge"].(string)
} }
if templateMetadata.Serve != "" { if templateMetadata["serve"] != nil {
if po.FrontEnd == nil { if po.FrontEnd == nil {
return fmt.Errorf("serve set in template metadata but not frontenddir") return fmt.Errorf("serve set in template metadata but not frontenddir")
} }
po.FrontEnd.Serve = templateMetadata.Serve po.FrontEnd.Serve = templateMetadata["serve"].(string)
} }
return nil return nil
} }

View File

@@ -1,35 +1,25 @@
package cmd package cmd
import ( import (
"bufio"
"fmt" "fmt"
"os"
"runtime"
"strconv" "strconv"
"strings"
) )
// Prompt asks the user for a value // Prompt asks the user for a value
func Prompt(question string, defaultValue ...string) string { func Prompt(question string, defaultValue ...string) string {
var answer string var answer string
haveDefault := len(defaultValue) > 0 && defaultValue[0] != ""
if len(defaultValue) > 0 { if haveDefault {
answer = defaultValue[0] question = fmt.Sprintf("%s (%s)", question, defaultValue[0])
question = fmt.Sprintf("%s (%s)", question, answer)
} }
fmt.Printf(question + ": ") fmt.Printf(question + ": ")
reader := bufio.NewReader(os.Stdin) fmt.Scanln(&answer)
input, _ := reader.ReadString('\n') if haveDefault {
EOL := "\n" if len(answer) == 0 {
if runtime.GOOS == "windows" { answer = defaultValue[0]
EOL = "\r\n" }
} }
input = strings.Replace(input, EOL, "", -1)
if input != "" {
answer = input
}
return answer return answer
} }
@@ -44,29 +34,18 @@ func PromptRequired(question string, defaultValue ...string) string {
} }
// PromptSelection asks the user to choose an option // PromptSelection asks the user to choose an option
func PromptSelection(question string, options []string, optionalDefaultValue ...int) int { func PromptSelection(question string, options []string) int {
defaultValue := -1
message := "Please choose an option"
fmt.Println(question + ":") fmt.Println(question + ":")
if len(optionalDefaultValue) > 0 {
defaultValue = optionalDefaultValue[0] + 1
message = fmt.Sprintf("%s [%d]", message, defaultValue)
}
for index, option := range options { for index, option := range options {
fmt.Printf(" %d: %s\n", index+1, option) fmt.Printf(" %d: %s\n", index+1, option)
} }
fmt.Println()
selectedValue := -1 selectedValue := -1
for { for {
choice := Prompt(message) choice := Prompt("Please choose an option")
if choice == "" && defaultValue > -1 {
selectedValue = defaultValue - 1
break
}
// index // index
number, err := strconv.Atoi(choice) number, err := strconv.Atoi(choice)

View File

@@ -1,98 +0,0 @@
package cmd
import (
"fmt"
"github.com/masterminds/semver"
)
// SemanticVersion is a struct containing a semantic version
type SemanticVersion struct {
Version *semver.Version
}
// NewSemanticVersion creates a new SemanticVersion object with the given version string
func NewSemanticVersion(version string) (*SemanticVersion, error) {
semverVersion, err := semver.NewVersion(version)
if err != nil {
return nil, err
}
return &SemanticVersion{
Version: semverVersion,
}, nil
}
// IsRelease returns true if it's a release version
func (s *SemanticVersion) IsRelease() bool {
return len(s.Version.Prerelease()) == 0 && len(s.Version.Metadata()) == 0
}
// IsPreRelease returns true if it's a prerelease version
func (s *SemanticVersion) IsPreRelease() bool {
return len(s.Version.Prerelease()) > 0
}
func (s *SemanticVersion) String() string {
return s.Version.String()
}
// IsGreaterThan returns true if this version is greater than the given version
func (s *SemanticVersion) IsGreaterThan(version *SemanticVersion) (bool, error) {
// Set up new constraint
constraint, err := semver.NewConstraint("> " + version.Version.String())
if err != nil {
return false, err
}
// Check if the desired one is greater than the requested on
success, msgs := constraint.Validate(s.Version)
if !success {
return false, msgs[0]
}
return true, nil
}
// IsGreaterThanOrEqual returns true if this version is greater than or equal the given version
func (s *SemanticVersion) IsGreaterThanOrEqual(version *SemanticVersion) (bool, error) {
// Set up new constraint
constraint, err := semver.NewConstraint(">= " + version.Version.String())
if err != nil {
return false, err
}
// Check if the desired one is greater than the requested on
success, msgs := constraint.Validate(s.Version)
if !success {
return false, msgs[0]
}
return true, nil
}
// MainVersion returns the main version of any version+prerelease+metadata
// EG: MainVersion("1.2.3-pre") => "1.2.3"
func (s *SemanticVersion) MainVersion() *SemanticVersion {
mainVersion := fmt.Sprintf("%d.%d.%d", s.Version.Major(), s.Version.Minor(), s.Version.Patch())
result, _ := NewSemanticVersion(mainVersion)
return result
}
// SemverCollection is a collection of SemanticVersion objects
type SemverCollection []*SemanticVersion
// Len returns the length of a collection. The number of Version instances
// on the slice.
func (c SemverCollection) Len() int {
return len(c)
}
// Less is needed for the sort interface to compare two Version objects on the
// slice. If checks if one is less than the other.
func (c SemverCollection) Less(i, j int) bool {
return c[i].Version.LessThan(c[j].Version)
}
// Swap is needed for the sort interface to replace the Version objects
// at two different positions in the slice.
func (c SemverCollection) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}

1
cmd/setup.go Normal file
View File

@@ -0,0 +1 @@
package cmd

View File

@@ -2,7 +2,6 @@ package cmd
import ( import (
"bytes" "bytes"
"os"
"os/exec" "os/exec"
) )
@@ -18,21 +17,6 @@ func NewShellHelper() *ShellHelper {
// Run the given command // Run the given command
func (sh *ShellHelper) Run(command string, vars ...string) (stdout, stderr string, err error) { func (sh *ShellHelper) Run(command string, vars ...string) (stdout, stderr string, err error) {
cmd := exec.Command(command, vars...) cmd := exec.Command(command, vars...)
cmd.Env = append(os.Environ(), "GO111MODULE=on")
var stdo, stde bytes.Buffer
cmd.Stdout = &stdo
cmd.Stderr = &stde
err = cmd.Run()
stdout = string(stdo.Bytes())
stderr = string(stde.Bytes())
return
}
// RunInDirectory runs the given command in the given directory
func (sh *ShellHelper) RunInDirectory(dir string, command string, vars ...string) (stdout, stderr string, err error) {
cmd := exec.Command(command, vars...)
cmd.Dir = dir
cmd.Env = append(os.Environ(), "GO111MODULE=on")
var stdo, stde bytes.Buffer var stdo, stde bytes.Buffer
cmd.Stdout = &stdo cmd.Stdout = &stdo
cmd.Stderr = &stde cmd.Stderr = &stde

View File

@@ -81,24 +81,21 @@ func (s *SystemHelper) BackupConfig() (string, error) {
func (s *SystemHelper) setup() error { func (s *SystemHelper) setup() error {
systemConfig := make(map[string]string)
// Try to load current values - ignore errors // Try to load current values - ignore errors
config, _ := s.LoadConfig() config, err := s.LoadConfig()
defaultName := ""
defaultEmail := ""
if config != nil {
defaultName = config.Name
defaultEmail = config.Email
}
if config.Name != "" { systemConfig := make(map[string]string)
systemConfig["name"] = PromptRequired("What is your name", config.Name) systemConfig["name"] = PromptRequired("What is your name", defaultName)
} else { systemConfig["email"] = PromptRequired("What is your email address", defaultEmail)
systemConfig["name"] = PromptRequired("What is your name")
}
if config.Email != "" {
systemConfig["email"] = PromptRequired("What is your email address", config.Email)
} else {
systemConfig["email"] = PromptRequired("What is your email address")
}
// Create the directory // Create the directory
err := s.fs.MkDirs(s.wailsSystemDir) err = s.fs.MkDirs(s.wailsSystemDir)
if err != nil { if err != nil {
return err return err
} }
@@ -245,7 +242,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
bin := programHelper.FindProgram(program.Name) bin := programHelper.FindProgram(program.Name)
if bin == nil { if bin == nil {
errors = true errors = true
logger.Error("Program '%s' not found. %s", program.Name, program.Help) logger.Red("Program '%s' not found. %s", program.Name, program.Help)
} else { } else {
logger.Green("Program '%s' found: %s", program.Name, bin.Path) logger.Green("Program '%s' found: %s", program.Name, bin.Path)
} }
@@ -268,30 +265,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
} }
if !installed { if !installed {
errors = true errors = true
logger.Error("Library '%s' not found. %s", library.Name, library.Help) logger.Red("Library '%s' not found. %s", library.Name, library.Help)
} else {
logger.Green("Library '%s' installed.", library.Name)
}
case Arch:
installed, err := PacmanInstalled(library.Name)
if err != nil {
return false, err
}
if !installed {
errors = true
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
} else {
logger.Green("Library '%s' installed.", library.Name)
}
case RedHat:
installed, err := RpmInstalled(library.Name)
if err != nil {
return false, err
}
if !installed {
errors = true
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
} else { } else {
logger.Green("Library '%s' installed.", library.Name) logger.Green("Library '%s' installed.", library.Name)
} }

View File

@@ -3,95 +3,112 @@ package cmd
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"log" "fmt"
"io/ioutil"
"os"
"path"
"path/filepath" "path/filepath"
"regexp" "runtime"
"strings" "strings"
"text/template" "text/template"
mewn "github.com/leaanthony/mewn"
mewnlib "github.com/leaanthony/mewn/lib"
"github.com/leaanthony/slicer"
) )
// TemplateMetadata holds all the metadata for a Wails template const templateSuffix = ".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"`
}
// TemplateDetails holds information about a specific template // TemplateHelper helps with creating projects
type TemplateDetails struct {
BasePath string
Path string
Metadata *TemplateMetadata
}
// TemplateList is a list of available templates
type TemplateList struct {
details map[string]*TemplateDetails
}
// NewTemplateList creates a new TemplateList object
func NewTemplateList(filenames *mewnlib.FileGroup) *TemplateList {
// Iterate each template and store information
result := &TemplateList{details: make(map[string]*TemplateDetails)}
entries := slicer.String()
entries.AddSlice(filenames.Entries())
// 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 {
log.Fatalf("corrupt metadata for template: %s", filename)
}
path := strings.Split(filename, "/")[0]
thisTemplate := &TemplateDetails{Path: path, Metadata: &metadata}
result.details[filename] = thisTemplate
})
return result
}
// Template holds details about a Wails template
type Template struct {
Name string
Path string
Description string
}
// TemplateHelper is a utility object to help with processing templates
type TemplateHelper struct { type TemplateHelper struct {
TemplateList *TemplateList system *SystemHelper
Files *mewnlib.FileGroup fs *FSHelper
templateDir string
// templates map[string]string
templateSuffix string
metadataFilename string
}
// Template defines a single template
type Template struct {
Name string
Dir string
Metadata map[string]interface{}
} }
// NewTemplateHelper creates a new template helper // NewTemplateHelper creates a new template helper
func NewTemplateHelper() *TemplateHelper { func NewTemplateHelper() *TemplateHelper {
files := mewn.Group("./templates") result := TemplateHelper{
system: NewSystemHelper(),
return &TemplateHelper{ fs: NewFSHelper(),
TemplateList: NewTemplateList(files), templateSuffix: ".template",
Files: files, 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
}
// GetTemplateNames returns a map of all available templates
func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) {
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
if err != nil {
return nil, err
}
return templateDirs, nil
}
// GetTemplateDetails returns a map of Template structs containing details
// of the found templates
func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) {
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
if err != nil {
return nil, err
}
result := make(map[string]*Template)
for name, dir := range templateDirs {
result[name] = &Template{
Dir: dir,
}
metadata, err := t.LoadMetadata(dir)
if err != nil {
return nil, err
}
result[name].Metadata = metadata
if metadata["name"] != nil {
result[name].Name = metadata["name"].(string)
} else {
// Ignore bad templates?
result[name] = nil
}
}
return result, nil
}
// LoadMetadata loads the template's 'metadata.json' file
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
}
// TemplateExists returns true if the given template name exists
func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) {
templates, err := t.GetTemplateNames()
if err != nil {
return false, err
}
_, exists := templates[templateName]
return exists, nil
} }
// InstallTemplate installs the template given in the project options to the // InstallTemplate installs the template given in the project options to the
@@ -99,57 +116,162 @@ func NewTemplateHelper() *TemplateHelper {
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error { func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
// Get template files // Get template files
templatePath := projectOptions.selectedTemplate.Path template, err := t.getTemplateFiles(projectOptions.Template)
if err != nil {
templateFilenames := slicer.String() return err
templateFilenames.AddSlice(projectOptions.templates.Files.Entries()) }
templateJSONFilename := filepath.Join(templatePath, "template.json")
templateFiles := templateFilenames.Filter(func(filename string) bool {
filename = filepath.FromSlash(filename)
return strings.HasPrefix(filename, templatePath) && filename != templateJSONFilename
})
var err error
templateFiles.Each(func(templateFile string) {
// Setup filenames
relativeFilename := strings.TrimPrefix(templateFile, templatePath)[1:]
targetFilename, err := filepath.Abs(filepath.Join(projectOptions.OutputDirectory, relativeFilename))
if err != nil {
return
}
filedata := projectOptions.templates.Files.Bytes(templateFile)
// 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 {
return
}
// 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
}
})
// Copy files to target
err = template.Install(projectPath, projectOptions)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
// 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
})
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)
err = fs.CopyFile(sourceFile, targetFile)
if err != nil {
return err
}
}
// 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
var tpl bytes.Buffer
err = tmpl.Execute(&tpl, projectOptions)
if err != nil {
fmt.Println("ERROR!!! " + err.Error())
return err
}
// 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
}
}
}
return nil
}

View File

@@ -0,0 +1 @@
2b79f883dc856221fc3265755d610e40

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<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>my-vue-app-01</title>
</head>
<body>
<noscript>
<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 -->
</body>
</html>

View File

@@ -2,7 +2,6 @@ import Vue from "vue";
import App from "./App.vue"; import App from "./App.vue";
Vue.config.productionTip = false; Vue.config.productionTip = false;
Vue.config.devtools = true;
import Bridge from "./wailsbridge"; import Bridge from "./wailsbridge";

View File

@@ -11,15 +11,12 @@ func basic() string {
func main() { func main() {
js := mewn.String("./frontend/dist/app.js")
css := mewn.String("./frontend/dist/app.css")
app := wails.CreateApp(&wails.AppConfig{ app := wails.CreateApp(&wails.AppConfig{
Width: 1024, Width: 1024,
Height: 768, Height: 768,
Title: "{{.Name}}", Title: "{{.Name}}",
JS: js, JS: mewn.String("./frontend/dist/app.js"),
CSS: css, CSS: mewn.String("./frontend/dist/app.css"),
Colour: "#131313", Colour: "#131313",
}) })
app.Bind(basic) app.Bind(basic)

View File

@@ -1,4 +1,5 @@
package cmd package cmd
// Version - Wails version // Version - Wails version
const Version = "v0.13.2" // ...oO(There must be a better way)
const Version = "v0.9.5"

View File

@@ -18,13 +18,11 @@ func init() {
setupCommand.Action(func() error { setupCommand.Action(func() error {
logger.PrintBanner() logger.PrintBanner();
var err error
system := cmd.NewSystemHelper() system := cmd.NewSystemHelper()
err = system.Initialise() err := system.Initialise()
if err == nil { if err != nil {
return err return err
} }
@@ -41,15 +39,13 @@ Create your first project by running 'wails init'.`
// Check we have a cgo capable environment // Check we have a cgo capable environment
logger.Yellow("Checking for prerequisites...") logger.Yellow("Checking for prerequisites...")
var requiredProgramErrors bool errors, err := checkRequiredPrograms()
requiredProgramErrors, err = checkRequiredPrograms()
if err != nil { if err != nil {
return err return err
} }
// Linux has library deps // Linux has library deps
var libraryErrors bool errors, err = checkLibraries()
libraryErrors, err = checkLibraries()
if err != nil { if err != nil {
return err return err
} }
@@ -62,8 +58,6 @@ Create your first project by running 'wails init'.`
logger.White("") logger.White("")
// Check for errors
var errors = libraryErrors || requiredProgramErrors
if !errors { if !errors {
logger.Yellow(successMessage) logger.Yellow(successMessage)
} }

20
cmd/wails/10_version.go Normal file
View File

@@ -0,0 +1,20 @@
package main
import (
"fmt"
"github.com/wailsapp/wails/cmd"
)
func init() {
commandDescription := `Outputs the current version of the wails cli tool.`
versionCommand := app.Command("version", "Print Wails cli version").
LongDescription(commandDescription)
versionCommand.Action(func() error {
fmt.Println(cmd.Version)
return nil
})
}

49
cmd/wails/12_report.go Normal file
View File

@@ -0,0 +1,49 @@
package main
import (
"fmt"
"os"
"runtime"
"github.com/wailsapp/wails/cmd"
)
func init() {
commandDescription := `Generates a report to help resolve issues.`
versionCommand := app.Command("report", "Generates Report").
LongDescription(commandDescription)
versionCommand.Action(func() error {
modules := os.Getenv("GO111MODULE")
if modules == "" {
modules = "(Not set)"
}
fmt.Println("Please copy and paste this report when creating issues")
fmt.Println("------------------------------------------------------")
fmt.Printf("Wails Version: %s\n", cmd.Version)
fmt.Println("Go:")
fmt.Printf(" GOOS : %s\n", runtime.GOOS)
fmt.Printf(" GOARCH : %s\n", runtime.GOARCH)
fmt.Printf(" Version : %s\n", runtime.Version())
fmt.Println("Environment:")
fmt.Printf(" Shell : %s\n", getShell())
fmt.Printf(" GO111MODULE: %s\n", modules)
fmt.Println("------------------------------------------------------")
return nil
})
}
func getShell() string {
switch runtime.GOOS {
case "windows":
return os.Getenv("COMSPEC")
case "linux":
return os.Getenv("SHELL")
case "darwin":
return os.Getenv("SHELL")
default:
return ""
}
}

View File

@@ -17,7 +17,7 @@ Any flags that are required and not given will be prompted for.`
LongDescription(commandDescription). LongDescription(commandDescription).
BoolFlag("f", "Use defaults", &projectOptions.UseDefaults). BoolFlag("f", "Use defaults", &projectOptions.UseDefaults).
StringFlag("dir", "Directory to create project in", &projectOptions.OutputDirectory). 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("name", "Project name", &projectOptions.Name).
StringFlag("description", "Project description", &projectOptions.Description). StringFlag("description", "Project description", &projectOptions.Description).
StringFlag("output", "Output binary name", &projectOptions.BinaryName) StringFlag("output", "Output binary name", &projectOptions.BinaryName)

View File

@@ -26,9 +26,6 @@ func init() {
initCmd.Action(func() error { initCmd.Action(func() error {
message := "Building Application" message := "Building Application"
if packageApp {
message = "Packaging Application"
}
if forceRebuild { if forceRebuild {
message += " (force rebuild)" message += " (force rebuild)"
} }
@@ -43,7 +40,7 @@ func init() {
fs := cmd.NewFSHelper() fs := cmd.NewFSHelper()
err := projectOptions.LoadConfig(fs.Cwd()) err := projectOptions.LoadConfig(fs.Cwd())
if err != nil { if err != nil {
return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory") return err
} }
// Validate config // Validate config

View File

@@ -14,7 +14,7 @@ func init() {
buildSpinner.SetSpinSpeed(50) buildSpinner.SetSpinSpeed(50)
commandDescription := `This command builds then serves your application in bridge mode. Useful for developing your app in a browser.` 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"). initCmd := app.Command("serve", "Run your Wails project in bridge mode.").
LongDescription(commandDescription). LongDescription(commandDescription).
BoolFlag("f", "Force rebuild of application components", &forceRebuild) BoolFlag("f", "Force rebuild of application components", &forceRebuild)
@@ -24,28 +24,19 @@ func init() {
logger.PrintSmallBanner(message) logger.PrintSmallBanner(message)
fmt.Println() fmt.Println()
// Check Mewn is installed
err := cmd.CheckMewn()
if err != nil {
return err
}
// Project options // Project options
projectOptions := &cmd.ProjectOptions{} projectOptions := &cmd.ProjectOptions{}
// Check we are in project directory // Check we are in project directory
// Check project.json loads correctly // Check project.json loads correctly
fs := cmd.NewFSHelper() fs := cmd.NewFSHelper()
err = projectOptions.LoadConfig(fs.Cwd()) err := projectOptions.LoadConfig(fs.Cwd())
if err != nil { if err != nil {
return err return err
} }
// Save project directory // Check Mewn is installed
projectDir := fs.Cwd() err = cmd.CheckMewn()
// Install the bridge library
err = cmd.InstallBridge("serve", projectDir, projectOptions)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,28 +1,25 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"log" "io/ioutil"
"net/http"
"strings"
"github.com/leaanthony/spinner" "github.com/leaanthony/spinner"
"github.com/mitchellh/go-homedir"
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
) )
func init() { func init() {
var prereleaseRequired bool
var specificVersion string
// var forceRebuild = false // var forceRebuild = false
checkSpinner := spinner.NewSpinner() checkSpinner := spinner.NewSpinner()
checkSpinner.SetSpinSpeed(50) checkSpinner.SetSpinSpeed(50)
commandDescription := `This command allows you to update your version of Wails.` commandDescription := `This command checks if there are updates to Wails.`
updateCmd := app.Command("update", "Update to newer [pre]releases or specific versions"). updateCmd := app.Command("update", "Check for Updates.").
LongDescription(commandDescription). LongDescription(commandDescription)
BoolFlag("pre", "Update to latest Prerelease", &prereleaseRequired).
StringFlag("version", "Install a specific version (Overrides other flags)", &specificVersion)
updateCmd.Action(func() error { updateCmd.Action(func() error {
@@ -32,133 +29,53 @@ func init() {
// Get versions // Get versions
checkSpinner.Start(message) checkSpinner.Start(message)
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/tags")
github := cmd.NewGitHubHelper()
var desiredVersion *cmd.SemanticVersion
var err error
var valid bool
if len(specificVersion) > 0 {
// Check if this is a valid version
valid, err = github.IsValidTag(specificVersion)
if err == nil {
if !valid {
err = fmt.Errorf("version '%s' is invalid", specificVersion)
} else {
desiredVersion, err = cmd.NewSemanticVersion(specificVersion)
}
}
} else {
if prereleaseRequired {
desiredVersion, err = github.GetLatestPreRelease()
} else {
desiredVersion, err = github.GetLatestStableRelease()
}
}
if err != nil { if err != nil {
checkSpinner.Error(err.Error()) checkSpinner.Error(err.Error())
return err return err
} }
checkSpinner.Success() checkSpinner.Success()
fmt.Println() body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(" Current Version : " + cmd.Version) checkSpinner.Error(err.Error())
return err
if len(specificVersion) > 0 {
fmt.Printf(" Desired Version : v%s\n", desiredVersion)
} else {
if prereleaseRequired {
fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion)
} else {
fmt.Printf(" Latest Release : v%s\n", desiredVersion)
}
} }
return updateToVersion(desiredVersion, len(specificVersion) > 0) data := []map[string]interface{}{}
}) err = json.Unmarshal(body, &data)
}
func updateToVersion(targetVersion *cmd.SemanticVersion, force bool) error {
var targetVersionString = "v" + targetVersion.String()
// Early exit
if targetVersionString == cmd.Version {
logger.Green("Looks like you're up to date!")
return nil
}
var desiredVersion string
if !force {
compareVersion := cmd.Version
currentVersion, err := cmd.NewSemanticVersion(compareVersion)
if err != nil { if err != nil {
return err return err
} }
var success bool latestVersion := data[0]["name"].(string)
fmt.Println()
// Release -> Pre-Release = Massage current version to prerelease format fmt.Println("Current Version: " + cmd.Version)
if targetVersion.IsPreRelease() && currentVersion.IsRelease() { fmt.Println(" Latest Version: " + latestVersion)
currentVersion, err = cmd.NewSemanticVersion(compareVersion) if latestVersion != cmd.Version {
updateSpinner := spinner.NewSpinner()
updateSpinner.SetSpinSpeed(40)
updateSpinner.Start("Updating to : " + latestVersion)
err = cmd.NewProgramHelper().RunCommandArray([]string{"go", "get", "-u", "-a", "github.com/wailsapp/wails/cmd/wails"})
if err != nil { if err != nil {
updateSpinner.Error(err.Error())
return err return err
} }
success, _ = targetVersion.IsGreaterThan(currentVersion) version, _, err := cmd.NewProgramHelper().GetOutputFromCommand("wails version")
} version = strings.TrimSpace(version)
// Pre-Release -> Release = Massage target version to prerelease format
if targetVersion.IsRelease() && currentVersion.IsPreRelease() {
// We are ok with greater than or equal
mainversion := currentVersion.MainVersion()
targetVersion, err = cmd.NewSemanticVersion(targetVersion.String())
if err != nil { if err != nil {
updateSpinner.Error(err.Error())
return err return err
} }
success, _ = targetVersion.IsGreaterThanOrEqual(mainversion) if version != latestVersion {
updateSpinner.Error()
logger.Yellow("Weird! Wails was supposed to update to %s but seems to be at %s instead.", latestVersion, version)
} else {
updateSpinner.Success()
logger.Green("Success! Wails updated to " + version)
}
} else {
logger.Yellow("Looks like you're up to date!")
} }
return nil
// Release -> Release = Standard check })
if (targetVersion.IsRelease() && currentVersion.IsRelease()) ||
(targetVersion.IsPreRelease() && currentVersion.IsPreRelease()) {
success, _ = targetVersion.IsGreaterThan(currentVersion)
}
// Compare
if !success {
logger.Red("The requested version is lower than the current version.")
logger.Red("If this is what you really want to do, use `wails update -version %s`", targetVersionString)
return nil
}
desiredVersion = "v" + targetVersion.String()
} else {
desiredVersion = "v" + targetVersion.String()
}
fmt.Println()
updateSpinner := spinner.NewSpinner()
updateSpinner.SetSpinSpeed(40)
updateSpinner.Start("Installing Wails " + desiredVersion)
// Run command in non module directory
homeDir, err := homedir.Dir()
if err != nil {
log.Fatal("Cannot find home directory! Please file a bug report!")
}
err = cmd.NewProgramHelper().RunCommandArray([]string{"go", "get", "github.com/wailsapp/wails/cmd/wails@" + desiredVersion}, homeDir)
if err != nil {
updateSpinner.Error(err.Error())
return err
}
updateSpinner.Success()
fmt.Println()
logger.Green("Wails updated to " + desiredVersion)
return nil
} }

View File

@@ -1,74 +0,0 @@
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

@@ -1,19 +0,0 @@
// +build windows
package cmd
import (
"os"
"golang.org/x/sys/windows"
)
// Credit: https://stackoverflow.com/a/52579002
func init() {
stdout := windows.Handle(os.Stdout.Fd())
var originalMode uint32
_ = windows.GetConsoleMode(stdout, &originalMode)
_ = windows.SetConsoleMode(stdout, originalMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
}

View File

@@ -87,7 +87,7 @@ func (e *eventManager) start(renderer Renderer) {
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
// Run main loop in separate goroutine // Run main loop in seperate goroutine
go func() { go func() {
wg.Done() wg.Done()
e.log.Info("Listening") e.log.Info("Listening")
@@ -126,7 +126,7 @@ func (e *eventManager) start(renderer Renderer) {
} }
} }
// Remove expired listeners in place // Remove expired listners in place
if len(listenersToRemove) > 0 { if len(listenersToRemove) > 0 {
listeners := e.listeners[event.Name][:0] listeners := e.listeners[event.Name][:0]
for _, listener := range listeners { for _, listener := range listeners {

18
go.mod
View File

@@ -1,7 +1,6 @@
module github.com/wailsapp/wails module github.com/wailsapp/wails
require ( require (
github.com/Masterminds/semver v1.4.2 // indirect
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect
@@ -9,20 +8,17 @@ require (
github.com/go-playground/colors v1.2.0 github.com/go-playground/colors v1.2.0
github.com/gorilla/websocket v1.4.0 github.com/gorilla/websocket v1.4.0
github.com/jackmordaunt/icns v1.0.0 github.com/jackmordaunt/icns v1.0.0
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/leaanthony/mewn v0.9.1
github.com/leaanthony/mewn v0.10.5 github.com/leaanthony/slicer v1.0.0
github.com/leaanthony/slicer v1.3.1
github.com/leaanthony/spinner v0.5.0 github.com/leaanthony/spinner v0.5.0
github.com/masterminds/semver v1.4.2
github.com/mattn/go-colorable v0.1.1 // indirect github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect 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/pkg/errors v0.8.1 // indirect
github.com/sirupsen/logrus v1.4.1 github.com/sirupsen/logrus v1.3.0
github.com/stretchr/testify v1.3.0 // indirect github.com/stretchr/testify v1.3.0 // indirect
github.com/wailsapp/webview v0.2.7 github.com/wailsapp/webview v0.2.5
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 // indirect golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f // indirect
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd // indirect
golang.org/x/sys v0.0.0-20190222171317-cd391775e71e // indirect
) )

43
go.sum
View File

@@ -1,5 +1,3 @@
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -21,65 +19,58 @@ github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmA
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= 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 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/leaanthony/mewn v0.9.1 h1:+qmAnR5nETU/00o5wvYJ7w9Y36R9uIBRB9I15E9Ru8A=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/leaanthony/mewn v0.9.1/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
github.com/leaanthony/mewn v0.10.5 h1:QKYVj8tI94alvVFZer7wPy66IcNpyNPITIkdhXbThX4= github.com/leaanthony/slicer v1.0.0 h1:BV2CySexcZ20qyHp5qBTxQhsazR6e8MBTF1EHmGu1xw=
github.com/leaanthony/mewn v0.10.5/go.mod h1:i3ygCWW96qVQlGa8sjWnTM0IKAijoFvTwATDIZgK4k0= github.com/leaanthony/slicer v1.0.0/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
github.com/leaanthony/slicer v1.3.1 h1:n2iIV2sxvL/3bpnmVY0vBjXf3yYFWcB6CYLVMrzJxRw=
github.com/leaanthony/slicer v1.3.1/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
github.com/leaanthony/spinner v0.5.0 h1:HQykt/iTy7fmINEREtRbWrt+8j4MxC8dtvWBxEWM9oA= 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/spinner v0.5.0/go.mod h1:8TSFz9SL1AUC4XSbEFYE6SfN5Mlus51qYluVGrie9ww=
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8= 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/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 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE= github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
github.com/masterminds/semver v1.4.2 h1:BgrAYDjlAebjtOwS7C/1QZoh5WgyXx4b59ydc+Ph8xI=
github.com/masterminds/semver v1.4.2/go.mod h1:s7KNT9fnd7edGzwwP7RBX4H0v/CYd5qdOLfkL1V75yg=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 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 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 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 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= 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/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 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/ribice/glice v0.0.0-20181011133736-685f13fa9b12/go.mod h1:A+ednilkKNW0CJGLsrLkq0D49M4EhlCi8gvnkwoZFn0= github.com/ribice/glice v0.0.0-20181011133736-685f13fa9b12/go.mod h1:A+ednilkKNW0CJGLsrLkq0D49M4EhlCi8gvnkwoZFn0=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 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.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/wailsapp/webview v0.2.7 h1:fN5L5H9Oivg9IJPk7uaXQnjqB68Fny11ZWkIaTIZHmk= github.com/wailsapp/webview v0.2.5 h1:/VacryPEUeMBb2VHHOjpoIze6ki8tW3qYX04MnI0b7o=
github.com/wailsapp/webview v0.2.7/go.mod h1:XO9HJbKWokDxUYTWQEBCYg95n/To1v7PxvanDNVf8hY= 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= github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb/go.mod h1:a1CV8KR4Dd1eP2g+mEijGOp+HKczwdKHWyx0aPHKvo4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f h1:qWFY9ZxP3tfI37wYIs/MnIAqK0vlXp1xnYEa5HxFSSY=
golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/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 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-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR170vGqDhJDOmpVd4Hjak= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU=
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30= 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-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug= golang.org/x/sys v0.0.0-20190222171317-cd391775e71e h1:oF7qaQxUH6KzFdKN4ww7NpPdo53SZi4UlcksLrb2y/o=
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190222171317-cd391775e71e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@@ -1,8 +1,8 @@
package wails package wails
import ( import (
"encoding/hex"
"encoding/json" "encoding/json"
"strings"
) )
// ipcResponse contains the response data from an RPC call // ipcResponse contains the response data from an RPC call
@@ -37,9 +37,7 @@ func newSuccessResponse(callbackID string, data interface{}) *ipcResponse {
// Serialise formats the response to a string // Serialise formats the response to a string
func (i *ipcResponse) Serialise() (string, error) { func (i *ipcResponse) Serialise() (string, error) {
b, err := json.Marshal(i) b, err := json.Marshal(i)
if err != nil { result := strings.Replace(string(b), "\\", "\\\\", -1)
return "", err result = strings.Replace(result, "'", "\\'", -1)
}
result := hex.EncodeToString(b)
return result, err return result, err
} }

View File

@@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"sync"
"github.com/dchest/htmlmin" "github.com/dchest/htmlmin"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
@@ -46,9 +45,6 @@ type Headless struct {
initialisationJS []string initialisationJS []string
server *http.Server server *http.Server
theConnection *websocket.Conn theConnection *websocket.Conn
// Mutex for writing to the socket
lock sync.Mutex
} }
// Initialise the Headless Renderer // Initialise the Headless Renderer
@@ -57,7 +53,7 @@ func (h *Headless) Initialise(appConfig *AppConfig, ipcManager *ipcManager, even
h.appConfig = appConfig h.appConfig = appConfig
h.eventManager = eventManager h.eventManager = eventManager
ipcManager.bindRenderer(h) ipcManager.bindRenderer(h)
h.log = newCustomLogger("Bridge") h.log = newCustomLogger("Headless")
return nil return nil
} }
@@ -107,10 +103,6 @@ func (h *Headless) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
} }
func (h *Headless) sendMessage(conn *websocket.Conn, msg string) { func (h *Headless) sendMessage(conn *websocket.Conn, msg string) {
h.lock.Lock()
defer h.lock.Unlock()
if err := conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil { if err := conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
h.log.Error(err.Error()) h.log.Error(err.Error())
} }
@@ -153,8 +145,8 @@ func (h *Headless) Run() error {
h.server = &http.Server{Addr: ":34115"} h.server = &http.Server{Addr: ":34115"}
http.HandleFunc("/bridge", h.wsBridgeHandler) http.HandleFunc("/bridge", h.wsBridgeHandler)
h.log.Info("Bridge mode started.") h.log.Info("Headless mode started.")
h.log.Info("The frontend will connect automatically.") h.log.Info("The Wails bridge will connect automatically.")
err := h.server.ListenAndServe() err := h.server.ListenAndServe()
if err != nil { if err != nil {
@@ -172,21 +164,21 @@ func (h *Headless) NewBinding(methodName string) error {
// SelectFile is unsupported for Headless but required // SelectFile is unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) SelectFile() string { func (h *Headless) SelectFile() string {
h.log.Warn("SelectFile() unsupported in bridge mode") h.log.Error("SelectFile() unsupported in headless mode")
return "" return ""
} }
// SelectDirectory is unsupported for Headless but required // SelectDirectory is unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) SelectDirectory() string { func (h *Headless) SelectDirectory() string {
h.log.Warn("SelectDirectory() unsupported in bridge mode") h.log.Error("SelectDirectory() unsupported in headless mode")
return "" return ""
} }
// SelectSaveFile is unsupported for Headless but required // SelectSaveFile is unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) SelectSaveFile() string { func (h *Headless) SelectSaveFile() string {
h.log.Warn("SelectSaveFile() unsupported in bridge mode") h.log.Error("SelectSaveFile() unsupported in headless mode")
return "" return ""
} }
@@ -245,23 +237,23 @@ func (h *Headless) SetColour(colour string) error {
// Fullscreen is unsupported for Headless but required // Fullscreen is unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) Fullscreen() { func (h *Headless) Fullscreen() {
h.log.Warn("Fullscreen() unsupported in bridge mode") h.log.Warn("Fullscreen() unsupported in headless mode")
} }
// UnFullscreen is unsupported for Headless but required // UnFullscreen is unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) UnFullscreen() { func (h *Headless) UnFullscreen() {
h.log.Warn("UnFullscreen() unsupported in bridge mode") h.log.Warn("UnFullscreen() unsupported in headless mode")
} }
// SetTitle is currently unsupported for Headless but required // SetTitle is currently unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) SetTitle(title string) { func (h *Headless) SetTitle(title string) {
h.log.WarnFields("SetTitle() unsupported in bridge mode", Fields{"title": title}) h.log.WarnFields("SetTitle() unsupported in headless mode", Fields{"title": title})
} }
// Close is unsupported for Headless but required // Close is unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) Close() { func (h *Headless) Close() {
h.log.Warn("Close() unsupported in bridge mode") h.log.Warn("Close() unsupported in headless mode")
} }

View File

@@ -122,7 +122,7 @@ func (w *webViewRenderer) evalJSSync(js string) error {
go func() { go func() {
exit := false exit := false
// We are done when we receive the Callback ID // We are done when we recieve the Callback ID
w.log.Debug("SyncJS: sending with ID = " + ID) w.log.Debug("SyncJS: sending with ID = " + ID)
w.eventManager.On(ID, func(...interface{}) { w.eventManager.On(ID, func(...interface{}) {
w.log.Debug("SyncJS: Got callback ID = " + ID) w.log.Debug("SyncJS: Got callback ID = " + ID)

View File

@@ -2,19 +2,17 @@ package wails
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method // Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
type Runtime struct { type Runtime struct {
Events *RuntimeEvents Events *RuntimeEvents
Log *RuntimeLog Log *RuntimeLog
Dialog *RuntimeDialog Dialog *RuntimeDialog
Window *RuntimeWindow Window *RuntimeWindow
FileSystem *RuntimeFileSystem
} }
func newRuntime(eventManager *eventManager, renderer Renderer) *Runtime { func newRuntime(eventManager *eventManager, renderer Renderer) *Runtime {
return &Runtime{ return &Runtime{
Events: newRuntimeEvents(eventManager), Events: newRuntimeEvents(eventManager),
Log: newRuntimeLog(), Log: newRuntimeLog(),
Dialog: newRuntimeDialog(renderer), Dialog: newRuntimeDialog(renderer),
Window: newRuntimeWindow(renderer), Window: newRuntimeWindow(renderer),
FileSystem: newRuntimeFileSystem(),
} }
} }

View File

@@ -18,5 +18,5 @@ func (r *RuntimeEvents) On(eventName string, callback func(optionalData ...inter
// Emit pass through // Emit pass through
func (r *RuntimeEvents) Emit(eventName string, optionalData ...interface{}) { func (r *RuntimeEvents) Emit(eventName string, optionalData ...interface{}) {
r.eventManager.Emit(eventName, optionalData...) r.eventManager.Emit(eventName, optionalData)
} }

View File

@@ -1,16 +0,0 @@
package wails
import homedir "github.com/mitchellh/go-homedir"
// RuntimeFileSystem exposes file system utilities to the runtime
type RuntimeFileSystem struct {
}
func newRuntimeFileSystem() *RuntimeFileSystem {
return &RuntimeFileSystem{}
}
// HomeDir returns the user's home directory
func (r *RuntimeFileSystem) HomeDir() (string, error) {
return homedir.Dir()
}

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env bash
if [ "$#" != "1" ]; then
echo "Tag required"
exit 1
fi
TAG=${1}
cat << EOF > cmd/version.go
package cmd
// Version - Wails version
const Version = "${TAG}"
EOF
git add cmd/version.go
git commit cmd/version.go -m "Bump to ${TAG}"
git tag ${TAG}

File diff suppressed because one or more lines are too long

View File

@@ -29,7 +29,7 @@ window.wailsbridge = {
'<div class="wails-reconnect-overlay"><div class="wails-reconnect-overlay-content"><div class="wails-reconnect-overlay-title">Wails Bridge</div><br><div class="wails-reconnect-overlay-loadingspinner"></div><br><div id="wails-reconnect-overlay-message">Waiting for backend</div></div></div>', '<div class="wails-reconnect-overlay"><div class="wails-reconnect-overlay-content"><div class="wails-reconnect-overlay-title">Wails Bridge</div><br><div class="wails-reconnect-overlay-loadingspinner"></div><br><div id="wails-reconnect-overlay-message">Waiting for backend</div></div></div>',
overlayCSS: overlayCSS:
".wails-reconnect-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.6);font-family:sans-serif;display:none;z-index:999999}.wails-reconnect-overlay-content{padding:20px 30px;text-align:center;width:20em;position:relative;height:14em;border-radius:1em;margin:5% auto 0;background-color:#fff;box-shadow:1px 1px 20px 3px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAqFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAEBAQAAAAAAAAAAAAEBAQEBAQDAwMBAQEAAAABAQEAAAAAAAAAAAABAQEAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWKCj6oAAAAN3RSTlMALiIqDhkGBAswJjP0GxP6NR4W9/ztjRDMhWU50G9g5eHXvbZ9XEI9xZTcqZl2aldKo55QwoCvZUgzhAAAAs9JREFUSMeNleeWqjAUhU0BCaH3Itiw9zKT93+zG02QK1hm/5HF+jzZJ6fQe6cyXE+jg9X7o9wxuylIIf4Tv2V3+bOrEXnf8dwQ/KQIGDN2/S+4OmVCVXL/ScBnfibxURqIByP/hONE8r8T+bDMlQ98KSl7Y8hzjpS8v1qtDh8u5f8KQpGpfnPPhqG8JeogN37Hq9eaN2xRhIwAaGnvws8F1ShxqK5ob2twYi1FAMD4rXsYtnC/JEiRbl4cUrCWhnMCLRFemXezXbb59QK4WASOsm6n2W1+4CBT2JmtzQ6fsrbGubR/NFbd2g5Y179+5w/GEHaKsHjYCet7CgrXU3txarNC7YxOVJtIj4/ERzMdZfzc31hp+8cD6eGILgarZY9uZ12hAs03vfBD9C171gS5Omz7OcvxALQIn4u8RRBBBcsi9WW2woO9ipLgfzpYlggg3ZRdROUC8KT7QLqq3W9KB5BbdFVg4929kdwp6+qaZnMCCNBdj+NyN1W885Ry/AL3D4AQbsVV4noCiM/C83kyYq80XlDAYQtralOiDzoRAHlotWl8q2tjvYlOgcg1A8jEApZa+C06TBdAz2Qv0wu11I/zZOyJQ6EwGez2P2b8PIQr1hwwnAZsAxwA4UAYOyXUxM/xp6tHAn4GUmPGM9R28oVxgC0e/zQJJI6DyhyZ1r7uzRQhpcW7x7vTaWSzKSG6aep77kroTEl3U81uSVaUTtgEINfC8epx+Q4F9SpplHG84Ek6m4RAq9/TLkOBrxyeuddZhHvGIp1XXfFy3Z3vtwNblKGiDn+J+92vwwABHghj7HnzlS1H5kB49AZvdGCFgiBPq69qfXPr3y++yilF0ON4R8eR7spAsLpZ95NqAW5tab1c4vkZm6aleajchMwYTdILQQTwE2OV411ZM9WztDjPql12caBi6gDpUKmDd4U1XNdQxZ4LIXQ5/Tr4P7I9tYcFrDK3AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:center}.wails-reconnect-overlay-title{font-size:2em}.wails-reconnect-overlay-message{font-size:1.3em}.wails-reconnect-overlay-loadingspinner{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#3E67EC #eee #eee;border-radius:50%;animation:loadingspin 1s linear infinite;margin:auto;padding:2.5em}@keyframes loadingspin{100%{transform:rotate(360deg)}}", ".wails-reconnect-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.6);font-family:sans-serif;display:none;z-index:999999}.wails-reconnect-overlay-content{padding:20px 30px;text-align:center;width:20em;position:relative;height:14em;border-radius:1em;margin:5% auto 0;background-color:#fff;box-shadow:1px 1px 20px 3px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAqFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAEBAQAAAAAAAAAAAAEBAQEBAQDAwMBAQEAAAABAQEAAAAAAAAAAAABAQEAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWKCj6oAAAAN3RSTlMALiIqDhkGBAswJjP0GxP6NR4W9/ztjRDMhWU50G9g5eHXvbZ9XEI9xZTcqZl2aldKo55QwoCvZUgzhAAAAs9JREFUSMeNleeWqjAUhU0BCaH3Itiw9zKT93+zG02QK1hm/5HF+jzZJ6fQe6cyXE+jg9X7o9wxuylIIf4Tv2V3+bOrEXnf8dwQ/KQIGDN2/S+4OmVCVXL/ScBnfibxURqIByP/hONE8r8T+bDMlQ98KSl7Y8hzjpS8v1qtDh8u5f8KQpGpfnPPhqG8JeogN37Hq9eaN2xRhIwAaGnvws8F1ShxqK5ob2twYi1FAMD4rXsYtnC/JEiRbl4cUrCWhnMCLRFemXezXbb59QK4WASOsm6n2W1+4CBT2JmtzQ6fsrbGubR/NFbd2g5Y179+5w/GEHaKsHjYCet7CgrXU3txarNC7YxOVJtIj4/ERzMdZfzc31hp+8cD6eGILgarZY9uZ12hAs03vfBD9C171gS5Omz7OcvxALQIn4u8RRBBBcsi9WW2woO9ipLgfzpYlggg3ZRdROUC8KT7QLqq3W9KB5BbdFVg4929kdwp6+qaZnMCCNBdj+NyN1W885Ry/AL3D4AQbsVV4noCiM/C83kyYq80XlDAYQtralOiDzoRAHlotWl8q2tjvYlOgcg1A8jEApZa+C06TBdAz2Qv0wu11I/zZOyJQ6EwGez2P2b8PIQr1hwwnAZsAxwA4UAYOyXUxM/xp6tHAn4GUmPGM9R28oVxgC0e/zQJJI6DyhyZ1r7uzRQhpcW7x7vTaWSzKSG6aep77kroTEl3U81uSVaUTtgEINfC8epx+Q4F9SpplHG84Ek6m4RAq9/TLkOBrxyeuddZhHvGIp1XXfFy3Z3vtwNblKGiDn+J+92vwwABHghj7HnzlS1H5kB49AZvdGCFgiBPq69qfXPr3y++yilF0ON4R8eR7spAsLpZ95NqAW5tab1c4vkZm6aleajchMwYTdILQQTwE2OV411ZM9WztDjPql12caBi6gDpUKmDd4U1XNdQxZ4LIXQ5/Tr4P7I9tYcFrDK3AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:center}.wails-reconnect-overlay-title{font-size:2em}.wails-reconnect-overlay-message{font-size:1.3em}.wails-reconnect-overlay-loadingspinner{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#3E67EC #eee #eee;border-radius:50%;animation:loadingspin 1s linear infinite;margin:auto;padding:2.5em}@keyframes loadingspin{100%{transform:rotate(360deg)}}",
log: function (message) { log: function(message) {
// eslint-disable-next-line // eslint-disable-next-line
console.log( console.log(
"%c wails bridge %c " + message + " ", "%c wails bridge %c " + message + " ",
@@ -102,7 +102,7 @@ function startBridge() {
// Bridge external.invoke // Bridge external.invoke
window.external = { window.external = {
invoke: function (msg) { invoke: function(msg) {
window.wailsbridge.websocket.send(msg); window.wailsbridge.websocket.send(msg);
} }
}; };
@@ -111,7 +111,6 @@ function startBridge() {
// Removes it if second parameter is true. // Removes it if second parameter is true.
function addScript(script, remove) { function addScript(script, remove) {
var s = document.createElement("script"); var s = document.createElement("script");
s.setAttribute('type', 'text/javascript');
s.textContent = script; s.textContent = script;
document.head.appendChild(s); document.head.appendChild(s);
@@ -143,11 +142,11 @@ function startBridge() {
// Try to connect to the backend every 300ms (default value). // Try to connect to the backend every 300ms (default value).
// Change this value in the main wailsbridge object. // Change this value in the main wailsbridge object.
function connect() { function connect() {
window.wailsbridge.connectTimer = setInterval(function () { window.wailsbridge.connectTimer = setInterval(function() {
if (window.wailsbridge.websocket == null) { if (window.wailsbridge.websocket == null) {
window.wailsbridge.websocket = new WebSocket(window.wailsbridge.wsURL); window.wailsbridge.websocket = new WebSocket(window.wailsbridge.wsURL);
window.wailsbridge.websocket.onopen = handleConnect; window.wailsbridge.websocket.onopen = handleConnect;
window.wailsbridge.websocket.onerror = function (e) { window.wailsbridge.websocket.onerror = function(e) {
e.stopImmediatePropagation(); e.stopImmediatePropagation();
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
@@ -160,6 +159,7 @@ function startBridge() {
function handleMessage(message) { function handleMessage(message) {
// As a bridge we ignore js and css injections // As a bridge we ignore js and css injections
switch (message.data[0]) { switch (message.data[0]) {
// Wails library - inject! // Wails library - inject!
case "w": case "w":
@@ -167,7 +167,7 @@ function startBridge() {
// Now wails runtime is loaded, wails for the ready event // Now wails runtime is loaded, wails for the ready event
// and callback to the main app // and callback to the main app
window.wails.events.on("wails:loaded", function () { window.wails.events.on("wails:loaded", function() {
window.wailsbridge.log("Wails Ready"); window.wailsbridge.log("Wails Ready");
if (window.wailsbridge.callback) { if (window.wailsbridge.callback) {
window.wailsbridge.log("Notifying application"); window.wailsbridge.log("Notifying application");
@@ -189,6 +189,7 @@ function startBridge() {
// Call back // Call back
case "c": case "c":
var callbackData = message.data.slice(1); var callbackData = message.data.slice(1);
window.wailsbridge.log("Callback = " + callbackData);
window.wails._.callback(callbackData); window.wails._.callback(callbackData);
break; break;
} }
@@ -204,7 +205,7 @@ function startBridge() {
export default { export default {
// The main function // The main function
// Passes the main Wails object to the callback if given. // Passes the main Wails object to the callback if given.
Start: function (callback) { Start: function(callback) {
// Save the callback // Save the callback
window.wailsbridge.callback = callback; window.wailsbridge.callback = callback;

View File

@@ -1,40 +0,0 @@
(function(){window.wails=window.wails||{};window.backend={};function cryptoRandom(){var array=new Uint32Array(1);return window.crypto.getRandomValues(array)[0]}function basicRandom(){return Math.random()*9007199254740991}var randomFunc;if(window.crypto){randomFunc=cryptoRandom}else{randomFunc=basicRandom}function isValidIdentifier(name){try{new Function("var "+name);return true}catch(e){return false}}function addScript(js,callbackID){var script=document.createElement("script");script.text=js;document.body.appendChild(script);window.wails.events.emit(callbackID)}function injectCSS(css){var elem=document.createElement('style');elem.setAttribute('type','text/css');if(elem.styleSheet){elem.styleSheet.cssText=css}else{elem.appendChild(document.createTextNode(css))}var head=document.head||document.getElementsByTagName('head')[0];head.appendChild(elem)}var bindingsBasePath=window.backend;function addBindingPath(pathSections){var currentPath=bindingsBasePath;for(var sectionIndex in pathSections){var section=pathSections[sectionIndex];if(!isValidIdentifier(section)){var errMessage=section+" is not a valid javascript identifier.";var err=new Error(errMessage);return[null,err]}if(!currentPath[section]){currentPath[section]={}}currentPath=currentPath[section]}return[currentPath,null]}function newBinding(bindingName){var bindingSections=bindingName.split('.').splice(1);var callName=bindingSections.pop();var pathToBinding;var err;var bs=addBindingPath(bindingSections);var pathToBinding=bs[0];var err=bs[1];if(err!=null){return err}pathToBinding[callName]=function(){var timeout=0;function dynamic(){var args=[].slice.call(arguments);return call(bindingName,args,timeout)}dynamic.setTimeout=function(newTimeout){timeout=newTimeout};dynamic.getTimeout=function(){return timeout};return dynamic}()}var callbacks={};function call(bindingName,data,timeout){if(timeout==null||timeout==undefined){timeout=0}return new Promise(function(resolve,reject){var callbackID;do{callbackID=bindingName+"-"+randomFunc()}while(callbacks[callbackID]);if(timeout>0){var timeoutHandle=setTimeout(function(){reject(Error("Call to "+bindingName+" timed out. Request ID: "+callbackID))},timeout)}callbacks[callbackID]={timeoutHandle:timeoutHandle,reject:reject,resolve:resolve};try{var payloaddata=JSON.stringify(data);message={type:"call",callbackid:callbackID,payload:{bindingName:bindingName,data:payloaddata}};var payload=JSON.stringify(message);external.invoke(payload)}catch(e){console.error(e)}})}function callback(incomingMessage){var message;try{message=JSON.parse(incomingMessage)}catch(e){wails.log.debug("Invalid JSON passed to callback: "+e.message);wails.log.debug("Message: "+incomingMessage);return}callbackID=message.callbackid;callbackData=callbacks[callbackID];if(!callbackData){console.error("Callback '"+callbackID+"' not registed!!!");return}clearTimeout(callbackData.timeoutHandle);delete callbacks[callbackID];if(message.error){return callbackData.reject(message.error)}return callbackData.resolve(message.data)}var eventListeners={};function on(eventName,callback){eventListeners[eventName]=eventListeners[eventName]||[];eventListeners[eventName].push(callback)}function notify(eventName,data){if(eventListeners[eventName]){eventListeners[eventName].forEach(function(element){var parsedData=[];if(data){try{parsedData=JSON.parse(data)}catch(e){wails.log.error("Invalid JSON data sent to notify. Event name = "+eventName)}}element.apply(null,parsedData)})}}function emit(eventName){var data=JSON.stringify([].slice.apply(arguments).slice(1));message={type:"event",payload:{name:eventName,data:data}};external.invoke(JSON.stringify(message))}window.wails.events={emit:emit,on:on};function sendLogMessage(level,message){message={type:"log",payload:{level:level,message:message}};external.invoke(JSON.stringify(message))}function logDebug(message){sendLogMessage("debug",message)}function logInfo(message){sendLogMessage("info",message)}function logWarning(message){sendLogMessage("warning",message)}function logError(message){sendLogMessage("error",message)}function logFatal(message){sendLogMessage("fatal",message)}window.wails.log={debug:logDebug,info:logInfo,warning:logWarning,error:logError,fatal:logFatal};window.wails._={newBinding:newBinding,callback:callback,notify:notify,sendLogMessage:sendLogMessage,callbacks:callbacks,injectCSS:injectCSS,addScript:addScript};window.wails.events.emit("wails:loaded");})();
(function(){window.wails=window.wails||{};window.backend={};function cryptoRandom(){var array=new Uint32Array(1);return window.crypto.getRandomValues(array)[0]}
function basicRandom(){return Math.random()*9007199254740991}
var randomFunc;if(window.crypto){randomFunc=cryptoRandom}else{randomFunc=basicRandom}
function isValidIdentifier(name){try{new Function("var "+name);return!0}catch(e){return!1}}
function addScript(js,callbackID){var script=document.createElement("script");script.text=js;document.body.appendChild(script);window.wails.events.emit(callbackID)}
function injectCSS(css){var elem=document.createElement('style');elem.setAttribute('type','text/css');if(elem.styleSheet){elem.styleSheet.cssText=css}else{elem.appendChild(document.createTextNode(css))}
var head=document.head||document.getElementsByTagName('head')[0];head.appendChild(elem)}
var bindingsBasePath=window.backend;function addBindingPath(pathSections){var currentPath=bindingsBasePath;for(var sectionIndex in pathSections){var section=pathSections[sectionIndex];if(!isValidIdentifier(section)){var errMessage=section+" is not a valid javascript identifier.";var err=new Error(errMessage);return[null,err]}
if(!currentPath[section]){currentPath[section]={}}
currentPath=currentPath[section]}
return[currentPath,null]}
function newBinding(bindingName){var bindingSections=bindingName.split('.').splice(1);var callName=bindingSections.pop();var pathToBinding;var err;var bs=addBindingPath(bindingSections);var pathToBinding=bs[0];var err=bs[1];if(err!=null){return err}
pathToBinding[callName]=function(){var timeout=0;function dynamic(){var args=[].slice.call(arguments);return call(bindingName,args,timeout)}
dynamic.setTimeout=function(newTimeout){timeout=newTimeout}
dynamic.getTimeout=function(){return timeout}
return dynamic}()}
var callbacks={};function call(bindingName,data,timeout){if(timeout==null||timeout==undefined){timeout=0}
return new Promise(function(resolve,reject){var callbackID;do{callbackID=bindingName+"-"+randomFunc()}while(callbacks[callbackID]);if(timeout>0){var timeoutHandle=setTimeout(function(){reject(Error("Call to "+bindingName+" timed out. Request ID: "+callbackID))},timeout)}
callbacks[callbackID]={timeoutHandle:timeoutHandle,reject:reject,resolve:resolve}
try{var payloaddata=JSON.stringify(data);message={type:"call",callbackid:callbackID,payload:{bindingName:bindingName,data:payloaddata,}}
var payload=JSON.stringify(message);external.invoke(payload)}catch(e){console.error(e)}})}
function callback(incomingMessage){incomingMessage=decodeURIComponent(incomingMessage.replace(/\s+/g,'').replace(/[0-9a-f]{2}/g,'%$&'));var message;try{message=JSON.parse(incomingMessage)}catch(e){wails.log.debug("Invalid JSON passed to callback: "+e.message);wails.log.debug("Message: "+incomingMessage);return}
callbackID=message.callbackid;callbackData=callbacks[callbackID];if(!callbackData){console.error("Callback '"+callbackID+"' not registed!!!");return}
clearTimeout(callbackData.timeoutHandle);delete callbacks[callbackID];if(message.error){return callbackData.reject(message.error)}
return callbackData.resolve(message.data)}
var eventListeners={};function on(eventName,callback){eventListeners[eventName]=eventListeners[eventName]||[];eventListeners[eventName].push(callback)}
function notify(eventName,data){if(eventListeners[eventName]){eventListeners[eventName].forEach(function(element){var parsedData=[];if(data){try{parsedData=JSON.parse(data)}catch(e){wails.log.error("Invalid JSON data sent to notify. Event name = "+eventName)}}
element.apply(null,parsedData)})}}
function emit(eventName){var data=JSON.stringify([].slice.apply(arguments).slice(1));message={type:"event",payload:{name:eventName,data:data,}}
external.invoke(JSON.stringify(message))}
window.wails.events={emit:emit,on:on};function sendLogMessage(level,message){message={type:"log",payload:{level:level,message:message,}}
external.invoke(JSON.stringify(message))}
function logDebug(message){sendLogMessage("debug",message)}
function logInfo(message){sendLogMessage("info",message)}
function logWarning(message){sendLogMessage("warning",message)}
function logError(message){sendLogMessage("error",message)}
function logFatal(message){sendLogMessage("fatal",message)}
window.wails.log={debug:logDebug,info:logInfo,warning:logWarning,error:logError,fatal:logFatal,};window.wails._={newBinding:newBinding,callback:callback,notify:notify,sendLogMessage:sendLogMessage,callbacks:callbacks,injectCSS:injectCSS,addScript:addScript,}
window.wails.events.emit("wails:loaded")})()

View File

@@ -1 +1 @@
!function(){var e;function n(e){try{return new Function("var "+e),!0}catch(e){return!1}}window.wails=window.wails||{},window.backend={},e=window.crypto?function(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}:function(){return 9007199254740991*Math.random()};var a=window.backend;var t={};var i={};function r(e,n){n={type:"log",payload:{level:e,message:n}},external.invoke(JSON.stringify(n))}window.wails.events={emit:function(e){var n=JSON.stringify([].slice.apply(arguments).slice(1));message={type:"event",payload:{name:e,data:n}},external.invoke(JSON.stringify(message))},on:function(e,n){i[e]=i[e]||[],i[e].push(n)}},window.wails.log={debug:function(e){r("debug",e)},info:function(e){r("info",e)},warning:function(e){r("warning",e)},error:function(e){r("error",e)},fatal:function(e){r("fatal",e)}},window.wails._={newBinding:function(i){var r,l=i.split(".").splice(1),o=l.pop(),c=function(e){var t=a;for(var i in e){var r=e[i];if(!n(r))return[null,new Error(r+" is not a valid javascript identifier.")];t[r]||(t[r]={}),t=t[r]}return[t,null]}(l),s=c[0];if(null!=(r=c[1]))return r;s[o]=function(){var n=0;function a(){var a=[].slice.call(arguments);return function(n,a,i){return null!=i&&null!=i||(i=0),new Promise(function(r,l){var o;do{o=n+"-"+e()}while(t[o]);if(i>0)var c=setTimeout(function(){l(Error("Call to "+n+" timed out. Request ID: "+o))},i);t[o]={timeoutHandle:c,reject:l,resolve:r};try{var s=JSON.stringify(a);message={type:"call",callbackid:o,payload:{bindingName:n,data:s}};var u=JSON.stringify(message);external.invoke(u)}catch(e){console.error(e)}})}(i,a,n)}return a.setTimeout=function(e){n=e},a.getTimeout=function(){return n},a}()},callback:function(e){var n;e=decodeURIComponent(e.replace(/\s+/g,"").replace(/[0-9a-f]{2}/g,"%$&"));try{n=JSON.parse(e)}catch(n){return wails.log.debug("Invalid JSON passed to callback: "+n.message),void wails.log.debug("Message: "+e)}if(callbackID=n.callbackid,callbackData=t[callbackID],callbackData)return clearTimeout(callbackData.timeoutHandle),delete t[callbackID],n.error?callbackData.reject(n.error):callbackData.resolve(n.data);console.error("Callback '"+callbackID+"' not registed!!!")},notify:function(e,n){i[e]&&i[e].forEach(function(a){var t=[];if(n)try{t=JSON.parse(n)}catch(n){wails.log.error("Invalid JSON data sent to notify. Event name = "+e)}a.apply(null,t)})},sendLogMessage:r,callbacks:t,injectCSS:function(e){var n=document.createElement("style");n.setAttribute("type","text/css"),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e)),(document.head||document.getElementsByTagName("head")[0]).appendChild(n)},addScript:function(e,n){var a=document.createElement("script");a.text=e,document.body.appendChild(a),window.wails.events.emit(n)}},window.wails.events.emit("wails:loaded")}(); (function(){window.wails=window.wails||{};window.backend={};function cryptoRandom(){var array=new Uint32Array(1);return window.crypto.getRandomValues(array)[0]}function basicRandom(){return Math.random()*9007199254740991}var randomFunc;if(window.crypto){randomFunc=cryptoRandom}else{randomFunc=basicRandom}function isValidIdentifier(name){try{new Function("var "+name);return true}catch(e){return false}}function addScript(js,callbackID){var script=document.createElement("script");script.text=js;document.body.appendChild(script);window.wails.events.emit(callbackID)}function injectCSS(css){var elem=document.createElement('style');elem.setAttribute('type','text/css');if(elem.styleSheet){elem.styleSheet.cssText=css}else{elem.appendChild(document.createTextNode(css))}var head=document.head||document.getElementsByTagName('head')[0];head.appendChild(elem)}var bindingsBasePath=window.backend;function addBindingPath(pathSections){var currentPath=bindingsBasePath;for(var sectionIndex in pathSections){var section=pathSections[sectionIndex];if(!isValidIdentifier(section)){var errMessage=section+" is not a valid javascript identifier.";var err=new Error(errMessage);return[null,err]}if(!currentPath[section]){currentPath[section]={}}currentPath=currentPath[section]}return[currentPath,null]}function newBinding(bindingName){var bindingSections=bindingName.split('.').splice(1);var callName=bindingSections.pop();var pathToBinding;var err;var bs=addBindingPath(bindingSections);var pathToBinding=bs[0];var err=bs[1];if(err!=null){return err}pathToBinding[callName]=function(){var timeout=0;function dynamic(){var args=[].slice.call(arguments);return call(bindingName,args,timeout)}dynamic.setTimeout=function(newTimeout){timeout=newTimeout};dynamic.getTimeout=function(){return timeout};return dynamic}()}var callbacks={};function call(bindingName,data,timeout){if(timeout==null||timeout==undefined){timeout=0}return new Promise(function(resolve,reject){var callbackID;do{callbackID=bindingName+"-"+randomFunc()}while(callbacks[callbackID]);if(timeout>0){var timeoutHandle=setTimeout(function(){reject(Error("Call to "+bindingName+" timed out. Request ID: "+callbackID))},timeout)}callbacks[callbackID]={timeoutHandle:timeoutHandle,reject:reject,resolve:resolve};try{var payloaddata=JSON.stringify(data);message={type:"call",callbackid:callbackID,payload:{bindingName:bindingName,data:payloaddata}};var payload=JSON.stringify(message);external.invoke(payload)}catch(e){console.error(e)}})}function callback(incomingMessage){var message;try{message=JSON.parse(incomingMessage)}catch(e){wails.log.debug("Invalid JSON passed to callback: "+e.message);wails.log.debug("Message: "+incomingMessage);return}callbackID=message.callbackid;callbackData=callbacks[callbackID];if(!callbackData){console.error("Callback '"+callbackID+"' not registed!!!");return}clearTimeout(callbackData.timeoutHandle);delete callbacks[callbackID];if(message.error){return callbackData.reject(message.error)}return callbackData.resolve(message.data)}var eventListeners={};function on(eventName,callback){eventListeners[eventName]=eventListeners[eventName]||[];eventListeners[eventName].push(callback)}function notify(eventName,data){if(eventListeners[eventName]){eventListeners[eventName].forEach(function(element){var parsedData=[];if(data){try{parsedData=JSON.parse(data)}catch(e){wails.log.error("Invalid JSON data sent to notify. Event name = "+eventName)}}element.apply(null,parsedData)})}}function emit(eventName){var data=JSON.stringify([].slice.apply(arguments).slice(1));message={type:"event",payload:{name:eventName,data:data}};external.invoke(JSON.stringify(message))}window.wails.events={emit:emit,on:on};function sendLogMessage(level,message){message={type:"log",payload:{level:level,message:message}};external.invoke(JSON.stringify(message))}function logDebug(message){sendLogMessage("debug",message)}function logInfo(message){sendLogMessage("info",message)}function logWarning(message){sendLogMessage("warning",message)}function logError(message){sendLogMessage("error",message)}function logFatal(message){sendLogMessage("fatal",message)}window.wails.log={debug:logDebug,info:logInfo,warning:logWarning,error:logError,fatal:logFatal};window.wails._={newBinding:newBinding,callback:callback,notify:notify,sendLogMessage:sendLogMessage,callbacks:callbacks,injectCSS:injectCSS,addScript:addScript};window.wails.events.emit("wails:loaded");})();

View File

@@ -10,8 +10,8 @@
function cryptoRandom() { function cryptoRandom() {
var array = new Uint32Array(1); var array = new Uint32Array(1);
return window.crypto.getRandomValues(array)[0]; return window.crypto.getRandomValues(array)[0];
} }
// LOLRandom // LOLRandom
function basicRandom() { function basicRandom() {
@@ -203,10 +203,6 @@
// Called by the backend to return data to a previously called // Called by the backend to return data to a previously called
// binding invocation // binding invocation
function callback(incomingMessage) { function callback(incomingMessage) {
// Decode the message - Credit: https://stackoverflow.com/a/13865680
incomingMessage = decodeURIComponent(incomingMessage.replace(/\s+/g, '').replace(/[0-9a-f]{2}/g, '%$&'));
// Parse the message // Parse the message
var message; var message;
try { try {
@@ -247,7 +243,7 @@
// notify informs frontend listeners that an event was emitted with the given data // notify informs frontend listeners that an event was emitted with the given data
function notify(eventName, data) { function notify(eventName, data) {
if (eventListeners[eventName]) { if (eventListeners[eventName]) {
eventListeners[eventName].forEach(function (element) { eventListeners[eventName].forEach(function(element) {
var parsedData = []; var parsedData = [];
// Parse data if we have it // Parse data if we have it
if (data) { if (data) {
@@ -336,8 +332,8 @@
callbacks: callbacks, callbacks: callbacks,
injectCSS: injectCSS, injectCSS: injectCSS,
addScript: addScript, addScript: addScript,
} }
/************************************************************/ /************************************************************/