Compare commits

...

336 Commits

Author SHA1 Message Date
Lea Anthony
89992d8636 feat: attempt to support Zorin 2019-07-03 19:42:32 +10:00
Lea Anthony
7dd42f964b Merge pull request #147 from wailsapp/develop
Release v0.17.0
2019-07-02 17:39:41 +10:00
Lea Anthony
078a7a5519 feat: release v0.17.0 2019-07-02 17:38:18 +10:00
Lea Anthony
d811f721ac docs: be explicit about node version 2019-07-01 21:50:16 +10:00
Lea Anthony
26950ba045 chore: version bump 2019-07-01 21:36:07 +10:00
Lea Anthony
80adb70e78 chore: version bump 2019-07-01 21:35:30 +10:00
Lea Anthony
0c042acd4a fix: template name order 2019-07-01 21:35:06 +10:00
Lea Anthony
0ad0c4151a feat: use slicer v1.3.2 2019-07-01 18:27:10 +10:00
Lea Anthony
65a8a1e1f7 feat: sort templates by name 2019-07-01 18:26:24 +10:00
Lea Anthony
a2ac8af882 chore: Bump to version v0.16.5-pre 2019-07-01 18:10:26 +10:00
Lea Anthony
52afbd3f15 fix: revert back to my-app 2019-07-01 09:01:07 +10:00
Lea Anthony
ce35ee5ca8 Merge branch 'bh90210-118-angular-support' into develop 2019-07-01 08:58:37 +10:00
Lea Anthony
74c64c6420 chore: misc updates for template 2019-07-01 08:57:42 +10:00
Lea Anthony
678328b7aa Merge branch '118-angular-support' of git://github.com/bh90210/wails into bh90210-118-angular-support 2019-06-30 18:11:35 +10:00
Lea Anthony
345c8bc094 fix: linting fixes 2019-06-30 17:16:38 +10:00
Lea Anthony
44386490c8 chore: add default case to bridge switch 2019-06-29 23:03:46 +10:00
bh90210
87158a342a feat: angular template 2019-06-29 15:45:48 +03:00
Lea Anthony
0b43fae32a docs: updated contributors 2019-06-29 21:43:19 +10:00
Lea Anthony
89f7a95167 Merge pull request #141 from wailsapp/138-Template-dependency-checker
feat: initial support for template dependencies
2019-06-27 19:56:57 +10:00
Lea Anthony
c5be3e5634 feat: initial support for template dependencies 2019-06-27 09:05:46 +10:00
Lea Anthony
7156740f6c fix: typo 2019-06-27 08:46:01 +10:00
Lea Anthony
2d29b626c7 chore: version bump 2019-06-26 19:50:22 +10:00
Lea Anthony
698145be1e Merge pull request #140 from wailsapp/139-go.mod-should-reflect-current-wails-version
feat: set wails version in go.mod
2019-06-26 19:48:35 +10:00
Lea Anthony
a9188cbfdd feat: set wails version in go.mod 2019-06-26 19:46:51 +10:00
Lea Anthony
d07cca0278 chore: version bump 2019-06-25 18:49:18 +10:00
Lea Anthony
60d1dc51ad Merge pull request #137 from wailsapp/135-Add-Debian-support
135 add debian support
2019-06-25 18:48:24 +10:00
Lea Anthony
105073e412 fix: add Debian support across tooling 2019-06-25 18:32:25 +10:00
Lea Anthony
9d1f1fff47 feat: debian support 2019-06-25 18:29:57 +10:00
Lea Anthony
08050ec35e Merge pull request #134 from wailsapp/133-Unsupported-Platform-Requests
133 unsupported platform requests
2019-06-25 08:18:06 +10:00
Lea Anthony
bd9751d888 feat: Support distribution support requests 2019-06-25 08:13:20 +10:00
Lea Anthony
7d171b0907 feat: initial support for platform requests 2019-06-24 09:11:06 +10:00
Lea Anthony
5b8f311465 Merge pull request #130 from wailsapp/123-Unify-Runtime-APIs
fix: linting
2019-06-22 08:47:25 +10:00
Lea Anthony
801465ac51 fix: linting 2019-06-22 08:45:46 +10:00
Lea Anthony
a84e2ae9b3 Merge pull request #129 from wailsapp/123-Unify-Runtime-APIs
feat: unify runtime API signatures
2019-06-22 08:43:23 +10:00
Lea Anthony
9496d1d47f Merge pull request #126 from bh90210/121-react-template-build-error
fix(react template): reverting bugfix + code clean-up
2019-06-22 08:39:16 +10:00
Lea Anthony
36e575e0a2 feat: unify runtime API signatures 2019-06-22 08:36:11 +10:00
ktc
70ccb8942b fix(react template): reverting bugfix + code clean-up 2019-06-19 20:09:23 +03:00
Lea Anthony
d3cd3d43bd chore: version bump 2019-06-19 21:04:27 +10:00
Lea Anthony
9116f0d06c Merge pull request #124 from wailsapp/116-Add-browser-methods-to-runtime
116 add browser methods to runtime
2019-06-19 21:01:53 +10:00
Lea Anthony
2c91e26add docs: guardrails badge 2019-06-19 21:01:00 +10:00
Lea Anthony
f1647443dc chore: add .jshintrc file to indicate es6 2019-06-19 20:54:36 +10:00
Lea Anthony
b6b6ce2d4a fix: linting fix 2019-06-19 20:53:04 +10:00
Lea Anthony
abcc869537 feat: added OpenFile 2019-06-19 20:49:39 +10:00
Lea Anthony
3e02e1676a Merge pull request #122 from bh90210/121-react-template-build-error
fix(react template): build bugfix
2019-06-19 08:31:57 +10:00
Lea Anthony
5c8a4de446 fix: version 2019-06-19 08:29:15 +10:00
Lea Anthony
7cabef946e feat: initial support for browser.openURL for f/e 2019-06-19 08:28:31 +10:00
ktc
f2519e5af2 fix(react template): build bugfix 2019-06-18 13:57:45 +03:00
Lea Anthony
63f1767755 Merge pull request #120 from wailsapp/develop
Release v0.16.0
2019-06-18 08:25:24 +10:00
Lea Anthony
5b002e88b7 feat: v0.16.0 release 2019-06-18 08:18:49 +10:00
Lea Anthony
3723e70e6f Merge pull request #117 from bh90210/master
react template
2019-06-16 17:31:02 +10:00
admin_3.exe
7c08ddbb07 Merge branch 'develop' into master 2019-06-16 10:20:36 +03:00
Lea Anthony
c8027f5b81 feat: react template 2019-06-16 17:13:40 +10:00
ktc
393e418e68 react template 2019-06-15 14:52:47 +03:00
Lea Anthony
dcc3e5fa79 Merge pull request #113 from wailsapp/112-deprecate-backend-injection-of-css-js
112 deprecate backend injection of css js
2019-05-30 08:46:21 +10:00
Lea Anthony
f4e6c407ba chore: remove old JS/CSS api 2019-05-30 08:43:26 +10:00
Lea Anthony
e718a56ed9 docs: updated contributors 2019-05-27 18:43:33 +10:00
Lea Anthony
068443f3fd Merge pull request #110 from ocelotsloth/develop
CMD: LINUX: Arch Linux detection without lsb-release
2019-05-27 18:41:26 +10:00
Mark Stenglein
1efc8cb934 CMD: LINUX: Arch Linux detection without lsb-release
The existing distribution detection does not work on Arch Linux
without the `lsb-release` package installed. This patch adds
detection using `/etc/os-release` in the same way that f9a1881
uses for Fedora and CentOS detection.

I changed the if statement that Bryn Sinclair used to a case
statement to avoid extra if-else-if statements.

I also needed to add a trim statement to remove the `"` characters
that are present in Arch Linux's `/etc/os-release` file.
2019-05-26 20:30:05 -04:00
Lea Anthony
1ce0620620 Merge pull request #107 from wailsapp/develop
Release v0.15.0
2019-05-26 14:03:47 +10:00
Lea Anthony
249a35f90f chore: release v0.15.0 2019-05-26 13:56:27 +10:00
Lea Anthony
d003de3270 chore: remove old package-lock.json 2019-05-26 13:46:51 +10:00
Lea Anthony
9cb2ed10b5 Update CONTRIBUTORS.md 2019-05-26 13:32:55 +10:00
Lea Anthony
4a376f1b67 fix: windows spinner 2019-05-25 12:22:20 +10:00
Lea Anthony
c540f3902c fix: polyfill for windows 2019-05-25 12:19:03 +10:00
Lea Anthony
accc04ef90 chore: version bump 2019-05-25 11:30:01 +10:00
Lea Anthony
d54bd3dc54 Merge pull request #106 from wailsapp/105-create-vuetify-template
Create vuetify template
2019-05-25 11:20:37 +10:00
Lea Anthony
a54bbb4e14 chore: linting fixes 2019-05-25 11:17:39 +10:00
Lea Anthony
6b1b999546 feat: add vuetify template 2019-05-25 11:13:34 +10:00
Lea Anthony
a5aeafc4bc chore: version bump 2019-05-25 09:28:21 +10:00
Lea Anthony
39ea5cc456 Update bug_report.md 2019-05-24 08:17:05 +10:00
Lea Anthony
a225b8d50a Update bug_report.md 2019-05-24 08:13:56 +10:00
Lea Anthony
e0036b1cbb Update bug_report.md 2019-05-24 08:11:18 +10:00
Lea Anthony
9a5833f7c9 Merge pull request #102 from wailsapp/98-use-snap-command
fix: use snap command for linux
2019-05-23 08:58:00 +10:00
Lea Anthony
06a1372e80 fix: use snap command for linux 2019-05-23 08:57:11 +10:00
Lea Anthony
7a16cf74f0 docs: mandate go 1.12 2019-05-22 19:25:09 +10:00
Lea Anthony
4239c89b76 Merge pull request #100 from wailsapp/99-update-issue-template
fix: align with new bug template
2019-05-22 19:14:46 +10:00
Lea Anthony
29ea5cc74d fix: slign with new bug template 2019-05-22 19:13:17 +10:00
Lea Anthony
fa27be083d Update bug_report.md 2019-05-22 19:09:50 +10:00
Lea Anthony
9be56c47e4 chore: reset version 2019-05-22 08:35:38 +10:00
Lea Anthony
249720b0cc chore: version bump 2019-05-22 08:30:24 +10:00
Lea Anthony
3553cb6694 Merge pull request #97 from wailsapp/92-build-on-first-init
92 build on first init
2019-05-22 07:27:19 +10:00
Lea Anthony
3c0fa4c55e chore: lint fixes 2019-05-22 07:25:42 +10:00
Lea Anthony
c07a4b6c16 Merge branch 'develop' into 92-build-on-first-init 2019-05-22 00:56:30 +10:00
Lea Anthony
8175eb4446 chore: version bump 2019-05-22 00:50:28 +10:00
Lea Anthony
eeab418c90 fix: version issue 2019-05-22 00:43:56 +10:00
Lea Anthony
0eb59d823e fix: version craziness 2019-05-22 00:42:17 +10:00
Lea Anthony
f07705268d feat: moar spinners 2019-05-20 23:53:14 +10:00
Lea Anthony
63fef39854 feat: build on init 2019-05-20 23:40:17 +10:00
Lea Anthony
3ea45da2c8 chore: version bump v0.14.5-pre 2019-05-20 20:47:35 +10:00
Lea Anthony
eb0d9f3ba4 Merge pull request #96 from wailsapp/91-create-developer-tooling
91 create developer tooling
2019-05-20 18:58:43 +10:00
Lea Anthony
8432f725a9 chore: updated go mod files 2019-05-20 18:45:01 +10:00
Lea Anthony
7015b80888 feat: new template generator 2019-05-20 18:44:14 +10:00
Lea Anthony
ddcc103f37 Update README.md 2019-05-19 13:56:58 +10:00
Lea Anthony
1ac16d1933 fix: minor fixes 2019-05-18 07:34:39 +10:00
Lea Anthony
0f36a88f0e feat: add Manjaro support 2019-05-18 07:18:34 +10:00
Lea Anthony
b30031d025 feat: multiple template support 2019-05-18 07:15:15 +10:00
Lea Anthony
b849964562 docs: fix awesomego link 2019-05-12 22:18:19 +10:00
Lea Anthony
cd152f0cd7 Merge branch 'master' into v0.14.0-pre 2019-05-12 15:15:11 +10:00
Lea Anthony
12280b51b9 chore: version bump 2019-05-12 15:12:10 +10:00
Lea Anthony
29256c5766 fix: update check 2019-05-12 15:11:40 +10:00
Lea Anthony
8b13c0b197 chore: update version 2019-05-12 15:02:50 +10:00
Lea Anthony
50e2037fba fix: same version comparison 2019-05-12 14:55:39 +10:00
Lea Anthony
f86c10af02 fix: update logic 2019-05-12 14:48:25 +10:00
Lea Anthony
00e165b139 Merge branch 'v0.13.0-pre' into v0.13.0 2019-05-12 14:20:40 +10:00
Lea Anthony
02199bbe9d fix: updating from pre to release 2019-05-12 14:20:04 +10:00
Lea Anthony
d591a55140 docs: added changelog 2019-05-12 13:53:09 +10:00
Lea Anthony
508295b558 docs: updated contributors 2019-05-12 13:52:30 +10:00
Lea Anthony
bdc33e1430 docs: update contributors 2019-05-12 13:37:31 +10:00
Lea Anthony
d55dcb2dfb chore: update version 2019-05-12 13:37:19 +10:00
Lea Anthony
79ac4c1d45 Merge pull request #86 from fishfishfish2104/v0.13.0-pre
Added Dependancy check for redhat distros
2019-05-12 13:31:45 +10:00
Lea Anthony
c6bfa85a1a Merge branch 'v0.13.0-pre' of github.com:wailsapp/wails into v0.13.0-pre 2019-05-12 13:00:55 +10:00
Lea Anthony
82289714ba chore: update go mod files 2019-05-12 13:00:34 +10:00
Lea Anthony
77142bd99e feat: support version flag 2019-05-12 12:59:35 +10:00
Lea Anthony
538f5c6501 fix: typo fixes 2019-05-12 12:51:14 +10:00
Lea Anthony
3ff02fb183 fix: better version checking 2019-05-12 12:50:50 +10:00
Lea Anthony
30298b4237 feat: add IsValidTag 2019-05-12 12:50:28 +10:00
fred2104
9f2c9a989f Added instructions for red hat distros 2019-05-12 09:06:23 +12:00
Lea Anthony
146147bed8 Merge branch 'pr/82' into v0.13.0-pre 2019-05-11 17:08:40 +10:00
Lea Anthony
76499b20c4 fix: windows template.json 2019-05-11 17:04:42 +10:00
Bryn Sinclair
b21e79daf5 changed to use rpm instead of yum as its faster 2019-05-11 12:19:18 +12:00
Lea Anthony
71194108de feat: better version comparison 2019-05-10 23:01:50 +10:00
Lea Anthony
11fd50f78d fix: ensure GO111MODULE=on 2019-05-10 21:23:58 +10:00
Lea Anthony
c08d1d7b3c fix: remove test data 2019-05-10 21:18:35 +10:00
Lea Anthony
2febf5a97a fix: set gomod=on when execing 2019-05-10 21:12:20 +10:00
Lea Anthony
cea7b1e494 feat: new Github helper 2019-05-10 21:11:43 +10:00
Lea Anthony
25962e2e53 fix: set correct version 2019-05-10 21:11:20 +10:00
Bryn Sinclair
43f9b141fe removed unnecessary dependancies
changed logger.red to logger.error
2019-05-10 21:06:58 +12:00
Bryn Sinclair
e1b729ea96 Merge commit 'f9a18817b74828ff8fae92a1a873087f9adc363b' of https://github.com/wailsapp/wails into v0.13.0-pre 2019-05-10 21:04:53 +12:00
Bryn Sinclair
f9a18817b7 Added library checking support for red hat distros (Only tested on fedora)
Changed some Package help inconsistencies
2019-05-10 17:41:30 +12:00
Yasuhiro Matsumoto
23cb97d314 Fix windows paths 2019-05-10 09:31:10 +09:00
Lea Anthony
32e085b609 docs: remove -u 2019-05-09 22:07:56 +10:00
Lea Anthony
389dee8db9 docs: add MDH 2019-05-09 22:06:53 +10:00
Lea Anthony
dba6fdf7e4 docs: add awesomego 2019-05-09 22:06:41 +10:00
Lea Anthony
cc45dcf91e fix: leave win assets on -p flag 2019-05-09 22:06:27 +10:00
Lea Anthony
4aeb554f1b fix: remove debug output 2019-05-09 19:43:19 +10:00
Lea Anthony
3d2268420b fix: show prerequisite errors 2019-05-09 19:31:07 +10:00
Lea Anthony
ca388be121 chore: update go.mod 2019-05-09 17:53:37 +10:00
Lea Anthony
f9ca13ff30 fix: remove -u from go get 2019-05-09 13:58:49 +10:00
Lea Anthony
319dbcdc49 chore: lint fix 2019-05-08 22:42:13 +10:00
Lea Anthony
bffbbd59ce fix: Windows 10 colour 2019-05-08 22:40:56 +10:00
Lea Anthony
8bd1d0ec92 fix: no need for windows separator 2019-05-08 22:32:04 +10:00
Lea Anthony
0daec29fab Updates to update command 2019-05-07 08:48:52 +10:00
Lea Anthony
bb3dbe0510 update to mewn 0.10.5 2019-05-07 08:25:35 +10:00
Lea Anthony
2fa9e3b0ee Bump to v0.12.0 2019-05-03 19:21:39 +10:00
Lea Anthony
40d1750345 Updated contributors 2019-05-03 19:20:09 +10:00
Lea Anthony
d2d4ea3033 Add Arch instructions 2019-05-03 19:09:36 +10:00
Lea Anthony
ff55170002 chore: improve updateversion.sh 2019-05-02 20:15:50 +10:00
Lea Anthony
444db6a560 docs: add contributors 2019-05-02 20:15:31 +10:00
Adrian Lanzafame
b015f27e14 add archlinux support 2019-05-02 13:35:34 +10:00
Lea Anthony
67a1f23b13 Merge pull request #72 from qaisjp/patch-1
Fix HTML spellings
2019-05-01 20:53:28 +10:00
Qais Patankar
9c98a7a9e3 Fix HTML spelling in README.md 2019-05-01 03:06:56 +01:00
Qais Patankar
5aa5ad8ad3 Fix HTML spelling in app_config.go 2019-05-01 03:06:19 +01:00
Lea Anthony
ac203ec931 version bump 2019-04-30 08:30:46 +10:00
Lea Anthony
3fd73186f4 Version bump 2019-04-30 08:22:18 +10:00
Lea Anthony
46307469e5 Updated Readme 2019-04-29 23:23:29 +10:00
Lea Anthony
31a67f3aed Add Hound badge 2019-04-29 18:43:27 +10:00
Lea Anthony
44919d2750 dialog errors -> warnings 2019-04-27 10:16:12 +10:00
Lea Anthony
cff87c641b update bridge warning messages 2019-04-27 10:14:08 +10:00
Lea Anthony
abbd71d057 Merge pull request #71 from wailsapp/replace-wailsbridge-when-serving
always install bridge on serve
2019-04-27 09:30:33 +10:00
Lea Anthony
aacfe8386a always install bridge on serve 2019-04-27 09:29:19 +10:00
Lea Anthony
97944d771a Bump to 0.11.6 2019-04-26 18:58:56 +10:00
Lea Anthony
3f1b616a5e Merge pull request #70 from wailsapp/update-webview
Update webview to 0.2.7
2019-04-26 18:56:38 +10:00
Lea Anthony
fdcc2fd2e5 Update webview to 0.2.7 2019-04-26 18:54:06 +10:00
Lea Anthony
855032ed1e release 0.11.3 2019-04-25 20:14:10 +10:00
Lea Anthony
760e109aab create windows builds 2019-04-25 20:12:56 +10:00
Lea Anthony
4c799bca8f version bump 2019-04-25 20:08:42 +10:00
Lea Anthony
2d08ebc054 vscode settings 2019-04-25 20:08:07 +10:00
Lea Anthony
91ab2c2b31 Version bump 2019-04-25 20:06:11 +10:00
Lea Anthony
13ad57d49f fix: ensure errors are logged 2019-04-25 20:05:39 +10:00
Lea Anthony
a109e3078d New dependency installation text 2019-04-23 08:46:39 +10:00
Lea Anthony
2e61a3c309 Set script type for injections 2019-04-23 08:46:11 +10:00
Lea Anthony
0373bea4e5 fix: destructure emit data 2019-04-23 08:44:47 +10:00
Lea Anthony
2d5825d73d Speed up Wails Serve 2019-04-20 12:15:19 +10:00
Lea Anthony
c4a042cb1d Added Runtime.FileSystem 2019-04-20 12:13:55 +10:00
Lea Anthony
205f9476fa Change 'Headless' to 'Bridge' in logging 2019-04-20 12:12:30 +10:00
Lea Anthony
a1230fcbb6 Badges! 2019-04-11 08:43:50 +10:00
Lea Anthony
ba5c32a4a1 more linting fixes 2019-04-11 08:38:14 +10:00
Lea Anthony
58eee64326 more linting fixes 2019-04-11 08:26:57 +10:00
Lea Anthony
41d786a13c Add devtools to Vue config in template 2019-04-10 08:48:12 +10:00
Lea Anthony
a2b7906c89 more linting fixes 2019-04-10 08:46:49 +10:00
Lea Anthony
eeb6fa4677 linting fixes 2019-04-10 08:38:46 +10:00
Lea Anthony
6a36d75774 Use cropped logo 2019-04-08 19:33:44 +10:00
Lea Anthony
6078f3c780 Center subtitle 2019-04-08 19:29:17 +10:00
Lea Anthony
fc11197725 Fix image 2019-04-08 19:24:20 +10:00
Lea Anthony
8c40b99194 Update license and readme 2019-04-08 19:18:39 +10:00
Lea Anthony
de53fc6510 chore: remove unused files 2019-03-29 08:25:18 +11:00
Lea Anthony
d4f4feb429 fix: better input during setup 2019-03-29 08:25:09 +11:00
Lea Anthony
02973c49ff fix: version output of built app 2019-03-29 08:24:46 +11:00
Lea Anthony
01dce9f139 Merge pull request #68 from wailsapp/fix-packaging
fix: call package when -p flag provided
2019-03-20 08:12:48 +11:00
Lea Anthony
6c0906e87d fix: call package when -p flag provided 2019-03-20 08:11:46 +11:00
Lea Anthony
d7cfc4c71a Merge pull request #67 from wailsapp/fix-concurrent-websocket-writes
fix: use mutex to serialise websocket writes
2019-03-19 08:35:49 +11:00
Lea Anthony
fec3e7eac5 fix: use mutex to serialise websocket writes 2019-03-19 08:35:09 +11:00
Lea Anthony
9f5e2c7dd4 Merge pull request #66 from wailsapp/handle-javascript-nulls
fix: convert js nulls to Go zero values
2019-03-19 08:21:31 +11:00
Lea Anthony
c5276cca6c fix: convert js nulls to Go zero values 2019-03-19 08:20:45 +11:00
Lea Anthony
74dbbbed8a Merge pull request #65 from wailsapp/improved-ipc-encoding
Use hex encoded strings for callbacks
2019-03-17 16:57:50 +11:00
Lea Anthony
629ac4b93c Use hex encoded strings for callbacks 2019-03-17 16:56:41 +11:00
Lea Anthony
5ece7e84b3 Release 0.11.0 2019-03-10 17:03:55 +11:00
Lea Anthony
eaba857676 Add frontend build back to serve 2019-03-10 17:02:57 +11:00
Lea Anthony
db489a3cae Remove banner from application cli 2019-03-10 17:02:36 +11:00
Lea Anthony
4821ab8597 Automate version bumps 2019-03-10 17:02:12 +11:00
Lea Anthony
670b769f82 version bump 2019-03-09 05:18:23 +11:00
Lea Anthony
eb53399824 add wails bridge assets 2019-03-08 20:39:09 +11:00
Lea Anthony
24e4fbfb68 ignore frontend files when using wails serve 2019-03-08 20:38:55 +11:00
Lea Anthony
7f54ca4ac3 version bump 2019-03-07 21:30:30 +11:00
Lea Anthony
b224803e4d fix vue basic template 2019-03-07 21:29:55 +11:00
Lea Anthony
28b2025aaa Merge pull request #63 from wailsapp/0.9.9
0.9.9
2019-03-07 08:25:23 +11:00
Lea Anthony
77e85705d1 Version bump 2019-03-07 08:23:38 +11:00
Lea Anthony
9fd24595c7 fix asset imports in vue basic template 2019-03-07 08:23:29 +11:00
Lea Anthony
69067e85f5 Merge pull request #62 from wailsapp/Default-Prompts-not-populating
Default prompts not populating
2019-03-07 05:48:15 +11:00
Lea Anthony
c8db58e00e Version bump 2019-03-07 05:47:13 +11:00
Lea Anthony
e96e0e0999 fix default prompts 2019-03-07 05:46:20 +11:00
Lea Anthony
2da21ec528 Merge pull request #60 from wailsapp/0.9.97
0.9.7
2019-03-06 19:14:46 +11:00
Lea Anthony
cda0b40414 Version bump 2019-03-06 19:12:38 +11:00
Lea Anthony
7f4229dd6b Add issue command 2019-03-06 19:12:12 +11:00
Lea Anthony
68651b77f4 use os specific path seperator 2019-03-06 19:11:46 +11:00
Lea Anthony
bf001f5ad2 Improve prompt handling 2019-03-06 19:11:03 +11:00
Lea Anthony
d1907b4ce5 Update issue templates 2019-03-06 07:59:24 +11:00
Lea Anthony
56363d193d Update issue templates 2019-03-04 22:36:00 +11:00
Lea Anthony
8553f43080 Misc linting fixes and version bump 2019-03-03 11:34:00 +11:00
Lea Anthony
587681bb8d Bump version 2019-03-02 12:56:56 +11:00
Lea Anthony
afbf80ea4a Merge pull request #59 from wailsapp/0.9.5
use mewn for templates
2019-03-02 12:55:36 +11:00
Lea Anthony
c180d7dccb use mewn for templates
massively improve template handling
2019-03-02 12:54:10 +11:00
Lea Anthony
c20aabc8f8 Merge pull request #58 from wailsapp/update-command
initial update command
2019-02-23 10:23:32 +11:00
Lea Anthony
4cccb628c9 initial update command 2019-02-23 10:20:37 +11:00
Lea Anthony
5d487347d4 Merge pull request #57 from wailsapp/#55-default-directory
default directory option
2019-02-22 09:04:12 +11:00
Lea Anthony
fe8b7ac5c9 default directory option 2019-02-22 09:03:41 +11:00
Lea Anthony
732c70777b Merge pull request #56 from wailsapp/minimise-console-spam
Big banner for Setup/Help. Small banner for commands.
2019-02-22 08:45:13 +11:00
Lea Anthony
753c5fd337 Big banner for Setup/Help. Small banner for commands. 2019-02-22 08:44:30 +11:00
Lea Anthony
2dad29673d Merge pull request #53 from wailsapp/adjust-windows-build-behaviour
package by default. -p  leaves resource artefacts
2019-02-22 05:17:54 +11:00
Lea Anthony
5e466893cf package by default. -p leaves resource artifacts 2019-02-22 05:17:23 +11:00
Lea Anthony
c15fd822c1 Merge pull request #52 from wailsapp/minor-fixes
remove frontend build from serve
2019-02-21 21:22:54 +11:00
Lea Anthony
42b1c0befa remove frontend build from serve 2019-02-21 21:21:05 +11:00
Lea Anthony
6ef8744e02 Merge pull request #51 from wailsapp/minor-fixes
Minor fixes
2019-02-21 08:25:10 +11:00
Lea Anthony
cf916c8e8b Updated sums 2019-02-21 08:24:30 +11:00
Lea Anthony
cdc1d4be3e Remove debug line 2019-02-21 08:23:44 +11:00
Lea Anthony
1c5284db3e Set window colour 2019-02-21 08:23:35 +11:00
Lea Anthony
073cdc3a55 Merge pull request #50 from wailsapp/window-debugging
minor bugfix
2019-02-20 23:04:35 +11:00
Lea Anthony
fd9363e842 minor bugfix 2019-02-20 23:04:11 +11:00
Lea Anthony
3051628fa2 Merge pull request #49 from wailsapp/window-debugging
Window debugging
2019-02-20 23:01:56 +11:00
Lea Anthony
cac97e8652 small refactor 2019-02-20 23:01:33 +11:00
Lea Anthony
2ccabc772b try and simplify 2019-02-20 22:54:06 +11:00
Lea Anthony
ff91241592 updated licenses + gomod 2019-02-20 22:48:59 +11:00
Lea Anthony
2257b1cab1 remove bad xml error 2019-02-20 22:41:33 +11:00
Lea Anthony
bdcf98fc15 Significant support for Windows builds 2019-02-20 22:24:47 +11:00
Lea Anthony
3025a94a77 use wails.min.js 2019-02-19 23:37:02 +11:00
Lea Anthony
d971495ad3 basics working 2019-02-19 21:06:24 +11:00
Lea Anthony
a4b1f469e9 Merge pull request #48 from wailsapp/move-to-new-prompt-library
Move to new prompt library
2019-02-19 19:38:29 +11:00
Lea Anthony
b18f04b30d removed survey 2019-02-19 19:37:45 +11:00
Lea Anthony
94e9447e1c Removed prompt library requirements 2019-02-19 19:25:33 +11:00
Lea Anthony
03c479c890 Fix vue template 2019-02-19 00:18:08 +11:00
Lea Anthony
c95a3a795e Merge pull request #47 from wailsapp/move-to-mewn
Move to mewn
2019-02-18 21:07:47 +11:00
Lea Anthony
1d8e99d846 Move to mewn 2019-02-18 21:06:53 +11:00
Lea Anthony
8e909fc9f4 Move to mewn 2019-02-18 08:31:22 +11:00
Lea Anthony
3bc86a4f50 Move bridge runtimes out of bundled assets 2019-02-17 06:12:05 +11:00
Lea Anthony
2c7913c202 use latest webview 2019-02-16 15:15:27 +11:00
Lea Anthony
d1c57ddb5f Merge pull request #46 from wailsapp/ignore-packr-findstring-errors-in-bridge-mode
Ignore packr findstring errors in bridge mode
2019-02-16 07:03:16 +11:00
Lea Anthony
9ffb517183 minor fixes 2019-02-16 07:02:16 +11:00
Lea Anthony
27f852ac6a ignoring findstring errors for bridge mode
refactored build mode strings
2019-02-16 06:58:30 +11:00
Lea Anthony
20c0b48634 version bump 2019-02-15 21:15:16 +11:00
Lea Anthony
6cf01b4239 Merge pull request #44 from wailsapp/get-vue-HMR-working
removed quote db for now. added vue basic
2019-02-15 21:12:24 +11:00
Lea Anthony
3ae88f8822 removed quote db for now. added vue basic 2019-02-15 21:11:42 +11:00
Lea Anthony
5994eb605f minor fixes to serve/build 2019-02-13 08:44:53 +11:00
Lea Anthony
9694dc57aa Merge pull request #43 from wailsapp/port-to-custom-webview
move webview out to seperate project
2019-02-11 08:30:33 +11:00
Lea Anthony
b5b78fddee move webview out to seperate project 2019-02-11 08:28:07 +11:00
Lea Anthony
c905185467 Merge pull request #42 from wailsapp/improve-build-output
Reduce output of prod build by ~30%
2019-02-06 06:27:38 +11:00
Lea Anthony
47ca7879cd Reduce output of prod build by ~30% 2019-02-06 06:26:54 +11:00
Lea Anthony
6202b3bf3e Merge pull request #41 from wailsapp/fix-linting-issues
simplified PromptForInputs
2019-02-05 18:53:32 +11:00
Lea Anthony
ea94c2de1f simplified PromptForInputs 2019-02-05 18:51:08 +11:00
Lea Anthony
eb0d4bc42f Merge pull request #40 from wailsapp/fix-linting-issues
Fix linting issues
2019-02-05 08:45:08 +11:00
Lea Anthony
b323c3db20 refactor promptforinputs 2019-02-05 08:43:50 +11:00
Lea Anthony
1670ac6567 add comments 2019-02-05 08:11:02 +11:00
Lea Anthony
c941176018 simplify Serve 2019-02-05 08:06:18 +11:00
Lea Anthony
a060d9dcc0 fix bridge installation path 2019-02-05 08:03:07 +11:00
Lea Anthony
ba208dce44 Merge pull request #39 from wailsapp/fix-linting-issues
Fix linting issues
2019-02-04 21:10:46 +11:00
Lea Anthony
9bbac46b3f Misc refactors 2019-02-04 21:09:56 +11:00
Lea Anthony
d8c591e64c refactored processCall 2019-02-04 19:50:26 +11:00
Lea Anthony
2c28a8f550 Fix css 2019-02-04 19:31:37 +11:00
Lea Anthony
d6c5586159 Merge pull request #38 from wailsapp/Improve-build/serve
Improve build/serve
2019-02-04 19:27:12 +11:00
Lea Anthony
08a7893b1d refactored build/serve 2019-02-04 18:49:56 +11:00
Lea Anthony
fa6cf17079 Fixed wails serve. Improved code structure. 2019-02-04 08:45:12 +11:00
Lea Anthony
fe2a20f92a Merge pull request #36 from wailsapp/Improve-build/serve
Improve build/serve
2019-02-02 14:07:14 +11:00
Lea Anthony
b713d57168 Tidy up serve. 2019-02-02 13:58:55 +11:00
Lea Anthony
17ca06693e add debug mode to build 2019-02-02 09:29:14 +11:00
Lea Anthony
243d738d64 Merge pull request #35 from wailsapp/Make-Serve-command
Add helpful message after serving
2019-01-31 18:59:37 +11:00
Lea Anthony
3f50b95f26 Add helpful message after serving 2019-01-31 18:59:07 +11:00
Lea Anthony
f0d8ce99a1 Merge pull request #34 from wailsapp/Make-Serve-command
Make serve command
2019-01-31 18:49:18 +11:00
Lea Anthony
259eec97d6 Added serve.
Serve only builds backend.
Build is always release build.
2019-01-31 18:48:12 +11:00
Lea Anthony
8b2168abe7 upgraded spinner to 0.5.0 2019-01-31 18:47:27 +11:00
Lea Anthony
a51e127309 Merge pull request #32 from wailsapp/Massively-Simplify
add webview license
2019-01-30 20:28:49 +11:00
Lea Anthony
c5cee79ff7 add webview license 2019-01-30 20:28:21 +11:00
Lea Anthony
9393b08c3f Merge pull request #31 from wailsapp/Massively-Simplify
Initial commit of simplification
2019-01-30 19:05:52 +11:00
Lea Anthony
0ca039e914 Initial commit of simplification 2019-01-30 09:00:46 +11:00
Lea Anthony
cd8b4f088f Merge pull request #29 from wailsapp/Move-headless-capability-into-own-library
Move headless capability into own library
2019-01-29 08:37:33 +11:00
Lea Anthony
847842504b Merge branch 'master' into Move-headless-capability-into-own-library 2019-01-29 08:36:27 +11:00
Lea Anthony
8ab91d31fe reduce function complexity 2019-01-29 08:36:21 +11:00
Lea Anthony
bb4d891549 Merge pull request #28 from wailsapp/Create-consistent-templates
Updated custom html
2019-01-29 08:31:21 +11:00
Lea Anthony
4a316a76fa Updated custom html 2019-01-29 08:30:38 +11:00
Lea Anthony
529e4cc07e Merge pull request #27 from wailsapp/Create-consistent-templates
update basic templates to use a frontend dir
2019-01-29 08:29:40 +11:00
Lea Anthony
579747d0f7 update basic templates to use a frontend dir 2019-01-29 08:28:59 +11:00
Lea Anthony
6880c53082 Merge pull request #26 from wailsapp/Move-headless-capability-into-own-library
Move headless capability into own library
2019-01-23 08:36:02 +11:00
Lea Anthony
6e011e75c3 updated vue template 2019-01-23 08:35:12 +11:00
Lea Anthony
683ba7dc59 support bridge mode
streamline some messaging
2019-01-23 06:01:45 +11:00
Lea Anthony
717e598330 Linter fix 2019-01-16 08:19:30 +11:00
Lea Anthony
a6489a1044 Merge pull request #25 from wailsapp/create-wails-css
Update basic template to use default CSS
2019-01-15 18:53:12 +11:00
Lea Anthony
df911adcae Update basic template to use default CSS 2019-01-15 18:52:18 +11:00
Lea Anthony
d7c0b1ec58 Merge pull request #24 from wailsapp/create-wails-css
inject default css if none given
2019-01-15 18:51:08 +11:00
Lea Anthony
7135d4fa27 inject default css if none given 2019-01-15 18:50:26 +11:00
Lea Anthony
83e063bf2b Merge pull request #23 from wailsapp/Update-execution-order-in-Headless-mode
Update execution order in headless mode
2019-01-15 08:36:10 +11:00
Lea Anthony
6e0773b355 fix for rendering fragments via headless 2019-01-15 08:34:32 +11:00
Lea Anthony
60f34223b0 bugfix for force rebuild 2019-01-15 08:33:48 +11:00
Lea Anthony
539be2ce84 Updated comments 2019-01-14 22:46:45 +11:00
Lea Anthony
561198b81b Fix unicode escaping 2019-01-14 19:18:03 +11:00
Lea Anthony
c823215eb6 Merge pull request #21 from wailsapp/Fix-npm-project-name
Fix npm package name
2019-01-13 18:04:39 +11:00
Lea Anthony
93f890f6d9 Fix npm package name 2019-01-13 18:02:51 +11:00
Lea Anthony
8a3aec6866 Merge pull request #20 from wailsapp/Update-execution-order-in-Headless-mode
Numerous fixes for headless mode.
2019-01-13 17:58:34 +11:00
Lea Anthony
1ef8ed73ab Remove debug statements 2019-01-13 17:57:21 +11:00
Lea Anthony
9004c3955e Numerous fixes for headless mode.
Remove script dom elements for internal calls.
2019-01-13 17:54:38 +11:00
Lea Anthony
4c98ce7da1 Merge pull request #19 from wailsapp/Update-execution-order-in-Headless-mode
fix for ipc binding
2019-01-12 16:00:44 +11:00
Lea Anthony
0ae5381203 fix for ipc binding
made reconnect modal a bit better
2019-01-12 15:56:49 +11:00
Lea Anthony
3f2f1b45f6 Merge pull request #18 from wailsapp/Support-Packaging
Add Licenses
2019-01-12 09:37:27 +11:00
Lea Anthony
e6bec8f7cc Add Licenses 2019-01-12 09:26:51 +11:00
Lea Anthony
f1f15fc1c5 Merge pull request #17 from wailsapp/Support-Packaging
Initial port of packager
2019-01-11 21:17:53 +11:00
Lea Anthony
bcca09563c Initial port of packager 2019-01-11 21:16:52 +11:00
Lea Anthony
ee355659ce Merge pull request #16 from wailsapp/change-code-mount-point
now binds go code to window.backend
2019-01-11 20:03:20 +11:00
Lea Anthony
a660e4a9da now binds go code to window.backend 2019-01-11 20:02:43 +11:00
Lea Anthony
a44fd57e98 Merge pull request #15 from wailsapp/Port-Build
Port build
2019-01-11 07:01:18 +11:00
Lea Anthony
c0371f141a Merge pull request #14 from wailsapp/Port-Build
Update vue template to use BoxString
2019-01-11 06:49:31 +11:00
Lea Anthony
a3c41d1740 Merge pull request #13 from wailsapp/Port-Build
Fix frameworkspinner
2019-01-11 06:32:41 +11:00
Lea Anthony
fb081b4876 Merge pull request #12 from wailsapp/Port-Build
Port build
2019-01-11 06:16:30 +11:00
Lea Anthony
9167063976 Merge pull request #11 from wailsapp/Port-Build
Made init less verbose
2019-01-09 08:26:56 +11:00
Lea Anthony
ffdbb0af64 Merge pull request #10 from wailsapp/Port-Build
updated runtime assets
2019-01-09 08:10:14 +11:00
Lea Anthony
d4b2563e9b Merge pull request #9 from wailsapp/Port-Build
mute logging of injected scripts
2019-01-09 06:35:52 +11:00
Lea Anthony
ab6e7531b4 Merge pull request #8 from wailsapp/Port-Build
Add assets
2019-01-08 21:33:04 +11:00
Lea Anthony
13efa58c9a Merge pull request #7 from wailsapp/Port-Build
fixes building on linux
2019-01-08 21:04:35 +11:00
Lea Anthony
0011e39c55 Merge pull request #6 from wailsapp/Port-Build
Initial Port
2019-01-08 20:15:49 +11:00
Lea Anthony
733258cc83 Merge pull request #5 from wailsapp/Port-Build
Initial commit of wails build
2019-01-08 07:59:22 +11:00
227 changed files with 5844 additions and 4926 deletions

View File

@@ -1,17 +0,0 @@
lib/project/templates/vue
lib/project/templates/blank
tools
test
.vscode/
tmp
examples/**/example*
!examples/**/*.*
node_modules
cmd.old
lib.old
cmd/wails/wails
.DS_Store
rewrite
.rewrite
examples/WIP/*
docs

42
.chglog/CHANGELOG.tpl.md Executable file
View File

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

27
.chglog/config.yml Executable file
View File

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

29
.eslintrc.js Normal file
View File

@@ -0,0 +1,29 @@
module.exports = {
"env": {
"browser": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2016,
"sourceType": "module",
},
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
}
};

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
#####################################################
If you have a technical issue, please do not open a bug this way!
Please use the `wails issue` command!
#####################################################
**Description**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behaviour:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behaviour**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**System Details**
Please provide your platform, GO version and variables, etc
**Additional context**
Add any other context about the problem here.

4
.gitignore vendored
View File

@@ -14,4 +14,6 @@
examples/**/example*
!examples/**/*.*
cmd/wails/wails
.DS_Store
.DS_Store
tmp
dist

34
.goreleaser.yml Normal file
View File

@@ -0,0 +1,34 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
builds:
- env:
- CGO_ENABLED=0
goos:
- windows
- linux
- darwin
goarch:
- 386
- amd64
ignore:
- goos: darwin
goarch: 386
main: ./cmd/wails/main.go
archive:
replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'

3
.jshintrc Normal file
View File

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

26
.vscode/launch.json vendored
View File

@@ -5,14 +5,36 @@
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"name": "Wails Init",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/wails/main.go",
"env": {},
"cwd": "/tmp",
"args": [
"setup"
"init",
"-name",
"runtime",
"-dir",
"runtime",
"-output",
"runtime",
"-template",
"vuebasic"
]
},
{
"name": "Wails Update Pre",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/wails/main.go",
"env": {},
"cwd": "/tmp",
"args": [
"update",
"-pre"
]
}
]

4
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"go.formatTool": "goimports",
"eslint.alwaysShowStatus": true
}

28
CHANGELOG.md Normal file
View File

@@ -0,0 +1,28 @@
2019-06-18 **v0.16.0**
* React template FTW! - Thanks [admin_3.exe](https://github.com/bh90210)!
* Updated contributors
* Arch Linux detection without lsb-release
* Removed deprecated methods for dealing with JS/CSS in the backend
2019-05-29 **v0.14.11-pre**
* Windows fix for spinner
2019-05-29 **v0.14.10-pre**
* Windows fix for Vuetify
2019-05-29 **v0.14.9-pre**
* Vuetify project template 🎉
2019-05-29 **v0.14.8-pre**
* Updated Ubuntu npm install command
2019-05-22 **v0.14.7-pre**
* New projects are built automatically when initialised
* Go 1.12 is now a minimum requirement
2019-05-21 **v0.14.6-pre**
* Hotfix for module dependency issue
2019-05-20 **v0.14.5-pre**
* Added developer tooling - New Template Generator
* Documentation fixes - Thanks [admin_3.exe](https://github.com/bh90210)!

15
CONTRIBUTORS.md Normal file
View File

@@ -0,0 +1,15 @@
# Contributors
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)

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018 wailsapp
Copyright (c) 2018-Present Lea Anthony
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

125
README.md
View File

@@ -1 +1,124 @@
# Coming Soon
<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/>
</p>
<p align="center">
A framework for building desktop applications using Go & Web Technologies.<br/><br/>
<a href="https://github.com/wailsapp/wails/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
<a href="https://goreportcard.com/report/github.com/wailsapp/wails"><img src="https://goreportcard.com/badge/github.com/wailsapp/wails"/></a>
<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://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></a>
<a href="https://github.com/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>
<a href="https://dashboard.guardrails.io/default/gh/wailsapp/wails"><img src="https://badges.guardrails.io/wailsapp/wails.svg?token=53657bc22ec360d7673c894fdd70568e918ec581d10d84427ed4de5fe1eeff1a"></a>
</p>
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
## Features
- Use standard Go libraries/frameworks for the backend
- Use any frontend technology to build your UI
- Quickly create Vue, Vuetify or React frontends for your Go programs
- Expose Go methods/functions to the frontend via a single bind command
- Uses native rendering engines - no embedded browser
- Shared events system
- Native file dialogs
- 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
Wails uses cgo to bind to the native rendering engines so a number of platform dependent libraries are needed as well as an installation of Go. The basic requirements are:
- Go 1.12
- npm
### MacOS
Make sure you have the xcode command line tools installed. This can be done by running:
`xcode-select --install`
### Linux
#### Ubuntu 18.04, Debian 9
`sudo apt install pkg-config build-essential libgtk-3-dev libwebkit2gtk-4.0-dev`
#### Arch Linux
`sudo pacman -S webkit2gtk gtk3`
#### Red Hat Based Distros
`sudo yum install webkit2gtk-devel gtk3-devel`
Note: If you have successfully installed these dependencies on a different flavour of Linux, please consider submitting a PR.
### Windows
Windows requires gcc and related tooling. The recommended download is from [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download). Once this is installed, you are good to go.
## Installation
**Ensure Go modules are enabled: GO111MODULE=on and go/bin is in your PATH variable.**
Installation is as simple as running the following command:
<pre style='color:white'>
go get github.com/wailsapp/wails/cmd/wails
</pre>
## Next Steps
It is recommended at this stage to read the comprehensive documentation at [https://wails.app](https://wails.app).
## FAQ
* Is this an alternative to Electron?
Depends on your requirements. It's designed to make it easy for Go programmers to make lightweight desktop applications or add a frontend to their existing applications. Whilst Wails does not currently offer hooks into native elements such as menus, this may change in the future.
* Who is this project aimed at?
Go programmers who want to bundle an HTML/JS/CSS frontend with their applications, without resorting to creating a server and opening a browser to view it.
* What's with the name?
When I saw WebView, I thought "What I really want is tooling around building a WebView app, a bit like Rails is to Ruby". So initially it was a play on words (Webview on Rails). It just so happened to also be a homophone of the English name for the [Country](https://en.wikipedia.org/wiki/Wales) I am from. So it stuck.
## Shoulders of Giants
Without the following people, this project would never have existed:
* [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - His support and feedback has been immense. More patience than you can throw a stick at (Not long now Dustin!).
* [Serge Zaitsev](https://github.com/zserge) - Creator of [Webview](https://github.com/zserge/webview) which Wails uses for the windowing.
And without [these people](CONTRIBUTORS.md), it wouldn't be what it is today. A huge thank you to each and every one of you!
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.
This project was mainly coded to the following albums:
* [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA)
* [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN)
* [The Midnight - Endless Summer](https://open.spotify.com/album/4Krg8zvprquh7TVn9OxZn8)
* [Gary Newman - Savage (Songs from a Broken World)](https://open.spotify.com/album/3kMfsD07Q32HRWKRrpcexr)
* [Steve Vai - Passion & Warfare](https://open.spotify.com/album/0oL0OhrE2rYVns4IGj8h2m)
* [Ben Howard - Every Kingdom](https://open.spotify.com/album/1nJsbWm3Yy2DW1KIc1OKle)
* [Ben Howard - Noonday Dream](https://open.spotify.com/album/6astw05cTiXEc2OvyByaPs)
* [Adwaith - Melyn](https://open.spotify.com/album/2vBE40Rp60tl7rNqIZjaXM)
* [Gwidaith Hen Fran - Cedors Hen Wrach](https://open.spotify.com/album/3v2hrfNGINPLuDP0YDTOjm)
* [Metallica - Metallica](https://open.spotify.com/album/2Kh43m04B1UkVcpcRa1Zug)
* [Bloc Party - Silent Alarm](https://open.spotify.com/album/6SsIdN05HQg2GwYLfXuzLB)
* [Maxthor - Another World](https://open.spotify.com/album/3tklE2Fgw1hCIUstIwPBJF)
* [Alun Tan Lan - Y Distawrwydd](https://open.spotify.com/album/0c32OywcLpdJCWWMC6vB8v)

File diff suppressed because one or more lines are too long

54
app.go
View File

@@ -2,13 +2,12 @@ package wails
import (
"github.com/wailsapp/wails/cmd"
"github.com/wailsapp/wails/cmd/frameworks"
)
// -------------------------------- Compile time Flags ------------------------------
// DebugMode indicates if we are in debug Mode
var DebugMode = "true"
// BuildMode indicates what mode we are in
var BuildMode = cmd.BuildModeProd
// ----------------------------------------------------------------------------------
@@ -18,17 +17,11 @@ type App struct {
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
headless bool // Indicates if the app should be started in headless mode
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
// This is a list of all the JS/CSS that needs injecting
// It will get injected in order
jsCache []string
cssCache []string
}
// CreateApp creates the application window with the given configuration
@@ -55,7 +48,7 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
result.config = appconfig
// Set up the CLI if not in release mode
if DebugMode == "true" {
if BuildMode != cmd.BuildModeProd {
result.cli = result.setupCli()
} else {
// Disable Inspector in release mode
@@ -67,12 +60,16 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
// Run the app
func (a *App) Run() error {
if DebugMode == "true" {
if BuildMode != cmd.BuildModeProd {
return a.cli.Run()
} else {
a.logLevel = "error"
return a.start()
}
a.logLevel = "error"
err := a.start()
if err != nil {
a.log.Error(err.Error())
}
return err
}
func (a *App) start() error {
@@ -84,7 +81,7 @@ func (a *App) start() error {
a.log.Info("Starting")
// Check if we are to run in headless mode
if a.headless {
if BuildMode == cmd.BuildModeBridge {
a.renderer = &Headless{}
}
@@ -109,21 +106,8 @@ func (a *App) start() error {
return err
}
// Inject framework, if specified
if frameworks.FrameworkToUse != nil {
a.renderer.InjectFramework(frameworks.FrameworkToUse.JS, frameworks.FrameworkToUse.CSS)
}
// Inject CSS
a.renderer.AddCSSList(a.cssCache)
// Inject JS
a.renderer.AddJSList(a.jsCache)
// Run the renderer
a.renderer.Run()
return nil
return a.renderer.Run()
}
// Bind allows the user to bind the given object
@@ -131,15 +115,3 @@ func (a *App) start() error {
func (a *App) Bind(object interface{}) {
a.bindingManager.bind(object)
}
// AddJS adds a piece of Javascript to a cache that
// gets injected at runtime
func (a *App) AddJS(js string) {
a.jsCache = append(a.jsCache, js)
}
// AddCSS adds a CSS string to a cache that
// gets injected at runtime
func (a *App) AddCSS(js string) {
a.cssCache = append(a.cssCache, js)
}

View File

@@ -1,8 +1,6 @@
package wails
import (
"fmt"
"github.com/wailsapp/wails/cmd"
)
@@ -11,18 +9,17 @@ func (app *App) setupCli() *cmd.Cli {
// Create a new cli
result := cmd.NewCli(app.config.Title, "Debug build")
result.Version(cmd.Version)
// Setup cli to handle loglevel and headless flags
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).
// BoolFlag("headless", "Runs the app in headless mode", &app.headless).
Action(app.start)
// Banner
result.PreRun(func(cli *cmd.Cli) error {
log := cmd.NewLogger()
log.PrintBanner()
fmt.Println()
log.YellowUnderline(app.config.Title + " - Debug Build")
return nil
})

View File

@@ -4,11 +4,9 @@ import (
"strings"
"github.com/dchest/htmlmin"
"github.com/gobuffalo/packr"
"github.com/leaanthony/mewn"
)
var assets = packr.NewBox("./assets/default")
// AppConfig is the configuration structure used when creating a Wails App object
type AppConfig struct {
Width, Height int
@@ -43,7 +41,7 @@ func (a *AppConfig) merge(in *AppConfig) error {
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 HMTL
// 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")
@@ -85,7 +83,7 @@ func newAppConfig(userConfig *AppConfig) (*AppConfig, error) {
Resizable: true,
Title: "My Wails App",
Colour: "#FFF", // White by default
HTML: BoxString(&defaultAssets, "default.html"),
HTML: mewn.String("./wailsruntimeassets/default/default.html"),
}
if userConfig != nil {

View File

@@ -1 +0,0 @@
<div id="app"></div>

File diff suppressed because one or more lines are too long

View File

@@ -1,179 +0,0 @@
<html>
<head>
<title>Wails Headless</title>
<style>
.wails-reconnect-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
font-family: sans-serif;
display: none;
z-index: 999999;
}
.wails-reconnect-overlay-content {
padding: 20px 30px;
text-align: center;
width: 20em;
position: relative;
height: 17em;
border-radius: 1em;
margin: 5% auto 0;
background-color: white;
box-shadow: 1px 1px 20px 3px;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAqFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAEBAQAAAAAAAAAAAAEBAQEBAQDAwMBAQEAAAABAQEAAAAAAAAAAAABAQEAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWKCj6oAAAAN3RSTlMALiIqDhkGBAswJjP0GxP6NR4W9/ztjRDMhWU50G9g5eHXvbZ9XEI9xZTcqZl2aldKo55QwoCvZUgzhAAAAs9JREFUSMeNleeWqjAUhU0BCaH3Itiw9zKT93+zG02QK1hm/5HF+jzZJ6fQe6cyXE+jg9X7o9wxuylIIf4Tv2V3+bOrEXnf8dwQ/KQIGDN2/S+4OmVCVXL/ScBnfibxURqIByP/hONE8r8T+bDMlQ98KSl7Y8hzjpS8v1qtDh8u5f8KQpGpfnPPhqG8JeogN37Hq9eaN2xRhIwAaGnvws8F1ShxqK5ob2twYi1FAMD4rXsYtnC/JEiRbl4cUrCWhnMCLRFemXezXbb59QK4WASOsm6n2W1+4CBT2JmtzQ6fsrbGubR/NFbd2g5Y179+5w/GEHaKsHjYCet7CgrXU3txarNC7YxOVJtIj4/ERzMdZfzc31hp+8cD6eGILgarZY9uZ12hAs03vfBD9C171gS5Omz7OcvxALQIn4u8RRBBBcsi9WW2woO9ipLgfzpYlggg3ZRdROUC8KT7QLqq3W9KB5BbdFVg4929kdwp6+qaZnMCCNBdj+NyN1W885Ry/AL3D4AQbsVV4noCiM/C83kyYq80XlDAYQtralOiDzoRAHlotWl8q2tjvYlOgcg1A8jEApZa+C06TBdAz2Qv0wu11I/zZOyJQ6EwGez2P2b8PIQr1hwwnAZsAxwA4UAYOyXUxM/xp6tHAn4GUmPGM9R28oVxgC0e/zQJJI6DyhyZ1r7uzRQhpcW7x7vTaWSzKSG6aep77kroTEl3U81uSVaUTtgEINfC8epx+Q4F9SpplHG84Ek6m4RAq9/TLkOBrxyeuddZhHvGIp1XXfFy3Z3vtwNblKGiDn+J+92vwwABHghj7HnzlS1H5kB49AZvdGCFgiBPq69qfXPr3y++yilF0ON4R8eR7spAsLpZ95NqAW5tab1c4vkZm6aleajchMwYTdILQQTwE2OV411ZM9WztDjPql12caBi6gDpUKmDd4U1XNdQxZ4LIXQ5/Tr4P7I9tYcFrDK3AAAAAElFTkSuQmCC");
background-repeat: no-repeat;
background-position: center;
}
.wails-reconnect-overlay-title {
font-size: 2em;
}
.wails-reconnect-overlay-message {
font-size: 1.3em;
}
/* https://codepen.io/EastingAndNorthing/pen/aNWrZz - Cheers Mark! */
.wails-reconnect-overlay-loadingspinner {
pointer-events: none;
width: 2.5em;
height: 2.5em;
border: 0.4em solid transparent;
border-color: #eee;
border-top-color: #3E67EC;
border-radius: 50%;
animation: loadingspin 1s linear infinite;
margin: auto;
padding: 2.5em;
}
@keyframes loadingspin {
100% {
transform: rotate(360deg)
}
}
</style>
</head>
<body>
<div class="wails-reconnect-overlay">
<div class="wails-reconnect-overlay-content">
<div class="wails-reconnect-overlay-title">Disconnected</div><br>
<div class="wails-reconnect-overlay-loadingspinner"></div><br>
<div class="wails-reconnect-overlay-message">Waiting for backend</div>
</div>
</div>
<div id="app"></div>
<script id="wails-headless-runtime">
(function () {
var websocket = null;
var connectTimer = null;
var reconnectOverlay = document.querySelector(".wails-reconnect-overlay");
var connectionState = "disconnected";
function showReconnectOverlay() {
reconnectOverlay.style.display = 'block';
}
function hideReconnectOverlay() {
reconnectOverlay.style.display = 'none';
}
window.external = {
invoke: function (msg) {
websocket.send(msg);
}
};
function addScript(script, id) {
var s = document.createElement("script")
if (id) {
s.id = id;
}
s.textContent = script;
document.head.appendChild(s)
}
function handleConnect() {
console.log("[Wails] Connected to backend");
addKeyListener();
hideReconnectOverlay();
clearInterval(connectTimer);
websocket.onclose = handleDisconnect;
websocket.onmessage = handleMessage;
connectionState = "connected";
// websocket.onerror = function () { }
}
function handleDisconnect() {
console.log("[Wails] Disconnected from backend");
websocket = null;
removeKeyListener();
connectionState = "disconnected";
showReconnectOverlay();
connect();
}
function connect() {
connectTimer = setInterval(function () {
if (websocket == null) {
websocket = new WebSocket("ws://localhost:34115/ws")
websocket.onopen = handleConnect;
websocket.onerror = function (e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
websocket = null;
return false
}
}
}, 300);
}
function handleMessage(e) {
addScript(e.data);
}
// Key listener
var delta = 300;
var lastKeypressTime = 0;
function KeyHandler(event) {
if (event.key === "`") {
var thisKeypressTime = new Date();
if (thisKeypressTime - lastKeypressTime <= delta) {
console.log("Double tap!")
// optional - if we'd rather not detect a triple-press
// as a second double-press, reset the timestamp
thisKeypressTime = 0;
}
lastKeypressTime = thisKeypressTime;
}
}
function addKeyListener() {
document.body.addEventListener('keydown', KeyHandler);
}
function removeKeyListener() {
document.body.removeEventListener('keydown', KeyHandler);
}
connect();
}());
</script>
</body>
</html>

View File

@@ -153,8 +153,11 @@ func (b *boundFunction) setInputValue(index int, typ reflect.Type, val interface
}
}()
// Do the conversion
result = reflect.ValueOf(val).Convert(typ)
// Translate javascript null values
if val == nil {
result = reflect.Zero(typ)
} else {
result = reflect.ValueOf(val).Convert(typ)
}
return result, err
}

65
binding_internal.go Normal file
View File

@@ -0,0 +1,65 @@
package wails
import "strings"
import "fmt"
type internalMethods struct{
log *CustomLogger
browser *RuntimeBrowser
}
func newInternalMethods() *internalMethods {
return &internalMethods{
log: newCustomLogger("InternalCall"),
browser: newRuntimeBrowser(),
}
}
func (i *internalMethods) processCall(callData *callData) (interface{}, error) {
if !strings.HasPrefix(callData.BindingName, ".wails.") {
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
}
// Strip prefix
var splitCall = strings.Split(callData.BindingName,".")[2:]
if len(splitCall) != 2 {
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
}
group := splitCall[0]
switch group {
case "Browser":
return i.processBrowserCommand(splitCall[1], callData.Data)
default:
return nil, fmt.Errorf("Unknown internal command group '%s'", group)
}
}
func (i *internalMethods) processBrowserCommand(command string, data interface{}) (interface{}, error) {
switch command {
case "OpenURL":
url := data.(string)
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
if url[0] == '"' {
url = url[1:]
}
if i := len(url)-1; url[i] == '"' {
url = url[:i]
}
i.log.Debugf("Calling Browser.OpenURL with '%s'", url)
return nil, i.browser.OpenURL(url)
case "OpenFile":
filename := data.(string)
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
if filename[0] == '"' {
filename = filename[1:]
}
if i := len(filename)-1; filename[i] == '"' {
filename = filename[:i]
}
i.log.Debugf("Calling Browser.OpenFile with '%s'", filename)
return nil, i.browser.OpenFile(filename)
default:
return nil, fmt.Errorf("Unknown Browser command '%s'", command)
}
}

View File

@@ -17,6 +17,7 @@ binding:
type bindingManager struct {
methods map[string]*boundMethod
functions map[string]*boundFunction
internalMethods *internalMethods
initMethods []*boundMethod
log *CustomLogger
renderer Renderer
@@ -27,9 +28,10 @@ type bindingManager struct {
func newBindingManager() *bindingManager {
result := &bindingManager{
methods: make(map[string]*boundMethod),
functions: make(map[string]*boundFunction),
log: newCustomLogger("Bind"),
methods: make(map[string]*boundMethod),
functions: make(map[string]*boundFunction),
log: newCustomLogger("Bind"),
internalMethods: newInternalMethods(),
}
return result
}
@@ -163,8 +165,76 @@ func (b *bindingManager) bind(object interface{}) {
b.objectsToBind = append(b.objectsToBind, object)
}
func (b *bindingManager) processInternalCall(callData *callData) (interface{}, error) {
// Strip prefix
return b.internalMethods.processCall(callData)
}
func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
// Return values
var result []reflect.Value
var err error
function := b.functions[callData.BindingName]
if function == nil {
return nil, fmt.Errorf("Invalid function name '%s'", callData.BindingName)
}
result, err = function.call(callData.Data)
if err != nil {
return nil, err
}
// Do we have an error return type?
if function.hasErrorReturnType {
// We do - last result is an error type
// Check if the last result was nil
b.log.Debugf("# of return types: %d", len(function.returnTypes))
b.log.Debugf("# of results: %d", len(result))
errorResult := result[len(function.returnTypes)-1]
if !errorResult.IsNil() {
// It wasn't - we have an error
return nil, errorResult.Interface().(error)
}
}
return result[0].Interface(), nil
}
func (b *bindingManager) processMethodCall(callData *callData) (interface{}, error) {
// Return values
var result []reflect.Value
var err error
// do we have this method?
method := b.methods[callData.BindingName]
if method == nil {
return nil, fmt.Errorf("Invalid method name '%s'", callData.BindingName)
}
result, err = method.call(callData.Data)
if err != nil {
return nil, err
}
// Do we have an error return type?
if method.hasErrorReturnType {
// We do - last result is an error type
// Check if the last result was nil
b.log.Debugf("# of return types: %d", len(method.returnTypes))
b.log.Debugf("# of results: %d", len(result))
errorResult := result[len(method.returnTypes)-1]
if !errorResult.IsNil() {
// It wasn't - we have an error
return nil, errorResult.Interface().(error)
}
}
if result != nil {
return result[0].Interface(), nil
}
return nil, nil
}
// process an incoming call request
func (b *bindingManager) processCall(callData *callData) (interface{}, error) {
func (b *bindingManager) processCall(callData *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
@@ -176,13 +246,10 @@ func (b *bindingManager) processCall(callData *callData) (interface{}, error) {
}
}
// Return values
var result []reflect.Value
var err error
// We need to catch reflect related panics and return
// a decent error message
// TODO: DEBUG THIS!
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("%s", r.(string))
@@ -191,59 +258,16 @@ func (b *bindingManager) processCall(callData *callData) (interface{}, error) {
switch dotCount {
case 1:
function := b.functions[callData.BindingName]
if function == nil {
return nil, fmt.Errorf("Invalid function name '%s'", callData.BindingName)
}
result, err = function.call(callData.Data)
if err != nil {
return nil, err
}
// Do we have an error return type?
if function.hasErrorReturnType {
// We do - last result is an error type
// Check if the last result was nil
b.log.Debugf("# of return types: %d", len(function.returnTypes))
b.log.Debugf("# of results: %d", len(result))
errorResult := result[len(function.returnTypes)-1]
if !errorResult.IsNil() {
// It wasn't - we have an error
return nil, errorResult.Interface().(error)
}
}
return result[0].Interface(), nil
result, err = b.processFunctionCall(callData)
case 2:
// do we have this method?
method := b.methods[callData.BindingName]
if method == nil {
return nil, fmt.Errorf("Invalid method name '%s'", callData.BindingName)
}
result, err = method.call(callData.Data)
if err != nil {
return nil, err
}
// Do we have an error return type?
if method.hasErrorReturnType {
// We do - last result is an error type
// Check if the last result was nil
b.log.Debugf("# of return types: %d", len(method.returnTypes))
b.log.Debugf("# of results: %d", len(result))
errorResult := result[len(method.returnTypes)-1]
if !errorResult.IsNil() {
// It wasn't - we have an error
return nil, errorResult.Interface().(error)
}
}
if result != nil {
return result[0].Interface(), nil
}
return nil, nil
result, err = b.processMethodCall(callData)
case 3:
result, err = b.processInternalCall(callData)
default:
return nil, fmt.Errorf("Invalid binding name '%s'", callData.BindingName)
result = nil
err = fmt.Errorf("Invalid binding name '%s'", callData.BindingName)
}
return
}
// callWailsInitMethods calls all of the WailsInit methods that were

10
cmd/build.go Normal file
View File

@@ -0,0 +1,10 @@
package cmd
const (
// BuildModeProd indicates we are building for prod mode
BuildModeProd = "prod"
// BuildModeDebug indicates we are building for debug mode
BuildModeDebug = "debug"
// BuildModeBridge indicates we are building for bridge mode
BuildModeBridge = "bridge"
)

View File

@@ -1,191 +0,0 @@
package cmd
import (
"bytes"
"fmt"
"image"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"text/template"
"time"
"github.com/jackmordaunt/icns"
)
// BundleHelper helps with the 'wails bundle' command
type BundleHelper struct {
fs *FSHelper
log *Logger
system *SystemHelper
}
// NewBundleHelper creates a new BundleHelper!
func NewBundleHelper() *BundleHelper {
return &BundleHelper{
fs: NewFSHelper(),
log: NewLogger(),
system: NewSystemHelper(),
}
}
type plistData struct {
Title string
Exe string
BundleID string
Version string
Author string
Date string
}
func newPlistData(title, exe, bundleID, version, author string) *plistData {
now := time.Now().Format(time.RFC822)
return &plistData{
Title: title,
Exe: exe,
Version: version,
BundleID: bundleID,
Author: author,
Date: now,
}
}
func defaultString(val string, defaultVal string) string {
if val != "" {
return val
}
return defaultVal
}
func (b *BundleHelper) getBundleFileBaseDir() string {
return filepath.Join(b.system.homeDir, "go", "src", "github.com", "wailsapp", "wails", "cmd", "bundle", runtime.GOOS)
}
// Bundle the application into a platform specific package
func (b *BundleHelper) Bundle(po *ProjectOptions) error {
// Check we have the exe
if !b.fs.FileExists(po.BinaryName) {
return fmt.Errorf("cannot bundle non-existant binary file '%s'. Please build with 'wails build' first", po.BinaryName)
}
switch runtime.GOOS {
case "darwin":
return b.bundleOSX(po)
default:
return fmt.Errorf("platform '%s' not supported for bundling yet", runtime.GOOS)
}
}
// Bundle the application
func (b *BundleHelper) bundleOSX(po *ProjectOptions) error {
system := NewSystemHelper()
config, err := system.LoadConfig()
if err != nil {
return err
}
name := defaultString(po.Name, "WailsTest")
exe := defaultString(po.BinaryName, name)
version := defaultString(po.Version, "0.1.0")
author := defaultString(config.Name, "Anonymous")
bundleID := strings.Join([]string{"wails", name, version}, ".")
plistData := newPlistData(name, exe, bundleID, version, author)
appname := po.Name + ".app"
// Check binary exists
source := path.Join(b.fs.Cwd(), exe)
if !b.fs.FileExists(source) {
// We need to build!
return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", exe)
}
// REmove the existing bundle
os.RemoveAll(appname)
exeDir := path.Join(b.fs.Cwd(), appname, "/Contents/MacOS")
b.fs.MkDirs(exeDir, 0755)
resourceDir := path.Join(b.fs.Cwd(), appname, "/Contents/Resources")
b.fs.MkDirs(resourceDir, 0755)
tmpl := template.New("infoPlist")
plistFile := filepath.Join(b.getBundleFileBaseDir(), "info.plist")
infoPlist, err := ioutil.ReadFile(plistFile)
if err != nil {
return err
}
tmpl.Parse(string(infoPlist))
// Write the template to a buffer
var tpl bytes.Buffer
err = tmpl.Execute(&tpl, plistData)
if err != nil {
return err
}
filename := path.Join(b.fs.Cwd(), appname, "Contents", "Info.plist")
err = ioutil.WriteFile(filename, tpl.Bytes(), 0644)
if err != nil {
return err
}
// Copy executable
target := path.Join(exeDir, exe)
err = b.fs.CopyFile(source, target)
if err != nil {
return err
}
err = os.Chmod(target, 0755)
if err != nil {
return err
}
err = b.bundleIcon(resourceDir)
return err
}
func (b *BundleHelper) bundleIcon(resourceDir string) error {
// TODO: Read this from project.json
const appIconFilename = "appicon.png"
srcIcon := path.Join(b.fs.Cwd(), appIconFilename)
// Check if appicon.png exists
if !b.fs.FileExists(srcIcon) {
// Install default icon
iconfile := filepath.Join(b.getBundleFileBaseDir(), "icon.png")
iconData, err := ioutil.ReadFile(iconfile)
if err != nil {
return err
}
err = ioutil.WriteFile(srcIcon, iconData, 0644)
if err != nil {
return err
}
}
tgtBundle := path.Join(resourceDir, "iconfile.icns")
imageFile, err := os.Open(srcIcon)
if err != nil {
return err
}
defer imageFile.Close()
srcImg, _, err := image.Decode(imageFile)
if err != nil {
return err
}
dest, err := os.Create(tgtBundle)
if err != nil {
return err
}
defer dest.Close()
if err := icns.Encode(dest, srcImg); err != nil {
return err
}
return nil
}

View File

@@ -96,6 +96,7 @@ type Command struct {
flagCount int
log *Logger
helpFlag bool
hidden bool
}
// NewCommand creates a new Command
@@ -106,6 +107,7 @@ func NewCommand(name string, description string, app *Cli, parentCommandPath str
SubCommandsMap: make(map[string]*Command),
App: app,
log: NewLogger(),
hidden: false,
}
// Set up command path
@@ -194,10 +196,8 @@ func (c *Command) Action(callback Action) *Command {
// PrintHelp - Output the help text for this command
func (c *Command) PrintHelp() {
versionString := c.AppVersion
if versionString != "" {
versionString = " " + versionString
}
c.log.PrintBanner()
commandTitle := c.CommandPath
if c.Shortdescription != "" {
commandTitle += " - " + c.Shortdescription
@@ -211,10 +211,12 @@ func (c *Command) PrintHelp() {
fmt.Println(c.Longdescription + "\n")
}
if len(c.SubCommands) > 0 {
fmt.Println("")
c.log.White("Available commands:")
fmt.Println("")
for _, subcommand := range c.SubCommands {
if subcommand.isHidden() {
continue
}
spacer := strings.Repeat(" ", 3+c.longestSubcommand-len(subcommand.Name))
isDefault := ""
if subcommand.isDefaultCommand() {
@@ -222,9 +224,9 @@ func (c *Command) PrintHelp() {
}
fmt.Printf(" %s%s%s %s\n", subcommand.Name, spacer, subcommand.Shortdescription, isDefault)
}
fmt.Println("")
}
if c.flagCount > 0 {
fmt.Println("")
c.log.White("Flags:")
fmt.Println()
c.Flags.SetOutput(os.Stdout)
@@ -240,6 +242,16 @@ func (c *Command) isDefaultCommand() bool {
return c.App.defaultCommand == c
}
// isHidden returns true if the command is a hidden command
func (c *Command) isHidden() bool {
return c.hidden
}
// Hidden hides the command from the Help system
func (c *Command) Hidden() {
c.hidden = true
}
// Command - Defines a subcommand
func (c *Command) Command(name, description string) *Command {
result := NewCommand(name, description, c.App, c.CommandPath)

10
cmd/cmd-mewn.go Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,69 +0,0 @@
package cmd
import (
"encoding/json"
"io/ioutil"
"path"
"path/filepath"
"runtime"
)
// FrameworkMetadata contains information about a given framework
type FrameworkMetadata struct {
Name string `json:"name"`
BuildTag string `json:"buildtag"`
Description string `json:"description"`
}
// Utility function for creating new FrameworkMetadata structs
func loadFrameworkMetadata(pathToMetadataJSON string) (*FrameworkMetadata, error) {
result := &FrameworkMetadata{}
configData, err := ioutil.ReadFile(pathToMetadataJSON)
if err != nil {
return nil, err
}
// Load and unmarshall!
err = json.Unmarshal(configData, result)
if err != nil {
return nil, err
}
return result, nil
}
// GetFrameworks returns information about all the available frameworks
func GetFrameworks() ([]*FrameworkMetadata, error) {
var err error
// Calculate framework base dir
_, filename, _, _ := runtime.Caller(1)
frameworksBaseDir := filepath.Join(path.Dir(filename), "frameworks")
// Get the subdirectories
fs := NewFSHelper()
frameworkDirs, err := fs.GetSubdirs(frameworksBaseDir)
if err != nil {
return nil, err
}
// Prepare result
result := []*FrameworkMetadata{}
// Iterate framework directories, looking for metadata.json files
for _, frameworkDir := range frameworkDirs {
var frameworkMetadata FrameworkMetadata
metadataFile := filepath.Join(frameworkDir, "metadata.json")
jsonData, err := ioutil.ReadFile(metadataFile)
if err != nil {
return nil, err
}
err = json.Unmarshal(jsonData, &frameworkMetadata)
if err != nil {
return nil, err
}
result = append(result, &frameworkMetadata)
}
// Read in framework metadata
return result, nil
}

File diff suppressed because one or more lines are too long

View File

@@ -1,16 +0,0 @@
// +build frameworkbootstrap4
package frameworks
import (
"github.com/gobuffalo/packr"
)
func init() {
assets := packr.NewBox("./bootstrap4default/assets")
FrameworkToUse = &Framework{
Name: "Bootstrap 4",
JS: BoxString(&assets, "bootstrap.bundle.min.js"),
CSS: BoxString(&assets, "bootstrap.min.css"),
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,17 +0,0 @@
// +build frameworkbootstrap4
package bootstrap4
import (
"github.com/gobuffalo/packr"
"github.com/wailsapp/wails/frameworks"
)
func init() {
assets := packr.NewBox("./assets")
frameworks.FrameworkToUse = &frameworks.Framework{
Name: "Bootstrap 4",
JS: BoxString(&assets, "bootstrap.bundle.min.js"),
CSS: BoxString(&assets, "bootstrap.min.css"),
}
}

View File

@@ -1,5 +0,0 @@
{
"Name": "Bootstrap 4",
"Description": "Standard Bootstrap 4 with default theme",
"BuildTag": "frameworkbootstrap4"
}

View File

@@ -1,16 +0,0 @@
// +build frameworkbootstrap4lux
package frameworks
import (
"github.com/gobuffalo/packr"
)
func init() {
assets := packr.NewBox("./bootstrap4lux/assets")
FrameworkToUse = &Framework{
Name: "Bootstrap 4 (Lux)",
JS: BoxString(&assets, "bootstrap.bundle.min.js"),
CSS: BoxString(&assets, "bootstrap.min.css"),
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,17 +0,0 @@
// +build frameworkbootstrap4lux
package bootstrap4
import (
"github.com/gobuffalo/packr"
"github.com/wailsapp/wails/frameworks"
)
func init() {
assets := packr.NewBox("./assets")
frameworks.FrameworkToUse = &frameworks.Framework{
Name: "Bootstrap 4 (Lux)",
JS: BoxString(&assets, "bootstrap.bundle.min.js"),
CSS: BoxString(&assets, "bootstrap.min.css"),
}
}

View File

@@ -1,5 +0,0 @@
{
"Name": "Bootstrap 4 (Lux)",
"Description": "Bootstrap with Lux theme",
"BuildTag": "frameworkbootstrap4lux"
}

View File

@@ -1,28 +0,0 @@
package frameworks
import (
"log"
"github.com/gobuffalo/packr"
)
// Framework has details about a specific framework
type Framework struct {
Name string
JS string
CSS string
Options string
}
// FrameworkToUse is the framework we will use when building
// Set by `wails init`, used by `wails build`
var FrameworkToUse *Framework
// BoxString extracts a string from a packr box
func BoxString(box *packr.Box, filename string) string {
result, err := box.FindString(filename)
if err != nil {
log.Fatal(err)
}
return result
}

100
cmd/fs.go
View File

@@ -1,13 +1,19 @@
package cmd
import (
"bytes"
"crypto/md5"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"runtime"
"github.com/leaanthony/slicer"
)
// FSHelper - Wrapper struct for File System utility commands
@@ -41,6 +47,14 @@ func (fs *FSHelper) FileExists(path string) bool {
return fi.Mode().IsRegular()
}
// CreateFile creates a file at the given filename location with the contents
// set to the given data. It will create intermediary directories if needed.
func (fs *FSHelper) CreateFile(filename string, data []byte) error {
// Ensure directory exists
fs.MkDirs(filepath.Dir(filename))
return ioutil.WriteFile(filename, data, 0644)
}
// MkDirs creates the given nested directories.
// Returns error on failure
func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error {
@@ -80,11 +94,49 @@ func (fs *FSHelper) Cwd() string {
return cwd
}
// RemoveFile removes the given filename
func (fs *FSHelper) RemoveFile(filename string) error {
return os.Remove(filename)
}
// RemoveFiles removes the given filenames
func (fs *FSHelper) RemoveFiles(files []string) error {
for _, filename := range files {
err := os.Remove(filename)
if err != nil {
return err
}
}
return nil
}
// Dir holds information about a directory
type Dir struct {
localPath string
fullPath string
}
// Directory creates a new Dir struct with the given directory path
func (fs *FSHelper) Directory(dir string) (*Dir, error) {
fullPath, err := filepath.Abs(dir)
return &Dir{fullPath: fullPath}, err
}
// LocalDir creates a new Dir struct based on a path relative to the caller
func (fs *FSHelper) LocalDir(dir string) (*Dir, error) {
_, filename, _, _ := runtime.Caller(1)
fullPath, err := filepath.Abs(filepath.Join(path.Dir(filename), dir))
return &Dir{
localPath: dir,
fullPath: fullPath,
}, err
}
// GetSubdirs will return a list of FQPs to subdirectories in the given directory
func (fs *FSHelper) GetSubdirs(dir string) (map[string]string, error) {
func (d *Dir) GetSubdirs() (map[string]string, error) {
// Read in the directory information
fileInfo, err := ioutil.ReadDir(dir)
fileInfo, err := ioutil.ReadDir(d.fullPath)
if err != nil {
return nil, err
}
@@ -96,25 +148,65 @@ func (fs *FSHelper) GetSubdirs(dir string) (map[string]string, error) {
// map["directoryName"] = "path/to/directoryName"
for _, file := range fileInfo {
if file.IsDir() {
subdirs[file.Name()] = filepath.Join(dir, file.Name())
subdirs[file.Name()] = filepath.Join(d.fullPath, file.Name())
}
}
return subdirs, nil
}
// GetAllFilenames returns all filename in and below this directory
func (d *Dir) GetAllFilenames() (*slicer.StringSlicer, error) {
result := slicer.String()
err := filepath.Walk(d.fullPath, func(dir string, info os.FileInfo, err error) error {
if dir == d.fullPath {
return nil
}
if err != nil {
return err
}
// Don't copy template metadata
result.Add(dir)
return nil
})
return result, err
}
// MkDir creates the given directory.
// Returns error on failure
func (fs *FSHelper) MkDir(dir string) error {
return os.Mkdir(dir, 0700)
}
// SaveAsJSON saves the JSON representation of the given data to the given filename
func (fs *FSHelper) SaveAsJSON(data interface{}, filename string) error {
var buf bytes.Buffer
e := json.NewEncoder(&buf)
e.SetEscapeHTML(false)
e.SetIndent("", " ")
e.Encode(data)
err := ioutil.WriteFile(filename, buf.Bytes(), 0755)
if err != nil {
return err
}
return nil
}
// LoadAsString will attempt to load the given file and return
// its contents as a string
func (fs *FSHelper) LoadAsString(filename string) (string, error) {
bytes, err := ioutil.ReadFile(filename)
bytes, err := fs.LoadAsBytes(filename)
return string(bytes), err
}
// LoadAsBytes returns the contents of the file as a byte slice
func (fs *FSHelper) LoadAsBytes(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
}
// FileMD5 returns the md5sum of the given file
func (fs *FSHelper) FileMD5(filename string) (string, error) {
f, err := os.Open(filename)

108
cmd/github.go Normal file
View File

@@ -0,0 +1,108 @@
package cmd
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sort"
)
// GitHubHelper is a utility class for interacting with GitHub
type GitHubHelper struct {
}
// NewGitHubHelper returns a new GitHub Helper
func NewGitHubHelper() *GitHubHelper {
return &GitHubHelper{}
}
// GetVersionTags gets the list of tags on the Wails repo
// It retuns a list of sorted tags in descending order
func (g *GitHubHelper) GetVersionTags() ([]*SemanticVersion, error) {
result := []*SemanticVersion{}
var err error
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/tags")
if err != nil {
return result, err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return result, err
}
data := []map[string]interface{}{}
err = json.Unmarshal(body, &data)
if err != nil {
return result, err
}
// Convert tag data to Version structs
for _, tag := range data {
version := tag["name"].(string)
semver, err := NewSemanticVersion(version)
if err != nil {
return result, err
}
result = append(result, semver)
}
// Reverse Sort
sort.Sort(sort.Reverse(SemverCollection(result)))
return result, err
}
// GetLatestStableRelease gets the latest stable release on GitHub
func (g *GitHubHelper) GetLatestStableRelease() (result *SemanticVersion, err error) {
tags, err := g.GetVersionTags()
if err != nil {
return nil, err
}
for _, tag := range tags {
if tag.IsRelease() {
return tag, nil
}
}
return nil, fmt.Errorf("no release tag found")
}
// GetLatestPreRelease gets the latest prerelease on GitHub
func (g *GitHubHelper) GetLatestPreRelease() (result *SemanticVersion, err error) {
tags, err := g.GetVersionTags()
if err != nil {
return nil, err
}
for _, tag := range tags {
if tag.IsPreRelease() {
return tag, nil
}
}
return nil, fmt.Errorf("no prerelease tag found")
}
// IsValidTag returns true if the given string is a valid tag
func (g *GitHubHelper) IsValidTag(tagVersion string) (bool, error) {
if tagVersion[0] == 'v' {
tagVersion = tagVersion[1:]
}
tags, err := g.GetVersionTags()
if err != nil {
return false, err
}
for _, tag := range tags {
if tag.String() == tagVersion {
return true, nil
}
}
return false, nil
}

306
cmd/helpers.go Normal file
View File

@@ -0,0 +1,306 @@
package cmd
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"time"
mewn "github.com/leaanthony/mewn"
"github.com/leaanthony/slicer"
"github.com/leaanthony/spinner"
)
var fs = NewFSHelper()
// ValidateFrontendConfig checks if the frontend config is valid
func ValidateFrontendConfig(projectOptions *ProjectOptions) error {
if projectOptions.FrontEnd.Dir == "" {
return fmt.Errorf("Frontend directory not set in project.json")
}
if projectOptions.FrontEnd.Build == "" {
return fmt.Errorf("Frontend build command not set in project.json")
}
if projectOptions.FrontEnd.Install == "" {
return fmt.Errorf("Frontend install command not set in project.json")
}
if projectOptions.FrontEnd.Bridge == "" {
return fmt.Errorf("Frontend bridge config not set in project.json")
}
return nil
}
// InstallGoDependencies will run go get in the current directory
func InstallGoDependencies() error {
depSpinner := spinner.New("Ensuring Dependencies are up to date...")
depSpinner.SetSpinSpeed(50)
depSpinner.Start()
err := NewProgramHelper().RunCommand("go get")
if err != nil {
depSpinner.Error()
return err
}
depSpinner.Success()
return nil
}
// BuildApplication will attempt to build the project based on the given inputs
func BuildApplication(binaryName string, forceRebuild bool, buildMode string, packageApp bool, projectOptions *ProjectOptions) error {
// Generate Windows assets if needed
if runtime.GOOS == "windows" {
cleanUp := !packageApp
err := NewPackageHelper().PackageWindows(projectOptions, cleanUp)
if err != nil {
return err
}
}
// Check Mewn is installed
err := CheckMewn()
if err != nil {
return err
}
compileMessage := "Packing + Compiling project"
if buildMode == BuildModeDebug {
compileMessage += " (Debug Mode)"
}
packSpinner := spinner.New(compileMessage + "...")
packSpinner.SetSpinSpeed(50)
packSpinner.Start()
buildCommand := slicer.String()
buildCommand.Add("mewn")
if buildMode == BuildModeBridge {
// Ignore errors
buildCommand.Add("-i")
}
buildCommand.Add("build")
if binaryName != "" {
buildCommand.Add("-o")
buildCommand.Add(binaryName)
}
// If we are forcing a rebuild
if forceRebuild {
buildCommand.Add("-a")
}
// Setup ld flags
ldflags := "-w -s "
if buildMode == BuildModeDebug {
ldflags = ""
}
// Add windows flags
if runtime.GOOS == "windows" {
ldflags += "-H windowsgui "
}
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
buildCommand.AddSlice([]string{"-ldflags", ldflags})
err = NewProgramHelper().RunCommandArray(buildCommand.AsSlice())
if err != nil {
packSpinner.Error()
return err
}
packSpinner.Success()
// packageApp
if packageApp {
err = PackageApplication(projectOptions)
if err != nil {
return err
}
}
return nil
}
// PackageApplication will attempt to package the application in a platform dependent way
func PackageApplication(projectOptions *ProjectOptions) error {
// Package app
message := "Generating .app"
if runtime.GOOS == "windows" {
err := CheckWindres()
if err != nil {
return err
}
message = "Generating resource bundle"
}
packageSpinner := spinner.New(message)
packageSpinner.SetSpinSpeed(50)
packageSpinner.Start()
err := NewPackageHelper().Package(projectOptions)
if err != nil {
packageSpinner.Error()
return err
}
packageSpinner.Success()
return nil
}
// BuildFrontend runs the given build command
func BuildFrontend(buildCommand string) error {
buildFESpinner := spinner.New("Building frontend...")
buildFESpinner.SetSpinSpeed(50)
buildFESpinner.Start()
err := NewProgramHelper().RunCommand(buildCommand)
if err != nil {
buildFESpinner.Error()
return err
}
buildFESpinner.Success()
return nil
}
// CheckMewn checks if mewn is installed and if not, attempts to fetch it
func CheckMewn() (err error) {
programHelper := NewProgramHelper()
if !programHelper.IsInstalled("mewn") {
buildSpinner := spinner.New()
buildSpinner.SetSpinSpeed(50)
buildSpinner.Start("Installing Mewn asset packer...")
err := programHelper.InstallGoPackage("github.com/leaanthony/mewn/cmd/mewn")
if err != nil {
buildSpinner.Error()
return err
}
buildSpinner.Success()
}
return nil
}
// CheckWindres checks if Windres is installed and if not, aborts
func CheckWindres() (err error) {
if runtime.GOOS != "windows" {
return nil
}
programHelper := NewProgramHelper()
if !programHelper.IsInstalled("windres") {
return fmt.Errorf("windres not installed. It comes by default with mingw. Ensure you have installed mingw correctly")
}
return nil
}
// InstallFrontendDeps attempts to install the frontend dependencies based on the given options
func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forceRebuild bool, caller string) error {
// Install frontend deps
err := os.Chdir(projectOptions.FrontEnd.Dir)
if err != nil {
return err
}
// Check if frontend deps have been updated
feSpinner := spinner.New("Ensuring frontend dependencies are up to date (This may take a while)")
feSpinner.SetSpinSpeed(50)
feSpinner.Start()
requiresNPMInstall := true
// Read in package.json MD5
fs := NewFSHelper()
packageJSONMD5, err := fs.FileMD5("package.json")
if err != nil {
return err
}
const md5sumFile = "package.json.md5"
// If we aren't forcing the install and the md5sum file exists
if !forceRebuild && fs.FileExists(md5sumFile) {
// Yes - read contents
savedMD5sum, err := fs.LoadAsString(md5sumFile)
// File exists
if err == nil {
// Compare md5
if savedMD5sum == packageJSONMD5 {
// Same - no need for reinstall
requiresNPMInstall = false
feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)")
}
}
}
// Md5 sum package.json
// Different? Build
if requiresNPMInstall || forceRebuild {
// Install dependencies
err = NewProgramHelper().RunCommand(projectOptions.FrontEnd.Install)
if err != nil {
feSpinner.Error()
return err
}
feSpinner.Success()
// Update md5sum file
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
}
// Install the bridge library
err = InstallBridge(caller, projectDir, projectOptions)
if err != nil {
return err
}
// Build frontend
err = BuildFrontend(projectOptions.FrontEnd.Build)
if err != nil {
return err
}
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"
}
// 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
}
// ServeProject attempts to serve up the current project so that it may be connected to
// via the Wails bridge
func ServeProject(projectOptions *ProjectOptions, logger *Logger) error {
go func() {
time.Sleep(2 * time.Second)
logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<")
}()
location, err := filepath.Abs(projectOptions.BinaryName)
if err != nil {
return err
}
logger.Yellow("Serving Application: " + location)
cmd := exec.Command(location)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
return err
}
return nil
}

View File

@@ -2,7 +2,13 @@ package cmd
import (
"fmt"
"io/ioutil"
"net/url"
"os"
"runtime"
"strings"
"github.com/pkg/browser"
)
// LinuxDistribution is of type int
@@ -10,9 +16,17 @@ type LinuxDistribution int
const (
// Unknown is the catch-all distro
Unknown LinuxDistribution = 0
Unknown LinuxDistribution = iota
// Ubuntu distribution
Ubuntu LinuxDistribution = 1
Ubuntu
// Arch linux distribution
Arch
// RedHat linux distribution
RedHat
// Debian distribution
Debian
// Zorin distribution
Zorin
)
// DistroInfo contains all the information relating to a linux distribution
@@ -22,6 +36,7 @@ type DistroInfo struct {
Release string
Codename string
DistributorID string
DiscoveredBy string
}
// GetLinuxDistroInfo returns information about the running linux distribution
@@ -36,7 +51,7 @@ func GetLinuxDistroInfo() *DistroInfo {
if err != nil {
return result
}
result.DiscoveredBy = "lsb"
for _, line := range strings.Split(stdout, "\n") {
if strings.Contains(line, ":") {
// Iterate lines a
@@ -49,6 +64,12 @@ func GetLinuxDistroInfo() *DistroInfo {
switch value {
case "Ubuntu":
result.Distribution = Ubuntu
case "Arch", "ManjaroLinux":
result.Distribution = Arch
case "Debian":
result.Distribution = Debian
case "Zorin":
result.Distribution = Zorin
}
case "Description":
result.Description = value
@@ -56,24 +77,125 @@ func GetLinuxDistroInfo() *DistroInfo {
result.Release = value
case "Codename":
result.Codename = value
}
}
}
// check if /etc/os-release exists
} else if _, err := os.Stat("/etc/os-release"); !os.IsNotExist(err) {
// Default value
osName := "Unknown"
version := ""
// read /etc/os-release
osRelease, _ := ioutil.ReadFile("/etc/os-release")
// 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
}
}
return result
}
// DpkgInstalled uses dpkg to see if a package is installed
func DpkgInstalled(packageName string) (bool, error) {
result := false
program := NewProgramHelper()
dpkg := program.FindProgram("dpkg")
if dpkg == nil {
return false, fmt.Errorf("cannot check dependencies: dpkg not found")
}
_, _, exitCode, _ := dpkg.Run("-L", packageName)
result = exitCode == 0
return result, nil
return exitCode == 0, nil
}
// PacmanInstalled uses pacman to see if a package is installed.
func PacmanInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
pacman := program.FindProgram("pacman")
if pacman == nil {
return false, fmt.Errorf("cannot check dependencies: pacman not found")
}
_, _, exitCode, _ := pacman.Run("-Qs", packageName)
return exitCode == 0, nil
}
// RpmInstalled uses rpm to see if a package is installed
func RpmInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
rpm := program.FindProgram("rpm")
if rpm == nil {
return false, fmt.Errorf("cannot check dependencies: rpm not found")
}
_, _, exitCode, _ := rpm.Run("--query", packageName)
return exitCode == 0, nil
}
// RequestSupportForDistribution promts the user to submit a request to support their
// currently unsupported distribution
func RequestSupportForDistribution(distroInfo *DistroInfo, libraryName string) error {
var logger = NewLogger()
defaultError := fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, libraryName)
logger.Yellow("Distribution '%s' is not currently supported, but we would love to!", distroInfo.DistributorID)
q := fmt.Sprintf("Would you like to submit a request to support distribution '%s'?", distroInfo.DistributorID)
result := Prompt(q, "yes")
if strings.ToLower(result) != "yes" {
return defaultError
}
title := fmt.Sprintf("Support Distribution '%s'", distroInfo.DistributorID)
var str strings.Builder
gomodule, exists := os.LookupEnv("GO111MODULE")
if !exists {
gomodule = "(Not Set)"
}
str.WriteString("\n| Name | Value |\n| ----- | ----- |\n")
str.WriteString(fmt.Sprintf("| Wails Version | %s |\n", Version))
str.WriteString(fmt.Sprintf("| Go Version | %s |\n", runtime.Version()))
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
str.WriteString(fmt.Sprintf("| Distribution ID | %s |\n", distroInfo.DistributorID))
str.WriteString(fmt.Sprintf("| Distribution Version | %s |\n", distroInfo.Release))
str.WriteString(fmt.Sprintf("| Discovered by | %s |\n", distroInfo.DiscoveredBy))
body := fmt.Sprintf("**Description**\nDistribution '%s' is 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())
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
}

View File

@@ -17,6 +17,7 @@ func NewLogger() *Logger {
return &Logger{errorOnly: false}
}
// SetErrorOnly ensures that only errors are logged out
func (l *Logger) SetErrorOnly(errorOnly bool) {
l.errorOnly = errorOnly
}
@@ -99,6 +100,17 @@ func (l *Logger) Error(format string, a ...interface{}) {
color.New(color.FgHiRed).PrintfFunc()("Error: "+format+"\n", a...)
}
// PrintSmallBanner prints a condensed banner
func (l *Logger) PrintSmallBanner(message ...string) {
yellow := color.New(color.FgYellow).SprintFunc()
red := color.New(color.FgRed).SprintFunc()
msg := ""
if len(message) > 0 {
msg = " - " + message[0]
}
fmt.Printf("%s %s%s\n", yellow("Wails"), red(Version), msg)
}
// PrintBanner prints the Wails banner before running commands
func (l *Logger) PrintBanner() error {
banner1 := ` _ __ _ __

259
cmd/package.go Normal file
View File

@@ -0,0 +1,259 @@
package cmd
import (
"bytes"
"fmt"
"image"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"text/template"
"time"
"github.com/jackmordaunt/icns"
)
// PackageHelper helps with the 'wails package' command
type PackageHelper struct {
fs *FSHelper
log *Logger
system *SystemHelper
}
// NewPackageHelper creates a new PackageHelper!
func NewPackageHelper() *PackageHelper {
return &PackageHelper{
fs: NewFSHelper(),
log: NewLogger(),
system: NewSystemHelper(),
}
}
type plistData struct {
Title string
Exe string
PackageID string
Version string
Author string
Date string
}
func newPlistData(title, exe, packageID, version, author string) *plistData {
now := time.Now().Format(time.RFC822)
return &plistData{
Title: title,
Exe: exe,
Version: version,
PackageID: packageID,
Author: author,
Date: now,
}
}
func defaultString(val string, defaultVal string) string {
if val != "" {
return val
}
return defaultVal
}
func (b *PackageHelper) getPackageFileBaseDir() string {
// Calculate template base dir
_, filename, _, _ := runtime.Caller(1)
return filepath.Join(path.Dir(filename), "packages", runtime.GOOS)
}
// Package the application into a platform specific package
func (b *PackageHelper) Package(po *ProjectOptions) error {
switch runtime.GOOS {
case "darwin":
// Check we have the exe
if !b.fs.FileExists(po.BinaryName) {
return fmt.Errorf("cannot bundle non-existent binary file '%s'. Please build with 'wails build' first", po.BinaryName)
}
return b.packageOSX(po)
case "windows":
return b.PackageWindows(po, false)
case "linux":
return fmt.Errorf("linux is not supported at this time. Please see https://github.com/wailsapp/wails/issues/2")
default:
return fmt.Errorf("platform '%s' not supported for bundling yet", runtime.GOOS)
}
}
// Package the application for OSX
func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
system := NewSystemHelper()
config, err := system.LoadConfig()
if err != nil {
return err
}
name := defaultString(po.Name, "WailsTest")
exe := defaultString(po.BinaryName, name)
version := defaultString(po.Version, "0.1.0")
author := defaultString(config.Name, "Anonymous")
packageID := strings.Join([]string{"wails", name, version}, ".")
plistData := newPlistData(name, exe, packageID, version, author)
appname := po.Name + ".app"
// Check binary exists
source := path.Join(b.fs.Cwd(), exe)
if !b.fs.FileExists(source) {
// We need to build!
return fmt.Errorf("Target '%s' not available. Has it been compiled yet?", exe)
}
// Remove the existing package
os.RemoveAll(appname)
exeDir := path.Join(b.fs.Cwd(), appname, "/Contents/MacOS")
b.fs.MkDirs(exeDir, 0755)
resourceDir := path.Join(b.fs.Cwd(), appname, "/Contents/Resources")
b.fs.MkDirs(resourceDir, 0755)
tmpl := template.New("infoPlist")
plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist")
infoPlist, err := ioutil.ReadFile(plistFile)
if err != nil {
return err
}
tmpl.Parse(string(infoPlist))
// Write the template to a buffer
var tpl bytes.Buffer
err = tmpl.Execute(&tpl, plistData)
if err != nil {
return err
}
filename := path.Join(b.fs.Cwd(), appname, "Contents", "Info.plist")
err = ioutil.WriteFile(filename, tpl.Bytes(), 0644)
if err != nil {
return err
}
// Copy executable
target := path.Join(exeDir, exe)
err = b.fs.CopyFile(source, target)
if err != nil {
return err
}
err = os.Chmod(target, 0755)
if err != nil {
return err
}
err = b.packageIconOSX(resourceDir)
return err
}
// PackageWindows packages the application for windows platforms
func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
basename := strings.TrimSuffix(po.BinaryName, ".exe")
// Copy icon
tgtIconFile := filepath.Join(b.fs.Cwd(), basename+".ico")
if !b.fs.FileExists(tgtIconFile) {
srcIconfile := filepath.Join(b.getPackageFileBaseDir(), "wails.ico")
err := b.fs.CopyFile(srcIconfile, tgtIconFile)
if err != nil {
return err
}
}
// Copy manifest
tgtManifestFile := filepath.Join(b.fs.Cwd(), basename+".exe.manifest")
if !b.fs.FileExists(tgtManifestFile) {
srcManifestfile := filepath.Join(b.getPackageFileBaseDir(), "wails.exe.manifest")
err := b.fs.CopyFile(srcManifestfile, tgtManifestFile)
if err != nil {
return err
}
}
// Copy rc file
tgtRCFile := filepath.Join(b.fs.Cwd(), basename+".rc")
if !b.fs.FileExists(tgtRCFile) {
srcRCfile := filepath.Join(b.getPackageFileBaseDir(), "wails.rc")
rcfilebytes, err := ioutil.ReadFile(srcRCfile)
if err != nil {
return err
}
rcfiledata := strings.Replace(string(rcfilebytes), "$NAME$", basename, -1)
err = ioutil.WriteFile(tgtRCFile, []byte(rcfiledata), 0755)
if err != nil {
return err
}
}
// Build syso
sysofile := filepath.Join(b.fs.Cwd(), basename+"-res.syso")
windresCommand := []string{"windres", "-o", sysofile, tgtRCFile}
err := NewProgramHelper().RunCommandArray(windresCommand)
if err != nil {
return err
}
// clean up
if cleanUp {
filesToDelete := []string{tgtIconFile, tgtManifestFile, tgtRCFile, sysofile}
err := b.fs.RemoveFiles(filesToDelete)
if err != nil {
return err
}
}
return nil
}
func (b *PackageHelper) copyIcon(resourceDir string) (string, error) {
// TODO: Read this from project.json
const appIconFilename = "appicon.png"
srcIcon := path.Join(b.fs.Cwd(), appIconFilename)
// Check if appicon.png exists
if !b.fs.FileExists(srcIcon) {
// Install default icon
iconfile := filepath.Join(b.getPackageFileBaseDir(), "icon.png")
iconData, err := ioutil.ReadFile(iconfile)
if err != nil {
return "", err
}
err = ioutil.WriteFile(srcIcon, iconData, 0644)
if err != nil {
return "", err
}
}
return srcIcon, nil
}
func (b *PackageHelper) packageIconOSX(resourceDir string) error {
srcIcon, err := b.copyIcon(resourceDir)
if err != nil {
return err
}
tgtBundle := path.Join(resourceDir, "iconfile.icns")
imageFile, err := os.Open(srcIcon)
if err != nil {
return err
}
defer imageFile.Close()
srcImg, _, err := image.Decode(imageFile)
if err != nil {
return err
}
dest, err := os.Create(tgtBundle)
if err != nil {
return err
}
defer dest.Close()
return icns.Encode(dest, srcImg)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View File

@@ -0,0 +1,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>CFBundleName</key><string>{{.Title}}</string>
<key>CFBundleExecutable</key><string>{{.Exe}}</string>
<key>CFBundleIdentifier</key><string>{{.PackageID}}</string>
<key>CFBundleVersion</key><string>{{.Version}}</string>
<key>CFBundleGetInfoString</key><string>Built by {{.Author}} at {{.Date}} using Wails (https://wails.app)</string>
<key>CFBundleShortVersionString</key><string>{{.Version}}</string>
<key>CFBundleIconFile</key><string>iconfile</string>
<key>NSHighResolutionCapable</key><string>true</string>
</dict></plist>

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity type="win32" name="MyApplication" version="1.0.0.0" processorArchitecture="amd64"/>
<asmv3:application>
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- fallback for Windows 7 and 8 -->
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness> <!-- falls back to per-monitor if per-monitor v2 is not supported -->
<gdiScaling xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">true</gdiScaling> <!-- enables GDI DPI scaling -->
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

View File

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

View File

@@ -49,11 +49,10 @@ func getRequiredProgramsLinux() *Prerequisites {
result := &Prerequisites{}
distroInfo := GetLinuxDistroInfo()
switch distroInfo.Distribution {
case Ubuntu:
case Ubuntu, Debian, Zorin:
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 apt install npm` 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"))
@@ -94,9 +93,15 @@ func getRequiredLibrariesLinux() (*Prerequisites, error) {
result := &Prerequisites{}
distroInfo := GetLinuxDistroInfo()
switch distroInfo.Distribution {
case Ubuntu:
case Ubuntu, Debian, Zorin:
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"))

View File

@@ -56,7 +56,7 @@ func (p *Program) GetFullPathToBinary() (string, error) {
}
// Run will execute the program with the given parameters
// Returns stdout + stderr as strings and an error if one occured
// Returns stdout + stderr as strings and an error if one occurred
func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err error) {
command, err := p.GetFullPathToBinary()
if err != nil {
@@ -92,7 +92,7 @@ func (p *Program) Run(vars ...string) (stdout, stderr string, exitCode int, err
// InstallGoPackage installs the given Go package
func (p *ProgramHelper) InstallGoPackage(packageName string) error {
args := strings.Split("get -u "+packageName, " ")
args := strings.Split("get "+packageName, " ")
_, stderr, err := p.shell.Run("go", args...)
if err != nil {
fmt.Println(stderr)
@@ -107,7 +107,7 @@ func (p *ProgramHelper) RunCommand(command string) error {
}
// RunCommandArray runs the command specified in the array
func (p *ProgramHelper) RunCommandArray(args []string) error {
func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error {
program := args[0]
// TODO: Run FindProgram here and get the full path to the exe
program, err := exec.LookPath(program)
@@ -116,7 +116,13 @@ func (p *ProgramHelper) RunCommandArray(args []string) error {
return err
}
args = args[1:]
_, stderr, err := p.shell.Run(program, args...)
var stderr string
// fmt.Printf("RunCommandArray = %s %+v\n", program, args)
if len(dir) > 0 {
_, stderr, err = p.shell.RunInDirectory(dir[0], program, args...)
} else {
_, stderr, err = p.shell.Run(program, args...)
}
if err != nil {
fmt.Println(stderr)
}

View File

@@ -4,10 +4,13 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"github.com/AlecAivazis/survey"
"github.com/leaanthony/slicer"
)
type author struct {
@@ -19,6 +22,8 @@ type frontend struct {
Dir string `json:"dir"`
Install string `json:"install"`
Build string `json:"build"`
Bridge string `json:"bridge"`
Serve string `json:"serve"`
}
type framework struct {
@@ -46,22 +51,14 @@ func NewProjectHelper() *ProjectHelper {
// GenerateProject generates a new project using the options given
func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
fs := NewFSHelper()
exists, err := ph.templates.TemplateExists(projectOptions.Template)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("template '%s' is invalid", projectOptions.Template)
}
// Calculate project path
projectPath, err := filepath.Abs(projectOptions.OutputDirectory)
if err != nil {
return err
}
_ = projectPath
if fs.DirExists(projectPath) {
return fmt.Errorf("directory '%s' already exists", projectPath)
}
@@ -82,11 +79,25 @@ func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
if err != nil {
return err
}
ph.log.Yellow("Project '%s' generated in directory '%s'!", projectOptions.Name, projectOptions.OutputDirectory)
ph.log.Yellow("To compile the project, run 'wails build' in the project directory.")
// // If we are on windows, dump a windows_resource.json
// if runtime.GOOS == "windows" {
// ph.GenerateWindowsResourceConfig(projectOptions)
// }
return nil
}
// // GenerateWindowsResourceConfig generates the default windows resource file
// func (ph *ProjectHelper) GenerateWindowsResourceConfig(po *ProjectOptions) {
// fmt.Println(buffer.String())
// // vi.Build()
// // vi.Walk()
// // err := vi.WriteSyso(outPath, runtime.GOARCH)
// }
// LoadProjectConfig loads the project config from the given directory
func (ph *ProjectHelper) LoadProjectConfig(dir string) (*ProjectOptions, error) {
po := ph.NewProjectOptions()
@@ -97,15 +108,14 @@ func (ph *ProjectHelper) LoadProjectConfig(dir string) (*ProjectOptions, error)
// NewProjectOptions creates a new default set of project options
func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
result := ProjectOptions{
Name: "",
Description: "Enter your project description",
Version: "0.1.0",
BinaryName: "",
system: NewSystemHelper(),
log: NewLogger(),
templates: NewTemplateHelper(),
templateNameMap: make(map[string]string),
Author: &author{},
Name: "",
Description: "Enter your project description",
Version: "0.1.0",
BinaryName: "",
system: NewSystemHelper(),
log: NewLogger(),
templates: NewTemplateHelper(),
Author: &author{},
}
// Populate system config
@@ -118,193 +128,102 @@ func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
return &result
}
// SelectQuestion creates a new select type question for Survey
func SelectQuestion(name, message string, options []string, defaultValue string, required bool) *survey.Question {
result := survey.Question{
Name: name,
Prompt: &survey.Select{
Message: message,
Options: options,
Default: defaultValue,
},
}
if required {
result.Validate = survey.Required
}
return &result
}
// InputQuestion creates a new input type question for Survey
func InputQuestion(name, message string, defaultValue string, required bool) *survey.Question {
result := survey.Question{
Name: name,
Prompt: &survey.Input{
Message: message + ":",
Default: defaultValue,
},
}
if required {
result.Validate = survey.Required
}
return &result
}
// ProjectOptions holds all the options available for a project
type ProjectOptions struct {
Name string `json:"name"`
Description string `json:"description"`
Author *author `json:"author,omitempty"`
Version string `json:"version"`
OutputDirectory string `json:"-"`
UseDefaults bool `json:"-"`
Template string `json:"-"`
BinaryName string `json:"binaryname"`
FrontEnd *frontend `json:"frontend,omitempty"`
NPMProjectName string `json:"-"`
Framework *framework `json:"framework,omitempty"`
system *SystemHelper
log *Logger
templates *TemplateHelper
templateNameMap map[string]string // Converts template prompt text to template name
Name string `json:"name"`
Description string `json:"description"`
Author *author `json:"author,omitempty"`
Version string `json:"version"`
OutputDirectory string `json:"-"`
UseDefaults bool `json:"-"`
Template string `json:"-"`
BinaryName string `json:"binaryname"`
FrontEnd *frontend `json:"frontend,omitempty"`
NPMProjectName string `json:"-"`
system *SystemHelper
log *Logger
templates *TemplateHelper
selectedTemplate *TemplateDetails
WailsVersion string
}
// Defaults sets the default project template
func (po *ProjectOptions) Defaults() {
po.Template = "basic"
po.Template = "vuebasic"
po.WailsVersion = Version
}
// PromptForInputs asks the user to input project details
func (po *ProjectOptions) PromptForInputs() error {
var questions []*survey.Question
fs := NewFSHelper()
processProjectName(po)
if po.Name == "" {
questions = append(questions, InputQuestion("Name", "The name of the project", "My Project", true))
} else {
fmt.Println("Project Name: " + po.Name)
}
if po.BinaryName == "" {
var binaryNameComputed string
if po.Name != "" {
binaryNameComputed = strings.ToLower(po.Name)
binaryNameComputed = strings.Replace(binaryNameComputed, " ", "-", -1)
binaryNameComputed = strings.Replace(binaryNameComputed, string(filepath.Separator), "-", -1)
binaryNameComputed = strings.Replace(binaryNameComputed, ":", "-", -1)
}
questions = append(questions, InputQuestion("BinaryName", "The output binary name", binaryNameComputed, true))
} else {
fmt.Println("Output binary Name: " + po.BinaryName)
}
if po.OutputDirectory != "" {
projectPath, err := filepath.Abs(po.OutputDirectory)
if err != nil {
return err
}
if fs.DirExists(projectPath) {
return fmt.Errorf("directory '%s' already exists", projectPath)
}
fmt.Println("Project Directory: " + po.OutputDirectory)
} else {
questions = append(questions, InputQuestion("OutputDirectory", "Project directory name", "", true))
processBinaryName(po)
err := processOutputDirectory(po)
if err != nil {
return err
}
// Process Templates
templateList := slicer.Interface()
options := slicer.String()
templateDetails, err := po.templates.GetTemplateDetails()
if err != nil {
return err
}
templates := []string{}
// Add a Custom Template
// templates = append(templates, "Custom - Choose your own CSS framework")
for templateName, templateDetails := range templateDetails {
templateText := templateName
// Check if metadata json exists
if templateDetails.Metadata != nil {
shortdescription := templateDetails.Metadata["shortdescription"]
if shortdescription != "" {
templateText += " - " + shortdescription.(string)
}
}
templates = append(templates, templateText)
po.templateNameMap[templateText] = templateName
}
if po.Template != "" {
if _, ok := templateDetails[po.Template]; !ok {
po.log.Error("Template '%s' invalid.", po.Template)
questions = append(questions, SelectQuestion("Template", "Select template", templates, templates[0], true))
// Check template is valid if given
if templateDetails[po.Template] == nil {
keys := make([]string, 0, len(templateDetails))
for k := range templateDetails {
keys = append(keys, k)
}
return fmt.Errorf("invalid template name '%s'. Valid options: %s", po.Template, strings.Join(keys, ", "))
}
po.selectedTemplate = templateDetails[po.Template]
} else {
questions = append(questions, SelectQuestion("Template", "Select template", templates, templates[0], true))
keys := make([]string, 0)
for k := range templateDetails {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
templateDetail := templateDetails[k]
templateList.Add(templateDetail)
options.Add(fmt.Sprintf("%s - %s", templateDetail.Metadata.Name, templateDetail.Metadata.ShortDescription))
}
templateIndex := 0
if len(options.AsSlice()) > 1 {
templateIndex = PromptSelection("Please select a template", options.AsSlice(), 0)
}
if len(templateList.AsSlice()) == 0 {
return fmt.Errorf("aborting: no templates found")
}
// After selection do this....
po.selectedTemplate = templateList.AsSlice()[templateIndex].(*TemplateDetails)
}
err = survey.Ask(questions, po)
if err != nil {
return err
}
fmt.Println("Template: " + po.selectedTemplate.Metadata.Name)
// Setup NPM Project name
po.NPMProjectName = strings.Replace(po.Name, " ", "_", -1)
// If we selected custom, prompt for framework
if po.Template == "custom - Choose your own CSS Framework" {
// Ask for the framework
var frameworkName string
frameworks, err := GetFrameworks()
frameworkNames := []string{}
metadataMap := make(map[string]*FrameworkMetadata)
for _, frameworkMetadata := range frameworks {
frameworkDetails := fmt.Sprintf("%s - %s", frameworkMetadata.Name, frameworkMetadata.Description)
metadataMap[frameworkDetails] = frameworkMetadata
frameworkNames = append(frameworkNames, frameworkDetails)
}
if err != nil {
return err
}
var frameworkQuestion []*survey.Question
frameworkQuestion = append(frameworkQuestion, SelectQuestion("Framework", "Select framework", frameworkNames, frameworkNames[0], true))
err = survey.Ask(frameworkQuestion, &frameworkName)
if err != nil {
return err
}
// Get metadata
metadata := metadataMap[frameworkName]
// Add to project config
po.Framework = &framework{
Name: metadata.Name,
BuildTag: metadata.BuildTag,
}
}
po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1))
// Fix template name
if po.templateNameMap[po.Template] != "" {
po.Template = po.templateNameMap[po.Template]
}
po.Template = strings.Split(po.selectedTemplate.Path, string(os.PathSeparator))[0]
// Populate template details
templateMetadata := templateDetails[po.Template].Metadata
if templateMetadata["frontenddir"] != nil {
po.FrontEnd = &frontend{}
po.FrontEnd.Dir = templateMetadata["frontenddir"].(string)
}
if templateMetadata["install"] != nil {
if po.FrontEnd == nil {
return fmt.Errorf("install set in template metadata but not frontenddir")
}
po.FrontEnd.Install = templateMetadata["install"].(string)
}
if templateMetadata["build"] != nil {
if po.FrontEnd == nil {
return fmt.Errorf("build set in template metadata but not frontenddir")
}
po.FrontEnd.Build = templateMetadata["build"].(string)
// // Populate template details
templateMetadata := po.selectedTemplate.Metadata
err = processTemplateMetadata(templateMetadata, po)
if err != nil {
return err
}
return nil
@@ -337,3 +256,86 @@ func (po *ProjectOptions) LoadConfig(projectDir string) error {
}
return json.Unmarshal(rawBytes, po)
}
func computeBinaryName(projectName string) string {
if projectName == "" {
return ""
}
var binaryNameComputed = strings.ToLower(projectName)
binaryNameComputed = strings.Replace(binaryNameComputed, " ", "-", -1)
binaryNameComputed = strings.Replace(binaryNameComputed, string(filepath.Separator), "-", -1)
binaryNameComputed = strings.Replace(binaryNameComputed, ":", "-", -1)
return binaryNameComputed
}
func processOutputDirectory(po *ProjectOptions) error {
// po.OutputDirectory
if po.OutputDirectory == "" {
po.OutputDirectory = PromptRequired("Project directory name", computeBinaryName(po.Name))
}
projectPath, err := filepath.Abs(po.OutputDirectory)
if err != nil {
return err
}
if NewFSHelper().DirExists(projectPath) {
return fmt.Errorf("directory '%s' already exists", projectPath)
}
fmt.Println("Project Directory: " + po.OutputDirectory)
return nil
}
func processProjectName(po *ProjectOptions) {
if po.Name == "" {
po.Name = Prompt("The name of the project", "My Project")
}
fmt.Println("Project Name: " + po.Name)
}
func processBinaryName(po *ProjectOptions) {
if po.BinaryName == "" {
var binaryNameComputed = computeBinaryName(po.Name)
po.BinaryName = Prompt("The output binary name", binaryNameComputed)
if runtime.GOOS == "windows" {
if !strings.HasSuffix(po.BinaryName, ".exe") {
po.BinaryName += ".exe"
}
}
}
fmt.Println("Output binary Name: " + po.BinaryName)
}
func processTemplateMetadata(templateMetadata *TemplateMetadata, po *ProjectOptions) error {
if templateMetadata.FrontendDir != "" {
po.FrontEnd = &frontend{}
po.FrontEnd.Dir = templateMetadata.FrontendDir
}
if templateMetadata.Install != "" {
if po.FrontEnd == nil {
return fmt.Errorf("install set in template metadata but not frontenddir")
}
po.FrontEnd.Install = templateMetadata.Install
}
if templateMetadata.Build != "" {
if po.FrontEnd == nil {
return fmt.Errorf("build set in template metadata but not frontenddir")
}
po.FrontEnd.Build = templateMetadata.Build
}
if templateMetadata.Bridge != "" {
if po.FrontEnd == nil {
return fmt.Errorf("bridge set in template metadata but not frontenddir")
}
po.FrontEnd.Bridge = templateMetadata.Bridge
}
if templateMetadata.Serve != "" {
if po.FrontEnd == nil {
return fmt.Errorf("serve set in template metadata but not frontenddir")
}
po.FrontEnd.Serve = templateMetadata.Serve
}
return nil
}

85
cmd/prompt.go Normal file
View File

@@ -0,0 +1,85 @@
package cmd
import (
"bufio"
"fmt"
"os"
"runtime"
"strconv"
"strings"
)
// Prompt asks the user for a value
func Prompt(question string, defaultValue ...string) string {
var answer string
if len(defaultValue) > 0 {
answer = defaultValue[0]
question = fmt.Sprintf("%s (%s)", question, answer)
}
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)
if input != "" {
answer = input
}
return answer
}
// PromptRequired calls Prompt repeatedly until a value is given
func PromptRequired(question string, defaultValue ...string) string {
for {
result := Prompt(question, defaultValue...)
if result != "" {
return result
}
}
}
// PromptSelection asks the user to choose an option
func PromptSelection(question string, options []string, optionalDefaultValue ...int) int {
defaultValue := -1
message := "Please choose an option"
fmt.Println(question + ":")
if len(optionalDefaultValue) > 0 {
defaultValue = optionalDefaultValue[0] + 1
message = fmt.Sprintf("%s [%d]", message, defaultValue)
}
for index, option := range options {
fmt.Printf(" %d: %s\n", index+1, option)
}
selectedValue := -1
for {
choice := Prompt(message)
if choice == "" && defaultValue > -1 {
selectedValue = defaultValue - 1
break
}
// index
number, err := strconv.Atoi(choice)
if err == nil {
if number > 0 && number <= len(options) {
selectedValue = number - 1
break
} else {
continue
}
}
}
return selectedValue
}

98
cmd/semver.go Normal file
View File

@@ -0,0 +1,98 @@
package cmd
import (
"fmt"
"github.com/masterminds/semver"
)
// SemanticVersion is a struct containing a semantic version
type SemanticVersion struct {
Version *semver.Version
}
// NewSemanticVersion creates a new SemanticVersion object with the given version string
func NewSemanticVersion(version string) (*SemanticVersion, error) {
semverVersion, err := semver.NewVersion(version)
if err != nil {
return nil, err
}
return &SemanticVersion{
Version: semverVersion,
}, nil
}
// IsRelease returns true if it's a release version
func (s *SemanticVersion) IsRelease() bool {
return len(s.Version.Prerelease()) == 0 && len(s.Version.Metadata()) == 0
}
// IsPreRelease returns true if it's a prerelease version
func (s *SemanticVersion) IsPreRelease() bool {
return len(s.Version.Prerelease()) > 0
}
func (s *SemanticVersion) String() string {
return s.Version.String()
}
// IsGreaterThan returns true if this version is greater than the given version
func (s *SemanticVersion) IsGreaterThan(version *SemanticVersion) (bool, error) {
// Set up new constraint
constraint, err := semver.NewConstraint("> " + version.Version.String())
if err != nil {
return false, err
}
// Check if the desired one is greater than the requested on
success, msgs := constraint.Validate(s.Version)
if !success {
return false, msgs[0]
}
return true, nil
}
// IsGreaterThanOrEqual returns true if this version is greater than or equal the given version
func (s *SemanticVersion) IsGreaterThanOrEqual(version *SemanticVersion) (bool, error) {
// Set up new constraint
constraint, err := semver.NewConstraint(">= " + version.Version.String())
if err != nil {
return false, err
}
// Check if the desired one is greater than the requested on
success, msgs := constraint.Validate(s.Version)
if !success {
return false, msgs[0]
}
return true, nil
}
// MainVersion returns the main version of any version+prerelease+metadata
// EG: MainVersion("1.2.3-pre") => "1.2.3"
func (s *SemanticVersion) MainVersion() *SemanticVersion {
mainVersion := fmt.Sprintf("%d.%d.%d", s.Version.Major(), s.Version.Minor(), s.Version.Patch())
result, _ := NewSemanticVersion(mainVersion)
return result
}
// SemverCollection is a collection of SemanticVersion objects
type SemverCollection []*SemanticVersion
// Len returns the length of a collection. The number of Version instances
// on the slice.
func (c SemverCollection) Len() int {
return len(c)
}
// Less is needed for the sort interface to compare two Version objects on the
// slice. If checks if one is less than the other.
func (c SemverCollection) Less(i, j int) bool {
return c[i].Version.LessThan(c[j].Version)
}
// Swap is needed for the sort interface to replace the Version objects
// at two different positions in the slice.
func (c SemverCollection) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}

View File

@@ -1 +0,0 @@
package cmd

View File

@@ -2,6 +2,7 @@ package cmd
import (
"bytes"
"os"
"os/exec"
)
@@ -17,6 +18,21 @@ func NewShellHelper() *ShellHelper {
// Run the given command
func (sh *ShellHelper) Run(command string, vars ...string) (stdout, stderr string, err error) {
cmd := exec.Command(command, vars...)
cmd.Env = append(os.Environ(), "GO111MODULE=on")
var stdo, stde bytes.Buffer
cmd.Stdout = &stdo
cmd.Stderr = &stde
err = cmd.Run()
stdout = string(stdo.Bytes())
stderr = string(stde.Bytes())
return
}
// RunInDirectory runs the given command in the given directory
func (sh *ShellHelper) RunInDirectory(dir string, command string, vars ...string) (stdout, stderr string, err error) {
cmd := exec.Command(command, vars...)
cmd.Dir = dir
cmd.Env = append(os.Environ(), "GO111MODULE=on")
var stdo, stde bytes.Buffer
cmd.Stdout = &stdo
cmd.Stderr = &stde

View File

@@ -10,7 +10,6 @@ import (
"strconv"
"time"
"github.com/AlecAivazis/survey"
homedir "github.com/mitchellh/go-homedir"
)
@@ -69,6 +68,17 @@ func (s *SystemHelper) ConfigFileIsValid() bool {
return err == nil
}
// GetAuthor returns a formatted string of the user's name and email
func (s *SystemHelper) GetAuthor() (string, error) {
var config *SystemConfig
config, err := s.LoadConfig()
if err != nil {
return "", err
}
return fmt.Sprintf("%s <%s>", config.Name, config.Email), nil
}
// BackupConfig attempts to backup the system config file
func (s *SystemHelper) BackupConfig() (string, error) {
now := strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
@@ -82,55 +92,43 @@ func (s *SystemHelper) BackupConfig() (string, error) {
func (s *SystemHelper) setup() error {
// Answers. We all need them.
answers := &SystemConfig{}
systemConfig := make(map[string]string)
// Try to load current values - ignore errors
config, err := s.LoadConfig()
defaultName := ""
defaultEmail := ""
if config != nil {
defaultName = config.Name
defaultEmail = config.Email
}
// Questions
var simpleQs = []*survey.Question{
{
Name: "Name",
Prompt: &survey.Input{
Message: "What is your name:",
Default: defaultName,
},
Validate: survey.Required,
},
{
Name: "Email",
Prompt: &survey.Input{
Message: "What is your email address:",
Default: defaultEmail,
},
Validate: survey.Required,
},
}
config, _ := s.LoadConfig()
// ask the questions
err = survey.Ask(simpleQs, answers)
if err != nil {
return err
if config.Name != "" {
systemConfig["name"] = PromptRequired("What is your name", config.Name)
} else {
systemConfig["name"] = PromptRequired("What is your name")
}
if config.Email != "" {
systemConfig["email"] = PromptRequired("What is your email address", config.Email)
} else {
systemConfig["email"] = PromptRequired("What is your email address")
}
// Create the directory
err = s.fs.MkDirs(s.wailsSystemDir)
err := s.fs.MkDirs(s.wailsSystemDir)
if err != nil {
return err
}
// Save
configData, err := json.Marshal(&systemConfig)
if err != nil {
return err
}
err = ioutil.WriteFile(s.wailsSystemConfig, configData, 0755)
if err != nil {
return err
}
fmt.Println()
s.log.White("Wails config saved to: " + s.wailsSystemConfig)
s.log.White("Feel free to customise these settings.")
fmt.Println()
return answers.Save(s.wailsSystemConfig)
return nil
}
const introText = `
@@ -258,7 +256,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
bin := programHelper.FindProgram(program.Name)
if bin == nil {
errors = true
logger.Red("Program '%s' not found. %s", program.Name, program.Help)
logger.Error("Program '%s' not found. %s", program.Name, program.Help)
} else {
logger.Green("Program '%s' found: %s", program.Name, bin.Path)
}
@@ -274,19 +272,41 @@ func CheckDependencies(logger *Logger) (bool, error) {
distroInfo := GetLinuxDistroInfo()
for _, library := range *requiredLibraries {
switch distroInfo.Distribution {
case Ubuntu:
case Ubuntu, Zorin, Debian:
installed, err := DpkgInstalled(library.Name)
if err != nil {
return false, err
}
if !installed {
errors = true
logger.Red("Library '%s' not found. %s", library.Name, library.Help)
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, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name)
return false, RequestSupportForDistribution(distroInfo, library.Name)
}
}
}

View File

@@ -5,91 +5,102 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
"log"
"path/filepath"
"runtime"
"strings"
"text/template"
"github.com/kennygrant/sanitize"
"github.com/leaanthony/slicer"
)
const templateSuffix = ".template"
// TemplateHelper helps with creating projects
type TemplateHelper struct {
system *SystemHelper
fs *FSHelper
templateDir string
// templates map[string]string
templateSuffix string
metadataFilename string
// TemplateMetadata holds all the metadata for a Wails template
type TemplateMetadata struct {
Name string `json:"name"`
Version string `json:"version"`
ShortDescription string `json:"shortdescription"`
Description string `json:"description"`
Install string `json:"install"`
Build string `json:"build"`
Author string `json:"author"`
Created string `json:"created"`
FrontendDir string `json:"frontenddir"`
Serve string `json:"serve"`
Bridge string `json:"bridge"`
WailsDir string `json:"wailsdir"`
TemplateDependencies []*TemplateDependency `json:"dependencies,omitempty"`
}
// Template defines a single template
type Template struct {
// TemplateDependency defines a binary dependency for the template
// EG: ng for angular
type TemplateDependency struct {
Bin string `json:"bin"`
Help string `json:"help"`
}
// TemplateDetails holds information about a specific template
type TemplateDetails struct {
Name string
Dir string
Metadata map[string]interface{}
Path string
Metadata *TemplateMetadata
fs *FSHelper
}
// TemplateHelper is a utility object to help with processing templates
type TemplateHelper struct {
templateDir *Dir
fs *FSHelper
metadataFilename string
}
// NewTemplateHelper creates a new template helper
func NewTemplateHelper() *TemplateHelper {
result := TemplateHelper{
system: NewSystemHelper(),
fs: NewFSHelper(),
templateSuffix: ".template",
templateDir, err := fs.LocalDir("./templates")
if err != nil {
log.Fatal("Unable to find the template directory. Please reinstall Wails.")
}
return &TemplateHelper{
templateDir: templateDir,
metadataFilename: "template.json",
}
// Calculate template base dir
_, filename, _, _ := runtime.Caller(1)
result.templateDir = filepath.Join(path.Dir(filename), "templates")
// result.templateDir = filepath.Join(result.system.homeDir, "go", "src", "github.com", "wailsapp", "wails", "cmd", "templates")
return &result
}
// GetTemplateNames returns a map of all available templates
func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) {
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
if err != nil {
return nil, err
}
return templateDirs, nil
// IsValidTemplate returns true if the given tempalte name resides on disk
func (t *TemplateHelper) IsValidTemplate(templateName string) bool {
pathToTemplate := filepath.Join(t.templateDir.fullPath, templateName)
return t.fs.DirExists(pathToTemplate)
}
// GetTemplateDetails returns a map of Template structs containing details
// of the found templates
func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) {
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
// SanitizeFilename sanitizes the given string to make a valid filename
func (t *TemplateHelper) SanitizeFilename(name string) string {
return sanitize.Name(name)
}
// CreateNewTemplate creates a new template based on the given directory name and string
func (t *TemplateHelper) CreateNewTemplate(dirname string, details *TemplateMetadata) (string, error) {
// Check if this template has already been created
if t.IsValidTemplate(dirname) {
return "", fmt.Errorf("cannot create template in directory '%s' - already exists", dirname)
}
targetDir := filepath.Join(t.templateDir.fullPath, dirname)
err := t.fs.MkDir(targetDir)
if err != nil {
return nil, err
return "", err
}
targetMetadata := filepath.Join(targetDir, t.metadataFilename)
err = t.fs.SaveAsJSON(details, targetMetadata)
result := make(map[string]*Template)
for name, dir := range templateDirs {
result[name] = &Template{
Dir: dir,
}
metadata, err := t.LoadMetadata(dir)
if err != nil {
return nil, err
}
result[name].Metadata = metadata
if metadata["name"] != nil {
result[name].Name = metadata["name"].(string)
} else {
// Ignore bad templates?
result[name] = nil
}
}
return result, nil
return targetDir, err
}
// LoadMetadata loads the template's 'metadata.json' file
func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error) {
func (t *TemplateHelper) LoadMetadata(dir string) (*TemplateMetadata, error) {
templateFile := filepath.Join(dir, t.metadataFilename)
result := make(map[string]interface{})
result := &TemplateMetadata{}
if !t.fs.FileExists(templateFile) {
return nil, nil
}
@@ -101,176 +112,137 @@ func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error
return result, err
}
// TemplateExists returns true if the given template name exists
func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) {
templates, err := t.GetTemplateNames()
// GetTemplateDetails returns a map of Template structs containing details
// of the found templates
func (t *TemplateHelper) GetTemplateDetails() (map[string]*TemplateDetails, error) {
// Get the subdirectory details
templateDirs, err := t.templateDir.GetSubdirs()
if err != nil {
return false, err
return nil, err
}
_, exists := templates[templateName]
return exists, nil
result := make(map[string]*TemplateDetails)
for name, dir := range templateDirs {
result[name] = &TemplateDetails{
Path: dir,
}
_ = &TemplateMetadata{}
metadata, err := t.LoadMetadata(dir)
if err != nil {
return nil, err
}
result[name].Metadata = metadata
if metadata.Name != "" {
result[name].Name = metadata.Name
} else {
// Ignore bad templates?
result[name] = nil
}
}
return result, nil
}
// GetTemplateFilenames returns all the filenames of the given template
func (t *TemplateHelper) GetTemplateFilenames(template *TemplateDetails) (*slicer.StringSlicer, error) {
// Get the subdirectory details
templateDir, err := t.fs.Directory(template.Path)
if err != nil {
return nil, err
}
return templateDir.GetAllFilenames()
}
// InstallTemplate installs the template given in the project options to the
// project path given
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
// Check dependencies before installing
dependencies := projectOptions.selectedTemplate.Metadata.TemplateDependencies
if dependencies != nil {
programHelper := NewProgramHelper()
logger := NewLogger()
errors := []string{}
for _, dep := range dependencies {
program := programHelper.FindProgram(dep.Bin)
if program == nil {
errors = append(errors, dep.Help)
}
}
if len(errors) > 0 {
mainError := "template dependencies not installed"
if len(errors) == 1 {
mainError = errors[0]
} else {
for _, error := range errors {
logger.Red(error)
}
}
return fmt.Errorf(mainError)
}
}
// Get template files
template, err := t.getTemplateFiles(projectOptions.Template)
templateFilenames, err := t.GetTemplateFilenames(projectOptions.selectedTemplate)
if err != nil {
return err
}
// Copy files to target
err = template.Install(projectPath, projectOptions)
if err != nil {
return err
}
templatePath := projectOptions.selectedTemplate.Path
return nil
}
// Save the version
projectOptions.WailsVersion = Version
// templateFiles categorises files found in a template
type templateFiles struct {
BaseDir string
StandardFiles []string
Templates []string
Dirs []string
}
templateJSONFilename := filepath.Join(templatePath, t.metadataFilename)
// newTemplateFiles returns a new TemplateFiles struct
func (t *TemplateHelper) newTemplateFiles(dir string) *templateFiles {
pathsep := string(os.PathSeparator)
// Ensure base directory has trailing slash
if !strings.HasSuffix(dir, pathsep) {
dir = dir + pathsep
}
return &templateFiles{
BaseDir: dir,
}
}
// AddStandardFile adds the given file to the list of standard files
func (t *templateFiles) AddStandardFile(filename string) {
localPath := strings.TrimPrefix(filename, t.BaseDir)
t.StandardFiles = append(t.StandardFiles, localPath)
}
// AddTemplate adds the given file to the list of template files
func (t *templateFiles) AddTemplate(filename string) {
localPath := strings.TrimPrefix(filename, t.BaseDir)
t.Templates = append(t.Templates, localPath)
}
// AddDir adds the given directory to the list of template dirs
func (t *templateFiles) AddDir(dir string) {
localPath := strings.TrimPrefix(dir, t.BaseDir)
t.Dirs = append(t.Dirs, localPath)
}
// getTemplateFiles returns a struct categorising files in
// the template directory
func (t *TemplateHelper) getTemplateFiles(templateName string) (*templateFiles, error) {
templates, err := t.GetTemplateNames()
if err != nil {
return nil, err
}
templateDir := templates[templateName]
result := t.newTemplateFiles(templateDir)
var localPath string
err = filepath.Walk(templateDir, func(dir string, info os.FileInfo, err error) error {
if dir == templateDir {
return nil
}
if err != nil {
return err
}
// Don't copy template metadata
localPath = strings.TrimPrefix(dir, templateDir+string(filepath.Separator))
if localPath == t.metadataFilename {
return nil
}
// Categorise the file
switch {
case info.IsDir():
result.AddDir(dir)
case strings.HasSuffix(info.Name(), templateSuffix):
result.AddTemplate(dir)
default:
result.AddStandardFile(dir)
}
return nil
templateFiles := templateFilenames.Filter(func(filename string) bool {
filename = filepath.FromSlash(filename)
return strings.HasPrefix(filename, templatePath) && filename != templateJSONFilename
})
if err != nil {
return nil, fmt.Errorf("error processing template '%s' in path '%q': %v", templateName, templateDir, err)
}
return result, err
}
templateFiles.Each(func(templateFile string) {
// Install the template files into the given project path
func (t *templateFiles) Install(projectPath string, projectOptions *ProjectOptions) error {
fs := NewFSHelper()
// Create directories
var targetDir string
for _, dirname := range t.Dirs {
targetDir = filepath.Join(projectPath, dirname)
fs.MkDir(targetDir)
}
// Copy standard files
var targetFile, sourceFile string
var err error
for _, filename := range t.StandardFiles {
sourceFile = filepath.Join(t.BaseDir, filename)
targetFile = filepath.Join(projectPath, filename)
err = fs.CopyFile(sourceFile, targetFile)
// Setup filenames
relativeFilename := strings.TrimPrefix(templateFile, templatePath)[1:]
targetFilename, err := filepath.Abs(filepath.Join(projectOptions.OutputDirectory, relativeFilename))
if err != nil {
return err
return
}
filedata, err := t.fs.LoadAsBytes(templateFile)
if err != nil {
return
}
}
// Do we have template files?
if len(t.Templates) > 0 {
// Iterate over the templates
var templateFile string
var tmpl *template.Template
for _, filename := range t.Templates {
// Load template text
templateFile = filepath.Join(t.BaseDir, filename)
templateText, err := fs.LoadAsString(templateFile)
if err != nil {
return err
}
// Apply template
tmpl = template.New(templateFile)
tmpl.Parse(templateText)
// Write the template to a buffer
// If file is a template, process it
if strings.HasSuffix(templateFile, ".template") {
templateData := string(filedata)
tmpl := template.New(templateFile)
tmpl.Parse(templateData)
var tpl bytes.Buffer
err = tmpl.Execute(&tpl, projectOptions)
if err != nil {
fmt.Println("ERROR!!! " + err.Error())
return err
return
}
// Save buffer to disk
targetFilename := strings.TrimSuffix(filename, templateSuffix)
targetFile = filepath.Join(projectPath, targetFilename)
err = ioutil.WriteFile(targetFile, tpl.Bytes(), 0644)
if err != nil {
return err
}
// Remove template suffix
targetFilename = strings.TrimSuffix(targetFilename, ".template")
// Set the filedata to the template result
filedata = tpl.Bytes()
}
// Normal file, just copy it
err = fs.CreateFile(targetFilename, filedata)
if err != nil {
return
}
})
if err != nil {
return err
}
return nil

View File

@@ -0,0 +1,13 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@@ -0,0 +1,47 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events.json
speed-measure-plugin.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
.editorcinfig

View File

@@ -0,0 +1,27 @@
# MyApp
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.3.
## Development server
Run `npx ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `npx ng generate component component-name` to generate a new component. You can also use `npx ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `npx ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Running unit tests
Run `npx ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `npx ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `npx ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@@ -0,0 +1,121 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"my-app": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "ngx-build-plus:browser",
"options": {
"outputPath": "dist/my-app",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}
},
"serve": {
"builder": "ngx-build-plus:dev-server",
"options": {
"browserTarget": "my-app:build"
},
"configurations": {
"production": {
"browserTarget": "my-app:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "my-app:build"
}
},
"test": {
"builder": "ngx-build-plus:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "my-app:serve"
},
"configurations": {
"production": {
"devServerTarget": "my-app:serve:production"
}
}
}
}
}
},
"defaultProject": "my-app"
}

View File

@@ -0,0 +1,12 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@@ -0,0 +1,32 @@
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

View File

@@ -0,0 +1,23 @@
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('Welcome to my-app!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});

View File

@@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getTitleText() {
return element(by.css('app-root h1')).getText() as Promise<string>;
}
}

View File

@@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View File

@@ -0,0 +1,32 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/my-app'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

View File

@@ -0,0 +1,50 @@
{
"name": "my-app",
"version": "0.0.0",
"scripts": {
"ng": "npx ng",
"start": "npx ng serve --poll=2000",
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
"test": "npx ng test",
"lint": "npx ng lint",
"e2e": "npx ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^8.0.2",
"@angular/cdk": "^8.0.1",
"@angular/common": "~8.0.1",
"@angular/compiler": "~8.0.1",
"@angular/core": "~8.0.1",
"@angular/forms": "~8.0.1",
"@angular/material": "^8.0.1",
"@angular/platform-browser": "~8.0.1",
"@angular/platform-browser-dynamic": "~8.0.1",
"@angular/router": "~8.0.1",
"ngx-build-plus": "^8.0.3",
"rxjs": "~6.4.0",
"tslib": "^1.9.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.800.0",
"@angular/cli": "~8.0.3",
"@angular/compiler-cli": "~8.0.1",
"@angular/language-service": "~8.0.1",
"@types/node": "~8.9.4",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.4.3"
}
}

View File

@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [
RouterModule.forRoot(routes)
],
exports: [RouterModule]
})
export class AppRoutingModule { }

View File

@@ -0,0 +1,14 @@
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<img width="300" alt="Angular Logo"
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
<br />
<button (click)="onClickMe()">Hello</button>
<p>{{clickMessage}}</p>
</div>
<router-outlet></router-outlet>

View File

@@ -0,0 +1,35 @@
import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'my-app'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('my-app');
});
it('should render title in a h1 tag', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to my-app!');
});
});

View File

@@ -0,0 +1,19 @@
import { Component } from '@angular/core';
@Component({
selector: '[id="app"]',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-app';
clickMessage = '';
onClickMe() {
// @ts-ignore
window.backend.basic().then(result =>
this.clickMessage = result
);
}
}

View File

@@ -0,0 +1,20 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { APP_BASE_HREF } from '@angular/common';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [{provide: APP_BASE_HREF, useValue : '/' }],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@@ -0,0 +1,16 @@
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>my-app</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -0,0 +1,18 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import 'zone.js'
import Bridge from './wailsbridge';
if (environment.production) {
enableProdMode();
}
Bridge.Start(() => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
});

View File

@@ -0,0 +1,63 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags.ts';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
//import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

View File

@@ -0,0 +1,24 @@
/* You can add global styles to this file, and also import other style files */
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #282c34;
}
p {
color: white
}
h1 {
color: white
}
button {
background-color: white;
color: black;
}

View File

@@ -0,0 +1,20 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

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

View File

@@ -0,0 +1,14 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"include": [
"src/**/*.ts"
],
"exclude": [
"src/test.ts",
"src/**/*.spec.ts"
]
}

View File

@@ -0,0 +1,23 @@
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2018",
"dom"
]
}
}

View File

@@ -0,0 +1,18 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

View File

@@ -0,0 +1,92 @@
{
"extends": "tslint:recommended",
"rules": {
"array-type": false,
"arrow-parens": false,
"deprecation": {
"severity": "warn"
},
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"import-blacklist": [
true,
"rxjs/Rx"
],
"interface-name": false,
"max-classes-per-file": false,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-consecutive-blank-lines": false,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-empty": false,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-use-before-declare": true,
"no-var-requires": false,
"object-literal-key-quotes": [
true,
"as-needed"
],
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [
true,
"single"
],
"trailing-comma": false,
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true
},
"rulesDirectory": [
"codelyzer"
]
}

View File

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

View File

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

View File

@@ -0,0 +1,20 @@
{
"name": "Angular",
"version": "1.0.0",
"shortdescription": "Angular 8 template (Requires node 10.8+)",
"description": "Angular projects w/ @angular/cli - Note: in order to reach the cli use npx like this: npx ng",
"dependencies": [
{
"bin": "npx",
"help": "This template requires 'npx'. Please install with 'npm install -g npx'"
}
],
"install": "npm install",
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
"author": "bh90210 <ktc@pm.me>",
"created": "2019-06-15 18:23:48.666414555 +0300 EEST m=+223.934866008",
"frontenddir": "frontend",
"serve": "npx ng serve --poll=2000",
"bridge": "src",
"wailsdir": ""
}

View File

@@ -1 +0,0 @@
module {{.BinaryName}}

View File

@@ -1,24 +0,0 @@
package main
import (
wails "github.com/wailsapp/wails"
)
var html = `
<div style='text-align:center'>
<h1> Basic Template </h1>
Welcome to your basic Wails app!
</div>
`
func main() {
// Initialise the app
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,
Title: "{{.Name}}",
HTML: html,
})
app.Run()
}

View File

@@ -1,7 +0,0 @@
{
"name": "Basic",
"shortdescription": "A basic template",
"description": "A basic template using vanilla JS",
"author": "Lea Anthony<lea.anthony@gmail.com>",
"created": "2018-10-18"
}

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