From b9558cc3cb7fac5f3d795808369b56eef4bbc69f Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sat, 18 Nov 2023 13:08:59 +1100 Subject: [PATCH] Update default taskfile. WIP linux packaging --- v3/cmd/wails3/main.go | 1 + .../commands/build_assets/appimage/build.sh | 26 ++++++ v3/internal/commands/dot_desktop.go | 81 +++++++++++++++++++ .../templates/_common/Taskfile.tmpl.yml | 66 ++++++++++++++- 4 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 v3/internal/commands/build_assets/appimage/build.sh create mode 100644 v3/internal/commands/dot_desktop.go diff --git a/v3/cmd/wails3/main.go b/v3/cmd/wails3/main.go index 38dcbfce8..6472556b2 100644 --- a/v3/cmd/wails3/main.go +++ b/v3/cmd/wails3/main.go @@ -44,6 +44,7 @@ func main() { generate.NewSubCommandFunction("syso", "Generate Windows .syso file", commands.GenerateSyso) generate.NewSubCommandFunction("bindings", "Generate bindings + models", commands.GenerateBindings) generate.NewSubCommandFunction("constants", "Generate JS constants from Go", commands.GenerateConstants) + generate.NewSubCommandFunction(".desktop", "Generate .desktop file", commands.GenerateDotDesktop) plugin := app.NewSubCommand("plugin", "Plugin tools") //plugin.NewSubCommandFunction("list", "List plugins", commands.PluginList) plugin.NewSubCommandFunction("init", "Initialise a new plugin", commands.PluginInit) diff --git a/v3/internal/commands/build_assets/appimage/build.sh b/v3/internal/commands/build_assets/appimage/build.sh new file mode 100644 index 000000000..fcba535e5 --- /dev/null +++ b/v3/internal/commands/build_assets/appimage/build.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) 2018-Present Lea Anthony +# SPDX-License-Identifier: MIT + +# Fail script on any error +set -euxo pipefail + +# Define variables +APP_DIR="${APP_NAME}.AppDir" + +# Create AppDir structure +mkdir -p "${APP_DIR}/usr/bin" +cp -r "${APP_BINARY}" "${APP_DIR}/usr/bin/" +cp "${ICON_PATH}" "${APP_DIR}/" +cp "${DESKTOP_FILE}" "${APP_DIR}/" + +# Download linuxdeploy and make it executable +wget -q -4 -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage +chmod +x linuxdeploy-x86_64.AppImage + +# Run linuxdeploy to bundle the application +./linuxdeploy-x86_64.AppImage --appdir "${APP_DIR}" --output appimage + +# Rename the generated AppImage +mv "${APP_NAME}*.AppImage" "${APP_NAME}.AppImage" + diff --git a/v3/internal/commands/dot_desktop.go b/v3/internal/commands/dot_desktop.go new file mode 100644 index 000000000..0fd674d9b --- /dev/null +++ b/v3/internal/commands/dot_desktop.go @@ -0,0 +1,81 @@ +package commands + +import ( + "bytes" + "fmt" + "os" +) + +type DotDesktopOptions struct { + OutputFile string `description:"The output file to write to"` + Type string `description:"The type of the desktop entry" default:"Application"` + Name string `description:"The name of the application"` + Exec string `description:"The binary name + args to execute"` + Icon string `description:"The icon name or path for the application"` + Categories string `description:"Categories in which the application should be shown e.g. 'Development;IDE;'"` + Comment string `description:"A brief description of the application"` + Terminal bool `description:"Whether the application runs in a terminal" default:"false"` + Keywords string `description:"Keywords associated with the application e.g. 'Editor;Image;'" default:"wails"` + Version string `description:"The version of the Desktop Entry Specification" default:"1.0"` + GenericName string `description:"A generic name for the application"` + StartupNotify bool `description:"If true, the app will send a notification when starting" default:"false"` + MimeType string `description:"The MIME types the application can handle e.g. 'image/gif;image/jpeg;'"` + //Actions []string `description:"Additional actions offered by the application"` +} + +func (d *DotDesktopOptions) asBytes() []byte { + var buf bytes.Buffer + // Mandatory fields + buf.WriteString("[Desktop Entry]\n") + buf.WriteString(fmt.Sprintf("Type=%s\n", d.Type)) + buf.WriteString(fmt.Sprintf("Name=%s\n", d.Name)) + buf.WriteString(fmt.Sprintf("Exec=%s\n", d.Exec)) + + // Optional fields with checks + if d.Icon != "" { + buf.WriteString(fmt.Sprintf("Icon=%s\n", d.Icon)) + } + if d.Categories != "" { + buf.WriteString(fmt.Sprintf("Categories=%s\n", d.Categories)) + } + if d.Comment != "" { + buf.WriteString(fmt.Sprintf("Comment=%s\n", d.Comment)) + } + buf.WriteString(fmt.Sprintf("Terminal=%t\n", d.Terminal)) + if d.Keywords != "" { + buf.WriteString(fmt.Sprintf("Keywords=%s\n", d.Keywords)) + } + if d.Version != "" { + buf.WriteString(fmt.Sprintf("Version=%s\n", d.Version)) + } + if d.GenericName != "" { + buf.WriteString(fmt.Sprintf("GenericName=%s\n", d.GenericName)) + } + buf.WriteString(fmt.Sprintf("StartupNotify=%t\n", d.StartupNotify)) + if d.MimeType != "" { + buf.WriteString(fmt.Sprintf("MimeType=%s\n", d.MimeType)) + } + return buf.Bytes() +} + +func GenerateDotDesktop(options *DotDesktopOptions) error { + + if options.Name == "" { + return fmt.Errorf("name is required") + } + + options.Name = normaliseName(options.Name) + + if options.Exec == "" { + return fmt.Errorf("exec is required") + } + + if options.OutputFile == "" { + options.OutputFile = options.Name + ".desktop" + } + + // Write to file + err := os.WriteFile(options.OutputFile, options.asBytes(), 0755) + + return err +} diff --git a/v3/internal/templates/_common/Taskfile.tmpl.yml b/v3/internal/templates/_common/Taskfile.tmpl.yml index 881de2cd0..d91458f00 100644 --- a/v3/internal/templates/_common/Taskfile.tmpl.yml +++ b/v3/internal/templates/_common/Taskfile.tmpl.yml @@ -265,8 +265,6 @@ tasks: vars: ARCH: amd64 - ## -------------------------- Misc -------------------------- ## - create:app:bundle: summary: Creates an `.app` bundle cmds: @@ -274,7 +272,69 @@ tasks: - cp build/icons.icns {{ "{{.BIN_DIR}}" }}/{{ "{{.APP_NAME}}" }}.app/Contents/Resources - cp {{ "{{.BIN_DIR}}" }}/{{ "{{.APP_NAME}}" }} {{ "{{.BIN_DIR}}" }}/{{ "{{.APP_NAME}}" }}.app/Contents/MacOS - cp build/Info.plist {{ "{{.BIN_DIR}}" }}/{{ "{{.APP_NAME}}" }}.app/Contents - + + ## ------> Linux <------ + + package:linux: + summary: Packages a production build of the application for Linux + platforms: [ linux ] + deps: + - task: build:linux + vars: + PRODUCTION: "true" + cmds: + - task: create:appimage + + create:appimage: + summary: Creates an AppImage + platforms: [ linux ] + deps: + - task: build:linux + vars: + PRODUCTION: "true" + - task: generate:linux:dotdesktop + cmds: + - chmod +x {{ "{{.BIN_DIR}}" }}/{{ "{{.APP_NAME}}" }} + - chmod +x build/appimage/build.sh + - sh: build/appimage/build.sh + env: + - APP_NAME: {{ "'{{.APP_NAME}}'" }} + - APP_BINARY: '{{ "{{.ROOT_DIR}}"}}/{{ "{{.BIN_DIR}}" }}/{{ "{{.APP_NAME}}" }}' + - ICON_PATH: '{{ "{{.ROOT_DIR}}"}}/build/appicon.png' + - DESKTOP_FILE: '{{ "{{.ROOT_DIR}}"}}/build/{{ "{{.APP_NAME}}" }}.desktop' + + generate:linux:dotdesktop: + summary: Generates a `.desktop` file + dir: build + sources: + - "appicon.png" + generates: + - "{{ "{{.ROOT_DIR}}"}}/build/appimage/{{ "{{.APP_NAME}}" }}.desktop" + cmds: + # Run `wails3 generate .desktop -help` for all the options + - | + wails3 generate .desktop + -name "{{ "{{.APP_NAME}}" }}" + -exec "{{ "{{.EXEC}}" }}" + -icon "{{ "{{.ICON}}" }}" + -outputfile {{ "{{.ROOT_DIR}}"}}/build/appimage/{{ "{{.APP_NAME}}" }}.desktop + # -categories "Development;Graphics;" + # -comment "A comment" + # -terminal "true" + # -version "1.0" + # -genericname "Generic Name" + # -keywords "keyword1;keyword2;" + # -startupnotify "true" + # -mimetype "application/x-extension1;application/x-extension2;" + + vars: + APP_NAME: '-name \"{{ "{{.APP_NAME}}" }}\"' + EXEC: '{{ "{{.ROOT_DIR}}"}}/{{ "{{.BIN_DIR}}" }}/{{ "{{.APP_NAME}}" }}' + ICON: '{{ "{{.ROOT_DIR}}"}}/build/appicon.png' + OUTPUTFILE: '-outputfile {{ "{{.ROOT_DIR}}"}}/build/appimage/{{ "{{.APP_NAME}}" }}.desktop' + ## -------------------------- Misc -------------------------- ## + + generate:icons: summary: Generates Windows `.ico` and Mac `.icns` files from an image dir: build