Compare commits

..

4 Commits

Author SHA1 Message Date
Lea Anthony
02bd44f772 Merge branch 'develop' into feature/gopath 2020-09-15 20:16:42 +10:00
Travis McLane
bd0c9dbc43 use wailsapp/xgo:1.0.1 for cross-compiling 2020-09-14 19:05:00 -05:00
Travis McLane
1c813622c0 update messages to output xgo version
TODO: allow image override
2020-09-13 08:51:54 -05:00
Travis McLane
76ba7d56ec implement gopath handling during cross compilation 2020-09-13 08:47:29 -05:00
554 changed files with 105 additions and 70789 deletions

View File

@@ -8,12 +8,8 @@ assignees: ''
---
#####################################################
**If you have a technical issue, please do not open a bug this way!**
Please use the `wails issue` command!
If you do not do this then the issue may be closed automatically.
NOTE: If your bug is related to Windows, make sure you read
the [Windows Developer Guide](https://wails.app/guides/windows/)
If you have a technical issue, please do not open a bug this way!
Please use the `wails issue` command!
#####################################################
**Description**
@@ -37,5 +33,3 @@ Please provide your platform, GO version and variables, etc
**Additional context**
Add any other context about the problem here.
- [ ] This issue is for Windows and I have read the [Windows Developer Guide](https://wails.app/guides/windows/)

View File

@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,10 +1,8 @@
name: latest pre-release
on:
push:
branches:
- develop
tags:
- '**-pre**'
- '**-pre**'
jobs:
build:

View File

@@ -1,29 +0,0 @@
name: Runtime
on:
push:
branches:
- v2-alpha
paths:
- 'v2/internal/frontend/runtime/**'
jobs:
rebuild-runtime:
name: Rebuild the runtime
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 14.17.6
cache: 'npm'
cache-dependency-path: v2/internal/frontend/runtime/package-lock.json
- run: npm install
working-directory: v2/internal/frontend/runtime
- run: npm run build
working-directory: v2/internal/frontend/runtime
- name: Commit changes
uses: devops-infra/action-commit-push@master
with:
github_token: "${{ secrets.GITHUB_TOKEN }}"
commit_prefix: "[AUTO]"
commit_message: "The runtime was rebuilt"

16
.gitignore vendored
View File

@@ -16,18 +16,4 @@ examples/**/example*
cmd/wails/wails
.DS_Store
tmp
node_modules/
package.json.md5
v2/test/**/frontend/dist
v2/test/**/build/
v2/test/frameless/icon.png
v2/test/hidden/icon.png
v2/test/kitchensink/frontend/public/bundle.*
v2/pkg/parser/testproject/frontend/wails
v2/test/kitchensink/frontend/public
v2/test/kitchensink/build/darwin/desktop/kitchensink
v2/test/kitchensink/frontend/package.json.md5
/v2/internal/ffenestri/windows/test/cmake-build-debug/
!v2/internal/ffenestri/windows/x64/webview2.dll
!v2/internal/ffenestri/windows/x64/WebView2Loader.dll
.idea/
node_modules/

View File

@@ -1,8 +1,4 @@
{
"go.formatTool": "goimports",
"eslint.alwaysShowStatus": true,
"files.associations": {
"__locale": "c",
"ios": "c"
}
"eslint.alwaysShowStatus": true
}

View File

@@ -35,10 +35,3 @@ Wails is what it is because of the time and effort given by these great people.
* [Dmitry Gomzyakov](https://github.com/kyoto44)
* [Arthur Wiebe](https://github.com/artooro)
* [Ilgıt Yıldırım](https://github.com/ilgityildirim)
* [Altynbek](https://github.com/gelleson)
* [Kyle](https://github.com/kmuchmore)
* [Balakrishna Prasad Ganne](https://github.com/aayush420)
* [Charaf Rezrazi](https://github.com/Rezrazi)
* [misitebao](https://github.com/misitebao)
* [Elie Grenon](https://github.com/DrunkenPoney)
* [Amaury Tobias Quiroz](https://github.com/amaury-tobias)

View File

@@ -147,12 +147,7 @@ This project was mainly coded to the following albums:
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
## Special Thanks
<p align="center" style="text-align: center">
A *huge* thanks to <a href="https://pace.dev"><img src="pace.jpeg"/> Pace</a> for sponsoring the project and helping the efforts to get Wails ported to Apple Silicon!<br/><br/>
If you are looking for a Project Management tool that's powerful but quick and easy to use, check them out!<br/><br/>
</p>
## Special Thank You
<p align="center" style="text-align: center">
A special thank you to JetBrains for donating licenses to us!<br/><br/>

6
app.go
View File

@@ -2,6 +2,7 @@ package wails
import (
"os"
"runtime"
"syscall"
"github.com/syossan27/tebata"
@@ -116,6 +117,11 @@ func (a *App) start() error {
return err
}
// Enable console for Windows debug builds
if runtime.GOOS == "windows" && BuildMode == cmd.BuildModeDebug {
a.renderer.EnableConsole()
}
// Start signal handler
t := tebata.New(os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
t.Reserve(func() {

View File

@@ -1,4 +1,3 @@
//go:build linux || darwin || !windows
// +build linux darwin !windows
package wails

View File

@@ -1,4 +1,3 @@
//go:build windows || !linux || !darwin
// +build windows !linux !darwin
package wails

File diff suppressed because one or more lines are too long

View File

@@ -143,7 +143,6 @@ func BuildDocker(binaryName string, buildMode string, projectOptions *ProjectOpt
"-v", fmt.Sprintf("%s:/build", filepath.Join(fs.Cwd(), "build")),
"-v", fmt.Sprintf("%s:/source", fs.Cwd()),
"-e", fmt.Sprintf("LOCAL_USER_ID=%v", userid),
"-e", fmt.Sprintf("FLAG_TAGS=%s", projectOptions.Tags),
"-e", fmt.Sprintf("FLAG_LDFLAGS=%s", ldFlags(projectOptions, buildMode)),
"-e", "FLAG_V=false",
"-e", "FLAG_X=false",
@@ -249,10 +248,6 @@ func BuildNative(binaryName string, forceRebuild bool, buildMode string, project
buildCommand.AddSlice([]string{"-ldflags", ldFlags(projectOptions, buildMode)})
if projectOptions.Tags != "" {
buildCommand.AddSlice([]string{"--tags", projectOptions.Tags})
}
if projectOptions.Verbose {
fmt.Printf("Command: %v\n", buildCommand.AsSlice())
}
@@ -540,9 +535,6 @@ func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error
func ServeProject(projectOptions *ProjectOptions, logger *Logger) error {
go func() {
time.Sleep(2 * time.Second)
if projectOptions.Platform == "windows" {
logger.Yellow("*** Please note: Windows builds use mshtml which is only compatible with IE11. We strongly recommend only using IE11 when running 'wails serve'! For more information, please read https://wails.app/guides/windows/ ***")
}
logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<")
}()
location, err := filepath.Abs(filepath.Join("build", projectOptions.BinaryName))
@@ -574,10 +566,6 @@ func ldFlags(po *ProjectOptions, buildMode string) string {
ldflags += "-H windowsgui "
}
if po.UseFirebug {
ldflags += "-X github.com/wailsapp/wails/lib/renderer.UseFirebug=true "
}
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
// Add additional ldflags passed in via the `ldflags` cli flag

View File

@@ -65,8 +65,6 @@ const (
Solus
// Ctlos Linux distribution
Ctlos
// EndeavourOS linux distribution
EndeavourOS
)
// DistroInfo contains all the information relating to a linux distribution
@@ -134,7 +132,7 @@ func parseOsRelease(osRelease string) *DistroInfo {
case "archlabs":
result.Distribution = ArchLabs
case "ctlos":
result.Distribution = Ctlos
result.Distribution = Ctlos
case "debian":
result.Distribution = Debian
case "ubuntu":
@@ -173,8 +171,6 @@ func parseOsRelease(osRelease string) *DistroInfo {
result.Distribution = PopOS
case "solus":
result.Distribution = Solus
case "endeavouros":
result.Distribution = EndeavourOS
default:
result.Distribution = Unknown
}

View File

@@ -202,16 +202,7 @@ distributions:
name: Ctlos Linux
gccversioncommand: *gccdumpversion
programs: *archdefaultprograms
libraries: *archdefaultlibraries
endeavouros:
id: endeavouros
releases:
default:
version: default
name: EndeavourOS
gccversioncommand: *gccdumpversion
programs: *archdefaultprograms
libraries: *archdefaultlibraries
libraries: *archdefaultlibraries
manjaro:
id: manjaro
releases:

View File

@@ -6,7 +6,6 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
@@ -151,7 +150,6 @@ type ProjectOptions struct {
Template string `json:"-"`
BinaryName string `json:"binaryname"`
FrontEnd *frontend `json:"frontend,omitempty"`
Tags string `json:"tags"`
NPMProjectName string `json:"-"`
system *SystemHelper
log *Logger
@@ -165,24 +163,6 @@ type ProjectOptions struct {
Architecture string
LdFlags string
GoPath string
UseFirebug bool
// Supported platforms
Platforms []string `json:"platforms,omitempty"`
}
// PlatformSupported returns true if the template is supported
// on the current platform
func (po *ProjectOptions) PlatformSupported() bool {
// Default is all platforms supported
if len(po.Platforms) == 0 {
return true
}
// Check that the platform is in the list
platformsSupported := slicer.String(po.Platforms)
return platformsSupported.Contains(runtime.GOOS)
}
// Defaults sets the default project template
@@ -253,16 +233,13 @@ func (po *ProjectOptions) PromptForInputs() error {
for _, k := range keys {
templateDetail := templateDetails[k]
templateList.Add(templateDetail)
if !templateDetail.Metadata.PlatformSupported() {
templateDetail.Metadata.Name = "* " + templateDetail.Metadata.Name
}
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 (* means unsupported on current platform)", options.AsSlice(), 0)
templateIndex = PromptSelection("Please select a template", options.AsSlice(), 0)
}
if len(templateList.AsSlice()) == 0 {
@@ -273,10 +250,6 @@ func (po *ProjectOptions) PromptForInputs() error {
po.selectedTemplate = templateList.AsSlice()[templateIndex].(*TemplateDetails)
}
po.selectedTemplate.Metadata.Name = strings.TrimPrefix(po.selectedTemplate.Metadata.Name, "* ")
if !po.selectedTemplate.Metadata.PlatformSupported() {
println("WARNING: This template is unsupported on this platform!")
}
fmt.Println("Template: " + po.selectedTemplate.Metadata.Name)
// Setup NPM Project name
@@ -399,9 +372,5 @@ func processTemplateMetadata(templateMetadata *TemplateMetadata, po *ProjectOpti
}
po.FrontEnd.Serve = templateMetadata.Serve
}
// Save platforms
po.Platforms = templateMetadata.Platforms
return nil
}

View File

@@ -24,19 +24,11 @@ func NewSemanticVersion(version string) (*SemanticVersion, error) {
// IsRelease returns true if it's a release version
func (s *SemanticVersion) IsRelease() bool {
// Limit to v1
if s.Version.Major() != 1 {
return false
}
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 {
// Limit to v1
if s.Version.Major() != 1 {
return false
}
return len(s.Version.Prerelease()) > 0
}

View File

@@ -1,65 +0,0 @@
package cmd
import (
"testing"
)
func TestSemanticVersion_IsPreRelease(t *testing.T) {
tests := []struct {
name string
version string
want bool
}{
{"v1.6.7-pre0", "v1.6.7-pre0", true},
{"v2.6.7+pre0", "v2.6.7+pre0", false},
{"v2.6.7", "v2.6.7", false},
{"v2.0.0+alpha.1", "v2.0.0+alpha.1", false},
{"v2.0.0-alpha.1", "v2.0.0-alpha.1", false},
{"v1.6.7", "v1.6.7", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
semanticversion, err := NewSemanticVersion(tt.version)
if err != nil {
t.Errorf("Invalid semantic version: %s", semanticversion)
return
}
s := &SemanticVersion{
Version: semanticversion.Version,
}
if got := s.IsPreRelease(); got != tt.want {
t.Errorf("IsPreRelease() = %v, want %v", got, tt.want)
}
})
}
}
func TestSemanticVersion_IsRelease(t *testing.T) {
tests := []struct {
name string
version string
want bool
}{
{"v1.6.7", "v1.6.7", true},
{"v2.6.7-pre0", "v2.6.7-pre0", false},
{"v2.6.7", "v2.6.7", false},
{"v2.6.7+release", "v2.6.7+release", false},
{"v2.0.0-alpha.1", "v2.0.0-alpha.1", false},
{"v1.6.7-pre0", "v1.6.7-pre0", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
semanticversion, err := NewSemanticVersion(tt.version)
if err != nil {
t.Errorf("Invalid semantic version: %s", semanticversion)
return
}
s := &SemanticVersion{
Version: semanticversion.Version,
}
if got := s.IsRelease(); got != tt.want {
t.Errorf("IsRelease() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -276,7 +276,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
switch distroInfo.Distribution {
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS:
libraryChecker = DpkgInstalled
case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM, EndeavourOS:
case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM:
libraryChecker = PacmanInstalled
case CentOS, Fedora, Tumbleweed, Leap:
libraryChecker = RpmInstalled

View File

@@ -7,7 +7,6 @@ import (
"io/ioutil"
"log"
"path/filepath"
"runtime"
"strings"
"text/template"
@@ -30,26 +29,6 @@ type TemplateMetadata struct {
Bridge string `json:"bridge"`
WailsDir string `json:"wailsdir"`
TemplateDependencies []*TemplateDependency `json:"dependencies,omitempty"`
// List of platforms that this template is supported on.
// No value means all platforms. A platform name is the same string
// as `runtime.GOOS` will return, eg: "darwin". NOTE: This is
// case sensitive.
Platforms []string `json:"platforms,omitempty"`
}
// PlatformSupported returns true if this template supports the
// currently running platform
func (m *TemplateMetadata) PlatformSupported() bool {
// Default is all platforms supported
if len(m.Platforms) == 0 {
return true
}
// Check that the platform is in the list
platformsSupported := slicer.String(m.Platforms)
return platformsSupported.Contains(runtime.GOOS)
}
// TemplateDependency defines a binary dependency for the template
@@ -149,11 +128,11 @@ func (t *TemplateHelper) GetTemplateDetails() (map[string]*TemplateDetails, erro
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

View File

@@ -1,3 +0,0 @@
> 1%
last 2 versions
not dead

View File

@@ -1,29 +0,0 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/typescript/recommended'
],
parserOptions: {
ecmaVersion: 2020
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)'
],
env: {
mocha: true
}
}
]
}

View File

@@ -1,21 +0,0 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

View File

@@ -1,35 +0,0 @@
# vue basic
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your tests
```
npm run test
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@@ -1,37 +0,0 @@
{
"name": "{{.NPMProjectName}}",
"author": "{{.Author.Name}}<{{.Author.Email}}>",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"lint": "vue-cli-service lint"
},
"dependencies": {
"vue": "^3.0.0-0",
"vue-router": "^4.0.0-0",
"regenerator-runtime": "^0.13.7",
"@wailsapp/runtime": "^1.1.1"
},
"devDependencies": {
"@types/chai": "^4.2.12",
"@types/mocha": "^8.0.3",
"@typescript-eslint/eslint-plugin": "^4.3.0",
"@typescript-eslint/parser": "^4.3.0",
"@vue/cli-plugin-eslint": "~4.5.9",
"@vue/cli-plugin-router": "~4.5.9",
"@vue/cli-plugin-typescript": "~4.5.9",
"@vue/cli-plugin-unit-mocha": "~4.5.9",
"@vue/cli-service": "~4.5.9",
"@vue/compiler-sfc": "^3.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"@vue/test-utils": "^2.0.0-0",
"chai": "^4.2.0",
"eslint": "<7.0.0",
"eslint-plugin-vue": "^7.0.0",
"node-sass": "^4.14.1",
"sass-loader": "^10.0.2",
"typescript": "~4.0.3"
}
}

View File

@@ -1,32 +0,0 @@
<template>
<div id=app>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

View File

@@ -1,34 +0,0 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'HelloWorld',
props: {
msg: String,
},
});
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@@ -1,8 +0,0 @@
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import * as Wails from '@wailsapp/runtime';
Wails.Init(() => {
createApp(App).use(router).mount('#app');
});

View File

@@ -1,27 +0,0 @@
import { createRouter, createMemoryHistory, RouteRecordRaw } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
component: About
}
]
const router = createRouter({
history: createMemoryHistory(),
routes
})
export default router

View File

@@ -1,5 +0,0 @@
declare module '*.vue' {
import { defineComponent } from 'vue'
const component: ReturnType<typeof defineComponent>
export default component
}

View File

@@ -1,5 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

View File

@@ -1,40 +0,0 @@
<template>
<div class="home">
<img @click="getMessage" alt="Vue logo" src="../assets/appicon.png" :style="{ height: '400px' }"/>
<HelloWorld :msg="message" />
</div>
</template>
<script lang="ts">
import { ref, defineComponent } from "vue";
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src
interface Backend {
basic(): Promise<string>;
}
declare global {
interface Window {
backend: Backend;
}
}
export default defineComponent({
name: "Home",
components: {
HelloWorld,
},
setup() {
const message = ref("Click the Icon");
const getMessage = () => {
window.backend.basic().then(result => {
message.value = result;
});
}
return { message: message, getMessage: getMessage };
},
});
</script>

View File

@@ -1,14 +0,0 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';
import { shallowMount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message';
const wrapper = shallowMount(HelloWorld, {
props: { msg }
});
expect(wrapper.text()).to.include(msg);
});
});

View File

@@ -1,41 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"mocha",
"chai"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}

View File

@@ -1,42 +0,0 @@
let cssConfig = {};
if (process.env.NODE_ENV == 'production') {
cssConfig = {
extract: {
filename: '[name].css',
chunkFilename: '[name].css'
}
};
}
module.exports = {
chainWebpack: config => {
let limit = 9999999999999999;
config.module
.rule('images')
.test(/\.(png|gif|jpg)(\?.*)?$/i)
.use('url-loader')
.loader('url-loader')
.tap(options => Object.assign(options, { limit: limit }));
config.module
.rule('fonts')
.test(/\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/i)
.use('url-loader')
.loader('url-loader')
.options({
limit: limit
});
},
css: cssConfig,
configureWebpack: {
output: {
filename: '[name].js'
},
optimization: {
splitChunks: false
}
},
devServer: {
disableHostCheck: true
}
};

View File

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

View File

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

View File

@@ -1,15 +0,0 @@
{
"name": "Vue3 Full",
"version": "1.0.0",
"shortdescription": "Vue 3, Vuex, Vue-router, and Webpack4",
"description": "Vue3.0.0 Vuex, Vue-router, and Webpack 4",
"install": "npm install",
"build": "npm run build",
"author": "Kyle Muchmore <kmuchmor@gmail.com>",
"created": "2020-09-24 21:18:55.09417 +0000 UTC m=+90.125590001",
"frontenddir": "frontend",
"serve": "npm run serve",
"bridge": "src",
"wailsdir": "",
"platforms": ["linux", "darwin"]
}

View File

@@ -11,7 +11,7 @@
"core-js": "^3.6.4",
"regenerator-runtime": "^0.13.3",
"vue": "^2.6.11",
"vuetify": "^2.3.15",
"vuetify": "^2.2.15",
"@wailsapp/runtime": "^1.0.10"
},
"devDependencies": {

View File

@@ -24,13 +24,13 @@
<v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-toolbar-title>Application</v-toolbar-title>
</v-app-bar>
<v-main>
<v-content>
<v-container fluid class="px-0">
<v-layout justify-center align-center class="px-0">
<hello-world></hello-world>
</v-layout>
</v-container>
</v-main>
</v-content>
<v-footer app fixed>
<span style="margin-left:1em">&copy; You</span>
</v-footer>
@@ -57,4 +57,4 @@
.logo {
width: 16em;
}
</style>
</style>

View File

@@ -1,4 +1,4 @@
package cmd
// Version - Wails version
const Version = "v1.11.0"
const Version = "v1.8.1-pre1"

View File

@@ -1,4 +1,3 @@
//go:build dev
// +build dev
package main

View File

@@ -1,4 +1,3 @@
//go:build dev
// +build dev
package main

View File

@@ -26,13 +26,11 @@ func init() {
var packageApp = false
var forceRebuild = false
var debugMode = false
var usefirebug = false
var gopath = ""
var typescriptFilename = ""
var verbose = false
var platform = ""
var ldflags = ""
var tags = ""
buildSpinner := spinner.NewSpinner()
buildSpinner.SetSpinSpeed(50)
@@ -43,12 +41,10 @@ func init() {
BoolFlag("p", "Package application on successful build", &packageApp).
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
BoolFlag("d", "Build in Debug mode", &debugMode).
BoolFlag("firebug", "Enable firebug console for debug builds", &usefirebug).
BoolFlag("verbose", "Verbose output", &verbose).
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename).
StringFlag("ldflags", "Extra options for -ldflags", &ldflags).
StringFlag("gopath", "Specify your GOPATH location. Mounted to /go during cross-compilation.", &gopath).
StringFlag("tags", "Build tags to pass to the go compiler (quoted and space separated)", &tags)
StringFlag("gopath", "Specify your GOPATH location. Mounted to /go during cross-compilation.", &gopath)
var b strings.Builder
for _, plat := range getSupportedPlatforms() {
@@ -73,7 +69,6 @@ func init() {
// Project options
projectOptions := &cmd.ProjectOptions{}
projectOptions.Verbose = verbose
projectOptions.UseFirebug = usefirebug
// Check we are in project directory
// Check project.json loads correctly
@@ -83,14 +78,6 @@ func init() {
return fmt.Errorf("Unable to find 'project.json'. Please check you are in a Wails project directory")
}
// Set firebug flag
projectOptions.UseFirebug = usefirebug
// Check that this platform is supported
if !projectOptions.PlatformSupported() {
logger.Yellow("WARNING: This project is unsupported on %s - it probably won't work!\n Valid platforms: %s\n", runtime.GOOS, strings.Join(projectOptions.Platforms, ", "))
}
// Set cross-compile
projectOptions.Platform = runtime.GOOS
if len(platform) > 0 {
@@ -114,9 +101,6 @@ func init() {
projectOptions.LdFlags = ldflags
projectOptions.GoPath = gopath
// Add tags
projectOptions.Tags = tags
// Validate config
// Check if we have a frontend
err = cmd.ValidateFrontendConfig(projectOptions)
@@ -200,10 +184,6 @@ func init() {
return err
}
if projectOptions.Platform == "windows" {
logger.Yellow("*** Please note: Windows builds use mshtml which is only compatible with IE11. For more information, please read https://wails.app/guides/windows/ ***")
}
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
return nil

View File

@@ -70,7 +70,6 @@ func init() {
}
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
return cmd.ServeProject(projectOptions, logger)
})
}

View File

@@ -1,4 +1,3 @@
//go:build windows
// +build windows
package cmd

View File

@@ -1,37 +1,20 @@
package wails
import (
"net/url"
"strings"
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails/runtime"
)
// AppConfig is the configuration structure used when creating a Wails App object
type AppConfig struct {
// The width and height of your application in pixels
Width, Height int
// The title to put in the title bar
Title string
// The HTML your app should use. If you leave it blank, a default will be used:
// <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="IE=edge" content="IE=edge"></head><body><div id="app"></div><script type="text/javascript"></script></body></html>
HTML string
// The Javascript your app should use. Normally this should be generated by a bundler.
JS string
// The CSS your app should use. Normally this should be generated by a bundler.
CSS string
// The colour of your window. Can take "#fff", "rgb(255,255,255)", "rgba(255,255,255,1)" formats
Colour string
// Indicates whether your app should be resizable
Resizable bool
// Indicated if the devtools should be disabled
Width, Height int
Title string
defaultHTML string
HTML string
JS string
CSS string
Colour string
Resizable bool
DisableInspector bool
}
@@ -50,14 +33,9 @@ func (a *AppConfig) GetTitle() string {
return a.Title
}
// GetHTML returns the default HTML
func (a *AppConfig) GetHTML() string {
if len(a.HTML) > 0 {
a.HTML = url.QueryEscape(a.HTML)
a.HTML = "data:text/html," + strings.ReplaceAll(a.HTML, "+", "%20")
a.HTML = strings.ReplaceAll(a.HTML, "%3D", "=")
}
return a.HTML
// GetDefaultHTML returns the default HTML
func (a *AppConfig) GetDefaultHTML() string {
return a.defaultHTML
}
// GetResizable returns true if the window should be resizable
@@ -97,18 +75,10 @@ func (a *AppConfig) merge(in *AppConfig) error {
a.Colour = in.Colour
}
if in.HTML != "" {
a.HTML = in.HTML
}
if in.JS != "" {
a.JS = in.JS
}
if in.HTML != "" {
a.HTML = in.HTML
}
if in.Width != 0 {
a.Width = in.Width
}
@@ -129,7 +99,7 @@ func newConfig(userConfig *AppConfig) (*AppConfig, error) {
Resizable: true,
Title: "My Wails App",
Colour: "#FFF", // White by default
HTML: defaultHTML,
HTML: mewn.String("./runtime/assets/default.html"),
}
if userConfig != nil {
@@ -141,17 +111,3 @@ func newConfig(userConfig *AppConfig) (*AppConfig, error) {
return result, nil
}
var defaultHTML = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body>
<div id="app"></div>
</body>
</html>`

2
go.mod
View File

@@ -22,7 +22,7 @@ require (
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
golang.org/x/text v0.3.0
gopkg.in/AlecAivazis/survey.v1 v1.8.4
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22

3
go.sum
View File

@@ -79,9 +79,8 @@ golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=

View File

@@ -6,9 +6,9 @@ type AppConfig interface {
GetHeight() int
GetTitle() string
GetResizable() bool
GetHTML() string
GetDefaultHTML() string
GetDisableInspector() bool
GetColour() string
GetCSS() string
GetJS() string
}
}

View File

@@ -8,6 +8,7 @@ import (
type Renderer interface {
Initialise(AppConfig, IPCManager, EventManager) error
Run() error
EnableConsole()
// Binding
NewBinding(bindingName string) error

View File

@@ -1,4 +1,4 @@
package interfaces
// Runtime interface
type Runtime interface{}
type Runtime interface {}

View File

@@ -56,6 +56,10 @@ func (h *Bridge) Initialise(appConfig interfaces.AppConfig, ipcManager interface
return nil
}
// EnableConsole not needed for bridge!
func (h *Bridge) EnableConsole() {
}
func (h *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
if err != nil {

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@ package renderer
import (
"time"
"unsafe"
"github.com/gorilla/websocket"
"github.com/leaanthony/mewn"
@@ -49,7 +50,7 @@ func (s *session) Identifier() string {
func (s *session) sendMessage(msg string) error {
if !s.done {
s.writeChan <- []byte(msg)
s.writeChan <- *(*[]byte)(unsafe.Pointer(&msg))
}
return nil
}

File diff suppressed because one or more lines are too long

View File

@@ -18,17 +18,14 @@ import (
// WebView defines the main webview application window
// Default values in []
// UseFirebug indicates whether to inject the firebug console
var UseFirebug = ""
type WebView struct {
window wv.WebView // The webview object
ipc interfaces.IPCManager
log *logger.CustomLogger
config interfaces.AppConfig
eventManager interfaces.EventManager
bindingCache []string
window wv.WebView // The webview object
ipc interfaces.IPCManager
log *logger.CustomLogger
config interfaces.AppConfig
eventManager interfaces.EventManager
bindingCache []string
enableConsole bool
}
// NewWebView returns a new WebView struct
@@ -58,7 +55,7 @@ func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCMana
Height: config.GetHeight(),
Title: config.GetTitle(),
Resizable: config.GetResizable(),
URL: config.GetHTML(),
URL: config.GetDefaultHTML(),
Debug: !config.GetDisableInspector(),
ExternalInvokeCallback: func(_ wv.WebView, message string) {
w.ipc.Dispatch(message, w.callback)
@@ -107,6 +104,11 @@ func (w *WebView) evalJS(js string) error {
return nil
}
// EnableConsole enables the console!
func (w *WebView) EnableConsole() {
w.enableConsole = true
}
// Escape the Javascripts!
func escapeJS(js string) (string, error) {
result := strings.Replace(js, "\\", "\\\\", -1)
@@ -177,9 +179,10 @@ func (w *WebView) Run() error {
w.log.Info("Running...")
// Inject firebug in debug mode on Windows
if UseFirebug != "" {
w.log.Debug("Injecting Firebug")
w.evalJS(`window.usefirebug=true;`)
if w.enableConsole {
w.log.Debug("Enabling Wails console")
console := mewn.String("../../runtime/assets/console.js")
w.evalJS(console)
}
// Runtime assets

View File

@@ -364,7 +364,6 @@ struct webview_priv
webkit_web_view_get_settings(WEBKIT_WEB_VIEW(w->priv.webview));
webkit_settings_set_enable_write_console_messages_to_stdout(settings, true);
webkit_settings_set_enable_developer_extras(settings, true);
webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS);
}
else
{

BIN
pace.jpeg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body>
<div id="app"></div>
<script type="text/javascript">function AddScript(js, callbackID) {
var script = document.createElement('script');
script.text = js;
document.body.appendChild(script);
}</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -3,12 +3,12 @@
"browser": true,
"es6": true,
"amd": true,
"node": true
"node": true,
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2016,
"sourceType": "module"
"sourceType": "module",
},
"rules": {
"indent": [

View File

@@ -26,7 +26,7 @@ export function OpenURL(url) {
* Opens the given filename using the system's default file handler
*
* @export
* @param {string} filename
* @param {sting} filename
* @returns
*/
export function OpenFile(filename) {

View File

@@ -62,7 +62,7 @@ if (window.crypto) {
export function Call(bindingName, data, timeout) {
// Timeout infinite by default
if (timeout == null) {
if (timeout == null || timeout == undefined) {
timeout = 0;
}

View File

@@ -45,7 +45,7 @@ function Invoke(message) {
*
* @export
* @param {string} type
* @param {Object} payload
* @param {string} payload
* @param {string=} callbackID
*/
export function SendMessage(type, payload, callbackID) {

View File

@@ -13,7 +13,7 @@ import * as Browser from './browser';
import { On, OnMultiple, Emit, Notify, Heartbeat, Acknowledge } from './events';
import { NewBinding } from './bindings';
import { Callback } from './calls';
import { AddScript, InjectCSS, InjectFirebug } from './utils';
import { AddScript, InjectCSS } from './utils';
import { AddIPCListener } from './ipc';
import * as Store from './store';
@@ -60,11 +60,6 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
window.wails.Log.Error('error: ' + error);
};
// Use firebug?
if( window.usefirebug ) {
InjectFirebug();
}
// Emit loaded event
Emit('wails:loaded');

View File

@@ -20,18 +20,6 @@ export function AddScript(js, callbackID) {
}
}
export function InjectFirebug() {
// set the debug attribute on HTML
var html = document.getElementsByTagName('html')[0];
html.setAttribute('debug', 'true');
var firebugURL = 'https://wails.app/assets/js/firebug-lite.js#startOpened=true,disableWhenFirebugActive=false';
var script = document.createElement('script');
script.src = firebugURL;
script.type = 'application/javascript';
document.head.appendChild(script);
window.wails.Log.Info('Injected firebug');
}
// Adapted from webview - thanks zserge!
export function InjectCSS(css) {
var elem = document.createElement('style');

View File

@@ -3959,9 +3959,9 @@
"dev": true
},
"ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
},
"interpret": {

View File

@@ -1 +1 @@
index.js
bridge.js

View File

@@ -1,6 +1,6 @@
{
"name": "@wailsapp/runtime",
"version": "1.1.1",
"version": "1.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -130,9 +130,9 @@
"dev": true
},
"ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
},
"invert-kv": {

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
echo "**** Checking if Wails passes unit tests ****"
if ! go test ./lib/... ./runtime/... ./cmd/...
if ! go test ./...
then
echo ""
echo "ERROR: Unit tests failed!"

View File

@@ -1,40 +0,0 @@
# Packing linux
* create app, app.desktop, app.png (512x512)
* chmod +x app!
* ./linuxdeploy-x86_64.AppImage --appdir AppDir -i react.png -d react.desktop -e react --output appimage
# Wails Doctor
Tested on:
* Debian 8
* Ubuntu 20.04
* Ubuntu 19.10
* Solus 4.1
* Centos 8
* Gentoo
* OpenSUSE/leap
* Fedora 31
### Development
Add a new package manager processor here: `v2/internal/system/packagemanager/`. IsAvailable should work even if the package is installed.
Add your new package manager to the list of package managers in `v2/internal/system/packagemanager/packagemanager.go`:
```
var db = map[string]PackageManager{
"eopkg": NewEopkg(),
"apt": NewApt(),
"yum": NewYum(),
"pacman": NewPacman(),
"emerge": NewEmerge(),
"zypper": NewZypper(),
}
```
## Gentoo
* Setup docker image using: emerge-webrsync -x -v

View File

@@ -1,6 +0,0 @@
# Wails v2 ALPHA
This branch contains WORK IN PROGRESS! There are no guarantees. Use at your peril!
This document will be updated as progress is made.

View File

@@ -1,48 +0,0 @@
# Build
The build command processes the Wails project and generates an application binary.
## Usage
`wails build <flags>`
### Flags
| Flag | Details | Default |
| :------------- | :----------- | :------ |
| -clean | Clean the bin directory before building | |
| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go |
| -ldflags "custom ld flags" | Use given ldflags | |
| -o path/to/binary | Compile to given path/filename | |
| -k | Keep generated assets | |
| -package | Create a platform specific package | |
| -production | Compile in production mode: -ldflags="-w -s" + "-h windows" on Windows | |
| -tags | Build tags to pass to Go compiler (quoted and space separated) | |
| -upx | Compress final binary with UPX (if installed) | |
| -upxflags "custom flags" | Flags to pass to upx | |
| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 |
| -delve | If true, runs delve on the compiled binary | false |
## The Build Process
The build process is as follows:
- The flags are processed, and an Options struct built containing the build context.
- The type of target is determined, and a custom build process is followed for target.
### Desktop Target
- The frontend dependencies are installed. The command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored.
- The frontend is then built. This command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored.
- The project directory is checked to see if the `build` directory exists. If not, it is created and default project assets are copied to it.
- An asset bundle is then created by reading the `html` key from `wails.json` and loading the referenced file. This is then parsed, looking for local Javascript and CSS references. Those files are in turn loaded into memory, converted to C data and saved into the asset bundle located at `build/assets.h`, which also includes the original HTML.
- The application icon is then processed: if there is no `build/appicon.png`, a default icon is copied. On Windows, an `app.ico` file is generated from this png. On Mac, `icons.icns` is generated.
- If there are icons in the `build/tray` directory, these are processed, converted to C data and saved as `build/trayicons.h`, ready for the compilation step.
- If there are icons in the `build/dialog` directory, these are processed, converted to C data and saved as `build/userdialogicons.h`, ready for the compilation step.
- If the `-package` flag is given for a Windows target, the Windows assets in the `build/windows` directory are processed: manifest + icons compiled to a `.syso` file (deleted after compilation).
- If we are building a universal binary for Mac, the application is compiled for both `arm64` and `amd64`. The `lipo` tool is then executed to create the universal binary.
- If we are not building a universal binary for Mac, the application is built using `go build`, using build tags to indicate type of application and build mode (debug/production).
- If the `-upx` flag was provided, `upx` is invoked to compress the binary. Custom flags may be provided using the `-upxflags` flag.
- If the `package` flag is given for a non Windows target, the application is bundled for the platform. On Mac, this creates a `.app` with the processed icons, the `Info.plist` in `build/darwin` and the compiled binary.

View File

@@ -1,222 +0,0 @@
package build
import (
"fmt"
"io"
"os"
"os/exec"
"runtime"
"strings"
"text/tabwriter"
"time"
"github.com/wailsapp/wails/v2/internal/system"
"github.com/leaanthony/clir"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/commands/build"
)
// AddBuildSubcommand adds the `build` command for the Wails application
func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
outputType := "desktop"
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
command := app.NewSubCommand("build", "Builds the application")
// Setup noPackage flag
noPackage := false
command.BoolFlag("noPackage", "Skips platform specific packaging", &noPackage)
compilerCommand := "go"
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
compress := false
command.BoolFlag("upx", "Compress final binary with UPX (if installed)", &compress)
compressFlags := ""
command.StringFlag("upxflags", "Flags to pass to upx", &compressFlags)
// Setup Platform flag
platform := runtime.GOOS
command.StringFlag("platform", "Platform to target", &platform)
// Verbosity
verbosity := 1
command.IntFlag("v", "Verbosity level (0 - silent, 1 - default, 2 - verbose)", &verbosity)
// ldflags to pass to `go`
ldflags := ""
command.StringFlag("ldflags", "optional ldflags", &ldflags)
// tags to pass to `go`
tags := ""
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
outputFilename := ""
command.StringFlag("o", "Output filename", &outputFilename)
// Clean build directory
cleanBuildDirectory := false
command.BoolFlag("clean", "Clean the build directory before building", &cleanBuildDirectory)
webview2 := "download"
command.StringFlag("webview2", "WebView2 installer strategy: download,embed,browser,error.", &webview2)
skipFrontend := false
command.BoolFlag("s", "Skips building the frontend", &skipFrontend)
forceBuild := false
command.BoolFlag("f", "Force build application", &forceBuild)
command.Action(func() error {
quiet := verbosity == 0
// Create logger
logger := clilogger.New(w)
logger.Mute(quiet)
// Validate output type
if !validTargetTypes.Contains(outputType) {
return fmt.Errorf("output type '%s' is not valid", outputType)
}
if !quiet {
app.PrintBanner()
}
// Check platform
validPlatformArch := slicer.String([]string{
"darwin",
"darwin/amd64",
"darwin/arm64",
"darwin/universal",
"linux",
//"linux/amd64",
//"linux/arm-7",
"windows",
"windows/amd64",
})
if !validPlatformArch.Contains(platform) {
return fmt.Errorf("platform %s is not supported", platform)
}
if compress && platform == "darwin/universal" {
println("Warning: compress flag unsupported for universal binaries. Ignoring.")
compress = false
}
// Lookup compiler path
compilerPath, err := exec.LookPath(compilerCommand)
if err != nil {
return fmt.Errorf("unable to find compiler: %s", compilerCommand)
}
// Tags
userTags := []string{}
for _, tag := range strings.Split(tags, " ") {
thisTag := strings.TrimSpace(tag)
if thisTag != "" {
userTags = append(userTags, thisTag)
}
}
// Webview2 installer strategy (download by default)
wv2rtstrategy := ""
webview2 = strings.ToLower(webview2)
if webview2 != "" {
validWV2Runtime := slicer.String([]string{"download", "embed", "browser", "error"})
if !validWV2Runtime.Contains(webview2) {
return fmt.Errorf("invalid option for flag 'webview2': %s", webview2)
}
// These are the build tags associated with the strategies
switch webview2 {
case "embed":
wv2rtstrategy = "wv2runtime.embed"
case "error":
wv2rtstrategy = "wv2runtime.error"
case "browser":
wv2rtstrategy = "wv2runtime.browser"
}
}
// Create BuildOptions
buildOptions := &build.Options{
Logger: logger,
OutputType: outputType,
OutputFile: outputFilename,
CleanBuildDirectory: cleanBuildDirectory,
Mode: build.Production,
Pack: !noPackage,
LDFlags: ldflags,
Compiler: compilerCommand,
Verbosity: verbosity,
ForceBuild: forceBuild,
IgnoreFrontend: skipFrontend,
Compress: compress,
CompressFlags: compressFlags,
UserTags: userTags,
WebView2Strategy: wv2rtstrategy,
}
// Calculate platform and arch
platformSplit := strings.Split(platform, "/")
buildOptions.Platform = platformSplit[0]
if system.IsAppleSilicon {
buildOptions.Arch = "arm64"
} else {
buildOptions.Arch = runtime.GOARCH
}
if len(platformSplit) == 2 {
buildOptions.Arch = platformSplit[1]
}
// Start a new tabwriter
w := new(tabwriter.Writer)
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
// Write out the system information
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "App Type: \t%s\n", buildOptions.OutputType)
fmt.Fprintf(w, "Platform: \t%s\n", buildOptions.Platform)
fmt.Fprintf(w, "Arch: \t%s\n", buildOptions.Arch)
fmt.Fprintf(w, "Compiler: \t%s\n", compilerPath)
fmt.Fprintf(w, "Skip Frontend: \t%t\n", skipFrontend)
fmt.Fprintf(w, "Compress: \t%t\n", buildOptions.Compress)
fmt.Fprintf(w, "Package: \t%t\n", buildOptions.Pack)
fmt.Fprintf(w, "Clean Build Dir: \t%t\n", buildOptions.CleanBuildDirectory)
fmt.Fprintf(w, "LDFlags: \t\"%s\"\n", buildOptions.LDFlags)
fmt.Fprintf(w, "Tags: \t[%s]\n", strings.Join(buildOptions.UserTags, ","))
if len(buildOptions.OutputFile) > 0 {
fmt.Fprintf(w, "Output File: \t%s\n", buildOptions.OutputFile)
}
fmt.Fprintf(w, "\n")
w.Flush()
return doBuild(buildOptions)
})
}
// doBuild is our main build command
func doBuild(buildOptions *build.Options) error {
// Start Time
start := time.Now()
outputFilename, err := build.Build(buildOptions)
if err != nil {
return err
}
// Output stats
elapsed := time.Since(start)
buildOptions.Logger.Println("")
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
buildOptions.Logger.Println("")
return nil
}

View File

@@ -1,22 +0,0 @@
# Dev
The dev command allows you to develop your application through a standard browser.
## Usage
`wails dev <flags>`
### Flags
| Flag | Details | Default |
| :------------- | :----------- | :------ |
| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go |
| -ldflags "custom ld flags" | Use given ldflags | |
| -e list,of,extensions | File extensions to trigger rebuilds | go |
| -w | Show warnings | false |
| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 |
| -loglevel | Loglevel to pass to the application - Trace, Debug, Info, Warning, Error | Debug |
## How it works
The project is built using a special mode that starts a webserver and starts listening to port 34115. When the frontend project is run independently, so long as the JS is wrapped with the runtime method `ready`, then the frontend will connect to the backend code via websockets. The interface should be present in your browser, and you should be able to interact with the backend as you would in a desktop app.

View File

@@ -1,385 +0,0 @@
package dev
import (
"fmt"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/internal/project"
"io"
"log"
"net/http"
"os"
"os/signal"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"
"github.com/pkg/browser"
"github.com/wailsapp/wails/v2/internal/colour"
"github.com/fsnotify/fsnotify"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/internal/fs"
"github.com/wailsapp/wails/v2/internal/process"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/commands/build"
)
func LogGreen(message string, args ...interface{}) {
text := fmt.Sprintf(message, args...)
println(colour.Green(text))
}
func LogRed(message string, args ...interface{}) {
text := fmt.Sprintf(message, args...)
println(colour.Red(text))
}
func LogDarkYellow(message string, args ...interface{}) {
text := fmt.Sprintf(message, args...)
println(colour.DarkYellow(text))
}
func sliceToMap(input []string) map[string]struct{} {
result := map[string]struct{}{}
for _, value := range input {
result[value] = struct{}{}
}
return result
}
// AddSubcommand adds the `dev` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("dev", "Development mode")
// Passthrough ldflags
ldflags := ""
command.StringFlag("ldflags", "optional ldflags", &ldflags)
// compiler command
compilerCommand := "go"
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
assetDir := ""
command.StringFlag("assetdir", "Serve assets from the given directory", &assetDir)
// extensions to trigger rebuilds of application
extensions := "go"
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &extensions)
openBrowser := false
command.BoolFlag("browser", "Open application in browser", &openBrowser)
noreload := false
command.BoolFlag("noreload", "Disable reload on asset change", &noreload)
wailsjsdir := ""
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &wailsjsdir)
// tags to pass to `go`
tags := ""
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
// Verbosity
verbosity := 1
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &verbosity)
loglevel := ""
command.StringFlag("loglevel", "Loglevel to use - Trace, Dev, Info, Warning, Error", &loglevel)
forceBuild := false
command.BoolFlag("f", "Force build application", &forceBuild)
command.Action(func() error {
// Create logger
logger := clilogger.New(w)
app.PrintBanner()
cwd, err := os.Getwd()
if err != nil {
return err
}
projectConfig, err := project.Load(cwd)
if err != nil {
return err
}
if projectConfig.AssetDirectory == "" && assetDir == "" {
return fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.")
}
if assetDir == "" && projectConfig.AssetDirectory != "" {
assetDir = projectConfig.AssetDirectory
}
if assetDir != projectConfig.AssetDirectory {
projectConfig.AssetDirectory = filepath.ToSlash(assetDir)
err := projectConfig.Save()
if err != nil {
return err
}
}
if err != nil {
return err
}
if wailsjsdir == "" && projectConfig.WailsJSDir != "" {
wailsjsdir = projectConfig.WailsJSDir
}
if wailsjsdir == "" {
wailsjsdir = "./frontend"
}
if wailsjsdir != projectConfig.WailsJSDir {
projectConfig.WailsJSDir = filepath.ToSlash(wailsjsdir)
err := projectConfig.Save()
if err != nil {
return err
}
}
buildOptions := &build.Options{
Logger: logger,
OutputType: "dev",
Mode: build.Dev,
Arch: runtime.GOARCH,
Pack: true,
Platform: runtime.GOOS,
LDFlags: ldflags,
Compiler: compilerCommand,
ForceBuild: forceBuild,
IgnoreFrontend: false,
Verbosity: verbosity,
WailsJSDir: wailsjsdir,
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
defer func(watcher *fsnotify.Watcher) {
err := watcher.Close()
if err != nil {
log.Fatal(err)
}
}(watcher)
var debugBinaryProcess *process.Process = nil
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(extensions, ","))
// Setup signal handler
quitChannel := make(chan os.Signal, 1)
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
exitCodeChannel := make(chan int, 1)
var passthruArgs []string
//if len(os.Args) > 2 {
// passthruArgs = os.Args[2:]
//}
// Do initial build
logger.Println("Building application for development...")
newProcess, appBinary, err := restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
if err != nil {
return err
}
if newProcess != nil {
debugBinaryProcess = newProcess
}
// open browser
if openBrowser {
err = browser.OpenURL("http://localhost:34115")
if err != nil {
return err
}
}
if err != nil {
return err
}
var newBinaryProcess *process.Process
// Get project dir
projectDir, err := os.Getwd()
if err != nil {
return err
}
// Get all subdirectories
dirs, err := fs.GetSubdirectories(projectDir)
if err != nil {
return err
}
LogGreen("Watching (sub)/directory: %s", projectDir)
// Setup a watcher for non-node_modules directories
dirs.Each(func(dir string) {
if strings.Contains(dir, "node_modules") {
return
}
// Ignore build directory
if strings.HasPrefix(dir, filepath.Join(projectDir, "build")) {
return
}
//println("Watching", dir)
err = watcher.Add(dir)
if err != nil {
logger.Fatal(err.Error())
}
})
// Main Loop
quit := false
// Use 100ms debounce
interval := 100 * time.Millisecond
timer := time.NewTimer(interval)
rebuild := false
reload := false
for quit == false {
//reload := false
select {
case exitCode := <-exitCodeChannel:
if exitCode == 0 {
quit = true
}
case item := <-watcher.Events:
// Check for file writes
if item.Op&fsnotify.Write == fsnotify.Write {
// Ignore directories
if fs.DirExists(item.Name) {
continue
}
// Iterate all file patterns
ext := filepath.Ext(item.Name)
if ext != "" {
ext = ext[1:]
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
rebuild = true
continue
}
}
if strings.HasPrefix(item.Name, assetDir) {
reload = true
}
timer.Reset(interval)
}
// Check for new directories
if item.Op&fsnotify.Create == fsnotify.Create {
// If this is a folder, add it to our watch list
if fs.DirExists(item.Name) {
//node_modules is BANNED!
if !strings.Contains(item.Name, "node_modules") {
err := watcher.Add(item.Name)
if err != nil {
logger.Fatal("%s", err.Error())
}
LogGreen("Added new directory to watcher: %s", item.Name)
}
}
}
case <-timer.C:
if rebuild {
rebuild = false
LogGreen("[Rebuild triggered] files updated")
// Try and build the app
newBinaryProcess, _, err = restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
if err != nil {
LogRed("Error during build: %s", err.Error())
continue
}
// If we have a new process, save it
if newBinaryProcess != nil {
debugBinaryProcess = newBinaryProcess
}
}
if reload {
reload = false
_, err = http.Get("http://localhost:34115/wails/reload")
if err != nil {
LogRed("Error during refresh: %s", err.Error())
}
}
case <-quitChannel:
LogGreen("\nCaught quit")
quit = true
}
}
// Kill the current program if running
if debugBinaryProcess != nil {
err := debugBinaryProcess.Kill()
if err != nil {
return err
}
}
// Remove dev binary
err = os.Remove(appBinary)
if err != nil {
return err
}
LogGreen("Development mode exited")
return nil
})
return nil
}
func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, assetDir string, firstRun bool, exitCodeChannel chan int) (*process.Process, string, error) {
appBinary, err := build.Build(buildOptions)
println()
if err != nil {
if firstRun {
return nil, "", err
}
LogRed("Build error - continuing to run current version")
LogDarkYellow(err.Error())
return nil, "", nil
}
// Kill existing binary if need be
if debugBinaryProcess != nil {
killError := debugBinaryProcess.Kill()
if killError != nil {
logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
}
debugBinaryProcess = nil
}
// Start up new binary with correct args
args := slicer.StringSlicer{}
args.Add("-loglevel", loglevel)
if assetDir != "" {
args.Add("-assetdir", assetDir)
}
if len(passthruArgs) > 0 {
args.AddSlice(passthruArgs)
}
newProcess := process.NewProcess(appBinary, args.AsSlice()...)
err = newProcess.Start(exitCodeChannel)
if err != nil {
// Remove binary
deleteError := fs.DeleteFile(appBinary)
if deleteError != nil {
logger.Fatal("Unable to delete app binary: " + appBinary)
}
logger.Fatal("Unable to start application: %s", err.Error())
}
return newProcess, appBinary, nil
}

View File

@@ -1,158 +0,0 @@
package doctor
import (
"fmt"
"io"
"os"
"runtime"
"strings"
"text/tabwriter"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/internal/system"
"github.com/wailsapp/wails/v2/internal/system/packagemanager"
"github.com/wailsapp/wails/v2/pkg/clilogger"
)
// AddSubcommand adds the `doctor` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("doctor", "Diagnose your environment")
command.Action(func() error {
logger := clilogger.New(w)
app.PrintBanner()
logger.Print("Scanning system - Please wait (this may take a long time)...")
// Get system info
info, err := system.GetInfo()
if err != nil {
logger.Println("Failed.")
return err
}
logger.Println("Done.")
logger.Println("")
// Start a new tabwriter
w := new(tabwriter.Writer)
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
// Write out the system information
fmt.Fprintf(w, "System\n")
fmt.Fprintf(w, "------\n")
fmt.Fprintf(w, "%s\t%s\n", "OS:", info.OS.Name)
fmt.Fprintf(w, "%s\t%s\n", "Version: ", info.OS.Version)
fmt.Fprintf(w, "%s\t%s\n", "ID:", info.OS.ID)
// Output Go Information
fmt.Fprintf(w, "%s\t%s\n", "Go Version:", runtime.Version())
fmt.Fprintf(w, "%s\t%s\n", "Platform:", runtime.GOOS)
fmt.Fprintf(w, "%s\t%s\n", "Architecture:", runtime.GOARCH)
// Exit early if PM not found
if info.PM != nil {
fmt.Fprintf(w, "%s\t%s\n", "Package Manager: ", info.PM.Name())
}
// Output Dependencies Status
var dependenciesMissing = []string{}
var externalPackages = []*packagemanager.Dependancy{}
var dependenciesAvailableRequired = 0
var dependenciesAvailableOptional = 0
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "Dependency\tPackage Name\tStatus\tVersion\n")
fmt.Fprintf(w, "----------\t------------\t------\t-------\n")
hasOptionalDependencies := false
// Loop over dependencies
for _, dependency := range info.Dependencies {
name := dependency.Name
if dependency.Optional {
name = "*" + name
hasOptionalDependencies = true
}
packageName := "Unknown"
status := "Not Found"
// If we found the package
if dependency.PackageName != "" {
packageName = dependency.PackageName
// If it's installed, update the status
if dependency.Installed {
status = "Installed"
} else {
// Generate meaningful status text
status = "Available"
if dependency.Optional {
dependenciesAvailableOptional++
} else {
dependenciesAvailableRequired++
}
}
} else {
if !dependency.Optional {
dependenciesMissing = append(dependenciesMissing, dependency.Name)
}
if dependency.External {
externalPackages = append(externalPackages, dependency)
}
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", name, packageName, status, dependency.Version)
}
if hasOptionalDependencies {
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "* - Optional Dependency\n")
}
w.Flush()
logger.Println("")
logger.Println("Diagnosis")
logger.Println("---------")
// Generate an appropriate diagnosis
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
logger.Println("Your system is ready for Wails development!")
} else {
logger.Println("Your system has missing dependencies!\n")
}
if dependenciesAvailableRequired != 0 {
logger.Println("Required package(s) installation details: \n" + info.Dependencies.InstallAllRequiredCommand())
}
if dependenciesAvailableOptional != 0 {
logger.Println("Optional package(s) installation details: \n" + info.Dependencies.InstallAllOptionalCommand())
}
//
//if len(externalPackages) > 0 {
// for _, p := range externalPackages {
// if p.Optional {
// print("[Optional] ")
// }
// logger.Println("Install " + p.Name + ": " + p.InstallCommand)
// }
//}
if len(dependenciesMissing) != 0 {
// TODO: Check if apps are available locally and if so, adjust the diagnosis
logger.Println("Fatal:")
logger.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
logger.Println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages")
}
logger.Println("")
return nil
})
return nil
}

View File

@@ -1,18 +0,0 @@
# Generate
The `generate` command provides the ability to generate various Wails related components.
## Usage
`wails generate [subcommand] [options]`
## Template
`wails generate template -name <name> [-frontend] [-q]`
Generate a starter template for you to customise.
| Flag | Details |
| :------------- | :----------- |
| -frontend | Copies all the files from the current directory into the template's `frontend` directory. Useful for converting frontend projects created by boilerplate generators. |
| -q | Suppress output |

View File

@@ -1,48 +0,0 @@
package generate
import (
"io"
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate/template"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/parser"
)
// AddSubcommand adds the `generate` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("generate", "Code Generation Tools")
//AddModuleCommand(app, command, w)
template.AddSubCommand(app, command, w)
return nil
}
func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
logger.Println("Processed Go package '" + pkg.Gopackage.Name + "' as '" + pkg.Name + "'")
for _, strct := range pkg.Structs() {
logger.Println("")
logger.Println(" Processed struct '" + strct.Name + "'")
if strct.IsBound {
for _, method := range strct.Methods {
logger.Println(" Bound method '" + method.Name + "'")
}
}
if strct.IsUsedAsData {
for _, field := range strct.Fields {
if !field.Ignored {
logger.Print(" Processed ")
if field.IsOptional {
logger.Print("optional ")
}
logger.Println("field '" + field.Name + "' as '" + field.JSName() + "'")
}
}
}
}
logger.Println("")
}

View File

@@ -1,58 +0,0 @@
package generate
import (
"io"
"time"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/parser"
)
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
// Backend API
backendAPI := parent.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
// Quiet Init
quiet := false
backendAPI.BoolFlag("q", "Suppress output to console", &quiet)
backendAPI.Action(func() error {
// Create logger
logger := clilogger.New(w)
logger.Mute(quiet)
app.PrintBanner()
logger.Print("Generating Javascript module for Go code...")
// Start Time
start := time.Now()
p, err := parser.GenerateWailsFrontendPackage()
if err != nil {
return err
}
logger.Println("done.")
logger.Println("")
elapsed := time.Since(start)
packages := p.Packages
// Print report
for _, pkg := range p.Packages {
if pkg.ShouldGenerate() {
logPackage(pkg, logger)
}
}
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
return nil
})
}

View File

@@ -1,38 +0,0 @@
# Next Steps
Congratulations on generating your template!
## Completing your template
The next steps to complete the template are:
1. Complete the fields in the `template.json` file.
2. Update `README.md`.
3. Edit `wails.tmpl.json` and ensure all fields are correct, especially:
- `html` - path to your `index.html`
- `frontend:install` - The command to install your frontend dependencies
- `frontend:build` - The command to build your frontend
4. Remove any `public` or `dist` directories.
5. Delete this file.
## Testing your template
You can test your template by running this command:
`wails init -name test -t {{.TemplateDir}}`
### Checklist
Once generated, do the following tests:
- Change into the new project directory and run `wails build`. A working binary should be generated in the `build/bin` project directory.
- Run `wails dev`. This will compile your backend and run it. You should be able to go into the frontend directory and run `npm run dev` (or whatever your dev command is) and this should run correctly. You should be able to then open a browser to your local dev server and the application should work.
## Publishing your template
You can publish a template to a git repository and use it as follows:
`wails init -name test -t https://your/git/url`
EG:
`wails init -name test -t https://github.com/leaanthony/testtemplate`

View File

@@ -1,16 +0,0 @@
# README
## About
About your template
## Building
To build this project in debug mode, use `wails build`. For production, use `wails build -production`.
To generate a platform native package, add the `-package` flag.
## Live Development
To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend`
directory and run `npm run dev`. The frontend dev server will run on http://localhost:5000. Connect to this
in your browser and connect to your application.

View File

@@ -1,35 +0,0 @@
package main
import (
"context"
"fmt"
)
// App struct
type App struct {
runtime context.Context
}
// NewApp creates a new App application struct
func NewApp() *App {
return &App{}
}
// startup is called at application startup
func (b *App) startup(ctx context.Context) {
// Perform your setup here
//TODO: move to new runtime layout
//b.runtime = runtime
//runtime.Window.SetTitle("{{.ProjectName}}")
}
// shutdown is called at application termination
func (b *App) shutdown(ctx context.Context) {
// Perform your teardown here
}
// Greet returns a greeting for the given name
func (b *App) Greet(name string) string {
return fmt.Sprintf("Hello %s!", name)
}

View File

@@ -1,27 +0,0 @@
{
"name": "vanilla",
"version": "1.0.0",
"description": "Vanilla Wails v2 template",
"main": "src/main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv dist"
},
"author": "{{.AuthorName}}",
"license": "ISC",
"dependencies": {
"@rollup/plugin-commonjs": "^19.0.0",
"@rollup/plugin-image": "^2.0.6",
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-url": "^6.0.0",
"@wails/runtime": "^1.3.20",
"rollup": "^2.50.4",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-postcss": "^4.0.0",
"rollup-plugin-terser": "^7.0.2",
"sirv-cli": "^1.0.12"
}
}

View File

@@ -1,103 +0,0 @@
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import postcss from 'rollup-plugin-postcss';
import image from '@rollup/plugin-image';
import url from '@rollup/plugin-url';
import copy from 'rollup-plugin-copy';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'dist/main.js'
},
onwarn: handleRollupWarning,
plugins: [
image(),
copy({
targets: [
{ src: 'src/index.html', dest: 'dist' },
{ src: 'src/main.css', dest: 'dist' },
]
}),
// Embed binary files
url({
include: ['**/*.woff', '**/*.woff2'],
limit: Infinity,
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
}),
commonjs(),
// PostCSS preprocessing
postcss({
extensions: ['.css', '.scss'],
extract: true,
minimize: false,
use: [
['sass', {
includePaths: [
'./src',
'./node_modules'
]
}]
],
}),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('dist'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
function handleRollupWarning(warning) {
console.error('ERROR: ' + warning.toString());
}
function serve() {
let server;
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}

View File

@@ -1,18 +0,0 @@
<html>
<head>
<link rel="stylesheet" href="/main.css">
</head>
<body data-wails-drag>
<div id="logo"></div>
<div id="input" data-wails-no-drag>
<input id="name" type="text">
<button onclick="greet()">Greet</button>
</div>
<div id="result"></div>
<script src="/main.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -1,21 +0,0 @@
import {ready} from '@wails/runtime';
ready( () => {
// Get input + focus
let nameElement = document.getElementById("name");
nameElement.focus();
// Setup the greet function
window.greet = function () {
// Get name
let name = nameElement.value;
// Call Basic.Greet(name)
window.backend.main.Basic.Greet(name).then((result) => {
// Update result with data back from Basic.Greet()
document.getElementById("result").innerText = result;
});
};
});

View File

@@ -1,9 +0,0 @@
module test
go 1.16
require (
github.com/wailsapp/wails/v2 v2.0.0-alpha
)
replace github.com/wailsapp/wails/v2 v2.0.0-alpha => {{.WailsDirectory}}

View File

@@ -1,47 +0,0 @@
package main
import (
"log"
"github.com/wailsapp/wails/v2/pkg/options/windows"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/logger"
"github.com/wailsapp/wails/v2/pkg/options"
)
func main() {
// Create application with options
app := NewApp()
err := wails.Run(&options.App{
Title: "{{.ProjectName}}",
Width: 800,
Height: 600,
MinWidth: 400,
MinHeight: 400,
MaxWidth: 1280,
MaxHeight: 1024,
DisableResize: false,
Fullscreen: false,
Frameless: false,
StartHidden: false,
HideWindowOnClose: false,
RGBA: &options.RGBA{0, 0, 0, 255},
Windows: &windows.Options{
WebviewIsTransparent: true,
WindowIsTranslucent: true,
DisableWindowIcon: true,
},
LogLevel: logger.DEBUG,
OnStartup: app.startup,
OnShutdown: app.shutdown,
Bind: []interface{}{
app,
},
})
if err != nil {
log.Fatal(err)
}
}

View File

@@ -1,7 +0,0 @@
{
"name": "Long name",
"shortname": "{{.Name}}",
"author": "",
"description": "Description of the template",
"helpurl": "URL for help with the template, eg homepage"
}

View File

@@ -1,11 +0,0 @@
{
"name": "{{.ProjectName}}",
"outputfilename": "{{.BinaryName}}",
"html": "frontend/dist/index.html",
"frontend:build": "npm run build",
"frontend:install": "npm install",
"author": {
"name": "{{.AuthorName}}",
"email": "{{.AuthorEmail}}"
}
}

View File

@@ -1,188 +0,0 @@
package template
import (
"embed"
"io"
"os"
"path/filepath"
"github.com/leaanthony/debme"
"github.com/leaanthony/gosod"
"github.com/wailsapp/wails/v2/internal/fs"
"github.com/leaanthony/clir"
"github.com/tidwall/sjson"
)
//go:embed base
var base embed.FS
func AddSubCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
// command
command := parent.NewSubCommand("template", "Generates a wails template")
name := ""
command.StringFlag("name", "The name of the template", &name)
migrate := false
command.BoolFlag("migrate", "This indicates that the current directory is a frontend project and should be used by the template", &migrate)
// Quiet Init
quiet := false
command.BoolFlag("q", "Suppress output to console", &quiet)
command.Action(func() error {
// If the current directory is not empty, we create a new directory
cwd, err := os.Getwd()
if err != nil {
return err
}
templateDir := cwd
empty, err := fs.DirIsEmpty(templateDir)
if err != nil {
return err
}
if !empty {
templateDir = filepath.Join(cwd, name)
println("Creating new template directory:", name)
err = fs.Mkdir(templateDir)
if err != nil {
return err
}
}
// Create base template
baseTemplate, err := debme.FS(base, "base")
if err != nil {
return err
}
g := gosod.New(baseTemplate)
g.SetTemplateFilters([]string{".template"})
err = os.Chdir(templateDir)
if err != nil {
return err
}
type templateData struct {
Name string
Description string
TemplateDir string
}
println("Extracting base template files...")
err = g.Extract(templateDir, &templateData{
Name: name,
TemplateDir: templateDir,
})
if err != nil {
return err
}
// If we aren't migrating the files, just exit
if migrate == false {
return nil
}
// Remove frontend directory
frontendDir := filepath.Join(templateDir, "frontend")
err = os.RemoveAll(frontendDir)
if err != nil {
return err
}
// Move the files into a new frontend directory
println("Migrating files to frontend directory...")
err = fs.MoveDirExtended(cwd, frontendDir, []string{name})
if err != nil {
return err
}
// Process package.json
err = processPackageJSON(frontendDir)
if err != nil {
return err
}
// Process package-lock.json
err = processPackageLockJSON(frontendDir)
if err != nil {
return err
}
// Remove node_modules - ignore error, eg it doesn't exist
_ = os.RemoveAll(filepath.Join(frontendDir, "node_modules"))
return nil
})
}
func processPackageJSON(frontendDir string) error {
var err error
packageJSON := filepath.Join(frontendDir, "package.json")
if !fs.FileExists(packageJSON) {
println("No package.json found - cannot process.")
return nil
}
data, err := os.ReadFile(packageJSON)
if err != nil {
return err
}
json := string(data)
// We will ignore these errors - it's not critical
println("Updating package.json data...")
json, _ = sjson.Set(json, "name", "{{.ProjectName}}")
json, _ = sjson.Set(json, "author", "{{.AuthorName}}")
err = os.WriteFile(packageJSON, []byte(json), 0644)
if err != nil {
return err
}
baseDir := filepath.Dir(packageJSON)
println("Renaming package.json -> package.tmpl.json...")
err = os.Rename(packageJSON, filepath.Join(baseDir, "package.tmpl.json"))
if err != nil {
return err
}
return nil
}
func processPackageLockJSON(frontendDir string) error {
var err error
filename := filepath.Join(frontendDir, "package-lock.json")
if !fs.FileExists(filename) {
println("No package-lock.json found - cannot process.")
return nil
}
data, err := os.ReadFile(filename)
if err != nil {
return err
}
json := string(data)
// We will ignore these errors - it's not critical
println("Updating package-lock.json data...")
json, _ = sjson.Set(json, "name", "{{.ProjectName}}")
err = os.WriteFile(filename, []byte(json), 0644)
if err != nil {
return err
}
baseDir := filepath.Dir(filename)
println("Renaming package-lock.json -> package-lock.tmpl.json...")
err = os.Rename(filename, filepath.Join(baseDir, "package-lock.tmpl.json"))
if err != nil {
return err
}
return nil
}

View File

@@ -1,177 +0,0 @@
package initialise
import (
"fmt"
"io"
"strings"
"time"
"github.com/wailsapp/wails/v2/pkg/buildassets"
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise/templates"
"github.com/leaanthony/clir"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/git"
)
// AddSubcommand adds the `init` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("init", "Initialise a new Wails project")
// Setup template name flag
templateName := "vanilla"
description := "Name of built-in template to use, path to template or template url."
command.StringFlag("t", description, &templateName)
// Setup project name
projectName := ""
command.StringFlag("n", "Name of project", &projectName)
// Setup project directory
projectDirectory := ""
command.StringFlag("d", "Project directory", &projectDirectory)
// Quiet Init
quiet := false
command.BoolFlag("q", "Suppress output to console", &quiet)
initGit := false
gitInstalled := git.IsInstalled()
if gitInstalled {
// Git Init
command.BoolFlag("g", "Initialise git repository", &initGit)
}
// VSCode project files
vscode := false
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
// List templates
list := false
command.BoolFlag("l", "List templates", &list)
command.Action(func() error {
// Create logger
logger := clilogger.New(w)
logger.Mute(quiet)
// Are we listing templates?
if list {
app.PrintBanner()
err := templates.OutputList(logger)
logger.Println("")
return err
}
// Validate name
if len(projectName) == 0 {
logger.Println("ERROR: Project name required")
logger.Println("")
command.PrintHelp()
return nil
}
if !quiet {
app.PrintBanner()
}
task := fmt.Sprintf("Initialising Project %s", strings.Title(projectName))
logger.Println(task)
logger.Println(strings.Repeat("-", len(task)))
// Create Template Options
options := &templates.Options{
ProjectName: projectName,
TargetDir: projectDirectory,
TemplateName: templateName,
Logger: logger,
GenerateVSCode: vscode,
InitGit: initGit,
}
// Try to discover author details from git config
findAuthorDetails(options)
return initProject(options)
})
return nil
}
// initProject is our main init command
func initProject(options *templates.Options) error {
// Start Time
start := time.Now()
// Install the template
remote, err := templates.Install(options)
if err != nil {
return err
}
// Install the default assets
err = buildassets.Install(options.TargetDir, options.ProjectName)
if err != nil {
return err
}
if options.InitGit {
err = initGit(options)
if err != nil {
return err
}
}
// Output stats
elapsed := time.Since(start)
options.Logger.Println("")
options.Logger.Println("Project Name: " + options.ProjectName)
options.Logger.Println("Project Directory: " + options.TargetDir)
options.Logger.Println("Project Template: " + options.TemplateName)
if options.GenerateVSCode {
options.Logger.Println("VSCode config files generated.")
}
if options.InitGit {
options.Logger.Println("Git repository initialised.")
}
if remote {
options.Logger.Println("\nNOTE: You have created a project using a remote template. The Wails project takes no responsibility for 3rd party templates. Only use remote templates that you trust.")
}
options.Logger.Println("")
options.Logger.Println(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
options.Logger.Println("")
return nil
}
func initGit(options *templates.Options) error {
err := git.InitRepo(options.TargetDir)
if err != nil {
return errors.Wrap(err, "Unable to initialise git repository:")
}
return nil
}
// findAuthorDetails tries to find the user's name and email
// from gitconfig. If it finds them, it stores them in the project options
func findAuthorDetails(options *templates.Options) {
if git.IsInstalled() {
name, err := git.Name()
if err == nil {
options.AuthorName = strings.TrimSpace(name)
}
email, err := git.Email()
if err == nil {
options.AuthorEmail = strings.TrimSpace(email)
}
}
}

View File

@@ -1,27 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Wails: Debug {{.ProjectName}} (Desktop)",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "${workspaceFolder}/{{.PathToDesktopBinary}}",
"preLaunchTask": "build_desktop",
"cwd": "",
"env": {},
"args": []
},
{
"name": "Wails: Debug {{.ProjectName}} (Server)",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "${workspaceFolder}/{{.PathToServerBinary}}",
"preLaunchTask": "build_server",
"cwd": "",
"env": {},
"args": []
},
]
}

View File

@@ -1,23 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build_desktop",
"type": "shell",
"options": {
"cwd": "{{.TargetDir}}"
},
"command": "wails build"
},
{
"label": "build_server",
"type": "shell",
"options": {
"cwd": "{{.TargetDir}}"
},
"command": "wails build -t server"
},
]
}

View File

@@ -1,366 +0,0 @@
package templates
import (
"embed"
"encoding/json"
"fmt"
gofs "io/fs"
"io/ioutil"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/go-git/go-git/v5"
"github.com/pkg/errors"
"github.com/leaanthony/debme"
"github.com/leaanthony/gosod"
"github.com/olekukonko/tablewriter"
"github.com/wailsapp/wails/v2/internal/fs"
"github.com/wailsapp/wails/v2/pkg/clilogger"
)
//go:embed templates
var templates embed.FS
//go:embed ides/*
var ides embed.FS
// Cahce for the templates
// We use this because we need different views of the same data
var templateCache []Template = nil
// Data contains the data we wish to embed during template installation
type Data struct {
ProjectName string
BinaryName string
WailsVersion string
NPMProjectName string
AuthorName string
AuthorEmail string
AuthorNameAndEmail string
WailsDirectory string
}
// Options for installing a template
type Options struct {
ProjectName string
TemplateName string
BinaryName string
TargetDir string
Logger *clilogger.CLILogger
GenerateVSCode bool
PathToDesktopBinary string
PathToServerBinary string
InitGit bool
AuthorName string
AuthorEmail string
}
// Template holds data relating to a template
// including the metadata stored in template.json
type Template struct {
// Template details
Name string `json:"name"`
ShortName string `json:"shortname"`
Author string `json:"author"`
Description string `json:"description"`
HelpURL string `json:"helpurl"`
// Other data
FS gofs.FS `json:"-"`
}
func parseTemplate(template gofs.FS) (Template, error) {
var result Template
data, err := gofs.ReadFile(template, "template.json")
if err != nil {
return result, errors.Wrap(err, "Error parsing template")
}
err = json.Unmarshal(data, &result)
if err != nil {
return result, err
}
result.FS = template
return result, nil
}
// List returns the list of available templates
func List() ([]Template, error) {
// If the cache isn't loaded, load it
if templateCache == nil {
err := loadTemplateCache()
if err != nil {
return nil, err
}
}
return templateCache, nil
}
// getTemplateByShortname returns the template with the given short name
func getTemplateByShortname(shortname string) (Template, error) {
var result Template
// If the cache isn't loaded, load it
if templateCache == nil {
err := loadTemplateCache()
if err != nil {
return result, err
}
}
for _, template := range templateCache {
if template.ShortName == shortname {
return template, nil
}
}
return result, fmt.Errorf("shortname '%s' is not a valid template shortname", shortname)
}
// Loads the template cache
func loadTemplateCache() error {
templatesFS, err := debme.FS(templates, "templates")
if err != nil {
return err
}
// Get directories
files, err := templatesFS.ReadDir(".")
if err != nil {
return err
}
// Reset cache
templateCache = []Template{}
for _, file := range files {
if file.IsDir() {
templateFS, err := templatesFS.FS(file.Name())
if err != nil {
return err
}
template, err := parseTemplate(templateFS)
if err != nil {
// Cannot parse this template, continue
continue
}
templateCache = append(templateCache, template)
}
}
return nil
}
// Install the given template. Returns true if the template is remote.
func Install(options *Options) (bool, error) {
// Get cwd
cwd, err := os.Getwd()
if err != nil {
return false, err
}
// Did the user want to install in current directory?
if options.TargetDir == "" {
// If the current directory is empty, use it
isEmpty, err := fs.DirIsEmpty(cwd)
if err != nil {
return false, err
}
if isEmpty {
// Yes - use cwd
options.TargetDir = cwd
} else {
options.TargetDir = filepath.Join(cwd, options.ProjectName)
if fs.DirExists(options.TargetDir) {
return false, fmt.Errorf("cannot create project directory. Dir exists: %s", options.TargetDir)
}
}
} else {
// Get the absolute path of the given directory
targetDir, err := filepath.Abs(filepath.Join(cwd, options.TargetDir))
if err != nil {
return false, err
}
options.TargetDir = targetDir
if !fs.DirExists(options.TargetDir) {
err := fs.Mkdir(options.TargetDir)
if err != nil {
return false, err
}
}
}
// Flag to indicate remote template
remoteTemplate := false
// Is this a shortname?
template, err := getTemplateByShortname(options.TemplateName)
if err != nil {
// Is this a filepath?
templatePath, err := filepath.Abs(options.TemplateName)
if fs.DirExists(templatePath) {
templateFS := os.DirFS(templatePath)
template, err = parseTemplate(templateFS)
if err != nil {
return false, errors.Wrap(err, "Error installing template")
}
} else {
// git clone to temporary dir
tempdir, err := gitclone(options)
defer func(path string) {
err := os.RemoveAll(path)
if err != nil {
log.Fatal(err)
}
}(tempdir)
if err != nil {
return false, err
}
// Remove the .git directory
err = os.RemoveAll(filepath.Join(tempdir, ".git"))
if err != nil {
return false, err
}
templateFS := os.DirFS(tempdir)
template, err = parseTemplate(templateFS)
if err != nil {
return false, err
}
remoteTemplate = true
}
}
// Use Gosod to install the template
installer := gosod.New(template.FS)
// Ignore template.json files
installer.IgnoreFile("template.json")
// Setup the data.
// We use the directory name for the binary name, like Go
BinaryName := filepath.Base(options.TargetDir)
NPMProjectName := strings.ToLower(strings.ReplaceAll(BinaryName, " ", ""))
localWailsDirectory := fs.RelativePath("../../../../../..")
templateData := &Data{
ProjectName: options.ProjectName,
BinaryName: filepath.Base(options.TargetDir),
NPMProjectName: NPMProjectName,
WailsDirectory: localWailsDirectory,
AuthorEmail: options.AuthorEmail,
AuthorName: options.AuthorName,
}
// Create a formatted name and email combo.
if options.AuthorName != "" {
templateData.AuthorNameAndEmail = options.AuthorName + " "
}
if options.AuthorEmail != "" {
templateData.AuthorNameAndEmail += "<" + options.AuthorEmail + ">"
}
templateData.AuthorNameAndEmail = strings.TrimSpace(templateData.AuthorNameAndEmail)
// Extract the template
err = installer.Extract(options.TargetDir, templateData)
if err != nil {
return false, err
}
err = generateIDEFiles(options)
if err != nil {
return false, err
}
return remoteTemplate, nil
}
// Clones the given uri and returns the temporary cloned directory
func gitclone(options *Options) (string, error) {
// Create temporary directory
dirname, err := ioutil.TempDir("", "wails-template-*")
if err != nil {
return "", err
}
_, err = git.PlainClone(dirname, false, &git.CloneOptions{
URL: options.TemplateName,
})
return dirname, err
}
// OutputList prints the list of available tempaltes to the given logger
func OutputList(logger *clilogger.CLILogger) error {
templates, err := List()
if err != nil {
return err
}
table := tablewriter.NewWriter(logger.Writer)
table.SetHeader([]string{"Template", "Short Name", "Description"})
table.SetAutoWrapText(false)
table.SetAutoFormatHeaders(true)
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetRowSeparator("")
table.SetHeaderLine(false)
table.SetBorder(false)
table.SetTablePadding("\t") // pad with tabs
table.SetNoWhiteSpace(true)
for _, template := range templates {
table.Append([]string{template.Name, template.ShortName, template.Description})
}
table.Render()
return nil
}
func generateIDEFiles(options *Options) error {
if options.GenerateVSCode {
return generateVSCodeFiles(options)
}
return nil
}
func generateVSCodeFiles(options *Options) error {
targetDir := filepath.Join(options.TargetDir, ".vscode")
source, err := debme.FS(ides, "ides/vscode")
if err != nil {
return err
}
// Use gosod to install the template
installer := gosod.New(source)
binaryName := filepath.Base(options.TargetDir)
if runtime.GOOS == "windows" {
// yay windows
binaryName += ".exe"
}
options.PathToDesktopBinary = filepath.Join("build", runtime.GOOS, "desktop", binaryName)
options.PathToServerBinary = filepath.Join("build", runtime.GOOS, "server", binaryName)
err = installer.Extract(targetDir, options)
if err != nil {
return err
}
return nil
}

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