Compare commits

..

2 Commits

Author SHA1 Message Date
Lea Anthony
9fbfccdd86 chore: merge master 2019-09-10 08:44:45 +10:00
Lea Anthony
1d1a7967ad chore: update wails-react-scripts dependency 2019-09-10 08:38:48 +10:00
474 changed files with 5317 additions and 43576 deletions

View File

@@ -1,32 +0,0 @@
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.13
uses: actions/setup-go@v1
with:
go-version: 1.13
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

View File

@@ -1,32 +0,0 @@
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.13
uses: actions/setup-go@v1
with:
go-version: 1.13
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

View File

@@ -1,34 +0,0 @@
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.13
uses: actions/setup-go@v1
with:
go-version: 1.13
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

11
.gitignore vendored
View File

@@ -16,13 +16,4 @@ examples/**/example*
cmd/wails/wails cmd/wails/wails
.DS_Store .DS_Store
tmp tmp
node_modules/ node_modules/
package.json.md5
v2/test/**/frontend/dist
v2/test/**/build/
v2/test/frameless/icon.png
v2/test/hidden/icon.png
v2/internal/ffenestri/runtime.c
v2/internal/runtime/assets/desktop.js
v2/test/kitchensink/frontend/public/bundle.*
v2/pkg/parser/testproject/frontend/wails

View File

@@ -2,33 +2,19 @@
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)
* [Nikolai Zimmermann](https://github.com/Chronophylos) * [Florian Didran](https://github.com/fdidron)
* [Toyam Cox](https://github.com/Vaelatern) * [Nikolai Zimmermann](https://github.com/Chronophylos)
* [Robin Eklind](https://github.com/mewmew) * [Toyam Cox](https://github.com/Vaelatern)
* [Kris Raney](https://github.com/kraney)
* [Jack Mordaunt](https://github.com/JackMordaunt)
* [Michael Hipp](https://github.com/MichaelHipp)
* [Travis McLane](https://github.com/tmclane)
* [Reuben Thomas-Davis](https://github.com/Rested)
* [Jarek](https://github.com/Jarek-SRT)
* [Konez2k](https://github.com/konez2k)
* [msms](https://github.com/sayuthisobri)
* [dedo1911](https://github.com/dedo1911)
* [Florian Didron](https://github.com/fdidron)
* [Christopher Murphy](https://github.com/Splode)
* [Zámbó, Levente](https://github.com/Lyimmi)
* [artem](https://github.com/Unix4ever)
* [Tim Kipp](https://github.com/timkippdev)

View File

@@ -1,5 +1,5 @@
<p align="center" style="text-align: center"> <p align="center" style="text-align: center">
<img src="logo_cropped.png" width="40%"><br/> <img src="https://github.com/wailsapp/docs/raw/master/.vuepress/public/media/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,14 +11,11 @@
<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://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://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/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
@@ -31,12 +28,15 @@ The official docs can be found at [https://wails.app](https://wails.app).
- 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
Wails uses cgo to bind to the native rendering engines so a number of platform dependent libraries are needed as well as an installation of Go. The basic requirements are: Wails uses cgo to bind to the native rendering engines so a number of platform dependent libraries are needed as well as an installation of Go. The basic requirements are:
- Go 1.13 - Go 1.12
- npm - npm
### MacOS ### MacOS
@@ -52,16 +52,15 @@ Make sure you have the xcode command line tools installed. This can be done by r
`sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev` `sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev`
_Debian: 8, 9, 10_ _Debian: 8, 9, 10_
_Ubuntu: 16.04, 18.04, 19.04_ _Ubuntu: 16.04, 18.04, 19.04_
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!_OS _Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali-Rolling_
#### Arch Linux / ArchLabs #### Arch Linux
`sudo pacman -S webkit2gtk gtk3` `sudo pacman -S webkit2gtk gtk3`
_Also succesfully test on: Manjaro & ArcoLinux_ _Also succesfully test on: ArcoLinuxB_
#### Centos #### Centos
@@ -94,7 +93,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 -u github.com/wailsapp/wails/cmd/wails go get github.com/wailsapp/wails/cmd/wails
</pre> </pre>
## Next Steps ## Next Steps
@@ -126,7 +125,8 @@ And without [these people](CONTRIBUTORS.md), it wouldn't be what it is today. A
Special Mentions: Special Mentions:
* [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. * [Bill Kennedy](https://twitter.com/goinggodotnet) - Go guru, encourager and all-round nice guy, whose infectious energy and inspiration powered me on when I had none left.
* [Mark Bates](https://github.com/markbates) - Creator of [Packr](https://github.com/gobuffalo/packr), inspiration for packing strategies which fed into some of the tooling.
This project was mainly coded to the following albums: This project was mainly coded to the following albums:
@@ -147,11 +147,3 @@ This project was mainly coded to the following albums:
## Licensing ## Licensing
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=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>

52
app.go
View File

@@ -1,11 +1,6 @@
package wails package wails
import ( import (
"os"
"runtime"
"syscall"
"github.com/syossan27/tebata"
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
"github.com/wailsapp/wails/lib/binding" "github.com/wailsapp/wails/lib/binding"
"github.com/wailsapp/wails/lib/event" "github.com/wailsapp/wails/lib/event"
@@ -44,7 +39,7 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
} }
result := &App{ result := &App{
logLevel: "debug", logLevel: "info",
renderer: renderer.NewWebView(), renderer: renderer.NewWebView(),
ipc: ipc.NewManager(), ipc: ipc.NewManager(),
bindingManager: binding.NewManager(), bindingManager: binding.NewManager(),
@@ -66,15 +61,11 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
result.config.DisableInspector = true result.config.DisableInspector = true
} }
// Platform specific init
platformInit()
return result return result
} }
// Run the app // Run the app
func (a *App) Run() error { func (a *App) Run() error {
if BuildMode != cmd.BuildModeProd { if BuildMode != cmd.BuildModeProd {
return a.cli.Run() return a.cli.Run()
} }
@@ -97,7 +88,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.NewBridge() a.renderer = &renderer.Bridge{}
} }
// Initialise the renderer // Initialise the renderer
@@ -106,18 +97,6 @@ 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
t := tebata.New(os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
t.Reserve(func() {
a.log.Debug("SIGNAL CAUGHT! Starting Shutdown")
a.renderer.Close()
})
// Start event manager and give it our renderer // Start event manager and give it our renderer
a.eventManager.Start(a.renderer) a.eventManager.Start(a.renderer)
@@ -133,33 +112,8 @@ func (a *App) start() error {
return err return err
} }
// Defer the shutdown
defer a.shutdown()
// Run the renderer // Run the renderer
err = a.renderer.Run() return a.renderer.Run()
if err != nil {
return err
}
return nil
}
// shutdown the app
func (a *App) shutdown() {
// Make sure this is only called once
a.log.Debug("Shutting down")
// Shutdown Binding Manager
a.bindingManager.Shutdown()
// Shutdown IPC Manager
a.ipc.Shutdown()
// Shutdown Event Manager
a.eventManager.Shutdown()
a.log.Debug("Cleanly Shutdown")
} }
// Bind allows the user to bind the given object // Bind allows the user to bind the given object

View File

@@ -1,7 +0,0 @@
// +build linux darwin !windows
package wails
func platformInit() {
}

View File

@@ -1,27 +0,0 @@
// +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
}

138
azure-pipelines.yaml Normal file
View File

@@ -0,0 +1,138 @@
# 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'

138
azure-pipelines.yml Normal file
View File

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

View File

@@ -12,7 +12,6 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings"
"github.com/leaanthony/slicer" "github.com/leaanthony/slicer"
) )
@@ -48,22 +47,6 @@ 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 {
@@ -117,10 +100,10 @@ func (fs *FSHelper) RemoveFile(filename string) error {
} }
// RemoveFiles removes the given filenames // RemoveFiles removes the given filenames
func (fs *FSHelper) RemoveFiles(files []string, continueOnError bool) error { func (fs *FSHelper) RemoveFiles(files []string) error {
for _, filename := range files { for _, filename := range files {
err := os.Remove(filename) err := os.Remove(filename)
if err != nil && !continueOnError { if err != nil {
return err return err
} }
} }
@@ -149,16 +132,6 @@ 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) {

View File

@@ -1,78 +0,0 @@
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)
}

View File

@@ -5,15 +5,11 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"os/user"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv"
"strings"
"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"
) )
@@ -39,161 +35,34 @@ 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(verbose bool) error { func InstallGoDependencies() error {
var depSpinner *spinner.Spinner depSpinner := spinner.New("Ensuring Dependencies are up to date...")
if !verbose { depSpinner.SetSpinSpeed(50)
depSpinner = spinner.New("Ensuring Dependencies are up to date...") depSpinner.Start()
depSpinner.SetSpinSpeed(50) err := NewProgramHelper().RunCommand("go get")
depSpinner.Start()
}
err := NewProgramHelper(verbose).RunCommand("go get")
if err != nil { if err != nil {
if !verbose { depSpinner.Error()
depSpinner.Error()
}
return err return err
} }
if !verbose { depSpinner.Success()
depSpinner.Success()
}
return nil return nil
} }
// EmbedAssets will embed the built frontend assets via mewn. // BuildApplication will attempt to build the project based on the given inputs
func EmbedAssets() ([]string, error) { func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error {
mewnFiles := lib.GetMewnFiles([]string{}, false)
referencedAssets, err := lib.GetReferencedAssets(mewnFiles) // Generate Windows assets if needed
if err != nil { if runtime.GOOS == "windows" {
return []string{}, err cleanUp := !packageApp
} err := NewPackageHelper().PackageWindows(projectOptions, cleanUp)
targetFiles := []string{}
for _, referencedAsset := range referencedAssets {
packfileData, err := lib.GeneratePackFileString(referencedAsset, false)
if err != nil { if err != nil {
return []string{}, err return err
} }
targetFile := filepath.Join(referencedAsset.BaseDir, referencedAsset.PackageName+"-mewn.go")
targetFiles = append(targetFiles, targetFile)
ioutil.WriteFile(targetFile, []byte(packfileData), 0644)
} }
return targetFiles, nil
}
func InitializeCrossCompilation(verbose bool) error {
// Check Docker
if err := CheckIfInstalled("docker"); err != nil {
return err
}
var packSpinner *spinner.Spinner
if !verbose {
packSpinner = spinner.New("Pulling wailsapp/xgo:latest docker image... (may take a while)")
packSpinner.SetSpinSpeed(50)
packSpinner.Start()
} else {
println("Pulling wailsapp/xgo:latest docker image... (may take a while)")
}
err := NewProgramHelper(verbose).RunCommandArray([]string{"docker",
"pull", "wailsapp/xgo:latest"})
if err != nil {
if packSpinner != nil {
packSpinner.Error()
}
return err
}
if packSpinner != nil {
packSpinner.Success()
}
return nil
}
// BuildDocker builds the project using the cross compiling wailsapp/xgo:latest container
func BuildDocker(binaryName string, buildMode string, projectOptions *ProjectOptions) error {
var packSpinner *spinner.Spinner
if buildMode == BuildModeBridge {
return fmt.Errorf("you cant serve the application in cross-compilation")
}
// Check build directory
buildDirectory := filepath.Join(fs.Cwd(), "build")
if !fs.DirExists(buildDirectory) {
fs.MkDir(buildDirectory)
}
buildCommand := slicer.String()
userid := 1000
user, _ := user.Current()
if i, err := strconv.Atoi(user.Uid); err == nil {
userid = i
}
for _, arg := range []string{
"docker",
"run",
"--rm",
"-v", fmt.Sprintf("%s:/build", filepath.Join(fs.Cwd(), "build")),
"-v", fmt.Sprintf("%s:/source", fs.Cwd()),
"-e", fmt.Sprintf("LOCAL_USER_ID=%v", userid),
"-e", fmt.Sprintf("FLAG_LDFLAGS=%s", ldFlags(projectOptions, buildMode)),
"-e", "FLAG_V=false",
"-e", "FLAG_X=false",
"-e", "FLAG_RACE=false",
"-e", "FLAG_BUILDMODE=default",
"-e", "FLAG_TRIMPATH=false",
"-e", fmt.Sprintf("TARGETS=%s", projectOptions.Platform+"/"+projectOptions.Architecture),
"-e", "GOPROXY=",
"-e", "GO111MODULE=on",
"wailsapp/xgo:latest",
".",
} {
buildCommand.Add(arg)
}
compileMessage := fmt.Sprintf(
"Packing + Compiling project for %s/%s using docker image wailsapp/xgo:latest",
projectOptions.Platform, projectOptions.Architecture)
if buildMode == BuildModeDebug {
compileMessage += " (Debug Mode)"
}
if !projectOptions.Verbose {
packSpinner = spinner.New(compileMessage + "...")
packSpinner.SetSpinSpeed(50)
packSpinner.Start()
} else {
println(compileMessage)
}
err := NewProgramHelper(projectOptions.Verbose).RunCommandArray(buildCommand.AsSlice())
if err != nil {
if packSpinner != nil {
packSpinner.Error()
}
return err
}
if packSpinner != nil {
packSpinner.Success()
}
return nil
}
// BuildNative builds on the target platform itself.
func BuildNative(binaryName string, forceRebuild bool, buildMode string, projectOptions *ProjectOptions) error {
// Check Mewn is installed // Check Mewn is installed
if err := CheckMewn(projectOptions.Verbose); err != nil { err := CheckMewn()
return err if err != nil {
}
if err := CheckWindres(); err != nil {
return err return err
} }
@@ -203,37 +72,23 @@ func BuildNative(binaryName string, forceRebuild bool, buildMode string, project
compileMessage += " (Debug Mode)" compileMessage += " (Debug Mode)"
} }
var packSpinner *spinner.Spinner packSpinner := spinner.New(compileMessage + "...")
if !projectOptions.Verbose { packSpinner.SetSpinSpeed(50)
packSpinner = spinner.New(compileMessage + "...") packSpinner.Start()
packSpinner.SetSpinSpeed(50)
packSpinner.Start()
} else {
println(compileMessage)
}
buildCommand := slicer.String() buildCommand := slicer.String()
buildCommand.Add("go") buildCommand.Add("mewn")
buildCommand.Add("build")
if buildMode == BuildModeBridge { if buildMode == BuildModeBridge {
// Ignore errors // Ignore errors
buildCommand.Add("-i") buildCommand.Add("-i")
} }
buildCommand.Add("build")
if binaryName != "" { if binaryName != "" {
// Alter binary name based on OS buildCommand.Add("-o")
switch projectOptions.Platform { buildCommand.Add(binaryName)
case "windows":
if !strings.HasSuffix(binaryName, ".exe") {
binaryName += ".exe"
}
default:
if strings.HasSuffix(binaryName, ".exe") {
binaryName = strings.TrimSuffix(binaryName, ".exe")
}
}
buildCommand.Add("-o", filepath.Join("build", binaryName))
} }
// If we are forcing a rebuild // If we are forcing a rebuild
@@ -241,74 +96,28 @@ func BuildNative(binaryName string, forceRebuild bool, buildMode string, project
buildCommand.Add("-a") buildCommand.Add("-a")
} }
buildCommand.AddSlice([]string{"-ldflags", ldFlags(projectOptions, buildMode)}) // Setup ld flags
ldflags := "-w -s "
if projectOptions.Verbose { if buildMode == BuildModeDebug {
fmt.Printf("Command: %v\n", buildCommand.AsSlice()) ldflags = ""
} }
err := NewProgramHelper(projectOptions.Verbose).RunCommandArray(buildCommand.AsSlice()) // Add windows flags
if err != nil { if runtime.GOOS == "windows" {
if packSpinner != nil { ldflags += "-H windowsgui "
packSpinner.Error() }
}
return err ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
}
if packSpinner != nil { buildCommand.AddSlice([]string{"-ldflags", ldflags})
packSpinner.Success() err = NewProgramHelper().RunCommandArray(buildCommand.AsSlice())
}
return nil
}
// BuildApplication will attempt to build the project based on the given inputs
func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error {
var err error
// embed resources
targetFiles, err := EmbedAssets()
if err != nil {
return err
}
if projectOptions.CrossCompile {
if err := InitializeCrossCompilation(projectOptions.Verbose); err != nil {
return err
}
}
helper := NewPackageHelper(projectOptions.Platform)
// Generate windows resources
if projectOptions.Platform == "windows" {
if err := helper.PackageWindows(projectOptions, false); err != nil {
return err
}
}
// cleanup temporary embedded assets
defer func() {
for _, filename := range targetFiles {
if err := os.Remove(filename); err != nil {
fmt.Println(err)
}
}
// Removed by popular demand
// TODO: Potentially add a flag to cleanup
// if projectOptions.Platform == "windows" {
// helper.CleanWindows(projectOptions)
// }
}()
if projectOptions.CrossCompile {
err = BuildDocker(binaryName, buildMode, projectOptions)
} else {
err = BuildNative(binaryName, forceRebuild, buildMode, projectOptions)
}
if err != nil { if err != nil {
packSpinner.Error()
return err return err
} }
packSpinner.Success()
// packageApp
if packageApp { if packageApp {
err = PackageApplication(projectOptions) err = PackageApplication(projectOptions)
if err != nil { if err != nil {
@@ -321,76 +130,61 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
// PackageApplication will attempt to package the application in a platform dependent way // PackageApplication will attempt to package the application in a platform dependent way
func PackageApplication(projectOptions *ProjectOptions) error { func PackageApplication(projectOptions *ProjectOptions) error {
var packageSpinner *spinner.Spinner // Package app
if projectOptions.Verbose { message := "Generating .app"
packageSpinner = spinner.New("Packaging application...") if runtime.GOOS == "windows" {
packageSpinner.SetSpinSpeed(50) err := CheckWindres()
packageSpinner.Start() if err != nil {
} return err
err := NewPackageHelper(projectOptions.Platform).Package(projectOptions)
if err != nil {
if packageSpinner != nil {
packageSpinner.Error()
} }
message = "Generating resource bundle"
}
packageSpinner := spinner.New(message)
packageSpinner.SetSpinSpeed(50)
packageSpinner.Start()
err := NewPackageHelper().Package(projectOptions)
if err != nil {
packageSpinner.Error()
return err return err
} }
if packageSpinner != nil { packageSpinner.Success()
packageSpinner.Success()
}
return nil return nil
} }
// BuildFrontend runs the given build command // BuildFrontend runs the given build command
func BuildFrontend(projectOptions *ProjectOptions) error { func BuildFrontend(buildCommand string) error {
var buildFESpinner *spinner.Spinner buildFESpinner := spinner.New("Building frontend...")
if !projectOptions.Verbose { buildFESpinner.SetSpinSpeed(50)
buildFESpinner = spinner.New("Building frontend...") buildFESpinner.Start()
buildFESpinner.SetSpinSpeed(50) err := NewProgramHelper().RunCommand(buildCommand)
buildFESpinner.Start()
} else {
println("Building frontend...")
}
err := NewProgramHelper(projectOptions.Verbose).RunCommand(projectOptions.FrontEnd.Build)
if err != nil { if err != nil {
if buildFESpinner != nil { buildFESpinner.Error()
buildFESpinner.Error()
}
return err return err
} }
if buildFESpinner != nil { buildFESpinner.Success()
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(verbose bool) (err error) { func CheckMewn() (err error) {
programHelper := NewProgramHelper(verbose) programHelper := NewProgramHelper()
if !programHelper.IsInstalled("mewn") { if !programHelper.IsInstalled("mewn") {
var buildSpinner *spinner.Spinner buildSpinner := spinner.New()
if !verbose { buildSpinner.SetSpinSpeed(50)
buildSpinner = spinner.New() buildSpinner.Start("Installing Mewn asset packer...")
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 {
if buildSpinner != nil { buildSpinner.Error()
buildSpinner.Error()
}
return err return err
} }
if buildSpinner != nil { buildSpinner.Success()
buildSpinner.Success()
}
} }
return nil return nil
} }
// CheckWindres checks if Windres is installed and if not, aborts // CheckWindres checks if Windres is installed and if not, aborts
func CheckWindres() (err error) { func CheckWindres() (err error) {
if runtime.GOOS != "windows" { // FIXME: Handle windows cross-compile for windows! if runtime.GOOS != "windows" {
return nil return nil
} }
programHelper := NewProgramHelper() programHelper := NewProgramHelper()
@@ -400,15 +194,6 @@ 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 {
@@ -419,14 +204,9 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
} }
// Check if frontend deps have been updated // Check if frontend deps have been updated
var feSpinner *spinner.Spinner feSpinner := spinner.New("Ensuring frontend dependencies are up to date (This may take a while)")
if !projectOptions.Verbose { feSpinner.SetSpinSpeed(50)
feSpinner = spinner.New("Ensuring frontend dependencies are up to date (This may take a while)") feSpinner.Start()
feSpinner.SetSpinSpeed(50)
feSpinner.Start()
} else {
println("Ensuring frontend dependencies are up to date (This may take a while)")
}
requiresNPMInstall := true requiresNPMInstall := true
@@ -439,15 +219,6 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
const md5sumFile = "package.json.md5" const md5sumFile = "package.json.md5"
// If node_modules does not exist, force a rebuild.
nodeModulesPath, err := filepath.Abs(filepath.Join(".", "node_modules"))
if err != nil {
return err
}
if !fs.DirExists(nodeModulesPath) {
forceRebuild = true
}
// If we aren't forcing the install and the md5sum file exists // If we aren't forcing the install and the md5sum file exists
if !forceRebuild && fs.FileExists(md5sumFile) { if !forceRebuild && fs.FileExists(md5sumFile) {
// Yes - read contents // Yes - read contents
@@ -458,11 +229,7 @@ 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
if feSpinner != nil { feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)")
feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)")
} else {
println("Skipped frontend dependencies (-f to force rebuild)")
}
} }
} }
} }
@@ -471,16 +238,12 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
// Different? Build // Different? Build
if requiresNPMInstall || forceRebuild { if requiresNPMInstall || forceRebuild {
// Install dependencies // Install dependencies
err = NewProgramHelper(projectOptions.Verbose).RunCommand(projectOptions.FrontEnd.Install) err = NewProgramHelper().RunCommand(projectOptions.FrontEnd.Install)
if err != nil { if err != nil {
if feSpinner != nil { feSpinner.Error()
feSpinner.Error()
}
return err return err
} }
if feSpinner != nil { feSpinner.Success()
feSpinner.Success()
}
// Update md5sum file // Update md5sum file
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644) ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
@@ -493,7 +256,7 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
} }
// Build frontend // Build frontend
err = BuildFrontend(projectOptions) err = BuildFrontend(projectOptions.FrontEnd.Build)
if err != nil { if err != nil {
return err return err
} }
@@ -512,7 +275,7 @@ func InstallRuntime(caller string, projectDir string, projectOptions *ProjectOpt
// InstallBridge installs the relevant bridge javascript library // InstallBridge installs the relevant bridge javascript library
func InstallBridge(projectDir string, projectOptions *ProjectOptions) error { func InstallBridge(projectDir string, projectOptions *ProjectOptions) error {
bridgeFileData := mewn.String("../runtime/assets/bridge.js") bridgeFileData := mewn.String("../runtime/assets/bridge.js")
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "init.js") bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "main.js")
err := fs.CreateFile(bridgeFileTarget, []byte(bridgeFileData)) err := fs.CreateFile(bridgeFileTarget, []byte(bridgeFileData))
return err return err
} }
@@ -520,7 +283,7 @@ func InstallBridge(projectDir string, projectOptions *ProjectOptions) error {
// InstallProdRuntime installs the production runtime // InstallProdRuntime installs the production runtime
func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error { func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error {
prodInit := mewn.String("../runtime/js/runtime/init.js") prodInit := mewn.String("../runtime/js/runtime/init.js")
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "init.js") bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "main.js")
err := fs.CreateFile(bridgeFileTarget, []byte(prodInit)) err := fs.CreateFile(bridgeFileTarget, []byte(prodInit))
return err return err
} }
@@ -532,7 +295,7 @@ func ServeProject(projectOptions *ProjectOptions, logger *Logger) error {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<") logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<")
}() }()
location, err := filepath.Abs(filepath.Join("build", projectOptions.BinaryName)) location, err := filepath.Abs(projectOptions.BinaryName)
if err != nil { if err != nil {
return err return err
} }
@@ -548,33 +311,3 @@ func ServeProject(projectOptions *ProjectOptions, logger *Logger) error {
return nil return nil
} }
func ldFlags(po *ProjectOptions, buildMode string) string {
// Setup ld flags
ldflags := "-w -s "
if buildMode == BuildModeDebug {
ldflags = ""
}
// Add windows flags
if po.Platform == "windows" && buildMode == BuildModeProd {
ldflags += "-H windowsgui "
}
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
// Add additional ldflags passed in via the `ldflags` cli flag
if len(po.LdFlags) > 0 {
ldflags += " " + po.LdFlags
}
// If we wish to generate typescript
if po.typescriptDefsFilename != "" {
cwd, err := os.Getwd()
if err == nil {
filename := filepath.Join(cwd, po.FrontEnd.Dir, po.typescriptDefsFilename)
ldflags += " -X github.com/wailsapp/wails/lib/binding.typescriptDefinitionFilename=" + filename
}
}
return ldflags
}

View File

@@ -41,28 +41,6 @@ const (
Elementary Elementary
// Kali distribution // Kali distribution
Kali Kali
// Neon distribution
Neon
// ArcoLinux distribution
ArcoLinux
// Manjaro distribution
Manjaro
// ManjaroARM distribution
ManjaroARM
// Deepin distribution
Deepin
// Raspbian distribution
Raspbian
// Tumbleweed (OpenSUSE) distribution
Tumbleweed
// Leap (OpenSUSE) distribution
Leap
// ArchLabs distribution
ArchLabs
// PopOS distribution
PopOS
// Solus distribution
Solus
) )
// DistroInfo contains all the information relating to a linux distribution // DistroInfo contains all the information relating to a linux distribution
@@ -111,14 +89,13 @@ func parseOsRelease(osRelease string) *DistroInfo {
} }
switch splitLine[0] { switch splitLine[0] {
case "ID": case "ID":
osID = strings.ToLower(strings.Trim(splitLine[1], "\"")) osID = strings.Trim(splitLine[1], "\"")
case "NAME": case "NAME":
osNAME = strings.Trim(splitLine[1], "\"") osNAME = strings.Trim(splitLine[1], "\"")
case "VERSION_ID": case "VERSION_ID":
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":
@@ -127,8 +104,6 @@ func parseOsRelease(osRelease string) *DistroInfo {
result.Distribution = CentOS result.Distribution = CentOS
case "arch": case "arch":
result.Distribution = Arch result.Distribution = Arch
case "archlabs":
result.Distribution = ArchLabs
case "debian": case "debian":
result.Distribution = Debian result.Distribution = Debian
case "ubuntu": case "ubuntu":
@@ -147,26 +122,6 @@ func parseOsRelease(osRelease string) *DistroInfo {
result.Distribution = Elementary result.Distribution = Elementary
case "kali": case "kali":
result.Distribution = Kali result.Distribution = Kali
case "neon":
result.Distribution = Neon
case "arcolinux":
result.Distribution = ArcoLinux
case "manjaro":
result.Distribution = Manjaro
case "manjaro-arm":
result.Distribution = ManjaroARM
case "deepin":
result.Distribution = Deepin
case "raspbian":
result.Distribution = Raspbian
case "opensuse-tumbleweed":
result.Distribution = Tumbleweed
case "opensuse-leap":
result.Distribution = Leap
case "pop":
result.Distribution = PopOS
case "solus":
result.Distribution = Solus
default: default:
result.Distribution = Unknown result.Distribution = Unknown
} }
@@ -203,17 +158,6 @@ func DpkgInstalled(packageName string) (bool, error) {
return exitCode == 0, nil return exitCode == 0, nil
} }
// EOpkgInstalled uses dpkg to see if a package is installed
func EOpkgInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
eopkg := program.FindProgram("eopkg")
if eopkg == nil {
return false, fmt.Errorf("cannot check dependencies: eopkg not found")
}
stdout, _, _, _ := eopkg.Run("info", packageName)
return strings.HasPrefix(stdout, "Installed"), nil
}
// PacmanInstalled uses pacman to see if a package is installed. // PacmanInstalled uses pacman to see if a package is installed.
func PacmanInstalled(packageName string) (bool, error) { func PacmanInstalled(packageName string) (bool, error) {
program := NewProgramHelper() program := NewProgramHelper()
@@ -285,9 +229,5 @@ func RequestSupportForDistribution(distroInfo *DistroInfo) error {
fmt.Println("Opening browser to file request.") fmt.Println("Opening browser to file request.")
browser.OpenURL(fullURL + url.PathEscape(params)) browser.OpenURL(fullURL + url.PathEscape(params))
result = Prompt("We have a guide for adding support for your distribution. Would you like to view it?", "yes")
if strings.ToLower(result) == "yes" {
browser.OpenURL("https://wails.app/guides/distro/")
}
return nil return nil
} }

View File

@@ -22,25 +22,5 @@ UBUNTU_CODENAME=bionic
if result.Distribution != Ubuntu { if result.Distribution != Ubuntu {
t.Errorf("expected 'Ubuntu' ID but got '%d'", result.Distribution) t.Errorf("expected 'Ubuntu' ID but got '%d'", result.Distribution)
} }
}
func TestTumbleweedDetection(t *testing.T) {
osrelease := `
NAME="openSUSE Tumbleweed"
# VERSION="20200414"
ID="opensuse-tumbleweed"
ID_LIKE="opensuse suse"
VERSION_ID="20200414"
PRETTY_NAME="openSUSE Tumbleweed"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:opensuse:tumbleweed:20200414"
BUG_REPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org/"
LOGO="distributor-logo"
`
result := parseOsRelease(osrelease)
if result.Distribution != Tumbleweed {
t.Errorf("expected 'Tumbleweed' ID but got '%d'", result.Distribution)
}
} }

View File

@@ -3,6 +3,7 @@ package cmd
import ( import (
"log" "log"
"github.com/leaanthony/mewn"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -78,14 +79,11 @@ 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, err := fs.LoadRelativeFile("./linuxdb.yaml") data := mewn.Bytes("./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)
} }

View File

@@ -28,15 +28,6 @@ distributions:
gccversioncommand: &gccdumpfullversion -dumpfullversion gccversioncommand: &gccdumpfullversion -dumpfullversion
programs: *debiandefaultprograms programs: *debiandefaultprograms
libraries: *debiandefaultlibraries libraries: *debiandefaultlibraries
pop:
id: pop
releases:
default:
version: default
name: Pop!_OS
gccversioncommand: &gccdumpfullversion -dumpfullversion
programs: *debiandefaultprograms
libraries: *debiandefaultlibraries
kali: kali:
id: kali id: kali
releases: releases:
@@ -82,24 +73,6 @@ distributions:
gccversioncommand: *gccdumpfullversion gccversioncommand: *gccdumpfullversion
programs: *debiandefaultprograms programs: *debiandefaultprograms
libraries: *debiandefaultlibraries libraries: *debiandefaultlibraries
neon:
id: neon
releases:
default:
version: default
name: KDE neon
gccversioncommand: *gccdumpfullversion
programs: *debiandefaultprograms
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:
@@ -164,54 +137,18 @@ distributions:
version: default version: default
name: Arch Linux name: Arch Linux
gccversioncommand: *gccdumpversion gccversioncommand: *gccdumpversion
programs: &archdefaultprograms programs:
- name: gcc - name: gcc
help: Please install with `sudo pacman -S gcc` and try again help: Please install with `sudo pacman -S gcc` and try again
- name: pkgconf - name: pkgconf
help: Please install with `sudo pacman -S pkgconf` and try again help: Please install with `sudo pacman -S pkgconf` and try again
- name: npm - name: npm
help: Please install with `sudo pacman -S npm` and try again help: Please install with `sudo pacman -S npm` and try again
libraries: &archdefaultlibraries libraries:
- name: gtk3 - name: gtk3
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
archlabs:
id: archlabs
releases:
default:
version: default
name: ArchLabs
gccversioncommand: *gccdumpversion
programs: *archdefaultprograms
libraries: *archdefaultlibraries
manjaro:
id: manjaro
releases:
default:
version: default
name: Manjaro Linux
gccversioncommand: *gccdumpversion
programs: *archdefaultprograms
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:
@@ -230,62 +167,4 @@ 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
solus:
id: solus
releases:
default:
version: default
name: Solus
gccversioncommand: *gccdumpfullversion
programs: &solusdefaultprograms
- name: gcc
help: Please install with `sudo eopkg it -c system.devel` and try again
- name: pkg-config
help: Please install with `sudo eopkg it -c system.devel` and try again
- name: npm
help: Please install with `sudo eopkg it nodejs` and try again
libraries: &solusdefaultlibraries
- name: libgtk-3-devel
help: Please install with `sudo eopkg it libgtk-3-devel` and try again
- name: libwebkit-gtk-devel
help: Please install with `sudo eopkg it libwebkit-gtk-devel` and try again
opensuse-tumbleweed:
id: opensuse-tumbleweed
releases:
default:
version: default
name: openSUSE Tumbleweed
gccversioncommand: *gccdumpfullversion
programs: &opensusedefaultprograms
- name: gcc
help: Please install with `sudo zypper in gcc-c++` and try again
- name: pkg-config
help: Please install with `sudo zypper in pkgconf-pkg-config` and try again
- name: npm
help: Please install `sudo zypper in nodejs` and try again
libraries: &opensusedefaultlibraries
- name: gtk3-devel
help: Please install with `sudo zypper in gtk3-devel` and try again
- name: webkit2gtk3-devel
help: Please install with `sudo zypper in webkit2gtk3-devel` and try again
opensuse-leap:
id: opensuse-leap
releases:
default:
version: default
name: openSUSE Leap
gccversioncommand: *gccdumpfullversion
programs: *opensusedefaultprograms
libraries: *opensusedefaultlibraries

View File

@@ -1,12 +1,9 @@
package cmd package cmd
import ( import (
"bufio"
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"image" "image"
"image/png"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path"
@@ -17,24 +14,21 @@ import (
"time" "time"
"github.com/jackmordaunt/icns" "github.com/jackmordaunt/icns"
"golang.org/x/image/draw"
) )
// PackageHelper helps with the 'wails package' command // PackageHelper helps with the 'wails package' command
type PackageHelper struct { type PackageHelper struct {
platform string fs *FSHelper
fs *FSHelper log *Logger
log *Logger system *SystemHelper
system *SystemHelper
} }
// NewPackageHelper creates a new PackageHelper! // NewPackageHelper creates a new PackageHelper!
func NewPackageHelper(platform string) *PackageHelper { func NewPackageHelper() *PackageHelper {
return &PackageHelper{ return &PackageHelper{
platform: platform, fs: NewFSHelper(),
fs: NewFSHelper(), log: NewLogger(),
log: NewLogger(), system: NewSystemHelper(),
system: NewSystemHelper(),
} }
} }
@@ -59,111 +53,6 @@ func newPlistData(title, exe, packageID, version, author string) *plistData {
} }
} }
type windowsIcoHeader struct {
_ uint16
imageType uint16
imageCount uint16
}
type windowsIcoDescriptor struct {
width uint8
height uint8
colours uint8
_ uint8
planes uint16
bpp uint16
size uint32
offset uint32
}
type windowsIcoContainer struct {
Header windowsIcoDescriptor
Data []byte
}
func generateWindowsIcon(pngFilename string, iconfile string) error {
sizes := []int{256, 128, 64, 48, 32, 16}
pngfile, err := os.Open(pngFilename)
if err != nil {
return err
}
defer pngfile.Close()
pngdata, err := png.Decode(pngfile)
if err != nil {
return err
}
icons := []windowsIcoContainer{}
for _, size := range sizes {
rect := image.Rect(0, 0, int(size), int(size))
rawdata := image.NewRGBA(rect)
scale := draw.CatmullRom
scale.Scale(rawdata, rect, pngdata, pngdata.Bounds(), draw.Over, nil)
icondata := new(bytes.Buffer)
writer := bufio.NewWriter(icondata)
err = png.Encode(writer, rawdata)
if err != nil {
return err
}
writer.Flush()
imgSize := size
if imgSize >= 256 {
imgSize = 0
}
data := icondata.Bytes()
icn := windowsIcoContainer{
Header: windowsIcoDescriptor{
width: uint8(imgSize),
height: uint8(imgSize),
planes: 1,
bpp: 32,
size: uint32(len(data)),
},
Data: data,
}
icons = append(icons, icn)
}
outfile, err := os.Create(iconfile)
if err != nil {
return err
}
defer outfile.Close()
ico := windowsIcoHeader{
imageType: 1,
imageCount: uint16(len(sizes)),
}
err = binary.Write(outfile, binary.LittleEndian, ico)
if err != nil {
return err
}
offset := uint32(6 + 16*len(sizes))
for _, icon := range icons {
icon.Header.offset = offset
err = binary.Write(outfile, binary.LittleEndian, icon.Header)
if err != nil {
return err
}
offset += icon.Header.size
}
for _, icon := range icons {
_, err = outfile.Write(icon.Data)
if err != nil {
return err
}
}
return nil
}
func defaultString(val string, defaultVal string) string { func defaultString(val string, defaultVal string) string {
if val != "" { if val != "" {
return val return val
@@ -174,30 +63,29 @@ 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", b.platform) return filepath.Join(path.Dir(filename), "packages", runtime.GOOS)
} }
// 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 b.platform { switch runtime.GOOS {
case "darwin": case "darwin":
// Check we have the exe
if !b.fs.FileExists(po.BinaryName) {
return fmt.Errorf("cannot bundle non-existent binary file '%s'. Please build with 'wails build' first", po.BinaryName)
}
return b.packageOSX(po) return b.packageOSX(po)
case "windows": case "windows":
return b.PackageWindows(po, true) return b.PackageWindows(po, false)
case "linux": case "linux":
return b.packageLinux(po) 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", b.platform) return fmt.Errorf("platform '%s' not supported for bundling yet", runtime.GOOS)
} }
} }
func (b *PackageHelper) packageLinux(po *ProjectOptions) error {
return nil
}
// Package the application for OSX // Package the application for OSX
func (b *PackageHelper) packageOSX(po *ProjectOptions) error { func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
build := path.Join(b.fs.Cwd(), "build")
system := NewSystemHelper() system := NewSystemHelper()
config, err := system.LoadConfig() config, err := system.LoadConfig()
@@ -212,68 +100,39 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
packageID := strings.Join([]string{"wails", name, version}, ".") packageID := strings.Join([]string{"wails", name, version}, ".")
plistData := newPlistData(name, exe, packageID, version, author) plistData := newPlistData(name, exe, packageID, version, author)
appname := po.Name + ".app" appname := po.Name + ".app"
plistFilename := path.Join(build, appname, "Contents", "Info.plist")
customPlist := path.Join(b.fs.Cwd(), "info.plist")
// Check binary exists // Check binary exists
source := path.Join(build, exe) source := path.Join(b.fs.Cwd(), exe)
if po.CrossCompile == true {
file, err := b.fs.FindFile(build, "darwin")
if err != nil {
return err
}
source = path.Join(build, file)
}
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?", source) return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", exe)
} }
// Remove the existing package // Remove the existing package
os.RemoveAll(appname) os.RemoveAll(appname)
// Create directories exeDir := path.Join(b.fs.Cwd(), appname, "/Contents/MacOS")
exeDir := path.Join(build, appname, "/Contents/MacOS")
b.fs.MkDirs(exeDir, 0755) b.fs.MkDirs(exeDir, 0755)
resourceDir := path.Join(build, appname, "/Contents/Resources") resourceDir := path.Join(b.fs.Cwd(), appname, "/Contents/Resources")
b.fs.MkDirs(resourceDir, 0755) b.fs.MkDirs(resourceDir, 0755)
tmpl := template.New("infoPlist")
plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist")
infoPlist, err := ioutil.ReadFile(plistFile)
if err != nil {
return err
}
tmpl.Parse(string(infoPlist))
// Do we have a custom plist in the project directory? // Write the template to a buffer
if !fs.FileExists(customPlist) { var tpl bytes.Buffer
err = tmpl.Execute(&tpl, plistData)
// No - create a new plist from our defaults if err != nil {
tmpl := template.New("infoPlist") return err
plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist") }
infoPlist, err := ioutil.ReadFile(plistFile) filename := path.Join(b.fs.Cwd(), appname, "Contents", "Info.plist")
if err != nil { err = ioutil.WriteFile(filename, tpl.Bytes(), 0644)
return err if err != nil {
} return err
tmpl.Parse(string(infoPlist))
// Write the template to a buffer
var tpl bytes.Buffer
err = tmpl.Execute(&tpl, plistData)
if err != nil {
return err
}
// Save to the package
err = ioutil.WriteFile(plistFilename, tpl.Bytes(), 0644)
if err != nil {
return err
}
// Also write to project directory for customisation
err = ioutil.WriteFile(customPlist, tpl.Bytes(), 0644)
if err != nil {
return err
}
} else {
// Yes - we have a plist. Copy it to the package verbatim
err = fs.CopyFile(customPlist, plistFilename)
if err != nil {
return err
}
} }
// Copy executable // Copy executable
@@ -291,37 +150,22 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
return err return err
} }
// CleanWindows removes any windows related files found in the directory
func (b *PackageHelper) CleanWindows(po *ProjectOptions) {
pdir := b.fs.Cwd()
basename := strings.TrimSuffix(po.BinaryName, ".exe")
exts := []string{".ico", ".exe.manifest", ".rc", "-res.syso"}
rsrcs := []string{}
for _, ext := range exts {
rsrcs = append(rsrcs, filepath.Join(pdir, basename+ext))
}
b.fs.RemoveFiles(rsrcs, true)
}
// PackageWindows packages the application for windows platforms // PackageWindows packages the application for windows platforms
func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error { func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
outputDir := b.fs.Cwd()
basename := strings.TrimSuffix(po.BinaryName, ".exe") basename := strings.TrimSuffix(po.BinaryName, ".exe")
// Copy default icon if needed // Copy icon
icon, err := b.copyIcon() tgtIconFile := filepath.Join(b.fs.Cwd(), basename+".ico")
if err != nil { if !b.fs.FileExists(tgtIconFile) {
return err srcIconfile := filepath.Join(b.getPackageFileBaseDir(), "wails.ico")
} err := b.fs.CopyFile(srcIconfile, tgtIconFile)
if err != nil {
// Generate icon from PNG return err
err = generateWindowsIcon(icon, basename+".ico") }
if err != nil {
return err
} }
// Copy manifest // Copy manifest
tgtManifestFile := filepath.Join(outputDir, basename+".exe.manifest") tgtManifestFile := filepath.Join(b.fs.Cwd(), basename+".exe.manifest")
if !b.fs.FileExists(tgtManifestFile) { if !b.fs.FileExists(tgtManifestFile) {
srcManifestfile := filepath.Join(b.getPackageFileBaseDir(), "wails.exe.manifest") srcManifestfile := filepath.Join(b.getPackageFileBaseDir(), "wails.exe.manifest")
err := b.fs.CopyFile(srcManifestfile, tgtManifestFile) err := b.fs.CopyFile(srcManifestfile, tgtManifestFile)
@@ -331,7 +175,7 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
} }
// Copy rc file // Copy rc file
tgtRCFile := filepath.Join(outputDir, basename+".rc") tgtRCFile := filepath.Join(b.fs.Cwd(), basename+".rc")
if !b.fs.FileExists(tgtRCFile) { if !b.fs.FileExists(tgtRCFile) {
srcRCfile := filepath.Join(b.getPackageFileBaseDir(), "wails.rc") srcRCfile := filepath.Join(b.getPackageFileBaseDir(), "wails.rc")
rcfilebytes, err := ioutil.ReadFile(srcRCfile) rcfilebytes, err := ioutil.ReadFile(srcRCfile)
@@ -346,37 +190,26 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
} }
// Build syso // Build syso
sysofile := filepath.Join(outputDir, basename+"-res.syso") sysofile := filepath.Join(b.fs.Cwd(), basename+"-res.syso")
windresCommand := []string{"windres", "-o", sysofile, tgtRCFile}
err := NewProgramHelper().RunCommandArray(windresCommand)
if err != nil {
return err
}
// cross-compile // clean up
if b.platform != runtime.GOOS { if cleanUp {
args := []string{ filesToDelete := []string{tgtIconFile, tgtManifestFile, tgtRCFile, sysofile}
"docker", "run", "--rm", err := b.fs.RemoveFiles(filesToDelete)
"-v", outputDir + ":/build",
"--entrypoint", "/bin/sh",
"wailsapp/xgo:latest",
"-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 { if err != nil {
return err return err
} }
} }
return nil return nil
} }
func (b *PackageHelper) copyIcon() (string, error) { func (b *PackageHelper) copyIcon(resourceDir string) (string, error) {
// TODO: Read this from project.json // TODO: Read this from project.json
const appIconFilename = "appicon.png" const appIconFilename = "appicon.png"
@@ -401,7 +234,7 @@ func (b *PackageHelper) copyIcon() (string, error) {
func (b *PackageHelper) packageIconOSX(resourceDir string) error { func (b *PackageHelper) packageIconOSX(resourceDir string) error {
srcIcon, err := b.copyIcon() srcIcon, err := b.copyIcon(resourceDir)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,6 +1,5 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict> <plist version="1.0"><dict>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleName</key><string>{{.Title}}</string> <key>CFBundleName</key><string>{{.Title}}</string>
<key>CFBundleExecutable</key><string>{{.Exe}}</string> <key>CFBundleExecutable</key><string>{{.Exe}}</string>
<key>CFBundleIdentifier</key><string>{{.PackageID}}</string> <key>CFBundleIdentifier</key><string>{{.PackageID}}</string>

View File

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

View File

@@ -3,7 +3,6 @@ package cmd
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -12,22 +11,14 @@ 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(verbose ...bool) *ProgramHelper { func NewProgramHelper() *ProgramHelper {
result := &ProgramHelper{ return &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
@@ -38,9 +29,8 @@ 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
@@ -55,9 +45,8 @@ 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,
} }
} }
@@ -74,18 +63,12 @@ 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...)
if !p.verbose { var stdo, stde bytes.Buffer
var stdo, stde bytes.Buffer cmd.Stdout = &stdo
cmd.Stdout = &stdo cmd.Stderr = &stde
cmd.Stderr = &stde err = cmd.Run()
err = cmd.Run() stdout = string(stdo.Bytes())
stdout = string(stdo.Bytes()) stderr = string(stde.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 {
@@ -117,19 +100,6 @@ func (p *ProgramHelper) InstallGoPackage(packageName string) error {
return err return err
} }
// InstallNPMPackage installs the given npm package
func (p *ProgramHelper) InstallNPMPackage(packageName string, save bool) error {
args := strings.Split("install "+packageName, " ")
if save {
args = append(args, "--save")
}
_, stderr, err := p.shell.Run("npm", args...)
if err != nil {
fmt.Println(stderr)
}
return err
}
// RunCommand runs the given command // RunCommand runs the given command
func (p *ProgramHelper) RunCommand(command string) error { func (p *ProgramHelper) RunCommand(command string) error {
args := strings.Split(command, " ") args := strings.Split(command, " ")
@@ -138,14 +108,13 @@ func (p *ProgramHelper) RunCommand(command string) error {
// RunCommandArray runs the command specified in the array // RunCommandArray runs the command specified in the array
func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error { func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error {
programCommand := args[0] program := args[0]
// TODO: Run FindProgram here and get the full path to the exe // TODO: Run FindProgram here and get the full path to the exe
program, err := exec.LookPath(programCommand) program, err := exec.LookPath(program)
if err != nil { if err != nil {
fmt.Printf("ERROR: Looks like '%s' isn't installed. Please install and try again.", programCommand) fmt.Printf("ERROR: Looks like '%s' isn't installed. Please install and try again.", program)
return err return err
} }
args = args[1:] args = args[1:]
var stderr string var stderr string
var stdout string var stdout string

View File

@@ -6,24 +6,13 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"sort" "sort"
"strings" "strings"
"github.com/leaanthony/slicer" "github.com/leaanthony/slicer"
) )
// PackageManager indicates different package managers
type PackageManager int
const (
// UNKNOWN package manager
UNKNOWN PackageManager = iota
// NPM package manager
NPM
// YARN package manager
YARN
)
type author struct { type author struct {
Name string `json:"name"` Name string `json:"name"`
Email string `json:"email"` Email string `json:"email"`
@@ -141,27 +130,21 @@ 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
Platform string
Architecture string
LdFlags string
} }
// Defaults sets the default project template // Defaults sets the default project template
@@ -170,28 +153,6 @@ 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
func (po *ProjectOptions) GetNPMBinaryName() (PackageManager, error) {
if po.FrontEnd == nil {
return UNKNOWN, fmt.Errorf("No frontend specified in project options")
}
if strings.Index(po.FrontEnd.Install, "npm") > -1 {
return NPM, nil
}
if strings.Index(po.FrontEnd.Install, "yarn") > -1 {
return YARN, nil
}
return UNKNOWN, nil
}
// PromptForInputs asks the user to input project details // PromptForInputs asks the user to input project details
func (po *ProjectOptions) PromptForInputs() error { func (po *ProjectOptions) PromptForInputs() error {
@@ -336,6 +297,11 @@ func processBinaryName(po *ProjectOptions) {
if po.BinaryName == "" { if po.BinaryName == "" {
var binaryNameComputed = computeBinaryName(po.Name) var binaryNameComputed = computeBinaryName(po.Name)
po.BinaryName = Prompt("The output binary name", binaryNameComputed) po.BinaryName = Prompt("The output binary name", binaryNameComputed)
if runtime.GOOS == "windows" {
if !strings.HasSuffix(po.BinaryName, ".exe") {
po.BinaryName += ".exe"
}
}
} }
fmt.Println("Output binary Name: " + po.BinaryName) fmt.Println("Output binary Name: " + po.BinaryName)
} }

View File

@@ -8,7 +8,6 @@ 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!
@@ -16,27 +15,16 @@ 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")
if !sh.verbose { var stdo, stde bytes.Buffer
var stdo, stde bytes.Buffer cmd.Stdout = &stdo
cmd.Stdout = &stdo cmd.Stderr = &stde
cmd.Stderr = &stde err = cmd.Run()
err = cmd.Run() stdout = string(stdo.Bytes())
stdout = string(stdo.Bytes()) stderr = string(stde.Bytes())
stderr = string(stde.Bytes())
} else {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
}
return return
} }
@@ -45,17 +33,11 @@ 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")
if !sh.verbose { var stdo, stde bytes.Buffer
var stdo, stde bytes.Buffer cmd.Stdout = &stdo
cmd.Stdout = &stdo cmd.Stderr = &stde
cmd.Stderr = &stde err = cmd.Run()
err = cmd.Run() stdout = string(stdo.Bytes())
stdout = string(stdo.Bytes()) stderr = string(stde.Bytes())
stderr = string(stde.Bytes())
} else {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
}
return return
} }

View File

@@ -5,11 +5,12 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"time" "time"
homedir "github.com/mitchellh/go-homedir"
) )
// SystemHelper - Defines everything related to the system // SystemHelper - Defines everything related to the system
@@ -37,11 +38,10 @@ func NewSystemHelper() *SystemHelper {
// setSystemDirs calculates the system directories it is interested in // setSystemDirs calculates the system directories it is interested in
func (s *SystemHelper) setSystemDirs() { func (s *SystemHelper) setSystemDirs() {
var err error var err error
s.homeDir, err = os.UserHomeDir() s.homeDir, err = homedir.Dir()
if err != nil { if err != nil {
log.Fatal("Cannot find home directory! Please file a bug report!") log.Fatal("Cannot find home directory! Please file a bug report!")
} }
// TODO: A better config system // TODO: A better config system
s.wailsSystemDir = filepath.Join(s.homeDir, ".wails") s.wailsSystemDir = filepath.Join(s.homeDir, ".wails")
s.wailsSystemConfig = filepath.Join(s.wailsSystemDir, s.configFilename) s.wailsSystemConfig = filepath.Join(s.wailsSystemDir, s.configFilename)
@@ -132,7 +132,7 @@ func (s *SystemHelper) setup() error {
} }
const introText = ` const introText = `
Wails is a lightweight framework for creating web-like desktop apps in Go. Wails is a lightweight framework for creating web-like desktop apps in Go.
I'll need to ask you a few questions so I can fill in your project templates and then I will try and see if you have the correct dependencies installed. If you don't have the right tools installed, I'll try and suggest how to install them. I'll need to ask you a few questions so I can fill in your project templates and then I will try and see if you have the correct dependencies installed. If you don't have the right tools installed, I'll try and suggest how to install them.
` `
@@ -274,18 +274,16 @@ 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, Deepin, Raspbian, PopOS: case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali:
libraryChecker = DpkgInstalled libraryChecker = DpkgInstalled
case Arch, ArcoLinux, ArchLabs, Manjaro, ManjaroARM: case Arch:
libraryChecker = PacmanInstalled libraryChecker = PacmanInstalled
case CentOS, Fedora, Tumbleweed, Leap: case CentOS, Fedora:
libraryChecker = RpmInstalled libraryChecker = RpmInstalled
case Gentoo: case Gentoo:
libraryChecker = EqueryInstalled libraryChecker = EqueryInstalled
case VoidLinux: case VoidLinux:
libraryChecker = XbpsInstalled libraryChecker = XbpsInstalled
case Solus:
libraryChecker = EOpkgInstalled
default: default:
return false, RequestSupportForDistribution(distroInfo) return false, RequestSupportForDistribution(distroInfo)
} }

View File

@@ -9,4 +9,4 @@
last 2 versions last 2 versions
Firefox ESR Firefox ESR
not dead not dead
IE 9-11 # For IE 9-11 support, remove 'not'. not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@@ -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 --host=0.0.0.0", "start": "npx ng serve --poll=2000",
"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,7 +22,6 @@
"@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",

View File

@@ -1,4 +1,3 @@
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';
@@ -7,7 +6,7 @@ import { environment } from './environments/environment';
import 'zone.js' import 'zone.js'
import * as Wails from '@wailsapp/runtime'; import Wails from '@wailsapp/runtime';
if (environment.production) { if (environment.production) {
enableProdMode(); enableProdMode();

View File

@@ -0,0 +1,17 @@
/*
Wails Bridge (c) 2019-present Lea Anthony
This prod version is to get around having to rewrite your code
for production. When doing a release build, this file will be used
instead of the full version.
*/
export default {
// The main function
// Passes the main Wails object to the callback if given.
Start: function(callback) {
if (callback) {
window.wails.events.on("wails:ready", callback);
}
}
};

View File

@@ -11,7 +11,7 @@
"module": "esnext", "module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"importHelpers": true, "importHelpers": true,
"target": "es5", "target": "es2015",
"typeRoots": [ "typeRoots": [
"node_modules/@types" "node_modules/@types"
], ],
@@ -20,4 +20,4 @@
"dom" "dom"
] ]
} }
} }

View File

@@ -11,7 +11,7 @@ func basic() string {
func main() { func main() {
js := mewn.String("./frontend/dist/my-app/main.js") js := mewn.String("./frontend/dist/my-app/main-es2015.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{

View File

@@ -4,12 +4,12 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"core-js": "^3.6.4", "core-js": "^3.1.4",
"react": "^16.13.1", "react": "^16.8.6",
"react-dom": "^16.13.1", "react-dom": "^16.8.6",
"wails-react-scripts": "3.0.1-2", "@wailsapp/wails-react-scripts": "3.0.1-2",
"react-modal": "3.11.2", "react-modal": "3.8.1",
"@wailsapp/runtime": "^1.0.10" "@wailsapp/runtime": "^1.0.0"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,13 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
@@ -23,9 +20,8 @@
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>React App</title>
</head> </head>
<body>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="app"></div> <div id="app"></div>
<!-- <!--
@@ -38,6 +34,5 @@
To begin the development, run `npm start` or `yarn start`. To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`. To create a production bundle, use `npm run build` or `yarn build`.
--> -->
</body> </body>
</html>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

View File

@@ -6,16 +6,6 @@
"src": "favicon.ico", "src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16", "sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon" "type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
} }
], ],
"start_url": ".", "start_url": ".",

View File

@@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@@ -3,16 +3,11 @@
} }
.App-logo { .App-logo {
animation: App-logo-spin infinite 20s linear;
height: 40vmin; height: 40vmin;
pointer-events: none; pointer-events: none;
} }
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header { .App-header {
background-color: #282c34; background-color: #282c34;
min-height: 100vh; min-height: 100vh;

View File

@@ -1,35 +1,48 @@
import React, { useState } from 'react'; import React from 'react';
import Modal from 'react-modal'; import Modal from 'react-modal';
function HelloWorld() { class HelloWorld extends React.Component {
const [showModal, setShowModal] = useState(false); constructor(props, context) {
const [result, setResult] = useState(null); super();
this.state = {
showModal: false
};
const handleOpenModal = () => { this.handleOpenModal = this.handleOpenModal.bind(this);
setShowModal(true); this.handleCloseModal = this.handleCloseModal.bind(this);
}
window.backend.basic().then((result) => setResult(result)); handleOpenModal () {
}; this.setState({ showModal: true });
const handleCloseModal = () => { window.backend.basic().then(result =>
setShowModal(false); this.setState({
}; result
})
);
}
return ( handleCloseModal () {
<div className="App"> this.setState({ showModal: false });
<button onClick={() => handleOpenModal()} type="button"> }
Hello
</button> render() {
<Modal const { result } = this.state;
appElement={document.getElementById("app")} return (
isOpen={showModal} <div className="App">
contentLabel="Minimal Modal Example" <button onClick={this.handleOpenModal} type="button">
> Hello
<p>{result}</p> </button>
<button onClick={() => handleCloseModal()}>Close Modal</button> <Modal
</Modal> isOpen={this.state.showModal}
</div> contentLabel="Minimal Modal Example"
); >
<p>{result}</p>
<button onClick={this.handleCloseModal}>Close Modal</button>
</Modal>
</div>
);
}
} }
export default HelloWorld; export default HelloWorld;

View File

@@ -3,20 +3,9 @@ import ReactDOM from 'react-dom';
import 'core-js/stable'; import 'core-js/stable';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import * as serviceWorker from './serviceWorker';
import * as Wails from '@wailsapp/runtime'; import Wails from '@wailsapp/runtime';
Wails.Init(() => { Wails.Init(() => {
ReactDOM.render( ReactDOM.render(<App />, document.getElementById('app'));
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("app")
);
}); });
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

View File

@@ -0,0 +1,17 @@
/*
Wails Bridge (c) 2019-present Lea Anthony
This prod version is to get around having to rewrite your code
for production. When doing a release build, this file will be used
instead of the full version.
*/
export default {
// The main function
// Passes the main Wails object to the callback if given.
Start: function (callback) {
if (callback) {
window.wails.Events.On("wails:ready", callback);
}
}
};

View File

@@ -1,8 +1,8 @@
{ {
"name": "React JS", "name": "React JS",
"version": "1.0.0", "version": "1.0.0",
"shortdescription": "Create React App v4 template", "shortdescription": "Create React App v3 template",
"description": "Create React App v4 standard tooling", "description": "Create React App v3 standar tooling",
"install": "npm install", "install": "npm install",
"build": "npm run build", "build": "npm run build",
"author": "bh90210 <ktc@pm.me>", "author": "bh90210 <ktc@pm.me>",

View File

@@ -1,5 +0,0 @@
# README
This is an experimental template for vanilla HTML/JS/CSS.
The webpack rules may need to be adjusted to correctly embed all assets. Babel may also need to be setup correctly.

View File

@@ -1,42 +0,0 @@
{
"name": "vanilla",
"author": "Lea<l>",
"private": true,
"scripts": {
"serve": "webpack-dev-server",
"build": "npx webpack"
},
"dependencies": {
"core-js": "^3.6.4",
"regenerator-runtime": "^0.13.3",
"@wailsapp/runtime": "^1.0.10"
},
"devDependencies": {
"babel-eslint": "^10.1.0",
"copy-webpack-plugin": "^6.0.2",
"eslint": "^6.8.0",
"eventsource-polyfill": "^0.9.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0",
"webpack-hot-middleware": "^2.25.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

View File

@@ -1,9 +0,0 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div id="app"></div>
<script src="main.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -1,30 +0,0 @@
import 'core-js/stable';
const runtime = require('@wailsapp/runtime');
// Main entry point
function start() {
// Ensure the default app div is 100% wide/high
var app = document.getElementById('app');
app.style.width = '100%';
app.style.height = '100%';
// Inject html
app.innerHTML = `
<div class='logo'></div>
<div class='container'>
<button id='button'>Click Me!</button>
<div id='result'/>
</div>
`;
// Connect button to Go method
document.getElementById('button').onclick = function() {
window.backend.basic().then( function(result) {
document.getElementById('result').innerText = result;
});
};
};
// We provide our entrypoint as a callback for runtime.Init
runtime.Init(start);

View File

@@ -1,56 +0,0 @@
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
let imageSizeLimit = 9007199254740991; // Number.MAX_SAFE_INTEGER
let sourceDir = path.resolve(__dirname, 'src');
let buildDir = path.resolve(__dirname, 'build');
module.exports = {
entry: {
index: path.resolve(sourceDir, 'main.js')
},
output: {
path: buildDir,
filename: 'main.js'
},
optimization: {
splitChunks: false
},
devServer: {
disableHostCheck: true,
contentBase: path.join(__dirname, 'src'),
compress: true,
open: true,
port: 8090
},
mode: 'production',
module: {
rules: [
{
test: /\.(png|gif|jpg|woff2?|eot|ttf|otf|svg)(\?.*)?$/i,
use: [
{
loader: 'url-loader',
options: {
limit: imageSizeLimit
}
}
],
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(sourceDir, 'main.css'),
to: path.resolve(buildDir, 'main.css')
},
{
from: path.resolve(sourceDir, 'index.html'),
to: path.resolve(buildDir, 'index.html')
},
]
})
]
};

View File

@@ -1,5 +0,0 @@
module {{.BinaryName}}
require (
github.com/wailsapp/wails {{.WailsVersion}}
)

View File

@@ -1,27 +0,0 @@
package main
import (
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
func basic() string {
return "Hello World!"
}
func main() {
js := mewn.String("./frontend/build/main.js")
css := mewn.String("./frontend/build/main.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,
Title: "{{.Name}}",
JS: js,
CSS: css,
Colour: "#131313",
})
app.Bind(basic)
app.Run()
}

View File

@@ -1,12 +0,0 @@
{
"name": "Vanilla",
"shortdescription": "A Vanilla HTML/JS template",
"description": "A basic template using plain html/js and bundled using Webpack 4",
"author": "Lea Anthony<lea.anthony@gmail.com>",
"created": "2020-06-14",
"frontenddir": "frontend",
"install": "npm install",
"build": "npm run build",
"serve": "npm run serve",
"bridge": "src"
}

View File

@@ -1,5 +1,5 @@
module.exports = { module.exports = {
presets: [ presets: [
[ '@vue/app', { useBuiltIns: 'entry' } ] '@vue/app'
] ]
} }

View File

@@ -8,21 +8,20 @@
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"core-js": "^3.6.4", "core-js": "^2.6.4",
"regenerator-runtime": "^0.13.3", "vue": "^2.5.22",
"vue": "^2.6.11", "@wailsapp/runtime": "^1.0.0"
"@wailsapp/runtime": "^1.0.10"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "^4.2.3", "@vue/cli-plugin-babel": "^3.4.0",
"@vue/cli-plugin-eslint": "^4.2.3", "@vue/cli-plugin-eslint": "^3.4.0",
"@vue/cli-service": "^4.2.3", "@vue/cli-service": "^3.4.0",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.0.1",
"eslint": "^6.8.0", "eslint": "^5.8.0",
"eslint-plugin-vue": "^6.2.1", "eslint-plugin-vue": "^5.0.0",
"eventsource-polyfill": "^0.9.6", "eventsource-polyfill": "^0.9.6",
"vue-template-compiler": "^2.6.11", "vue-template-compiler": "^2.5.21",
"webpack-hot-middleware": "^2.25.0" "webpack-hot-middleware": "^2.24.3"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,

View File

@@ -1,12 +1,10 @@
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';
Vue.config.productionTip = false; Vue.config.productionTip = false;
Vue.config.devtools = true; Vue.config.devtools = true;
import * as Wails from '@wailsapp/runtime'; import Wails from '@wailsapp/runtime';
Wails.Init(() => { Wails.Init(() => {
new Vue({ new Vue({

View File

@@ -37,6 +37,7 @@ module.exports = {
} }
}, },
devServer: { devServer: {
disableHostCheck: true disableHostCheck: true,
host: "localhost"
} }
}; };

View File

@@ -1,5 +1,5 @@
module.exports = { module.exports = {
presets: [ presets: [
[ '@vue/app', { useBuiltIns: 'entry' } ] '@vue/app'
] ]
} }

View File

@@ -7,24 +7,24 @@
"build": "vue-cli-service build", "build": "vue-cli-service build",
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"core-js": "^3.6.4", "babel-polyfill": "^6.26.0",
"regenerator-runtime": "^0.13.3", "core-js": "^2.6.4",
"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",
"@wailsapp/runtime": "^1.0.10" "@wailsapp/runtime": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "^4.2.3", "@vue/cli-plugin-babel": "^3.4.0",
"@vue/cli-plugin-eslint": "^4.2.3", "@vue/cli-plugin-eslint": "^3.4.0",
"@vue/cli-service": "^4.2.3", "@vue/cli-service": "^3.4.0",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.0.1",
"eslint": "^6.8.0", "eslint": "^5.8.0",
"eslint-plugin-vue": "^6.2.1", "eslint-plugin-vue": "^5.0.0",
"eventsource-polyfill": "^0.9.6", "eventsource-polyfill": "^0.9.6",
"vue-template-compiler": "^2.6.11", "vue-template-compiler": "^2.5.21",
"webpack-hot-middleware": "^2.25.0" "webpack-hot-middleware": "^2.24.3"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,
@@ -50,4 +50,4 @@
"last 2 versions", "last 2 versions",
"not ie <= 8" "not ie <= 8"
] ]
} }

View File

@@ -1,5 +1,4 @@
import 'core-js/stable'; import 'babel-polyfill';
import 'regenerator-runtime/runtime';
import Vue from 'vue'; import Vue from 'vue';
// Setup Vuetify // Setup Vuetify
@@ -13,7 +12,7 @@ import App from './App.vue';
Vue.config.productionTip = false; Vue.config.productionTip = false;
Vue.config.devtools = true; Vue.config.devtools = true;
import * as Wails from '@wailsapp/runtime'; import Wails from '@wailsapp/runtime';
Wails.Init(() => { Wails.Init(() => {
new Vue({ new Vue({

View File

@@ -37,6 +37,7 @@ module.exports = {
} }
}, },
devServer: { devServer: {
disableHostCheck: true disableHostCheck: true,
host: "localhost"
} }
}; };

View File

@@ -1,8 +1,8 @@
{ {
"name": "Vuetify1.5/Webpack Basic", "name": "Vuetify Basic",
"version": "1.0.0", "version": "1.0.0",
"shortdescription": "A basic Vuetify1.5/Webpack4 template", "shortdescription": "Vuetify + Webpack",
"description": "Basic template using Vuetify v1.5 and bundled using Webpack", "description": "Basic template using Vuetify 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": ""
} }

View File

@@ -1,3 +0,0 @@
{
"esversion": 6
}

View File

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

View File

@@ -1,5 +0,0 @@
module.exports = {
presets: [
[ '@vue/app', { useBuiltIns: 'entry' } ]
]
};

View File

@@ -1,53 +0,0 @@
{
"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.4",
"regenerator-runtime": "^0.13.3",
"vue": "^2.6.11",
"vuetify": "^2.2.15",
"@wailsapp/runtime": "^1.0.10"
},
"devDependencies": {
"@mdi/font": "^4.9.95",
"@vue/cli-plugin-babel": "^4.2.3",
"@vue/cli-plugin-eslint": "^4.2.3",
"@vue/cli-service": "^4.2.3",
"babel-eslint": "^10.1.0",
"eslint": "^6.8.0",
"eslint-plugin-vue": "^6.2.1",
"eventsource-polyfill": "^0.9.6",
"vue-template-compiler": "^2.6.11",
"webpack-hot-middleware": "^2.25.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

View File

@@ -1,60 +0,0 @@
<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">&copy; 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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

View File

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

View File

@@ -1,29 +0,0 @@
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');
});

View File

@@ -1,42 +0,0 @@
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
}
};

View File

@@ -1,5 +0,0 @@
module {{.BinaryName}}
require (
github.com/wailsapp/wails {{.WailsVersion}}
)

View File

@@ -1,27 +0,0 @@
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()
}

View File

@@ -1,14 +0,0 @@
{
"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": ""
}

View File

@@ -1,4 +1,4 @@
package cmd package cmd
// Version - Wails version // Version - Wails version
const Version = "v1.7.2-pre3" const Version = "v0.17.14-pre"

View File

@@ -40,7 +40,7 @@ Create your first project by running 'wails init'.`
} }
// Check Mewn // Check Mewn
err = cmd.CheckMewn(false) err = cmd.CheckMewn()
if err != nil { if err != nil {
return err return err
} }

View File

@@ -1,385 +0,0 @@
package main
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"github.com/Masterminds/semver"
"github.com/leaanthony/spinner"
"github.com/wailsapp/wails/cmd"
)
// Constants
var checkSpinner = spinner.NewSpinner()
var migrateProjectOptions = &cmd.ProjectOptions{}
var migrateFS = cmd.NewFSHelper()
var migrateGithub = cmd.NewGitHubHelper()
var programHelper = cmd.NewProgramHelper()
var lessThanV1 *semver.Constraints
// The user's go.mod
var goMod string
var goModFile string
// The user's main.js
var mainJSFile string
var mainJSContents string
// Frontend directory
var frontEndDir string
func init() {
var dryrun bool
var err error
lessThanV1, err = semver.NewConstraint("< v1.0.0")
if err != nil {
log.Fatal(err)
}
// var forceRebuild = false
checkSpinner.SetSpinSpeed(50)
commandDescription := `EXPERIMENTAL - This command attempts to migrate projects to the latest Wails version.`
updateCmd := app.Command("migrate", "Migrate projects to latest Wails release").
LongDescription(commandDescription).
BoolFlag("dryrun", "Only display what would be done", &dryrun)
updateCmd.Action(func() error {
message := "Migrate Project"
logger.PrintSmallBanner(message)
logger.Red("WARNING: This is an experimental command. Ensure you have backups of your project!")
logger.Red("It currently only supports npm based projects.")
fmt.Println()
// Check project directory
err := checkProjectDirectory()
if err != nil {
return err
}
// Find Wails version from go.mod
wailsVersion, err := getWailsVersion()
if err != nil {
return err
}
// Get latest stable version
var latestVersion *semver.Version
latestVersion, err = getLatestWailsVersion()
if err != nil {
return err
}
var canMigrate bool
canMigrate, err = canMigrateVersion(wailsVersion, latestVersion)
if err != nil {
return err
}
if !canMigrate {
return nil
}
// Check for wailsbridge
wailsBridge, err := checkWailsBridge()
if err != nil {
return err
}
// Is main.js using bridge.Init()
canUpdateMainJS, err := checkMainJS()
if err != nil {
return err
}
// TODO: Check if we are using legacy js runtime
// Operations
logger.Yellow("Operations to perform:")
logger.Yellowf(" - Update to Wails v%s\n", latestVersion)
if len(wailsBridge) > 0 {
logger.Yellow(" - Delete wailsbridge.js")
}
if canUpdateMainJS {
logger.Yellow(" - Patch main.js")
}
logger.Yellow(" - Ensure '@wailsapp/runtime` module is installed")
if dryrun {
logger.White("Exiting: Dry Run")
return nil
}
logger.Red("*WARNING* About to modify your project!")
logger.Red("Type 'YES' to continue: ")
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
input := scanner.Text()
if input != "YES" {
logger.Red("ABORTED!")
return nil
}
logger.Yellow("Let's do this!")
err = updateWailsVersion(wailsVersion, latestVersion)
if err != nil {
return err
}
if len(wailsBridge) > 0 {
err = deleteWailsBridge(wailsBridge)
if err != nil {
return err
}
}
if canUpdateMainJS {
err = patchMainJS()
if err != nil {
return err
}
}
// Install runtime
err = installWailsRuntime()
if err != nil {
return err
}
fmt.Println()
logger.Yellow("Migration complete! Check project by running `wails build`.")
return nil
})
}
func checkProjectDirectory() error {
// Get versions
checkSpinner.Start("Check Project Directory")
// Check we are in project directory
err := migrateProjectOptions.LoadConfig(migrateFS.Cwd())
if err != nil {
checkSpinner.Error()
return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory")
}
checkSpinner.Success()
return nil
}
func getWailsVersion() (*semver.Version, error) {
checkSpinner.Start("Get Wails Version")
result, err := cmd.GetWailsVersion()
if err != nil {
checkSpinner.Error(err.Error())
return nil, err
}
return result, nil
}
func canMigrateVersion(wailsVersion *semver.Version, latestVersion *semver.Version) (bool, error) {
checkSpinner.Start("Checking ability to Migrate")
// Check if we are at the latest version!!!!
if wailsVersion.Equal(latestVersion) || wailsVersion.GreaterThan(latestVersion) {
checkSpinner.Errorf("Checking ability to Migrate: No! (v%s >= v%s)", wailsVersion, latestVersion)
return false, nil
}
// Check for < v1.0.0
if lessThanV1.Check(wailsVersion) {
checkSpinner.Successf("Checking ability to Migrate: Yes! (v%s < v1.0.0)", wailsVersion)
return true, nil
}
checkSpinner.Error("Unable to migrate")
return false, fmt.Errorf("No migration rules for version %s", wailsVersion)
}
func checkWailsBridge() (string, error) {
checkSpinner.Start("Checking if legacy Wails Bridge present")
// Check frontend dir is available
if migrateProjectOptions.FrontEnd == nil ||
len(migrateProjectOptions.FrontEnd.Dir) == 0 ||
!migrateFS.DirExists(migrateProjectOptions.FrontEnd.Dir) {
checkSpinner.Error("Unable to determine frontend directory")
return "", fmt.Errorf("Unable to determine frontend directory")
}
frontEndDir = migrateProjectOptions.FrontEnd.Dir
wailsBridgePath, err := filepath.Abs(filepath.Join(".", frontEndDir, "src", "wailsbridge.js"))
if err != nil {
checkSpinner.Error(err.Error())
return "", err
}
// If it doesn't exist, return blank string
if !migrateFS.FileExists(wailsBridgePath) {
checkSpinner.Success("Checking if legacy Wails Bridge present: No")
return "", nil
}
checkSpinner.Success("Checking if legacy Wails Bridge present: Yes")
return wailsBridgePath, nil
}
// This function determines if the main.js file using wailsbridge can be auto-updated
func checkMainJS() (bool, error) {
checkSpinner.Start("Checking if main.js can be migrated")
var err error
// Check main.js is there
if migrateProjectOptions.FrontEnd == nil ||
len(migrateProjectOptions.FrontEnd.Dir) == 0 ||
!migrateFS.DirExists(migrateProjectOptions.FrontEnd.Dir) {
checkSpinner.Error("Unable to determine frontend directory")
return false, fmt.Errorf("Unable to determine frontend directory")
}
frontEndDir = migrateProjectOptions.FrontEnd.Dir
mainJSFile, err = filepath.Abs(filepath.Join(".", frontEndDir, "src", "main.js"))
if err != nil {
checkSpinner.Error("Unable to find main.js")
return false, err
}
mainJSContents, err = migrateFS.LoadAsString(mainJSFile)
if err != nil {
checkSpinner.Error("Unable to load main.js")
return false, err
}
// Check we have a line like: import Bridge from "./wailsbridge";
if strings.Index(mainJSContents, `import Bridge from "./wailsbridge";`) == -1 {
checkSpinner.Success("Checking if main.js can be migrated: No - Cannot find `import Bridge`")
return false, nil
}
// Check we have a line like: Bridge.Start(() => {
if strings.Index(mainJSContents, `Bridge.Start(`) == -1 {
checkSpinner.Success("Checking if main.js can be migrated: No - Cannot find `Bridge.Start`")
return false, nil
}
checkSpinner.Success("Checking if main.js can be migrated: Yes")
return true, nil
}
func getLatestWailsVersion() (*semver.Version, error) {
checkSpinner.Start("Checking GitHub for latest Wails version")
version, err := migrateGithub.GetLatestStableRelease()
if err != nil {
checkSpinner.Error("Checking GitHub for latest Wails version: Failed")
return nil, err
}
checkSpinner.Successf("Checking GitHub for latest Wails version: v%s", version)
return version.Version, nil
}
func updateWailsVersion(currentVersion, latestVersion *semver.Version) error {
// Patch go.mod
checkSpinner.Start("Patching go.mod")
wailsModule := "github.com/wailsapp/wails"
old := fmt.Sprintf("%s v%s", wailsModule, currentVersion)
new := fmt.Sprintf("%s v%s", wailsModule, latestVersion)
goMod = strings.Replace(goMod, old, new, -1)
err := ioutil.WriteFile(goModFile, []byte(goMod), 0600)
if err != nil {
checkSpinner.Error()
return err
}
checkSpinner.Success()
return nil
}
func deleteWailsBridge(bridgeFilename string) error {
// Patch go.mod
checkSpinner.Start("Delete legacy wailsbridge.js")
err := migrateFS.RemoveFile(bridgeFilename)
if err != nil {
checkSpinner.Error()
return err
}
checkSpinner.Success()
return nil
}
func patchMainJS() error {
// Patch main.js
checkSpinner.Start("Patching main.js")
// Patch import line
oldImportLine := `import Bridge from "./wailsbridge";`
newImportLine := `import * as Wails from "@wailsapp/runtime";`
mainJSContents = strings.Replace(mainJSContents, oldImportLine, newImportLine, -1)
// Patch Start line
oldStartLine := `Bridge.Start`
newStartLine := `Wails.Init`
mainJSContents = strings.Replace(mainJSContents, oldStartLine, newStartLine, -1)
err := ioutil.WriteFile(mainJSFile, []byte(mainJSContents), 0600)
if err != nil {
checkSpinner.Error()
return err
}
checkSpinner.Success()
return nil
}
func installWailsRuntime() error {
checkSpinner.Start("Installing @wailsapp/runtime module")
// Change to the frontend directory
err := os.Chdir(frontEndDir)
if err != nil {
checkSpinner.Error()
return nil
}
// Determine package manager
packageManager, err := migrateProjectOptions.GetNPMBinaryName()
if err != nil {
checkSpinner.Error()
return nil
}
switch packageManager {
case cmd.NPM:
// npm install --save @wailsapp/runtime
programHelper.InstallNPMPackage("@wailsapp/runtime", true)
default:
checkSpinner.Error()
return fmt.Errorf("Unknown package manager")
}
checkSpinner.Success()
return nil
}

View File

@@ -3,34 +3,16 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"runtime"
"strings"
"github.com/leaanthony/spinner" "github.com/leaanthony/spinner"
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
) )
// getSupportedPlatforms returns a slice of platform/architecture
// targets that are buildable using the cross-platform 'x' option.
func getSupportedPlatforms() []string {
return []string{
"darwin/amd64",
"linux/amd64",
"linux/arm-7",
"windows/amd64",
}
}
func init() { 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 = ""
var ldflags = ""
buildSpinner := spinner.NewSpinner() buildSpinner := spinner.NewSpinner()
buildSpinner.SetSpinSpeed(50) buildSpinner.SetSpinSpeed(50)
@@ -39,18 +21,7 @@ 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("ldflags", "Extra options for -ldflags", &ldflags)
var b strings.Builder
for _, plat := range getSupportedPlatforms() {
fmt.Fprintf(&b, " - %s\n", plat)
}
initCmd.StringFlag("x",
fmt.Sprintf("Cross-compile application to specified platform via xgo\n%s", b.String()),
&platform)
initCmd.Action(func() error { initCmd.Action(func() error {
@@ -66,7 +37,6 @@ 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
@@ -76,28 +46,6 @@ func init() {
return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory") return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory")
} }
// Set cross-compile
projectOptions.Platform = runtime.GOOS
if len(platform) > 0 {
supported := false
for _, plat := range getSupportedPlatforms() {
if plat == platform {
supported = true
}
}
if !supported {
return fmt.Errorf("unsupported platform '%s' specified.\nPlease run `wails build -h` to see the supported platform/architecture options", platform)
}
projectOptions.CrossCompile = true
plat := strings.Split(platform, "/")
projectOptions.Platform = plat[0]
projectOptions.Architecture = plat[1]
}
// Add ldflags
projectOptions.LdFlags = ldflags
// Validate config // Validate config
// Check if we have a frontend // Check if we have a frontend
err = cmd.ValidateFrontendConfig(projectOptions) err = cmd.ValidateFrontendConfig(projectOptions)
@@ -125,13 +73,16 @@ 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 {
@@ -139,7 +90,7 @@ func init() {
} }
// Install dependencies // Install dependencies
err = cmd.InstallGoDependencies(projectOptions.Verbose) err = cmd.InstallGoDependencies()
if err != nil { if err != nil {
return err return err
} }
@@ -150,32 +101,6 @@ 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()
}
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

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"runtime"
"github.com/leaanthony/spinner" "github.com/leaanthony/spinner"
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
@@ -11,14 +10,12 @@ 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 {
@@ -28,7 +25,7 @@ func init() {
fmt.Println() fmt.Println()
// Check Mewn is installed // Check Mewn is installed
err := cmd.CheckMewn(verbose) err := cmd.CheckMewn()
if err != nil { if err != nil {
return err return err
} }
@@ -44,10 +41,6 @@ func init() {
return err return err
} }
// Set project options
projectOptions.Verbose = verbose
projectOptions.Platform = runtime.GOOS
// Save project directory // Save project directory
projectDir := fs.Cwd() projectDir := fs.Cwd()
@@ -58,7 +51,7 @@ func init() {
} }
// Install dependencies // Install dependencies
err = cmd.InstallGoDependencies(projectOptions.Verbose) err = cmd.InstallGoDependencies()
if err != nil { if err != nil {
return err return err
} }

View File

@@ -3,9 +3,9 @@ package main
import ( import (
"fmt" "fmt"
"log" "log"
"os"
"github.com/leaanthony/spinner" "github.com/leaanthony/spinner"
"github.com/mitchellh/go-homedir"
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
) )
@@ -146,7 +146,7 @@ func updateToVersion(targetVersion *cmd.SemanticVersion, force bool) error {
updateSpinner.Start("Installing Wails " + desiredVersion) updateSpinner.Start("Installing Wails " + desiredVersion)
// Run command in non module directory // Run command in non module directory
homeDir, err := os.UserHomeDir() homeDir, err := homedir.Dir()
if err != nil { if err != nil {
log.Fatal("Cannot find home directory! Please file a bug report!") log.Fatal("Cannot find home directory! Please file a bug report!")
} }

View File

@@ -80,16 +80,15 @@ To help you in this process, we will ask for some information, add Go/Wails deta
npm := program.FindProgram("npm") npm := program.FindProgram("npm")
if npm != nil { if npm != nil {
stdout, _, _, _ := npm.Run("--version") stdout, _, _, _ := npm.Run("--version")
npmVersion = stdout nodeVersion = stdout
npmVersion = npmVersion[:len(npmVersion)-1] nodeVersion = nodeVersion[:len(nodeVersion)-1]
npmVersion = strings.TrimSpace(npmVersion)
} }
node := program.FindProgram("node") node := program.FindProgram("node")
if node != nil { if node != nil {
stdout, _, _, _ := node.Run("--version") stdout, _, _, _ := node.Run("--version")
nodeVersion = stdout npmVersion = stdout
nodeVersion = nodeVersion[:len(nodeVersion)-1] npmVersion = npmVersion[:len(npmVersion)-1]
} }
str.WriteString("\n| Name | Value |\n| ----- | ----- |\n") str.WriteString("\n| Name | Value |\n| ----- | ----- |\n")

View File

@@ -1,9 +1,6 @@
package main package main
import ( import (
"os"
"os/exec"
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
) )
@@ -18,9 +15,5 @@ func main() {
err := app.Run() err := app.Run()
if err != nil { if err != nil {
logger.Error(err.Error()) logger.Error(err.Error())
if exitErr, ok := err.(*exec.ExitError); ok {
os.Exit(exitErr.ExitCode())
}
os.Exit(1)
} }
} }

View File

@@ -1 +0,0 @@
windres.exe -o %1 %2

View File

@@ -1,9 +1,6 @@
package wails package wails
import ( import "github.com/leaanthony/mewn"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails/runtime"
)
// AppConfig is the configuration structure used when creating a Wails App object // AppConfig is the configuration structure used when creating a Wails App object
type AppConfig struct { type AppConfig struct {
@@ -68,7 +65,7 @@ func (a *AppConfig) merge(in *AppConfig) error {
a.CSS = in.CSS a.CSS = in.CSS
} }
if in.Title != "" { if in.Title != "" {
a.Title = runtime.ProcessEncoding(in.Title) a.Title = in.Title
} }
if in.Colour != "" { if in.Colour != "" {

17
go.mod
View File

@@ -2,7 +2,9 @@ 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/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
@@ -10,22 +12,19 @@ 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.4.0 github.com/leaanthony/slicer v1.3.2
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
github.com/mitchellh/go-homedir v1.1.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
github.com/pkg/errors v0.8.1 // indirect github.com/pkg/errors v0.8.1 // indirect
github.com/sirupsen/logrus v1.4.1 github.com/sirupsen/logrus v1.4.1
github.com/stretchr/testify v1.3.0 // indirect github.com/stretchr/testify v1.3.0 // indirect
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 // indirect
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
golang.org/x/text v0.3.0
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.13

34
go.sum
View File

@@ -2,11 +2,15 @@ github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITg
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/abadojack/whatlanggo v1.0.1 h1:19N6YogDnf71CTHm3Mp2qhYfkRdyvbgwWdd2EPxJRG4=
github.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH9B/K8tQB2uoc=
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=
@@ -28,14 +32,15 @@ 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.4.0 h1:Q9u4w+UBU4WHjXnEDdz+eRLMKF/rnyosRBiqULnc1J8= github.com/leaanthony/slicer v1.3.2 h1:kGWWFoyaY5WzwGrUsHXMmGbssuYthP4qYBNlkNpNAB8=
github.com/leaanthony/slicer v1.4.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= github.com/leaanthony/slicer v1.3.2/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
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=
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs= github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8= github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE= github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
@@ -46,6 +51,8 @@ github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98=
@@ -62,28 +69,21 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba h1:2DHfQOxcpWdGf5q5IzCUFPNvRX9Icf+09RvQK2VnJq0=
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba/go.mod h1:iLnlXG2Pakcii2CU0cbY07DRCSvpWNa7nFxtevhOChk=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR170vGqDhJDOmpVd4Hjak=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc= gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=
gopkg.in/AlecAivazis/survey.v1 v1.8.4/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= gopkg.in/AlecAivazis/survey.v1 v1.8.4/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

View File

@@ -2,11 +2,7 @@ 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"
@@ -14,32 +10,26 @@ 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
functions map[string]*boundFunction functions map[string]*boundFunction
internalMethods *internalMethods internalMethods *internalMethods
initMethods []*boundMethod initMethods []*boundMethod
shutdownMethods []*boundMethod
log *logger.CustomLogger log *logger.CustomLogger
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
} }
@@ -97,55 +87,9 @@ 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 {
@@ -159,12 +103,6 @@ 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++ {
@@ -174,8 +112,6 @@ 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
@@ -191,9 +127,6 @@ func (b *Manager) bindMethod(object interface{}) error {
if newMethod.isWailsInit { if newMethod.isWailsInit {
b.log.Debugf("Detected WailsInit function: %s", fullMethodName) b.log.Debugf("Detected WailsInit function: %s", fullMethodName)
b.initMethods = append(b.initMethods, newMethod) b.initMethods = append(b.initMethods, newMethod)
} else if newMethod.isWailsShutdown {
b.log.Debugf("Detected WailsShutdown function: %s", fullMethodName)
b.shutdownMethods = append(b.shutdownMethods, newMethod)
} else { } else {
// Save boundMethod // Save boundMethod
b.log.Infof("Bound Method: %s()", fullMethodName) b.log.Infof("Bound Method: %s()", fullMethodName)
@@ -359,13 +292,3 @@ func (b *Manager) callWailsInitMethods() error {
} }
return nil return nil
} }
// Shutdown the binding manager
func (b *Manager) Shutdown() {
b.log.Debug("Shutdown called")
for _, method := range b.shutdownMethods {
b.log.Debugf("Calling Shutdown for method: %s", method.fullName)
method.call("[]")
}
b.log.Debug("Shutdown complete")
}

View File

@@ -18,7 +18,6 @@ type boundMethod struct {
log *logger.CustomLogger log *logger.CustomLogger
hasErrorReturnType bool // Indicates if there is an error return type hasErrorReturnType bool // Indicates if there is an error return type
isWailsInit bool isWailsInit bool
isWailsShutdown bool
} }
// Creates a new bound method based on the given method + type // Creates a new bound method based on the given method + type
@@ -40,11 +39,6 @@ func newBoundMethod(name string, fullName string, method reflect.Value, objectTy
err = result.processWailsInit() err = result.processWailsInit()
} }
// Are we a WailsShutdown method?
if result.Name == "WailsShutdown" {
err = result.processWailsShutdown()
}
return result, err return result, err
} }
@@ -217,20 +211,3 @@ func (b *boundMethod) processWailsInit() error {
return nil return nil
} }
func (b *boundMethod) processWailsShutdown() error {
// We must have only 1 input, it must be *wails.Runtime
if len(b.inputs) != 0 {
return fmt.Errorf("Invalid WailsShutdown() definition. Expected 0 inputs, but got %d", len(b.inputs))
}
// We must have only 1 output, it must be error
if len(b.returnTypes) != 0 {
return fmt.Errorf("Invalid WailsShutdown() definition. Expected 0 return types, but got %d", len(b.returnTypes))
}
// We are indeed a wails Shutdown method
b.isWailsShutdown = true
return nil
}

View File

@@ -3,30 +3,26 @@ package event
import ( import (
"fmt" "fmt"
"sync" "sync"
"github.com/wailsapp/wails/lib/interfaces"
"github.com/wailsapp/wails/lib/logger" "github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages" "github.com/wailsapp/wails/lib/messages"
"github.com/wailsapp/wails/lib/interfaces"
) )
// 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 exit bool
log *logger.CustomLogger log *logger.CustomLogger
renderer interfaces.Renderer // Messages will be dispatched to the frontend renderer interfaces.Renderer // Messages will be dispatched to the frontend
wg sync.WaitGroup
} }
// NewManager creates a new event manager with a 100 event buffer // NewManager creates a new event manager with a 100 event buffer
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, exit: false,
log: logger.NewCustomLogger("Events"), log: logger.NewCustomLogger("Events"),
} }
} }
@@ -91,14 +87,15 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
// Store renderer // Store renderer
e.renderer = renderer e.renderer = renderer
// Set up waitgroup so we can wait for goroutine to quit // Set up waitgroup so we can wait for goroutine to start
e.running = true var wg sync.WaitGroup
e.wg.Add(1) wg.Add(1)
// Run main loop in separate goroutine // Run main loop in separate goroutine
go func() { go func() {
wg.Done()
e.log.Info("Listening") e.log.Info("Listening")
for e.running { for e.exit == false {
// TODO: Listen for application exit // TODO: Listen for application exit
select { select {
case event := <-e.incomingEvents: case event := <-e.incomingEvents:
@@ -142,18 +139,14 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
} }
} }
} }
case <-e.quitChannel:
e.running = false
} }
} }
e.wg.Done()
}() }()
// Wait for goroutine to start
wg.Wait()
} }
// Shutdown is called when exiting the Application func (e *Manager) stop() {
func (e *Manager) Shutdown() { e.exit = true
e.log.Debug("Shutting Down")
e.quitChannel <- struct{}{}
e.log.Debug("Waiting for main loop to exit")
e.wg.Wait()
} }

View File

@@ -7,5 +7,4 @@ type BindingManager interface {
Bind(object interface{}) Bind(object interface{})
Start(renderer Renderer, runtime Runtime) error Start(renderer Renderer, runtime Runtime) error
ProcessCall(callData *messages.CallData) (result interface{}, err error) ProcessCall(callData *messages.CallData) (result interface{}, err error)
Shutdown()
} }

View File

@@ -8,5 +8,4 @@ type EventManager interface {
Emit(eventName string, optionalData ...interface{}) Emit(eventName string, optionalData ...interface{})
On(eventName string, callback func(...interface{})) On(eventName string, callback func(...interface{}))
Start(Renderer) Start(Renderer)
Shutdown()
} }

View File

@@ -1,13 +1,8 @@
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, f CallbackFunc) Dispatch(message string)
Start(eventManager EventManager, bindingManager BindingManager) Start(eventManager EventManager, bindingManager BindingManager)
Shutdown()
} }

View File

@@ -3,23 +3,22 @@ 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
// Dialog Runtime // Dialog Runtime
SelectFile(title string, filter string) string SelectFile() string
SelectDirectory() string SelectDirectory() string
SelectSaveFile(title string, filter string) string SelectSaveFile() string
// Window Runtime // Window Runtime
SetColour(string) error SetColour(string) error

View File

@@ -2,7 +2,6 @@ package ipc
import ( import (
"fmt" "fmt"
"sync"
"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,20 +12,18 @@ import (
type Manager struct { type Manager struct {
renderer interfaces.Renderer // The renderer renderer interfaces.Renderer // The renderer
messageQueue chan *ipcMessage messageQueue chan *ipcMessage
quitChannel chan struct{} // quitChannel chan struct{}
// signals chan os.Signal // signals chan os.Signal
log *logger.CustomLogger log *logger.CustomLogger
eventManager interfaces.EventManager eventManager interfaces.EventManager
bindingManager interfaces.BindingManager bindingManager interfaces.BindingManager
running bool
wg sync.WaitGroup
} }
// NewManager creates a new IPC Manager // NewManager creates a new IPC Manager
func NewManager() interfaces.IPCManager { func NewManager() interfaces.IPCManager {
result := &Manager{ result := &Manager{
messageQueue: make(chan *ipcMessage, 100), messageQueue: make(chan *ipcMessage, 100),
quitChannel: make(chan struct{}), // quitChannel: make(chan struct{}),
// signals: make(chan os.Signal, 1), // signals: make(chan os.Signal, 1),
log: logger.NewCustomLogger("IPC"), log: logger.NewCustomLogger("IPC"),
} }
@@ -47,12 +44,9 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
i.log.Info("Starting") i.log.Info("Starting")
// signal.Notify(manager.signals, os.Interrupt) // signal.Notify(manager.signals, os.Interrupt)
i.running = true
// Keep track of this goroutine
i.wg.Add(1)
go func() { go func() {
for i.running { running := true
for running {
select { select {
case incomingMessage := <-i.messageQueue: case incomingMessage := <-i.messageQueue:
i.log.DebugFields("Processing message", logger.Fields{ i.log.DebugFields("Processing message", logger.Fields{
@@ -123,22 +117,25 @@ 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,
}) })
case <-i.quitChannel: // case <-manager.quitChannel:
i.running = false // Debug("[MessageQueue] Quit caught")
// running = false
// case <-manager.signals:
// Debug("[MessageQueue] Signal caught")
// running = false
} }
} }
i.log.Debug("Stopping") i.log.Debug("Stopping")
i.wg.Done()
}() }()
} }
// 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, cb interfaces.CallbackFunc) { func (i *Manager) Dispatch(message string) {
// Create a new IPC Message // Create a new IPC Message
incomingMessage, err := newIPCMessage(message, i.SendResponse(cb)) incomingMessage, err := newIPCMessage(message, i.SendResponse)
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,
@@ -158,25 +155,15 @@ func (i *Manager) Dispatch(message string, cb interfaces.CallbackFunc) {
} }
// SendResponse sends the given response back to the frontend // SendResponse sends the given response back to the frontend
// It sends the data back to the correct renderer by way of the provided callback function func (i *Manager) SendResponse(response *ipcResponse) error {
func (i *Manager) SendResponse(cb interfaces.CallbackFunc) func(i *ipcResponse) error {
return func(response *ipcResponse) error { // Serialise the Message
// Serialise the Message data, err := response.Serialise()
data, err := response.Serialise() if err != nil {
if err != nil { fmt.Printf(err.Error())
fmt.Printf(err.Error()) return err
return err
}
return cb(data)
} }
} // Call back to the front end
return i.renderer.Callback(data)
// Shutdown is called when exiting the Application
func (i *Manager) Shutdown() {
i.log.Debug("Shutdown called")
i.quitChannel <- struct{}{}
i.log.Debug("Waiting of main loop shutdown")
i.wg.Wait()
} }

View File

@@ -1,10 +1,254 @@
package renderer package renderer
import ( import (
bridge "github.com/wailsapp/wails/lib/renderer/bridge" "encoding/json"
"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"
) )
// NewBridge returns a new Bridge struct type messageType int
func NewBridge() *bridge.Bridge {
return &bridge.Bridge{} 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
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 {
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.Warn("Close() unsupported in bridge mode")
} }

View File

@@ -1,222 +0,0 @@
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 := newSession(conn,
h.bindingCache,
h.ipcManager,
logger.NewCustomLogger("BridgeSession"),
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(title string, filter string) 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(title string, filter string) 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 marshal JSON data in event: %s ", err.Error())
return err
}
}
// Double encode data to ensure everything is escaped correctly.
data, err = json.Marshal(string(data))
if err != nil {
h.log.Errorf("Cannot marshal JSON data in event: %s ", err.Error())
return err
}
message := "window.wails._.Notify('" + event.Name + "'," + string(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")
for _, session := range h.sessions {
session.Shutdown()
}
err := h.server.Close()
if err != nil {
h.log.Errorf(err.Error())
}
}

View File

@@ -1,9 +0,0 @@
package renderer
// Autogenerated by Mewn - Do not alter
import "github.com/leaanthony/mewn"
func init() {
mewn.AddAsset(".", "../../runtime/assets/wails.js", "1f8b08000000000000ff94586d8f1bb711fe2b2ba255481f8f91dc14a977c318cee582a838df053ebbfda00a01b53b92e85b915b2e758a20f1bf17b3efba97a2050c7bc519728633cf3c33f468b533a9d7d650c38e8fca45208f216917234f1d3bea1585b95b30077ee74c84df02fe28acf365825bacc42579d4b1e3793c9af246181f43489a4d0637a52acfa96df772cbfb6fcfb815b91c4dfab5e0c5561aee452a817b91c9de550edcb1a317163fd9e974b7fc0aa91719acb481df9c2dc0f943a57604b3db8253cb1ce2d184afc1c72eb0c0bd70727875b233f5ee8c8ca43f146057d1fd61bbb4f9785cff2bbcbdf74e9bf567b51e8f5fb3f85c971f1f55be83987cb4d92e0712187f6d33f9fd77281bb576db6852bbebcfae5f25653a86f1981ae9a9618cff6d0c6d864ca257f43b94125b9922b2bd93198ff18fe82df59b30974e36cea50e94076a7679cef0382f1c75afb9ee38c960a576b9274f235edfc204c6df560e95555cfa201bb6b28e56308ab4890cf322a38e5bde5d17d8b103112c82586a93557e71cb588b2f873132f2399a9fdcf67da7d19f2a1adf43fc82b04330fa059c28c281714073f6494a1ac5264485b3dee225c54695777bd306abae02dc8067149210eea917a59cb040e76718f788cb12228c59ea49823900c61b4f66467bc2e9739f6781b12699c7903489abc34a7e86e56efde2ae5d609dd6ccacec8b4af940e99fca194ce54b7aab81deb573d6bda8950db47e515ee52f6a95ed756c7b1d5befb29cdc1560be7cba7971dfa13dbdd1fb456359bda0b86c0d68395ff4dca7da1c34a1c45cc68663fa962a7d98fd1c7b5ea8436e55164348ce9854afe85e9bcceec55ee9bc5c3a9dade1fdf325b1876569d307f0a20484358b1b25f8c383332a17da3cda07a086712d72306bbff971d2d50cc849023fb482042e2e989ec3821a16e8dfefef6e455d6e7a75a08eb1d0dd2dad11ab28c9ed9af0630e8f90c7866fa12cd51a620803e51dde28a524abb16306a2bc11e90a3043c9aa91ec5b940c855923841a1a4351d98856351e0c0b78cf3d2fcefad2639b9bb64c77793e927e3c6e3e4e27eae5847103fbe83767b7ba04da67de715b675527993d6a692ec825b9d85316f61b9d032de67a5193de8f13867aa92cc17fd65bb03b4f8708b2b4423725572acf236f2372612e48e4f516b2c8eebc883ec1bf7750fa68f6731c910bcd5860dcb3044dc8a3af8ffc55992c8738e50e903a62cb1d94367f84d885c4bb03e6096147f811c94f9bf5adda221633e555fc24cfc82b9a8554f97453c5d29ad2e620aa582330c21008eb33ea7aa4a446a720171543757a073caad15a53f293b3fb129ce8ea6f98c2e5ebba750d1a16f6b2c179ea0e85b7435ac6801b8999fba28dffcbdb0fcea9039d76547fb651acc17f5226b3db7f60a341f4cc278b9798fcdd64f2fdf4ddbbb77ffdeefbef26efde4ddf7c547e235cb597b25011c0b663f4c8d00a5fa3675d77444da44de99549b17f01637ee3ec3e42873f1f0ae800618cf511a62d52519aabb28c5419a9a83d90b040fd4697dc30ee11b197538ebfc555433067cdac9dbd842a8afc50b73fc3f8e5742411f6132925f59772ca42e09bb352b96b4b6533370b897f9d4ef345d31fd0e96d75d30425a2d8951bea06b9bcee3be9139ccd17a2cc75da7aa4dc7ab705e34b562fd329b2af3c9a015221248a127804e309f77565df9f39fb80e610f16d5dc33efaa50d03417d7261181f4d7a7cd79aa369e89dbeeab24eafda794695a55e9bd36918d49e45a709fcd0dd60c8a6d5ddbdec64735824ed3687038b67ff53bff7dc311cd67050f6384c876ec0604d042b30f4610c0dce110a6032790c7cd83fe4f0c7e9d44b7bfd2ac75fe5f116f63fd5b4113f9f8fe60b915a932a4f8d288b5c7b4a0461d56797c4f3939118a16d45d3ae15393949dc0fade0729ab80b39adadd40f04dc377aa096b141729b6a21ad139693489711968e8a1e55aeb3e8ab7a5465ea74e1239d81f17aa5c109c258e2e776814c3fb70b790c5519cded22d4ad1c44610bca1aabfabf5ad5ff9f55bd904ff80afbf0e0d1d4c2a6ab910a037d6e938e6f0df7c8b3dd8cd9f799b3f20769705a5cbf20edb921701f280bbc2590e7d94e8ccc20b5197cf934bbb2dbc21a3098780745ae52a0dffeabbcf876cd0961fdd27c72f94e5dae16c7b701457ffed3b80a823b1c1b4a28942b713e694a12dacb9399a943895a51a1ca12326c91ed0015475dfc413483072722fad8cc2011611d34595293ec8efabaa9d7196c38c4c93ac278aaceb895450bb7b6cf4bd20625faa6b3ea38f9a6cab983b52e3d64a3d188b496cedba61e5ac5ee9a8372ed4060c5591f673c831c3c44e8056f4e786f45dddc69b3c0625ca9ba3c0581f4c802bfb55eaf0ef1b39e83dcdcd395af58bca159c6ebc2ab961ae21a561eaea31fd56c8b95cb30757a983a18a42ea3e76943c7a2128cc7cc99ca3d115d238347c8ec91ac0839d8ae6b51cdc663dff287e35316aac6e343e01fb2ecbe2aa92737ac2f95d9b42a8fe6e9799d03fea2a4ae424c8cf0f0879786779a4b9b1d903dc164571b9d67880e188fafab21686630de57f7f72fb0deabb6fc2107c212c042fce0bdd3cb9d074a90d7092768ffdbb42c09e3202addfb0d807f3ffc21d2b2fc5cf919c3996f4f6ca2ceadcda07abcf7c20da8ec74ea7eaec137ce953f1d3eab6af0a30495080e3aeccc427d6bede319867af6dbd50dc2da803b8b80aebb3c4e82fc561e6fec3a76bc19d262cbabe496f1f1ce3cc9d25df368bd331f77b9d7450ef11dbfde6a1f5ff35f4139bf04759ed9fef184f34a728f3818f056554433e3c13daabc7aa3227b399cb5bbd5e1b08db34860950f1fd20763f739646b889fbcbb466866309365dd2ca6fa4dd1cee0b78936ade3035e309c7c831c8707518cd2eff1d7c18c32434386b27075f6c6e3b7ac6dc1d654257efe1f569e57cf8ee1167163d7a2e9456fdebc79135da9dd7ae3a32f6653314956134e8432c2f86b5b7bc2c4d9e835ad2f9f6e50035ed7b8d106a25b8b5afe75ad2b9befb6a6d173afeb5521401dcb02bfc687a0cecb185fcb901116162cf94f000000ffff04075a367c140000")
}

View File

@@ -1,136 +0,0 @@
package renderer
import (
"time"
"unsafe"
"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
shutdown chan bool
writeChan chan []byte
done bool
}
func newSession(conn *websocket.Conn, bindingCache []string, ipc interfaces.IPCManager, logger *logger.CustomLogger, eventMgr interfaces.EventManager) *session {
return &session{
conn: conn,
bindingCache: bindingCache,
ipc: ipc,
log: logger,
eventManager: eventMgr,
shutdown: make(chan bool),
writeChan: make(chan []byte, 100),
}
}
// 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 {
if !s.done {
s.writeChan <- *(*[]byte)(unsafe.Pointer(&msg))
}
return nil
}
func (s *session) start(firstSession bool) {
s.log.Infof("Connected to frontend.")
go s.writePump()
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)
if s.done {
break
}
}
}
// 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)
}
// Shutdown
func (s *session) Shutdown() {
s.done = true
s.shutdown <- true
s.log.Debugf("session %v exit", s.Identifier())
}
// writePump pulls messages from the writeChan and sends them to the client
// since it uses a channel to read the messages the socket is protected without locks
func (s *session) writePump() {
s.log.Debugf("Session %v - writePump start", s.Identifier())
for {
select {
case msg, ok := <-s.writeChan:
s.conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
if !ok {
s.log.Debug("writeChan was closed!")
s.conn.WriteMessage(websocket.CloseMessage, []byte{})
return
}
if err := s.conn.WriteMessage(websocket.TextMessage, msg); err != nil {
s.log.Debug(err.Error())
return
}
case <-s.shutdown:
break
}
}
s.log.Debug("writePump exiting...")
}

File diff suppressed because one or more lines are too long

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