mirror of
https://github.com/taigrr/wails.git
synced 2026-04-04 22:22:41 -07:00
Compare commits
179 Commits
v0.17.0
...
v1.0.2-pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
084d412d86 | ||
|
|
788d22740b | ||
|
|
34ef3de737 | ||
|
|
8149cbc3c0 | ||
|
|
2032ef8225 | ||
|
|
38e897f646 | ||
|
|
de2f9a1e9e | ||
|
|
c506c95506 | ||
|
|
955cfbb689 | ||
|
|
aa698b993d | ||
|
|
a6fa5feb0c | ||
|
|
67a52b2a57 | ||
|
|
99d22fdcb7 | ||
|
|
7051ffd425 | ||
|
|
bac823566c | ||
|
|
401ebee719 | ||
|
|
b5b92c4afa | ||
|
|
2c2aee2d30 | ||
|
|
806b1aa8e0 | ||
|
|
416bd7bfc4 | ||
|
|
aca72d3f7a | ||
|
|
ad20e2622b | ||
|
|
94c56115a5 | ||
|
|
daeda501f4 | ||
|
|
fb1e8647bc | ||
|
|
723236f348 | ||
|
|
394a823d82 | ||
|
|
afe57802ad | ||
|
|
914642bd1d | ||
|
|
dafd9bcb24 | ||
|
|
7f75f27f6b | ||
|
|
d77fa1ee74 | ||
|
|
82e00ff83a | ||
|
|
14f91ab109 | ||
|
|
19706a12a4 | ||
|
|
52e6091f0f | ||
|
|
2db1624faf | ||
|
|
f5d3fb0848 | ||
|
|
85a64914aa | ||
|
|
0819207e33 | ||
|
|
50a0bc7701 | ||
|
|
c51f0cad6f | ||
|
|
6795f6c678 | ||
|
|
315ef5f7ea | ||
|
|
24530d9da4 | ||
|
|
d572418ec3 | ||
|
|
8c7480d277 | ||
|
|
96fc70df26 | ||
|
|
1c8d4c902a | ||
|
|
08fc1d53d0 | ||
|
|
6c5d5e40f4 | ||
|
|
3f1dfe931c | ||
|
|
cb850c9653 | ||
|
|
8d8f47363a | ||
|
|
d399b7580d | ||
|
|
1b04b71254 | ||
|
|
0b19ad1427 | ||
|
|
9aca99911e | ||
|
|
a7f61e335e | ||
|
|
9fff0a513e | ||
|
|
f453be12c8 | ||
|
|
20428b0407 | ||
|
|
7fd5b77cbe | ||
|
|
d2cac50f93 | ||
|
|
00f1f82520 | ||
|
|
02fbb14e34 | ||
|
|
f961659ada | ||
|
|
93942111bc | ||
|
|
dc5a68acce | ||
|
|
12ff0f8c97 | ||
|
|
c375c281ee | ||
|
|
7d86b0f7c4 | ||
|
|
990f7dd06c | ||
|
|
0b6f256d55 | ||
|
|
694f80434a | ||
|
|
0a57fa4035 | ||
|
|
099967ae94 | ||
|
|
718bb1b852 | ||
|
|
af1a1a2498 | ||
|
|
cc0617d247 | ||
|
|
99a3f87cef | ||
|
|
1ccdb1bc4e | ||
|
|
62b1967e45 | ||
|
|
c10303e7c0 | ||
|
|
4a61584827 | ||
|
|
cf249ba836 | ||
|
|
08fe7b64d6 | ||
|
|
77939ea414 | ||
|
|
468394d03c | ||
|
|
dc87699a1e | ||
|
|
36e906507d | ||
|
|
a5f9688708 | ||
|
|
880f900e51 | ||
|
|
349306cf73 | ||
|
|
f140697857 | ||
|
|
3d9e9a1342 | ||
|
|
1a82406d2b | ||
|
|
26ff8df7e5 | ||
|
|
54b4b157b3 | ||
|
|
add7e89097 | ||
|
|
b7dae216df | ||
|
|
0b9d093d6c | ||
|
|
7f282ad071 | ||
|
|
d6ed583e07 | ||
|
|
930cab2d9d | ||
|
|
ae41f33dcc | ||
|
|
5af6b7cafe | ||
|
|
68ac3763d0 | ||
|
|
cdc66b556e | ||
|
|
3ff16322c2 | ||
|
|
d60066a0b1 | ||
|
|
9d6ebf0fd4 | ||
|
|
839815e2fb | ||
|
|
846fe479bf | ||
|
|
62f7070e0c | ||
|
|
dd418b36c2 | ||
|
|
f4f04f2199 | ||
|
|
3a7514bbdc | ||
|
|
213f07fed4 | ||
|
|
ed3ed8aa18 | ||
|
|
d038dca37c | ||
|
|
bb86d770a1 | ||
|
|
33daa8621e | ||
|
|
6c124fcff4 | ||
|
|
45833574b3 | ||
|
|
5cb00eb481 | ||
|
|
e2105331c1 | ||
|
|
21d2383e63 | ||
|
|
6c945a4eed | ||
|
|
6c8d34dfd3 | ||
|
|
b9b42c059e | ||
|
|
3f657b34cf | ||
|
|
6e81a36ada | ||
|
|
ddec01a429 | ||
|
|
21fdb3be7d | ||
|
|
c1a13ab6d0 | ||
|
|
750a02efc6 | ||
|
|
5e047debfc | ||
|
|
9cac336708 | ||
|
|
827c2b9a95 | ||
|
|
b36a3c4abb | ||
|
|
0bac205565 | ||
|
|
67a8ad8e12 | ||
|
|
9de2f66f50 | ||
|
|
9370030ff3 | ||
|
|
e38d6e7ef0 | ||
|
|
2f21fc3575 | ||
|
|
63e73f5f64 | ||
|
|
e1adc1ba49 | ||
|
|
030e911ea4 | ||
|
|
d2f114e44e | ||
|
|
700d3f84d3 | ||
|
|
1d49042013 | ||
|
|
8671b1e6cf | ||
|
|
517d6c44ec | ||
|
|
a082a659ea | ||
|
|
083153efc9 | ||
|
|
65a2560153 | ||
|
|
29535c10a3 | ||
|
|
24c7362163 | ||
|
|
f6ff7d7b16 | ||
|
|
b0a075cdf2 | ||
|
|
98d4d6b33c | ||
|
|
9ba3e0512b | ||
|
|
eff63175e5 | ||
|
|
75a0b632bc | ||
|
|
a2af626477 | ||
|
|
8aa97f64ef | ||
|
|
caa1e04b5a | ||
|
|
cddf6a0204 | ||
|
|
9fa1f42dc7 | ||
|
|
c7e709d487 | ||
|
|
6801398f3d | ||
|
|
982d14c049 | ||
|
|
ddbaf55ae7 | ||
|
|
5552a8501b | ||
|
|
b997becb2f | ||
|
|
753516bab7 | ||
|
|
89992d8636 |
@@ -1,42 +0,0 @@
|
||||
{{ if .Versions -}}
|
||||
<a name="unreleased"></a>
|
||||
## [Unreleased]
|
||||
|
||||
{{ if .Unreleased.CommitGroups -}}
|
||||
{{ range .Unreleased.CommitGroups -}}
|
||||
### {{ .Title }}
|
||||
{{ range .Commits -}}
|
||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
{{ range .Versions }}
|
||||
<a name="{{ .Tag.Name }}"></a>
|
||||
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
|
||||
{{ range .CommitGroups -}}
|
||||
### {{ .Title }}
|
||||
{{ range .Commits -}}
|
||||
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
|
||||
{{- if .NoteGroups -}}
|
||||
{{ range .NoteGroups -}}
|
||||
### {{ .Title }}
|
||||
{{ range .Notes }}
|
||||
{{ .Body }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
{{- if .Versions }}
|
||||
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
|
||||
{{ range .Versions -}}
|
||||
{{ if .Tag.Previous -}}
|
||||
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
@@ -1,27 +0,0 @@
|
||||
style: github
|
||||
template: CHANGELOG.tpl.md
|
||||
info:
|
||||
title: CHANGELOG
|
||||
repository_url: https://github.com/wailsapp/wails
|
||||
options:
|
||||
commits:
|
||||
# filters:
|
||||
# Type:
|
||||
# - feat
|
||||
# - fix
|
||||
# - perf
|
||||
# - refactor
|
||||
commit_groups:
|
||||
# title_maps:
|
||||
# feat: Features
|
||||
# fix: Bug Fixes
|
||||
# perf: Performance Improvements
|
||||
# refactor: Code Refactoring
|
||||
header:
|
||||
pattern: "^(\\w*)\\:\\s(.*)$"
|
||||
pattern_maps:
|
||||
- Type
|
||||
- Subject
|
||||
notes:
|
||||
keywords:
|
||||
- BREAKING CHANGE
|
||||
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@@ -0,0 +1 @@
|
||||
runtime/assets/default.html
|
||||
@@ -1,7 +1,8 @@
|
||||
module.exports = {
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
"es6": true,
|
||||
"node": true,
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
@@ -26,4 +27,4 @@ module.exports = {
|
||||
"always"
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
19
.github/stale.yml
vendored
Normal file
19
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 30
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
- onhold
|
||||
- inprogress
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: wontfix
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,4 +16,4 @@ examples/**/example*
|
||||
cmd/wails/wails
|
||||
.DS_Store
|
||||
tmp
|
||||
dist
|
||||
node_modules/
|
||||
6
.hound.yml
Normal file
6
.hound.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
jshint:
|
||||
config_file: .jshintrc
|
||||
eslint:
|
||||
enabled: true
|
||||
config_file: .eslintrc
|
||||
ignore_file: .eslintignore
|
||||
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -4,6 +4,13 @@
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Test cmd package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "test",
|
||||
"program": "${workspaceFolder}/cmd/"
|
||||
},
|
||||
{
|
||||
"name": "Wails Init",
|
||||
"type": "go",
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
|
||||
2019-07-20 **v0.17.6-pre**
|
||||
* Significant refactor of runtime
|
||||
* Removed wailsbridge file - now a unified approach taken
|
||||
* Fixed React on Windows - Thanks [Florian Didran](https://github.com/fdidron)!
|
||||
|
||||
2019-06-18 **v0.16.0**
|
||||
* React template FTW! - Thanks [admin_3.exe](https://github.com/bh90210)!
|
||||
* Updated contributors
|
||||
|
||||
@@ -2,14 +2,24 @@
|
||||
|
||||
Wails is what it is because of the time and effort given by these great people. A huge thank you to each and every one!
|
||||
|
||||
* [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot)
|
||||
* [Qais Patankar](https://github.com/qaisjp)
|
||||
* [Anthony Lee](https://github.com/alee792)
|
||||
* [Adrian Lanzafame](https://github.com/lanzafame)
|
||||
* [0xflotus](https://github.com/0xflotus)
|
||||
* [Michael D Henderson](https://github.com/mdhender)
|
||||
* [fred2104](https://github.com/fishfishfish2104)
|
||||
* [intelwalk](https://github.com/intelwalk)
|
||||
* [Mark Stenglein](https://github.com/ocelotsloth)
|
||||
* [admin_3.exe](https://github.com/bh90210)
|
||||
* [iceleo-com](https://github.com/iceleo-com)
|
||||
* [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot)
|
||||
* [Qais Patankar](https://github.com/qaisjp)
|
||||
* [Anthony Lee](https://github.com/alee792)
|
||||
* [Adrian Lanzafame](https://github.com/lanzafame)
|
||||
* [Mattn](https://github.com/mattn)
|
||||
* [0xflotus](https://github.com/0xflotus)
|
||||
* [Michael D Henderson](https://github.com/mdhender)
|
||||
* [fred2104](https://github.com/fishfishfish2104)
|
||||
* [intelwalk](https://github.com/intelwalk)
|
||||
* [Mark Stenglein](https://github.com/ocelotsloth)
|
||||
* [admin_3.exe](https://github.com/bh90210)
|
||||
* [iceleo-com](https://github.com/iceleo-com)
|
||||
* [fallendusk](https://github.com/fallendusk)
|
||||
* [Florian Didran](https://github.com/fdidron)
|
||||
* [Nikolai Zimmermann](https://github.com/Chronophylos)
|
||||
* [Toyam Cox](https://github.com/Vaelatern)
|
||||
* [Robin Eklind](https://github.com/mewmew)
|
||||
* [Kris Raney](https://github.com/kraney)
|
||||
* [Jack Mordaunt](https://github.com/JackMordaunt)
|
||||
* [Michael Hipp](https://github.com/MichaelHipp)
|
||||
* [Travis McLane](https://github.com/tmclane)
|
||||
50
README.md
50
README.md
@@ -1,5 +1,5 @@
|
||||
<p align="center" style="text-align: center">
|
||||
<img src="https://github.com/wailsapp/docs/raw/master/.vuepress/public/media/logo_cropped.png" width="40%"><br/>
|
||||
<img src="logo_cropped.png" width="40%"><br/>
|
||||
</p>
|
||||
<p align="center">
|
||||
A framework for building desktop applications using Go & Web Technologies.<br/><br/>
|
||||
@@ -8,13 +8,16 @@
|
||||
<a href="http://godoc.org/github.com/wailsapp/wails"><img src="https://img.shields.io/badge/godoc-reference-blue.svg"/></a>
|
||||
<a href="https://www.codefactor.io/repository/github/wailsapp/wails"><img src="https://www.codefactor.io/repository/github/wailsapp/wails/badge" alt="CodeFactor" /></a>
|
||||
<a href="https://github.com/wailsapp/wails/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat" alt="CodeFactor" /></a>
|
||||
<a href="https://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://github.com/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>
|
||||
<a href="https://dashboard.guardrails.io/default/gh/wailsapp/wails"><img src="https://badges.guardrails.io/wailsapp/wails.svg?token=53657bc22ec360d7673c894fdd70568e918ec581d10d84427ed4de5fe1eeff1a"></a>
|
||||
<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>
|
||||
</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 official docs can be found at [https://wails.app](https://wails.app).
|
||||
|
||||
## Features
|
||||
|
||||
- Use standard Go libraries/frameworks for the backend
|
||||
@@ -27,9 +30,6 @@ The traditional method of providing web interfaces to Go programs is via a built
|
||||
- Powerful cli tool
|
||||
- Multiplatform
|
||||
|
||||
## Project Status
|
||||
|
||||
Wails is currently in Beta. Please make sure you read the [Project Status](https://wails.app/project_status.html) if you are interested in using this project.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -46,19 +46,41 @@ Make sure you have the xcode command line tools installed. This can be done by r
|
||||
|
||||
### Linux
|
||||
|
||||
#### Ubuntu 18.04, Debian 9
|
||||
#### Debian/Ubuntu
|
||||
|
||||
`sudo apt install pkg-config build-essential libgtk-3-dev libwebkit2gtk-4.0-dev`
|
||||
`sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev`
|
||||
|
||||
_Debian: 8, 9, 10_
|
||||
|
||||
_Ubuntu: 16.04, 18.04, 19.04_
|
||||
|
||||
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
`sudo pacman -S webkit2gtk gtk3`
|
||||
|
||||
#### Red Hat Based Distros
|
||||
_Also succesfully test on: Manjaro & ArcoLinux_
|
||||
|
||||
`sudo yum install webkit2gtk-devel gtk3-devel`
|
||||
#### Centos
|
||||
|
||||
Note: If you have successfully installed these dependencies on a different flavour of Linux, please consider submitting a PR.
|
||||
`sudo yum install webkitgtk3-devel gtk3-devel`
|
||||
|
||||
_CentOS 6, 7_
|
||||
|
||||
#### Fedora
|
||||
|
||||
`sudo yum install webkit2gtk3-devel gtk3-devel`
|
||||
|
||||
_Fedora 29, 30_
|
||||
|
||||
#### VoidLinux & VoidLinux-musl
|
||||
|
||||
`xbps-install gtk+3-devel webkit2gtk-devel`
|
||||
|
||||
#### Gentoo
|
||||
|
||||
`sudo emerge gtk+:3 webkit-gtk`
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -71,7 +93,7 @@ Windows requires gcc and related tooling. The recommended download is from [http
|
||||
Installation is as simple as running the following command:
|
||||
|
||||
<pre style='color:white'>
|
||||
go get github.com/wailsapp/wails/cmd/wails
|
||||
go get -u github.com/wailsapp/wails/cmd/wails
|
||||
</pre>
|
||||
|
||||
## Next Steps
|
||||
@@ -103,8 +125,7 @@ And without [these people](CONTRIBUTORS.md), it wouldn't be what it is today. A
|
||||
|
||||
Special Mentions:
|
||||
|
||||
* [Bill Kennedy](https://twitter.com/goinggodotnet) - Go guru, encourager and all-round nice guy, whose infectious energy and inspiration powered me on when I had none left.
|
||||
* [Mark Bates](https://github.com/markbates) - Creator of [Packr](https://github.com/gobuffalo/packr), inspiration for packing strategies which fed into some of the tooling.
|
||||
* [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.
|
||||
|
||||
This project was mainly coded to the following albums:
|
||||
|
||||
@@ -122,3 +143,6 @@ This project was mainly coded to the following albums:
|
||||
* [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF)
|
||||
* [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v)
|
||||
|
||||
## Licensing
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
|
||||
|
||||
102
app.go
102
app.go
@@ -1,7 +1,18 @@
|
||||
package wails
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/syossan27/tebata"
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
"github.com/wailsapp/wails/lib/binding"
|
||||
"github.com/wailsapp/wails/lib/event"
|
||||
"github.com/wailsapp/wails/lib/interfaces"
|
||||
"github.com/wailsapp/wails/lib/ipc"
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
"github.com/wailsapp/wails/lib/renderer"
|
||||
)
|
||||
|
||||
// -------------------------------- Compile time Flags ------------------------------
|
||||
@@ -13,15 +24,15 @@ var BuildMode = cmd.BuildModeProd
|
||||
|
||||
// App defines the main application struct
|
||||
type App struct {
|
||||
config *AppConfig // The Application configuration object
|
||||
cli *cmd.Cli // In debug mode, we have a cli
|
||||
renderer Renderer // The renderer is what we will render the app to
|
||||
logLevel string // The log level of the app
|
||||
ipc *ipcManager // Handles the IPC calls
|
||||
log *CustomLogger // Logger
|
||||
bindingManager *bindingManager // Handles binding of Go code to renderer
|
||||
eventManager *eventManager // Handles all the events
|
||||
runtime *Runtime // The runtime object for registered structs
|
||||
config *AppConfig // The Application configuration object
|
||||
cli *cmd.Cli // In debug mode, we have a cli
|
||||
renderer interfaces.Renderer // The renderer is what we will render the app to
|
||||
logLevel string // The log level of the app
|
||||
ipc interfaces.IPCManager // Handles the IPC calls
|
||||
log *logger.CustomLogger // Logger
|
||||
bindingManager interfaces.BindingManager // Handles binding of Go code to renderer
|
||||
eventManager interfaces.EventManager // Handles all the events
|
||||
runtime interfaces.Runtime // The runtime object for registered structs
|
||||
}
|
||||
|
||||
// CreateApp creates the application window with the given configuration
|
||||
@@ -33,15 +44,15 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
|
||||
}
|
||||
|
||||
result := &App{
|
||||
logLevel: "info",
|
||||
renderer: &webViewRenderer{},
|
||||
ipc: newIPCManager(),
|
||||
bindingManager: newBindingManager(),
|
||||
eventManager: newEventManager(),
|
||||
log: newCustomLogger("App"),
|
||||
logLevel: "debug",
|
||||
renderer: renderer.NewWebView(),
|
||||
ipc: ipc.NewManager(),
|
||||
bindingManager: binding.NewManager(),
|
||||
eventManager: event.NewManager(),
|
||||
log: logger.NewCustomLogger("App"),
|
||||
}
|
||||
|
||||
appconfig, err := newAppConfig(userConfig)
|
||||
appconfig, err := newConfig(userConfig)
|
||||
if err != nil {
|
||||
result.log.Fatalf("Cannot use custom HTML: %s", err.Error())
|
||||
}
|
||||
@@ -55,11 +66,15 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
|
||||
result.config.DisableInspector = true
|
||||
}
|
||||
|
||||
// Platform specific init
|
||||
platformInit()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Run the app
|
||||
func (a *App) Run() error {
|
||||
|
||||
if BuildMode != cmd.BuildModeProd {
|
||||
return a.cli.Run()
|
||||
}
|
||||
@@ -75,14 +90,14 @@ func (a *App) Run() error {
|
||||
func (a *App) start() error {
|
||||
|
||||
// Set the log level
|
||||
setLogLevel(a.logLevel)
|
||||
logger.SetLogLevel(a.logLevel)
|
||||
|
||||
// Log starup
|
||||
a.log.Info("Starting")
|
||||
|
||||
// Check if we are to run in headless mode
|
||||
// Check if we are to run in bridge mode
|
||||
if BuildMode == cmd.BuildModeBridge {
|
||||
a.renderer = &Headless{}
|
||||
a.renderer = &renderer.Bridge{}
|
||||
}
|
||||
|
||||
// Initialise the renderer
|
||||
@@ -91,27 +106,64 @@ func (a *App) start() error {
|
||||
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
|
||||
a.eventManager.start(a.renderer)
|
||||
a.eventManager.Start(a.renderer)
|
||||
|
||||
// Start the IPC Manager and give it the event manager and binding manager
|
||||
a.ipc.start(a.eventManager, a.bindingManager)
|
||||
a.ipc.Start(a.eventManager, a.bindingManager)
|
||||
|
||||
// Create the runtime
|
||||
a.runtime = newRuntime(a.eventManager, a.renderer)
|
||||
a.runtime = NewRuntime(a.eventManager, a.renderer)
|
||||
|
||||
// Start binding manager and give it our renderer
|
||||
err = a.bindingManager.start(a.renderer, a.runtime)
|
||||
err = a.bindingManager.Start(a.renderer, a.runtime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Defer the shutdown
|
||||
defer a.shutdown()
|
||||
|
||||
// Run the renderer
|
||||
return a.renderer.Run()
|
||||
err = 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
|
||||
// with the application
|
||||
func (a *App) Bind(object interface{}) {
|
||||
a.bindingManager.bind(object)
|
||||
a.bindingManager.Bind(object)
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
package wails
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/dchest/htmlmin"
|
||||
"github.com/leaanthony/mewn"
|
||||
)
|
||||
|
||||
// AppConfig is the configuration structure used when creating a Wails App object
|
||||
type AppConfig struct {
|
||||
Width, Height int
|
||||
Title string
|
||||
defaultHTML string
|
||||
HTML string
|
||||
JS string
|
||||
CSS string
|
||||
Colour string
|
||||
Resizable bool
|
||||
DisableInspector bool
|
||||
isHTMLFragment bool
|
||||
}
|
||||
|
||||
func (a *AppConfig) merge(in *AppConfig) error {
|
||||
if in.CSS != "" {
|
||||
a.CSS = in.CSS
|
||||
}
|
||||
if in.Title != "" {
|
||||
a.Title = in.Title
|
||||
}
|
||||
if in.HTML != "" {
|
||||
minified, err := htmlmin.Minify([]byte(in.HTML), &htmlmin.Options{
|
||||
MinifyScripts: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
inlineHTML := string(minified)
|
||||
inlineHTML = strings.Replace(inlineHTML, "'", "\\'", -1)
|
||||
inlineHTML = strings.Replace(inlineHTML, "\n", " ", -1)
|
||||
a.HTML = strings.TrimSpace(inlineHTML)
|
||||
|
||||
// Deduce whether this is a full html page or a fragment
|
||||
// The document is determined to be a fragment if an HTML
|
||||
// tag exists and is located before the first div tag
|
||||
HTMLTagIndex := strings.Index(a.HTML, "<html")
|
||||
DivTagIndex := strings.Index(a.HTML, "<div")
|
||||
|
||||
if HTMLTagIndex == -1 {
|
||||
a.isHTMLFragment = true
|
||||
} else {
|
||||
if DivTagIndex < HTMLTagIndex {
|
||||
a.isHTMLFragment = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if in.Colour != "" {
|
||||
a.Colour = in.Colour
|
||||
}
|
||||
|
||||
if in.JS != "" {
|
||||
a.JS = in.JS
|
||||
}
|
||||
|
||||
if in.Width != 0 {
|
||||
a.Width = in.Width
|
||||
}
|
||||
if in.Height != 0 {
|
||||
a.Height = in.Height
|
||||
}
|
||||
a.Resizable = in.Resizable
|
||||
a.DisableInspector = in.DisableInspector
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates the default configuration
|
||||
func newAppConfig(userConfig *AppConfig) (*AppConfig, error) {
|
||||
result := &AppConfig{
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
Resizable: true,
|
||||
Title: "My Wails App",
|
||||
Colour: "#FFF", // White by default
|
||||
HTML: mewn.String("./wailsruntimeassets/default/default.html"),
|
||||
}
|
||||
|
||||
if userConfig != nil {
|
||||
err := result.merge(userConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
7
app_other.go
Normal file
7
app_other.go
Normal file
@@ -0,0 +1,7 @@
|
||||
// +build +linux +darwin !windows
|
||||
|
||||
package wails
|
||||
|
||||
func platformInit() {
|
||||
|
||||
}
|
||||
27
app_windows.go
Normal file
27
app_windows.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// +build windows !linux !darwin
|
||||
|
||||
package wails
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func platformInit() {
|
||||
err := SetProcessDPIAware()
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// SetProcessDPIAware via user32.dll
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiaware
|
||||
// Also, thanks Jack Mordaunt! https://github.com/wailsapp/wails/issues/293
|
||||
func SetProcessDPIAware() error {
|
||||
status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
||||
if status == 0 {
|
||||
return fmt.Errorf("exit status %d: %v %v", status, r, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
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'
|
||||
@@ -11,10 +11,9 @@ func (app *App) setupCli() *cmd.Cli {
|
||||
result := cmd.NewCli(app.config.Title, "Debug build")
|
||||
result.Version(cmd.Version)
|
||||
|
||||
// Setup cli to handle loglevel and headless flags
|
||||
// Setup cli to handle loglevel
|
||||
result.
|
||||
StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel).
|
||||
// BoolFlag("headless", "Runs the app in headless mode", &app.headless).
|
||||
Action(app.start)
|
||||
|
||||
// Banner
|
||||
File diff suppressed because one or more lines are too long
@@ -18,7 +18,7 @@ func NewGitHubHelper() *GitHubHelper {
|
||||
}
|
||||
|
||||
// GetVersionTags gets the list of tags on the Wails repo
|
||||
// It retuns a list of sorted tags in descending order
|
||||
// It returns a list of sorted tags in descending order
|
||||
func (g *GitHubHelper) GetVersionTags() ([]*SemanticVersion, error) {
|
||||
|
||||
result := []*SemanticVersion{}
|
||||
|
||||
@@ -7,9 +7,10 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mewn "github.com/leaanthony/mewn"
|
||||
"github.com/leaanthony/mewn"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/leaanthony/spinner"
|
||||
)
|
||||
@@ -87,6 +88,17 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
||||
buildCommand.Add("build")
|
||||
|
||||
if binaryName != "" {
|
||||
// Alter binary name based on OS
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
if !strings.HasSuffix(binaryName, ".exe") {
|
||||
binaryName += ".exe"
|
||||
}
|
||||
default:
|
||||
if strings.HasSuffix(binaryName, ".exe") {
|
||||
binaryName = strings.TrimSuffix(binaryName, ".exe")
|
||||
}
|
||||
}
|
||||
buildCommand.Add("-o")
|
||||
buildCommand.Add(binaryName)
|
||||
}
|
||||
@@ -103,7 +115,7 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
|
||||
}
|
||||
|
||||
// Add windows flags
|
||||
if runtime.GOOS == "windows" {
|
||||
if runtime.GOOS == "windows" && buildMode == BuildModeProd {
|
||||
ldflags += "-H windowsgui "
|
||||
}
|
||||
|
||||
@@ -219,6 +231,15 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
||||
|
||||
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 !forceRebuild && fs.FileExists(md5sumFile) {
|
||||
// Yes - read contents
|
||||
@@ -249,8 +270,8 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
||||
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
||||
}
|
||||
|
||||
// Install the bridge library
|
||||
err = InstallBridge(caller, projectDir, projectOptions)
|
||||
// Install the runtime
|
||||
err = InstallRuntime(caller, projectDir, projectOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -263,22 +284,29 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstallBridge installs the relevant bridge javascript library
|
||||
func InstallBridge(caller string, projectDir string, projectOptions *ProjectOptions) error {
|
||||
bridgeFile := "wailsbridge.prod.js"
|
||||
if caller == "serve" {
|
||||
bridgeFile = "wailsbridge.js"
|
||||
// InstallRuntime installs the correct runtime for the type of build
|
||||
func InstallRuntime(caller string, projectDir string, projectOptions *ProjectOptions) error {
|
||||
if caller == "build" {
|
||||
return InstallProdRuntime(projectDir, projectOptions)
|
||||
}
|
||||
|
||||
// Copy bridge to project
|
||||
bridgeAssets := mewn.Group("../wailsruntimeassets/bridge/")
|
||||
bridgeFileData := bridgeAssets.Bytes(bridgeFile)
|
||||
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js")
|
||||
err := fs.CreateFile(bridgeFileTarget, bridgeFileData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return InstallBridge(projectDir, projectOptions)
|
||||
}
|
||||
|
||||
// InstallBridge installs the relevant bridge javascript library
|
||||
func InstallBridge(projectDir string, projectOptions *ProjectOptions) error {
|
||||
bridgeFileData := mewn.String("../runtime/assets/bridge.js")
|
||||
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "init.js")
|
||||
err := fs.CreateFile(bridgeFileTarget, []byte(bridgeFileData))
|
||||
return err
|
||||
}
|
||||
|
||||
// InstallProdRuntime installs the production runtime
|
||||
func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error {
|
||||
prodInit := mewn.String("../runtime/js/runtime/init.js")
|
||||
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "init.js")
|
||||
err := fs.CreateFile(bridgeFileTarget, []byte(prodInit))
|
||||
return err
|
||||
}
|
||||
|
||||
// ServeProject attempts to serve up the current project so that it may be connected to
|
||||
|
||||
240
cmd/linux.go
240
cmd/linux.go
@@ -17,110 +17,148 @@ type LinuxDistribution int
|
||||
const (
|
||||
// Unknown is the catch-all distro
|
||||
Unknown LinuxDistribution = iota
|
||||
// Debian distribution
|
||||
Debian
|
||||
// Ubuntu distribution
|
||||
Ubuntu
|
||||
// Arch linux distribution
|
||||
Arch
|
||||
// RedHat linux distribution
|
||||
RedHat
|
||||
// Debian distribution
|
||||
Debian
|
||||
// CentOS linux distribution
|
||||
CentOS
|
||||
// Fedora linux distribution
|
||||
Fedora
|
||||
// Gentoo distribution
|
||||
Gentoo
|
||||
// Zorin distribution
|
||||
Zorin
|
||||
// Parrot distribution
|
||||
Parrot
|
||||
// Linuxmint distribution
|
||||
Linuxmint
|
||||
// VoidLinux distribution
|
||||
VoidLinux
|
||||
// Elementary distribution
|
||||
Elementary
|
||||
// Kali distribution
|
||||
Kali
|
||||
// Neon distribution
|
||||
Neon
|
||||
// ArcoLinux distribution
|
||||
ArcoLinux
|
||||
// Manjaro distribution
|
||||
Manjaro
|
||||
)
|
||||
|
||||
// DistroInfo contains all the information relating to a linux distribution
|
||||
type DistroInfo struct {
|
||||
Distribution LinuxDistribution
|
||||
Description string
|
||||
Release string
|
||||
Codename string
|
||||
DistributorID string
|
||||
DiscoveredBy string
|
||||
Distribution LinuxDistribution
|
||||
Name string
|
||||
ID string
|
||||
Description string
|
||||
Release string
|
||||
}
|
||||
|
||||
// GetLinuxDistroInfo returns information about the running linux distribution
|
||||
func GetLinuxDistroInfo() *DistroInfo {
|
||||
result := &DistroInfo{Distribution: Unknown}
|
||||
program := NewProgramHelper()
|
||||
// Does lsb_release exist?
|
||||
|
||||
lsbRelease := program.FindProgram("lsb_release")
|
||||
if lsbRelease != nil {
|
||||
stdout, _, _, err := lsbRelease.Run("-a")
|
||||
if err != nil {
|
||||
return result
|
||||
}
|
||||
result.DiscoveredBy = "lsb"
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
if strings.Contains(line, ":") {
|
||||
// Iterate lines a
|
||||
details := strings.Split(line, ":")
|
||||
key := strings.TrimSpace(details[0])
|
||||
value := strings.TrimSpace(details[1])
|
||||
switch key {
|
||||
case "Distributor ID":
|
||||
result.DistributorID = value
|
||||
switch value {
|
||||
case "Ubuntu":
|
||||
result.Distribution = Ubuntu
|
||||
case "Arch", "ManjaroLinux":
|
||||
result.Distribution = Arch
|
||||
case "Debian":
|
||||
result.Distribution = Debian
|
||||
}
|
||||
case "Description":
|
||||
result.Description = value
|
||||
case "Release":
|
||||
result.Release = value
|
||||
case "Codename":
|
||||
result.Codename = value
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if /etc/os-release exists
|
||||
} else if _, err := os.Stat("/etc/os-release"); !os.IsNotExist(err) {
|
||||
// Default value
|
||||
osName := "Unknown"
|
||||
version := ""
|
||||
// read /etc/os-release
|
||||
result := &DistroInfo{
|
||||
Distribution: Unknown,
|
||||
ID: "unknown",
|
||||
Name: "Unknown",
|
||||
}
|
||||
_, err := os.Stat("/etc/os-release")
|
||||
if !os.IsNotExist(err) {
|
||||
osRelease, _ := ioutil.ReadFile("/etc/os-release")
|
||||
// Split into lines
|
||||
lines := strings.Split(string(osRelease), "\n")
|
||||
// Iterate lines
|
||||
for _, line := range lines {
|
||||
// Split each line by the equals char
|
||||
splitLine := strings.SplitN(line, "=", 2)
|
||||
// Check we have
|
||||
if len(splitLine) != 2 {
|
||||
continue
|
||||
}
|
||||
switch splitLine[0] {
|
||||
case "NAME":
|
||||
osName = strings.Trim(splitLine[1], "\"")
|
||||
case "VERSION_ID":
|
||||
version = strings.Trim(splitLine[1], "\"")
|
||||
}
|
||||
|
||||
}
|
||||
// Check distro name against list of distros
|
||||
result.Release = version
|
||||
result.DiscoveredBy = "os-release"
|
||||
switch osName {
|
||||
case "Fedora":
|
||||
result.Distribution = RedHat
|
||||
case "CentOS":
|
||||
result.Distribution = RedHat
|
||||
case "Arch Linux":
|
||||
result.Distribution = Arch
|
||||
case "Debian GNU/Linux":
|
||||
result.Distribution = Debian
|
||||
default:
|
||||
result.Distribution = Unknown
|
||||
result.DistributorID = osName
|
||||
}
|
||||
result = parseOsRelease(string(osRelease))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// parseOsRelease parses the given os-release data and returns
|
||||
// a DistroInfo struct with the details
|
||||
func parseOsRelease(osRelease string) *DistroInfo {
|
||||
result := &DistroInfo{Distribution: Unknown}
|
||||
|
||||
// Default value
|
||||
osID := "unknown"
|
||||
osNAME := "Unknown"
|
||||
version := ""
|
||||
|
||||
// Split into lines
|
||||
lines := strings.Split(osRelease, "\n")
|
||||
// Iterate lines
|
||||
for _, line := range lines {
|
||||
// Split each line by the equals char
|
||||
splitLine := strings.SplitN(line, "=", 2)
|
||||
// Check we have
|
||||
if len(splitLine) != 2 {
|
||||
continue
|
||||
}
|
||||
switch splitLine[0] {
|
||||
case "ID":
|
||||
osID = strings.Trim(splitLine[1], "\"")
|
||||
case "NAME":
|
||||
osNAME = strings.Trim(splitLine[1], "\"")
|
||||
case "VERSION_ID":
|
||||
version = strings.Trim(splitLine[1], "\"")
|
||||
}
|
||||
}
|
||||
// Check distro name against list of distros
|
||||
switch osID {
|
||||
case "fedora":
|
||||
result.Distribution = Fedora
|
||||
case "centos":
|
||||
result.Distribution = CentOS
|
||||
case "arch":
|
||||
result.Distribution = Arch
|
||||
case "debian":
|
||||
result.Distribution = Debian
|
||||
case "ubuntu":
|
||||
result.Distribution = Ubuntu
|
||||
case "gentoo":
|
||||
result.Distribution = Gentoo
|
||||
case "zorin":
|
||||
result.Distribution = Zorin
|
||||
case "parrot":
|
||||
result.Distribution = Parrot
|
||||
case "linuxmint":
|
||||
result.Distribution = Linuxmint
|
||||
case "void":
|
||||
result.Distribution = VoidLinux
|
||||
case "elementary":
|
||||
result.Distribution = Elementary
|
||||
case "kali":
|
||||
result.Distribution = Kali
|
||||
case "neon":
|
||||
result.Distribution = Neon
|
||||
case "arcolinux":
|
||||
result.Distribution = ArcoLinux
|
||||
case "manjaro":
|
||||
result.Distribution = Manjaro
|
||||
default:
|
||||
result.Distribution = Unknown
|
||||
}
|
||||
|
||||
result.Name = osNAME
|
||||
result.ID = osID
|
||||
result.Release = version
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// CheckPkgInstalled is all functions that use local programs to see if a package is installed
|
||||
type CheckPkgInstalled func(string) (bool, error)
|
||||
|
||||
// EqueryInstalled uses equery to see if a package is installed
|
||||
func EqueryInstalled(packageName string) (bool, error) {
|
||||
program := NewProgramHelper()
|
||||
equery := program.FindProgram("equery")
|
||||
if equery == nil {
|
||||
return false, fmt.Errorf("cannont check dependencies: equery not found")
|
||||
}
|
||||
_, _, exitCode, _ := equery.Run("l", packageName)
|
||||
return exitCode == 0, nil
|
||||
}
|
||||
|
||||
// DpkgInstalled uses dpkg to see if a package is installed
|
||||
func DpkgInstalled(packageName string) (bool, error) {
|
||||
program := NewProgramHelper()
|
||||
@@ -143,6 +181,17 @@ func PacmanInstalled(packageName string) (bool, error) {
|
||||
return exitCode == 0, nil
|
||||
}
|
||||
|
||||
// XbpsInstalled uses pacman to see if a package is installed.
|
||||
func XbpsInstalled(packageName string) (bool, error) {
|
||||
program := NewProgramHelper()
|
||||
xbpsQuery := program.FindProgram("xbps-query")
|
||||
if xbpsQuery == nil {
|
||||
return false, fmt.Errorf("cannot check dependencies: xbps-query not found")
|
||||
}
|
||||
_, _, exitCode, _ := xbpsQuery.Run("-S", packageName)
|
||||
return exitCode == 0, nil
|
||||
}
|
||||
|
||||
// RpmInstalled uses rpm to see if a package is installed
|
||||
func RpmInstalled(packageName string) (bool, error) {
|
||||
program := NewProgramHelper()
|
||||
@@ -156,18 +205,18 @@ func RpmInstalled(packageName string) (bool, error) {
|
||||
|
||||
// RequestSupportForDistribution promts the user to submit a request to support their
|
||||
// currently unsupported distribution
|
||||
func RequestSupportForDistribution(distroInfo *DistroInfo, libraryName string) error {
|
||||
func RequestSupportForDistribution(distroInfo *DistroInfo) error {
|
||||
var logger = NewLogger()
|
||||
defaultError := fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, libraryName)
|
||||
defaultError := fmt.Errorf("unable to check libraries on distribution '%s'", distroInfo.Name)
|
||||
|
||||
logger.Yellow("Distribution '%s' is not currently supported, but we would love to!", distroInfo.DistributorID)
|
||||
q := fmt.Sprintf("Would you like to submit a request to support distribution '%s'?", distroInfo.DistributorID)
|
||||
logger.Yellow("Distribution '%s' is not currently supported, but we would love to!", distroInfo.Name)
|
||||
q := fmt.Sprintf("Would you like to submit a request to support distribution '%s'?", distroInfo.Name)
|
||||
result := Prompt(q, "yes")
|
||||
if strings.ToLower(result) != "yes" {
|
||||
return defaultError
|
||||
}
|
||||
|
||||
title := fmt.Sprintf("Support Distribution '%s'", distroInfo.DistributorID)
|
||||
title := fmt.Sprintf("Support Distribution '%s'", distroInfo.Name)
|
||||
|
||||
var str strings.Builder
|
||||
|
||||
@@ -182,16 +231,15 @@ func RequestSupportForDistribution(distroInfo *DistroInfo, libraryName string) e
|
||||
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
|
||||
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
|
||||
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
|
||||
str.WriteString(fmt.Sprintf("| Distribution ID | %s |\n", distroInfo.DistributorID))
|
||||
str.WriteString(fmt.Sprintf("| Distribution ID | %s |\n", distroInfo.ID))
|
||||
str.WriteString(fmt.Sprintf("| Distribution Name | %s |\n", distroInfo.Name))
|
||||
str.WriteString(fmt.Sprintf("| Distribution Version | %s |\n", distroInfo.Release))
|
||||
str.WriteString(fmt.Sprintf("| Discovered by | %s |\n", distroInfo.DiscoveredBy))
|
||||
|
||||
body := fmt.Sprintf("**Description**\nDistribution '%s' is currently unsupported.\n\n**Further Information**\n\n%s\n\n*Please add any extra information here, EG: libraries that are needed to make the distribution work, or commands to install them*", distroInfo.DistributorID, str.String())
|
||||
body := fmt.Sprintf("**Description**\nDistribution '%s' is currently unsupported.\n\n**Further Information**\n\n%s\n\n*Please add any extra information here, EG: libraries that are needed to make the distribution work, or commands to install them*", distroInfo.ID, str.String())
|
||||
fullURL := "https://github.com/wailsapp/wails/issues/new?"
|
||||
params := "title=" + title + "&body=" + body
|
||||
|
||||
fmt.Println("Opening browser to file request.")
|
||||
browser.OpenURL(fullURL + url.PathEscape(params))
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
26
cmd/linux_test.go
Normal file
26
cmd/linux_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package cmd
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestUbuntuDetection(t *testing.T) {
|
||||
osrelease := `
|
||||
NAME="Ubuntu"
|
||||
VERSION="18.04.2 LTS (Bionic Beaver)"
|
||||
ID=ubuntu
|
||||
ID_LIKE=debian
|
||||
PRETTY_NAME="Ubuntu 18.04.2 LTS"
|
||||
VERSION_ID="18.04"
|
||||
HOME_URL="https://www.ubuntu.com/"
|
||||
SUPPORT_URL="https://help.ubuntu.com/"
|
||||
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
|
||||
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
|
||||
VERSION_CODENAME=bionic
|
||||
UBUNTU_CODENAME=bionic
|
||||
`
|
||||
|
||||
result := parseOsRelease(osrelease)
|
||||
if result.Distribution != Ubuntu {
|
||||
t.Errorf("expected 'Ubuntu' ID but got '%d'", result.Distribution)
|
||||
}
|
||||
|
||||
}
|
||||
91
cmd/linuxdb.go
Normal file
91
cmd/linuxdb.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/leaanthony/mewn"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// LinuxDB is the database for linux distribution data.
|
||||
type LinuxDB struct {
|
||||
Distributions map[string]*Distribution `yaml:"distributions"`
|
||||
}
|
||||
|
||||
// Distribution holds the os-release ID and a map of releases.
|
||||
type Distribution struct {
|
||||
ID string `yaml:"id"`
|
||||
Releases map[string]*Release `yaml:"releases"`
|
||||
}
|
||||
|
||||
// GetRelease attempts to return the specific Release information
|
||||
// for the given release name. If there is no specific match, the
|
||||
// default release data is returned.
|
||||
func (d *Distribution) GetRelease(version string) *Release {
|
||||
result := d.Releases[version]
|
||||
if result == nil {
|
||||
result = d.Releases["default"]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Release holds the name and version of the release as given by
|
||||
// os-release. Programs is a slice of dependant programs required
|
||||
// to be present on the local installation for Wails to function.
|
||||
// Libraries is a slice of libraries that must be present for Wails
|
||||
// applications to compile.
|
||||
type Release struct {
|
||||
Name string `yaml:"name"`
|
||||
Version string `yaml:"version"`
|
||||
GccVersionCommand string `yaml:"gccversioncommand"`
|
||||
Programs []*Prerequisite `yaml:"programs"`
|
||||
Libraries []*Prerequisite `yaml:"libraries"`
|
||||
}
|
||||
|
||||
// Prerequisite is a simple struct containing a program/library name
|
||||
// plus the distribution specific help text indicating how to install
|
||||
// it.
|
||||
type Prerequisite struct {
|
||||
Name string `yaml:"name"`
|
||||
Help string `yaml:"help,omitempty"`
|
||||
}
|
||||
|
||||
// Load will load the given filename from disk and attempt to
|
||||
// import the data into the LinuxDB.
|
||||
func (l *LinuxDB) Load(filename string) error {
|
||||
if fs.FileExists(filename) {
|
||||
data, err := fs.LoadAsBytes(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return l.ImportData(data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ImportData will unmarshal the given YAML formatted data
|
||||
// into the LinuxDB
|
||||
func (l *LinuxDB) ImportData(data []byte) error {
|
||||
return yaml.Unmarshal(data, l)
|
||||
}
|
||||
|
||||
// GetDistro returns the Distribution information for the
|
||||
// given distribution name. If the distribution is not supported,
|
||||
// nil is returned.
|
||||
func (l *LinuxDB) GetDistro(distro string) *Distribution {
|
||||
return l.Distributions[distro]
|
||||
}
|
||||
|
||||
// NewLinuxDB creates a new LinuxDB instance from the bundled
|
||||
// linuxdb.yaml file.
|
||||
func NewLinuxDB() *LinuxDB {
|
||||
data := mewn.Bytes("./linuxdb.yaml")
|
||||
result := LinuxDB{
|
||||
Distributions: make(map[string]*Distribution),
|
||||
}
|
||||
err := result.ImportData(data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return &result
|
||||
}
|
||||
197
cmd/linuxdb.yaml
Normal file
197
cmd/linuxdb.yaml
Normal file
@@ -0,0 +1,197 @@
|
||||
---
|
||||
distributions:
|
||||
debian:
|
||||
id: debian
|
||||
releases:
|
||||
default:
|
||||
name: Debian
|
||||
version: default
|
||||
gccversioncommand: &gccdumpversion -dumpversion
|
||||
programs: &debiandefaultprograms
|
||||
- name: gcc
|
||||
help: Please install with `sudo apt-get install build-essential` and try again
|
||||
- name: pkg-config
|
||||
help: Please install with `sudo apt-get install pkg-config` and try again
|
||||
- name: npm
|
||||
help: Please install with `curl -sL https://deb.nodesource.com/setup_12.x | sudo bash - && sudo apt-get install -y nodejs` and try again
|
||||
libraries: &debiandefaultlibraries
|
||||
- name: libgtk-3-dev
|
||||
help: Please install with `sudo apt-get install libgtk-3-dev` and try again
|
||||
- name: libwebkit2gtk-4.0-dev
|
||||
help: Please install with `sudo apt-get install libwebkit2gtk-4.0-dev` and try again
|
||||
ubuntu:
|
||||
id: ubuntu
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Ubuntu
|
||||
gccversioncommand: &gccdumpfullversion -dumpfullversion
|
||||
programs: *debiandefaultprograms
|
||||
libraries: *debiandefaultlibraries
|
||||
kali:
|
||||
id: kali
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Kali GNU/Linux
|
||||
gccversioncommand: *gccdumpfullversion
|
||||
programs: *debiandefaultprograms
|
||||
libraries: *debiandefaultlibraries
|
||||
parrot:
|
||||
id: parrot
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Parrot GNU/Linux
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs: *debiandefaultprograms
|
||||
libraries: *debiandefaultlibraries
|
||||
zorin:
|
||||
id: zorin
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Zorin
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs: *debiandefaultprograms
|
||||
libraries: *debiandefaultlibraries
|
||||
linuxmint:
|
||||
id: linuxmint
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Linux Mint
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs: *debiandefaultprograms
|
||||
libraries: *debiandefaultlibraries
|
||||
elementary:
|
||||
id: elementary
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: elementary OS
|
||||
gccversioncommand: *gccdumpfullversion
|
||||
programs: *debiandefaultprograms
|
||||
libraries: *debiandefaultlibraries
|
||||
neon:
|
||||
id: neon
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: KDE neon
|
||||
gccversioncommand: *gccdumpfullversion
|
||||
programs: *debiandefaultprograms
|
||||
libraries: *debiandefaultlibraries
|
||||
void:
|
||||
id: void
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: VoidLinux
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs:
|
||||
- name: gcc
|
||||
help: Please install with `xbps-install base-devel` and try again
|
||||
- name: pkg-config
|
||||
help: Please install with `xbps-install pkg-config` and try again
|
||||
- name: npm
|
||||
help: Please install with `xbps-install nodejs` and try again
|
||||
libraries:
|
||||
- name: gtk+3-devel
|
||||
help: Please install with `xbps-install gtk+3-devel` and try again
|
||||
- name: webkit2gtk-devel
|
||||
help: Please install with `xbps-install webkit2gtk-devel` and try again
|
||||
centos:
|
||||
id: centos
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: CentOS Linux
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs:
|
||||
- name: gcc
|
||||
help: Please install with `sudo yum install gcc-c++ make` and try again
|
||||
- name: pkg-config
|
||||
help: Please install with `sudo yum install pkgconf-pkg-config` and try again
|
||||
- name: npm
|
||||
help: Please install with `sudo yum install epel-release && sudo yum install nodejs` and try again
|
||||
libraries:
|
||||
- name: gtk3-devel
|
||||
help: Please install with `sudo yum install gtk3-devel` and try again
|
||||
- name: webkitgtk3-devel
|
||||
help: Please install with `sudo yum install webkitgtk3-devel` and try again
|
||||
fedora:
|
||||
id: fedora
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Fedora
|
||||
gccversioncommand: *gccdumpfullversion
|
||||
programs:
|
||||
- name: gcc
|
||||
help: Please install with `sudo yum install gcc-c++ make` and try again
|
||||
- name: pkg-config
|
||||
help: Please install with `sudo yum install pkgconf-pkg-config` and try again
|
||||
- name: npm
|
||||
help: Please install `sudo yum install nodejs` and try again
|
||||
libraries:
|
||||
- name: gtk3-devel
|
||||
help: Please install with `sudo yum install gtk3-devel` and try again
|
||||
- name: webkit2gtk3-devel
|
||||
help: Please install with `sudo yum install webkit2gtk3-devel` and try again
|
||||
arch:
|
||||
id: arch
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Arch Linux
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs: &archdefaultprograms
|
||||
- name: gcc
|
||||
help: Please install with `sudo pacman -S gcc` and try again
|
||||
- name: pkgconf
|
||||
help: Please install with `sudo pacman -S pkgconf` and try again
|
||||
- name: npm
|
||||
help: Please install with `sudo pacman -S npm` and try again
|
||||
libraries: &archdefaultlibraries
|
||||
- name: gtk3
|
||||
help: Please install with `sudo pacman -S gtk3` and try again
|
||||
- name: webkit2gtk
|
||||
help: Please install with `sudo pacman -S webkit2gtk` and try again
|
||||
manjaro:
|
||||
id: manjaro
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Manjaro Linux
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs: *archdefaultprograms
|
||||
libraries: *archdefaultlibraries
|
||||
arcolinux:
|
||||
id: arcolinux
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: ArcoLinux
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs: *archdefaultprograms
|
||||
libraries: *archdefaultlibraries
|
||||
gentoo:
|
||||
id: gentoo
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Gentoo
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs:
|
||||
- name: gcc
|
||||
help: Please install using your system's package manager
|
||||
- name: pkg-config
|
||||
help: Please install using your system's package manager
|
||||
- name: npm
|
||||
help: Please install using your system's package manager
|
||||
libraries:
|
||||
- name: gtk+:3
|
||||
help: Please install with `sudo emerge gtk+:3` and try again
|
||||
- name: webkit-gtk
|
||||
help: Please install with `sudo emerge webkit-gtk` and try again
|
||||
81
cmd/linuxdb_test.go
Normal file
81
cmd/linuxdb_test.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package cmd
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNewLinuxDB(t *testing.T) {
|
||||
_ = NewLinuxDB()
|
||||
}
|
||||
|
||||
func TestKnownDistro(t *testing.T) {
|
||||
var linuxDB = NewLinuxDB()
|
||||
result := linuxDB.GetDistro("ubuntu")
|
||||
if result == nil {
|
||||
t.Error("Cannot get distro 'ubuntu'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownDistro(t *testing.T) {
|
||||
var linuxDB = NewLinuxDB()
|
||||
result := linuxDB.GetDistro("unknown")
|
||||
if result != nil {
|
||||
t.Error("Should get nil for distribution 'unknown'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultRelease(t *testing.T) {
|
||||
var linuxDB = NewLinuxDB()
|
||||
result := linuxDB.GetDistro("ubuntu")
|
||||
if result == nil {
|
||||
t.Error("Cannot get distro 'ubuntu'")
|
||||
}
|
||||
|
||||
release := result.GetRelease("default")
|
||||
if release == nil {
|
||||
t.Error("Cannot get release 'default' for distro 'ubuntu'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownRelease(t *testing.T) {
|
||||
var linuxDB = NewLinuxDB()
|
||||
result := linuxDB.GetDistro("ubuntu")
|
||||
if result == nil {
|
||||
t.Error("Cannot get distro 'ubuntu'")
|
||||
}
|
||||
|
||||
release := result.GetRelease("16.04")
|
||||
if release == nil {
|
||||
t.Error("Failed to get release 'default' for unknown release version '16.04'")
|
||||
}
|
||||
|
||||
if release.Version != "default" {
|
||||
t.Errorf("Got version '%s' instead of 'default' for unknown release version '16.04'", result.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPrerequisites(t *testing.T) {
|
||||
var linuxDB = NewLinuxDB()
|
||||
result := linuxDB.GetDistro("debian")
|
||||
if result == nil {
|
||||
t.Error("Cannot get distro 'debian'")
|
||||
}
|
||||
|
||||
release := result.GetRelease("default")
|
||||
if release == nil {
|
||||
t.Error("Failed to get release 'default' for unknown release version '16.04'")
|
||||
}
|
||||
|
||||
if release.Version != "default" {
|
||||
t.Errorf("Got version '%s' instead of 'default' for unknown release version '16.04'", result.ID)
|
||||
}
|
||||
|
||||
if release.Name != "Debian" {
|
||||
t.Errorf("Got Release Name '%s' instead of 'debian' for unknown release version '16.04'", release.Name)
|
||||
}
|
||||
|
||||
if len(release.Programs) != 3 {
|
||||
t.Errorf("Expected %d programs for unknown release version '16.04'", len(release.Programs))
|
||||
}
|
||||
if len(release.Libraries) != 2 {
|
||||
t.Errorf("Expected %d libraries for unknown release version '16.04'", len(release.Libraries))
|
||||
}
|
||||
}
|
||||
@@ -191,8 +191,15 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
|
||||
|
||||
// Build syso
|
||||
sysofile := filepath.Join(b.fs.Cwd(), basename+"-res.syso")
|
||||
windresCommand := []string{"windres", "-o", sysofile, tgtRCFile}
|
||||
err := NewProgramHelper().RunCommandArray(windresCommand)
|
||||
|
||||
batfile, err := fs.LocalDir(".")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
windresBatFile := filepath.Join(batfile.fullPath, "windres.bat")
|
||||
windresCommand := []string{windresBatFile, sysofile, tgtRCFile}
|
||||
err = NewProgramHelper().RunCommandArray(windresCommand)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,13 +5,6 @@ import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Prerequisite defines a Prerequisite!
|
||||
type Prerequisite struct {
|
||||
Name string
|
||||
Help string
|
||||
Path string
|
||||
}
|
||||
|
||||
func newPrerequisite(name, help string) *Prerequisite {
|
||||
return &Prerequisite{Name: name, Help: help}
|
||||
}
|
||||
@@ -48,16 +41,13 @@ func getRequiredProgramsOSX() *Prerequisites {
|
||||
func getRequiredProgramsLinux() *Prerequisites {
|
||||
result := &Prerequisites{}
|
||||
distroInfo := GetLinuxDistroInfo()
|
||||
switch distroInfo.Distribution {
|
||||
case Ubuntu, Debian:
|
||||
result.Add(newPrerequisite("gcc", "Please install with `sudo apt install build-essentials` and try again"))
|
||||
result.Add(newPrerequisite("pkg-config", "Please install with `sudo apt install pkg-config` and try again"))
|
||||
result.Add(newPrerequisite("npm", "Please install with `sudo snap install node --channel=12/stable --classic` and try again"))
|
||||
default:
|
||||
result.Add(newPrerequisite("gcc", "Please install with your system package manager and try again"))
|
||||
result.Add(newPrerequisite("pkg-config", "Please install with your system package manager and try again"))
|
||||
result.Add(newPrerequisite("npm", "Please install from https://nodejs.org/en/download/ and try again"))
|
||||
|
||||
if distroInfo.Distribution != Unknown {
|
||||
var linuxDB = NewLinuxDB()
|
||||
distro := linuxDB.GetDistro(distroInfo.ID)
|
||||
release := distro.GetRelease(distroInfo.Release)
|
||||
for _, program := range release.Programs {
|
||||
result.Add(program)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -91,20 +81,15 @@ func getRequiredLibrariesOSX() (*Prerequisites, error) {
|
||||
|
||||
func getRequiredLibrariesLinux() (*Prerequisites, error) {
|
||||
result := &Prerequisites{}
|
||||
// The Linux Distribution DB
|
||||
distroInfo := GetLinuxDistroInfo()
|
||||
switch distroInfo.Distribution {
|
||||
case Ubuntu:
|
||||
result.Add(newPrerequisite("libgtk-3-dev", "Please install with `sudo apt install libgtk-3-dev` and try again"))
|
||||
result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with `sudo apt install libwebkit2gtk-4.0-dev` and try again"))
|
||||
case Arch:
|
||||
result.Add(newPrerequisite("gtk3", "Please install with `sudo pacman -S gtk3` and try again"))
|
||||
result.Add(newPrerequisite("webkit2gtk", "Please install with `sudo pacman -S webkit2gtk` and try again"))
|
||||
case RedHat:
|
||||
result.Add(newPrerequisite("gtk3-devel", "Please install with `sudo yum install gtk3-devel` and try again"))
|
||||
result.Add(newPrerequisite("webkit2gtk3-devel", "Please install with `sudo yum install webkit2gtk3-devel` and try again"))
|
||||
default:
|
||||
result.Add(newPrerequisite("libgtk-3-dev", "Please install with your system package manager and try again"))
|
||||
result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with your system package manager and try again"))
|
||||
if distroInfo.Distribution != Unknown {
|
||||
var linuxDB = NewLinuxDB()
|
||||
distro := linuxDB.GetDistro(distroInfo.ID)
|
||||
release := distro.GetRelease(distroInfo.Release)
|
||||
for _, library := range release.Libraries {
|
||||
result.Add(library)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -100,6 +100,19 @@ func (p *ProgramHelper) InstallGoPackage(packageName string) error {
|
||||
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
|
||||
func (p *ProgramHelper) RunCommand(command string) error {
|
||||
args := strings.Split(command, " ")
|
||||
@@ -115,16 +128,18 @@ func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error {
|
||||
fmt.Printf("ERROR: Looks like '%s' isn't installed. Please install and try again.", program)
|
||||
return err
|
||||
}
|
||||
|
||||
args = args[1:]
|
||||
var stderr string
|
||||
// fmt.Printf("RunCommandArray = %s %+v\n", program, args)
|
||||
var stdout string
|
||||
if len(dir) > 0 {
|
||||
_, stderr, err = p.shell.RunInDirectory(dir[0], program, args...)
|
||||
stdout, stderr, err = p.shell.RunInDirectory(dir[0], program, args...)
|
||||
} else {
|
||||
_, stderr, err = p.shell.Run(program, args...)
|
||||
stdout, stderr, err = p.shell.Run(program, args...)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(stderr)
|
||||
fmt.Println(stdout)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,6 +13,18 @@ import (
|
||||
"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 {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
@@ -112,9 +124,9 @@ func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
|
||||
Description: "Enter your project description",
|
||||
Version: "0.1.0",
|
||||
BinaryName: "",
|
||||
system: NewSystemHelper(),
|
||||
log: NewLogger(),
|
||||
templates: NewTemplateHelper(),
|
||||
system: ph.system,
|
||||
log: ph.log,
|
||||
templates: ph.templates,
|
||||
Author: &author{},
|
||||
}
|
||||
|
||||
@@ -153,6 +165,23 @@ func (po *ProjectOptions) Defaults() {
|
||||
po.WailsVersion = Version
|
||||
}
|
||||
|
||||
// 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
|
||||
func (po *ProjectOptions) PromptForInputs() error {
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -20,11 +19,7 @@ func Prompt(question string, defaultValue ...string) string {
|
||||
fmt.Printf(question + ": ")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
input, _ := reader.ReadString('\n')
|
||||
EOL := "\n"
|
||||
if runtime.GOOS == "windows" {
|
||||
EOL = "\r\n"
|
||||
}
|
||||
input = strings.Replace(input, EOL, "", -1)
|
||||
input = strings.TrimSpace(input)
|
||||
|
||||
if input != "" {
|
||||
answer = input
|
||||
|
||||
@@ -3,7 +3,7 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/masterminds/semver"
|
||||
"github.com/Masterminds/semver"
|
||||
)
|
||||
|
||||
// SemanticVersion is a struct containing a semantic version
|
||||
|
||||
@@ -269,44 +269,35 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var libraryChecker CheckPkgInstalled
|
||||
distroInfo := GetLinuxDistroInfo()
|
||||
|
||||
switch distroInfo.Distribution {
|
||||
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon:
|
||||
libraryChecker = DpkgInstalled
|
||||
case Arch, Manjaro, ArcoLinux:
|
||||
libraryChecker = PacmanInstalled
|
||||
case CentOS, Fedora:
|
||||
libraryChecker = RpmInstalled
|
||||
case Gentoo:
|
||||
libraryChecker = EqueryInstalled
|
||||
case VoidLinux:
|
||||
libraryChecker = XbpsInstalled
|
||||
default:
|
||||
return false, RequestSupportForDistribution(distroInfo)
|
||||
}
|
||||
|
||||
for _, library := range *requiredLibraries {
|
||||
switch distroInfo.Distribution {
|
||||
case Ubuntu, Debian:
|
||||
installed, err := DpkgInstalled(library.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !installed {
|
||||
errors = true
|
||||
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
|
||||
} else {
|
||||
logger.Green("Library '%s' installed.", library.Name)
|
||||
}
|
||||
case Arch:
|
||||
installed, err := PacmanInstalled(library.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !installed {
|
||||
errors = true
|
||||
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
|
||||
} else {
|
||||
logger.Green("Library '%s' installed.", library.Name)
|
||||
}
|
||||
case RedHat:
|
||||
installed, err := RpmInstalled(library.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !installed {
|
||||
errors = true
|
||||
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
|
||||
} else {
|
||||
logger.Green("Library '%s' installed.", library.Name)
|
||||
}
|
||||
default:
|
||||
return false, RequestSupportForDistribution(distroInfo, library.Name)
|
||||
installed, err := libraryChecker(library.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !installed {
|
||||
errors = true
|
||||
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
|
||||
} else {
|
||||
logger.Green("Library '%s' installed.", library.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func NewTemplateHelper() *TemplateHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// IsValidTemplate returns true if the given tempalte name resides on disk
|
||||
// IsValidTemplate returns true if the given template name resides on disk
|
||||
func (t *TemplateHelper) IsValidTemplate(templateName string) bool {
|
||||
pathToTemplate := filepath.Join(t.templateDir.fullPath, templateName)
|
||||
return t.fs.DirExists(pathToTemplate)
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||
IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "npx ng",
|
||||
"start": "npx ng serve --poll=2000",
|
||||
"start": "npx ng serve --poll=2000 --host=0.0.0.0",
|
||||
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
|
||||
"test": "npx ng test",
|
||||
"lint": "npx ng lint",
|
||||
@@ -21,6 +21,8 @@
|
||||
"@angular/platform-browser": "~8.0.1",
|
||||
"@angular/platform-browser-dynamic": "~8.0.1",
|
||||
"@angular/router": "~8.0.1",
|
||||
"@wailsapp/runtime": "^1.0.0",
|
||||
"core-js": "^3.4.4",
|
||||
"ngx-build-plus": "^8.0.3",
|
||||
"rxjs": "~6.4.0",
|
||||
"tslib": "^1.9.0",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'core-js/stable';
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
@@ -6,13 +7,13 @@ import { environment } from './environments/environment';
|
||||
|
||||
import 'zone.js'
|
||||
|
||||
import Bridge from './wailsbridge';
|
||||
import * as Wails from '@wailsapp/runtime';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
Bridge.Start(() => {
|
||||
Wails.Init(() => {
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
});
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
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",
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
"target": "es5",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
@@ -20,4 +20,4 @@
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ func basic() string {
|
||||
|
||||
func main() {
|
||||
|
||||
js := mewn.String("./frontend/dist/my-app/main-es2015.js")
|
||||
js := mewn.String("./frontend/dist/my-app/main.js")
|
||||
css := mewn.String("./frontend/dist/my-app/styles.css")
|
||||
|
||||
app := wails.CreateApp(&wails.AppConfig{
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"core-js": "^3.1.4",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"wails-react-scripts": "3.0.1-2",
|
||||
"react-modal": "3.8.1"
|
||||
"react-modal": "3.8.1",
|
||||
"@wailsapp/runtime": "^1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import 'core-js/stable';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
import Bridge from "./wailsbridge";
|
||||
import * as Wails from '@wailsapp/runtime';
|
||||
|
||||
Bridge.Start(() => {
|
||||
Wails.Init(() => {
|
||||
ReactDOM.render(<App />, document.getElementById('app'));
|
||||
});
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
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 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^2.6.4",
|
||||
"vue": "^2.5.22"
|
||||
"core-js": "^3.6.1",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"vue": "^2.5.22",
|
||||
"@wailsapp/runtime": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^3.4.0",
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import Vue from "vue";
|
||||
import App from "./App.vue";
|
||||
import 'core-js/stable';
|
||||
import 'regenerator-runtime/runtime';
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
Vue.config.devtools = true;
|
||||
|
||||
import Bridge from "./wailsbridge";
|
||||
import * as Wails from '@wailsapp/runtime';
|
||||
|
||||
Bridge.Start(() => {
|
||||
new Vue({
|
||||
render: h => h(App)
|
||||
}).$mount("#app");
|
||||
Wails.Init(() => {
|
||||
new Vue({
|
||||
render: h => h(App)
|
||||
}).$mount('#app');
|
||||
});
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -37,7 +37,6 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
devServer: {
|
||||
disableHostCheck: true,
|
||||
host: "localhost"
|
||||
disableHostCheck: true
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"core-js": "^2.6.4",
|
||||
"core-js": "^3.6.1",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"material-design-icons-iconfont": "^5.0.1",
|
||||
"vue": "^2.5.22",
|
||||
"vuetify": "^1.5.14"
|
||||
"vuetify": "^1.5.14",
|
||||
"@wailsapp/runtime": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^3.4.0",
|
||||
@@ -49,4 +50,4 @@
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'babel-polyfill';
|
||||
import Vue from "vue";
|
||||
import 'core-js/stable';
|
||||
import 'regenerator-runtime/runtime';
|
||||
import Vue from 'vue';
|
||||
|
||||
// Setup Vuetify
|
||||
import Vuetify from 'vuetify';
|
||||
@@ -7,15 +8,15 @@ Vue.use(Vuetify);
|
||||
import 'vuetify/dist/vuetify.min.css';
|
||||
import 'material-design-icons-iconfont';
|
||||
|
||||
import App from "./App.vue";
|
||||
import App from './App.vue';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
Vue.config.devtools = true;
|
||||
|
||||
import Bridge from "./wailsbridge";
|
||||
import * as Wails from '@wailsapp/runtime';
|
||||
|
||||
Bridge.Start(() => {
|
||||
new Vue({
|
||||
render: h => h(App)
|
||||
}).$mount("#app");
|
||||
Wails.Init(() => {
|
||||
new Vue({
|
||||
render: h => h(App)
|
||||
}).$mount('#app');
|
||||
});
|
||||
|
||||
@@ -37,7 +37,6 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
devServer: {
|
||||
disableHostCheck: true,
|
||||
host: "localhost"
|
||||
disableHostCheck: true
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "Vuetify Basic",
|
||||
"name": "Vuetify1.5/Webpack Basic",
|
||||
"version": "1.0.0",
|
||||
"shortdescription": "Vuetify + Webpack",
|
||||
"description": "Basic template using Vuetify and bundled using Webpack",
|
||||
"shortdescription": "A basic Vuetify1.5/Webpack4 template",
|
||||
"description": "Basic template using Vuetify v1.5 and bundled using Webpack",
|
||||
"install": "npm install",
|
||||
"build": "npm run build",
|
||||
"author": "lea <lea.anthony@gmail.com>",
|
||||
@@ -11,4 +11,4 @@
|
||||
"serve": "npm run serve",
|
||||
"bridge": "src",
|
||||
"wailsdir": ""
|
||||
}
|
||||
}
|
||||
|
||||
3
cmd/templates/vuetify2-basic/.jshint
Normal file
3
cmd/templates/vuetify2-basic/.jshint
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"esversion": 6
|
||||
}
|
||||
21
cmd/templates/vuetify2-basic/frontend/.gitignore
vendored
Normal file
21
cmd/templates/vuetify2-basic/frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw*
|
||||
5
cmd/templates/vuetify2-basic/frontend/babel.config.js
Normal file
5
cmd/templates/vuetify2-basic/frontend/babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
[ '@vue/app', { useBuiltIns: 'entry' } ]
|
||||
]
|
||||
};
|
||||
53
cmd/templates/vuetify2-basic/frontend/package.json.template
Normal file
53
cmd/templates/vuetify2-basic/frontend/package.json.template
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "{{.NPMProjectName}}",
|
||||
"author": "{{.Author.Name}}<{{.Author.Email}}>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.1",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"vue": "^2.5.22",
|
||||
"vuetify": "^2.0.15",
|
||||
"@wailsapp/runtime": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mdi/font": "^4.3.95",
|
||||
"@vue/cli-plugin-babel": "^3.4.0",
|
||||
"@vue/cli-plugin-eslint": "^3.4.0",
|
||||
"@vue/cli-service": "^3.4.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"eslint": "^5.8.0",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"eventsource-polyfill": "^0.9.6",
|
||||
"vue-template-compiler": "^2.5.21",
|
||||
"webpack-hot-middleware": "^2.24.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"rules": {},
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
]
|
||||
}
|
||||
60
cmd/templates/vuetify2-basic/frontend/src/App.vue
Normal file
60
cmd/templates/vuetify2-basic/frontend/src/App.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<v-app id="inspire">
|
||||
<v-navigation-drawer v-model="drawer" clipped fixed app>
|
||||
<v-list dense>
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-view-dashboard</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Dashboard</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-settings</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Settings</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
<v-app-bar app fixed clipped-left>
|
||||
<v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
|
||||
<v-toolbar-title>Application</v-toolbar-title>
|
||||
</v-app-bar>
|
||||
<v-content>
|
||||
<v-container fluid class="px-0">
|
||||
<v-layout justify-center align-center class="px-0">
|
||||
<hello-world></hello-world>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-content>
|
||||
<v-footer app fixed>
|
||||
<span style="margin-left:1em">© You</span>
|
||||
</v-footer>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HelloWorld from "./components/HelloWorld.vue"
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
drawer: false
|
||||
}),
|
||||
components: {
|
||||
HelloWorld
|
||||
},
|
||||
props: {
|
||||
source: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.logo {
|
||||
width: 16em;
|
||||
}
|
||||
</style>
|
||||
BIN
cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png
Normal file
BIN
cmd/templates/vuetify2-basic/frontend/src/assets/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 301 KiB |
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<v-container fluid class="px-0">
|
||||
<v-layout>
|
||||
<v-flex xs12 sm6 offset-sm3>
|
||||
<v-card raised="raised" class="pa-4 ma-4">
|
||||
<v-layout justify-center align-center class="pa-4 ma-4">
|
||||
<v-img :src="require('../assets/images/logo.png')"></v-img>
|
||||
</v-layout>
|
||||
<v-card-actions>
|
||||
<v-layout justify-center align-center class="px-0">
|
||||
<v-btn color="blue" @click="getMessage">Press Me</v-btn>
|
||||
</v-layout>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<div class="text-xs-center">
|
||||
<v-dialog v-model="dialog" width="500">
|
||||
<v-card>
|
||||
<v-card-title class="headline" primary-title>Message from Go</v-card-title>
|
||||
<v-card-text>{{message}}</v-card-text>
|
||||
<v-divider></v-divider>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" text @click="dialog = false">Awesome</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
message: " ",
|
||||
raised: true,
|
||||
dialog: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getMessage: function () {
|
||||
var self = this
|
||||
window.backend.basic().then(result => {
|
||||
self.message = result
|
||||
self.dialog = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h1 {
|
||||
margin-top: 2em;
|
||||
position: relative;
|
||||
min-height: 5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
font-size: 1.7em;
|
||||
border-color: blue;
|
||||
background-color: blue;
|
||||
color: white;
|
||||
border: 3px solid white;
|
||||
border-radius: 10px;
|
||||
padding: 9px;
|
||||
cursor: pointer;
|
||||
transition: 500ms;
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 1.7em;
|
||||
border-color: white;
|
||||
background-color: #121212;
|
||||
color: white;
|
||||
border: 3px solid white;
|
||||
border-radius: 10px;
|
||||
padding: 9px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
29
cmd/templates/vuetify2-basic/frontend/src/main.js
Normal file
29
cmd/templates/vuetify2-basic/frontend/src/main.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'core-js/stable';
|
||||
import 'regenerator-runtime/runtime';
|
||||
import '@mdi/font/css/materialdesignicons.css';
|
||||
import Vue from 'vue';
|
||||
import Vuetify from 'vuetify';
|
||||
import 'vuetify/dist/vuetify.min.css';
|
||||
|
||||
Vue.use(Vuetify);
|
||||
|
||||
import App from './App.vue';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
Vue.config.devtools = true;
|
||||
|
||||
import Wails from '@wailsapp/runtime';
|
||||
|
||||
Wails.Init(() => {
|
||||
new Vue({
|
||||
vuetify: new Vuetify({
|
||||
icons: {
|
||||
iconfont: 'mdi'
|
||||
},
|
||||
theme: {
|
||||
dark: true
|
||||
}
|
||||
}),
|
||||
render: h => h(App)
|
||||
}).$mount('#app');
|
||||
});
|
||||
42
cmd/templates/vuetify2-basic/frontend/vue.config.js
Normal file
42
cmd/templates/vuetify2-basic/frontend/vue.config.js
Normal file
@@ -0,0 +1,42 @@
|
||||
let cssConfig = {};
|
||||
|
||||
if (process.env.NODE_ENV == 'production') {
|
||||
cssConfig = {
|
||||
extract: {
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[name].css'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
chainWebpack: config => {
|
||||
let limit = 9999999999999999;
|
||||
config.module
|
||||
.rule('images')
|
||||
.test(/\.(png|gif|jpg)(\?.*)?$/i)
|
||||
.use('url-loader')
|
||||
.loader('url-loader')
|
||||
.tap(options => Object.assign(options, { limit: limit }));
|
||||
config.module
|
||||
.rule('fonts')
|
||||
.test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i)
|
||||
.use('url-loader')
|
||||
.loader('url-loader')
|
||||
.options({
|
||||
limit: limit
|
||||
});
|
||||
},
|
||||
css: cssConfig,
|
||||
configureWebpack: {
|
||||
output: {
|
||||
filename: '[name].js'
|
||||
},
|
||||
optimization: {
|
||||
splitChunks: false
|
||||
}
|
||||
},
|
||||
devServer: {
|
||||
disableHostCheck: true
|
||||
}
|
||||
};
|
||||
5
cmd/templates/vuetify2-basic/go.mod.template
Normal file
5
cmd/templates/vuetify2-basic/go.mod.template
Normal file
@@ -0,0 +1,5 @@
|
||||
module {{.BinaryName}}
|
||||
|
||||
require (
|
||||
github.com/wailsapp/wails {{.WailsVersion}}
|
||||
)
|
||||
27
cmd/templates/vuetify2-basic/main.go.template
Normal file
27
cmd/templates/vuetify2-basic/main.go.template
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/mewn"
|
||||
"github.com/wailsapp/wails"
|
||||
)
|
||||
|
||||
func basic() string {
|
||||
return "Hello World!"
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
js := mewn.String("./frontend/dist/app.js")
|
||||
css := mewn.String("./frontend/dist/app.css")
|
||||
|
||||
app := wails.CreateApp(&wails.AppConfig{
|
||||
Width: 1024,
|
||||
Height: 768,
|
||||
Title: "{{.Name}}",
|
||||
JS: js,
|
||||
CSS: css,
|
||||
Colour: "#131313",
|
||||
})
|
||||
app.Bind(basic)
|
||||
app.Run()
|
||||
}
|
||||
14
cmd/templates/vuetify2-basic/template.json
Executable file
14
cmd/templates/vuetify2-basic/template.json
Executable file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "Vuetify2/Webpack Basic",
|
||||
"version": "1.0.0",
|
||||
"shortdescription": "A basic Vuetify2/Webpack4 template",
|
||||
"description": "Basic template using Vuetify v2 and bundled using Webpack",
|
||||
"install": "npm install",
|
||||
"build": "npm run build",
|
||||
"author": "Michael Hipp <michael@redmule.com>",
|
||||
"created": "2019-09-06",
|
||||
"frontenddir": "frontend",
|
||||
"serve": "npm run serve",
|
||||
"bridge": "src",
|
||||
"wailsdir": ""
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package cmd
|
||||
|
||||
// Version - Wails version
|
||||
const Version = "v0.17.0"
|
||||
const Version = "v1.0.2-pre2"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
@@ -24,7 +23,7 @@ func init() {
|
||||
|
||||
system := cmd.NewSystemHelper()
|
||||
err = system.Initialise()
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -33,23 +32,9 @@ Create your first project by running 'wails init'.`
|
||||
if runtime.GOOS != "windows" {
|
||||
successMessage = "🚀 " + successMessage
|
||||
}
|
||||
// Platform check
|
||||
err = platformCheck()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check we have a cgo capable environment
|
||||
logger.Yellow("Checking for prerequisites...")
|
||||
var requiredProgramErrors bool
|
||||
requiredProgramErrors, err = checkRequiredPrograms()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Linux has library deps
|
||||
var libraryErrors bool
|
||||
libraryErrors, err = checkLibraries()
|
||||
// Chrck for programs and libraries dependencies
|
||||
errors, err := cmd.CheckDependencies(logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -60,76 +45,14 @@ Create your first project by running 'wails init'.`
|
||||
return err
|
||||
}
|
||||
|
||||
logger.White("")
|
||||
|
||||
// Check for errors
|
||||
var errors = libraryErrors || requiredProgramErrors
|
||||
if !errors {
|
||||
// CheckDependencies() returns !errors
|
||||
// so to get the right message in this
|
||||
// check we have to do it in reversed
|
||||
if errors {
|
||||
logger.Yellow(successMessage)
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func platformCheck() error {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
logger.Yellow("Detected Platform: OSX")
|
||||
case "windows":
|
||||
logger.Yellow("Detected Platform: Windows")
|
||||
case "linux":
|
||||
logger.Yellow("Detected Platform: Linux")
|
||||
default:
|
||||
return fmt.Errorf("Platform %s is currently not supported", runtime.GOOS)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkLibraries() (errors bool, err error) {
|
||||
if runtime.GOOS == "linux" {
|
||||
// Check library prerequisites
|
||||
requiredLibraries, err := cmd.GetRequiredLibraries()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
distroInfo := cmd.GetLinuxDistroInfo()
|
||||
for _, library := range *requiredLibraries {
|
||||
switch distroInfo.Distribution {
|
||||
case cmd.Ubuntu, cmd.Debian:
|
||||
installed, err := cmd.DpkgInstalled(library.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !installed {
|
||||
errors = true
|
||||
logger.Red("Library '%s' not found. %s", library.Name, library.Help)
|
||||
} else {
|
||||
logger.Green("Library '%s' installed.", library.Name)
|
||||
}
|
||||
default:
|
||||
return false, cmd.RequestSupportForDistribution(distroInfo, library.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func checkRequiredPrograms() (errors bool, err error) {
|
||||
requiredPrograms, err := cmd.GetRequiredPrograms()
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
errors = false
|
||||
programHelper := cmd.NewProgramHelper()
|
||||
for _, program := range *requiredPrograms {
|
||||
bin := programHelper.FindProgram(program.Name)
|
||||
if bin == nil {
|
||||
errors = true
|
||||
logger.Red("Program '%s' not found. %s", program.Name, program.Help)
|
||||
} else {
|
||||
logger.Green("Program '%s' found: %s", program.Name, bin.Path)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
408
cmd/wails/15_migrate.go
Normal file
408
cmd/wails/15_migrate.go
Normal file
@@ -0,0 +1,408 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"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")
|
||||
var result *semver.Version
|
||||
|
||||
// Load file
|
||||
var err error
|
||||
goModFile, err = filepath.Abs(filepath.Join(".", "go.mod"))
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return nil, fmt.Errorf("Unable to load go.mod at %s", goModFile)
|
||||
}
|
||||
goMod, err = migrateFS.LoadAsString(goModFile)
|
||||
if err != nil {
|
||||
checkSpinner.Error()
|
||||
return nil, fmt.Errorf("Unable to load go.mod")
|
||||
}
|
||||
|
||||
// Find wails version
|
||||
versionRegexp := regexp.MustCompile(`.*github.com/wailsapp/wails.*(v\d+.\d+.\d+)`)
|
||||
versions := versionRegexp.FindStringSubmatch(goMod)
|
||||
|
||||
if len(versions) != 2 {
|
||||
return nil, fmt.Errorf("Unable to determine Wails version")
|
||||
}
|
||||
|
||||
version := versions[1]
|
||||
result, err = semver.NewVersion(version)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse Wails version: %s", version)
|
||||
}
|
||||
checkSpinner.Success("Found Wails Version: " + version)
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -72,8 +72,17 @@ func init() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure that runtime init.js is the production version
|
||||
err = cmd.InstallProdRuntime(projectDir, projectOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Move to project directory
|
||||
err = os.Chdir(projectDir)
|
||||
if err != nil {
|
||||
|
||||
@@ -45,7 +45,7 @@ func init() {
|
||||
projectDir := fs.Cwd()
|
||||
|
||||
// Install the bridge library
|
||||
err = cmd.InstallBridge("serve", projectDir, projectOptions)
|
||||
err = cmd.InstallBridge(projectDir, projectOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -42,12 +42,65 @@ To help you in this process, we will ask for some information, add Go/Wails deta
|
||||
gomodule = "(Not Set)"
|
||||
}
|
||||
|
||||
// get version numbers for GCC, node & npm
|
||||
program := cmd.NewProgramHelper()
|
||||
// string helpers
|
||||
var gccVersion, nodeVersion, npmVersion string
|
||||
|
||||
// choose between OS (mac,linux,win)
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
gcc := program.FindProgram("gcc")
|
||||
if gcc != nil {
|
||||
stdout, _, _, _ := gcc.Run("-dumpversion")
|
||||
gccVersion = strings.TrimSpace(stdout)
|
||||
}
|
||||
case "linux":
|
||||
// for linux we have to collect
|
||||
// the distribution name
|
||||
distroInfo := cmd.GetLinuxDistroInfo()
|
||||
linuxDB := cmd.NewLinuxDB()
|
||||
distro := linuxDB.GetDistro(distroInfo.ID)
|
||||
release := distro.GetRelease(distroInfo.Release)
|
||||
gccVersionCommand := release.GccVersionCommand
|
||||
|
||||
gcc := program.FindProgram("gcc")
|
||||
if gcc != nil {
|
||||
stdout, _, _, _ := gcc.Run(gccVersionCommand)
|
||||
gccVersion = strings.TrimSpace(stdout)
|
||||
}
|
||||
case "windows":
|
||||
gcc := program.FindProgram("gcc")
|
||||
if gcc != nil {
|
||||
stdout, _, _, _ := gcc.Run("-dumpversion")
|
||||
gccVersion = strings.TrimSpace(stdout)
|
||||
}
|
||||
}
|
||||
|
||||
npm := program.FindProgram("npm")
|
||||
if npm != nil {
|
||||
stdout, _, _, _ := npm.Run("--version")
|
||||
npmVersion = stdout
|
||||
npmVersion = npmVersion[:len(npmVersion)-1]
|
||||
npmVersion = strings.TrimSpace(npmVersion)
|
||||
}
|
||||
|
||||
node := program.FindProgram("node")
|
||||
if node != nil {
|
||||
stdout, _, _, _ := node.Run("--version")
|
||||
nodeVersion = stdout
|
||||
nodeVersion = nodeVersion[:len(nodeVersion)-1]
|
||||
}
|
||||
|
||||
str.WriteString("\n| Name | Value |\n| ----- | ----- |\n")
|
||||
str.WriteString(fmt.Sprintf("| Wails Version | %s |\n", cmd.Version))
|
||||
str.WriteString(fmt.Sprintf("| Go Version | %s |\n", runtime.Version()))
|
||||
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
|
||||
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
|
||||
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
|
||||
str.WriteString(fmt.Sprintf("| GCC | %s |\n", gccVersion))
|
||||
str.WriteString(fmt.Sprintf("| Npm | %s |\n", npmVersion))
|
||||
str.WriteString(fmt.Sprintf("| Node | %s |\n", nodeVersion))
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println("Processing template and preparing for upload.")
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
)
|
||||
|
||||
@@ -15,5 +18,9 @@ func main() {
|
||||
err := app.Run()
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
os.Exit(exitErr.ExitCode())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
1
cmd/windres.bat
Normal file
1
cmd/windres.bat
Normal file
@@ -0,0 +1 @@
|
||||
windres.exe -o %1 %2
|
||||
113
config.go
Normal file
113
config.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package wails
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/mewn"
|
||||
"github.com/wailsapp/wails/runtime"
|
||||
)
|
||||
|
||||
// AppConfig is the configuration structure used when creating a Wails App object
|
||||
type AppConfig struct {
|
||||
Width, Height int
|
||||
Title string
|
||||
defaultHTML string
|
||||
HTML string
|
||||
JS string
|
||||
CSS string
|
||||
Colour string
|
||||
Resizable bool
|
||||
DisableInspector bool
|
||||
}
|
||||
|
||||
// GetWidth returns the desired width
|
||||
func (a *AppConfig) GetWidth() int {
|
||||
return a.Width
|
||||
}
|
||||
|
||||
// GetHeight returns the desired height
|
||||
func (a *AppConfig) GetHeight() int {
|
||||
return a.Height
|
||||
}
|
||||
|
||||
// GetTitle returns the desired window title
|
||||
func (a *AppConfig) GetTitle() string {
|
||||
return a.Title
|
||||
}
|
||||
|
||||
// GetDefaultHTML returns the default HTML
|
||||
func (a *AppConfig) GetDefaultHTML() string {
|
||||
return a.defaultHTML
|
||||
}
|
||||
|
||||
// GetResizable returns true if the window should be resizable
|
||||
func (a *AppConfig) GetResizable() bool {
|
||||
return a.Resizable
|
||||
}
|
||||
|
||||
// GetDisableInspector returns true if the inspector should be disabled
|
||||
func (a *AppConfig) GetDisableInspector() bool {
|
||||
return a.DisableInspector
|
||||
}
|
||||
|
||||
// GetColour returns the colour
|
||||
func (a *AppConfig) GetColour() string {
|
||||
return a.Colour
|
||||
}
|
||||
|
||||
// GetCSS returns the user CSS
|
||||
func (a *AppConfig) GetCSS() string {
|
||||
return a.CSS
|
||||
}
|
||||
|
||||
// GetJS returns the user Javascript
|
||||
func (a *AppConfig) GetJS() string {
|
||||
return a.JS
|
||||
}
|
||||
|
||||
func (a *AppConfig) merge(in *AppConfig) error {
|
||||
if in.CSS != "" {
|
||||
a.CSS = in.CSS
|
||||
}
|
||||
if in.Title != "" {
|
||||
a.Title = runtime.ProcessEncoding(in.Title)
|
||||
}
|
||||
|
||||
if in.Colour != "" {
|
||||
a.Colour = in.Colour
|
||||
}
|
||||
|
||||
if in.JS != "" {
|
||||
a.JS = in.JS
|
||||
}
|
||||
|
||||
if in.Width != 0 {
|
||||
a.Width = in.Width
|
||||
}
|
||||
if in.Height != 0 {
|
||||
a.Height = in.Height
|
||||
}
|
||||
a.Resizable = in.Resizable
|
||||
a.DisableInspector = in.DisableInspector
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates the default configuration
|
||||
func newConfig(userConfig *AppConfig) (*AppConfig, error) {
|
||||
result := &AppConfig{
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
Resizable: true,
|
||||
Title: "My Wails App",
|
||||
Colour: "#FFF", // White by default
|
||||
HTML: mewn.String("./runtime/assets/default.html"),
|
||||
}
|
||||
|
||||
if userConfig != nil {
|
||||
err := result.merge(userConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
8
go.mod
8
go.mod
@@ -1,7 +1,8 @@
|
||||
module github.com/wailsapp/wails
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver v1.4.2 // indirect
|
||||
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
|
||||
@@ -14,7 +15,6 @@ require (
|
||||
github.com/leaanthony/mewn v0.10.7
|
||||
github.com/leaanthony/slicer v1.3.2
|
||||
github.com/leaanthony/spinner v0.5.3
|
||||
github.com/masterminds/semver v1.4.2
|
||||
github.com/mattn/go-colorable v0.1.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.7 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
@@ -23,9 +23,11 @@ require (
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/sirupsen/logrus v1.4.1
|
||||
github.com/stretchr/testify v1.3.0 // indirect
|
||||
github.com/wailsapp/webview v0.2.7
|
||||
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
|
||||
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 // indirect
|
||||
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862
|
||||
golang.org/x/text v0.3.0
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
||||
)
|
||||
|
||||
20
go.sum
20
go.sum
@@ -2,6 +2,8 @@ github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITg
|
||||
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/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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -25,7 +27,6 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
|
||||
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -41,14 +42,10 @@ 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/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
|
||||
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
||||
github.com/masterminds/semver v1.4.2 h1:BgrAYDjlAebjtOwS7C/1QZoh5WgyXx4b59ydc+Ph8xI=
|
||||
github.com/masterminds/semver v1.4.2/go.mod h1:s7KNT9fnd7edGzwwP7RBX4H0v/CYd5qdOLfkL1V75yg=
|
||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||
github.com/mattn/go-colorable v0.0.9/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/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||
@@ -73,11 +70,9 @@ 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.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/wailsapp/webview v0.2.7 h1:fN5L5H9Oivg9IJPk7uaXQnjqB68Fny11ZWkIaTIZHmk=
|
||||
github.com/wailsapp/webview v0.2.7/go.mod h1:XO9HJbKWokDxUYTWQEBCYg95n/To1v7PxvanDNVf8hY=
|
||||
github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb/go.mod h1:a1CV8KR4Dd1eP2g+mEijGOp+HKczwdKHWyx0aPHKvo4=
|
||||
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-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -86,14 +81,17 @@ golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR17
|
||||
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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug=
|
||||
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=
|
||||
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/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22 h1:0efs3hwEZhFKsCoP8l6dDB1AZWMgnEl3yWXWRZTOaEA=
|
||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package wails
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
)
|
||||
|
||||
type boundFunction struct {
|
||||
@@ -14,7 +16,7 @@ type boundFunction struct {
|
||||
functionType reflect.Type
|
||||
inputs []reflect.Type
|
||||
returnTypes []reflect.Type
|
||||
log *CustomLogger
|
||||
log *logger.CustomLogger
|
||||
hasErrorReturnType bool
|
||||
}
|
||||
|
||||
@@ -30,7 +32,7 @@ func newBoundFunction(object interface{}) (*boundFunction, error) {
|
||||
fullName: name,
|
||||
function: objectValue,
|
||||
functionType: objectType,
|
||||
log: newCustomLogger(name),
|
||||
log: logger.NewCustomLogger(name),
|
||||
}
|
||||
|
||||
err := result.processParameters()
|
||||
@@ -55,7 +57,7 @@ func (b *boundFunction) processParameters() error {
|
||||
b.inputs[index] = param
|
||||
typ := param
|
||||
index := index
|
||||
b.log.DebugFields("Input param", Fields{
|
||||
b.log.DebugFields("Input param", logger.Fields{
|
||||
"index": index,
|
||||
"name": name,
|
||||
"kind": kind,
|
||||
@@ -1,27 +1,33 @@
|
||||
package wails
|
||||
package binding
|
||||
|
||||
import "strings"
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
type internalMethods struct{
|
||||
log *CustomLogger
|
||||
browser *RuntimeBrowser
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
"github.com/wailsapp/wails/lib/messages"
|
||||
"github.com/wailsapp/wails/runtime"
|
||||
)
|
||||
|
||||
type internalMethods struct {
|
||||
log *logger.CustomLogger
|
||||
browser *runtime.Browser
|
||||
}
|
||||
|
||||
func newInternalMethods() *internalMethods {
|
||||
return &internalMethods{
|
||||
log: newCustomLogger("InternalCall"),
|
||||
browser: newRuntimeBrowser(),
|
||||
log: logger.NewCustomLogger("InternalCall"),
|
||||
browser: runtime.NewBrowser(),
|
||||
}
|
||||
}
|
||||
|
||||
func (i *internalMethods) processCall(callData *callData) (interface{}, error) {
|
||||
func (i *internalMethods) processCall(callData *messages.CallData) (interface{}, error) {
|
||||
if !strings.HasPrefix(callData.BindingName, ".wails.") {
|
||||
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
||||
}
|
||||
|
||||
// Strip prefix
|
||||
var splitCall = strings.Split(callData.BindingName,".")[2:]
|
||||
var splitCall = strings.Split(callData.BindingName, ".")[2:]
|
||||
if len(splitCall) != 2 {
|
||||
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
||||
}
|
||||
@@ -37,14 +43,14 @@ func (i *internalMethods) processCall(callData *callData) (interface{}, error) {
|
||||
|
||||
func (i *internalMethods) processBrowserCommand(command string, data interface{}) (interface{}, error) {
|
||||
switch command {
|
||||
case "OpenURL":
|
||||
case "OpenURL":
|
||||
url := data.(string)
|
||||
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
|
||||
if url[0] == '"' {
|
||||
url = url[1:]
|
||||
}
|
||||
if i := len(url)-1; url[i] == '"' {
|
||||
url = url[:i]
|
||||
if i := len(url) - 1; url[i] == '"' {
|
||||
url = url[:i]
|
||||
}
|
||||
i.log.Debugf("Calling Browser.OpenURL with '%s'", url)
|
||||
return nil, i.browser.OpenURL(url)
|
||||
@@ -54,12 +60,12 @@ func (i *internalMethods) processBrowserCommand(command string, data interface{}
|
||||
if filename[0] == '"' {
|
||||
filename = filename[1:]
|
||||
}
|
||||
if i := len(filename)-1; filename[i] == '"' {
|
||||
filename = filename[:i]
|
||||
if i := len(filename) - 1; filename[i] == '"' {
|
||||
filename = filename[:i]
|
||||
}
|
||||
i.log.Debugf("Calling Browser.OpenFile with '%s'", filename)
|
||||
return nil, i.browser.OpenFile(filename)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown Browser command '%s'", command)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,47 @@
|
||||
package wails
|
||||
package binding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unicode"
|
||||
|
||||
"github.com/wailsapp/wails/lib/interfaces"
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
"github.com/wailsapp/wails/lib/messages"
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
binding:
|
||||
Name() // Full name (package+name)
|
||||
Call(params)
|
||||
|
||||
**/
|
||||
|
||||
type bindingManager struct {
|
||||
// Manager handles method binding
|
||||
type Manager struct {
|
||||
methods map[string]*boundMethod
|
||||
functions map[string]*boundFunction
|
||||
internalMethods *internalMethods
|
||||
initMethods []*boundMethod
|
||||
log *CustomLogger
|
||||
renderer Renderer
|
||||
runtime *Runtime // The runtime object to pass to bound structs
|
||||
shutdownMethods []*boundMethod
|
||||
log *logger.CustomLogger
|
||||
renderer interfaces.Renderer
|
||||
runtime interfaces.Runtime // The runtime object to pass to bound structs
|
||||
objectsToBind []interface{}
|
||||
bindPackageNames bool // Package name should be considered when binding
|
||||
}
|
||||
|
||||
func newBindingManager() *bindingManager {
|
||||
result := &bindingManager{
|
||||
// NewManager creates a new Manager struct
|
||||
func NewManager() interfaces.BindingManager {
|
||||
result := &Manager{
|
||||
methods: make(map[string]*boundMethod),
|
||||
functions: make(map[string]*boundFunction),
|
||||
log: newCustomLogger("Bind"),
|
||||
log: logger.NewCustomLogger("Bind"),
|
||||
internalMethods: newInternalMethods(),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Sets flag to indicate package names should be considered when binding
|
||||
func (b *bindingManager) BindPackageNames() {
|
||||
// BindPackageNames sets a flag to indicate package names should be considered when binding
|
||||
func (b *Manager) BindPackageNames() {
|
||||
b.bindPackageNames = true
|
||||
}
|
||||
|
||||
func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error {
|
||||
// Start the binding manager
|
||||
func (b *Manager) Start(renderer interfaces.Renderer, runtime interfaces.Runtime) error {
|
||||
b.log.Info("Starting")
|
||||
b.renderer = renderer
|
||||
b.runtime = runtime
|
||||
@@ -54,7 +54,7 @@ func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *bindingManager) initialise() error {
|
||||
func (b *Manager) initialise() error {
|
||||
|
||||
var err error
|
||||
// var binding *boundMethod
|
||||
@@ -92,7 +92,7 @@ func (b *bindingManager) initialise() error {
|
||||
}
|
||||
|
||||
// bind the given struct method
|
||||
func (b *bindingManager) bindMethod(object interface{}) error {
|
||||
func (b *Manager) bindMethod(object interface{}) error {
|
||||
|
||||
objectType := reflect.TypeOf(object)
|
||||
baseName := objectType.String()
|
||||
@@ -128,6 +128,9 @@ func (b *bindingManager) bindMethod(object interface{}) error {
|
||||
if newMethod.isWailsInit {
|
||||
b.log.Debugf("Detected WailsInit function: %s", fullMethodName)
|
||||
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 {
|
||||
// Save boundMethod
|
||||
b.log.Infof("Bound Method: %s()", fullMethodName)
|
||||
@@ -142,7 +145,7 @@ func (b *bindingManager) bindMethod(object interface{}) error {
|
||||
}
|
||||
|
||||
// bind the given function object
|
||||
func (b *bindingManager) bindFunction(object interface{}) error {
|
||||
func (b *Manager) bindFunction(object interface{}) error {
|
||||
|
||||
newFunction, err := newBoundFunction(object)
|
||||
if err != nil {
|
||||
@@ -159,18 +162,18 @@ func (b *bindingManager) bindFunction(object interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save the given object to be bound at start time
|
||||
func (b *bindingManager) bind(object interface{}) {
|
||||
// Bind saves the given object to be bound at start time
|
||||
func (b *Manager) Bind(object interface{}) {
|
||||
// Store binding
|
||||
b.objectsToBind = append(b.objectsToBind, object)
|
||||
}
|
||||
|
||||
func (b *bindingManager) processInternalCall(callData *callData) (interface{}, error) {
|
||||
func (b *Manager) processInternalCall(callData *messages.CallData) (interface{}, error) {
|
||||
// Strip prefix
|
||||
return b.internalMethods.processCall(callData)
|
||||
}
|
||||
|
||||
func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
|
||||
func (b *Manager) processFunctionCall(callData *messages.CallData) (interface{}, error) {
|
||||
// Return values
|
||||
var result []reflect.Value
|
||||
var err error
|
||||
@@ -196,10 +199,14 @@ func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, e
|
||||
return nil, errorResult.Interface().(error)
|
||||
}
|
||||
}
|
||||
return result[0].Interface(), nil
|
||||
// fmt.Printf("result = '%+v'\n", result)
|
||||
if len(result) > 0 {
|
||||
return result[0].Interface(), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *bindingManager) processMethodCall(callData *callData) (interface{}, error) {
|
||||
func (b *Manager) processMethodCall(callData *messages.CallData) (interface{}, error) {
|
||||
// Return values
|
||||
var result []reflect.Value
|
||||
var err error
|
||||
@@ -233,8 +240,8 @@ func (b *bindingManager) processMethodCall(callData *callData) (interface{}, err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// process an incoming call request
|
||||
func (b *bindingManager) processCall(callData *callData) (result interface{}, err error) {
|
||||
// ProcessCall processes the given call request
|
||||
func (b *Manager) ProcessCall(callData *messages.CallData) (result interface{}, err error) {
|
||||
b.log.Debugf("Wanting to call %s", callData.BindingName)
|
||||
|
||||
// Determine if this is function call or method call by the number of
|
||||
@@ -272,7 +279,7 @@ func (b *bindingManager) processCall(callData *callData) (result interface{}, er
|
||||
|
||||
// callWailsInitMethods calls all of the WailsInit methods that were
|
||||
// registered with the runtime object
|
||||
func (b *bindingManager) callWailsInitMethods() error {
|
||||
func (b *Manager) callWailsInitMethods() error {
|
||||
// Create reflect value for runtime object
|
||||
runtimeValue := reflect.ValueOf(b.runtime)
|
||||
params := []reflect.Value{runtimeValue}
|
||||
@@ -289,3 +296,13 @@ func (b *bindingManager) callWailsInitMethods() error {
|
||||
}
|
||||
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")
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package wails
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
)
|
||||
|
||||
type boundMethod struct {
|
||||
@@ -13,9 +15,10 @@ type boundMethod struct {
|
||||
method reflect.Value
|
||||
inputs []reflect.Type
|
||||
returnTypes []reflect.Type
|
||||
log *CustomLogger
|
||||
log *logger.CustomLogger
|
||||
hasErrorReturnType bool // Indicates if there is an error return type
|
||||
isWailsInit bool
|
||||
isWailsShutdown bool
|
||||
}
|
||||
|
||||
// Creates a new bound method based on the given method + type
|
||||
@@ -27,7 +30,7 @@ func newBoundMethod(name string, fullName string, method reflect.Value, objectTy
|
||||
}
|
||||
|
||||
// Setup logger
|
||||
result.log = newCustomLogger(result.fullName)
|
||||
result.log = logger.NewCustomLogger(result.fullName)
|
||||
|
||||
// Check if Parameters are valid
|
||||
err := result.processParameters()
|
||||
@@ -37,6 +40,11 @@ func newBoundMethod(name string, fullName string, method reflect.Value, objectTy
|
||||
err = result.processWailsInit()
|
||||
}
|
||||
|
||||
// Are we a WailsShutdown method?
|
||||
if result.Name == "WailsShutdown" {
|
||||
err = result.processWailsShutdown()
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -57,7 +65,7 @@ func (b *boundMethod) processParameters() error {
|
||||
b.inputs[index] = param
|
||||
typ := param
|
||||
index := index
|
||||
b.log.DebugFields("Input param", Fields{
|
||||
b.log.DebugFields("Input param", logger.Fields{
|
||||
"index": index,
|
||||
"name": name,
|
||||
"kind": kind,
|
||||
@@ -166,10 +174,10 @@ func (b *boundMethod) setInputValue(index int, typ reflect.Type, val interface{}
|
||||
reflect.Map,
|
||||
reflect.Ptr,
|
||||
reflect.Slice:
|
||||
logger.Debug("Converting nil to type")
|
||||
b.log.Debug("Converting nil to type")
|
||||
result = reflect.ValueOf(val).Convert(typ)
|
||||
default:
|
||||
logger.Debug("Cannot convert nil to type, returning error")
|
||||
b.log.Debug("Cannot convert nil to type, returning error")
|
||||
return reflect.Zero(typ), fmt.Errorf("Unable to use null value for parameter %d of method %s", index+1, b.fullName)
|
||||
}
|
||||
} else {
|
||||
@@ -209,3 +217,20 @@ func (b *boundMethod) processWailsInit() error {
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,31 +1,37 @@
|
||||
package wails
|
||||
package event
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/lib/interfaces"
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
"github.com/wailsapp/wails/lib/messages"
|
||||
)
|
||||
|
||||
// eventManager handles and processes events
|
||||
type eventManager struct {
|
||||
incomingEvents chan *eventData
|
||||
// Manager handles and processes events
|
||||
type Manager struct {
|
||||
incomingEvents chan *messages.EventData
|
||||
listeners map[string][]*eventListener
|
||||
exit bool
|
||||
log *CustomLogger
|
||||
renderer Renderer // Messages will be dispatched to the frontend
|
||||
running bool
|
||||
log *logger.CustomLogger
|
||||
renderer interfaces.Renderer // Messages will be dispatched to the frontend
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// newEventManager creates a new event manager with a 100 event buffer
|
||||
func newEventManager() *eventManager {
|
||||
return &eventManager{
|
||||
incomingEvents: make(chan *eventData, 100),
|
||||
// NewManager creates a new event manager with a 100 event buffer
|
||||
func NewManager() interfaces.EventManager {
|
||||
return &Manager{
|
||||
incomingEvents: make(chan *messages.EventData, 100),
|
||||
listeners: make(map[string][]*eventListener),
|
||||
exit: false,
|
||||
log: newCustomLogger("Events"),
|
||||
running: false,
|
||||
log: logger.NewCustomLogger("Events"),
|
||||
}
|
||||
}
|
||||
|
||||
// PushEvent places the given event on to the event queue
|
||||
func (e *eventManager) PushEvent(eventData *eventData) {
|
||||
func (e *Manager) PushEvent(eventData *messages.EventData) {
|
||||
e.incomingEvents <- eventData
|
||||
}
|
||||
|
||||
@@ -40,7 +46,7 @@ type eventListener struct {
|
||||
}
|
||||
|
||||
// Creates a new event listener from the given callback function
|
||||
func (e *eventManager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
|
||||
func (e *Manager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
|
||||
|
||||
// Sanity check inputs
|
||||
if callback == nil {
|
||||
@@ -65,37 +71,37 @@ func (e *eventManager) addEventListener(eventName string, callback func(...inter
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *eventManager) On(eventName string, callback func(...interface{})) {
|
||||
// On adds a listener for the given event
|
||||
func (e *Manager) On(eventName string, callback func(...interface{})) {
|
||||
// Add a persistent eventListener (counter = 0)
|
||||
e.addEventListener(eventName, callback, 0)
|
||||
}
|
||||
|
||||
// Emit broadcasts the given event to the subscribed listeners
|
||||
func (e *eventManager) Emit(eventName string, optionalData ...interface{}) {
|
||||
e.incomingEvents <- &eventData{Name: eventName, Data: optionalData}
|
||||
func (e *Manager) Emit(eventName string, optionalData ...interface{}) {
|
||||
e.incomingEvents <- &messages.EventData{Name: eventName, Data: optionalData}
|
||||
}
|
||||
|
||||
// Starts the event manager's queue processing
|
||||
func (e *eventManager) start(renderer Renderer) {
|
||||
// Start the event manager's queue processing
|
||||
func (e *Manager) Start(renderer interfaces.Renderer) {
|
||||
|
||||
e.log.Info("Starting")
|
||||
|
||||
// Store renderer
|
||||
e.renderer = renderer
|
||||
|
||||
// Set up waitgroup so we can wait for goroutine to start
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
// Set up waitgroup so we can wait for goroutine to quit
|
||||
e.running = true
|
||||
e.wg.Add(1)
|
||||
|
||||
// Run main loop in separate goroutine
|
||||
go func() {
|
||||
wg.Done()
|
||||
e.log.Info("Listening")
|
||||
for e.exit == false {
|
||||
for e.running {
|
||||
// TODO: Listen for application exit
|
||||
select {
|
||||
case event := <-e.incomingEvents:
|
||||
e.log.DebugFields("Got Event", Fields{
|
||||
e.log.DebugFields("Got Event", logger.Fields{
|
||||
"data": event.Data,
|
||||
"name": event.Name,
|
||||
})
|
||||
@@ -135,14 +141,18 @@ func (e *eventManager) start(renderer Renderer) {
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
e.wg.Done()
|
||||
}()
|
||||
|
||||
// Wait for goroutine to start
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (e *eventManager) stop() {
|
||||
e.exit = true
|
||||
// Shutdown is called when exiting the Application
|
||||
func (e *Manager) Shutdown() {
|
||||
e.log.Debug("Shutting Down")
|
||||
e.running = false
|
||||
e.log.Debug("Waiting for main loop to exit")
|
||||
e.wg.Wait()
|
||||
}
|
||||
14
lib/interfaces/appconfig.go
Normal file
14
lib/interfaces/appconfig.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package interfaces
|
||||
|
||||
// AppConfig is the application config interface
|
||||
type AppConfig interface {
|
||||
GetWidth() int
|
||||
GetHeight() int
|
||||
GetTitle() string
|
||||
GetResizable() bool
|
||||
GetDefaultHTML() string
|
||||
GetDisableInspector() bool
|
||||
GetColour() string
|
||||
GetCSS() string
|
||||
GetJS() string
|
||||
}
|
||||
11
lib/interfaces/bindingmanager.go
Normal file
11
lib/interfaces/bindingmanager.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package interfaces
|
||||
|
||||
import "github.com/wailsapp/wails/lib/messages"
|
||||
|
||||
// BindingManager is the binding manager interface
|
||||
type BindingManager interface {
|
||||
Bind(object interface{})
|
||||
Start(renderer Renderer, runtime Runtime) error
|
||||
ProcessCall(callData *messages.CallData) (result interface{}, err error)
|
||||
Shutdown()
|
||||
}
|
||||
12
lib/interfaces/eventmanager.go
Normal file
12
lib/interfaces/eventmanager.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package interfaces
|
||||
|
||||
import "github.com/wailsapp/wails/lib/messages"
|
||||
|
||||
// EventManager is the event manager interface
|
||||
type EventManager interface {
|
||||
PushEvent(*messages.EventData)
|
||||
Emit(eventName string, optionalData ...interface{})
|
||||
On(eventName string, callback func(...interface{}))
|
||||
Start(Renderer)
|
||||
Shutdown()
|
||||
}
|
||||
9
lib/interfaces/ipcmanager.go
Normal file
9
lib/interfaces/ipcmanager.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package interfaces
|
||||
|
||||
// IPCManager is the event manager interface
|
||||
type IPCManager interface {
|
||||
BindRenderer(Renderer)
|
||||
Dispatch(message string)
|
||||
Start(eventManager EventManager, bindingManager BindingManager)
|
||||
Shutdown()
|
||||
}
|
||||
@@ -1,16 +1,21 @@
|
||||
package wails
|
||||
package interfaces
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/lib/messages"
|
||||
)
|
||||
|
||||
// Renderer is an interface describing a Wails target to render the app to
|
||||
type Renderer interface {
|
||||
Initialise(*AppConfig, *ipcManager, *eventManager) error
|
||||
Initialise(AppConfig, IPCManager, EventManager) error
|
||||
Run() error
|
||||
EnableConsole()
|
||||
|
||||
// Binding
|
||||
NewBinding(bindingName string) error
|
||||
Callback(data string) error
|
||||
|
||||
// Events
|
||||
NotifyEvent(eventData *eventData) error
|
||||
NotifyEvent(eventData *messages.EventData) error
|
||||
|
||||
// Dialog Runtime
|
||||
SelectFile() string
|
||||
4
lib/interfaces/runtime.go
Normal file
4
lib/interfaces/runtime.go
Normal file
@@ -0,0 +1,4 @@
|
||||
package interfaces
|
||||
|
||||
// Runtime interface
|
||||
type Runtime interface {}
|
||||
@@ -1,13 +1,10 @@
|
||||
package wails
|
||||
package ipc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type callData struct {
|
||||
BindingName string `json:"bindingName"`
|
||||
Data string `json:"data,omitempty"`
|
||||
}
|
||||
"github.com/wailsapp/wails/lib/messages"
|
||||
)
|
||||
|
||||
func init() {
|
||||
messageProcessors["call"] = processCallData
|
||||
@@ -15,7 +12,7 @@ func init() {
|
||||
|
||||
func processCallData(message *ipcMessage) (*ipcMessage, error) {
|
||||
|
||||
var payload callData
|
||||
var payload messages.CallData
|
||||
|
||||
// Decode binding call data
|
||||
payloadMap := message.Payload.(map[string]interface{})
|
||||
@@ -1,13 +1,10 @@
|
||||
package wails
|
||||
package ipc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type eventData struct {
|
||||
Name string `json:"name"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
"github.com/wailsapp/wails/lib/messages"
|
||||
)
|
||||
|
||||
// Register the message handler
|
||||
func init() {
|
||||
@@ -19,7 +16,7 @@ func processEventData(message *ipcMessage) (*ipcMessage, error) {
|
||||
|
||||
// TODO: Is it worth double checking this is actually an event message,
|
||||
// even though that's done by the caller?
|
||||
var payload eventData
|
||||
var payload messages.EventData
|
||||
|
||||
// Decode event data
|
||||
payloadMap := message.Payload.(map[string]interface{})
|
||||
@@ -1,9 +1,6 @@
|
||||
package wails
|
||||
package ipc
|
||||
|
||||
type logData struct {
|
||||
Level string `json:"level"`
|
||||
Message string `json:"string"`
|
||||
}
|
||||
import "github.com/wailsapp/wails/lib/messages"
|
||||
|
||||
// Register the message handler
|
||||
func init() {
|
||||
@@ -13,7 +10,7 @@ func init() {
|
||||
// This processes the given log message
|
||||
func processLogData(message *ipcMessage) (*ipcMessage, error) {
|
||||
|
||||
var payload logData
|
||||
var payload messages.LogData
|
||||
|
||||
// Decode event data
|
||||
payloadMap := message.Payload.(map[string]interface{})
|
||||
@@ -1,35 +1,46 @@
|
||||
package wails
|
||||
package ipc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/lib/interfaces"
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
"github.com/wailsapp/wails/lib/messages"
|
||||
)
|
||||
|
||||
type ipcManager struct {
|
||||
renderer Renderer // The renderer
|
||||
// Manager manages the IPC subsystem
|
||||
type Manager struct {
|
||||
renderer interfaces.Renderer // The renderer
|
||||
messageQueue chan *ipcMessage
|
||||
// quitChannel chan struct{}
|
||||
quitChannel chan struct{}
|
||||
// signals chan os.Signal
|
||||
log *CustomLogger
|
||||
eventManager *eventManager
|
||||
bindingManager *bindingManager
|
||||
log *logger.CustomLogger
|
||||
eventManager interfaces.EventManager
|
||||
bindingManager interfaces.BindingManager
|
||||
running bool
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func newIPCManager() *ipcManager {
|
||||
result := &ipcManager{
|
||||
// NewManager creates a new IPC Manager
|
||||
func NewManager() interfaces.IPCManager {
|
||||
result := &Manager{
|
||||
messageQueue: make(chan *ipcMessage, 100),
|
||||
// quitChannel: make(chan struct{}),
|
||||
quitChannel: make(chan struct{}),
|
||||
// signals: make(chan os.Signal, 1),
|
||||
log: newCustomLogger("IPC"),
|
||||
log: logger.NewCustomLogger("IPC"),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Sets the renderer, returns the dispatch function
|
||||
func (i *ipcManager) bindRenderer(renderer Renderer) {
|
||||
// BindRenderer sets the renderer, returns the dispatch function
|
||||
func (i *Manager) BindRenderer(renderer interfaces.Renderer) {
|
||||
i.renderer = renderer
|
||||
}
|
||||
|
||||
func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingManager) {
|
||||
// Start the IPC Manager
|
||||
func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager interfaces.BindingManager) {
|
||||
|
||||
// Store manager references
|
||||
i.eventManager = eventManager
|
||||
@@ -37,41 +48,44 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
||||
|
||||
i.log.Info("Starting")
|
||||
// signal.Notify(manager.signals, os.Interrupt)
|
||||
i.running = true
|
||||
|
||||
// Keep track of this goroutine
|
||||
i.wg.Add(1)
|
||||
go func() {
|
||||
running := true
|
||||
for running {
|
||||
for i.running {
|
||||
select {
|
||||
case incomingMessage := <-i.messageQueue:
|
||||
i.log.DebugFields("Processing message", Fields{
|
||||
i.log.DebugFields("Processing message", logger.Fields{
|
||||
"1D": &incomingMessage,
|
||||
})
|
||||
switch incomingMessage.Type {
|
||||
case "call":
|
||||
callData := incomingMessage.Payload.(*callData)
|
||||
i.log.DebugFields("Processing call", Fields{
|
||||
callData := incomingMessage.Payload.(*messages.CallData)
|
||||
i.log.DebugFields("Processing call", logger.Fields{
|
||||
"1D": &incomingMessage,
|
||||
"bindingName": callData.BindingName,
|
||||
"data": callData.Data,
|
||||
})
|
||||
go func() {
|
||||
result, err := bindingManager.processCall(callData)
|
||||
i.log.DebugFields("processed call", Fields{"result": result, "err": err})
|
||||
result, err := bindingManager.ProcessCall(callData)
|
||||
i.log.DebugFields("processed call", logger.Fields{"result": result, "err": err})
|
||||
if err != nil {
|
||||
incomingMessage.ReturnError(err.Error())
|
||||
} else {
|
||||
incomingMessage.ReturnSuccess(result)
|
||||
}
|
||||
i.log.DebugFields("Finished processing call", Fields{
|
||||
i.log.DebugFields("Finished processing call", logger.Fields{
|
||||
"1D": &incomingMessage,
|
||||
})
|
||||
}()
|
||||
case "event":
|
||||
|
||||
// Extract event data
|
||||
eventData := incomingMessage.Payload.(*eventData)
|
||||
eventData := incomingMessage.Payload.(*messages.EventData)
|
||||
|
||||
// Log
|
||||
i.log.DebugFields("Processing event", Fields{
|
||||
i.log.DebugFields("Processing event", logger.Fields{
|
||||
"name": eventData.Name,
|
||||
"data": eventData.Data,
|
||||
})
|
||||
@@ -80,24 +94,24 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
||||
i.eventManager.PushEvent(eventData)
|
||||
|
||||
// Log
|
||||
i.log.DebugFields("Finished processing event", Fields{
|
||||
i.log.DebugFields("Finished processing event", logger.Fields{
|
||||
"name": eventData.Name,
|
||||
})
|
||||
case "log":
|
||||
logdata := incomingMessage.Payload.(*logData)
|
||||
logdata := incomingMessage.Payload.(*messages.LogData)
|
||||
switch logdata.Level {
|
||||
case "info":
|
||||
logger.Info(logdata.Message)
|
||||
logger.GlobalLogger.Info(logdata.Message)
|
||||
case "debug":
|
||||
logger.Debug(logdata.Message)
|
||||
logger.GlobalLogger.Debug(logdata.Message)
|
||||
case "warning":
|
||||
logger.Warning(logdata.Message)
|
||||
logger.GlobalLogger.Warn(logdata.Message)
|
||||
case "error":
|
||||
logger.Error(logdata.Message)
|
||||
logger.GlobalLogger.Error(logdata.Message)
|
||||
case "fatal":
|
||||
logger.Fatal(logdata.Message)
|
||||
logger.GlobalLogger.Fatal(logdata.Message)
|
||||
default:
|
||||
i.log.ErrorFields("Invalid log level sent", Fields{
|
||||
logger.ErrorFields("Invalid log level sent", logger.Fields{
|
||||
"level": logdata.Level,
|
||||
"message": logdata.Message,
|
||||
})
|
||||
@@ -107,25 +121,22 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
||||
}
|
||||
|
||||
// Log
|
||||
i.log.DebugFields("Finished processing message", Fields{
|
||||
i.log.DebugFields("Finished processing message", logger.Fields{
|
||||
"1D": &incomingMessage,
|
||||
})
|
||||
// case <-manager.quitChannel:
|
||||
// Debug("[MessageQueue] Quit caught")
|
||||
// running = false
|
||||
// case <-manager.signals:
|
||||
// Debug("[MessageQueue] Signal caught")
|
||||
// running = false
|
||||
default:
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
i.log.Debug("Stopping")
|
||||
i.wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Dispatch receives JSON encoded messages from the renderer.
|
||||
// It processes the message to ensure that it is valid and places
|
||||
// the processed message on the message queue
|
||||
func (i *ipcManager) Dispatch(message string) {
|
||||
func (i *Manager) Dispatch(message string) {
|
||||
|
||||
// Create a new IPC Message
|
||||
incomingMessage, err := newIPCMessage(message, i.SendResponse)
|
||||
@@ -148,7 +159,7 @@ func (i *ipcManager) Dispatch(message string) {
|
||||
}
|
||||
|
||||
// SendResponse sends the given response back to the frontend
|
||||
func (i *ipcManager) SendResponse(response *ipcResponse) error {
|
||||
func (i *Manager) SendResponse(response *ipcResponse) error {
|
||||
|
||||
// Serialise the Message
|
||||
data, err := response.Serialise()
|
||||
@@ -160,3 +171,11 @@ func (i *ipcManager) SendResponse(response *ipcResponse) error {
|
||||
// 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.running = false
|
||||
i.log.Debug("Waiting of main loop shutdown")
|
||||
i.wg.Wait()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package wails
|
||||
package ipc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package wails
|
||||
package ipc
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
@@ -1,4 +1,4 @@
|
||||
package wails
|
||||
package logger
|
||||
|
||||
// CustomLogger is a wrapper object to logrus
|
||||
type CustomLogger struct {
|
||||
@@ -6,7 +6,8 @@ type CustomLogger struct {
|
||||
errorOnly bool
|
||||
}
|
||||
|
||||
func newCustomLogger(prefix string) *CustomLogger {
|
||||
// NewCustomLogger creates a new custom logger with the given prefix
|
||||
func NewCustomLogger(prefix string) *CustomLogger {
|
||||
return &CustomLogger{
|
||||
prefix: "[" + prefix + "] ",
|
||||
}
|
||||
@@ -14,90 +15,90 @@ func newCustomLogger(prefix string) *CustomLogger {
|
||||
|
||||
// Info level message
|
||||
func (c *CustomLogger) Info(message string) {
|
||||
logger.Info(c.prefix + message)
|
||||
GlobalLogger.Info(c.prefix + message)
|
||||
}
|
||||
|
||||
// Infof - formatted message
|
||||
func (c *CustomLogger) Infof(message string, args ...interface{}) {
|
||||
logger.Infof(c.prefix+message, args...)
|
||||
GlobalLogger.Infof(c.prefix+message, args...)
|
||||
}
|
||||
|
||||
// InfoFields - message with fields
|
||||
func (c *CustomLogger) InfoFields(message string, fields Fields) {
|
||||
logger.WithFields(map[string]interface{}(fields)).Info(c.prefix + message)
|
||||
GlobalLogger.WithFields(map[string]interface{}(fields)).Info(c.prefix + message)
|
||||
}
|
||||
|
||||
// Debug level message
|
||||
func (c *CustomLogger) Debug(message string) {
|
||||
logger.Debug(c.prefix + message)
|
||||
GlobalLogger.Debug(c.prefix + message)
|
||||
}
|
||||
|
||||
// Debugf - formatted message
|
||||
func (c *CustomLogger) Debugf(message string, args ...interface{}) {
|
||||
logger.Debugf(c.prefix+message, args...)
|
||||
GlobalLogger.Debugf(c.prefix+message, args...)
|
||||
}
|
||||
|
||||
// DebugFields - message with fields
|
||||
func (c *CustomLogger) DebugFields(message string, fields Fields) {
|
||||
logger.WithFields(map[string]interface{}(fields)).Debug(c.prefix + message)
|
||||
GlobalLogger.WithFields(map[string]interface{}(fields)).Debug(c.prefix + message)
|
||||
}
|
||||
|
||||
// Warn level message
|
||||
func (c *CustomLogger) Warn(message string) {
|
||||
logger.Warn(c.prefix + message)
|
||||
GlobalLogger.Warn(c.prefix + message)
|
||||
}
|
||||
|
||||
// Warnf - formatted message
|
||||
func (c *CustomLogger) Warnf(message string, args ...interface{}) {
|
||||
logger.Warnf(c.prefix+message, args...)
|
||||
GlobalLogger.Warnf(c.prefix+message, args...)
|
||||
}
|
||||
|
||||
// WarnFields - message with fields
|
||||
func (c *CustomLogger) WarnFields(message string, fields Fields) {
|
||||
logger.WithFields(map[string]interface{}(fields)).Warn(c.prefix + message)
|
||||
GlobalLogger.WithFields(map[string]interface{}(fields)).Warn(c.prefix + message)
|
||||
}
|
||||
|
||||
// Error level message
|
||||
func (c *CustomLogger) Error(message string) {
|
||||
logger.Error(c.prefix + message)
|
||||
GlobalLogger.Error(c.prefix + message)
|
||||
}
|
||||
|
||||
// Errorf - formatted message
|
||||
func (c *CustomLogger) Errorf(message string, args ...interface{}) {
|
||||
logger.Errorf(c.prefix+message, args...)
|
||||
GlobalLogger.Errorf(c.prefix+message, args...)
|
||||
}
|
||||
|
||||
// ErrorFields - message with fields
|
||||
func (c *CustomLogger) ErrorFields(message string, fields Fields) {
|
||||
logger.WithFields(map[string]interface{}(fields)).Error(c.prefix + message)
|
||||
GlobalLogger.WithFields(map[string]interface{}(fields)).Error(c.prefix + message)
|
||||
}
|
||||
|
||||
// Fatal level message
|
||||
func (c *CustomLogger) Fatal(message string) {
|
||||
logger.Fatal(c.prefix + message)
|
||||
GlobalLogger.Fatal(c.prefix + message)
|
||||
}
|
||||
|
||||
// Fatalf - formatted message
|
||||
func (c *CustomLogger) Fatalf(message string, args ...interface{}) {
|
||||
logger.Fatalf(c.prefix+message, args...)
|
||||
GlobalLogger.Fatalf(c.prefix+message, args...)
|
||||
}
|
||||
|
||||
// FatalFields - message with fields
|
||||
func (c *CustomLogger) FatalFields(message string, fields Fields) {
|
||||
logger.WithFields(map[string]interface{}(fields)).Fatal(c.prefix + message)
|
||||
GlobalLogger.WithFields(map[string]interface{}(fields)).Fatal(c.prefix + message)
|
||||
}
|
||||
|
||||
// Panic level message
|
||||
func (c *CustomLogger) Panic(message string) {
|
||||
logger.Panic(c.prefix + message)
|
||||
GlobalLogger.Panic(c.prefix + message)
|
||||
}
|
||||
|
||||
// Panicf - formatted message
|
||||
func (c *CustomLogger) Panicf(message string, args ...interface{}) {
|
||||
logger.Panicf(c.prefix+message, args...)
|
||||
GlobalLogger.Panicf(c.prefix+message, args...)
|
||||
}
|
||||
|
||||
// PanicFields - message with fields
|
||||
func (c *CustomLogger) PanicFields(message string, fields Fields) {
|
||||
logger.WithFields(map[string]interface{}(fields)).Panic(c.prefix + message)
|
||||
GlobalLogger.WithFields(map[string]interface{}(fields)).Panic(c.prefix + message)
|
||||
}
|
||||
47
lib/logger/log.go
Normal file
47
lib/logger/log.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GlobalLogger is the global logger
|
||||
var GlobalLogger = logrus.New()
|
||||
|
||||
// Fields is used by the customLogger object to output
|
||||
// fields along with a message
|
||||
type Fields map[string]interface{}
|
||||
|
||||
// Default options for the global logger
|
||||
func init() {
|
||||
GlobalLogger.SetOutput(os.Stdout)
|
||||
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
|
||||
// ErrorFields is a helper for logging fields to the global logger
|
||||
func ErrorFields(message string, fields Fields) {
|
||||
GlobalLogger.WithFields(map[string]interface{}(fields)).Error(message)
|
||||
}
|
||||
|
||||
// SetLogLevel sets the log level to the given level
|
||||
func SetLogLevel(level string) {
|
||||
switch strings.ToLower(level) {
|
||||
case "info":
|
||||
GlobalLogger.SetLevel(logrus.InfoLevel)
|
||||
case "debug":
|
||||
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||
case "warn":
|
||||
GlobalLogger.SetLevel(logrus.WarnLevel)
|
||||
case "error":
|
||||
GlobalLogger.SetLevel(logrus.ErrorLevel)
|
||||
case "fatal":
|
||||
GlobalLogger.SetLevel(logrus.FatalLevel)
|
||||
case "panic":
|
||||
GlobalLogger.SetLevel(logrus.PanicLevel)
|
||||
default:
|
||||
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||
GlobalLogger.Warnf("Log level '%s' not recognised. Setting to Debug.", level)
|
||||
}
|
||||
}
|
||||
7
lib/messages/calldata.go
Normal file
7
lib/messages/calldata.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package messages
|
||||
|
||||
// CallData represents a call to a Go function/method
|
||||
type CallData struct {
|
||||
BindingName string `json:"bindingName"`
|
||||
Data string `json:"data,omitempty"`
|
||||
}
|
||||
7
lib/messages/eventdata.go
Normal file
7
lib/messages/eventdata.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package messages
|
||||
|
||||
// EventData represents an event sent from the frontend
|
||||
type EventData struct {
|
||||
Name string `json:"name"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
7
lib/messages/logdata.go
Normal file
7
lib/messages/logdata.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package messages
|
||||
|
||||
// LogData represents a call to log from the frontend
|
||||
type LogData struct {
|
||||
Level string `json:"level"`
|
||||
Message string `json:"string"`
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package wails
|
||||
package renderer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -10,6 +10,9 @@ import (
|
||||
"github.com/dchest/htmlmin"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/leaanthony/mewn"
|
||||
"github.com/wailsapp/wails/lib/interfaces"
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
"github.com/wailsapp/wails/lib/messages"
|
||||
)
|
||||
|
||||
type messageType int
|
||||
@@ -28,17 +31,17 @@ func (m messageType) toString() string {
|
||||
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
||||
}
|
||||
|
||||
// Headless is a backend that opens a local web server
|
||||
// Bridge is a backend that opens a local web server
|
||||
// and renders the files over a websocket
|
||||
type Headless struct {
|
||||
type Bridge struct {
|
||||
// Common
|
||||
log *CustomLogger
|
||||
ipcManager *ipcManager
|
||||
appConfig *AppConfig
|
||||
eventManager *eventManager
|
||||
log *logger.CustomLogger
|
||||
ipcManager interfaces.IPCManager
|
||||
appConfig interfaces.AppConfig
|
||||
eventManager interfaces.EventManager
|
||||
bindingCache []string
|
||||
|
||||
// Headless specific
|
||||
// Bridge specific
|
||||
initialisationJS []string
|
||||
server *http.Server
|
||||
theConnection *websocket.Conn
|
||||
@@ -47,17 +50,17 @@ type Headless struct {
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// Initialise the Headless Renderer
|
||||
func (h *Headless) Initialise(appConfig *AppConfig, ipcManager *ipcManager, eventManager *eventManager) error {
|
||||
// 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 = newCustomLogger("Bridge")
|
||||
ipcManager.BindRenderer(h)
|
||||
h.log = logger.NewCustomLogger("Bridge")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Headless) evalJS(js string, mtype messageType) error {
|
||||
func (h *Bridge) evalJS(js string, mtype messageType) error {
|
||||
|
||||
message := mtype.toString() + js
|
||||
|
||||
@@ -71,7 +74,11 @@ func (h *Headless) evalJS(js string, mtype messageType) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Headless) injectCSS(css string) {
|
||||
// EnableConsole not needed for bridge!
|
||||
func (h *Bridge) EnableConsole() {
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -83,11 +90,11 @@ func (h *Headless) injectCSS(css string) {
|
||||
minifiedCSS = strings.Replace(minifiedCSS, "\\", "\\\\", -1)
|
||||
minifiedCSS = strings.Replace(minifiedCSS, "'", "\\'", -1)
|
||||
minifiedCSS = strings.Replace(minifiedCSS, "\n", " ", -1)
|
||||
inject := fmt.Sprintf("wails._.injectCSS('%s')", minifiedCSS)
|
||||
inject := fmt.Sprintf("wails._.InjectCSS('%s')", minifiedCSS)
|
||||
h.evalJS(inject, cssMessage)
|
||||
}
|
||||
|
||||
func (h *Headless) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
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)
|
||||
@@ -102,7 +109,7 @@ func (h *Headless) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
go h.start(conn)
|
||||
}
|
||||
|
||||
func (h *Headless) sendMessage(conn *websocket.Conn, msg string) {
|
||||
func (h *Bridge) sendMessage(conn *websocket.Conn, msg string) {
|
||||
|
||||
h.lock.Lock()
|
||||
defer h.lock.Unlock()
|
||||
@@ -112,12 +119,12 @@ func (h *Headless) sendMessage(conn *websocket.Conn, msg string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Headless) start(conn *websocket.Conn) {
|
||||
func (h *Bridge) start(conn *websocket.Conn) {
|
||||
|
||||
// set external.invoke
|
||||
h.log.Infof("Connected to frontend.")
|
||||
|
||||
wailsRuntime := mewn.String("./wailsruntimeassets/default/wails.min.js")
|
||||
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||
h.evalJS(wailsRuntime, wailsRuntimeMessage)
|
||||
|
||||
// Inject bindings
|
||||
@@ -144,8 +151,8 @@ func (h *Headless) start(conn *websocket.Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
// Run the app in headless mode!
|
||||
func (h *Headless) Run() error {
|
||||
// Run the app in Bridge mode!
|
||||
func (h *Bridge) Run() error {
|
||||
h.server = &http.Server{Addr: ":34115"}
|
||||
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
||||
|
||||
@@ -153,52 +160,52 @@ func (h *Headless) Run() error {
|
||||
h.log.Info("The frontend will connect automatically.")
|
||||
|
||||
err := h.server.ListenAndServe()
|
||||
if err != nil {
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
h.log.Fatal(err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// NewBinding creates a new binding with the frontend
|
||||
func (h *Headless) NewBinding(methodName string) error {
|
||||
func (h *Bridge) NewBinding(methodName string) error {
|
||||
h.bindingCache = append(h.bindingCache, methodName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SelectFile is unsupported for Headless but required
|
||||
// SelectFile is unsupported for Bridge but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) SelectFile() string {
|
||||
func (h *Bridge) SelectFile() string {
|
||||
h.log.Warn("SelectFile() unsupported in bridge mode")
|
||||
return ""
|
||||
}
|
||||
|
||||
// SelectDirectory is unsupported for Headless but required
|
||||
// SelectDirectory is unsupported for Bridge but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) SelectDirectory() string {
|
||||
func (h *Bridge) SelectDirectory() string {
|
||||
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
||||
return ""
|
||||
}
|
||||
|
||||
// SelectSaveFile is unsupported for Headless but required
|
||||
// SelectSaveFile is unsupported for Bridge but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) SelectSaveFile() string {
|
||||
func (h *Bridge) SelectSaveFile() string {
|
||||
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
||||
return ""
|
||||
}
|
||||
|
||||
// Callback sends a callback to the frontend
|
||||
func (h *Headless) Callback(data string) error {
|
||||
func (h *Bridge) Callback(data string) error {
|
||||
return h.evalJS(data, callbackMessage)
|
||||
}
|
||||
|
||||
// NotifyEvent notifies the frontend of an event
|
||||
func (h *Headless) NotifyEvent(event *eventData) error {
|
||||
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")
|
||||
logger.Error(err)
|
||||
h.log.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -215,37 +222,41 @@ func (h *Headless) NotifyEvent(event *eventData) error {
|
||||
}
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("window.wails._.notify('%s','%s')", event.Name, data)
|
||||
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data)
|
||||
return h.evalJS(message, notifyMessage)
|
||||
}
|
||||
|
||||
// SetColour is unsupported for Headless but required
|
||||
// SetColour is unsupported for Bridge but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) SetColour(colour string) error {
|
||||
h.log.WarnFields("SetColour ignored for headless more", Fields{"col": colour})
|
||||
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 Headless but required
|
||||
// Fullscreen is unsupported for Bridge but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) Fullscreen() {
|
||||
func (h *Bridge) Fullscreen() {
|
||||
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
||||
}
|
||||
|
||||
// UnFullscreen is unsupported for Headless but required
|
||||
// UnFullscreen is unsupported for Bridge but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) UnFullscreen() {
|
||||
func (h *Bridge) UnFullscreen() {
|
||||
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
||||
}
|
||||
|
||||
// SetTitle is currently unsupported for Headless but required
|
||||
// SetTitle is currently unsupported for Bridge but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) SetTitle(title string) {
|
||||
h.log.WarnFields("SetTitle() unsupported in bridge mode", Fields{"title": title})
|
||||
func (h *Bridge) SetTitle(title string) {
|
||||
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title})
|
||||
}
|
||||
|
||||
// Close is unsupported for Headless but required
|
||||
// Close is unsupported for Bridge but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) Close() {
|
||||
h.log.Warn("Close() unsupported in bridge mode")
|
||||
func (h *Bridge) Close() {
|
||||
h.log.Debug("Shutting down")
|
||||
err := h.server.Close()
|
||||
if err != nil {
|
||||
h.log.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
11
lib/renderer/renderer-mewn.go
Normal file
11
lib/renderer/renderer-mewn.go
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user