mirror of
https://github.com/wavetermdev/wails.git
synced 2026-04-22 15:26:15 -07:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 62d97f85ec | |||
| 496461920f | |||
| 22b53192e6 | |||
| c1a0e1338f | |||
| 7266f2a78a | |||
| 774cbdec38 | |||
| ba6b28b3c2 | |||
| 3d68ef0115 | |||
| 0342023990 | |||
| 2922a98f7c | |||
| b82be31d7e | |||
| 8d7c033a66 | |||
| 516c4853f9 | |||
| 832d6bc4d3 | |||
| fa0afe92f0 | |||
| ea40cf8705 | |||
| 3853d2d1bf | |||
| d249c2207b | |||
| 0bf41090b0 | |||
| 529ec569f7 | |||
| 7c1490a8b1 |
@@ -1 +0,0 @@
|
||||
runtime/assets/default.html
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true,
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2016,
|
||||
"sourceType": "module",
|
||||
},
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
"tab"
|
||||
],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"single"
|
||||
],
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Discord Chat
|
||||
url: https://discord.gg/BrRSWTaxVK
|
||||
about: Ask questions and discuss with other Wails users in real time.
|
||||
|
||||
- name: GitHub Community Discussions
|
||||
url: https://github.com/wailsapp/wails/discussions
|
||||
about: If your question is not a feature or a bug, please go to the discussion panel and retrieve if your question already exists before submitting.
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# Description
|
||||
|
||||
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
|
||||
|
||||
Fixes # (issue)
|
||||
|
||||
## Type of change
|
||||
|
||||
Please delete options that are not relevant.
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] This change requires a documentation update
|
||||
|
||||
# How Has This Been Tested?
|
||||
|
||||
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration using `wails doctor`.
|
||||
|
||||
- [ ] Windows
|
||||
- [ ] macOS
|
||||
- [ ] Linux
|
||||
|
||||
## Test Configuration
|
||||
|
||||
Please paste the output of `wails doctor`. If you are unable to run this command, please describe your environment in as much detail as possible.
|
||||
|
||||
# Checklist:
|
||||
|
||||
- [ ] I have updated `website/src/pages/changelog.mdx` with details of this PR
|
||||
- [ ] My code follows the general coding style of this project
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have made corresponding changes to the documentation
|
||||
- [ ] My changes generate no new warnings
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] New and existing unit tests pass locally with my changes
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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:'
|
||||
@@ -1,6 +0,0 @@
|
||||
jshint:
|
||||
config_file: .jshintrc
|
||||
eslint:
|
||||
enabled: true
|
||||
config_file: .eslintrc
|
||||
ignore_file: .eslintignore
|
||||
+3
-2
@@ -26,8 +26,8 @@
|
||||
<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://app.slack.com/client/T029RQSE6/CJ4P9F7MZ">
|
||||
<img alt="Slack" src="https://img.shields.io/badge/slack-gophers%2Fwails%20-blue?logo=slack"/>
|
||||
<a href="https://discord.gg/BrRSWTaxVK">
|
||||
<img alt="Discord" src="https://dcbadge.vercel.app/api/server/BrRSWTaxVK?style=flat"/>
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://github.com/wailsapp/wails/actions/workflows/build-and-test.yml" rel="nofollow">
|
||||
@@ -58,6 +58,7 @@
|
||||
- [スポンサー](#スポンサー)
|
||||
- [始め方](#始め方)
|
||||
- [FAQ](#faq)
|
||||
- [スター数の推移](#スター数の推移)
|
||||
- [コントリビューター](#コントリビューター)
|
||||
- [特記事項](#特記事項)
|
||||
- [スペシャルサンクス](#スペシャルサンクス)
|
||||
|
||||
+3
-2
@@ -26,8 +26,8 @@
|
||||
<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://app.slack.com/client/T029RQSE6/CJ4P9F7MZ">
|
||||
<img alt="Slack" src="https://img.shields.io/badge/slack-gophers%2Fwails%20-blue?logo=slack"/>
|
||||
<a href="https://discord.gg/BrRSWTaxVK">
|
||||
<img alt="Discord" src="https://dcbadge.vercel.app/api/server/BrRSWTaxVK?style=flat"/>
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://github.com/wailsapp/wails/actions/workflows/build-and-test.yml" rel="nofollow">
|
||||
@@ -57,6 +57,7 @@
|
||||
- [시작하기](#시작하기)
|
||||
- [스폰서](#스폰서)
|
||||
- [FAQ](#faq)
|
||||
- [Stargazers 성장 추세](#stargazers-성장-추세)
|
||||
- [기여자](#기여자)
|
||||
- [라이센스](#라이센스)
|
||||
- [영감](#영감)
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
<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://app.slack.com/client/T029RQSE6/CJ4P9F7MZ">
|
||||
<img alt="Slack" src="https://img.shields.io/badge/slack-gophers%2Fwails%20-blue?logo=slack"/>
|
||||
<a href="https://discord.gg/BrRSWTaxVK">
|
||||
<img alt="Discord" src="https://dcbadge.vercel.app/api/server/BrRSWTaxVK?style=flat"/>
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://github.com/wailsapp/wails/actions/workflows/build-and-test.yml" rel="nofollow">
|
||||
@@ -55,6 +55,7 @@
|
||||
- [Getting Started](#getting-started)
|
||||
- [Sponsors](#sponsors)
|
||||
- [FAQ](#faq)
|
||||
- [Stargazers over time](#stargazers-over-time)
|
||||
- [Contributors](#contributors)
|
||||
- [License](#license)
|
||||
- [Inspiration](#inspiration)
|
||||
@@ -91,9 +92,9 @@ The installation instructions are on the [official website](https://wails.io/doc
|
||||
|
||||
## Sponsors
|
||||
|
||||
|
||||
This project is supported by these kind people / companies:
|
||||
<img src="website/static/img/sponsors.svg" style="width:100%;max-width:800px;"/>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://wails.io/img/sponsor/jetbrains-grayscale.webp" style="width: 100px"/>
|
||||
</p>
|
||||
|
||||
+3
-2
@@ -26,8 +26,8 @@
|
||||
<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://app.slack.com/client/T029RQSE6/CJ4P9F7MZ">
|
||||
<img alt="Slack" src="https://img.shields.io/badge/slack-gophers%2Fwails%20-blue?logo=slack"/>
|
||||
<a href="https://discord.gg/BrRSWTaxVK">
|
||||
<img alt="Discord" src="https://dcbadge.vercel.app/api/server/BrRSWTaxVK?style=flat"/>
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://github.com/wailsapp/wails/actions/workflows/build-and-test.yml" rel="nofollow">
|
||||
@@ -57,6 +57,7 @@
|
||||
- [快速入门](#快速入门)
|
||||
- [赞助商](#赞助商)
|
||||
- [常见问题](#常见问题)
|
||||
- [星星增长趋势](#星星增长趋势)
|
||||
- [贡献者](#贡献者)
|
||||
- [许可证](#许可证)
|
||||
- [灵感](#灵感)
|
||||
|
||||
+1
-1
@@ -21,4 +21,4 @@ tasks:
|
||||
release:
|
||||
dir: v2/tools/release
|
||||
cmds:
|
||||
- go run release.go
|
||||
- go run release.go {{.CLI_ARGS}}
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
package wails
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/syossan27/tebata"
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
"github.com/wailsapp/wails/lib/binding"
|
||||
"github.com/wailsapp/wails/lib/event"
|
||||
"github.com/wailsapp/wails/lib/interfaces"
|
||||
"github.com/wailsapp/wails/lib/ipc"
|
||||
"github.com/wailsapp/wails/lib/logger"
|
||||
"github.com/wailsapp/wails/lib/renderer"
|
||||
wailsruntime "github.com/wailsapp/wails/runtime"
|
||||
)
|
||||
|
||||
// -------------------------------- Compile time Flags ------------------------------
|
||||
|
||||
// BuildMode indicates what mode we are in
|
||||
var BuildMode = cmd.BuildModeProd
|
||||
|
||||
// Runtime is the Go Runtime struct
|
||||
type Runtime = wailsruntime.Runtime
|
||||
|
||||
// Store is a state store used for syncing with
|
||||
// the front end
|
||||
type Store = wailsruntime.Store
|
||||
|
||||
// CustomLogger is a specialised logger
|
||||
type CustomLogger = logger.CustomLogger
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
// App defines the main application struct
|
||||
type App struct {
|
||||
config *AppConfig // The Application configuration object
|
||||
cli *cmd.Cli // In debug mode, we have a cli
|
||||
renderer interfaces.Renderer // The renderer is what we will render the app to
|
||||
logLevel string // The log level of the app
|
||||
ipc interfaces.IPCManager // Handles the IPC calls
|
||||
log *logger.CustomLogger // Logger
|
||||
bindingManager interfaces.BindingManager // Handles binding of Go code to renderer
|
||||
eventManager interfaces.EventManager // Handles all the events
|
||||
runtime interfaces.Runtime // The runtime object for registered structs
|
||||
}
|
||||
|
||||
// CreateApp creates the application window with the given configuration
|
||||
// If none given, the defaults are used
|
||||
func CreateApp(optionalConfig ...*AppConfig) *App {
|
||||
var userConfig *AppConfig
|
||||
if len(optionalConfig) > 0 {
|
||||
userConfig = optionalConfig[0]
|
||||
}
|
||||
|
||||
result := &App{
|
||||
logLevel: "debug",
|
||||
renderer: renderer.NewWebView(),
|
||||
ipc: ipc.NewManager(),
|
||||
bindingManager: binding.NewManager(),
|
||||
eventManager: event.NewManager(),
|
||||
log: logger.NewCustomLogger("App"),
|
||||
}
|
||||
|
||||
appconfig, err := newConfig(userConfig)
|
||||
if err != nil {
|
||||
result.log.Fatalf("Cannot use custom HTML: %s", err.Error())
|
||||
}
|
||||
result.config = appconfig
|
||||
|
||||
// Set up the CLI if not in release mode
|
||||
if BuildMode != cmd.BuildModeProd {
|
||||
result.cli = result.setupCli()
|
||||
} else {
|
||||
// Disable Inspector in release mode
|
||||
result.config.DisableInspector = true
|
||||
}
|
||||
|
||||
// Platform specific init
|
||||
platformInit()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Run the app
|
||||
func (a *App) Run() error {
|
||||
|
||||
if BuildMode != cmd.BuildModeProd {
|
||||
return a.cli.Run()
|
||||
}
|
||||
|
||||
a.logLevel = "error"
|
||||
err := a.start()
|
||||
if err != nil {
|
||||
a.log.Error(err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *App) start() error {
|
||||
|
||||
// Set the log level
|
||||
logger.SetLogLevel(a.logLevel)
|
||||
|
||||
// Log starup
|
||||
a.log.Info("Starting")
|
||||
|
||||
// Check if we are to run in bridge mode
|
||||
if BuildMode == cmd.BuildModeBridge {
|
||||
a.renderer = renderer.NewBridge()
|
||||
}
|
||||
|
||||
// Initialise the renderer
|
||||
err := a.renderer.Initialise(a.config, a.ipc, a.eventManager)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Start signal handler
|
||||
t := tebata.New(os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
|
||||
t.Reserve(func() {
|
||||
a.log.Debug("SIGNAL CAUGHT! Starting Shutdown")
|
||||
a.renderer.Close()
|
||||
})
|
||||
|
||||
// Start event manager and give it our renderer
|
||||
a.eventManager.Start(a.renderer)
|
||||
|
||||
// Start the IPC Manager and give it the event manager and binding manager
|
||||
a.ipc.Start(a.eventManager, a.bindingManager)
|
||||
|
||||
// Create the runtime
|
||||
a.runtime = wailsruntime.NewRuntime(a.eventManager, a.renderer)
|
||||
|
||||
// Start binding manager and give it our renderer
|
||||
err = a.bindingManager.Start(a.renderer, a.runtime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Defer the shutdown
|
||||
defer a.shutdown()
|
||||
|
||||
// Run the renderer
|
||||
err = a.renderer.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// shutdown the app
|
||||
func (a *App) shutdown() {
|
||||
// Make sure this is only called once
|
||||
a.log.Debug("Shutting down")
|
||||
|
||||
// Shutdown Binding Manager
|
||||
a.bindingManager.Shutdown()
|
||||
|
||||
// Shutdown IPC Manager
|
||||
a.ipc.Shutdown()
|
||||
|
||||
// Shutdown Event Manager
|
||||
a.eventManager.Shutdown()
|
||||
|
||||
a.log.Debug("Cleanly Shutdown")
|
||||
}
|
||||
|
||||
// Bind allows the user to bind the given object
|
||||
// with the application
|
||||
func (a *App) Bind(object interface{}) {
|
||||
a.bindingManager.Bind(object)
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
//go:build linux || darwin || !windows
|
||||
// +build linux darwin !windows
|
||||
|
||||
package wails
|
||||
|
||||
func platformInit() {
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
//go:build windows || !linux || !darwin
|
||||
// +build windows !linux !darwin
|
||||
|
||||
package wails
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func platformInit() {
|
||||
err := SetProcessDPIAware()
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// SetProcessDPIAware via user32.dll
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiaware
|
||||
// Also, thanks Jack Mordaunt! https://github.com/wailsapp/wails/issues/293
|
||||
func SetProcessDPIAware() error {
|
||||
status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
||||
if status == 0 {
|
||||
return fmt.Errorf("exit status %d: %v %v", status, r, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package wails
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
)
|
||||
|
||||
// setupCli creates a new cli handler for the application
|
||||
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
|
||||
result.
|
||||
StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel).
|
||||
Action(app.start)
|
||||
|
||||
// Banner
|
||||
result.PreRun(func(cli *cmd.Cli) error {
|
||||
log := cmd.NewLogger()
|
||||
log.YellowUnderline(app.config.Title + " - Debug Build")
|
||||
return nil
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
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"
|
||||
)
|
||||
-285
@@ -1,285 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewCli - Creates a new Cli application object
|
||||
func NewCli(name, description string) *Cli {
|
||||
result := &Cli{}
|
||||
result.rootCommand = NewCommand(name, description, result, "")
|
||||
result.log = NewLogger()
|
||||
return result
|
||||
}
|
||||
|
||||
// Cli - The main application object
|
||||
type Cli struct {
|
||||
rootCommand *Command
|
||||
defaultCommand *Command
|
||||
preRunCommand func(*Cli) error
|
||||
log *Logger
|
||||
}
|
||||
|
||||
// Version - Set the Application version string
|
||||
func (c *Cli) Version(version string) {
|
||||
c.rootCommand.AppVersion = version
|
||||
}
|
||||
|
||||
// PrintHelp - Prints the application's help
|
||||
func (c *Cli) PrintHelp() {
|
||||
c.rootCommand.PrintHelp()
|
||||
}
|
||||
|
||||
// Run - Runs the application with the given arguments
|
||||
func (c *Cli) Run(args ...string) error {
|
||||
if c.preRunCommand != nil {
|
||||
err := c.preRunCommand(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(args) == 0 {
|
||||
args = os.Args[1:]
|
||||
}
|
||||
return c.rootCommand.Run(args)
|
||||
}
|
||||
|
||||
// DefaultCommand - Sets the given command as the command to run when
|
||||
// no other commands given
|
||||
func (c *Cli) DefaultCommand(defaultCommand *Command) *Cli {
|
||||
c.defaultCommand = defaultCommand
|
||||
return c
|
||||
}
|
||||
|
||||
// Command - Adds a command to the application
|
||||
func (c *Cli) Command(name, description string) *Command {
|
||||
return c.rootCommand.Command(name, description)
|
||||
}
|
||||
|
||||
// PreRun - Calls the given function before running the specific command
|
||||
func (c *Cli) PreRun(callback func(*Cli) error) {
|
||||
c.preRunCommand = callback
|
||||
}
|
||||
|
||||
// BoolFlag - Adds a boolean flag to the root command
|
||||
func (c *Cli) BoolFlag(name, description string, variable *bool) *Command {
|
||||
c.rootCommand.BoolFlag(name, description, variable)
|
||||
return c.rootCommand
|
||||
}
|
||||
|
||||
// StringFlag - Adds a string flag to the root command
|
||||
func (c *Cli) StringFlag(name, description string, variable *string) *Command {
|
||||
c.rootCommand.StringFlag(name, description, variable)
|
||||
return c.rootCommand
|
||||
}
|
||||
|
||||
// Action represents a function that gets calls when the command is called by
|
||||
// the user
|
||||
type Action func() error
|
||||
|
||||
// Command represents a command that may be run by the user
|
||||
type Command struct {
|
||||
Name string
|
||||
CommandPath string
|
||||
Shortdescription string
|
||||
Longdescription string
|
||||
AppVersion string
|
||||
SubCommands []*Command
|
||||
SubCommandsMap map[string]*Command
|
||||
longestSubcommand int
|
||||
ActionCallback Action
|
||||
App *Cli
|
||||
Flags *flag.FlagSet
|
||||
flagCount int
|
||||
log *Logger
|
||||
helpFlag bool
|
||||
hidden bool
|
||||
}
|
||||
|
||||
// NewCommand creates a new Command
|
||||
func NewCommand(name string, description string, app *Cli, parentCommandPath string) *Command {
|
||||
result := &Command{
|
||||
Name: name,
|
||||
Shortdescription: description,
|
||||
SubCommandsMap: make(map[string]*Command),
|
||||
App: app,
|
||||
log: NewLogger(),
|
||||
hidden: false,
|
||||
}
|
||||
|
||||
// Set up command path
|
||||
if parentCommandPath != "" {
|
||||
result.CommandPath += parentCommandPath + " "
|
||||
}
|
||||
result.CommandPath += name
|
||||
|
||||
// Set up flag set
|
||||
result.Flags = flag.NewFlagSet(result.CommandPath, flag.ContinueOnError)
|
||||
result.BoolFlag("help", "Get help on the '"+result.CommandPath+"' command.", &result.helpFlag)
|
||||
|
||||
// result.Flags.Usage = result.PrintHelp
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// parseFlags parses the given flags
|
||||
func (c *Command) parseFlags(args []string) error {
|
||||
// Parse flags
|
||||
tmp := os.Stderr
|
||||
os.Stderr = nil
|
||||
err := c.Flags.Parse(args)
|
||||
os.Stderr = tmp
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %s\n\n", err.Error())
|
||||
c.PrintHelp()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Run - Runs the Command with the given arguments
|
||||
func (c *Command) Run(args []string) error {
|
||||
|
||||
// If we have arguments, process them
|
||||
if len(args) > 0 {
|
||||
// Check for subcommand
|
||||
subcommand := c.SubCommandsMap[args[0]]
|
||||
if subcommand != nil {
|
||||
return subcommand.Run(args[1:])
|
||||
}
|
||||
|
||||
// Parse flags
|
||||
err := c.parseFlags(args)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %s\n\n", err.Error())
|
||||
c.PrintHelp()
|
||||
return err
|
||||
}
|
||||
|
||||
// Help takes precedence
|
||||
if c.helpFlag {
|
||||
c.PrintHelp()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have an action?
|
||||
if c.ActionCallback != nil {
|
||||
return c.ActionCallback()
|
||||
}
|
||||
|
||||
// If we haven't specified a subcommand
|
||||
// check for an app level default command
|
||||
if c.App.defaultCommand != nil {
|
||||
// Prevent recursion!
|
||||
if c.App.defaultCommand != c {
|
||||
// only run default command if no args passed
|
||||
if len(args) == 0 {
|
||||
return c.App.defaultCommand.Run(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing left we can do
|
||||
c.PrintHelp()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Action - Define an action from this command
|
||||
func (c *Command) Action(callback Action) *Command {
|
||||
c.ActionCallback = callback
|
||||
return c
|
||||
}
|
||||
|
||||
// PrintHelp - Output the help text for this command
|
||||
func (c *Command) PrintHelp() {
|
||||
c.log.PrintBanner()
|
||||
|
||||
commandTitle := c.CommandPath
|
||||
if c.Shortdescription != "" {
|
||||
commandTitle += " - " + c.Shortdescription
|
||||
}
|
||||
// Ignore root command
|
||||
if c.CommandPath != c.Name {
|
||||
c.log.Yellow(commandTitle)
|
||||
}
|
||||
if c.Longdescription != "" {
|
||||
fmt.Println()
|
||||
fmt.Println(c.Longdescription + "\n")
|
||||
}
|
||||
if len(c.SubCommands) > 0 {
|
||||
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() {
|
||||
isDefault = "[default]"
|
||||
}
|
||||
fmt.Printf(" %s%s%s %s\n", subcommand.Name, spacer, subcommand.Shortdescription, isDefault)
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
if c.flagCount > 0 {
|
||||
c.log.White("Flags:")
|
||||
fmt.Println()
|
||||
c.Flags.SetOutput(os.Stdout)
|
||||
c.Flags.PrintDefaults()
|
||||
c.Flags.SetOutput(os.Stderr)
|
||||
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// isDefaultCommand returns true if called on the default command
|
||||
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)
|
||||
result.log = c.log
|
||||
c.SubCommands = append(c.SubCommands, result)
|
||||
c.SubCommandsMap[name] = result
|
||||
if len(name) > c.longestSubcommand {
|
||||
c.longestSubcommand = len(name)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BoolFlag - Adds a boolean flag to the command
|
||||
func (c *Command) BoolFlag(name, description string, variable *bool) *Command {
|
||||
c.Flags.BoolVar(variable, name, *variable, description)
|
||||
c.flagCount++
|
||||
return c
|
||||
}
|
||||
|
||||
// StringFlag - Adds a string flag to the command
|
||||
func (c *Command) StringFlag(name, description string, variable *string) *Command {
|
||||
c.Flags.StringVar(variable, name, *variable, description)
|
||||
c.flagCount++
|
||||
return c
|
||||
}
|
||||
|
||||
// LongDescription - Sets the long description for the command
|
||||
func (c *Command) LongDescription(Longdescription string) *Command {
|
||||
c.Longdescription = Longdescription
|
||||
return c
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
// FSHelper - Wrapper struct for File System utility commands
|
||||
type FSHelper struct {
|
||||
}
|
||||
|
||||
// NewFSHelper - Returns a new FSHelper
|
||||
func NewFSHelper() *FSHelper {
|
||||
result := &FSHelper{}
|
||||
return result
|
||||
}
|
||||
|
||||
// DirExists - Returns true if the given path resolves to a directory on the filesystem
|
||||
func (fs *FSHelper) DirExists(path string) bool {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return fi.Mode().IsDir()
|
||||
}
|
||||
|
||||
// FileExists returns a boolean value indicating whether
|
||||
// the given file exists
|
||||
func (fs *FSHelper) FileExists(path string) bool {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return fi.Mode().IsRegular()
|
||||
}
|
||||
|
||||
// FindFile returns the first occurrence of match inside path.
|
||||
func (fs *FSHelper) FindFile(path, match string) (string, error) {
|
||||
files, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if !f.IsDir() && strings.Contains(f.Name(), match) {
|
||||
return f.Name(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("file not found")
|
||||
}
|
||||
|
||||
// CreateFile creates a file at the given filename location with the contents
|
||||
// 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 os.WriteFile(filename, data, 0644)
|
||||
}
|
||||
|
||||
// MkDirs creates the given nested directories.
|
||||
// Returns error on failure
|
||||
func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error {
|
||||
var perms os.FileMode
|
||||
perms = 0700
|
||||
if len(mode) == 1 {
|
||||
perms = mode[0]
|
||||
}
|
||||
return os.MkdirAll(fullPath, perms)
|
||||
}
|
||||
|
||||
// CopyFile from source to target
|
||||
func (fs *FSHelper) CopyFile(source, target string) error {
|
||||
s, err := os.Open(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
d, err := os.Create(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(d, s); err != nil {
|
||||
d.Close()
|
||||
return err
|
||||
}
|
||||
return d.Close()
|
||||
}
|
||||
|
||||
// Cwd returns the current working directory
|
||||
// Aborts on Failure
|
||||
func (fs *FSHelper) Cwd() string {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal("Unable to get working directory!")
|
||||
}
|
||||
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, continueOnError bool) error {
|
||||
for _, filename := range files {
|
||||
err := os.Remove(filename)
|
||||
if err != nil && !continueOnError {
|
||||
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 (d *Dir) GetSubdirs() (map[string]string, error) {
|
||||
|
||||
// Read in the directory information
|
||||
fileInfo, err := os.ReadDir(d.fullPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Allocate space for the list
|
||||
subdirs := make(map[string]string)
|
||||
|
||||
// Pull out the directories and store in the map as
|
||||
// map["directoryName"] = "path/to/directoryName"
|
||||
for _, file := range fileInfo {
|
||||
if file.IsDir() {
|
||||
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 := os.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 := 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 os.ReadFile(filename)
|
||||
}
|
||||
|
||||
// FileMD5 returns the md5sum of the given file
|
||||
func (fs *FSHelper) FileMD5(filename string) (string, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := md5.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"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 returns 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/releases")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
body, err := io.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
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user