mirror of
https://github.com/taigrr/wails.git
synced 2026-04-04 14:12:40 -07:00
Compare commits
2 Commits
463---keep
...
update-wai
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fbfccdd86 | ||
|
|
1d1a7967ad |
32
.github/workflows/latest-pre.yml
vendored
32
.github/workflows/latest-pre.yml
vendored
@@ -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
|
|
||||||
32
.github/workflows/pr.yml
vendored
32
.github/workflows/pr.yml
vendored
@@ -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
|
|
||||||
34
.github/workflows/release.yml
vendored
34
.github/workflows/release.yml
vendored
@@ -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
|
|
||||||
@@ -2,30 +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)
|
|
||||||
|
|||||||
32
README.md
32
README.md
@@ -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
|
||||||
|
|
||||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
|
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
|
||||||
|
|
||||||
## Special Thank You
|
|
||||||
|
|
||||||
<p align="center" style="text-align: center">
|
|
||||||
A special thank you to JetBrains for donating licenses to us!<br/><br/>
|
|
||||||
Please click the logo to let them know your appreciation!<br/><br/>
|
|
||||||
<a href="https://www.jetbrains.com?from=Wails"><img src="jetbrains-grayscale.png" width="30%"></a>
|
|
||||||
</p>
|
|
||||||
|
|||||||
52
app.go
52
app.go
@@ -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
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
// +build linux darwin !windows
|
|
||||||
|
|
||||||
package wails
|
|
||||||
|
|
||||||
func platformInit() {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
138
azure-pipelines.yaml
Normal 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
138
azure-pipelines.yml
Normal 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
31
cmd/fs.go
31
cmd/fs.go
@@ -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) {
|
||||||
|
|
||||||
|
|||||||
78
cmd/gomod.go
78
cmd/gomod.go
@@ -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)
|
|
||||||
|
|
||||||
}
|
|
||||||
429
cmd/helpers.go
429
cmd/helpers.go
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
62
cmd/linux.go
62
cmd/linux.go
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
127
cmd/linuxdb.yaml
127
cmd/linuxdb.yaml
@@ -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
|
|
||||||
235
cmd/package.go
235
cmd/package.go
@@ -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()
|
||||||
@@ -214,25 +102,18 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
|
|||||||
appname := po.Name + ".app"
|
appname := po.Name + ".app"
|
||||||
|
|
||||||
// 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)
|
||||||
|
|
||||||
exeDir := path.Join(build, appname, "/Contents/MacOS")
|
exeDir := path.Join(b.fs.Cwd(), 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")
|
tmpl := template.New("infoPlist")
|
||||||
plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist")
|
plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist")
|
||||||
@@ -248,7 +129,7 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
filename := path.Join(build, appname, "Contents", "Info.plist")
|
filename := path.Join(b.fs.Cwd(), appname, "Contents", "Info.plist")
|
||||||
err = ioutil.WriteFile(filename, tpl.Bytes(), 0644)
|
err = ioutil.WriteFile(filename, tpl.Bytes(), 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -269,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)
|
||||||
@@ -309,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)
|
||||||
@@ -324,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"
|
||||||
@@ -379,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
100 ICON "$NAME$.ico"
|
100 ICON "$NAME$.ico"
|
||||||
110 24 "$NAME$.exe.manifest"
|
100 24 "$NAME$.exe.manifest"
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
42
cmd/shell.go
42
cmd/shell.go
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,13 +38,12 @@ 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.UserConfigDir()
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'.
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
17
cmd/templates/angular-template/frontend/src/wailsbridge.js
vendored
Normal file
17
cmd/templates/angular-template/frontend/src/wailsbridge.js
vendored
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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{
|
||||||
|
|||||||
@@ -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.0",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.13.0",
|
"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",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'core-js/stable';
|
|||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
import * as Wails from '@wailsapp/runtime';
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
Wails.Init(() => {
|
Wails.Init(() => {
|
||||||
ReactDOM.render(<App />, document.getElementById('app'));
|
ReactDOM.render(<App />, document.getElementById('app'));
|
||||||
|
|||||||
17
cmd/templates/create-react-app/frontend/src/wailsbridge.js
Normal file
17
cmd/templates/create-react-app/frontend/src/wailsbridge.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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.
|
|
||||||
@@ -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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -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
@@ -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);
|
|
||||||
@@ -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')
|
|
||||||
},
|
|
||||||
]
|
|
||||||
})
|
|
||||||
]
|
|
||||||
};
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module {{.BinaryName}}
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/wailsapp/wails {{.WailsVersion}}
|
|
||||||
)
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
'@vue/app'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
disableHostCheck: true
|
disableHostCheck: true,
|
||||||
|
host: "localhost"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
'@vue/app'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -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({
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
disableHostCheck: true
|
disableHostCheck: true,
|
||||||
|
host: "localhost"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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": ""
|
||||||
}
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"esversion": 6
|
|
||||||
}
|
|
||||||
21
cmd/templates/vuetify2-basic/frontend/.gitignore
vendored
21
cmd/templates/vuetify2-basic/frontend/.gitignore
vendored
@@ -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*
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
presets: [
|
|
||||||
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
|
||||||
]
|
|
||||||
};
|
|
||||||
@@ -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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -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">© 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 |
@@ -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>
|
|
||||||
@@ -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');
|
|
||||||
});
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module {{.BinaryName}}
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/wailsapp/wails {{.WailsVersion}}
|
|
||||||
)
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
@@ -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": ""
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
const Version = "v1.7.1"
|
const Version = "v0.17.14-pre"
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
windres.exe -o %1 %2
|
|
||||||
@@ -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
17
go.mod
@@ -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-20200323222414-85ca7c5b95cd
|
|
||||||
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
|
|
||||||
|
|||||||
32
go.sum
32
go.sum
@@ -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,26 +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/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 |
@@ -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")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,215 +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 unmarshall JSON data in event: %s ", err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data)
|
|
||||||
dead := []*session{}
|
|
||||||
for _, session := range h.sessions {
|
|
||||||
err := session.evalJS(message, notifyMessage)
|
|
||||||
if err != nil {
|
|
||||||
h.log.Debugf("Failed to send message to %s - Removing listener : %v", session.Identifier(), err)
|
|
||||||
h.log.Infof("Connection from [%v] unresponsive - dropping", session.Identifier())
|
|
||||||
dead = append(dead, session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h.lock.Lock()
|
|
||||||
defer h.lock.Unlock()
|
|
||||||
for _, session := range dead {
|
|
||||||
delete(h.sessions, session.Identifier())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetColour is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SetColour(colour string) error {
|
|
||||||
h.log.WarnFields("SetColour ignored for Bridge more", logger.Fields{"col": colour})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fullscreen is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) Fullscreen() {
|
|
||||||
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnFullscreen is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) UnFullscreen() {
|
|
||||||
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTitle is currently unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) SetTitle(title string) {
|
|
||||||
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close is unsupported for Bridge but required
|
|
||||||
// for the Renderer interface
|
|
||||||
func (h *Bridge) Close() {
|
|
||||||
h.log.Debug("Shutting down")
|
|
||||||
for _, session := range h.sessions {
|
|
||||||
session.Shutdown()
|
|
||||||
}
|
|
||||||
err := h.server.Close()
|
|
||||||
if err != nil {
|
|
||||||
h.log.Errorf(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
@@ -19,13 +19,12 @@ import (
|
|||||||
// WebView defines the main webview application window
|
// WebView defines the main webview application window
|
||||||
// Default values in []
|
// Default values in []
|
||||||
type WebView struct {
|
type WebView struct {
|
||||||
window wv.WebView // The webview object
|
window wv.WebView // The webview object
|
||||||
ipc interfaces.IPCManager
|
ipc interfaces.IPCManager
|
||||||
log *logger.CustomLogger
|
log *logger.CustomLogger
|
||||||
config interfaces.AppConfig
|
config interfaces.AppConfig
|
||||||
eventManager interfaces.EventManager
|
eventManager interfaces.EventManager
|
||||||
bindingCache []string
|
bindingCache []string
|
||||||
enableConsole bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebView returns a new WebView struct
|
// NewWebView returns a new WebView struct
|
||||||
@@ -58,7 +57,7 @@ func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCMana
|
|||||||
URL: config.GetDefaultHTML(),
|
URL: config.GetDefaultHTML(),
|
||||||
Debug: !config.GetDisableInspector(),
|
Debug: !config.GetDisableInspector(),
|
||||||
ExternalInvokeCallback: func(_ wv.WebView, message string) {
|
ExternalInvokeCallback: func(_ wv.WebView, message string) {
|
||||||
w.ipc.Dispatch(message, w.callback)
|
w.ipc.Dispatch(message)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -104,11 +103,6 @@ func (w *WebView) evalJS(js string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableConsole enables the console!
|
|
||||||
func (w *WebView) EnableConsole() {
|
|
||||||
w.enableConsole = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Escape the Javascripts!
|
// Escape the Javascripts!
|
||||||
func escapeJS(js string) (string, error) {
|
func escapeJS(js string) (string, error) {
|
||||||
result := strings.Replace(js, "\\", "\\\\", -1)
|
result := strings.Replace(js, "\\", "\\\\", -1)
|
||||||
@@ -176,19 +170,16 @@ func (w *WebView) Exit() {
|
|||||||
// Run the window main loop
|
// Run the window main loop
|
||||||
func (w *WebView) Run() error {
|
func (w *WebView) Run() error {
|
||||||
|
|
||||||
w.log.Info("Running...")
|
w.log.Info("Run()")
|
||||||
|
|
||||||
// Inject firebug in debug mode on Windows
|
|
||||||
if w.enableConsole {
|
|
||||||
w.log.Debug("Enabling Wails console")
|
|
||||||
console := mewn.String("../../runtime/assets/console.js")
|
|
||||||
w.evalJS(console)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runtime assets
|
// Runtime assets
|
||||||
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||||
|
w.log.Info("1")
|
||||||
|
|
||||||
w.evalJS(wailsRuntime)
|
w.evalJS(wailsRuntime)
|
||||||
|
|
||||||
|
w.log.Info("2")
|
||||||
|
|
||||||
// Ping the wait channel when the wails runtime is loaded
|
// Ping the wait channel when the wails runtime is loaded
|
||||||
w.eventManager.On("wails:loaded", func(...interface{}) {
|
w.eventManager.On("wails:loaded", func(...interface{}) {
|
||||||
|
|
||||||
@@ -245,7 +236,7 @@ func (w *WebView) NewBinding(methodName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectFile opens a dialog that allows the user to select a file
|
// SelectFile opens a dialog that allows the user to select a file
|
||||||
func (w *WebView) SelectFile(title string, filter string) string {
|
func (w *WebView) SelectFile() string {
|
||||||
var result string
|
var result string
|
||||||
|
|
||||||
// We need to run this on the main thread, however Dispatch is
|
// We need to run this on the main thread, however Dispatch is
|
||||||
@@ -255,7 +246,7 @@ func (w *WebView) SelectFile(title string, filter string) string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(wv.DialogTypeOpen, 0, title, "", filter)
|
result = w.window.Dialog(wv.DialogTypeOpen, 0, "Select File", "")
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
@@ -273,7 +264,7 @@ func (w *WebView) SelectDirectory() string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(wv.DialogTypeOpen, wv.DialogFlagDirectory, "Select Directory", "", "")
|
result = w.window.Dialog(wv.DialogTypeOpen, wv.DialogFlagDirectory, "Select Directory", "")
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
@@ -282,7 +273,7 @@ func (w *WebView) SelectDirectory() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectSaveFile opens a dialog that allows the user to select a file to save
|
// SelectSaveFile opens a dialog that allows the user to select a file to save
|
||||||
func (w *WebView) SelectSaveFile(title string, filter string) string {
|
func (w *WebView) SelectSaveFile() string {
|
||||||
var result string
|
var result string
|
||||||
// We need to run this on the main thread, however Dispatch is
|
// We need to run this on the main thread, however Dispatch is
|
||||||
// non-blocking so we launch this in a goroutine and wait for
|
// non-blocking so we launch this in a goroutine and wait for
|
||||||
@@ -291,7 +282,7 @@ func (w *WebView) SelectSaveFile(title string, filter string) string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(wv.DialogTypeSave, 0, title, "", filter)
|
result = w.window.Dialog(wv.DialogTypeSave, 0, "Save file", "")
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
@@ -299,8 +290,8 @@ func (w *WebView) SelectSaveFile(title string, filter string) string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback sends a callback to the frontend
|
// Callback sends a callback to the frontend
|
||||||
func (w *WebView) callback(data string) error {
|
func (w *WebView) Callback(data string) error {
|
||||||
callbackCMD := fmt.Sprintf("window.wails._.Callback('%s');", data)
|
callbackCMD := fmt.Sprintf("window.wails._.Callback('%s');", data)
|
||||||
return w.evalJS(callbackCMD)
|
return w.evalJS(callbackCMD)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Package webview implements Go bindings to https://github.com/zserge/webview C library.
|
// Package wails implements Go bindings to https://github.com/zserge/webview C library.
|
||||||
// It is a modified version of webview.go from that repository
|
// It is a modified version of webview.go from that repository
|
||||||
|
|
||||||
// Bindings closely repeat the C APIs and include both, a simplified
|
// Bindings closely repeat the C APIs and include both, a simplified
|
||||||
// single-function API to just open a full-screen webview window, and a more
|
// single-function API to just open a full-screen webview window, and a more
|
||||||
// advanced and featureful set of APIs, including Go-to-JavaScript bindings.
|
// advanced and featureful set of APIs, including Go-to-JavaScript bindings.
|
||||||
@@ -10,10 +11,10 @@
|
|||||||
package webview
|
package webview
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo linux openbsd freebsd CFLAGS: -DWEBVIEW_GTK=1 -Wno-deprecated-declarations
|
#cgo linux openbsd freebsd CFLAGS: -DWEBVIEW_GTK=1
|
||||||
#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0
|
#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||||
|
|
||||||
#cgo windows CFLAGS: -DWEBVIEW_WINAPI=1 -std=c99
|
#cgo windows CFLAGS: -DWEBVIEW_WINAPI=1
|
||||||
#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32
|
#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32
|
||||||
|
|
||||||
#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1 -x objective-c
|
#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1 -x objective-c
|
||||||
@@ -74,9 +75,9 @@ static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void CgoDialog(void *w, int dlgtype, int flags,
|
static inline void CgoDialog(void *w, int dlgtype, int flags,
|
||||||
char *title, char *arg, char *res, size_t ressz, char *filter) {
|
char *title, char *arg, char *res, size_t ressz) {
|
||||||
webview_dialog(w, dlgtype, flags,
|
webview_dialog(w, dlgtype, flags,
|
||||||
(const char*)title, (const char*) arg, res, ressz, filter);
|
(const char*)title, (const char*) arg, res, ressz);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int CgoWebViewEval(void *w, char *js) {
|
static inline int CgoWebViewEval(void *w, char *js) {
|
||||||
@@ -186,7 +187,7 @@ type WebView interface {
|
|||||||
// Dialog() opens a system dialog of the given type and title. String
|
// Dialog() opens a system dialog of the given type and title. String
|
||||||
// argument can be provided for certain dialogs, such as alert boxes. For
|
// argument can be provided for certain dialogs, such as alert boxes. For
|
||||||
// alert boxes argument is a message inside the dialog box.
|
// alert boxes argument is a message inside the dialog box.
|
||||||
Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string
|
Dialog(dlgType DialogType, flags int, title string, arg string) string
|
||||||
// Terminate() breaks the main UI loop. This method must be called from the main thread
|
// Terminate() breaks the main UI loop. This method must be called from the main thread
|
||||||
// only. See Dispatch() for more details.
|
// only. See Dispatch() for more details.
|
||||||
Terminate()
|
Terminate()
|
||||||
@@ -311,7 +312,7 @@ func (w *webview) SetFullscreen(fullscreen bool) {
|
|||||||
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
|
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string {
|
func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string) string {
|
||||||
const maxPath = 4096
|
const maxPath = 4096
|
||||||
titlePtr := C.CString(title)
|
titlePtr := C.CString(title)
|
||||||
defer C.free(unsafe.Pointer(titlePtr))
|
defer C.free(unsafe.Pointer(titlePtr))
|
||||||
@@ -319,10 +320,8 @@ func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string
|
|||||||
defer C.free(unsafe.Pointer(argPtr))
|
defer C.free(unsafe.Pointer(argPtr))
|
||||||
resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath)))
|
resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath)))
|
||||||
defer C.free(unsafe.Pointer(resultPtr))
|
defer C.free(unsafe.Pointer(resultPtr))
|
||||||
filterPtr := C.CString(filter)
|
|
||||||
defer C.free(unsafe.Pointer(filterPtr))
|
|
||||||
C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr,
|
C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr,
|
||||||
argPtr, resultPtr, C.size_t(maxPath), filterPtr)
|
argPtr, resultPtr, C.size_t(maxPath))
|
||||||
return C.GoString(resultPtr)
|
return C.GoString(resultPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ struct webview_priv
|
|||||||
NSAutoreleasePool *pool;
|
NSAutoreleasePool *pool;
|
||||||
NSWindow *window;
|
NSWindow *window;
|
||||||
WebView *webview;
|
WebView *webview;
|
||||||
id delegate;
|
id windowDelegate;
|
||||||
int should_exit;
|
int should_exit;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
@@ -139,7 +139,7 @@ struct webview_priv
|
|||||||
#define DEFAULT_URL \
|
#define DEFAULT_URL \
|
||||||
"data:text/" \
|
"data:text/" \
|
||||||
"html,%3C%21DOCTYPE%20html%3E%0A%3Chtml%20lang=%22en%22%3E%0A%3Chead%3E%" \
|
"html,%3C%21DOCTYPE%20html%3E%0A%3Chtml%20lang=%22en%22%3E%0A%3Chead%3E%" \
|
||||||
"3Cmeta%20charset=%22utf-8%22%3E%3Cmeta%20http-equiv=%22IE=edge%22%" \
|
"3Cmeta%20charset=%22utf-8%22%3E%3Cmeta%20http-equiv=%22IE=edge%22%" \
|
||||||
"20content=%22IE=edge%22%3E%3C%2Fhead%3E%0A%3Cbody%3E%3Cdiv%20id=%22app%22%" \
|
"20content=%22IE=edge%22%3E%3C%2Fhead%3E%0A%3Cbody%3E%3Cdiv%20id=%22app%22%" \
|
||||||
"3E%3C%2Fdiv%3E%3Cscript%20type=%22text%2Fjavascript%22%3E%3C%2Fscript%3E%" \
|
"3E%3C%2Fdiv%3E%3Cscript%20type=%22text%2Fjavascript%22%3E%3C%2Fscript%3E%" \
|
||||||
"3C%2Fbody%3E%0A%3C%2Fhtml%3E"
|
"3C%2Fbody%3E%0A%3C%2Fhtml%3E"
|
||||||
@@ -174,7 +174,7 @@ struct webview_priv
|
|||||||
WEBVIEW_API void webview_dialog(struct webview *w,
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
||||||
enum webview_dialog_type dlgtype, int flags,
|
enum webview_dialog_type dlgtype, int flags,
|
||||||
const char *title, const char *arg,
|
const char *title, const char *arg,
|
||||||
char *result, size_t resultsz, char *filter);
|
char *result, size_t resultsz);
|
||||||
WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
|
WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
|
||||||
void *arg);
|
void *arg);
|
||||||
WEBVIEW_API void webview_terminate(struct webview *w);
|
WEBVIEW_API void webview_terminate(struct webview *w);
|
||||||
@@ -418,7 +418,7 @@ struct webview_priv
|
|||||||
WEBVIEW_API void webview_dialog(struct webview *w,
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
||||||
enum webview_dialog_type dlgtype, int flags,
|
enum webview_dialog_type dlgtype, int flags,
|
||||||
const char *title, const char *arg,
|
const char *title, const char *arg,
|
||||||
char *result, size_t resultsz, char *filter)
|
char *result, size_t resultsz)
|
||||||
{
|
{
|
||||||
GtkWidget *dlg;
|
GtkWidget *dlg;
|
||||||
if (result != NULL)
|
if (result != NULL)
|
||||||
@@ -438,17 +438,6 @@ struct webview_priv
|
|||||||
"_Cancel", GTK_RESPONSE_CANCEL,
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
||||||
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
|
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
|
||||||
GTK_RESPONSE_ACCEPT, NULL);
|
GTK_RESPONSE_ACCEPT, NULL);
|
||||||
if (filter[0] != '\0') {
|
|
||||||
GtkFileFilter *file_filter = gtk_file_filter_new();
|
|
||||||
gchar **filters = g_strsplit(filter, ",", -1);
|
|
||||||
gint i;
|
|
||||||
for(i = 0; filters && filters[i]; i++) {
|
|
||||||
gtk_file_filter_add_pattern(file_filter, filters[i]);
|
|
||||||
}
|
|
||||||
gtk_file_filter_set_name(file_filter, filter);
|
|
||||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dlg), file_filter);
|
|
||||||
g_strfreev(filters);
|
|
||||||
}
|
|
||||||
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
|
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
|
||||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
|
||||||
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
|
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
|
||||||
@@ -1049,7 +1038,7 @@ struct webview_priv
|
|||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TCHAR *classname = TEXT("WebView");
|
static const TCHAR *classname = "WebView";
|
||||||
static const SAFEARRAYBOUND ArrayBound = {1, 0};
|
static const SAFEARRAYBOUND ArrayBound = {1, 0};
|
||||||
|
|
||||||
static IOleClientSiteVtbl MyIOleClientSiteTable = {
|
static IOleClientSiteVtbl MyIOleClientSiteTable = {
|
||||||
@@ -1238,7 +1227,7 @@ struct webview_priv
|
|||||||
}
|
}
|
||||||
VariantInit(&myURL);
|
VariantInit(&myURL);
|
||||||
myURL.vt = VT_BSTR;
|
myURL.vt = VT_BSTR;
|
||||||
// #ifndef UNICODE
|
#ifndef UNICODE
|
||||||
{
|
{
|
||||||
wchar_t *buffer = webview_to_utf16(webPageName);
|
wchar_t *buffer = webview_to_utf16(webPageName);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
@@ -1248,9 +1237,9 @@ struct webview_priv
|
|||||||
myURL.bstrVal = SysAllocString(buffer);
|
myURL.bstrVal = SysAllocString(buffer);
|
||||||
GlobalFree(buffer);
|
GlobalFree(buffer);
|
||||||
}
|
}
|
||||||
// #else
|
#else
|
||||||
// myURL.bstrVal = SysAllocString(webPageName);
|
myURL.bstrVal = SysAllocString(webPageName);
|
||||||
// #endif
|
#endif
|
||||||
if (!myURL.bstrVal)
|
if (!myURL.bstrVal)
|
||||||
{
|
{
|
||||||
badalloc:
|
badalloc:
|
||||||
@@ -1288,7 +1277,7 @@ struct webview_priv
|
|||||||
if (!SafeArrayAccessData(sfArray, (void **)&pVar))
|
if (!SafeArrayAccessData(sfArray, (void **)&pVar))
|
||||||
{
|
{
|
||||||
pVar->vt = VT_BSTR;
|
pVar->vt = VT_BSTR;
|
||||||
// #ifndef UNICODE
|
#ifndef UNICODE
|
||||||
{
|
{
|
||||||
wchar_t *buffer = webview_to_utf16(url);
|
wchar_t *buffer = webview_to_utf16(url);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
@@ -1298,9 +1287,9 @@ struct webview_priv
|
|||||||
bstr = SysAllocString(buffer);
|
bstr = SysAllocString(buffer);
|
||||||
GlobalFree(buffer);
|
GlobalFree(buffer);
|
||||||
}
|
}
|
||||||
// #else
|
#else
|
||||||
// bstr = SysAllocString(url);
|
bstr = SysAllocString(string);
|
||||||
// #endif
|
#endif
|
||||||
if ((pVar->bstrVal = bstr))
|
if ((pVar->bstrVal = bstr))
|
||||||
{
|
{
|
||||||
htmlDoc2->lpVtbl->write(htmlDoc2, sfArray);
|
htmlDoc2->lpVtbl->write(htmlDoc2, sfArray);
|
||||||
@@ -1415,14 +1404,11 @@ struct webview_priv
|
|||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZeroMemory(&wc, sizeof(WNDCLASSEX));
|
ZeroMemory(&wc, sizeof(WNDCLASSEX));
|
||||||
wc.cbSize = sizeof(WNDCLASSEX);
|
wc.cbSize = sizeof(WNDCLASSEX);
|
||||||
wc.hInstance = hInstance;
|
wc.hInstance = hInstance;
|
||||||
wc.lpfnWndProc = wndproc;
|
wc.lpfnWndProc = wndproc;
|
||||||
wc.lpszClassName = classname;
|
wc.lpszClassName = classname;
|
||||||
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(100));
|
|
||||||
wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(100));
|
|
||||||
RegisterClassEx(&wc);
|
RegisterClassEx(&wc);
|
||||||
|
|
||||||
style = WS_OVERLAPPEDWINDOW;
|
style = WS_OVERLAPPEDWINDOW;
|
||||||
@@ -1445,24 +1431,10 @@ struct webview_priv
|
|||||||
rect.bottom = rect.bottom - rect.top + top;
|
rect.bottom = rect.bottom - rect.top + top;
|
||||||
rect.top = top;
|
rect.top = top;
|
||||||
|
|
||||||
#ifdef UNICODE
|
|
||||||
wchar_t *u16title = webview_to_utf16(w->title);
|
|
||||||
if (u16title == NULL)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
w->priv.hwnd =
|
|
||||||
CreateWindowEx(0, classname, u16title, style, rect.left, rect.top,
|
|
||||||
rect.right - rect.left, rect.bottom - rect.top,
|
|
||||||
HWND_DESKTOP, NULL, hInstance, (void *)w);
|
|
||||||
#else
|
|
||||||
w->priv.hwnd =
|
w->priv.hwnd =
|
||||||
CreateWindowEx(0, classname, w->title, style, rect.left, rect.top,
|
CreateWindowEx(0, classname, w->title, style, rect.left, rect.top,
|
||||||
rect.right - rect.left, rect.bottom - rect.top,
|
rect.right - rect.left, rect.bottom - rect.top,
|
||||||
HWND_DESKTOP, NULL, hInstance, (void *)w);
|
HWND_DESKTOP, NULL, hInstance, (void *)w);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (w->priv.hwnd == 0)
|
if (w->priv.hwnd == 0)
|
||||||
{
|
{
|
||||||
OleUninitialize();
|
OleUninitialize();
|
||||||
@@ -1473,13 +1445,7 @@ struct webview_priv
|
|||||||
|
|
||||||
DisplayHTMLPage(w);
|
DisplayHTMLPage(w);
|
||||||
|
|
||||||
#ifdef UNICODE
|
|
||||||
SetWindowText(w->priv.hwnd, u16title);
|
|
||||||
GlobalFree(u16title);
|
|
||||||
#else
|
|
||||||
SetWindowText(w->priv.hwnd, w->title);
|
SetWindowText(w->priv.hwnd, w->title);
|
||||||
#endif
|
|
||||||
|
|
||||||
ShowWindow(w->priv.hwnd, SW_SHOWDEFAULT);
|
ShowWindow(w->priv.hwnd, SW_SHOWDEFAULT);
|
||||||
UpdateWindow(w->priv.hwnd);
|
UpdateWindow(w->priv.hwnd);
|
||||||
SetFocus(w->priv.hwnd);
|
SetFocus(w->priv.hwnd);
|
||||||
@@ -1506,11 +1472,6 @@ struct webview_priv
|
|||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN:
|
||||||
case WM_KEYUP:
|
case WM_KEYUP:
|
||||||
{
|
{
|
||||||
// Disable refresh when pressing F5 on windows
|
|
||||||
if (msg.wParam == VK_F5)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
HRESULT r = S_OK;
|
HRESULT r = S_OK;
|
||||||
IWebBrowser2 *webBrowser2;
|
IWebBrowser2 *webBrowser2;
|
||||||
IOleObject *browser = *w->priv.browser;
|
IOleObject *browser = *w->priv.browser;
|
||||||
@@ -1620,17 +1581,7 @@ struct webview_priv
|
|||||||
|
|
||||||
WEBVIEW_API void webview_set_title(struct webview *w, const char *title)
|
WEBVIEW_API void webview_set_title(struct webview *w, const char *title)
|
||||||
{
|
{
|
||||||
#ifdef UNICODE
|
|
||||||
wchar_t *u16title = webview_to_utf16(title);
|
|
||||||
if (u16title == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SetWindowText(w->priv.hwnd, u16title);
|
|
||||||
GlobalFree(u16title);
|
|
||||||
#else
|
|
||||||
SetWindowText(w->priv.hwnd, title);
|
SetWindowText(w->priv.hwnd, title);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen)
|
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen)
|
||||||
@@ -1793,7 +1744,7 @@ struct webview_priv
|
|||||||
WEBVIEW_API void webview_dialog(struct webview *w,
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
||||||
enum webview_dialog_type dlgtype, int flags,
|
enum webview_dialog_type dlgtype, int flags,
|
||||||
const char *title, const char *arg,
|
const char *title, const char *arg,
|
||||||
char *result, size_t resultsz, char *filter)
|
char *result, size_t resultsz)
|
||||||
{
|
{
|
||||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
||||||
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
|
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
|
||||||
@@ -1833,32 +1784,6 @@ struct webview_priv
|
|||||||
FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
|
FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
|
||||||
FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
|
FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
|
||||||
}
|
}
|
||||||
if (filter[0] != '\0')
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
int i=0;
|
|
||||||
char* token;
|
|
||||||
char* filter_dup = strdup(filter);
|
|
||||||
for (count=1; filter[count]; filter[count]==',' ? count++ : *filter++);
|
|
||||||
COMDLG_FILTERSPEC rgSpec[count];
|
|
||||||
char* filters[count];
|
|
||||||
token = strtok(filter_dup, ",");
|
|
||||||
while(token != NULL)
|
|
||||||
{
|
|
||||||
filters[i] = token;
|
|
||||||
token = strtok(NULL, ",");
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
for (int i=0; i < count; i++) {
|
|
||||||
wchar_t *wFilter = (wchar_t *)malloc(4096);
|
|
||||||
MultiByteToWideChar(CP_ACP, 0, filters[i], -1, wFilter, 4096);
|
|
||||||
rgSpec[i].pszName = wFilter;
|
|
||||||
rgSpec[i].pszSpec = wFilter;
|
|
||||||
}
|
|
||||||
if (dlg->lpVtbl->SetFileTypes(dlg, count, rgSpec) != S_OK) {
|
|
||||||
goto error_dlg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK)
|
if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK)
|
||||||
{
|
{
|
||||||
goto error_dlg;
|
goto error_dlg;
|
||||||
@@ -1969,26 +1894,6 @@ struct webview_priv
|
|||||||
[script setValue:self forKey:@"external"];
|
[script setValue:self forKey:@"external"];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void webview_run_input_open_panel(id self, SEL cmd, id webview,
|
|
||||||
id listener, BOOL allowMultiple)
|
|
||||||
{
|
|
||||||
char filename[256] = "";
|
|
||||||
struct webview *w =
|
|
||||||
(struct webview *)objc_getAssociatedObject(self, "webview");
|
|
||||||
|
|
||||||
webview_dialog(w, WEBVIEW_DIALOG_TYPE_OPEN, WEBVIEW_DIALOG_FLAG_FILE, "", "",
|
|
||||||
filename, 255, "");
|
|
||||||
filename[255] = '\0';
|
|
||||||
if (strlen(filename) > 0)
|
|
||||||
{
|
|
||||||
[listener chooseFilename:[NSString stringWithUTF8String:filename]];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[listener cancel];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void webview_external_invoke(id self, SEL cmd, id arg)
|
static void webview_external_invoke(id self, SEL cmd, id arg)
|
||||||
{
|
{
|
||||||
struct webview *w =
|
struct webview *w =
|
||||||
@@ -2001,7 +1906,7 @@ struct webview_priv
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
w->external_invoke_cb(w, [(NSString *)(arg) UTF8String]);
|
w->external_invoke_cb(w, [(NSString *)(arg)UTF8String]);
|
||||||
}
|
}
|
||||||
|
|
||||||
WEBVIEW_API int webview_init(struct webview *w)
|
WEBVIEW_API int webview_init(struct webview *w)
|
||||||
@@ -2022,17 +1927,12 @@ struct webview_priv
|
|||||||
class_addMethod(webViewDelegateClass,
|
class_addMethod(webViewDelegateClass,
|
||||||
sel_registerName("webView:didClearWindowObject:forFrame:"),
|
sel_registerName("webView:didClearWindowObject:forFrame:"),
|
||||||
(IMP)webview_did_clear_window_object, "v@:@@@");
|
(IMP)webview_did_clear_window_object, "v@:@@@");
|
||||||
class_addMethod(
|
|
||||||
webViewDelegateClass,
|
|
||||||
sel_registerName("webView:runOpenPanelForFileButtonWithResultListener:"
|
|
||||||
"allowMultipleFiles:"),
|
|
||||||
(IMP)webview_run_input_open_panel, "v@:@@c");
|
|
||||||
class_addMethod(webViewDelegateClass, sel_registerName("invoke:"),
|
class_addMethod(webViewDelegateClass, sel_registerName("invoke:"),
|
||||||
(IMP)webview_external_invoke, "v@:@");
|
(IMP)webview_external_invoke, "v@:@");
|
||||||
objc_registerClassPair(webViewDelegateClass);
|
objc_registerClassPair(webViewDelegateClass);
|
||||||
|
|
||||||
w->priv.delegate = [[webViewDelegateClass alloc] init];
|
w->priv.windowDelegate = [[webViewDelegateClass alloc] init];
|
||||||
objc_setAssociatedObject(w->priv.delegate, "webview", (id)(w),
|
objc_setAssociatedObject(w->priv.windowDelegate, "webview", (id)(w),
|
||||||
OBJC_ASSOCIATION_ASSIGN);
|
OBJC_ASSOCIATION_ASSIGN);
|
||||||
|
|
||||||
NSRect r = NSMakeRect(0, 0, w->width, w->height);
|
NSRect r = NSMakeRect(0, 0, w->width, w->height);
|
||||||
@@ -2060,7 +1960,7 @@ struct webview_priv
|
|||||||
NSString *nsTitle = [NSString stringWithUTF8String:w->title];
|
NSString *nsTitle = [NSString stringWithUTF8String:w->title];
|
||||||
[w->priv.window setTitle:nsTitle];
|
[w->priv.window setTitle:nsTitle];
|
||||||
|
|
||||||
[w->priv.window setDelegate:w->priv.delegate];
|
[w->priv.window setDelegate:w->priv.windowDelegate];
|
||||||
[w->priv.window center];
|
[w->priv.window center];
|
||||||
|
|
||||||
// NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"wat"];
|
// NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"wat"];
|
||||||
@@ -2089,8 +1989,7 @@ struct webview_priv
|
|||||||
[w->priv.webview setAutoresizesSubviews:YES];
|
[w->priv.webview setAutoresizesSubviews:YES];
|
||||||
[w->priv.webview
|
[w->priv.webview
|
||||||
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||||
w->priv.webview.frameLoadDelegate = w->priv.delegate;
|
w->priv.webview.frameLoadDelegate = w->priv.windowDelegate;
|
||||||
w->priv.webview.UIDelegate = w->priv.delegate;
|
|
||||||
[[w->priv.window contentView] addSubview:w->priv.webview];
|
[[w->priv.window contentView] addSubview:w->priv.webview];
|
||||||
[w->priv.window orderFrontRegardless];
|
[w->priv.window orderFrontRegardless];
|
||||||
|
|
||||||
@@ -2240,16 +2139,12 @@ struct webview_priv
|
|||||||
WEBVIEW_API void webview_dialog(struct webview *w,
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
||||||
enum webview_dialog_type dlgtype, int flags,
|
enum webview_dialog_type dlgtype, int flags,
|
||||||
const char *title, const char *arg,
|
const char *title, const char *arg,
|
||||||
char *result, size_t resultsz, char *filter)
|
char *result, size_t resultsz)
|
||||||
{
|
{
|
||||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
||||||
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
|
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
|
||||||
{
|
{
|
||||||
NSSavePanel *panel;
|
NSSavePanel *panel;
|
||||||
NSString *filter_str = [NSString stringWithUTF8String:filter];
|
|
||||||
filter_str = [filter_str stringByReplacingOccurrencesOfString:@"*."
|
|
||||||
withString:@""];
|
|
||||||
NSArray *fileTypes = [filter_str componentsSeparatedByString:@","];
|
|
||||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN)
|
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN)
|
||||||
{
|
{
|
||||||
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
||||||
@@ -2262,10 +2157,6 @@ struct webview_priv
|
|||||||
{
|
{
|
||||||
[openPanel setCanChooseFiles:YES];
|
[openPanel setCanChooseFiles:YES];
|
||||||
[openPanel setCanChooseDirectories:NO];
|
[openPanel setCanChooseDirectories:NO];
|
||||||
if(filter[0] != NULL)
|
|
||||||
{
|
|
||||||
[openPanel setAllowedFileTypes:fileTypes];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
[openPanel setResolvesAliases:NO];
|
[openPanel setResolvesAliases:NO];
|
||||||
[openPanel setAllowsMultipleSelection:NO];
|
[openPanel setAllowsMultipleSelection:NO];
|
||||||
@@ -2279,10 +2170,6 @@ struct webview_priv
|
|||||||
[panel setShowsHiddenFiles:YES];
|
[panel setShowsHiddenFiles:YES];
|
||||||
[panel setExtensionHidden:NO];
|
[panel setExtensionHidden:NO];
|
||||||
[panel setCanSelectHiddenExtension:NO];
|
[panel setCanSelectHiddenExtension:NO];
|
||||||
if(filter[0] != NULL)
|
|
||||||
{
|
|
||||||
[panel setAllowedFileTypes:fileTypes];
|
|
||||||
}
|
|
||||||
[panel setTreatsFilePackagesAsDirectories:YES];
|
[panel setTreatsFilePackagesAsDirectories:YES];
|
||||||
[panel beginSheetModalForWindow:w->priv.window
|
[panel beginSheetModalForWindow:w->priv.window
|
||||||
completionHandler:^(NSInteger result) {
|
completionHandler:^(NSInteger result) {
|
||||||
|
|||||||
BIN
logo_cropped.png
BIN
logo_cropped.png
Binary file not shown.
|
Before Width: | Height: | Size: 122 KiB |
@@ -14,7 +14,7 @@ function init() {
|
|||||||
window.wailsbridge = {
|
window.wailsbridge = {
|
||||||
reconnectOverlay: null,
|
reconnectOverlay: null,
|
||||||
reconnectTimer: 300,
|
reconnectTimer: 300,
|
||||||
wsURL: 'ws://' + window.location.hostname + ':34115/bridge',
|
wsURL: 'ws://localhost:34115/bridge',
|
||||||
connectionState: null,
|
connectionState: null,
|
||||||
config: {},
|
config: {},
|
||||||
websocket: null,
|
websocket: null,
|
||||||
@@ -95,6 +95,13 @@ function startBridge() {
|
|||||||
window.wailsbridge.reconnectOverlay.style.display = 'none';
|
window.wailsbridge.reconnectOverlay.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bridge external.invoke
|
||||||
|
window.external = {
|
||||||
|
invoke: function (msg) {
|
||||||
|
window.wailsbridge.websocket.send(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Adds a script to the Dom.
|
// Adds a script to the Dom.
|
||||||
// Removes it if second parameter is true.
|
// Removes it if second parameter is true.
|
||||||
function addScript(script, remove) {
|
function addScript(script, remove) {
|
||||||
@@ -207,4 +214,4 @@ function Init(callback) {
|
|||||||
start(callback);
|
start(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Init;
|
module.exports = { Init };
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
(function () {
|
|
||||||
|
|
||||||
window.wailsconsole = {};
|
|
||||||
|
|
||||||
var debugconsole = document.createElement("div");
|
|
||||||
var header = document.createElement("div");
|
|
||||||
var consoleOut = document.createElement("div");
|
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('keyup', logKey);
|
|
||||||
|
|
||||||
debugconsole.id = "wailsdebug";
|
|
||||||
debugconsole.style.fontSize = "18px";
|
|
||||||
debugconsole.style.width = "100%";
|
|
||||||
debugconsole.style.height = "35%";
|
|
||||||
debugconsole.style.maxHeight = "35%";
|
|
||||||
debugconsole.style.position = "fixed";
|
|
||||||
debugconsole.style.left = "0px";
|
|
||||||
debugconsole.style.backgroundColor = "rgba(255,255,255,0.8)";
|
|
||||||
debugconsole.style.borderTop = '1px solid black';
|
|
||||||
debugconsole.style.color = "black";
|
|
||||||
debugconsole.style.display = "none";
|
|
||||||
|
|
||||||
header.style.width = "100%";
|
|
||||||
header.style.height = "30px";
|
|
||||||
header.style.display = "block";
|
|
||||||
// header.style.paddingTop = "3px";
|
|
||||||
header.style.verticalAlign = "middle";
|
|
||||||
header.style.paddingLeft = "10px";
|
|
||||||
header.style.background = "rgba(255,255,255,0.8)";
|
|
||||||
header.innerHTML = " <span style='vertical-align: middle'> Wails Console > <input id='conin' style='border: solid 1px black; width: 50%'></input><span style='padding-left: 5px; cursor:pointer;' onclick='window.wailsconsole.clearConsole()'>Clear</span></span>";
|
|
||||||
|
|
||||||
consoleOut.style.position = "absolute";
|
|
||||||
consoleOut.style.width = "100%";
|
|
||||||
consoleOut.style.height = "auto";
|
|
||||||
consoleOut.style.top = "30px";
|
|
||||||
// consoleOut.style.paddingLeft = "10px";
|
|
||||||
consoleOut.style.bottom = "0px";
|
|
||||||
consoleOut.style.backgroundColor = "rgba(200,200,200,1)";
|
|
||||||
consoleOut.style.overflowY = "scroll";
|
|
||||||
consoleOut.style.msOverflowStyle = "-ms-autohiding-scrollbar";
|
|
||||||
|
|
||||||
debugconsole.appendChild(header);
|
|
||||||
debugconsole.appendChild(consoleOut);
|
|
||||||
document.body.appendChild(debugconsole);
|
|
||||||
console.log(debugconsole.style.display)
|
|
||||||
|
|
||||||
function logKey(e) {
|
|
||||||
var conin = document.getElementById('conin');
|
|
||||||
if (e.which == 27 && e.shiftKey) {
|
|
||||||
toggleConsole(conin);
|
|
||||||
}
|
|
||||||
if (e.which == 13 && consoleVisible()) {
|
|
||||||
var command = conin.value.trim();
|
|
||||||
if (command.length > 0) {
|
|
||||||
console.log("> " + command)
|
|
||||||
try {
|
|
||||||
evaluateInput(command);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e.message);
|
|
||||||
}
|
|
||||||
conin.value = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function consoleVisible() {
|
|
||||||
return debugconsole.style.display == "block";
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleConsole(conin) {
|
|
||||||
var display = "none"
|
|
||||||
if (debugconsole.style.display == "none") display = "block";
|
|
||||||
debugconsole.style.display = display;
|
|
||||||
if (display == "block") {
|
|
||||||
conin.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateExpression(expression) {
|
|
||||||
|
|
||||||
var pathSegments = [].concat(expression.split('.'));
|
|
||||||
if (pathSegments[0] == 'window') {
|
|
||||||
pathSegments.shift()
|
|
||||||
}
|
|
||||||
var currentObject = window;
|
|
||||||
for (var i = 0; i < pathSegments.length; i++) {
|
|
||||||
var pathSegment = pathSegments[i];
|
|
||||||
if (currentObject[pathSegment] == undefined) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
currentObject = currentObject[pathSegment];
|
|
||||||
}
|
|
||||||
console.log(JSON.stringify(currentObject));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateInput(command) {
|
|
||||||
try {
|
|
||||||
if (evaluateExpression(command)) {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
eval(command);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Set us up as a listener
|
|
||||||
function hookIntoIPC() {
|
|
||||||
if (window.wails && window.wails._ && window.wails._.AddIPCListener) {
|
|
||||||
window.wails._.AddIPCListener(processIPCMessage);
|
|
||||||
} else {
|
|
||||||
setTimeout(hookIntoIPC, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hookIntoIPC();
|
|
||||||
|
|
||||||
function processIPCMessage(message) {
|
|
||||||
console.log(message);
|
|
||||||
var parsedMessage;
|
|
||||||
try {
|
|
||||||
parsedMessage = JSON.parse(message);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Error in parsing IPC message: " + e.message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var logmessage = "[IPC] "
|
|
||||||
switch (parsedMessage.type) {
|
|
||||||
case 'call':
|
|
||||||
logmessage += " Call: " + parsedMessage.payload.bindingName;
|
|
||||||
var params = "";
|
|
||||||
var parsedParams = JSON.parse(parsedMessage.payload.data);
|
|
||||||
if (parsedParams.length > 0) {
|
|
||||||
params = parsedParams;
|
|
||||||
}
|
|
||||||
logmessage += "(" + params + ")";
|
|
||||||
break;
|
|
||||||
case 'log':
|
|
||||||
logmessage += "Log (" + parsedMessage.payload.level + "): " + parsedMessage.payload.message;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logmessage = message;
|
|
||||||
}
|
|
||||||
console.log(logmessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.wailsconsole.clearConsole = function () {
|
|
||||||
consoleOut.innerHTML = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log = function (message) {
|
|
||||||
consoleOut.innerHTML = consoleOut.innerHTML + "<span style='padding-left: 5px'>" + message + '</span><br/>';
|
|
||||||
consoleOut.scrollTop = consoleOut.scrollHeight;
|
|
||||||
|
|
||||||
};
|
|
||||||
console.error = function (message) {
|
|
||||||
consoleOut.innerHTML = consoleOut.innerHTML + "<span style='color:red; padding-left: 5px'> Error: " + message + '</span><br/>';
|
|
||||||
consoleOut.scrollTop = consoleOut.scrollHeight;
|
|
||||||
};
|
|
||||||
// var h = document.getElementsByTagName("html")[0];
|
|
||||||
// console.log("html margin: " + h.style.marginLeft);
|
|
||||||
// console.log("html padding: " + h.style.paddingLeft);
|
|
||||||
|
|
||||||
// setInterval(function() { console.log("test");}, 1000);
|
|
||||||
// setInterval(function() { console.error("oops");}, 3000);
|
|
||||||
// var script = document.createElement('script');
|
|
||||||
// script.src = "https://cdnjs.cloudflare.com/ajax/libs/firebug-lite/1.4.0/firebug-lite.js#startOpened=true";
|
|
||||||
// document.body.appendChild(script);
|
|
||||||
|
|
||||||
})();
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,6 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "github.com/wailsapp/wails/lib/interfaces"
|
import "github.com/wailsapp/wails/lib/interfaces"
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// Dialog exposes an interface to native dialogs
|
// Dialog exposes an interface to native dialogs
|
||||||
type Dialog struct {
|
type Dialog struct {
|
||||||
@@ -16,16 +15,8 @@ func NewDialog(renderer interfaces.Renderer) *Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectFile prompts the user to select a file
|
// SelectFile prompts the user to select a file
|
||||||
func (r *Dialog) SelectFile(params ...string) string {
|
func (r *Dialog) SelectFile() string {
|
||||||
title := "Select File"
|
return r.renderer.SelectFile()
|
||||||
filter := ""
|
|
||||||
if len(params) > 0 {
|
|
||||||
title = params[0]
|
|
||||||
}
|
|
||||||
if len(params) > 1 {
|
|
||||||
filter = strings.Replace(params[1], " ", "", -1)
|
|
||||||
}
|
|
||||||
return r.renderer.SelectFile(title, filter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectDirectory prompts the user to select a directory
|
// SelectDirectory prompts the user to select a directory
|
||||||
@@ -34,14 +25,6 @@ func (r *Dialog) SelectDirectory() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectSaveFile prompts the user to select a file for saving
|
// SelectSaveFile prompts the user to select a file for saving
|
||||||
func (r *Dialog) SelectSaveFile(params ...string) string {
|
func (r *Dialog) SelectSaveFile() string {
|
||||||
title := "Select Save"
|
return r.renderer.SelectSaveFile()
|
||||||
filter := ""
|
|
||||||
if len(params) > 0 {
|
|
||||||
title = params[0]
|
|
||||||
}
|
|
||||||
if len(params) > 1 {
|
|
||||||
filter = strings.Replace(params[1], " ", "", -1)
|
|
||||||
}
|
|
||||||
return r.renderer.SelectSaveFile(title, filter)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "os"
|
import homedir "github.com/mitchellh/go-homedir"
|
||||||
|
|
||||||
// FileSystem exposes file system utilities to the runtime
|
// FileSystem exposes file system utilities to the runtime
|
||||||
type FileSystem struct{}
|
type FileSystem struct {}
|
||||||
|
|
||||||
// NewFileSystem creates a new FileSystem struct
|
// NewFileSystem creates a new FileSystem struct
|
||||||
func NewFileSystem() *FileSystem {
|
func NewFileSystem() *FileSystem {
|
||||||
@@ -12,5 +12,5 @@ func NewFileSystem() *FileSystem {
|
|||||||
|
|
||||||
// HomeDir returns the user's home directory
|
// HomeDir returns the user's home directory
|
||||||
func (r *FileSystem) HomeDir() (string, error) {
|
func (r *FileSystem) HomeDir() (string, error) {
|
||||||
return os.UserHomeDir()
|
return homedir.Dir()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
"error",
|
"error",
|
||||||
"tab"
|
"tab"
|
||||||
],
|
],
|
||||||
"linebreak-style": 0,
|
"linebreak-style": [
|
||||||
|
"error",
|
||||||
|
"unix"
|
||||||
|
],
|
||||||
"quotes": [
|
"quotes": [
|
||||||
"error",
|
"error",
|
||||||
"single"
|
"single"
|
||||||
@@ -25,4 +28,4 @@
|
|||||||
"always"
|
"always"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,15 +46,13 @@ export function NewBinding(bindingName) {
|
|||||||
// Check if we have a path (IE Struct)
|
// Check if we have a path (IE Struct)
|
||||||
if (bindingSections.length > 1) {
|
if (bindingSections.length > 1) {
|
||||||
// Iterate over binding sections, adding them to the window.backend object
|
// Iterate over binding sections, adding them to the window.backend object
|
||||||
for (let index = 0; index < bindingSections.length-1; index += 1) {
|
for (let index = 0; index < bindingSections.length - 1; index += 1) {
|
||||||
const name = bindingSections[index];
|
const name = bindingSections[index];
|
||||||
// Is name a valid javascript identifier?
|
// Is name a valid javascript identifier?
|
||||||
if (!isValidIdentifier(name)) {
|
if (!isValidIdentifier(name)) {
|
||||||
return new Error(`${name} is not a valid javascript identifier.`);
|
return new Error(`${name} is not a valid javascript identifier.`);
|
||||||
}
|
}
|
||||||
if (!pathToBinding[name]) {
|
pathToBinding[name] = {};
|
||||||
pathToBinding[name] = {};
|
|
||||||
}
|
|
||||||
pathToBinding = pathToBinding[name];
|
pathToBinding = pathToBinding[name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user