mirror of
https://github.com/taigrr/wails.git
synced 2026-04-06 07:02:42 -07:00
Compare commits
55 Commits
angular-fi
...
cross-comp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68cd6a7f0e | ||
|
|
e00ffdbeea | ||
|
|
8d3c32c630 | ||
|
|
4eebbfd22c | ||
|
|
1998736baa | ||
|
|
89579db7fa | ||
|
|
3679114445 | ||
|
|
9e5dd0bc86 | ||
|
|
8c9ca5be95 | ||
|
|
526136099b | ||
|
|
f490bf8bc9 | ||
|
|
3edca62a38 | ||
|
|
7ae2acac90 | ||
|
|
7d822dfe8d | ||
|
|
c0f5c28e3b | ||
|
|
79188c503f | ||
|
|
bd6745bef0 | ||
|
|
8a14cc9a4c | ||
|
|
8a7c098041 | ||
|
|
030bd629df | ||
|
|
cad65f8f3f | ||
|
|
0c790bb08c | ||
|
|
fa1bc016fe | ||
|
|
5fc41949ae | ||
|
|
3d13368043 | ||
|
|
0bca7b57e0 | ||
|
|
332e9d66ea | ||
|
|
93884a5aeb | ||
|
|
c1fbca834b | ||
|
|
60fe2c0912 | ||
|
|
2e1e8b1513 | ||
|
|
dd49292b68 | ||
|
|
af30e5e6ba | ||
|
|
558cc9681c | ||
|
|
62f6bece57 | ||
|
|
084d412d86 | ||
|
|
788d22740b | ||
|
|
34ef3de737 | ||
|
|
8149cbc3c0 | ||
|
|
2032ef8225 | ||
|
|
38e897f646 | ||
|
|
de2f9a1e9e | ||
|
|
c506c95506 | ||
|
|
955cfbb689 | ||
|
|
aa698b993d | ||
|
|
a6fa5feb0c | ||
|
|
67a52b2a57 | ||
|
|
99d22fdcb7 | ||
|
|
7051ffd425 | ||
|
|
bac823566c | ||
|
|
401ebee719 | ||
|
|
b5b92c4afa | ||
|
|
2c2aee2d30 | ||
|
|
806b1aa8e0 | ||
|
|
94c56115a5 |
32
.github/workflows/latest-pre.yml
vendored
Normal file
32
.github/workflows/latest-pre.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: latest pre-release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '**-pre**'
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Test Build Latest Pre-Release
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.12
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.12
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go get -v -d ./...
|
||||||
|
- name: Build
|
||||||
|
run: go build -v ./cmd/wails
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: ./wails version
|
||||||
32
.github/workflows/pr.yml
vendored
Normal file
32
.github/workflows/pr.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: pr
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Test Build PR
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.12
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.12
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go get -v -d ./...
|
||||||
|
- name: Build
|
||||||
|
run: go build -v ./cmd/wails
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: ./wails version
|
||||||
34
.github/workflows/release.yml
vendored
Normal file
34
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
tags:
|
||||||
|
- '!**pre**'
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Test Build Latest Release
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.12
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.12
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go get -v -d ./...
|
||||||
|
- name: Build
|
||||||
|
run: go build -v ./cmd/wails
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: ./wails version
|
||||||
@@ -2,21 +2,24 @@
|
|||||||
|
|
||||||
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!
|
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)
|
* [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot)
|
||||||
* [Qais Patankar](https://github.com/qaisjp)
|
* [Qais Patankar](https://github.com/qaisjp)
|
||||||
* [Anthony Lee](https://github.com/alee792)
|
* [Anthony Lee](https://github.com/alee792)
|
||||||
* [Adrian Lanzafame](https://github.com/lanzafame)
|
* [Adrian Lanzafame](https://github.com/lanzafame)
|
||||||
* [Mattn](https://github.com/mattn)
|
* [Mattn](https://github.com/mattn)
|
||||||
* [0xflotus](https://github.com/0xflotus)
|
* [0xflotus](https://github.com/0xflotus)
|
||||||
* [Michael D Henderson](https://github.com/mdhender)
|
* [Michael D Henderson](https://github.com/mdhender)
|
||||||
* [fred2104](https://github.com/fishfishfish2104)
|
* [fred2104](https://github.com/fishfishfish2104)
|
||||||
* [intelwalk](https://github.com/intelwalk)
|
* [intelwalk](https://github.com/intelwalk)
|
||||||
* [Mark Stenglein](https://github.com/ocelotsloth)
|
* [Mark Stenglein](https://github.com/ocelotsloth)
|
||||||
* [admin_3.exe](https://github.com/bh90210)
|
* [admin_3.exe](https://github.com/bh90210)
|
||||||
* [iceleo-com](https://github.com/iceleo-com)
|
* [iceleo-com](https://github.com/iceleo-com)
|
||||||
* [fallendusk](https://github.com/fallendusk)
|
* [fallendusk](https://github.com/fallendusk)
|
||||||
* [Florian Didran](https://github.com/fdidron)
|
* [Florian Didran](https://github.com/fdidron)
|
||||||
* [Nikolai Zimmermann](https://github.com/Chronophylos)
|
* [Nikolai Zimmermann](https://github.com/Chronophylos)
|
||||||
* [Toyam Cox](https://github.com/Vaelatern)
|
* [Toyam Cox](https://github.com/Vaelatern)
|
||||||
* [Robin Eklind](https://github.com/mewmew)
|
* [Robin Eklind](https://github.com/mewmew)
|
||||||
* [Kris Raney](https://github.com/kraney)
|
* [Kris Raney](https://github.com/kraney)
|
||||||
|
* [Jack Mordaunt](https://github.com/JackMordaunt)
|
||||||
|
* [Michael Hipp](https://github.com/MichaelHipp)
|
||||||
|
* [Travis McLane](https://github.com/tmclane)
|
||||||
23
README.md
23
README.md
@@ -1,5 +1,5 @@
|
|||||||
<p align="center" style="text-align: center">
|
<p align="center" style="text-align: center">
|
||||||
<img src="https://github.com/wailsapp/docs/raw/master/.vuepress/public/media/logo_cropped.png" width="40%"><br/>
|
<img src="logo_cropped.png" width="40%"><br/>
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
A framework for building desktop applications using Go & Web Technologies.<br/><br/>
|
A framework for building desktop applications using Go & Web Technologies.<br/><br/>
|
||||||
@@ -11,11 +11,14 @@
|
|||||||
<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_shield" alt="FOSSA Status"><img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=shield"/></a>
|
<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_shield" alt="FOSSA Status"><img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=shield"/></a>
|
||||||
<a href="https://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></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://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://dev.azure.com/leaanthony/Wails/_build/latest?definitionId=1&branchName=master" rel="nofollow"><img src="https://dev.azure.com/leaanthony/Wails/_apis/build/status/wailsapp.wails?branchName=master" alt="Pipelines"></a>
|
<a href="https://github.com/wailsapp/wails/workflows/release/badge.svg?branch=master" rel="nofollow"><img src="https://github.com/wailsapp/wails/workflows/release/badge.svg?branch=master" alt="Release Pipelines"></a>
|
||||||
|
<a href="https://github.com/wailsapp/wails/workflows/latest-pre/badge.svg?branch=masterr" rel="nofollow"><img src="https://github.com/wailsapp/wails/workflows/latest-pre/badge.svg?branch=master" alt="Pre-Release Pipelines"></a>
|
||||||
</p>
|
</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!
|
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!
|
||||||
|
|
||||||
|
The official docs can be found at [https://wails.app](https://wails.app).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Use standard Go libraries/frameworks for the backend
|
- Use standard Go libraries/frameworks for the backend
|
||||||
@@ -28,9 +31,6 @@ The traditional method of providing web interfaces to Go programs is via a built
|
|||||||
- Powerful cli tool
|
- Powerful cli tool
|
||||||
- Multiplatform
|
- 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
|
## Installation
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ Windows requires gcc and related tooling. The recommended download is from [http
|
|||||||
Installation is as simple as running the following command:
|
Installation is as simple as running the following command:
|
||||||
|
|
||||||
<pre style='color:white'>
|
<pre style='color:white'>
|
||||||
go get github.com/wailsapp/wails/cmd/wails
|
go get -u github.com/wailsapp/wails/cmd/wails
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
@@ -126,8 +126,7 @@ And without [these people](CONTRIBUTORS.md), it wouldn't be what it is today. A
|
|||||||
|
|
||||||
Special Mentions:
|
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.
|
* [Byron](https://github.com/bh90210) - At times, Byron has single handedly kept this project alive. Without his incredible input, we never would have got to v1.
|
||||||
* [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:
|
This project was mainly coded to the following albums:
|
||||||
|
|
||||||
@@ -148,3 +147,11 @@ This project was mainly coded to the following albums:
|
|||||||
## Licensing
|
## Licensing
|
||||||
|
|
||||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
|
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
|
||||||
|
|
||||||
|
## Special Thank You
|
||||||
|
|
||||||
|
<p align="center" style="text-align: center">
|
||||||
|
A special thank you to JetBrains for donating licenses to us!<br/><br/>
|
||||||
|
Please click the logo to let them know your appreciation!<br/><br/>
|
||||||
|
<a href="https://www.jetbrains.com?from=Wails"><img src="jetbrains-grayscale.png" width="30%"></a>
|
||||||
|
</p>
|
||||||
|
|||||||
30
app.go
30
app.go
@@ -1,7 +1,6 @@
|
|||||||
package wails
|
package wails
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -45,7 +44,7 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &App{
|
result := &App{
|
||||||
logLevel: "info",
|
logLevel: "debug",
|
||||||
renderer: renderer.NewWebView(),
|
renderer: renderer.NewWebView(),
|
||||||
ipc: ipc.NewManager(),
|
ipc: ipc.NewManager(),
|
||||||
bindingManager: binding.NewManager(),
|
bindingManager: binding.NewManager(),
|
||||||
@@ -67,28 +66,12 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
|
|||||||
result.config.DisableInspector = true
|
result.config.DisableInspector = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// If running windows, do a hidpi fix
|
// Platform specific init
|
||||||
if runtime.GOOS == "windows" {
|
platformInit()
|
||||||
err := SetProcessDPIAware()
|
|
||||||
if err != nil {
|
|
||||||
result.log.Fatalf(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetProcessDPIAware via user32.dll
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiaware
|
|
||||||
// Also, thanks Jack Mordaynt! https://github.com/wailsapp/wails/issues/293
|
|
||||||
func SetProcessDPIAware() error {
|
|
||||||
status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
|
||||||
if status == 0 {
|
|
||||||
return fmt.Errorf("exit status %d: %v %v", status, r, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the app
|
// Run the app
|
||||||
func (a *App) Run() error {
|
func (a *App) Run() error {
|
||||||
|
|
||||||
@@ -114,7 +97,7 @@ func (a *App) start() error {
|
|||||||
|
|
||||||
// Check if we are to run in bridge mode
|
// Check if we are to run in bridge mode
|
||||||
if BuildMode == cmd.BuildModeBridge {
|
if BuildMode == cmd.BuildModeBridge {
|
||||||
a.renderer = &renderer.Bridge{}
|
a.renderer = renderer.NewBridge()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the renderer
|
// Initialise the renderer
|
||||||
@@ -123,6 +106,11 @@ func (a *App) start() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable console for Windows debug builds
|
||||||
|
if runtime.GOOS == "windows" && BuildMode == cmd.BuildModeDebug {
|
||||||
|
a.renderer.EnableConsole()
|
||||||
|
}
|
||||||
|
|
||||||
// Start signal handler
|
// Start signal handler
|
||||||
t := tebata.New(os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
|
t := tebata.New(os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
|
||||||
t.Reserve(func() {
|
t.Reserve(func() {
|
||||||
|
|||||||
7
app_other.go
Normal file
7
app_other.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// +build +linux +darwin !windows
|
||||||
|
|
||||||
|
package wails
|
||||||
|
|
||||||
|
func platformInit() {
|
||||||
|
|
||||||
|
}
|
||||||
27
app_windows.go
Normal file
27
app_windows.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// +build windows !linux !darwin
|
||||||
|
|
||||||
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func platformInit() {
|
||||||
|
err := SetProcessDPIAware()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProcessDPIAware via user32.dll
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiaware
|
||||||
|
// Also, thanks Jack Mordaunt! https://github.com/wailsapp/wails/issues/293
|
||||||
|
func SetProcessDPIAware() error {
|
||||||
|
status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
||||||
|
if status == 0 {
|
||||||
|
return fmt.Errorf("exit status %d: %v %v", status, r, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
# avoid double trigger by applying some rules
|
|
||||||
# start a pipeline when push to 'master' branch
|
|
||||||
trigger:
|
|
||||||
- master
|
|
||||||
# or when pull request on 'develop' branch
|
|
||||||
pr:
|
|
||||||
- develop
|
|
||||||
|
|
||||||
# for now there is only one stage 'Build'
|
|
||||||
# in the future we could use multistage strategy for releases
|
|
||||||
stages:
|
|
||||||
- stage: Build
|
|
||||||
|
|
||||||
# there are 3 jobs
|
|
||||||
# one for each os
|
|
||||||
jobs:
|
|
||||||
- deployment: Linux
|
|
||||||
displayName: Lin
|
|
||||||
variables:
|
|
||||||
GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path
|
|
||||||
GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path
|
|
||||||
GOBIN: '$(GOPATH)/bin' # Go binaries path
|
|
||||||
GOMODULE: 'on'
|
|
||||||
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
|
||||||
pool:
|
|
||||||
vmImage: 'Ubuntu-16.04'
|
|
||||||
environment: 'linux-dev'
|
|
||||||
strategy:
|
|
||||||
runOnce:
|
|
||||||
deploy:
|
|
||||||
steps:
|
|
||||||
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
|
||||||
clean: true # whether to fetch clean each time
|
|
||||||
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
|
||||||
# go version 1.12.7
|
|
||||||
- script: |
|
|
||||||
wget "https://storage.googleapis.com/golang/go1.12.7.linux-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
|
||||||
tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
|
||||||
displayName: 'Install Go 1.12.7 Linux'
|
|
||||||
- script: |
|
|
||||||
mkdir -p '$(GOBIN)'
|
|
||||||
mkdir -p '$(GOPATH)/pkg'
|
|
||||||
mkdir -p '$(GOROOT)'
|
|
||||||
shopt -s extglob
|
|
||||||
shopt -s dotglob
|
|
||||||
echo '##vso[task.prependpath]$(GOBIN)'
|
|
||||||
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
|
||||||
displayName: 'Set up the Go workspace'
|
|
||||||
- script: |
|
|
||||||
go version
|
|
||||||
go get -v -d ./...
|
|
||||||
cd cmd/wails
|
|
||||||
go install
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Get dependencies, then build'
|
|
||||||
- script: |
|
|
||||||
wails version
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Check we have output'
|
|
||||||
|
|
||||||
- deployment: Mac
|
|
||||||
displayName: Mac
|
|
||||||
variables:
|
|
||||||
GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path
|
|
||||||
GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path
|
|
||||||
GOBIN: '$(GOPATH)/bin' # Go binaries path
|
|
||||||
GOMODULE: 'on'
|
|
||||||
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
|
||||||
pool:
|
|
||||||
vmImage: 'macOS-10.14'
|
|
||||||
environment: 'mac-dev'
|
|
||||||
strategy:
|
|
||||||
runOnce:
|
|
||||||
deploy:
|
|
||||||
steps:
|
|
||||||
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
|
||||||
clean: true # whether to fetch clean each time
|
|
||||||
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
|
||||||
# go version 1.12.7
|
|
||||||
- script: |
|
|
||||||
wget "https://storage.googleapis.com/golang/go1.12.7.darwin-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
|
||||||
tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
|
||||||
displayName: 'Install Go 1.12.7 Linux'
|
|
||||||
- script: |
|
|
||||||
mkdir -p '$(GOBIN)'
|
|
||||||
mkdir -p '$(GOPATH)/pkg'
|
|
||||||
mkdir -p '$(GOROOT)'
|
|
||||||
shopt -s extglob
|
|
||||||
shopt -s dotglob
|
|
||||||
echo '##vso[task.prependpath]$(GOBIN)'
|
|
||||||
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
|
||||||
displayName: 'Set up the Go workspace'
|
|
||||||
- script: |
|
|
||||||
go version
|
|
||||||
go get -v -d ./...
|
|
||||||
cd cmd/wails
|
|
||||||
go install
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Get dependencies, then build'
|
|
||||||
- script: |
|
|
||||||
wails version
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Check we have output'
|
|
||||||
|
|
||||||
- deployment: Win
|
|
||||||
displayName: Win
|
|
||||||
variables:
|
|
||||||
GOMODULE: 'on'
|
|
||||||
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
|
||||||
pool:
|
|
||||||
vmImage: 'windows-2019'
|
|
||||||
environment: 'win-dev'
|
|
||||||
strategy:
|
|
||||||
runOnce:
|
|
||||||
deploy:
|
|
||||||
steps:
|
|
||||||
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
|
||||||
clean: true # whether to fetch clean each time
|
|
||||||
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
|
||||||
# Go tool installer
|
|
||||||
# Find in cache or download a specific version of Go and add it to the PATH
|
|
||||||
- task: GoTool@0
|
|
||||||
inputs:
|
|
||||||
version: '1.12.7'
|
|
||||||
goPath: '$(Agent.BuildDirectory)/go'
|
|
||||||
goBin: '$(Agent.BuildDirectory)/go/bin'
|
|
||||||
displayName: 'Set up the Go workspace'
|
|
||||||
- script: |
|
|
||||||
go version
|
|
||||||
go get -v -d ./...
|
|
||||||
cd cmd/wails
|
|
||||||
go install
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Get dependencies, then build'
|
|
||||||
- script: |
|
|
||||||
wails version
|
|
||||||
workingDirectory: '$(Agent.BuildDirectory)/go/bin'
|
|
||||||
displayName: 'Check we have output'
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
# avoid double trigger by applying some rules
|
|
||||||
# start a pipeline when push to 'master' branch
|
|
||||||
trigger:
|
|
||||||
- master
|
|
||||||
# or when pull request on 'develop' branch
|
|
||||||
pr:
|
|
||||||
- develop
|
|
||||||
|
|
||||||
# for now there is only one stage 'Build'
|
|
||||||
# in the future we could use multistage strategy for releases
|
|
||||||
stages:
|
|
||||||
- stage: Build
|
|
||||||
|
|
||||||
# there are 3 jobs
|
|
||||||
# one for each os
|
|
||||||
jobs:
|
|
||||||
- deployment: Linux
|
|
||||||
displayName: Lin
|
|
||||||
variables:
|
|
||||||
GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path
|
|
||||||
GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path
|
|
||||||
GOBIN: '$(GOPATH)/bin' # Go binaries path
|
|
||||||
GOMODULE: 'on'
|
|
||||||
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
|
||||||
pool:
|
|
||||||
vmImage: 'Ubuntu-16.04'
|
|
||||||
environment: 'linux-dev'
|
|
||||||
strategy:
|
|
||||||
runOnce:
|
|
||||||
deploy:
|
|
||||||
steps:
|
|
||||||
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
|
||||||
clean: true # whether to fetch clean each time
|
|
||||||
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
|
||||||
# go version 1.12.7
|
|
||||||
- script: |
|
|
||||||
wget "https://storage.googleapis.com/golang/go1.12.7.linux-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
|
||||||
tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
|
||||||
displayName: 'Install Go 1.12.7 Linux'
|
|
||||||
- script: |
|
|
||||||
mkdir -p '$(GOBIN)'
|
|
||||||
mkdir -p '$(GOPATH)/pkg'
|
|
||||||
mkdir -p '$(GOROOT)'
|
|
||||||
shopt -s extglob
|
|
||||||
shopt -s dotglob
|
|
||||||
echo '##vso[task.prependpath]$(GOBIN)'
|
|
||||||
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
|
||||||
displayName: 'Set up the Go workspace'
|
|
||||||
- script: |
|
|
||||||
go version
|
|
||||||
go get -v -d ./...
|
|
||||||
cd cmd/wails
|
|
||||||
go install
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Get dependencies, then build'
|
|
||||||
- script: |
|
|
||||||
wails version
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Check we have output'
|
|
||||||
|
|
||||||
- deployment: Mac
|
|
||||||
displayName: Mac
|
|
||||||
variables:
|
|
||||||
GOPATH: '$(Agent.BuildDirectory)/gopath' # Go workspace path
|
|
||||||
GOROOT: '$(Agent.BuildDirectory)/go' # Go installation path
|
|
||||||
GOBIN: '$(GOPATH)/bin' # Go binaries path
|
|
||||||
GOMODULE: 'on'
|
|
||||||
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
|
||||||
pool:
|
|
||||||
vmImage: 'macOS-10.14'
|
|
||||||
environment: 'mac-dev'
|
|
||||||
strategy:
|
|
||||||
runOnce:
|
|
||||||
deploy:
|
|
||||||
steps:
|
|
||||||
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
|
||||||
clean: true # whether to fetch clean each time
|
|
||||||
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
|
||||||
# go version 1.12.7
|
|
||||||
- script: |
|
|
||||||
wget "https://storage.googleapis.com/golang/go1.12.7.darwin-amd64.tar.gz" --output-document "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
|
||||||
tar -C '$(Agent.BuildDirectory)' -xzf "$(Agent.BuildDirectory)/go1.12.7.tar.gz"
|
|
||||||
displayName: 'Install Go 1.12.7 Linux'
|
|
||||||
- script: |
|
|
||||||
mkdir -p '$(GOBIN)'
|
|
||||||
mkdir -p '$(GOPATH)/pkg'
|
|
||||||
mkdir -p '$(GOROOT)'
|
|
||||||
shopt -s extglob
|
|
||||||
shopt -s dotglob
|
|
||||||
echo '##vso[task.prependpath]$(GOBIN)'
|
|
||||||
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
|
||||||
displayName: 'Set up the Go workspace'
|
|
||||||
- script: |
|
|
||||||
go version
|
|
||||||
go get -v -d ./...
|
|
||||||
cd cmd/wails
|
|
||||||
go install
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Get dependencies, then build'
|
|
||||||
- script: |
|
|
||||||
wails version
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Check we have output'
|
|
||||||
|
|
||||||
- deployment: Win
|
|
||||||
displayName: Win
|
|
||||||
variables:
|
|
||||||
GOMODULE: 'on'
|
|
||||||
modulePath: '$(Agent.BuildDirectory)/wails' # Path to the module's code
|
|
||||||
pool:
|
|
||||||
vmImage: 'windows-2019'
|
|
||||||
environment: 'win-dev'
|
|
||||||
strategy:
|
|
||||||
runOnce:
|
|
||||||
deploy:
|
|
||||||
steps:
|
|
||||||
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
|
|
||||||
clean: true # whether to fetch clean each time
|
|
||||||
path: wails # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
|
|
||||||
# Go tool installer
|
|
||||||
# Find in cache or download a specific version of Go and add it to the PATH
|
|
||||||
- task: GoTool@0
|
|
||||||
inputs:
|
|
||||||
version: '1.12.7'
|
|
||||||
goPath: '$(Agent.BuildDirectory)/go'
|
|
||||||
goBin: '$(Agent.BuildDirectory)/go/bin'
|
|
||||||
displayName: 'Set up the Go workspace'
|
|
||||||
- script: |
|
|
||||||
go version
|
|
||||||
go get -v -d ./...
|
|
||||||
cd cmd/wails
|
|
||||||
go install
|
|
||||||
workingDirectory: '$(modulePath)'
|
|
||||||
displayName: 'Get dependencies, then build'
|
|
||||||
- script: |
|
|
||||||
wails version
|
|
||||||
workingDirectory: '$(Agent.BuildDirectory)/go/bin'
|
|
||||||
displayName: 'Check we have output'
|
|
||||||
File diff suppressed because one or more lines are too long
27
cmd/fs.go
27
cmd/fs.go
@@ -12,6 +12,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
)
|
)
|
||||||
@@ -47,6 +48,22 @@ func (fs *FSHelper) FileExists(path string) bool {
|
|||||||
return fi.Mode().IsRegular()
|
return fi.Mode().IsRegular()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindFile returns the first occurrence of match inside path.
|
||||||
|
func (fs *FSHelper) FindFile(path, match string) (string, error) {
|
||||||
|
files, err := ioutil.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
if !f.IsDir() && strings.Contains(f.Name(), match) {
|
||||||
|
return f.Name(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("file not found")
|
||||||
|
}
|
||||||
|
|
||||||
// CreateFile creates a file at the given filename location with the contents
|
// CreateFile creates a file at the given filename location with the contents
|
||||||
// set to the given data. It will create intermediary directories if needed.
|
// set to the given data. It will create intermediary directories if needed.
|
||||||
func (fs *FSHelper) CreateFile(filename string, data []byte) error {
|
func (fs *FSHelper) CreateFile(filename string, data []byte) error {
|
||||||
@@ -132,6 +149,16 @@ func (fs *FSHelper) LocalDir(dir string) (*Dir, error) {
|
|||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadRelativeFile loads the given file relative to the caller's directory
|
||||||
|
func (fs *FSHelper) LoadRelativeFile(relativePath string) ([]byte, error) {
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
fullPath, err := filepath.Abs(filepath.Join(path.Dir(filename), relativePath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ioutil.ReadFile(fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
// GetSubdirs will return a list of FQPs to subdirectories in the given directory
|
// GetSubdirs will return a list of FQPs to subdirectories in the given directory
|
||||||
func (d *Dir) GetSubdirs() (map[string]string, error) {
|
func (d *Dir) GetSubdirs() (map[string]string, error) {
|
||||||
|
|
||||||
|
|||||||
78
cmd/gomod.go
Normal file
78
cmd/gomod.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetWailsVersion() (*semver.Version, error) {
|
||||||
|
var FS = NewFSHelper()
|
||||||
|
var result *semver.Version
|
||||||
|
|
||||||
|
// Load file
|
||||||
|
var err error
|
||||||
|
goModFile, err := filepath.Abs(filepath.Join(".", "go.mod"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to load go.mod at %s", goModFile)
|
||||||
|
}
|
||||||
|
goMod, err := FS.LoadAsString(goModFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to load go.mod")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find wails version
|
||||||
|
versionRegexp := regexp.MustCompile(`.*github.com/wailsapp/wails.*(v\d+.\d+.\d+(?:-pre\d+)?)`)
|
||||||
|
versions := versionRegexp.FindStringSubmatch(goMod)
|
||||||
|
|
||||||
|
if len(versions) != 2 {
|
||||||
|
return nil, fmt.Errorf("Unable to determine Wails version")
|
||||||
|
}
|
||||||
|
|
||||||
|
version := versions[1]
|
||||||
|
result, err = semver.NewVersion(version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse Wails version: %s", version)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCurrentVersion() (*semver.Version, error) {
|
||||||
|
result, err := semver.NewVersion(Version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse Wails version: %s", Version)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GoModOutOfSync() (bool, error) {
|
||||||
|
gomodversion, err := GetWailsVersion()
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
currentVersion, err := GetCurrentVersion()
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
result := !currentVersion.Equal(gomodversion)
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateGoModVersion() error {
|
||||||
|
currentVersion, err := GetCurrentVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
currentVersionString := currentVersion.String()
|
||||||
|
|
||||||
|
requireLine := "-require=github.com/wailsapp/wails@v" + currentVersionString
|
||||||
|
|
||||||
|
// Issue: go mod edit -require=github.com/wailsapp/wails@1.0.2-pre5
|
||||||
|
helper := NewProgramHelper()
|
||||||
|
command := []string{"go", "mod", "edit", requireLine}
|
||||||
|
return helper.RunCommandArray(command)
|
||||||
|
|
||||||
|
}
|
||||||
258
cmd/helpers.go
258
cmd/helpers.go
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/leaanthony/mewn"
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/leaanthony/mewn/lib"
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/leaanthony/spinner"
|
"github.com/leaanthony/spinner"
|
||||||
)
|
)
|
||||||
@@ -36,35 +37,88 @@ 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(verbose bool) error {
|
||||||
depSpinner := spinner.New("Ensuring Dependencies are up to date...")
|
var depSpinner *spinner.Spinner
|
||||||
depSpinner.SetSpinSpeed(50)
|
if !verbose {
|
||||||
depSpinner.Start()
|
depSpinner = spinner.New("Ensuring Dependencies are up to date...")
|
||||||
err := NewProgramHelper().RunCommand("go get")
|
depSpinner.SetSpinSpeed(50)
|
||||||
|
depSpinner.Start()
|
||||||
|
}
|
||||||
|
err := NewProgramHelper(verbose).RunCommand("go get")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
depSpinner.Error()
|
if !verbose {
|
||||||
|
depSpinner.Error()
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
depSpinner.Success()
|
if !verbose {
|
||||||
|
depSpinner.Success()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmbedAssets will embed the built frontend assets via mewn.
|
||||||
|
func EmbedAssets() ([]string, error) {
|
||||||
|
mewnFiles := lib.GetMewnFiles([]string{}, false)
|
||||||
|
|
||||||
|
referencedAssets, err := lib.GetReferencedAssets(mewnFiles)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetFiles := []string{}
|
||||||
|
|
||||||
|
for _, referencedAsset := range referencedAssets {
|
||||||
|
packfileData, err := lib.GeneratePackFileString(referencedAsset, false)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
targetFile := filepath.Join(referencedAsset.BaseDir, referencedAsset.PackageName+"-mewn.go")
|
||||||
|
targetFiles = append(targetFiles, targetFile)
|
||||||
|
ioutil.WriteFile(targetFile, []byte(packfileData), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetFiles, nil
|
||||||
|
}
|
||||||
|
|
||||||
// BuildApplication will attempt to build the project based on the given inputs
|
// BuildApplication will attempt to build the project based on the given inputs
|
||||||
func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error {
|
func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error {
|
||||||
|
|
||||||
|
if buildMode == BuildModeBridge && projectOptions.CrossCompile {
|
||||||
|
return fmt.Errorf("you cant serve the application in cross-compilation")
|
||||||
|
}
|
||||||
|
|
||||||
// Generate Windows assets if needed
|
// Generate Windows assets if needed
|
||||||
if runtime.GOOS == "windows" {
|
if projectOptions.Platform == "windows" {
|
||||||
cleanUp := !packageApp
|
cleanUp := !packageApp
|
||||||
err := NewPackageHelper().PackageWindows(projectOptions, cleanUp)
|
err := NewPackageHelper(projectOptions.Platform).PackageWindows(projectOptions, cleanUp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Mewn is installed
|
if projectOptions.CrossCompile {
|
||||||
err := CheckMewn()
|
// Check build directory
|
||||||
if err != nil {
|
buildDirectory := filepath.Join(fs.Cwd(), "build")
|
||||||
return err
|
if !fs.DirExists(buildDirectory) {
|
||||||
|
fs.MkDir(buildDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Docker
|
||||||
|
if err := CheckIfInstalled("docker"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check xgo
|
||||||
|
if err := CheckIfInstalled("xgo"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check Mewn is installed
|
||||||
|
err := CheckMewn(projectOptions.Verbose)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compileMessage := "Packing + Compiling project"
|
compileMessage := "Packing + Compiling project"
|
||||||
@@ -73,21 +127,47 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
|||||||
compileMessage += " (Debug Mode)"
|
compileMessage += " (Debug Mode)"
|
||||||
}
|
}
|
||||||
|
|
||||||
packSpinner := spinner.New(compileMessage + "...")
|
var packSpinner *spinner.Spinner
|
||||||
packSpinner.SetSpinSpeed(50)
|
if !projectOptions.Verbose {
|
||||||
packSpinner.Start()
|
packSpinner = spinner.New(compileMessage + "...")
|
||||||
|
packSpinner.SetSpinSpeed(50)
|
||||||
|
packSpinner.Start()
|
||||||
|
} else {
|
||||||
|
println(compileMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// embed resources
|
||||||
|
targetFiles, err := EmbedAssets()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup temporary embedded assets
|
||||||
|
defer func() {
|
||||||
|
for _, filename := range targetFiles {
|
||||||
|
if err := os.Remove(filename); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
buildCommand := slicer.String()
|
buildCommand := slicer.String()
|
||||||
buildCommand.Add("mewn")
|
if projectOptions.CrossCompile {
|
||||||
|
buildCommand.Add("xgo")
|
||||||
|
} else {
|
||||||
|
buildCommand.Add("mewn")
|
||||||
|
}
|
||||||
|
|
||||||
if buildMode == BuildModeBridge {
|
if buildMode == BuildModeBridge {
|
||||||
// Ignore errors
|
// Ignore errors
|
||||||
buildCommand.Add("-i")
|
buildCommand.Add("-i")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildCommand.Add("build")
|
if !projectOptions.CrossCompile {
|
||||||
|
buildCommand.Add("build")
|
||||||
|
}
|
||||||
|
|
||||||
if binaryName != "" {
|
if binaryName != "" && !projectOptions.CrossCompile {
|
||||||
// Alter binary name based on OS
|
// Alter binary name based on OS
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "windows":
|
case "windows":
|
||||||
@@ -99,12 +179,11 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
|||||||
binaryName = strings.TrimSuffix(binaryName, ".exe")
|
binaryName = strings.TrimSuffix(binaryName, ".exe")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildCommand.Add("-o")
|
buildCommand.Add("-o", binaryName)
|
||||||
buildCommand.Add(binaryName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are forcing a rebuild
|
// If we are forcing a rebuild
|
||||||
if forceRebuild {
|
if forceRebuild && !projectOptions.CrossCompile {
|
||||||
buildCommand.Add("-a")
|
buildCommand.Add("-a")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,19 +194,40 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add windows flags
|
// Add windows flags
|
||||||
if runtime.GOOS == "windows" && buildMode == BuildModeProd {
|
if projectOptions.Platform == "windows" && buildMode == BuildModeProd {
|
||||||
ldflags += "-H windowsgui "
|
ldflags += "-H windowsgui "
|
||||||
}
|
}
|
||||||
|
|
||||||
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
|
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
|
||||||
|
|
||||||
|
// If we wish to generate typescript
|
||||||
|
if projectOptions.typescriptDefsFilename != "" {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
filename := filepath.Join(cwd, projectOptions.FrontEnd.Dir, projectOptions.typescriptDefsFilename)
|
||||||
|
ldflags += " -X github.com/wailsapp/wails/lib/binding.typescriptDefinitionFilename=" + filename
|
||||||
|
}
|
||||||
|
|
||||||
buildCommand.AddSlice([]string{"-ldflags", ldflags})
|
buildCommand.AddSlice([]string{"-ldflags", ldflags})
|
||||||
err = NewProgramHelper().RunCommandArray(buildCommand.AsSlice())
|
|
||||||
|
if projectOptions.CrossCompile {
|
||||||
|
buildCommand.Add("-targets", projectOptions.Platform+"/"+projectOptions.Architecture)
|
||||||
|
buildCommand.Add("-out", "build/"+binaryName)
|
||||||
|
buildCommand.Add("./")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = NewProgramHelper(projectOptions.Verbose).RunCommandArray(buildCommand.AsSlice())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
packSpinner.Error()
|
if packSpinner != nil {
|
||||||
|
packSpinner.Error()
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
packSpinner.Success()
|
if packSpinner != nil {
|
||||||
|
packSpinner.Success()
|
||||||
|
}
|
||||||
|
|
||||||
// packageApp
|
// packageApp
|
||||||
if packageApp {
|
if packageApp {
|
||||||
@@ -144,52 +244,78 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
|||||||
func PackageApplication(projectOptions *ProjectOptions) error {
|
func PackageApplication(projectOptions *ProjectOptions) error {
|
||||||
// Package app
|
// Package app
|
||||||
message := "Generating .app"
|
message := "Generating .app"
|
||||||
if runtime.GOOS == "windows" {
|
if projectOptions.Platform == "windows" {
|
||||||
err := CheckWindres()
|
err := CheckWindres()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
message = "Generating resource bundle"
|
message = "Generating resource bundle"
|
||||||
}
|
}
|
||||||
packageSpinner := spinner.New(message)
|
var packageSpinner *spinner.Spinner
|
||||||
packageSpinner.SetSpinSpeed(50)
|
if !projectOptions.Verbose {
|
||||||
packageSpinner.Start()
|
packageSpinner = spinner.New(message)
|
||||||
err := NewPackageHelper().Package(projectOptions)
|
packageSpinner.SetSpinSpeed(50)
|
||||||
|
packageSpinner.Start()
|
||||||
|
} else {
|
||||||
|
println(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := NewPackageHelper(projectOptions.Platform).Package(projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
packageSpinner.Error()
|
if packageSpinner != nil {
|
||||||
|
packageSpinner.Error()
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
packageSpinner.Success()
|
if packageSpinner != nil {
|
||||||
|
packageSpinner.Success()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildFrontend runs the given build command
|
// BuildFrontend runs the given build command
|
||||||
func BuildFrontend(buildCommand string) error {
|
func BuildFrontend(projectOptions *ProjectOptions) error {
|
||||||
buildFESpinner := spinner.New("Building frontend...")
|
var buildFESpinner *spinner.Spinner
|
||||||
buildFESpinner.SetSpinSpeed(50)
|
if !projectOptions.Verbose {
|
||||||
buildFESpinner.Start()
|
buildFESpinner = spinner.New("Building frontend...")
|
||||||
err := NewProgramHelper().RunCommand(buildCommand)
|
buildFESpinner.SetSpinSpeed(50)
|
||||||
|
buildFESpinner.Start()
|
||||||
|
} else {
|
||||||
|
println("Building frontend...")
|
||||||
|
}
|
||||||
|
err := NewProgramHelper(projectOptions.Verbose).RunCommand(projectOptions.FrontEnd.Build)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buildFESpinner.Error()
|
if buildFESpinner != nil {
|
||||||
|
buildFESpinner.Error()
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buildFESpinner.Success()
|
if buildFESpinner != nil {
|
||||||
|
buildFESpinner.Success()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckMewn checks if mewn is installed and if not, attempts to fetch it
|
// CheckMewn checks if mewn is installed and if not, attempts to fetch it
|
||||||
func CheckMewn() (err error) {
|
func CheckMewn(verbose bool) (err error) {
|
||||||
programHelper := NewProgramHelper()
|
programHelper := NewProgramHelper(verbose)
|
||||||
if !programHelper.IsInstalled("mewn") {
|
if !programHelper.IsInstalled("mewn") {
|
||||||
buildSpinner := spinner.New()
|
var buildSpinner *spinner.Spinner
|
||||||
buildSpinner.SetSpinSpeed(50)
|
if !verbose {
|
||||||
buildSpinner.Start("Installing Mewn asset packer...")
|
buildSpinner = spinner.New()
|
||||||
|
buildSpinner.SetSpinSpeed(50)
|
||||||
|
buildSpinner.Start("Installing Mewn asset packer...")
|
||||||
|
}
|
||||||
err := programHelper.InstallGoPackage("github.com/leaanthony/mewn/cmd/mewn")
|
err := programHelper.InstallGoPackage("github.com/leaanthony/mewn/cmd/mewn")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buildSpinner.Error()
|
if buildSpinner != nil {
|
||||||
|
buildSpinner.Error()
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buildSpinner.Success()
|
if buildSpinner != nil {
|
||||||
|
buildSpinner.Success()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -206,6 +332,15 @@ func CheckWindres() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckIfInstalled returns if application is installed
|
||||||
|
func CheckIfInstalled(application string) (err error) {
|
||||||
|
programHelper := NewProgramHelper()
|
||||||
|
if !programHelper.IsInstalled(application) {
|
||||||
|
return fmt.Errorf("%s not installed. Ensure you have installed %s correctly", application, application)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// InstallFrontendDeps attempts to install the frontend dependencies based on the given options
|
// InstallFrontendDeps attempts to install the frontend dependencies based on the given options
|
||||||
func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forceRebuild bool, caller string) error {
|
func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forceRebuild bool, caller string) error {
|
||||||
|
|
||||||
@@ -216,9 +351,14 @@ 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)")
|
var feSpinner *spinner.Spinner
|
||||||
feSpinner.SetSpinSpeed(50)
|
if !projectOptions.Verbose {
|
||||||
feSpinner.Start()
|
feSpinner = spinner.New("Ensuring frontend dependencies are up to date (This may take a while)")
|
||||||
|
feSpinner.SetSpinSpeed(50)
|
||||||
|
feSpinner.Start()
|
||||||
|
} else {
|
||||||
|
println("Ensuring frontend dependencies are up to date (This may take a while)")
|
||||||
|
}
|
||||||
|
|
||||||
requiresNPMInstall := true
|
requiresNPMInstall := true
|
||||||
|
|
||||||
@@ -250,7 +390,11 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
|||||||
if savedMD5sum == packageJSONMD5 {
|
if savedMD5sum == packageJSONMD5 {
|
||||||
// Same - no need for reinstall
|
// Same - no need for reinstall
|
||||||
requiresNPMInstall = false
|
requiresNPMInstall = false
|
||||||
feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)")
|
if feSpinner != nil {
|
||||||
|
feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)")
|
||||||
|
} else {
|
||||||
|
println("Skipped frontend dependencies (-f to force rebuild)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,12 +403,16 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
|||||||
// Different? Build
|
// Different? Build
|
||||||
if requiresNPMInstall || forceRebuild {
|
if requiresNPMInstall || forceRebuild {
|
||||||
// Install dependencies
|
// Install dependencies
|
||||||
err = NewProgramHelper().RunCommand(projectOptions.FrontEnd.Install)
|
err = NewProgramHelper(projectOptions.Verbose).RunCommand(projectOptions.FrontEnd.Install)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
feSpinner.Error()
|
if feSpinner != nil {
|
||||||
|
feSpinner.Error()
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
feSpinner.Success()
|
if feSpinner != nil {
|
||||||
|
feSpinner.Success()
|
||||||
|
}
|
||||||
|
|
||||||
// Update md5sum file
|
// Update md5sum file
|
||||||
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
||||||
@@ -277,7 +425,7 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build frontend
|
// Build frontend
|
||||||
err = BuildFrontend(projectOptions.FrontEnd.Build)
|
err = BuildFrontend(projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
17
cmd/linux.go
17
cmd/linux.go
@@ -43,8 +43,16 @@ const (
|
|||||||
Kali
|
Kali
|
||||||
// Neon distribution
|
// Neon distribution
|
||||||
Neon
|
Neon
|
||||||
|
// ArcoLinux distribution
|
||||||
|
ArcoLinux
|
||||||
// Manjaro distribution
|
// Manjaro distribution
|
||||||
Manjaro
|
Manjaro
|
||||||
|
// ManjaroARM distribution
|
||||||
|
ManjaroARM
|
||||||
|
// Deepin distribution
|
||||||
|
Deepin
|
||||||
|
// Raspbian distribution
|
||||||
|
Raspbian
|
||||||
)
|
)
|
||||||
|
|
||||||
// DistroInfo contains all the information relating to a linux distribution
|
// DistroInfo contains all the information relating to a linux distribution
|
||||||
@@ -100,6 +108,7 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
|||||||
version = strings.Trim(splitLine[1], "\"")
|
version = strings.Trim(splitLine[1], "\"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check distro name against list of distros
|
// Check distro name against list of distros
|
||||||
switch osID {
|
switch osID {
|
||||||
case "fedora":
|
case "fedora":
|
||||||
@@ -128,8 +137,16 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
|||||||
result.Distribution = Kali
|
result.Distribution = Kali
|
||||||
case "neon":
|
case "neon":
|
||||||
result.Distribution = Neon
|
result.Distribution = Neon
|
||||||
|
case "arcolinux":
|
||||||
|
result.Distribution = ArcoLinux
|
||||||
case "manjaro":
|
case "manjaro":
|
||||||
result.Distribution = Manjaro
|
result.Distribution = Manjaro
|
||||||
|
case "manjaro-arm":
|
||||||
|
result.Distribution = ManjaroARM
|
||||||
|
case "deepin":
|
||||||
|
result.Distribution = Deepin
|
||||||
|
case "raspbian":
|
||||||
|
result.Distribution = Raspbian
|
||||||
default:
|
default:
|
||||||
result.Distribution = Unknown
|
result.Distribution = Unknown
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/leaanthony/mewn"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -79,11 +78,14 @@ func (l *LinuxDB) GetDistro(distro string) *Distribution {
|
|||||||
// NewLinuxDB creates a new LinuxDB instance from the bundled
|
// NewLinuxDB creates a new LinuxDB instance from the bundled
|
||||||
// linuxdb.yaml file.
|
// linuxdb.yaml file.
|
||||||
func NewLinuxDB() *LinuxDB {
|
func NewLinuxDB() *LinuxDB {
|
||||||
data := mewn.Bytes("./linuxdb.yaml")
|
data, err := fs.LoadRelativeFile("./linuxdb.yaml")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Could not load linuxdb.yaml")
|
||||||
|
}
|
||||||
result := LinuxDB{
|
result := LinuxDB{
|
||||||
Distributions: make(map[string]*Distribution),
|
Distributions: make(map[string]*Distribution),
|
||||||
}
|
}
|
||||||
err := result.ImportData(data)
|
err = result.ImportData(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,15 @@ distributions:
|
|||||||
gccversioncommand: *gccdumpfullversion
|
gccversioncommand: *gccdumpfullversion
|
||||||
programs: *debiandefaultprograms
|
programs: *debiandefaultprograms
|
||||||
libraries: *debiandefaultlibraries
|
libraries: *debiandefaultlibraries
|
||||||
|
deepin:
|
||||||
|
id: deepin
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Deepin
|
||||||
|
gccversioncommand: *gccdumpfullversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
void:
|
void:
|
||||||
id: void
|
id: void
|
||||||
releases:
|
releases:
|
||||||
@@ -158,6 +167,15 @@ distributions:
|
|||||||
help: Please install with `sudo pacman -S gtk3` and try again
|
help: Please install with `sudo pacman -S gtk3` and try again
|
||||||
- name: webkit2gtk
|
- name: webkit2gtk
|
||||||
help: Please install with `sudo pacman -S webkit2gtk` and try again
|
help: Please install with `sudo pacman -S webkit2gtk` and try again
|
||||||
|
arcolinux:
|
||||||
|
id: arcolinux
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: ArcoLinux
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs: *archdefaultprograms
|
||||||
|
libraries: *archdefaultlibraries
|
||||||
manjaro:
|
manjaro:
|
||||||
id: manjaro
|
id: manjaro
|
||||||
releases:
|
releases:
|
||||||
@@ -167,6 +185,15 @@ distributions:
|
|||||||
gccversioncommand: *gccdumpversion
|
gccversioncommand: *gccdumpversion
|
||||||
programs: *archdefaultprograms
|
programs: *archdefaultprograms
|
||||||
libraries: *archdefaultlibraries
|
libraries: *archdefaultlibraries
|
||||||
|
manjaro-arm:
|
||||||
|
id: manjaro-arm
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Manjaro-ARM
|
||||||
|
gccversioncommand: *gccdumpversion
|
||||||
|
programs: *archdefaultprograms
|
||||||
|
libraries: *archdefaultlibraries
|
||||||
gentoo:
|
gentoo:
|
||||||
id: gentoo
|
id: gentoo
|
||||||
releases:
|
releases:
|
||||||
@@ -185,4 +212,14 @@ distributions:
|
|||||||
- name: gtk+:3
|
- name: gtk+:3
|
||||||
help: Please install with `sudo emerge gtk+:3` and try again
|
help: Please install with `sudo emerge gtk+:3` and try again
|
||||||
- name: webkit-gtk
|
- name: webkit-gtk
|
||||||
help: Please install with `sudo emerge webkit-gtk` and try again
|
help: Please install with `sudo emerge webkit-gtk` and try again
|
||||||
|
|
||||||
|
raspbian:
|
||||||
|
id: raspbian
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Raspbian
|
||||||
|
gccversioncommand: *gccdumpfullversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
|
|||||||
@@ -18,17 +18,19 @@ import (
|
|||||||
|
|
||||||
// PackageHelper helps with the 'wails package' command
|
// PackageHelper helps with the 'wails package' command
|
||||||
type PackageHelper struct {
|
type PackageHelper struct {
|
||||||
fs *FSHelper
|
platform string
|
||||||
log *Logger
|
fs *FSHelper
|
||||||
system *SystemHelper
|
log *Logger
|
||||||
|
system *SystemHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPackageHelper creates a new PackageHelper!
|
// NewPackageHelper creates a new PackageHelper!
|
||||||
func NewPackageHelper() *PackageHelper {
|
func NewPackageHelper(platform string) *PackageHelper {
|
||||||
return &PackageHelper{
|
return &PackageHelper{
|
||||||
fs: NewFSHelper(),
|
platform: platform,
|
||||||
log: NewLogger(),
|
fs: NewFSHelper(),
|
||||||
system: NewSystemHelper(),
|
log: NewLogger(),
|
||||||
|
system: NewSystemHelper(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,16 +65,23 @@ func defaultString(val string, defaultVal string) string {
|
|||||||
func (b *PackageHelper) getPackageFileBaseDir() string {
|
func (b *PackageHelper) getPackageFileBaseDir() string {
|
||||||
// Calculate template base dir
|
// Calculate template base dir
|
||||||
_, filename, _, _ := runtime.Caller(1)
|
_, filename, _, _ := runtime.Caller(1)
|
||||||
return filepath.Join(path.Dir(filename), "packages", runtime.GOOS)
|
return filepath.Join(path.Dir(filename), "packages", b.platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Package the application into a platform specific package
|
// Package the application into a platform specific package
|
||||||
func (b *PackageHelper) Package(po *ProjectOptions) error {
|
func (b *PackageHelper) Package(po *ProjectOptions) error {
|
||||||
switch runtime.GOOS {
|
switch b.platform {
|
||||||
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)
|
// Check cross-compiled application
|
||||||
|
if b.platform == runtime.GOOS {
|
||||||
|
return fmt.Errorf("cannot bundle non-existent binary file '%s'. Please build with 'wails build' first", po.BinaryName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := b.fs.FindFile(path.Join(b.fs.Cwd(), "build"), "darwin"); err != nil {
|
||||||
|
return fmt.Errorf("cannot bundle non-existent cross-compiled binary file '%s'. Please build with 'wails build -x darwin' first", po.BinaryName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return b.packageOSX(po)
|
return b.packageOSX(po)
|
||||||
case "windows":
|
case "windows":
|
||||||
@@ -80,7 +89,7 @@ func (b *PackageHelper) Package(po *ProjectOptions) error {
|
|||||||
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:
|
||||||
return fmt.Errorf("platform '%s' not supported for bundling yet", runtime.GOOS)
|
return fmt.Errorf("platform '%s' not supported for bundling yet", b.platform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +112,22 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
|
|||||||
|
|
||||||
// Check binary exists
|
// Check binary exists
|
||||||
source := path.Join(b.fs.Cwd(), exe)
|
source := path.Join(b.fs.Cwd(), exe)
|
||||||
|
|
||||||
|
if b.platform != runtime.GOOS {
|
||||||
|
|
||||||
|
file, err := b.fs.FindFile(path.Join(b.fs.Cwd(), "build"), "darwin")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// rename to exe
|
||||||
|
if err := os.Rename(path.Join(b.fs.Cwd(), "build", file), path.Join(b.fs.Cwd(), "build", exe)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
source = path.Join(b.fs.Cwd(), "build", exe)
|
||||||
|
}
|
||||||
|
|
||||||
if !b.fs.FileExists(source) {
|
if !b.fs.FileExists(source) {
|
||||||
// We need to build!
|
// We need to build!
|
||||||
return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", exe)
|
return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", exe)
|
||||||
@@ -192,16 +217,36 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
|
|||||||
// Build syso
|
// Build syso
|
||||||
sysofile := filepath.Join(b.fs.Cwd(), basename+"-res.syso")
|
sysofile := filepath.Join(b.fs.Cwd(), basename+"-res.syso")
|
||||||
|
|
||||||
batfile, err := fs.LocalDir(".")
|
// cross-compile
|
||||||
if err != nil {
|
if b.platform != runtime.GOOS {
|
||||||
return err
|
folder, err := os.Getwd()
|
||||||
}
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
windresBatFile := filepath.Join(batfile.fullPath, "windres.bat")
|
args := []string{
|
||||||
windresCommand := []string{windresBatFile, sysofile, tgtRCFile}
|
"docker", "run", "--rm",
|
||||||
err = NewProgramHelper().RunCommandArray(windresCommand)
|
"-v", folder + ":/build",
|
||||||
if err != nil {
|
"--entrypoint", "/bin/sh",
|
||||||
return err
|
"techknowlogick/xgo",
|
||||||
|
"-c", "/usr/bin/x86_64-w64-mingw32-windres -o /build/" + basename + "-res.syso /build/" + basename + ".rc",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := NewProgramHelper().RunCommandArray(args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
batfile, err := fs.LocalDir(".")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
windresBatFile := filepath.Join(batfile.fullPath, "windres.bat")
|
||||||
|
windresCommand := []string{windresBatFile, sysofile, tgtRCFile}
|
||||||
|
err = NewProgramHelper().RunCommandArray(windresCommand)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -11,14 +12,22 @@ import (
|
|||||||
|
|
||||||
// ProgramHelper - Utility functions around installed applications
|
// ProgramHelper - Utility functions around installed applications
|
||||||
type ProgramHelper struct {
|
type ProgramHelper struct {
|
||||||
shell *ShellHelper
|
shell *ShellHelper
|
||||||
|
verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProgramHelper - Creates a new ProgramHelper
|
// NewProgramHelper - Creates a new ProgramHelper
|
||||||
func NewProgramHelper() *ProgramHelper {
|
func NewProgramHelper(verbose ...bool) *ProgramHelper {
|
||||||
return &ProgramHelper{
|
result := &ProgramHelper{
|
||||||
shell: NewShellHelper(),
|
shell: NewShellHelper(),
|
||||||
}
|
}
|
||||||
|
if len(verbose) > 0 {
|
||||||
|
result.verbose = verbose[0]
|
||||||
|
if result.verbose {
|
||||||
|
result.shell.SetVerbose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsInstalled tries to determine if the given binary name is installed
|
// IsInstalled tries to determine if the given binary name is installed
|
||||||
@@ -29,8 +38,9 @@ func (p *ProgramHelper) IsInstalled(programName string) bool {
|
|||||||
|
|
||||||
// Program - A struct to define an installed application/binary
|
// Program - A struct to define an installed application/binary
|
||||||
type Program struct {
|
type Program struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
|
verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindProgram attempts to find the given program on the system.FindProgram
|
// FindProgram attempts to find the given program on the system.FindProgram
|
||||||
@@ -45,8 +55,9 @@ func (p *ProgramHelper) FindProgram(programName string) *Program {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &Program{
|
return &Program{
|
||||||
Name: programName,
|
Name: programName,
|
||||||
Path: path,
|
Path: path,
|
||||||
|
verbose: p.verbose,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,12 +74,18 @@ func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err
|
|||||||
return "", "", 1, err
|
return "", "", 1, err
|
||||||
}
|
}
|
||||||
cmd := exec.Command(command, vars...)
|
cmd := exec.Command(command, vars...)
|
||||||
var stdo, stde bytes.Buffer
|
if !p.verbose {
|
||||||
cmd.Stdout = &stdo
|
var stdo, stde bytes.Buffer
|
||||||
cmd.Stderr = &stde
|
cmd.Stdout = &stdo
|
||||||
err = cmd.Run()
|
cmd.Stderr = &stde
|
||||||
stdout = string(stdo.Bytes())
|
err = cmd.Run()
|
||||||
stderr = string(stde.Bytes())
|
stdout = string(stdo.Bytes())
|
||||||
|
stderr = string(stde.Bytes())
|
||||||
|
} else {
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/10385551/get-exit-code-go
|
// https://stackoverflow.com/questions/10385551/get-exit-code-go
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -142,21 +142,26 @@ 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
|
selectedTemplate *TemplateDetails
|
||||||
WailsVersion string
|
WailsVersion string
|
||||||
|
typescriptDefsFilename string
|
||||||
|
Verbose bool `json:"-"`
|
||||||
|
CrossCompile bool `json:"-"`
|
||||||
|
Platform string `json:"-"`
|
||||||
|
Architecture string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaults sets the default project template
|
// Defaults sets the default project template
|
||||||
@@ -165,6 +170,11 @@ func (po *ProjectOptions) Defaults() {
|
|||||||
po.WailsVersion = Version
|
po.WailsVersion = Version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTypescriptDefsFilename indicates that we want to generate typescript bindings to the given file
|
||||||
|
func (po *ProjectOptions) SetTypescriptDefsFilename(filename string) {
|
||||||
|
po.typescriptDefsFilename = filename
|
||||||
|
}
|
||||||
|
|
||||||
// GetNPMBinaryName returns the type of package manager used by the project
|
// GetNPMBinaryName returns the type of package manager used by the project
|
||||||
func (po *ProjectOptions) GetNPMBinaryName() (PackageManager, error) {
|
func (po *ProjectOptions) GetNPMBinaryName() (PackageManager, error) {
|
||||||
if po.FrontEnd == nil {
|
if po.FrontEnd == nil {
|
||||||
|
|||||||
42
cmd/shell.go
42
cmd/shell.go
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
// ShellHelper helps with Shell commands
|
// ShellHelper helps with Shell commands
|
||||||
type ShellHelper struct {
|
type ShellHelper struct {
|
||||||
|
verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewShellHelper creates a new ShellHelper!
|
// NewShellHelper creates a new ShellHelper!
|
||||||
@@ -15,16 +16,27 @@ func NewShellHelper() *ShellHelper {
|
|||||||
return &ShellHelper{}
|
return &ShellHelper{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetVerbose sets the verbose flag
|
||||||
|
func (sh *ShellHelper) SetVerbose() {
|
||||||
|
sh.verbose = true
|
||||||
|
}
|
||||||
|
|
||||||
// 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")
|
cmd.Env = append(os.Environ(), "GO111MODULE=on")
|
||||||
var stdo, stde bytes.Buffer
|
if !sh.verbose {
|
||||||
cmd.Stdout = &stdo
|
var stdo, stde bytes.Buffer
|
||||||
cmd.Stderr = &stde
|
cmd.Stdout = &stdo
|
||||||
err = cmd.Run()
|
cmd.Stderr = &stde
|
||||||
stdout = string(stdo.Bytes())
|
err = cmd.Run()
|
||||||
stderr = string(stde.Bytes())
|
stdout = string(stdo.Bytes())
|
||||||
|
stderr = string(stde.Bytes())
|
||||||
|
} else {
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,11 +45,17 @@ func (sh *ShellHelper) RunInDirectory(dir string, command string, vars ...string
|
|||||||
cmd := exec.Command(command, vars...)
|
cmd := exec.Command(command, vars...)
|
||||||
cmd.Dir = dir
|
cmd.Dir = dir
|
||||||
cmd.Env = append(os.Environ(), "GO111MODULE=on")
|
cmd.Env = append(os.Environ(), "GO111MODULE=on")
|
||||||
var stdo, stde bytes.Buffer
|
if !sh.verbose {
|
||||||
cmd.Stdout = &stdo
|
var stdo, stde bytes.Buffer
|
||||||
cmd.Stderr = &stde
|
cmd.Stdout = &stdo
|
||||||
err = cmd.Run()
|
cmd.Stderr = &stde
|
||||||
stdout = string(stdo.Bytes())
|
err = cmd.Run()
|
||||||
stderr = string(stde.Bytes())
|
stdout = string(stdo.Bytes())
|
||||||
|
stderr = string(stde.Bytes())
|
||||||
|
} else {
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,9 +274,9 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
|||||||
distroInfo := GetLinuxDistroInfo()
|
distroInfo := GetLinuxDistroInfo()
|
||||||
|
|
||||||
switch distroInfo.Distribution {
|
switch distroInfo.Distribution {
|
||||||
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon:
|
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian:
|
||||||
libraryChecker = DpkgInstalled
|
libraryChecker = DpkgInstalled
|
||||||
case Arch, Manjaro:
|
case Arch, ArcoLinux, Manjaro, ManjaroARM:
|
||||||
libraryChecker = PacmanInstalled
|
libraryChecker = PacmanInstalled
|
||||||
case CentOS, Fedora:
|
case CentOS, Fedora:
|
||||||
libraryChecker = RpmInstalled
|
libraryChecker = RpmInstalled
|
||||||
|
|||||||
@@ -9,4 +9,4 @@
|
|||||||
last 2 versions
|
last 2 versions
|
||||||
Firefox ESR
|
Firefox ESR
|
||||||
not dead
|
not dead
|
||||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "npx ng",
|
"ng": "npx ng",
|
||||||
"start": "npx ng serve --poll=2000",
|
"start": "npx ng serve --poll=2000 --host=0.0.0.0",
|
||||||
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
|
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
|
||||||
"test": "npx ng test",
|
"test": "npx ng test",
|
||||||
"lint": "npx ng lint",
|
"lint": "npx ng lint",
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"@angular/platform-browser-dynamic": "~8.0.1",
|
"@angular/platform-browser-dynamic": "~8.0.1",
|
||||||
"@angular/router": "~8.0.1",
|
"@angular/router": "~8.0.1",
|
||||||
"@wailsapp/runtime": "^1.0.0",
|
"@wailsapp/runtime": "^1.0.0",
|
||||||
|
"core-js": "^3.4.4",
|
||||||
"ngx-build-plus": "^8.0.3",
|
"ngx-build-plus": "^8.0.3",
|
||||||
"rxjs": "~6.4.0",
|
"rxjs": "~6.4.0",
|
||||||
"tslib": "^1.9.0",
|
"tslib": "^1.9.0",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'core-js/stable';
|
||||||
import { enableProdMode } from '@angular/core';
|
import { enableProdMode } from '@angular/core';
|
||||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"target": "es2015",
|
"target": "es5",
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"node_modules/@types"
|
"node_modules/@types"
|
||||||
],
|
],
|
||||||
@@ -20,4 +20,4 @@
|
|||||||
"dom"
|
"dom"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ func basic() string {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
js := mewn.String("./frontend/dist/my-app/main-es2015.js")
|
js := mewn.String("./frontend/dist/my-app/main.js")
|
||||||
css := mewn.String("./frontend/dist/my-app/styles.css")
|
css := mewn.String("./frontend/dist/my-app/styles.css")
|
||||||
|
|
||||||
app := wails.CreateApp(&wails.AppConfig{
|
app := wails.CreateApp(&wails.AppConfig{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue/app'
|
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^2.6.4",
|
"core-js": "^3.6.1",
|
||||||
|
"regenerator-runtime": "^0.13.3",
|
||||||
"vue": "^2.5.22",
|
"vue": "^2.5.22",
|
||||||
"@wailsapp/runtime": "^1.0.0"
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'core-js/stable';
|
||||||
|
import 'regenerator-runtime/runtime';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
disableHostCheck: true,
|
disableHostCheck: true
|
||||||
host: "localhost"
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue/app'
|
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel-polyfill": "^6.26.0",
|
"core-js": "^3.6.1",
|
||||||
"core-js": "^2.6.4",
|
"regenerator-runtime": "^0.13.3",
|
||||||
"material-design-icons-iconfont": "^5.0.1",
|
"material-design-icons-iconfont": "^5.0.1",
|
||||||
"vue": "^2.5.22",
|
"vue": "^2.5.22",
|
||||||
"vuetify": "^1.5.14",
|
"vuetify": "^1.5.14",
|
||||||
@@ -50,4 +50,4 @@
|
|||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
"not ie <= 8"
|
"not ie <= 8"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'babel-polyfill';
|
import 'core-js/stable';
|
||||||
|
import 'regenerator-runtime/runtime';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
// Setup Vuetify
|
// Setup Vuetify
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
disableHostCheck: true,
|
disableHostCheck: true
|
||||||
host: "localhost"
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "Vuetify Basic",
|
"name": "Vuetify1.5/Webpack Basic",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"shortdescription": "Vuetify + Webpack",
|
"shortdescription": "A basic Vuetify1.5/Webpack4 template",
|
||||||
"description": "Basic template using Vuetify and bundled using Webpack",
|
"description": "Basic template using Vuetify v1.5 and bundled using Webpack",
|
||||||
"install": "npm install",
|
"install": "npm install",
|
||||||
"build": "npm run build",
|
"build": "npm run build",
|
||||||
"author": "lea <lea.anthony@gmail.com>",
|
"author": "lea <lea.anthony@gmail.com>",
|
||||||
@@ -11,4 +11,4 @@
|
|||||||
"serve": "npm run serve",
|
"serve": "npm run serve",
|
||||||
"bridge": "src",
|
"bridge": "src",
|
||||||
"wailsdir": ""
|
"wailsdir": ""
|
||||||
}
|
}
|
||||||
|
|||||||
3
cmd/templates/vuetify2-basic/.jshint
Normal file
3
cmd/templates/vuetify2-basic/.jshint
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"esversion": 6
|
||||||
|
}
|
||||||
21
cmd/templates/vuetify2-basic/frontend/.gitignore
vendored
Normal file
21
cmd/templates/vuetify2-basic/frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw*
|
||||||
5
cmd/templates/vuetify2-basic/frontend/babel.config.js
Normal file
5
cmd/templates/vuetify2-basic/frontend/babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||||
|
]
|
||||||
|
};
|
||||||
53
cmd/templates/vuetify2-basic/frontend/package.json.template
Normal file
53
cmd/templates/vuetify2-basic/frontend/package.json.template
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"name": "{{.NPMProjectName}}",
|
||||||
|
"author": "{{.Author.Name}}<{{.Author.Email}}>",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"core-js": "^3.6.1",
|
||||||
|
"regenerator-runtime": "^0.13.3",
|
||||||
|
"vue": "^2.5.22",
|
||||||
|
"vuetify": "^2.0.15",
|
||||||
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@mdi/font": "^4.3.95",
|
||||||
|
"@vue/cli-plugin-babel": "^3.4.0",
|
||||||
|
"@vue/cli-plugin-eslint": "^3.4.0",
|
||||||
|
"@vue/cli-service": "^3.4.0",
|
||||||
|
"babel-eslint": "^10.0.1",
|
||||||
|
"eslint": "^5.8.0",
|
||||||
|
"eslint-plugin-vue": "^5.0.0",
|
||||||
|
"eventsource-polyfill": "^0.9.6",
|
||||||
|
"vue-template-compiler": "^2.5.21",
|
||||||
|
"webpack-hot-middleware": "^2.24.3"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"rules": {},
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"plugins": {
|
||||||
|
"autoprefixer": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
|
}
|
||||||
60
cmd/templates/vuetify2-basic/frontend/src/App.vue
Normal file
60
cmd/templates/vuetify2-basic/frontend/src/App.vue
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<v-app id="inspire">
|
||||||
|
<v-navigation-drawer v-model="drawer" clipped fixed app>
|
||||||
|
<v-list dense>
|
||||||
|
<v-list-item>
|
||||||
|
<v-list-item-icon>
|
||||||
|
<v-icon>mdi-view-dashboard</v-icon>
|
||||||
|
</v-list-item-icon>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title>Dashboard</v-list-item-title>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item>
|
||||||
|
<v-list-item-icon>
|
||||||
|
<v-icon>mdi-settings</v-icon>
|
||||||
|
</v-list-item-icon>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title>Settings</v-list-item-title>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-navigation-drawer>
|
||||||
|
<v-app-bar app fixed clipped-left>
|
||||||
|
<v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
|
||||||
|
<v-toolbar-title>Application</v-toolbar-title>
|
||||||
|
</v-app-bar>
|
||||||
|
<v-content>
|
||||||
|
<v-container fluid class="px-0">
|
||||||
|
<v-layout justify-center align-center class="px-0">
|
||||||
|
<hello-world></hello-world>
|
||||||
|
</v-layout>
|
||||||
|
</v-container>
|
||||||
|
</v-content>
|
||||||
|
<v-footer app fixed>
|
||||||
|
<span style="margin-left:1em">© You</span>
|
||||||
|
</v-footer>
|
||||||
|
</v-app>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HelloWorld from "./components/HelloWorld.vue"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
drawer: false
|
||||||
|
}),
|
||||||
|
components: {
|
||||||
|
HelloWorld
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
source: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.logo {
|
||||||
|
width: 16em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
BIN
cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png
Normal file
BIN
cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 301 KiB |
@@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<v-container fluid class="px-0">
|
||||||
|
<v-layout>
|
||||||
|
<v-flex xs12 sm6 offset-sm3>
|
||||||
|
<v-card raised="raised" class="pa-4 ma-4">
|
||||||
|
<v-layout justify-center align-center class="pa-4 ma-4">
|
||||||
|
<v-img :src="require('../assets/images/logo.png')"></v-img>
|
||||||
|
</v-layout>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-layout justify-center align-center class="px-0">
|
||||||
|
<v-btn color="blue" @click="getMessage">Press Me</v-btn>
|
||||||
|
</v-layout>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-flex>
|
||||||
|
</v-layout>
|
||||||
|
<div class="text-xs-center">
|
||||||
|
<v-dialog v-model="dialog" width="500">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="headline" primary-title>Message from Go</v-card-title>
|
||||||
|
<v-card-text>{{message}}</v-card-text>
|
||||||
|
<v-divider></v-divider>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="primary" text @click="dialog = false">Awesome</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
</v-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
message: " ",
|
||||||
|
raised: true,
|
||||||
|
dialog: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMessage: function () {
|
||||||
|
var self = this
|
||||||
|
window.backend.basic().then(result => {
|
||||||
|
self.message = result
|
||||||
|
self.dialog = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
h1 {
|
||||||
|
margin-top: 2em;
|
||||||
|
position: relative;
|
||||||
|
min-height: 5rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
font-size: 1.7em;
|
||||||
|
border-color: blue;
|
||||||
|
background-color: blue;
|
||||||
|
color: white;
|
||||||
|
border: 3px solid white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: 500ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 1.7em;
|
||||||
|
border-color: white;
|
||||||
|
background-color: #121212;
|
||||||
|
color: white;
|
||||||
|
border: 3px solid white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
29
cmd/templates/vuetify2-basic/frontend/src/main.js
Normal file
29
cmd/templates/vuetify2-basic/frontend/src/main.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import 'core-js/stable';
|
||||||
|
import 'regenerator-runtime/runtime';
|
||||||
|
import '@mdi/font/css/materialdesignicons.css';
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Vuetify from 'vuetify';
|
||||||
|
import 'vuetify/dist/vuetify.min.css';
|
||||||
|
|
||||||
|
Vue.use(Vuetify);
|
||||||
|
|
||||||
|
import App from './App.vue';
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
Vue.config.devtools = true;
|
||||||
|
|
||||||
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
|
Wails.Init(() => {
|
||||||
|
new Vue({
|
||||||
|
vuetify: new Vuetify({
|
||||||
|
icons: {
|
||||||
|
iconfont: 'mdi'
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
dark: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app');
|
||||||
|
});
|
||||||
42
cmd/templates/vuetify2-basic/frontend/vue.config.js
Normal file
42
cmd/templates/vuetify2-basic/frontend/vue.config.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
let cssConfig = {};
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV == 'production') {
|
||||||
|
cssConfig = {
|
||||||
|
extract: {
|
||||||
|
filename: '[name].css',
|
||||||
|
chunkFilename: '[name].css'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
chainWebpack: config => {
|
||||||
|
let limit = 9999999999999999;
|
||||||
|
config.module
|
||||||
|
.rule('images')
|
||||||
|
.test(/\.(png|gif|jpg)(\?.*)?$/i)
|
||||||
|
.use('url-loader')
|
||||||
|
.loader('url-loader')
|
||||||
|
.tap(options => Object.assign(options, { limit: limit }));
|
||||||
|
config.module
|
||||||
|
.rule('fonts')
|
||||||
|
.test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i)
|
||||||
|
.use('url-loader')
|
||||||
|
.loader('url-loader')
|
||||||
|
.options({
|
||||||
|
limit: limit
|
||||||
|
});
|
||||||
|
},
|
||||||
|
css: cssConfig,
|
||||||
|
configureWebpack: {
|
||||||
|
output: {
|
||||||
|
filename: '[name].js'
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
splitChunks: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
disableHostCheck: true
|
||||||
|
}
|
||||||
|
};
|
||||||
5
cmd/templates/vuetify2-basic/go.mod.template
Normal file
5
cmd/templates/vuetify2-basic/go.mod.template
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module {{.BinaryName}}
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/wailsapp/wails {{.WailsVersion}}
|
||||||
|
)
|
||||||
27
cmd/templates/vuetify2-basic/main.go.template
Normal file
27
cmd/templates/vuetify2-basic/main.go.template
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/wailsapp/wails"
|
||||||
|
)
|
||||||
|
|
||||||
|
func basic() string {
|
||||||
|
return "Hello World!"
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
js := mewn.String("./frontend/dist/app.js")
|
||||||
|
css := mewn.String("./frontend/dist/app.css")
|
||||||
|
|
||||||
|
app := wails.CreateApp(&wails.AppConfig{
|
||||||
|
Width: 1024,
|
||||||
|
Height: 768,
|
||||||
|
Title: "{{.Name}}",
|
||||||
|
JS: js,
|
||||||
|
CSS: css,
|
||||||
|
Colour: "#131313",
|
||||||
|
})
|
||||||
|
app.Bind(basic)
|
||||||
|
app.Run()
|
||||||
|
}
|
||||||
14
cmd/templates/vuetify2-basic/template.json
Executable file
14
cmd/templates/vuetify2-basic/template.json
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "Vuetify2/Webpack Basic",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"shortdescription": "A basic Vuetify2/Webpack4 template",
|
||||||
|
"description": "Basic template using Vuetify v2 and bundled using Webpack",
|
||||||
|
"install": "npm install",
|
||||||
|
"build": "npm run build",
|
||||||
|
"author": "Michael Hipp <michael@redmule.com>",
|
||||||
|
"created": "2019-09-06",
|
||||||
|
"frontenddir": "frontend",
|
||||||
|
"serve": "npm run serve",
|
||||||
|
"bridge": "src",
|
||||||
|
"wailsdir": ""
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
const Version = "v0.19.0"
|
const Version = "v1.0.2"
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ Create your first project by running 'wails init'.`
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check Mewn
|
// Check Mewn
|
||||||
err = cmd.CheckMewn()
|
err = cmd.CheckMewn(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
@@ -183,35 +182,13 @@ func checkProjectDirectory() error {
|
|||||||
|
|
||||||
func getWailsVersion() (*semver.Version, error) {
|
func getWailsVersion() (*semver.Version, error) {
|
||||||
checkSpinner.Start("Get Wails Version")
|
checkSpinner.Start("Get Wails Version")
|
||||||
var result *semver.Version
|
|
||||||
|
|
||||||
// Load file
|
result, err := cmd.GetWailsVersion()
|
||||||
var err error
|
|
||||||
goModFile, err = filepath.Abs(filepath.Join(".", "go.mod"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
checkSpinner.Error()
|
checkSpinner.Error(err.Error())
|
||||||
return nil, fmt.Errorf("Unable to load go.mod at %s", goModFile)
|
return nil, err
|
||||||
}
|
}
|
||||||
goMod, err = migrateFS.LoadAsString(goModFile)
|
|
||||||
if err != nil {
|
|
||||||
checkSpinner.Error()
|
|
||||||
return nil, fmt.Errorf("Unable to load go.mod")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find wails version
|
|
||||||
versionRegexp := regexp.MustCompile(`.*github.com/wailsapp/wails.*(v\d+.\d+.\d+)`)
|
|
||||||
versions := versionRegexp.FindStringSubmatch(goMod)
|
|
||||||
|
|
||||||
if len(versions) != 2 {
|
|
||||||
return nil, fmt.Errorf("Unable to determine Wails version")
|
|
||||||
}
|
|
||||||
|
|
||||||
version := versions[1]
|
|
||||||
result, err = semver.NewVersion(version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Unable to parse Wails version: %s", version)
|
|
||||||
}
|
|
||||||
checkSpinner.Success("Found Wails Version: " + version)
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/leaanthony/spinner"
|
"github.com/leaanthony/spinner"
|
||||||
"github.com/wailsapp/wails/cmd"
|
"github.com/wailsapp/wails/cmd"
|
||||||
)
|
)
|
||||||
@@ -13,6 +16,10 @@ func init() {
|
|||||||
var packageApp = false
|
var packageApp = false
|
||||||
var forceRebuild = false
|
var forceRebuild = false
|
||||||
var debugMode = false
|
var debugMode = false
|
||||||
|
var typescriptFilename = ""
|
||||||
|
var verbose = false
|
||||||
|
var platform = ""
|
||||||
|
|
||||||
buildSpinner := spinner.NewSpinner()
|
buildSpinner := spinner.NewSpinner()
|
||||||
buildSpinner.SetSpinSpeed(50)
|
buildSpinner.SetSpinSpeed(50)
|
||||||
|
|
||||||
@@ -21,7 +28,10 @@ func init() {
|
|||||||
LongDescription(commandDescription).
|
LongDescription(commandDescription).
|
||||||
BoolFlag("p", "Package application on successful build", &packageApp).
|
BoolFlag("p", "Package application on successful build", &packageApp).
|
||||||
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
||||||
BoolFlag("d", "Build in Debug mode", &debugMode)
|
BoolFlag("d", "Build in Debug mode", &debugMode).
|
||||||
|
BoolFlag("verbose", "Verbose output", &verbose).
|
||||||
|
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename).
|
||||||
|
StringFlag("x", "Cross-compile application to specified platform via xgo", &platform)
|
||||||
|
|
||||||
initCmd.Action(func() error {
|
initCmd.Action(func() error {
|
||||||
|
|
||||||
@@ -37,6 +47,7 @@ func init() {
|
|||||||
|
|
||||||
// Project options
|
// Project options
|
||||||
projectOptions := &cmd.ProjectOptions{}
|
projectOptions := &cmd.ProjectOptions{}
|
||||||
|
projectOptions.Verbose = verbose
|
||||||
|
|
||||||
// Check we are in project directory
|
// Check we are in project directory
|
||||||
// Check project.json loads correctly
|
// Check project.json loads correctly
|
||||||
@@ -73,16 +84,13 @@ func init() {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that runtime init.js is the production version
|
// Ensure that runtime init.js is the production version
|
||||||
err = cmd.InstallProdRuntime(projectDir, projectOptions)
|
err = cmd.InstallProdRuntime(projectDir, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Move to project directory
|
// Move to project directory
|
||||||
err = os.Chdir(projectDir)
|
err = os.Chdir(projectDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -90,7 +98,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Install dependencies
|
// Install dependencies
|
||||||
err = cmd.InstallGoDependencies()
|
err = cmd.InstallGoDependencies(projectOptions.Verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -101,6 +109,55 @@ func init() {
|
|||||||
buildMode = cmd.BuildModeDebug
|
buildMode = cmd.BuildModeDebug
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save if we wish to dump typescript or not
|
||||||
|
if typescriptFilename != "" {
|
||||||
|
projectOptions.SetTypescriptDefsFilename(typescriptFilename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update go.mod if it is out of sync with current version
|
||||||
|
outofsync, err := cmd.GoModOutOfSync()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gomodVersion, err := cmd.GetWailsVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if outofsync {
|
||||||
|
syncMessage := fmt.Sprintf("Updating go.mod (Wails version %s => %s)", gomodVersion, cmd.Version)
|
||||||
|
buildSpinner := spinner.NewSpinner(syncMessage)
|
||||||
|
buildSpinner.Start()
|
||||||
|
err := cmd.UpdateGoModVersion()
|
||||||
|
if err != nil {
|
||||||
|
buildSpinner.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buildSpinner.Success()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set cross-compile
|
||||||
|
projectOptions.Platform = runtime.GOOS
|
||||||
|
if len(platform) > 0 {
|
||||||
|
|
||||||
|
projectOptions.CrossCompile = true
|
||||||
|
projectOptions.Platform = platform
|
||||||
|
projectOptions.Architecture = "amd64"
|
||||||
|
|
||||||
|
// check build architecture
|
||||||
|
if strings.Contains(platform, "/") {
|
||||||
|
p := strings.Split(platform, "/")
|
||||||
|
projectOptions.Platform = p[0]
|
||||||
|
projectOptions.Architecture = p[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check supported platforms
|
||||||
|
supportedPlatforms := slicer.String([]string{"linux/amd64", "linux/386", "windows/amd64", "windows/386", "darwin/amd64"})
|
||||||
|
targetPlatform := projectOptions.Platform + "/" + projectOptions.Architecture
|
||||||
|
if !supportedPlatforms.Contains(targetPlatform) {
|
||||||
|
println("\n*** WARNING: Unsupported target platform", targetPlatform+".", "Supported:", supportedPlatforms.Join(", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, packageApp, projectOptions)
|
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode, packageApp, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ import (
|
|||||||
func init() {
|
func init() {
|
||||||
|
|
||||||
var forceRebuild = false
|
var forceRebuild = false
|
||||||
|
var verbose = false
|
||||||
buildSpinner := spinner.NewSpinner()
|
buildSpinner := spinner.NewSpinner()
|
||||||
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("verbose", "Verbose output", &verbose).
|
||||||
BoolFlag("f", "Force rebuild of application components", &forceRebuild)
|
BoolFlag("f", "Force rebuild of application components", &forceRebuild)
|
||||||
|
|
||||||
initCmd.Action(func() error {
|
initCmd.Action(func() error {
|
||||||
@@ -25,13 +27,14 @@ func init() {
|
|||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
// Check Mewn is installed
|
// Check Mewn is installed
|
||||||
err := cmd.CheckMewn()
|
err := cmd.CheckMewn(verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Project options
|
// Project options
|
||||||
projectOptions := &cmd.ProjectOptions{}
|
projectOptions := &cmd.ProjectOptions{}
|
||||||
|
projectOptions.Verbose = verbose
|
||||||
|
|
||||||
// Check we are in project directory
|
// Check we are in project directory
|
||||||
// Check project.json loads correctly
|
// Check project.json loads correctly
|
||||||
@@ -51,7 +54,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Install dependencies
|
// Install dependencies
|
||||||
err = cmd.InstallGoDependencies()
|
err = cmd.InstallGoDependencies(projectOptions.Verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
7
go.mod
7
go.mod
@@ -3,9 +3,6 @@ module github.com/wailsapp/wails
|
|||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver v1.4.2
|
github.com/Masterminds/semver v1.4.2
|
||||||
github.com/abadojack/whatlanggo v1.0.1
|
github.com/abadojack/whatlanggo v1.0.1
|
||||||
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect
|
|
||||||
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac
|
|
||||||
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect
|
|
||||||
github.com/fatih/color v1.7.0
|
github.com/fatih/color v1.7.0
|
||||||
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
|
||||||
@@ -13,7 +10,7 @@ require (
|
|||||||
github.com/kennygrant/sanitize v1.2.4
|
github.com/kennygrant/sanitize v1.2.4
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
github.com/leaanthony/mewn v0.10.7
|
github.com/leaanthony/mewn v0.10.7
|
||||||
github.com/leaanthony/slicer v1.3.2
|
github.com/leaanthony/slicer v1.4.1
|
||||||
github.com/leaanthony/spinner v0.5.3
|
github.com/leaanthony/spinner v0.5.3
|
||||||
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/mattn/go-isatty v0.0.7 // indirect
|
||||||
@@ -31,3 +28,5 @@ require (
|
|||||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
||||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
||||||
)
|
)
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|||||||
10
go.sum
10
go.sum
@@ -7,12 +7,6 @@ github.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH
|
|||||||
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=
|
||||||
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc h1:VBS1z48BFEe00G81z8MKOtwX7f/ISkuH38NscT8iVPw=
|
|
||||||
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc/go.mod h1:ABJPuor7YlcsHmvJ1QxX38e2NcufLY3hm0yXv+cy9sI=
|
|
||||||
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac h1:DpMwFluHWoZpV9ex5XjkWO4HyCz5HLVI8XbHw0FhHi4=
|
|
||||||
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac/go.mod h1:XsAE+b4rOZc8gvgsgF+wU75mNBvBcyED1wdd9PBLlJ0=
|
|
||||||
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 h1:Fm10/KNuoAyBm2P5P5H91Xy21hGcZnBdjR+cMdytv1M=
|
|
||||||
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947/go.mod h1:Dv9D0NUlAsaQcGQZa5kc5mqR9ua72SmA8VXi4cd+cBw=
|
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M=
|
github.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M=
|
||||||
@@ -34,8 +28,8 @@ github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmPA=
|
github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmPA=
|
||||||
github.com/leaanthony/mewn v0.10.7/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
github.com/leaanthony/mewn v0.10.7/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
||||||
github.com/leaanthony/slicer v1.3.2 h1:kGWWFoyaY5WzwGrUsHXMmGbssuYthP4qYBNlkNpNAB8=
|
github.com/leaanthony/slicer v1.4.1 h1:X/SmRIDhkUAolP79mSTO0jTcVX1k504PJBqvV6TwP0w=
|
||||||
github.com/leaanthony/slicer v1.3.2/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
github.com/leaanthony/slicer v1.4.1/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||||
github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y=
|
github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y=
|
||||||
github.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo=
|
github.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo=
|
||||||
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
||||||
|
|||||||
BIN
jetbrains-grayscale.png
Normal file
BIN
jetbrains-grayscale.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 103 KiB |
@@ -2,7 +2,11 @@ package binding
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/lib/interfaces"
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
@@ -10,6 +14,8 @@ import (
|
|||||||
"github.com/wailsapp/wails/lib/messages"
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var typescriptDefinitionFilename = ""
|
||||||
|
|
||||||
// Manager handles method binding
|
// Manager handles method binding
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
methods map[string]*boundMethod
|
methods map[string]*boundMethod
|
||||||
@@ -21,16 +27,19 @@ type Manager struct {
|
|||||||
renderer interfaces.Renderer
|
renderer interfaces.Renderer
|
||||||
runtime interfaces.Runtime // The runtime object to pass to bound structs
|
runtime interfaces.Runtime // The runtime object to pass to bound structs
|
||||||
objectsToBind []interface{}
|
objectsToBind []interface{}
|
||||||
bindPackageNames bool // Package name should be considered when binding
|
bindPackageNames bool // Package name should be considered when binding
|
||||||
|
structList map[string][]string // structList["mystruct"] = []string{"Method1", "Method2"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager creates a new Manager struct
|
// NewManager creates a new Manager struct
|
||||||
func NewManager() interfaces.BindingManager {
|
func NewManager() interfaces.BindingManager {
|
||||||
|
|
||||||
result := &Manager{
|
result := &Manager{
|
||||||
methods: make(map[string]*boundMethod),
|
methods: make(map[string]*boundMethod),
|
||||||
functions: make(map[string]*boundFunction),
|
functions: make(map[string]*boundFunction),
|
||||||
log: logger.NewCustomLogger("Bind"),
|
log: logger.NewCustomLogger("Bind"),
|
||||||
internalMethods: newInternalMethods(),
|
internalMethods: newInternalMethods(),
|
||||||
|
structList: make(map[string][]string),
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -88,9 +97,55 @@ func (b *Manager) initialise() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we wish to generate a typescript definition file...
|
||||||
|
if typescriptDefinitionFilename != "" {
|
||||||
|
err := b.generateTypescriptDefinitions()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate typescript
|
||||||
|
func (b *Manager) generateTypescriptDefinitions() error {
|
||||||
|
|
||||||
|
var output strings.Builder
|
||||||
|
|
||||||
|
for structname, methodList := range b.structList {
|
||||||
|
structname = strings.SplitN(structname, ".", 2)[1]
|
||||||
|
output.WriteString(fmt.Sprintf("Interface %s {\n", structname))
|
||||||
|
for _, method := range methodList {
|
||||||
|
output.WriteString(fmt.Sprintf("\t%s: (...args : any[]) => Promise\n", method))
|
||||||
|
}
|
||||||
|
output.WriteString("}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
output.WriteString("\n")
|
||||||
|
output.WriteString("Interface Backend {\n")
|
||||||
|
|
||||||
|
for structname := range b.structList {
|
||||||
|
structname = strings.SplitN(structname, ".", 2)[1]
|
||||||
|
output.WriteString(fmt.Sprintf("\t%[1]s: %[1]s\n", structname))
|
||||||
|
}
|
||||||
|
output.WriteString("}\n")
|
||||||
|
|
||||||
|
globals := `
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
backend: Backend;
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
output.WriteString(globals)
|
||||||
|
|
||||||
|
b.log.Info("Written Typescript file: " + typescriptDefinitionFilename)
|
||||||
|
|
||||||
|
dir := filepath.Dir(typescriptDefinitionFilename)
|
||||||
|
os.MkdirAll(dir, 0755)
|
||||||
|
return ioutil.WriteFile(typescriptDefinitionFilename, []byte(output.String()), 0755)
|
||||||
|
}
|
||||||
|
|
||||||
// bind the given struct method
|
// bind the given struct method
|
||||||
func (b *Manager) bindMethod(object interface{}) error {
|
func (b *Manager) bindMethod(object interface{}) error {
|
||||||
|
|
||||||
@@ -104,6 +159,12 @@ func (b *Manager) bindMethod(object interface{}) error {
|
|||||||
|
|
||||||
b.log.Debugf("Processing struct: %s", baseName)
|
b.log.Debugf("Processing struct: %s", baseName)
|
||||||
|
|
||||||
|
// Calc actual name
|
||||||
|
actualName := strings.TrimPrefix(baseName, "main.")
|
||||||
|
if b.structList[actualName] == nil {
|
||||||
|
b.structList[actualName] = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over method definitions
|
// Iterate over method definitions
|
||||||
for i := 0; i < objectType.NumMethod(); i++ {
|
for i := 0; i < objectType.NumMethod(); i++ {
|
||||||
|
|
||||||
@@ -113,6 +174,8 @@ func (b *Manager) bindMethod(object interface{}) error {
|
|||||||
fullMethodName := baseName + "." + methodName
|
fullMethodName := baseName + "." + methodName
|
||||||
method := reflect.ValueOf(object).MethodByName(methodName)
|
method := reflect.ValueOf(object).MethodByName(methodName)
|
||||||
|
|
||||||
|
b.structList[actualName] = append(b.structList[actualName], methodName)
|
||||||
|
|
||||||
// Skip unexported methods
|
// Skip unexported methods
|
||||||
if !unicode.IsUpper([]rune(methodName)[0]) {
|
if !unicode.IsUpper([]rune(methodName)[0]) {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package event
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/lib/interfaces"
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
"github.com/wailsapp/wails/lib/logger"
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
@@ -13,6 +12,7 @@ import (
|
|||||||
// Manager handles and processes events
|
// Manager handles and processes events
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
incomingEvents chan *messages.EventData
|
incomingEvents chan *messages.EventData
|
||||||
|
quitChannel chan struct{}
|
||||||
listeners map[string][]*eventListener
|
listeners map[string][]*eventListener
|
||||||
running bool
|
running bool
|
||||||
log *logger.CustomLogger
|
log *logger.CustomLogger
|
||||||
@@ -24,6 +24,7 @@ type Manager struct {
|
|||||||
func NewManager() interfaces.EventManager {
|
func NewManager() interfaces.EventManager {
|
||||||
return &Manager{
|
return &Manager{
|
||||||
incomingEvents: make(chan *messages.EventData, 100),
|
incomingEvents: make(chan *messages.EventData, 100),
|
||||||
|
quitChannel: make(chan struct{}, 1),
|
||||||
listeners: make(map[string][]*eventListener),
|
listeners: make(map[string][]*eventListener),
|
||||||
running: false,
|
running: false,
|
||||||
log: logger.NewCustomLogger("Events"),
|
log: logger.NewCustomLogger("Events"),
|
||||||
@@ -141,8 +142,8 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
case <-e.quitChannel:
|
||||||
time.Sleep(1 * time.Millisecond)
|
e.running = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.wg.Done()
|
e.wg.Done()
|
||||||
@@ -152,7 +153,7 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
|
|||||||
// Shutdown is called when exiting the Application
|
// Shutdown is called when exiting the Application
|
||||||
func (e *Manager) Shutdown() {
|
func (e *Manager) Shutdown() {
|
||||||
e.log.Debug("Shutting Down")
|
e.log.Debug("Shutting Down")
|
||||||
e.running = false
|
e.quitChannel <- struct{}{}
|
||||||
e.log.Debug("Waiting for main loop to exit")
|
e.log.Debug("Waiting for main loop to exit")
|
||||||
e.wg.Wait()
|
e.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package interfaces
|
package interfaces
|
||||||
|
|
||||||
|
// CallbackFunc defines the signature of a function required to be provided to the
|
||||||
|
// Dispatch function so that the response may be returned
|
||||||
|
type CallbackFunc func(string) error
|
||||||
|
|
||||||
// IPCManager is the event manager interface
|
// IPCManager is the event manager interface
|
||||||
type IPCManager interface {
|
type IPCManager interface {
|
||||||
BindRenderer(Renderer)
|
BindRenderer(Renderer)
|
||||||
Dispatch(message string)
|
Dispatch(message string, f CallbackFunc)
|
||||||
Start(eventManager EventManager, bindingManager BindingManager)
|
Start(eventManager EventManager, bindingManager BindingManager)
|
||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,15 @@ package interfaces
|
|||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/lib/messages"
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Renderer is an interface describing a Wails target to render the app to
|
// Renderer is an interface describing a Wails target to render the app to
|
||||||
type Renderer interface {
|
type Renderer interface {
|
||||||
Initialise(AppConfig, IPCManager, EventManager) error
|
Initialise(AppConfig, IPCManager, EventManager) error
|
||||||
Run() error
|
Run() error
|
||||||
|
EnableConsole()
|
||||||
|
|
||||||
// Binding
|
// Binding
|
||||||
NewBinding(bindingName string) error
|
NewBinding(bindingName string) error
|
||||||
Callback(data string) error
|
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
NotifyEvent(eventData *messages.EventData) error
|
NotifyEvent(eventData *messages.EventData) error
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package ipc
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/lib/interfaces"
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
"github.com/wailsapp/wails/lib/logger"
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
@@ -124,8 +123,8 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
|
|||||||
i.log.DebugFields("Finished processing message", logger.Fields{
|
i.log.DebugFields("Finished processing message", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
})
|
})
|
||||||
default:
|
case <-i.quitChannel:
|
||||||
time.Sleep(1 * time.Millisecond)
|
i.running = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.log.Debug("Stopping")
|
i.log.Debug("Stopping")
|
||||||
@@ -136,10 +135,10 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
|
|||||||
// Dispatch receives JSON encoded messages from the renderer.
|
// Dispatch receives JSON encoded messages from the renderer.
|
||||||
// It processes the message to ensure that it is valid and places
|
// It processes the message to ensure that it is valid and places
|
||||||
// the processed message on the message queue
|
// the processed message on the message queue
|
||||||
func (i *Manager) Dispatch(message string) {
|
func (i *Manager) Dispatch(message string, cb interfaces.CallbackFunc) {
|
||||||
|
|
||||||
// Create a new IPC Message
|
// Create a new IPC Message
|
||||||
incomingMessage, err := newIPCMessage(message, i.SendResponse)
|
incomingMessage, err := newIPCMessage(message, i.SendResponse(cb))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.log.ErrorFields("Could not understand incoming message! ", map[string]interface{}{
|
i.log.ErrorFields("Could not understand incoming message! ", map[string]interface{}{
|
||||||
"message": message,
|
"message": message,
|
||||||
@@ -159,23 +158,25 @@ func (i *Manager) Dispatch(message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendResponse sends the given response back to the frontend
|
// SendResponse sends the given response back to the frontend
|
||||||
func (i *Manager) SendResponse(response *ipcResponse) error {
|
// It sends the data back to the correct renderer by way of the provided callback function
|
||||||
|
func (i *Manager) SendResponse(cb interfaces.CallbackFunc) func(i *ipcResponse) error {
|
||||||
|
|
||||||
// Serialise the Message
|
return func(response *ipcResponse) error {
|
||||||
data, err := response.Serialise()
|
// Serialise the Message
|
||||||
if err != nil {
|
data, err := response.Serialise()
|
||||||
fmt.Printf(err.Error())
|
if err != nil {
|
||||||
return err
|
fmt.Printf(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cb(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call back to the front end
|
|
||||||
return i.renderer.Callback(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown is called when exiting the Application
|
// Shutdown is called when exiting the Application
|
||||||
func (i *Manager) Shutdown() {
|
func (i *Manager) Shutdown() {
|
||||||
i.log.Debug("Shutdown called")
|
i.log.Debug("Shutdown called")
|
||||||
i.running = false
|
i.quitChannel <- struct{}{}
|
||||||
i.log.Debug("Waiting of main loop shutdown")
|
i.log.Debug("Waiting of main loop shutdown")
|
||||||
i.wg.Wait()
|
i.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,258 +1,10 @@
|
|||||||
package renderer
|
package renderer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
bridge "github.com/wailsapp/wails/lib/renderer/bridge"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/dchest/htmlmin"
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"github.com/leaanthony/mewn"
|
|
||||||
"github.com/wailsapp/wails/lib/interfaces"
|
|
||||||
"github.com/wailsapp/wails/lib/logger"
|
|
||||||
"github.com/wailsapp/wails/lib/messages"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type messageType int
|
// NewBridge returns a new Bridge struct
|
||||||
|
func NewBridge() *bridge.Bridge {
|
||||||
const (
|
return &bridge.Bridge{}
|
||||||
jsMessage messageType = iota
|
|
||||||
cssMessage
|
|
||||||
htmlMessage
|
|
||||||
notifyMessage
|
|
||||||
bindingMessage
|
|
||||||
callbackMessage
|
|
||||||
wailsRuntimeMessage
|
|
||||||
)
|
|
||||||
|
|
||||||
func (m messageType) toString() string {
|
|
||||||
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bridge is a backend that opens a local web server
|
|
||||||
// and renders the files over a websocket
|
|
||||||
type Bridge struct {
|
|
||||||
// Common
|
|
||||||
log *logger.CustomLogger
|
|
||||||
ipcManager interfaces.IPCManager
|
|
||||||
appConfig interfaces.AppConfig
|
|
||||||
eventManager interfaces.EventManager
|
|
||||||
bindingCache []string
|
|
||||||
|
|
||||||
// Bridge specific
|
|
||||||
initialisationJS []string
|
|
||||||
server *http.Server
|
|
||||||
theConnection *websocket.Conn
|
|
||||||
|
|
||||||
// Mutex for writing to the socket
|
|
||||||
lock sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialise the Bridge Renderer
|
|
||||||
func (h *Bridge) Initialise(appConfig interfaces.AppConfig, ipcManager interfaces.IPCManager, eventManager interfaces.EventManager) error {
|
|
||||||
h.ipcManager = ipcManager
|
|
||||||
h.appConfig = appConfig
|
|
||||||
h.eventManager = eventManager
|
|
||||||
ipcManager.BindRenderer(h)
|
|
||||||
h.log = logger.NewCustomLogger("Bridge")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) evalJS(js string, mtype messageType) error {
|
|
||||||
|
|
||||||
message := mtype.toString() + js
|
|
||||||
|
|
||||||
if h.theConnection == nil {
|
|
||||||
h.initialisationJS = append(h.initialisationJS, message)
|
|
||||||
} else {
|
|
||||||
// Prepend message type to message
|
|
||||||
h.sendMessage(h.theConnection, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) injectCSS(css string) {
|
|
||||||
// Minify css to overcome issues in the browser with carriage returns
|
|
||||||
minified, err := htmlmin.Minify([]byte(css), &htmlmin.Options{
|
|
||||||
MinifyStyles: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
h.log.Fatal("Unable to minify CSS: " + css)
|
|
||||||
}
|
|
||||||
minifiedCSS := string(minified)
|
|
||||||
minifiedCSS = strings.Replace(minifiedCSS, "\\", "\\\\", -1)
|
|
||||||
minifiedCSS = strings.Replace(minifiedCSS, "'", "\\'", -1)
|
|
||||||
minifiedCSS = strings.Replace(minifiedCSS, "\n", " ", -1)
|
|
||||||
inject := fmt.Sprintf("wails._.InjectCSS('%s')", minifiedCSS)
|
|
||||||
h.evalJS(inject, cssMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
h.theConnection = conn
|
|
||||||
h.log.Infof("Connection from frontend accepted [%p].", h.theConnection)
|
|
||||||
conn.SetCloseHandler(func(int, string) error {
|
|
||||||
h.log.Infof("Connection dropped [%p].", h.theConnection)
|
|
||||||
h.theConnection = nil
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
go h.start(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) sendMessage(conn *websocket.Conn, msg string) {
|
|
||||||
|
|
||||||
h.lock.Lock()
|
|
||||||
defer h.lock.Unlock()
|
|
||||||
|
|
||||||
if err := conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
|
|
||||||
h.log.Error(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Bridge) start(conn *websocket.Conn) {
|
|
||||||
|
|
||||||
// set external.invoke
|
|
||||||
h.log.Infof("Connected to frontend.")
|
|
||||||
|
|
||||||
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
|
||||||
h.evalJS(wailsRuntime, wailsRuntimeMessage)
|
|
||||||
|
|
||||||
// Inject bindings
|
|
||||||
for _, binding := range h.bindingCache {
|
|
||||||
h.evalJS(binding, bindingMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit that everything is loaded and ready
|
|
||||||
h.eventManager.Emit("wails:ready")
|
|
||||||
|
|
||||||
for {
|
|
||||||
messageType, buffer, err := conn.ReadMessage()
|
|
||||||
if messageType == -1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
h.log.Errorf("Error reading message: ", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
h.log.Debugf("Got message: %#v\n", string(buffer))
|
|
||||||
|
|
||||||
h.ipcManager.Dispatch(string(buffer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the app in Bridge mode!
|
|
||||||
func (h *Bridge) Run() error {
|
|
||||||
h.server = &http.Server{Addr: ":34115"}
|
|
||||||
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
|
||||||
|
|
||||||
h.log.Info("Bridge mode started.")
|
|
||||||
h.log.Info("The frontend will connect automatically.")
|
|
||||||
|
|
||||||
err := h.server.ListenAndServe()
|
|
||||||
if err != nil && err != http.ErrServerClosed {
|
|
||||||
h.log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBinding creates a new binding with the frontend
|
|
||||||
func (h *Bridge) NewBinding(methodName string) error {
|
|
||||||
h.bindingCache = append(h.bindingCache, methodName)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectFile is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SelectFile() string {
|
|
||||||
h.log.Warn("SelectFile() unsupported in bridge mode")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectDirectory is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SelectDirectory() string {
|
|
||||||
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectSaveFile is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SelectSaveFile() string {
|
|
||||||
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback sends a callback to the frontend
|
|
||||||
func (h *Bridge) Callback(data string) error {
|
|
||||||
return h.evalJS(data, callbackMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyEvent notifies the frontend of an event
|
|
||||||
func (h *Bridge) NotifyEvent(event *messages.EventData) error {
|
|
||||||
|
|
||||||
// Look out! Nils about!
|
|
||||||
var err error
|
|
||||||
if event == nil {
|
|
||||||
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
|
|
||||||
h.log.Error(err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default data is a blank array
|
|
||||||
data := []byte("[]")
|
|
||||||
|
|
||||||
// Process event data
|
|
||||||
if event.Data != nil {
|
|
||||||
// Marshall the data
|
|
||||||
data, err = json.Marshal(event.Data)
|
|
||||||
if err != nil {
|
|
||||||
h.log.Errorf("Cannot unmarshall JSON data in event: %s ", err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data)
|
|
||||||
return h.evalJS(message, notifyMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetColour is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SetColour(colour string) error {
|
|
||||||
h.log.WarnFields("SetColour ignored for Bridge more", logger.Fields{"col": colour})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fullscreen is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) Fullscreen() {
|
|
||||||
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnFullscreen is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) UnFullscreen() {
|
|
||||||
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTitle is currently unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SetTitle(title string) {
|
|
||||||
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) Close() {
|
|
||||||
h.log.Debug("Shutting down")
|
|
||||||
err := h.server.Close()
|
|
||||||
if err != nil {
|
|
||||||
h.log.Errorf(err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
214
lib/renderer/bridge/bridge.go
Normal file
214
lib/renderer/bridge/bridge.go
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package renderer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type messageType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
jsMessage messageType = iota
|
||||||
|
cssMessage
|
||||||
|
htmlMessage
|
||||||
|
notifyMessage
|
||||||
|
bindingMessage
|
||||||
|
callbackMessage
|
||||||
|
wailsRuntimeMessage
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m messageType) toString() string {
|
||||||
|
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bridge is a backend that opens a local web server
|
||||||
|
// and renders the files over a websocket
|
||||||
|
type Bridge struct {
|
||||||
|
// Common
|
||||||
|
log *logger.CustomLogger
|
||||||
|
ipcManager interfaces.IPCManager
|
||||||
|
appConfig interfaces.AppConfig
|
||||||
|
eventManager interfaces.EventManager
|
||||||
|
bindingCache []string
|
||||||
|
|
||||||
|
// Bridge specific
|
||||||
|
server *http.Server
|
||||||
|
|
||||||
|
lock sync.Mutex
|
||||||
|
sessions map[string]session
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the Bridge Renderer
|
||||||
|
func (h *Bridge) Initialise(appConfig interfaces.AppConfig, ipcManager interfaces.IPCManager, eventManager interfaces.EventManager) error {
|
||||||
|
h.sessions = map[string]session{}
|
||||||
|
h.ipcManager = ipcManager
|
||||||
|
h.appConfig = appConfig
|
||||||
|
h.eventManager = eventManager
|
||||||
|
ipcManager.BindRenderer(h)
|
||||||
|
h.log = logger.NewCustomLogger("Bridge")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableConsole not needed for bridge!
|
||||||
|
func (h *Bridge) EnableConsole() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
h.log.Infof("Connection from frontend accepted [%s].", conn.RemoteAddr().String())
|
||||||
|
h.startSession(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Bridge) startSession(conn *websocket.Conn) {
|
||||||
|
s := session{
|
||||||
|
conn: conn,
|
||||||
|
bindingCache: h.bindingCache,
|
||||||
|
ipc: h.ipcManager,
|
||||||
|
log: h.log,
|
||||||
|
eventManager: h.eventManager,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.SetCloseHandler(func(int, string) error {
|
||||||
|
h.log.Infof("Connection dropped [%s].", s.Identifier())
|
||||||
|
h.eventManager.Emit("wails:bridge:session:closed", s.Identifier())
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
delete(h.sessions, s.Identifier())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
go s.start(len(h.sessions) == 0)
|
||||||
|
h.sessions[s.Identifier()] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the app in Bridge mode!
|
||||||
|
func (h *Bridge) Run() error {
|
||||||
|
h.server = &http.Server{Addr: ":34115"}
|
||||||
|
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
||||||
|
|
||||||
|
h.log.Info("Bridge mode started.")
|
||||||
|
h.log.Info("The frontend will connect automatically.")
|
||||||
|
|
||||||
|
err := h.server.ListenAndServe()
|
||||||
|
if err != nil && err != http.ErrServerClosed {
|
||||||
|
h.log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBinding creates a new binding with the frontend
|
||||||
|
func (h *Bridge) NewBinding(methodName string) error {
|
||||||
|
h.bindingCache = append(h.bindingCache, methodName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectFile is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SelectFile() string {
|
||||||
|
h.log.Warn("SelectFile() unsupported in bridge mode")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDirectory is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SelectDirectory() string {
|
||||||
|
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectSaveFile is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SelectSaveFile() string {
|
||||||
|
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyEvent notifies the frontend of an event
|
||||||
|
func (h *Bridge) NotifyEvent(event *messages.EventData) error {
|
||||||
|
|
||||||
|
// Look out! Nils about!
|
||||||
|
var err error
|
||||||
|
if event == nil {
|
||||||
|
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
|
||||||
|
h.log.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default data is a blank array
|
||||||
|
data := []byte("[]")
|
||||||
|
|
||||||
|
// Process event data
|
||||||
|
if event.Data != nil {
|
||||||
|
// Marshall the data
|
||||||
|
data, err = json.Marshal(event.Data)
|
||||||
|
if err != nil {
|
||||||
|
h.log.Errorf("Cannot unmarshall JSON data in event: %s ", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data)
|
||||||
|
dead := []session{}
|
||||||
|
for _, session := range h.sessions {
|
||||||
|
err := session.evalJS(message, notifyMessage)
|
||||||
|
if err != nil {
|
||||||
|
h.log.Debugf("Failed to send message to %s - Removing listener : %v", session.Identifier(), err)
|
||||||
|
h.log.Infof("Connection from [%v] unresponsive - dropping", session.Identifier())
|
||||||
|
dead = append(dead, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
for _, session := range dead {
|
||||||
|
delete(h.sessions, session.Identifier())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetColour is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SetColour(colour string) error {
|
||||||
|
h.log.WarnFields("SetColour ignored for Bridge more", logger.Fields{"col": colour})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fullscreen is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) Fullscreen() {
|
||||||
|
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnFullscreen is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) UnFullscreen() {
|
||||||
|
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTitle is currently unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) SetTitle(title string) {
|
||||||
|
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close is unsupported for Bridge but required
|
||||||
|
// for the Renderer interface
|
||||||
|
func (h *Bridge) Close() {
|
||||||
|
h.log.Debug("Shutting down")
|
||||||
|
err := h.server.Close()
|
||||||
|
if err != nil {
|
||||||
|
h.log.Errorf(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
90
lib/renderer/bridge/session.go
Normal file
90
lib/renderer/bridge/session.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package renderer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO Move this back into bridge.go
|
||||||
|
|
||||||
|
// session represents a single websocket session
|
||||||
|
type session struct {
|
||||||
|
bindingCache []string
|
||||||
|
conn *websocket.Conn
|
||||||
|
eventManager interfaces.EventManager
|
||||||
|
log *logger.CustomLogger
|
||||||
|
ipc interfaces.IPCManager
|
||||||
|
|
||||||
|
// Mutex for writing to the socket
|
||||||
|
lock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identifier returns a string identifier for the remote connection.
|
||||||
|
// Taking the form of the client's <ip address>:<port>.
|
||||||
|
func (s *session) Identifier() string {
|
||||||
|
if s.conn != nil {
|
||||||
|
return s.conn.RemoteAddr().String()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *session) sendMessage(msg string) error {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
if err := s.conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
|
||||||
|
s.log.Debug(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *session) start(firstSession bool) {
|
||||||
|
s.log.Infof("Connected to frontend.")
|
||||||
|
|
||||||
|
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||||
|
s.evalJS(wailsRuntime, wailsRuntimeMessage)
|
||||||
|
|
||||||
|
// Inject bindings
|
||||||
|
for _, binding := range s.bindingCache {
|
||||||
|
s.evalJS(binding, bindingMessage)
|
||||||
|
}
|
||||||
|
s.eventManager.Emit("wails:bridge:session:started", s.Identifier())
|
||||||
|
|
||||||
|
// Emit that everything is loaded and ready
|
||||||
|
if firstSession {
|
||||||
|
s.eventManager.Emit("wails:ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
messageType, buffer, err := s.conn.ReadMessage()
|
||||||
|
if messageType == -1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
s.log.Errorf("Error reading message: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.log.Debugf("Got message: %#v\n", string(buffer))
|
||||||
|
|
||||||
|
s.ipc.Dispatch(string(buffer), s.Callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback sends a callback to the frontend
|
||||||
|
func (s *session) Callback(data string) error {
|
||||||
|
return s.evalJS(data, callbackMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *session) evalJS(js string, mtype messageType) error {
|
||||||
|
|
||||||
|
// Prepend message type to message
|
||||||
|
return s.sendMessage(mtype.toString() + js)
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -19,12 +19,13 @@ import (
|
|||||||
// WebView defines the main webview application window
|
// WebView defines the main webview application window
|
||||||
// Default values in []
|
// Default values in []
|
||||||
type WebView struct {
|
type WebView struct {
|
||||||
window wv.WebView // The webview object
|
window wv.WebView // The webview object
|
||||||
ipc interfaces.IPCManager
|
ipc interfaces.IPCManager
|
||||||
log *logger.CustomLogger
|
log *logger.CustomLogger
|
||||||
config interfaces.AppConfig
|
config interfaces.AppConfig
|
||||||
eventManager interfaces.EventManager
|
eventManager interfaces.EventManager
|
||||||
bindingCache []string
|
bindingCache []string
|
||||||
|
enableConsole bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebView returns a new WebView struct
|
// NewWebView returns a new WebView struct
|
||||||
@@ -57,7 +58,7 @@ func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCMana
|
|||||||
URL: config.GetDefaultHTML(),
|
URL: config.GetDefaultHTML(),
|
||||||
Debug: !config.GetDisableInspector(),
|
Debug: !config.GetDisableInspector(),
|
||||||
ExternalInvokeCallback: func(_ wv.WebView, message string) {
|
ExternalInvokeCallback: func(_ wv.WebView, message string) {
|
||||||
w.ipc.Dispatch(message)
|
w.ipc.Dispatch(message, w.callback)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -103,6 +104,11 @@ func (w *WebView) evalJS(js string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnableConsole enables the console!
|
||||||
|
func (w *WebView) EnableConsole() {
|
||||||
|
w.enableConsole = true
|
||||||
|
}
|
||||||
|
|
||||||
// Escape the Javascripts!
|
// Escape the Javascripts!
|
||||||
func escapeJS(js string) (string, error) {
|
func escapeJS(js string) (string, error) {
|
||||||
result := strings.Replace(js, "\\", "\\\\", -1)
|
result := strings.Replace(js, "\\", "\\\\", -1)
|
||||||
@@ -172,6 +178,13 @@ func (w *WebView) Run() error {
|
|||||||
|
|
||||||
w.log.Info("Running...")
|
w.log.Info("Running...")
|
||||||
|
|
||||||
|
// Inject firebug in debug mode on Windows
|
||||||
|
if w.enableConsole {
|
||||||
|
w.log.Debug("Enabling Wails console")
|
||||||
|
console := mewn.String("../../runtime/assets/console.js")
|
||||||
|
w.evalJS(console)
|
||||||
|
}
|
||||||
|
|
||||||
// Runtime assets
|
// Runtime assets
|
||||||
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||||
w.evalJS(wailsRuntime)
|
w.evalJS(wailsRuntime)
|
||||||
@@ -286,8 +299,8 @@ func (w *WebView) SelectSaveFile() string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback sends a callback to the frontend
|
// callback sends a callback to the frontend
|
||||||
func (w *WebView) Callback(data string) error {
|
func (w *WebView) callback(data string) error {
|
||||||
callbackCMD := fmt.Sprintf("window.wails._.Callback('%s');", data)
|
callbackCMD := fmt.Sprintf("window.wails._.Callback('%s');", data)
|
||||||
return w.evalJS(callbackCMD)
|
return w.evalJS(callbackCMD)
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
logo_cropped.png
Normal file
BIN
logo_cropped.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
@@ -14,7 +14,7 @@ function init() {
|
|||||||
window.wailsbridge = {
|
window.wailsbridge = {
|
||||||
reconnectOverlay: null,
|
reconnectOverlay: null,
|
||||||
reconnectTimer: 300,
|
reconnectTimer: 300,
|
||||||
wsURL: 'ws://localhost:34115/bridge',
|
wsURL: 'ws://' + window.location.hostname + ':34115/bridge',
|
||||||
connectionState: null,
|
connectionState: null,
|
||||||
config: {},
|
config: {},
|
||||||
websocket: null,
|
websocket: null,
|
||||||
|
|||||||
175
runtime/assets/console.js
Normal file
175
runtime/assets/console.js
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
(function () {
|
||||||
|
|
||||||
|
window.wailsconsole = {};
|
||||||
|
|
||||||
|
var debugconsole = document.createElement("div");
|
||||||
|
var header = document.createElement("div");
|
||||||
|
var consoleOut = document.createElement("div");
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('keyup', logKey);
|
||||||
|
|
||||||
|
debugconsole.id = "wailsdebug";
|
||||||
|
debugconsole.style.fontSize = "18px";
|
||||||
|
debugconsole.style.width = "100%";
|
||||||
|
debugconsole.style.height = "35%";
|
||||||
|
debugconsole.style.maxHeight = "35%";
|
||||||
|
debugconsole.style.position = "fixed";
|
||||||
|
debugconsole.style.left = "0px";
|
||||||
|
debugconsole.style.backgroundColor = "rgba(255,255,255,0.8)";
|
||||||
|
debugconsole.style.borderTop = '1px solid black';
|
||||||
|
debugconsole.style.color = "black";
|
||||||
|
debugconsole.style.display = "none";
|
||||||
|
|
||||||
|
header.style.width = "100%";
|
||||||
|
header.style.height = "30px";
|
||||||
|
header.style.display = "block";
|
||||||
|
// header.style.paddingTop = "3px";
|
||||||
|
header.style.verticalAlign = "middle";
|
||||||
|
header.style.paddingLeft = "10px";
|
||||||
|
header.style.background = "rgba(255,255,255,0.8)";
|
||||||
|
header.innerHTML = " <span style='vertical-align: middle'> Wails Console > <input id='conin' style='border: solid 1px black; width: 50%'></input><span style='padding-left: 5px; cursor:pointer;' onclick='window.wailsconsole.clearConsole()'>Clear</span></span>";
|
||||||
|
|
||||||
|
consoleOut.style.position = "absolute";
|
||||||
|
consoleOut.style.width = "100%";
|
||||||
|
consoleOut.style.height = "auto";
|
||||||
|
consoleOut.style.top = "30px";
|
||||||
|
// consoleOut.style.paddingLeft = "10px";
|
||||||
|
consoleOut.style.bottom = "0px";
|
||||||
|
consoleOut.style.backgroundColor = "rgba(200,200,200,1)";
|
||||||
|
consoleOut.style.overflowY = "scroll";
|
||||||
|
consoleOut.style.msOverflowStyle = "-ms-autohiding-scrollbar";
|
||||||
|
|
||||||
|
debugconsole.appendChild(header);
|
||||||
|
debugconsole.appendChild(consoleOut);
|
||||||
|
document.body.appendChild(debugconsole);
|
||||||
|
console.log(debugconsole.style.display)
|
||||||
|
|
||||||
|
function logKey(e) {
|
||||||
|
var conin = document.getElementById('conin');
|
||||||
|
if (e.which == 27 && e.shiftKey) {
|
||||||
|
toggleConsole(conin);
|
||||||
|
}
|
||||||
|
if (e.which == 13 && consoleVisible()) {
|
||||||
|
var command = conin.value.trim();
|
||||||
|
if (command.length > 0) {
|
||||||
|
console.log("> " + command)
|
||||||
|
try {
|
||||||
|
evaluateInput(command);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e.message);
|
||||||
|
}
|
||||||
|
conin.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function consoleVisible() {
|
||||||
|
return debugconsole.style.display == "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleConsole(conin) {
|
||||||
|
var display = "none"
|
||||||
|
if (debugconsole.style.display == "none") display = "block";
|
||||||
|
debugconsole.style.display = display;
|
||||||
|
if (display == "block") {
|
||||||
|
conin.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function evaluateExpression(expression) {
|
||||||
|
|
||||||
|
var pathSegments = [].concat(expression.split('.'));
|
||||||
|
if (pathSegments[0] == 'window') {
|
||||||
|
pathSegments.shift()
|
||||||
|
}
|
||||||
|
var currentObject = window;
|
||||||
|
for (var i = 0; i < pathSegments.length; i++) {
|
||||||
|
var pathSegment = pathSegments[i];
|
||||||
|
if (currentObject[pathSegment] == undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
currentObject = currentObject[pathSegment];
|
||||||
|
}
|
||||||
|
console.log(JSON.stringify(currentObject));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function evaluateInput(command) {
|
||||||
|
try {
|
||||||
|
if (evaluateExpression(command)) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
eval(command);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set us up as a listener
|
||||||
|
function hookIntoIPC() {
|
||||||
|
if (window.wails && window.wails._ && window.wails._.AddIPCListener) {
|
||||||
|
window.wails._.AddIPCListener(processIPCMessage);
|
||||||
|
} else {
|
||||||
|
setTimeout(hookIntoIPC, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hookIntoIPC();
|
||||||
|
|
||||||
|
function processIPCMessage(message) {
|
||||||
|
console.log(message);
|
||||||
|
var parsedMessage;
|
||||||
|
try {
|
||||||
|
parsedMessage = JSON.parse(message);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error in parsing IPC message: " + e.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var logmessage = "[IPC] "
|
||||||
|
switch (parsedMessage.type) {
|
||||||
|
case 'call':
|
||||||
|
logmessage += " Call: " + parsedMessage.payload.bindingName;
|
||||||
|
var params = "";
|
||||||
|
var parsedParams = JSON.parse(parsedMessage.payload.data);
|
||||||
|
if (parsedParams.length > 0) {
|
||||||
|
params = parsedParams;
|
||||||
|
}
|
||||||
|
logmessage += "(" + params + ")";
|
||||||
|
break;
|
||||||
|
case 'log':
|
||||||
|
logmessage += "Log (" + parsedMessage.payload.level + "): " + parsedMessage.payload.message;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logmessage = message;
|
||||||
|
}
|
||||||
|
console.log(logmessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.wailsconsole.clearConsole = function () {
|
||||||
|
consoleOut.innerHTML = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log = function (message) {
|
||||||
|
consoleOut.innerHTML = consoleOut.innerHTML + "<span style='padding-left: 5px'>" + message + '</span><br/>';
|
||||||
|
consoleOut.scrollTop = consoleOut.scrollHeight;
|
||||||
|
|
||||||
|
};
|
||||||
|
console.error = function (message) {
|
||||||
|
consoleOut.innerHTML = consoleOut.innerHTML + "<span style='color:red; padding-left: 5px'> Error: " + message + '</span><br/>';
|
||||||
|
consoleOut.scrollTop = consoleOut.scrollHeight;
|
||||||
|
};
|
||||||
|
// var h = document.getElementsByTagName("html")[0];
|
||||||
|
// console.log("html margin: " + h.style.marginLeft);
|
||||||
|
// console.log("html padding: " + h.style.paddingLeft);
|
||||||
|
|
||||||
|
// setInterval(function() { console.log("test");}, 1000);
|
||||||
|
// setInterval(function() { console.error("oops");}, 3000);
|
||||||
|
// var script = document.createElement('script');
|
||||||
|
// script.src = "https://cdnjs.cloudflare.com/ajax/libs/firebug-lite/1.4.0/firebug-lite.js#startOpened=true";
|
||||||
|
// document.body.appendChild(script);
|
||||||
|
|
||||||
|
})();
|
||||||
File diff suppressed because one or more lines are too long
@@ -9,17 +9,35 @@ The lightweight framework for web-like apps
|
|||||||
*/
|
*/
|
||||||
/* jshint esversion: 6 */
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
// IPC Listeners
|
||||||
|
var listeners = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener to IPC messages
|
||||||
|
* @param {function} callback
|
||||||
|
*/
|
||||||
|
export function AddIPCListener(callback) {
|
||||||
|
listeners.push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke sends the given message to the backend
|
* Invoke sends the given message to the backend
|
||||||
*
|
*
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
function Invoke(message) {
|
function Invoke(message) {
|
||||||
if ( window.wailsbridge ) {
|
if (window.wailsbridge) {
|
||||||
window.wailsbridge.websocket.send(message);
|
window.wailsbridge.websocket.send(message);
|
||||||
} else {
|
} else {
|
||||||
window.external.invoke(message);
|
window.external.invoke(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also send to listeners
|
||||||
|
if (listeners.length > 0) {
|
||||||
|
for (var i = 0; i < listeners.length; i++) {
|
||||||
|
listeners[i](message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { On, OnMultiple, Emit, Notify, Heartbeat, Acknowledge } from './events';
|
|||||||
import { NewBinding } from './bindings';
|
import { NewBinding } from './bindings';
|
||||||
import { Callback } from './calls';
|
import { Callback } from './calls';
|
||||||
import { AddScript, InjectCSS } from './utils';
|
import { AddScript, InjectCSS } from './utils';
|
||||||
|
import { AddIPCListener } from './ipc';
|
||||||
|
|
||||||
// Initialise global if not already
|
// Initialise global if not already
|
||||||
window.wails = window.wails || {};
|
window.wails = window.wails || {};
|
||||||
@@ -27,6 +28,7 @@ var internal = {
|
|||||||
AddScript,
|
AddScript,
|
||||||
InjectCSS,
|
InjectCSS,
|
||||||
Init,
|
Init,
|
||||||
|
AddIPCListener,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup runtime structure
|
// Setup runtime structure
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ function Once(eventName, callback) {
|
|||||||
* @param {string} eventName
|
* @param {string} eventName
|
||||||
*/
|
*/
|
||||||
function Emit(eventName) {
|
function Emit(eventName) {
|
||||||
return window.wails.Events.Emit(eventName);
|
var args = [eventName].slice.call(arguments);
|
||||||
|
return window.wails.Events.Emit.apply(null, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ function Init(callback) {
|
|||||||
window.wails._.Init(callback);
|
window.wails._.Init(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Init;
|
module.exports = Init;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wailsapp/runtime",
|
"name": "@wailsapp/runtime",
|
||||||
"version": "1.0.9",
|
"version": "1.0.10",
|
||||||
"description": "Wails Javascript runtime library",
|
"description": "Wails Javascript runtime library",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"types": "runtime.d.ts",
|
"types": "runtime.d.ts",
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ echo "**** WE ARE DONE! ****"
|
|||||||
func runCommand(command string, args ...string) {
|
func runCommand(command string, args ...string) {
|
||||||
cmd := exec.Command(command, args...)
|
cmd := exec.Command(command, args...)
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
|
fmt.Println(string(output))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(string(output))
|
log.Println(string(output))
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|||||||
Reference in New Issue
Block a user