mirror of
https://github.com/wownero/wowlet.git
synced 2026-10-28 19:58:35 +01:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4050d51760 | ||
|
|
8dacc3ba5a | ||
|
|
66c16d152d | ||
|
|
f4bbfd49ad | ||
|
|
142b79ee27 | ||
|
|
a43e9fe122 | ||
|
|
ce84b1d062 | ||
|
|
0e6113729d | ||
|
|
27d7b346c0 | ||
|
|
ea9c73826b | ||
|
|
5a9605c87b | ||
|
|
db151c2920 |
@@ -1,7 +1,7 @@
|
||||
name: linux appimage (gitea self-hosted)
|
||||
|
||||
# Runs ONLY on Gitea (GitHub ignores .gitea/workflows), in the private Builds
|
||||
# repository. Gitea is master; GitHub is a mirror and a release surface.
|
||||
# repository. GitHub wownero/wowlet owns source and release publication.
|
||||
#
|
||||
# Unlike the Windows lane, which builds a static toolchain of its own through
|
||||
# contrib/depends, the x86_64 AppImage links against the host's Qt6. Those
|
||||
@@ -42,30 +42,36 @@ jobs:
|
||||
|
||||
- name: fetch wownerod to embed
|
||||
run: |
|
||||
rm -rf /tmp/wownerod-embed && mkdir -p /tmp/wownerod-embed
|
||||
curl -fL -o /tmp/wownero.tar.bz2 \
|
||||
# ubuntu-latest and windows-latest both resolve to the same host in
|
||||
# host mode, so a fixed /tmp path lets a concurrently dispatched job's
|
||||
# `rm -rf` delete this job's binary between fetch and configure. Scope
|
||||
# every extract to the run.
|
||||
EMBED="/tmp/wowlet-${GITHUB_RUN_ID:-local}"
|
||||
rm -rf "$EMBED/wownerod-embed" && mkdir -p "$EMBED/wownerod-embed"
|
||||
curl -fL -o "$EMBED/wownero.tar.bz2" \
|
||||
https://github.com/wownero/wownero-codeberg-mirror/releases/download/v0.11.4.0/wownero-x86_64-linux-gnu-v0.11.4.0.tar.bz2
|
||||
rm -rf /tmp/wow-x && mkdir -p /tmp/wow-x
|
||||
tar xjf /tmp/wownero.tar.bz2 -C /tmp/wow-x
|
||||
find /tmp/wow-x -name wownerod -type f -exec cp {} /tmp/wownerod-embed/ \;
|
||||
chmod +x /tmp/wownerod-embed/wownerod
|
||||
ls -la /tmp/wownerod-embed
|
||||
rm -rf "$EMBED/wow-x" && mkdir -p "$EMBED/wow-x"
|
||||
tar xjf "$EMBED/wownero.tar.bz2" -C "$EMBED/wow-x"
|
||||
find "$EMBED/wow-x" -name wownerod -type f -exec cp {} "$EMBED/wownerod-embed/" \;
|
||||
chmod +x "$EMBED/wownerod-embed/wownerod"
|
||||
ls -la "$EMBED/wownerod-embed"
|
||||
|
||||
- name: fetch tor to embed
|
||||
run: |
|
||||
rm -rf /tmp/tor-embed && mkdir -p /tmp/tor-embed
|
||||
curl -fL -o /tmp/teb.tgz \
|
||||
EMBED="/tmp/wowlet-${GITHUB_RUN_ID:-local}"
|
||||
rm -rf "$EMBED/tor-embed" && mkdir -p "$EMBED/tor-embed"
|
||||
curl -fL -o "$EMBED/teb.tgz" \
|
||||
https://archive.torproject.org/tor-package-archive/torbrowser/15.0/tor-expert-bundle-linux-x86_64-15.0.tar.gz
|
||||
rm -rf /tmp/teb && mkdir -p /tmp/teb && tar xzf /tmp/teb.tgz -C /tmp/teb
|
||||
cp /tmp/teb/tor/tor /tmp/teb/tor/libssl.so.3 /tmp/teb/tor/libevent-2.1.so.7 \
|
||||
/tmp/teb/tor/libcrypto.so.3 /tmp/tor-embed/
|
||||
rm -rf "$EMBED/teb" && mkdir -p "$EMBED/teb" && tar xzf "$EMBED/teb.tgz" -C "$EMBED/teb"
|
||||
cp "$EMBED/teb/tor/tor" "$EMBED/teb/tor/libssl.so.3" "$EMBED/teb/tor/libevent-2.1.so.7" \
|
||||
"$EMBED/teb/tor/libcrypto.so.3" "$EMBED/tor-embed/"
|
||||
# The expert bundle's tor carries no rpath; point it and its libs at
|
||||
# $ORIGIN so the embedded copy resolves them from the extract dir on
|
||||
# any distro.
|
||||
for f in tor libssl.so.3 libevent-2.1.so.7 libcrypto.so.3; do
|
||||
patchelf --set-rpath '$ORIGIN' /tmp/tor-embed/$f
|
||||
patchelf --set-rpath '$ORIGIN' "$EMBED/tor-embed/$f"
|
||||
done
|
||||
chmod +x /tmp/tor-embed/tor
|
||||
chmod +x "$EMBED/tor-embed/tor"
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
@@ -73,15 +79,16 @@ jobs:
|
||||
# binary, or TorManager::unpackBins() sees embedded > unpacked and
|
||||
# rewrites Tor on every launch. The bundle's release number (15.0) is
|
||||
# not its tor version, so derive it.
|
||||
TORVER=$(/tmp/tor-embed/tor --version | grep -oE '[0-9]+(\.[0-9]+){3}' | head -1)
|
||||
EMBED="/tmp/wowlet-${GITHUB_RUN_ID:-local}"
|
||||
TORVER=$("$EMBED/tor-embed/tor" --version | grep -oE '[0-9]+(\.[0-9]+){3}' | head -1)
|
||||
echo "embedded tor version: $TORVER"
|
||||
# ARCH=x86-64, never native: the build host's CPU is newer than many
|
||||
# users' and native bakes in unsupported instructions -> SIGILL.
|
||||
cmake -S . -B build \
|
||||
-DWITH_SCANNER=OFF \
|
||||
-DARCH=x86-64 \
|
||||
-DWOWNEROD_DIR=/tmp/wownerod-embed \
|
||||
-DTOR_DIR=/tmp/tor-embed \
|
||||
-DWOWNEROD_DIR="$EMBED/wownerod-embed" \
|
||||
-DTOR_DIR="$EMBED/tor-embed" \
|
||||
-DTOR_VERSION="$TORVER"
|
||||
cmake --build build -j6
|
||||
ls -la build/bin/
|
||||
@@ -91,7 +98,7 @@ jobs:
|
||||
rm -rf AppDir
|
||||
mkdir -p AppDir/usr/bin AppDir/usr/share/applications \
|
||||
AppDir/usr/share/icons/hicolor/256x256/apps
|
||||
cp build/bin/feather AppDir/usr/bin/wowlet
|
||||
cp build/bin/wowlet AppDir/usr/bin/wowlet
|
||||
chmod +x AppDir/usr/bin/wowlet
|
||||
cp src/assets/wowlet.desktop AppDir/usr/share/applications/wowlet.desktop
|
||||
cp src/assets/images/appicons/256x256.png \
|
||||
@@ -147,3 +154,41 @@ jobs:
|
||||
name: wowlet-x86_64-linux-AppImage
|
||||
path: wowlet-x86_64.AppImage
|
||||
if-no-files-found: error
|
||||
|
||||
- name: publish the AppImage to the tag's release
|
||||
# The artifact above uploads fine but this Gitea's REST listing reports
|
||||
# zero artifacts for every run, so a tag build's output cannot be fetched
|
||||
# back through the API. Release assets can, so publish there as well.
|
||||
# Fail-safe by design: with no usable token this says why and exits 0,
|
||||
# it never turns a green build red.
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -eu
|
||||
FILE=wowlet-x86_64.AppImage
|
||||
TAG="${GITHUB_REF#refs/tags/}"
|
||||
API="${GITHUB_SERVER_URL:-https://git.such.software}/api/v1/repos/$GITHUB_REPOSITORY"
|
||||
if [ -z "${RELEASE_TOKEN:-}" ]; then
|
||||
echo "no token available to this runner, skipping the release upload" >&2
|
||||
exit 0
|
||||
fi
|
||||
H="Authorization: token $RELEASE_TOKEN"
|
||||
# Single-line python on purpose: a continuation line at column 0 would
|
||||
# end this block scalar and break the workflow's YAML. `|| true` keeps
|
||||
# a malformed response from aborting the step under `set -e`.
|
||||
rid=$(curl -sS -H "$H" "$API/releases/tags/$TAG" | python3 -c "import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||
if [ -z "$rid" ]; then
|
||||
rid=$(curl -sS -H "$H" -H "Content-Type: application/json" -X POST \
|
||||
-d "{\"tag_name\":\"$TAG\",\"name\":\"wowlet $TAG\"}" "$API/releases" | python3 -c "import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||
fi
|
||||
if [ -z "$rid" ]; then
|
||||
echo "could not resolve or create a release for $TAG, skipping the upload" >&2
|
||||
exit 0
|
||||
fi
|
||||
code=$(curl -sS -H "$H" -o /dev/null -w '%{http_code}' -X POST \
|
||||
-F "attachment=@$FILE" "$API/releases/$rid/assets?name=$(basename "$FILE")")
|
||||
echo "release asset upload returned HTTP $code"
|
||||
if [ "$code" != "201" ]; then
|
||||
echo "the release upload did not return 201; the run artifact still holds the build" >&2
|
||||
fi
|
||||
|
||||
@@ -103,8 +103,39 @@ jobs:
|
||||
# for the dormant `installed/` layout)
|
||||
mkdir -p dist/Wowlet.app/Contents/Resources
|
||||
cp ../src/assets/images/appicons/appicon.icns dist/Wowlet.app/Contents/Resources/
|
||||
# bundle Qt frameworks/plugins so the app runs off-machine
|
||||
/opt/homebrew/opt/qt/bin/macdeployqt dist/Wowlet.app
|
||||
# bundle Qt frameworks/plugins so the app runs off-machine.
|
||||
# -qmldir is not optional: our QML lives in .qrc resources, which
|
||||
# macdeployqt cannot scan, so without it the bundle ships no QML
|
||||
# modules at all and every page importing anything beyond QtQuick
|
||||
# fails to load. That is how 5.1.2 shipped a grey mining tab on mac
|
||||
# while Linux was fine: Contents/Resources held no qml directory, and
|
||||
# the app logged 'module "QtQuick.Layouts" is not installed'.
|
||||
/opt/homebrew/opt/qt/bin/macdeployqt dist/Wowlet.app -qmldir=../src/assets/qml
|
||||
|
||||
# qmlimportscanner reads only the `import` lines in our QML and does
|
||||
# not follow a module's own qmldir depends chain, so transitive
|
||||
# modules (QtQuick -> QtQml.WorkerScript/Models) are silently skipped.
|
||||
# The AppImage build hit this twice and blanket-copies the trees; do
|
||||
# the same here, before the dylib passes below so their deps resolve.
|
||||
# Ask Qt where its QML modules live rather than assuming a brew
|
||||
# layout; the AppImage build asks qmake the same question.
|
||||
QTPREFIX="$(brew --prefix qt)"
|
||||
QMLSRC="$("$QTPREFIX/bin/qmake6" -query QT_INSTALL_QML 2>/dev/null || echo "$QTPREFIX/share/qt/qml")"
|
||||
[ -d "$QMLSRC" ] || { echo "ERROR: Qt QML modules not found at $QMLSRC" >&2; exit 1; }
|
||||
mkdir -p dist/Wowlet.app/Contents/Resources/qml
|
||||
for m in QtQuick QtQml; do
|
||||
cp -Rn "$QMLSRC/$m" dist/Wowlet.app/Contents/Resources/qml/ 2>/dev/null || true
|
||||
done
|
||||
|
||||
# Guard: the module the mining tab needs has to be in the bundle. A
|
||||
# missing QML module is invisible until someone opens the tab, so it
|
||||
# fails the build instead of shipping a page that paints grey.
|
||||
for m in QtQuick QtQuick/Layouts; do
|
||||
[ -d "dist/Wowlet.app/Contents/Resources/qml/$m" ] || {
|
||||
echo "ERROR: $m missing from the bundle; QML pages will not load" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
# macdeployqt bundles Qt frameworks but not the plain-dylib brew deps
|
||||
# of Qt's image plugins (libwebp/libsharpyuv/libbrotli...), which are
|
||||
@@ -216,3 +247,47 @@ jobs:
|
||||
name: wowlet-macos
|
||||
path: build/wowlet-macos-*.zip
|
||||
retention-days: 14
|
||||
# Without this an empty upload passes silently, which is how a signed
|
||||
# build can appear to publish while shipping nothing.
|
||||
if-no-files-found: error
|
||||
|
||||
- name: publish the signed zip to the tag's release
|
||||
# Same reason as the Linux job: run artifacts upload but this Gitea's
|
||||
# REST listing returns zero for every run, so the notarized zip cannot
|
||||
# be fetched back through the API. Release assets can be. Fail-safe:
|
||||
# with no usable token this says why and exits 0.
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -eu
|
||||
FILE=$(ls build/wowlet-macos-*.zip 2>/dev/null | head -1)
|
||||
if [ -z "$FILE" ]; then
|
||||
echo "no macOS zip to publish; the packaging step should have failed first" >&2
|
||||
exit 0
|
||||
fi
|
||||
TAG="${GITHUB_REF#refs/tags/}"
|
||||
API="${GITHUB_SERVER_URL:-https://git.such.software}/api/v1/repos/$GITHUB_REPOSITORY"
|
||||
if [ -z "${RELEASE_TOKEN:-}" ]; then
|
||||
echo "no token available to this runner, skipping the release upload" >&2
|
||||
exit 0
|
||||
fi
|
||||
H="Authorization: token $RELEASE_TOKEN"
|
||||
# Single-line python on purpose: a continuation line at column 0 would
|
||||
# end this block scalar and break the workflow's YAML. `|| true` keeps
|
||||
# a malformed response from aborting the step under `set -e`.
|
||||
rid=$(curl -sS -H "$H" "$API/releases/tags/$TAG" | python3 -c "import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||
if [ -z "$rid" ]; then
|
||||
rid=$(curl -sS -H "$H" -H "Content-Type: application/json" -X POST \
|
||||
-d "{\"tag_name\":\"$TAG\",\"name\":\"wowlet $TAG\"}" "$API/releases" | python3 -c "import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
||||
fi
|
||||
if [ -z "$rid" ]; then
|
||||
echo "could not resolve or create a release for $TAG, skipping the upload" >&2
|
||||
exit 0
|
||||
fi
|
||||
code=$(curl -sS -H "$H" -o /dev/null -w '%{http_code}' -X POST \
|
||||
-F "attachment=@$FILE" "$API/releases/$rid/assets?name=$(basename "$FILE")")
|
||||
echo "release asset upload returned HTTP $code"
|
||||
if [ "$code" != "201" ]; then
|
||||
echo "the release upload did not return 201; the run artifact still holds the build" >&2
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: windows build + sign (gitea self-hosted)
|
||||
|
||||
# Runs ONLY on Gitea (GitHub ignores .gitea/workflows), in the private Builds
|
||||
# repository. Gitea is master; GitHub is a mirror and a release surface.
|
||||
# repository. GitHub wownero/wowlet owns source and release publication.
|
||||
#
|
||||
# Two jobs on two different machines, and that split is the whole point:
|
||||
#
|
||||
@@ -98,13 +98,17 @@ jobs:
|
||||
|
||||
- name: fetch wownerod.exe to embed
|
||||
run: |
|
||||
rm -rf /tmp/wownerod-embed && mkdir -p /tmp/wownerod-embed
|
||||
curl -fL -o /tmp/wownero-win.zip \
|
||||
# This job and the Linux one land on the same host in host mode, and a
|
||||
# fixed /tmp path let each wipe the other's binary mid-build. Scope the
|
||||
# extract to the run.
|
||||
EMBED="/tmp/wowlet-${GITHUB_RUN_ID:-local}"
|
||||
rm -rf "$EMBED/wownerod-embed" && mkdir -p "$EMBED/wownerod-embed"
|
||||
curl -fL -o "$EMBED/wownero-win.zip" \
|
||||
https://github.com/wownero/wownero-codeberg-mirror/releases/download/v0.11.4.0/wownero-x86_64-w64-mingw32-v0.11.4.0.zip
|
||||
# -j flattens the versioned subdir so wownerod.exe is a DIRECT child
|
||||
# (WownerodQrcGenerator globs ${WOWNEROD_DIR}/* non-recursively).
|
||||
unzip -o -j /tmp/wownero-win.zip 'wownero-x86_64-w64-mingw32-v0.11.4.0/wownerod.exe' -d /tmp/wownerod-embed
|
||||
ls -la /tmp/wownerod-embed
|
||||
unzip -o -j "$EMBED/wownero-win.zip" 'wownero-x86_64-w64-mingw32-v0.11.4.0/wownerod.exe' -d "$EMBED/wownerod-embed"
|
||||
ls -la "$EMBED/wownerod-embed"
|
||||
|
||||
- name: build wowlet.exe
|
||||
run: |
|
||||
@@ -118,7 +122,7 @@ jobs:
|
||||
-DCHECK_UPDATES=OFF \
|
||||
-DTOR_INSTALLED=On \
|
||||
-DFEATHER_TARGET_TRIPLET="$HOST" \
|
||||
-DWOWNEROD_DIR=/tmp/wownerod-embed \
|
||||
-DWOWNEROD_DIR="/tmp/wowlet-${GITHUB_RUN_ID:-local}/wownerod-embed" \
|
||||
..
|
||||
cmake --build . -j6
|
||||
ls -la bin/
|
||||
@@ -129,7 +133,7 @@ jobs:
|
||||
# archive contains the signed binary.
|
||||
run: |
|
||||
mkdir -p stage/tor
|
||||
cp build/bin/feather.exe stage/wowlet.exe
|
||||
cp build/bin/wowlet.exe stage/wowlet.exe
|
||||
cp "contrib/depends/$HOST/Tor/tor.exe" stage/tor/tor.exe
|
||||
(cp LICENSE stage/LICENSE.txt 2>/dev/null || cp COPYING stage/LICENSE.txt 2>/dev/null) || true
|
||||
ls -la stage stage/tor
|
||||
@@ -266,3 +270,47 @@ jobs:
|
||||
wowlet-x86_64-windows.zip
|
||||
wowlet-x86_64-windows-unsigned.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: publish the Windows zips to the tag's release
|
||||
# Same reason as the Linux and macOS jobs: artifacts upload fine, but
|
||||
# this Gitea's REST listing reports zero for every run, so the signed exe
|
||||
# cannot be fetched back through the API. Release assets can be.
|
||||
#
|
||||
# This runs after the Authenticode, timestamp and signer checks above, so
|
||||
# an unsigned or untimestamped binary never reaches a release. curl.exe,
|
||||
# not Invoke-WebRequest: `shell: powershell` is Windows PowerShell 5.1,
|
||||
# whose Invoke-WebRequest has no -Form for multipart uploads.
|
||||
#
|
||||
# Fail-safe: a build that produced a correctly signed binary must not go
|
||||
# red because publishing failed, so every bad path reports and exits 0.
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
shell: powershell
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
$ErrorActionPreference = 'Continue'
|
||||
if (-not $env:RELEASE_TOKEN) {
|
||||
Write-Host "no token available to this runner, skipping the release upload"
|
||||
exit 0
|
||||
}
|
||||
$tag = $env:GITHUB_REF -replace '^refs/tags/', ''
|
||||
$server = if ($env:GITHUB_SERVER_URL) { $env:GITHUB_SERVER_URL } else { 'https://git.such.software' }
|
||||
$api = "$server/api/v1/repos/$env:GITHUB_REPOSITORY"
|
||||
$auth = "Authorization: token $env:RELEASE_TOKEN"
|
||||
$rid = ''
|
||||
try { $rid = ((curl.exe -sS -H $auth "$api/releases/tags/$tag") | ConvertFrom-Json).id } catch { $rid = '' }
|
||||
if (-not $rid) {
|
||||
try {
|
||||
$body = "{""tag_name"":""$tag"",""name"":""wowlet $tag""}"
|
||||
$rid = ((curl.exe -sS -H $auth -H "Content-Type: application/json" -X POST -d $body "$api/releases") | ConvertFrom-Json).id
|
||||
} catch { $rid = '' }
|
||||
}
|
||||
if (-not $rid) {
|
||||
Write-Host "could not resolve or create a release for $tag, skipping the upload"
|
||||
exit 0
|
||||
}
|
||||
foreach ($f in @('wowlet-x86_64-windows.zip', 'wowlet-x86_64-windows-unsigned.zip')) {
|
||||
if (-not (Test-Path $f)) { Write-Host "missing $f, nothing to publish for it"; continue }
|
||||
$code = curl.exe -sS -o NUL -w '%{http_code}' -H $auth -F "attachment=@$f" "$api/releases/$rid/assets?name=$f"
|
||||
Write-Host "release asset upload for $f returned HTTP $code"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
name: ci/gh-actions/build
|
||||
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
# Legacy builds are manual only. Release artifacts are built in Builds/wowlet.
|
||||
on: [workflow_dispatch]
|
||||
|
||||
# NOTE (wownero-rebase branch): the Arch + macOS jobs from upstream Feather's build.yml are
|
||||
# temporarily disabled to get a fast, cheap iteration loop while bringing up the build against the
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
name: source checks
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
name: Wowlet documentation gate
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check generated documentation and support contacts
|
||||
run: make check
|
||||
@@ -1,6 +1,7 @@
|
||||
name: ci/gh-actions/guix
|
||||
|
||||
on: [push, pull_request]
|
||||
# Legacy builds are manual only. Release artifacts are built in Builds/wowlet.
|
||||
on: [workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
cache-sources:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
project(feather
|
||||
VERSION "5.1.2"
|
||||
VERSION "5.1.4"
|
||||
DESCRIPTION "A free Monero desktop wallet"
|
||||
LANGUAGES CXX C ASM
|
||||
)
|
||||
|
||||
@@ -13,4 +13,7 @@ clean:
|
||||
DEFAULT_GOAL := default
|
||||
default: build
|
||||
|
||||
.PHONY: default build attest verify clean
|
||||
check:
|
||||
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s contrib/docs/tests -v
|
||||
|
||||
.PHONY: default build attest verify clean check
|
||||
|
||||
@@ -1,60 +1,44 @@
|
||||
# Feather Wallet
|
||||
# Wowlet
|
||||
|
||||
Feather is a free Monero desktop wallet for Linux, Tails, macOS and Windows. It is written in C++ with the Qt framework.
|
||||
|
||||
- **easy-to-use**, **small** and **fast** - Feather runs well on any modern hardware, including virtual machines and live operating systems.
|
||||
- **beginner friendly**, but also caters to advanced Monero users by providing a [feature set](https://docs.featherwallet.org/guides/features) that is on par with the official CLI.
|
||||
- ships with **sane defaults** that suit most users, but can also be configured for high or uncommon threat models.
|
||||
- serves as a testing grounds for **experimental features** that may later be adopted in the reference wallets.
|
||||
Wowlet is a Wownero desktop wallet for Linux, macOS and Windows, built with C++ and
|
||||
Qt. It is based on [Feather Wallet](https://github.com/feather-wallet/feather).
|
||||
|
||||
## Download
|
||||
|
||||
You can download Feather from **[featherwallet.org](https://featherwallet.org/download/)** or **[GitHub](https://github.com/feather-wallet/feather/releases)**.
|
||||
Download Wowlet and its signed release hashes from
|
||||
[Wowlet releases](https://github.com/wownero/wowlet/releases).
|
||||
|
||||
If you need help installing Feather, check the [installation documentation](https://docs.featherwallet.org/).
|
||||
## Support
|
||||
|
||||
We recommend that you verify downloads with GPG. Releases are signed with our [release signing key](https://docs.featherwallet.org/guides/release-signing-key). The fingerprint is:
|
||||
- Matrix: [#wownero-gen:wowne.ro](https://matrix.to/#/#wownero-gen:wowne.ro)
|
||||
- IRC: `#wownero` on [OFTC](https://www.oftc.net/), or use
|
||||
[webchat](https://webchat.oftc.net/?randomnick=1&channels=wownero)
|
||||
- Email: [wownero@wownero.org](mailto:wownero@wownero.org)
|
||||
- Bug reports: [Wowlet issues](https://github.com/wownero/wowlet/issues)
|
||||
|
||||
```
|
||||
8185 E158 A333 30C7 FD61 BC0D 1F76 E155 CEFB A71C
|
||||
```
|
||||
If nobody replies immediately, stay in the room and give volunteers time to respond.
|
||||
Include your Wowlet version, operating system, reproduction steps and any error
|
||||
message. Never share your wallet seed, private keys, password or wallet files.
|
||||
|
||||
Windows releases are code-signed for free by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/).
|
||||
|
||||
## Resources
|
||||
|
||||
* [Official Site](https://featherwallet.org)
|
||||
* [Documentation](https://docs.featherwallet.org)
|
||||
* [Git Repository](https://github.com/feather-wallet/feather)
|
||||
* [Matrix](https://matrix.to/#/#feather:monero.social)
|
||||
* IRC: `#feather` on [OFTC](https://www.oftc.net/)
|
||||
* Mail: dev@featherwallet.org
|
||||
|
||||
If you need help with your wallet, please contact us via Matrix or IRC.
|
||||
If you don't have an IRC client, you can join the room via [webchat](https://webchat.oftc.net/?randomnick=1&channels=feather).
|
||||
If you don’t receive a response immediately please idle in the room.
|
||||
|
||||
## Release Builds
|
||||
|
||||
To learn how to run a bootstrappable release build, see: [contrib/guix/README.md](https://github.com/feather-wallet/feather/blob/master/contrib/guix/README.md)
|
||||
|
||||
For release attestations, see the [feather-sigs](http://github.com/feather-wallet/feather-sigs) repo.
|
||||
|
||||
For release policy, see: [RELEASE.md](https://github.com/feather-wallet/feather/blob/master/RELEASE.md)
|
||||
Report vulnerabilities privately using [SECURITY.md](SECURITY.md).
|
||||
|
||||
## Development
|
||||
|
||||
If you are looking to set up a development environment for Feather, see [HACKING.md](https://github.com/feather-wallet/feather/blob/master/HACKING.md).
|
||||
[GitHub](https://github.com/wownero/wowlet) is the canonical source repository.
|
||||
Release builds run in our private Builds system. Signed release artifacts and
|
||||
hashes are published on GitHub Releases. GitHub runs lightweight source checks;
|
||||
its legacy build workflows require an explicit manual dispatch.
|
||||
|
||||
It is highly recommended that you join our Matrix or IRC channel if you are hacking on Feather.
|
||||
Idling in this channel is the best way to stay updated on best practices and new developments.
|
||||
The application includes an offline documentation browser under Help. Its guides
|
||||
are generated by `contrib/docs/generate.py` from the Feather documentation submodule.
|
||||
Wowlet-specific guides in `contrib/docs/overrides` take precedence over upstream
|
||||
guides with the same filename. Edit those sources, then regenerate; files under
|
||||
`src/assets/docs` are generated and must not be edited directly.
|
||||
|
||||
For information on how Feather is maintained, see: [MAINTENANCE.md](https://github.com/feather-wallet/feather/blob/master/MAINTENANCE.md)
|
||||
|
||||
To report a security vulnerability, see: [SECURITY.md](https://github.com/feather-wallet/feather/blob/master/SECURITY.md)
|
||||
Run the documentation regression checks with `make check`. The inherited build
|
||||
instructions are in [HACKING.md](HACKING.md).
|
||||
|
||||
## License
|
||||
|
||||
Feather is free and open-source software, [licensed under BSD-3](https://raw.githubusercontent.com/feather-wallet/feather/master/LICENSE).
|
||||
|
||||
Copyright (c) 2020-2025, The Monero Project
|
||||
Wowlet is free and open-source software under [BSD-3-Clause](LICENSE).
|
||||
Upstream copyright notices are retained in the source.
|
||||
|
||||
+7
-39
@@ -2,43 +2,11 @@
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please do not open an issue to report security issues.
|
||||
Report Wowlet security vulnerabilities privately to
|
||||
[wownero@wownero.org](mailto:wownero@wownero.org).
|
||||
Please do not disclose them in public issues or community chat before the
|
||||
maintainers have had time to investigate.
|
||||
|
||||
To report a vulnerability email to dev@featherwallet.org
|
||||
|
||||
The following keys may be used to communicate sensitive information to developers:
|
||||
|
||||
| Name | Fingerprint |
|
||||
|---------|---------------------------------------------------|
|
||||
| tobtoht | E87B D921 CDD8 85C9 D78A 38C5 E45B 10DD 027D 2472 |
|
||||
|
||||
Public keys can be found in [`utils/pubkeys`](utils/pubkeys).
|
||||
|
||||
## Bug Bounty Program
|
||||
|
||||
A bounty may be rewarded to a vulnerability report **if and only if** the issue can result in **a loss of funds**.
|
||||
|
||||
You must describe a **plausible scenario** in which a loss of funds can occur (or has occurred) that **isn't solely attributable to user error**.
|
||||
|
||||
Only **the code** of the **latest tagged release** of **[this repository](https://github.com/feather-wallet/feather/)** is in scope.
|
||||
|
||||
**The bounty can only be rewarded in XMR**. The bounty amount for your report is determined by the maintainers and ranges from USD 150 to USD 3000 (in terms of XMR) and depends on the severity of the issue and other factors.
|
||||
|
||||
Clarifications on scope:
|
||||
|
||||
- The issue **must be present in a [signed](https://docs.featherwallet.org/guides/release-signing-key) [release build](https://github.com/feather-wallet/feather/blob/master/contrib/guix/README.md)**. Custom builds, including distribution packages, are out of scope.
|
||||
- The developers **must be able to reproduce and fix the issue**. If the issue cannot be fixed **in our code** for any reason, it is out of scope.
|
||||
- The live [websites](https://github.com/feather-wallet/feather-site/blob/master/mirrors.txt) and their repositories are out of scope.
|
||||
- Loss of funds due to malware on the user's machine is out of scope.
|
||||
- Memory imaging, including cold boot attacks, is out of scope.
|
||||
- Social engineering against users is out of scope. This includes messages received from the [websocket server](https://docs.featherwallet.org/guides/websocket).
|
||||
- Any form of coercion, physical or psychological, is out of scope.
|
||||
- Vulnerabilities that are attributable to hardware are out of scope.
|
||||
- If the issue was fixed in the `master` branch before we receive your report, it is invalid and not eligible for a bounty from this program.
|
||||
- If the vulnerability involves binary exploitation, we may ask you to provide a proof of concept of secret key exfiltration.
|
||||
- Vulnerabilities that are present in the monero submodule but were not introduced in patches made by the Feather developers must
|
||||
be reported [upstream](https://github.com/monero-project/meta/blob/master/VULNERABILITY_RESPONSE_PROCESS.md) and are not eligible for a bounty from this program.
|
||||
- Vulnerabilities that are present in any of our third-party dependencies must be reported upstream and are not eligible for a bounty from this program.
|
||||
- Vulnerabilities that are present in [supported hardware wallets](https://docs.featherwallet.org/guides/hardware-wallet-support) must be reported upstream and are not eligible for a bounty from this program.
|
||||
- A bounty will not be awarded if the reported vulnerability was already known. We may make an exception if you demonstrate that the severity of the issue was underestimated and no immediate fix was planned.
|
||||
- If, during your research, you disrupt Feather's release infrastructure or services, or attempt to coerce its developers, you will not be awarded a bounty.
|
||||
Include the affected Wowlet version, operating system, expected impact and steps
|
||||
to reproduce the issue. Use a disposable wallet for any reproduction and never
|
||||
send a real wallet seed, private keys, password or wallet files.
|
||||
|
||||
@@ -5,4 +5,4 @@ echo $HERE
|
||||
|
||||
# Tails 5.8 sets QT_QPA_PLATFORM to wayland which breaks our app
|
||||
export QT_QPA_PLATFORM=xcb
|
||||
${APPDIR}/usr/bin/feather $*
|
||||
${APPDIR}/usr/bin/wowlet $*
|
||||
|
||||
@@ -5,29 +5,29 @@ unset SOURCE_DATE_EPOCH
|
||||
|
||||
# Manually create the AppImage (reproducibly) since linuxdeployqt is not able to create cross-compiled AppImages
|
||||
|
||||
APPDIR="$PWD/feather.AppDir"
|
||||
APPDIR="$PWD/wowlet.AppDir"
|
||||
|
||||
mkdir -p "$APPDIR"
|
||||
mkdir -p "$APPDIR/usr/share/applications/"
|
||||
mkdir -p "$APPDIR/usr/bin"
|
||||
|
||||
cp "src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop"
|
||||
cp "src/assets/feather.desktop" "$APPDIR/feather.desktop"
|
||||
cp "src/assets/images/appicons/64x64.png" "$APPDIR/feather.png"
|
||||
cp "build/bin/feather" "$APPDIR/usr/bin/feather"
|
||||
chmod +x "$APPDIR/usr/bin/feather"
|
||||
cp "src/assets/wowlet.desktop" "$APPDIR/usr/share/applications/wowlet.desktop"
|
||||
cp "src/assets/wowlet.desktop" "$APPDIR/wowlet.desktop"
|
||||
cp "src/assets/images/appicons/64x64.png" "$APPDIR/wowlet.png"
|
||||
cp "build/bin/wowlet" "$APPDIR/usr/bin/wowlet"
|
||||
chmod +x "$APPDIR/usr/bin/wowlet"
|
||||
|
||||
cp "contrib/AppImage/AppRun" "$APPDIR/"
|
||||
chmod +x "$APPDIR/AppRun"
|
||||
|
||||
find feather.AppDir/ -exec touch -h -a -m -t 202101010100.00 {} \;
|
||||
find wowlet.AppDir/ -exec touch -h -a -m -t 202101010100.00 {} \;
|
||||
|
||||
mksquashfs feather.AppDir feather.squashfs -comp zstd -info -root-owned -no-xattrs -noappend -fstime 0
|
||||
mksquashfs wowlet.AppDir wowlet.squashfs -comp zstd -info -root-owned -no-xattrs -noappend -fstime 0
|
||||
# mksquashfs writes a timestamp to the header
|
||||
printf '\x00\x00\x00\x00' | dd conv=notrunc of=feather.squashfs bs=1 seek=$((0x8))
|
||||
printf '\x00\x00\x00\x00' | dd conv=notrunc of=wowlet.squashfs bs=1 seek=$((0x8))
|
||||
|
||||
rm -f feather.AppImage
|
||||
rm -f wowlet.AppImage
|
||||
|
||||
cat "${GITHUB_WORKSPACE:-/feather}/contrib/depends/${HOST}/runtime" >> feather.AppImage
|
||||
cat feather.squashfs >> feather.AppImage
|
||||
chmod a+x feather.AppImage
|
||||
cat "${GITHUB_WORKSPACE:-/feather}/contrib/depends/${HOST}/runtime" >> wowlet.AppImage
|
||||
cat wowlet.squashfs >> wowlet.AppImage
|
||||
chmod a+x wowlet.AppImage
|
||||
|
||||
@@ -43,6 +43,15 @@ SET(absl_ROOT @prefix@)
|
||||
SET(NATIVE_BIN_PATH @prefix@/native/bin CACHE FILEPATH "path to native binaries" FORCE)
|
||||
SET(LRELEASE_PATH @prefix@/native/bin CACHE FILEPATH "path to lrelease" FORCE)
|
||||
|
||||
# A cross Qt that carries qtdeclarative makes find_package(Qt6) demand a HOST Qt,
|
||||
# because QML needs host-side tools (qmlcachegen, qmlimportscanner,
|
||||
# qmltyperegistrar). depends already builds one: native_qt installs to
|
||||
# native/qt-host and qt.mk hands that path to the cross Qt's own configure. Our
|
||||
# build never heard about it, so Qt6Config refused with "please set the
|
||||
# QT_HOST_PATH cache variable" and the Windows cross build has failed since
|
||||
# qtdeclarative landed. Same path, stated once more for the consuming project.
|
||||
SET(QT_HOST_PATH @prefix@/native/qt-host CACHE PATH "host Qt for cross QML tooling")
|
||||
|
||||
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
SET(LIBUNWIND_INCLUDE_DIR @prefix@/include)
|
||||
SET(LIBUNWIND_LIBRARIES @prefix@/lib/libunwind.a)
|
||||
|
||||
@@ -2,6 +2,7 @@ import os
|
||||
import glob
|
||||
|
||||
DOCS_DIR = "external/feather-docs/content/_guides"
|
||||
OVERRIDES_DIR = "contrib/docs/overrides"
|
||||
OUT_DIR = "src/assets/docs"
|
||||
|
||||
CATEGORY_MAP = {
|
||||
@@ -21,9 +22,12 @@ outfiles = glob.glob(f"{OUT_DIR}/*.md")
|
||||
for file in outfiles:
|
||||
os.remove(file)
|
||||
|
||||
files = glob.glob(f"{DOCS_DIR}/*.md")
|
||||
# Wowlet owns its support contacts. Local sources take precedence so regenerating
|
||||
# the bundled docs cannot restore Feather's contact details.
|
||||
files = {os.path.basename(path): path for path in glob.glob(f"{DOCS_DIR}/*.md")}
|
||||
files.update({os.path.basename(path): path for path in glob.glob(f"{OVERRIDES_DIR}/*.md")})
|
||||
|
||||
for file in files:
|
||||
for file in sorted(files.values()):
|
||||
with open(file) as f:
|
||||
doc = f.read()
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: "How to report an issue"
|
||||
nav_title: "Report an issue"
|
||||
category: "help"
|
||||
---
|
||||
|
||||
For help with Wowlet, contact the Wownero community:
|
||||
|
||||
- Matrix: [#wownero-gen:wowne.ro](https://matrix.to/#/#wownero-gen:wowne.ro)
|
||||
- IRC: `#wownero` on [OFTC](https://www.oftc.net/)
|
||||
- Email: [wownero@wownero.org](mailto:wownero@wownero.org)
|
||||
- Bug reports: [Wowlet issues](https://github.com/wownero/wowlet/issues)
|
||||
|
||||
For live support, use Matrix or IRC. If you do not have an IRC client, join
|
||||
[#wownero in your browser](https://webchat.oftc.net/?randomnick=1&channels=wownero).
|
||||
If nobody replies immediately, stay in the room and give volunteers time to respond.
|
||||
|
||||
Please include your Wowlet version, operating system, the steps that caused the
|
||||
problem, and any error message. Review **Help → Debug Info** before sharing it and
|
||||
remove any personal information. Never share your wallet seed, private keys or
|
||||
password, and do not upload your wallet files.
|
||||
|
||||
Report security vulnerabilities privately to
|
||||
[wownero@wownero.org](mailto:wownero@wownero.org), rather than in a public issue or
|
||||
chat. See the [Wowlet security policy](https://github.com/wownero/wowlet/blob/master/SECURITY.md).
|
||||
|
||||
Downloads and signed release hashes are available from
|
||||
[Wowlet releases](https://github.com/wownero/wowlet/releases), also linked from
|
||||
[wownero.org](https://wownero.org/).
|
||||
@@ -0,0 +1,85 @@
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from urllib.parse import parse_qs, urlsplit
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[3]
|
||||
|
||||
|
||||
class GenerateDocsTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.directory = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.directory.cleanup)
|
||||
self.root = Path(self.directory.name)
|
||||
self.upstream = self.root / "external/feather-docs/content/_guides"
|
||||
self.upstream.mkdir(parents=True)
|
||||
self.output = self.root / "src/assets/docs"
|
||||
self.output.mkdir(parents=True)
|
||||
shutil.copytree(ROOT / "contrib/docs/overrides", self.root / "contrib/docs/overrides")
|
||||
|
||||
def write_upstream(self, name, body):
|
||||
(self.upstream / name).write_text(
|
||||
'---\ntitle: "Upstream guide"\nnav_title: "Upstream"\ncategory: "help"\n---\n'
|
||||
+ body
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-B", str(ROOT / "contrib/docs/generate.py")],
|
||||
cwd=self.root, capture_output=True, text=True,
|
||||
)
|
||||
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
|
||||
|
||||
def assert_wownero_contacts(self, document):
|
||||
urls = [urlsplit(url) for url in re.findall(r"\]\(([^)]+)\)", document)]
|
||||
self.assertTrue(any(
|
||||
url.hostname == "matrix.to" and url.fragment == "/#wownero-gen:wowne.ro"
|
||||
for url in urls
|
||||
), "Matrix must lead to Wownero's published room")
|
||||
self.assertTrue(any(
|
||||
url.hostname == "webchat.oftc.net"
|
||||
and "wownero" in parse_qs(url.query).get("channels", [])
|
||||
for url in urls
|
||||
), "Webchat must join Wownero's IRC channel")
|
||||
self.assertTrue(any(
|
||||
url.hostname == "github.com" and url.path == "/wownero/wowlet/issues"
|
||||
for url in urls
|
||||
), "Bug reports must go to the Wowlet tracker")
|
||||
self.assertTrue(any(
|
||||
url.scheme == "mailto" and url.path == "wownero@wownero.org"
|
||||
for url in urls
|
||||
), "Email must reach the published Wownero contact")
|
||||
for url in urls:
|
||||
self.assertNotIn("feather", url.geturl().lower(), "Support must not route to Feather")
|
||||
|
||||
def test_support_override_survives_regeneration(self):
|
||||
self.write_upstream("report_an_issue.md", "Upstream support contacts")
|
||||
self.write_upstream("accounts.md", "An upstream guide without an override")
|
||||
(self.output / "stale.md").write_text("Obsolete generated guide")
|
||||
for body in ("Upstream support contacts", "Changed upstream support contacts"):
|
||||
self.write_upstream("report_an_issue.md", body)
|
||||
self.generate()
|
||||
support = (self.output / "report_an_issue.md").read_text()
|
||||
self.assert_wownero_contacts(support)
|
||||
self.assertNotIn(body, support)
|
||||
self.assertRegex(support, r"(?m)^\[nav_title\]: # \(.+\)$")
|
||||
self.assertRegex(support, r"(?m)^\[category\]: # \(.+\)$")
|
||||
self.assertIn("An upstream guide without an override", (self.output / "accounts.md").read_text())
|
||||
self.assertFalse((self.output / "stale.md").exists())
|
||||
|
||||
def test_readme_and_security_contacts_agree_with_bundled_help(self):
|
||||
readme = (ROOT / "README.md").read_text()
|
||||
support = readme.split("## Support\n", 1)[1].split("\n## ", 1)[0]
|
||||
self.assert_wownero_contacts(support)
|
||||
policy = (ROOT / "SECURITY.md").read_text()
|
||||
self.assertIn("mailto:wownero@wownero.org", policy)
|
||||
self.assertNotIn("featherwallet.org", policy)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -34,13 +34,13 @@
|
||||
<string>????</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>feather</string>
|
||||
<string>wowlet</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>Feather</string>
|
||||
<string>Wowlet</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.monero-project.feather</string>
|
||||
<string>org.wownero.wowlet</string>
|
||||
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Camera is used to scan QR codes on demand.</string>
|
||||
|
||||
+13
-9
@@ -148,7 +148,10 @@ add_executable(feather ${EXECUTABLE_FLAG} main.cpp
|
||||
${ASSETS_TOR}
|
||||
)
|
||||
|
||||
# The CMake target keeps its upstream name so the target_* calls below stay put;
|
||||
# only what we ship is renamed.
|
||||
set_target_properties(feather PROPERTIES
|
||||
OUTPUT_NAME wowlet
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
LINK_FLAGS_RELEASE -s
|
||||
)
|
||||
@@ -370,14 +373,14 @@ else()
|
||||
)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/feather.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/32x32.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps RENAME "feather.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/48x48.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps RENAME "feather.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/64x64.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/64x64/apps RENAME "feather.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/96x96.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/96x96/apps RENAME "feather.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/128x128.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/128x128/apps RENAME "feather.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/256x256.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps RENAME "feather.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/512x512.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/512x512/apps RENAME "feather.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/wowlet.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/32x32.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps RENAME "wowlet.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/48x48.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps RENAME "wowlet.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/64x64.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/64x64/apps RENAME "wowlet.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/96x96.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/96x96/apps RENAME "wowlet.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/128x128.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/128x128/apps RENAME "wowlet.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/256x256.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps RENAME "wowlet.png")
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/512x512.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/512x512/apps RENAME "wowlet.png")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -385,13 +388,14 @@ if(APPLE)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/contrib/macdeploy/Info.plist.in ${CMAKE_SOURCE_DIR}/contrib/macdeploy/Info.plist @ONLY)
|
||||
|
||||
set_target_properties(feather PROPERTIES
|
||||
OUTPUT_NAME wowlet
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/contrib/macdeploy/Info.plist"
|
||||
LINK_FLAGS_RELEASE -s
|
||||
)
|
||||
|
||||
file(COPY "${CMAKE_SOURCE_DIR}/src/assets/images/appicons/appicon.icns" DESTINATION "${CMAKE_SOURCE_DIR}/installed/feather.app/Contents/Resources/" )
|
||||
file(COPY "${CMAKE_SOURCE_DIR}/src/assets/images/appicons/appicon.icns" DESTINATION "${CMAKE_SOURCE_DIR}/installed/wowlet.app/Contents/Resources/" )
|
||||
endif()
|
||||
|
||||
qt_finalize_executable(feather)
|
||||
|
||||
Reference in New Issue
Block a user