Compare commits

...

18 Commits

Author SHA1 Message Date
Lea Anthony bd9751d888 feat: Support distribution support requests 2019-06-25 08:13:20 +10:00
Lea Anthony 7d171b0907 feat: initial support for platform requests 2019-06-24 09:11:06 +10:00
Lea Anthony 5b8f311465 Merge pull request #130 from wailsapp/123-Unify-Runtime-APIs
fix: linting
2019-06-22 08:47:25 +10:00
Lea Anthony 801465ac51 fix: linting 2019-06-22 08:45:46 +10:00
Lea Anthony a84e2ae9b3 Merge pull request #129 from wailsapp/123-Unify-Runtime-APIs
feat: unify runtime API signatures
2019-06-22 08:43:23 +10:00
Lea Anthony 9496d1d47f Merge pull request #126 from bh90210/121-react-template-build-error
fix(react template): reverting bugfix + code clean-up
2019-06-22 08:39:16 +10:00
Lea Anthony 36e575e0a2 feat: unify runtime API signatures 2019-06-22 08:36:11 +10:00
ktc 70ccb8942b fix(react template): reverting bugfix + code clean-up 2019-06-19 20:09:23 +03:00
Lea Anthony d3cd3d43bd chore: version bump 2019-06-19 21:04:27 +10:00
Lea Anthony 9116f0d06c Merge pull request #124 from wailsapp/116-Add-browser-methods-to-runtime
116 add browser methods to runtime
2019-06-19 21:01:53 +10:00
Lea Anthony 2c91e26add docs: guardrails badge 2019-06-19 21:01:00 +10:00
Lea Anthony f1647443dc chore: add .jshintrc file to indicate es6 2019-06-19 20:54:36 +10:00
Lea Anthony b6b6ce2d4a fix: linting fix 2019-06-19 20:53:04 +10:00
Lea Anthony abcc869537 feat: added OpenFile 2019-06-19 20:49:39 +10:00
Lea Anthony 3e02e1676a Merge pull request #122 from bh90210/121-react-template-build-error
fix(react template): build bugfix
2019-06-19 08:31:57 +10:00
Lea Anthony 5c8a4de446 fix: version 2019-06-19 08:29:15 +10:00
Lea Anthony 7cabef946e feat: initial support for browser.openURL for f/e 2019-06-19 08:28:31 +10:00
ktc f2519e5af2 fix(react template): build bugfix 2019-06-18 13:57:45 +03:00
20 changed files with 278 additions and 93 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"esversion": 6
}
+1
View File
@@ -10,6 +10,7 @@
<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/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>
<a href="https://dashboard.guardrails.io/default/gh/wailsapp/wails"><img src="https://badges.guardrails.io/wailsapp/wails.svg?token=53657bc22ec360d7673c894fdd70568e918ec581d10d84427ed4de5fe1eeff1a"></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!
+65
View File
@@ -0,0 +1,65 @@
package wails
import "strings"
import "fmt"
type internalMethods struct{
log *CustomLogger
browser *RuntimeBrowser
}
func newInternalMethods() *internalMethods {
return &internalMethods{
log: newCustomLogger("InternalCall"),
browser: newRuntimeBrowser(),
}
}
func (i *internalMethods) processCall(callData *callData) (interface{}, error) {
if !strings.HasPrefix(callData.BindingName, ".wails.") {
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
}
// Strip prefix
var splitCall = strings.Split(callData.BindingName,".")[2:]
if len(splitCall) != 2 {
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
}
group := splitCall[0]
switch group {
case "Browser":
return i.processBrowserCommand(splitCall[1], callData.Data)
default:
return nil, fmt.Errorf("Unknown internal command group '%s'", group)
}
}
func (i *internalMethods) processBrowserCommand(command string, data interface{}) (interface{}, error) {
switch command {
case "OpenURL":
url := data.(string)
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
if url[0] == '"' {
url = url[1:]
}
if i := len(url)-1; url[i] == '"' {
url = url[:i]
}
i.log.Debugf("Calling Browser.OpenURL with '%s'", url)
return nil, i.browser.OpenURL(url)
case "OpenFile":
filename := data.(string)
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
if filename[0] == '"' {
filename = filename[1:]
}
if i := len(filename)-1; filename[i] == '"' {
filename = filename[:i]
}
i.log.Debugf("Calling Browser.OpenFile with '%s'", filename)
return nil, i.browser.OpenFile(filename)
default:
return nil, fmt.Errorf("Unknown Browser command '%s'", command)
}
}
+12 -3
View File
@@ -17,6 +17,7 @@ binding:
type bindingManager struct {
methods map[string]*boundMethod
functions map[string]*boundFunction
internalMethods *internalMethods
initMethods []*boundMethod
log *CustomLogger
renderer Renderer
@@ -27,9 +28,10 @@ type bindingManager struct {
func newBindingManager() *bindingManager {
result := &bindingManager{
methods: make(map[string]*boundMethod),
functions: make(map[string]*boundFunction),
log: newCustomLogger("Bind"),
methods: make(map[string]*boundMethod),
functions: make(map[string]*boundFunction),
log: newCustomLogger("Bind"),
internalMethods: newInternalMethods(),
}
return result
}
@@ -163,6 +165,11 @@ func (b *bindingManager) bind(object interface{}) {
b.objectsToBind = append(b.objectsToBind, object)
}
func (b *bindingManager) processInternalCall(callData *callData) (interface{}, error) {
// Strip prefix
return b.internalMethods.processCall(callData)
}
func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
// Return values
var result []reflect.Value
@@ -254,6 +261,8 @@ func (b *bindingManager) processCall(callData *callData) (result interface{}, er
result, err = b.processFunctionCall(callData)
case 2:
result, err = b.processMethodCall(callData)
case 3:
result, err = b.processInternalCall(callData)
default:
result = nil
err = fmt.Errorf("Invalid binding name '%s'", callData.BindingName)
+10
View File
File diff suppressed because one or more lines are too long
+78 -9
View File
@@ -3,9 +3,12 @@ package cmd
import (
"fmt"
"io/ioutil"
"net/url"
"os"
"regexp"
"runtime"
"strings"
"github.com/pkg/browser"
)
// LinuxDistribution is of type int
@@ -29,6 +32,7 @@ type DistroInfo struct {
Release string
Codename string
DistributorID string
DiscoveredBy string
}
// GetLinuxDistroInfo returns information about the running linux distribution
@@ -43,7 +47,7 @@ func GetLinuxDistroInfo() *DistroInfo {
if err != nil {
return result
}
result.DiscoveredBy = "lsb"
for _, line := range strings.Split(stdout, "\n") {
if strings.Contains(line, ":") {
// Iterate lines a
@@ -58,6 +62,8 @@ func GetLinuxDistroInfo() *DistroInfo {
result.Distribution = Ubuntu
case "Arch", "ManjaroLinux":
result.Distribution = Arch
// case "Debian":
// result.Distribution = Debian
}
case "Description":
result.Description = value
@@ -65,21 +71,37 @@ func GetLinuxDistroInfo() *DistroInfo {
result.Release = value
case "Codename":
result.Codename = value
}
}
}
// check if /etc/os-release exists
} else if _, err := os.Stat("/etc/os-release"); !os.IsNotExist(err) {
// Default value
osName := "Unknown"
version := ""
// 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])
// strip quotations
osName = strings.Trim(osName, "\"")
// Split into lines
lines := strings.Split(string(osRelease), "\n")
// Iterate lines
for _, line := range lines {
// Split each line by the equals char
splitLine := strings.SplitN(line, "=", 2)
// Check we have
if len(splitLine) != 2 {
continue
}
switch splitLine[0] {
case "NAME":
osName = strings.Trim(splitLine[1], "\"")
case "VERSION_ID":
version = strings.Trim(splitLine[1], "\"")
}
}
// Check distro name against list of distros
result.Release = version
result.DiscoveredBy = "os-release"
switch osName {
case "Fedora":
result.Distribution = RedHat
@@ -87,6 +109,11 @@ func GetLinuxDistroInfo() *DistroInfo {
result.Distribution = RedHat
case "Arch Linux":
result.Distribution = Arch
// case "Debian GNU/Linux":
// result.Distribution = Debian
default:
result.Distribution = Unknown
result.DistributorID = osName
}
}
return result
@@ -124,3 +151,45 @@ func RpmInstalled(packageName string) (bool, error) {
_, _, exitCode, _ := rpm.Run("--query", packageName)
return exitCode == 0, nil
}
// RequestSupportForDistribution promts the user to submit a request to support their
// currently unsupported distribution
func RequestSupportForDistribution(distroInfo *DistroInfo, libraryName string) error {
var logger = NewLogger()
defaultError := fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, libraryName)
logger.Yellow("Distribution '%s' is not currently supported, but we would love to!", distroInfo.DistributorID)
q := fmt.Sprintf("Would you like to submit a request to support distribution '%s'?", distroInfo.DistributorID)
result := Prompt(q, "yes")
if strings.ToLower(result) != "yes" {
return defaultError
}
title := fmt.Sprintf("Support Distribution '%s'", distroInfo.DistributorID)
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", 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))
str.WriteString(fmt.Sprintf("| Distribution ID | %s |\n", distroInfo.DistributorID))
str.WriteString(fmt.Sprintf("| Distribution Version | %s |\n", distroInfo.Release))
str.WriteString(fmt.Sprintf("| Discovered by | %s |\n", distroInfo.DiscoveredBy))
body := fmt.Sprintf("**Description**\nDistribution '%s' is curently unsupported.\n\n**Further Information**\n\n%s\n\n*Please add any extra information here, EG: libraries that are needed to make the distribution work, or commands to install them*", distroInfo.DistributorID, str.String())
fullURL := "https://github.com/wailsapp/wails/issues/new?"
params := "title=" + title + "&body=" + body
fmt.Println("Opening browser to file request.")
browser.OpenURL(fullURL + url.PathEscape(params))
return nil
}
+1 -2
View File
@@ -295,7 +295,6 @@ func CheckDependencies(logger *Logger) (bool, error) {
logger.Green("Library '%s' installed.", library.Name)
}
case RedHat:
installed, err := RpmInstalled(library.Name)
if err != nil {
return false, err
@@ -307,7 +306,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
logger.Green("Library '%s' installed.", library.Name)
}
default:
return false, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name)
return false, RequestSupportForDistribution(distroInfo, library.Name)
}
}
}
@@ -26,22 +26,8 @@ class HelloWorld extends React.Component {
this.setState({ showModal: false });
}
startAsync() {
this.setState({
loading: true
});
window.backend.basic().then(result =>
this.setState({
loading: false,
result
})
);
}
render() {
const { loading, result } = this.state;
const { result } = this.state;
return (
<div className="App">
<button onClick={this.handleOpenModal} type="button">
@@ -9,9 +9,9 @@
export default {
// The main function
// Passes the main Wails object to the callback if given.
Start: function(callback) {
Start: function (callback) {
if (callback) {
window.wails.events.on("wails:ready", callback);
window.wails.Events.On("wails:ready", callback);
}
}
};
@@ -9,9 +9,9 @@
export default {
// The main function
// Passes the main Wails object to the callback if given.
Start: function(callback) {
Start: function (callback) {
if (callback) {
window.wails.events.on("wails:ready", callback);
window.wails.Events.On("wails:ready", callback);
}
}
};
+1 -1
View File
@@ -1,4 +1,4 @@
package cmd
// Version - Wails version
const Version = "v0.16.0"
const Version = "v0.16.1-pre"
+1 -1
View File
@@ -108,7 +108,7 @@ func checkLibraries() (errors bool, err error) {
logger.Green("Library '%s' installed.", library.Name)
}
default:
return false, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name)
return false, cmd.RequestSupportForDistribution(distroInfo, library.Name)
}
}
}
+2
View File
@@ -6,6 +6,7 @@ type Runtime struct {
Log *RuntimeLog
Dialog *RuntimeDialog
Window *RuntimeWindow
Browser *RuntimeBrowser
FileSystem *RuntimeFileSystem
}
@@ -15,6 +16,7 @@ func newRuntime(eventManager *eventManager, renderer Renderer) *Runtime {
Log: newRuntimeLog(),
Dialog: newRuntimeDialog(renderer),
Window: newRuntimeWindow(renderer),
Browser: newRuntimeBrowser(),
FileSystem: newRuntimeFileSystem(),
}
}
+25
View File
@@ -0,0 +1,25 @@
package wails
import "github.com/pkg/browser"
// GlobalRuntimeBrowser is the global instance of the RuntimeBrowser object
// Why? Because we need to use it in both the runtime and from the frontend
var GlobalRuntimeBrowser = newRuntimeBrowser()
// RuntimeBrowser exposes browser methods to the runtime
type RuntimeBrowser struct {
}
func newRuntimeBrowser() *RuntimeBrowser {
return &RuntimeBrowser{}
}
// OpenURL opens the given url in the system's default browser
func (r *RuntimeBrowser) OpenURL(url string) error {
return browser.OpenURL(url)
}
// OpenFile opens the given file in the system's default browser
func (r *RuntimeBrowser) OpenFile(filePath string) error {
return browser.OpenFile(filePath)
}
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -167,7 +167,7 @@ function startBridge() {
// Now wails runtime is loaded, wails for the ready event
// 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");
if (window.wailsbridge.callback) {
window.wailsbridge.log("Notifying application");
@@ -9,9 +9,9 @@
export default {
// The main function
// Passes the main Wails object to the callback if given.
Start: function(callback) {
Start: function (callback) {
if (callback) {
window.wails.events.on("wails:ready", callback);
window.wails.Events.On("wails:ready", callback);
}
}
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+68 -12
View File
@@ -43,7 +43,7 @@
var script = document.createElement("script");
script.text = js;
document.body.appendChild(script);
window.wails.events.emit(callbackID);
window.wails.Events.Emit(callbackID);
}
// -------------- CSS ---------------
@@ -200,6 +200,11 @@
})
}
// systemCall is used to call wails methods from the frontend
function systemCall(method, data) {
return call(".wails." + method, data);
}
// Called by the backend to return data to a previously called
// binding invocation
function callback(incomingMessage) {
@@ -212,8 +217,8 @@
try {
message = JSON.parse(incomingMessage);
} catch (e) {
wails.log.debug("Invalid JSON passed to callback: " + e.message);
wails.log.debug("Message: " + incomingMessage);
wails.Log.Debug("Invalid JSON passed to callback: " + e.message);
wails.Log.Debug("Message: " + incomingMessage);
return;
}
callbackID = message.callbackid;
@@ -254,7 +259,7 @@
try {
parsedData = JSON.parse(data);
} catch (e) {
wails.log.error("Invalid JSON data sent to notify. Event name = " + eventName)
wails.Log.Error("Invalid JSON data sent to notify. Event name = " + eventName);
}
}
element.apply(null, parsedData);
@@ -279,12 +284,46 @@
external.invoke(JSON.stringify(message));
}
function deprecatedEventsFunction(fn, oldName) {
var newName = oldName[0].toUpperCase() + oldName.substring(1);
return function (eventName, eventData) {
console.warn('Method events.' + oldName + ' has been deprecated. Please use Events.' + newName);
return fn(eventName, eventData);
};
}
// Deprecated Events calls
window.wails.events = {
emit: deprecatedEventsFunction(emit, 'emit'),
on: deprecatedEventsFunction(on, 'on'),
};
// Events calls
window.wails.events = { emit: emit, on: on };
window.wails.Events = {
Emit: emit,
On: on
};
/************************************************************/
/************************* Browser **************************/
function OpenURL(url) {
return systemCall("Browser.OpenURL", url);
}
function OpenFile(filename) {
return systemCall("Browser.OpenFile", filename);
}
window.wails.Browser = {
OpenURL,
OpenFile,
};
/************************* Logging **************************/
// Sends a log message to the backend with the given
@@ -302,6 +341,14 @@
external.invoke(JSON.stringify(message));
}
function deprecatedLogFunction(fn, oldName) {
var newName = oldName[0].toUpperCase() + oldName.substring(1);
return function (message) {
console.warn('Method Log.' + oldName + ' has been deprecated. Please use Log.' + newName);
return fn(message);
};
}
function logDebug(message) {
sendLogMessage("debug", message);
}
@@ -319,13 +366,22 @@
}
window.wails.log = {
debug: logDebug,
info: logInfo,
warning: logWarning,
error: logError,
fatal: logFatal,
debug: deprecatedLogFunction(logDebug, 'debug'),
info: deprecatedLogFunction(logInfo, 'info'),
warning: deprecatedLogFunction(logWarning, 'warning'),
error: deprecatedLogFunction(logError, 'error'),
fatal: deprecatedLogFunction(logFatal, 'fatal'),
};
window.wails.Log = {
Debug: logDebug,
Info: logInfo,
Warning: logWarning,
Error: logError,
Fatal: logFatal,
};
/************************** Exports *************************/
window.wails._ = {
@@ -336,12 +392,12 @@
callbacks: callbacks,
injectCSS: injectCSS,
addScript: addScript,
}
};
/************************************************************/
// Notify backend that the runtime has finished loading
window.wails.events.emit("wails:loaded");
window.wails.Events.Emit("wails:loaded");
})()