Compare commits

...

11 Commits

Author SHA1 Message Date
B.D. Murphy
f2cf2c4396 fix: rename all novelwriter icons/assets to umbraedit
Some checks are pending
Syntax / Linting and Type Checking (push) Waiting to run
Tests / Linux Python 3.11 (push) Waiting to run
Tests / Linux Python 3.12 (push) Waiting to run
Tests / Linux Python 3.13 (push) Waiting to run
Tests / Linux Python 3.14 (push) Waiting to run
Tests / Linux Python 3.15 (push) Waiting to run
Tests / MacOS Python 3.14 (push) Waiting to run
Tests / Windows Python 3.14 (push) Waiting to run
Tests / PR Coverage Report (push) Blocked by required conditions
Tests / Action Coverage Report (push) Blocked by required conditions
Tests / Ubuntu 24.04 & Sys Packages (push) Waiting to run
Tests / Fedora 44 & Sys Packages (push) Waiting to run
- Rename novelwriter.iconset to umbraedit.iconset with all icon sizes
- Rename setup/icons/novelwriter.* to umbraedit.*
- Rename setup/data/hicolor/ novelwriter icons to umbraedit
- Rename setup/data/novelwriter.* to umbraedit.*
- Rename docs/source/_static/novelwriter-* to umbraedit-*
- Rename setup/flatpak/io.novelwriter.novelwriter.yml to io.umbraedit.umbraedit.yml
- Rename setup/data/novelwriter.desktop to umbraedit.desktop
- Update setup/macos/build.sh to reference umbraedit.iconset
- Rebuild macOS DMG with correct UmbraEdit icon
2026-11-07 04:07:09 -08:00
B.D. Murphy
79a9ab995d fix: rename novelwriter.iconset to umbraedit.iconset, rebuild macOS DMG with correct icon
Some checks failed
Syntax / Linting and Type Checking (push) Has been cancelled
Tests / Linux Python 3.11 (push) Has been cancelled
Tests / Linux Python 3.12 (push) Has been cancelled
Tests / Linux Python 3.13 (push) Has been cancelled
Tests / Linux Python 3.14 (push) Has been cancelled
Tests / Linux Python 3.15 (push) Has been cancelled
Tests / MacOS Python 3.14 (push) Has been cancelled
Tests / Windows Python 3.14 (push) Has been cancelled
Tests / PR Coverage Report (push) Has been cancelled
Tests / Action Coverage Report (push) Has been cancelled
Tests / Ubuntu 24.04 & Sys Packages (push) Has been cancelled
Tests / Fedora 44 & Sys Packages (push) Has been cancelled
2026-11-07 03:58:14 -08:00
B.D. Murphy
f6aabb7c5d fix: handle apt-get update failure gracefully
Some checks failed
Syntax / Linting and Type Checking (push) Has been cancelled
Tests / Linux Python 3.11 (push) Has been cancelled
Tests / Linux Python 3.12 (push) Has been cancelled
Tests / Linux Python 3.13 (push) Has been cancelled
Tests / Linux Python 3.14 (push) Has been cancelled
Tests / Linux Python 3.15 (push) Has been cancelled
Tests / MacOS Python 3.14 (push) Has been cancelled
Tests / Windows Python 3.14 (push) Has been cancelled
Tests / PR Coverage Report (push) Has been cancelled
Tests / Action Coverage Report (push) Has been cancelled
Tests / Ubuntu 24.04 & Sys Packages (push) Has been cancelled
Tests / Fedora 44 & Sys Packages (push) Has been cancelled
- If apt-get update fails, show clear error message telling user
  to fix their package repositories first
- Exit with error instead of silently continuing with broken deps
- Only fail on critical apt-get update failure, not individual
  package install failures (those are warnings)
2026-11-06 17:57:57 -08:00
B.D. Murphy
b2782daece fix: make build-linux.sh resilient to apt-get update failures
Some checks failed
Syntax / Linting and Type Checking (push) Has been cancelled
Tests / Linux Python 3.11 (push) Has been cancelled
Tests / Linux Python 3.12 (push) Has been cancelled
Tests / Linux Python 3.13 (push) Has been cancelled
Tests / Linux Python 3.14 (push) Has been cancelled
Tests / Linux Python 3.15 (push) Has been cancelled
Tests / MacOS Python 3.14 (push) Has been cancelled
Tests / Windows Python 3.14 (push) Has been cancelled
Tests / PR Coverage Report (push) Has been cancelled
Tests / Action Coverage Report (push) Has been cancelled
Tests / Ubuntu 24.04 & Sys Packages (push) Has been cancelled
Tests / Fedora 44 & Sys Packages (push) Has been cancelled
2026-11-06 17:07:08 -08:00
B.D. Murphy
e7fdf05b00 feat: add build-linux.sh for Linux AMD64 packaging
Some checks failed
Syntax / Linting and Type Checking (push) Has been cancelled
Tests / Linux Python 3.11 (push) Has been cancelled
Tests / Linux Python 3.12 (push) Has been cancelled
Tests / Linux Python 3.13 (push) Has been cancelled
Tests / Linux Python 3.14 (push) Has been cancelled
Tests / Linux Python 3.15 (push) Has been cancelled
Tests / MacOS Python 3.14 (push) Has been cancelled
Tests / Windows Python 3.14 (push) Has been cancelled
Tests / PR Coverage Report (push) Has been cancelled
Tests / Action Coverage Report (push) Has been cancelled
Tests / Ubuntu 24.04 & Sys Packages (push) Has been cancelled
Tests / Fedora 44 & Sys Packages (push) Has been cancelled
- Add build-linux.sh script for end-to-end Linux builds
- Add build-linux.sh to MANIFEST.in for source distribution inclusion
- Fix all build scripts to handle sys.path when run directly
2026-11-06 16:23:26 -08:00
B.D. Murphy
02c532234c fix: add sys.path fix to build scripts for direct execution
Some checks failed
Syntax / Linting and Type Checking (push) Has been cancelled
Tests / Linux Python 3.11 (push) Has been cancelled
Tests / Linux Python 3.12 (push) Has been cancelled
Tests / Linux Python 3.13 (push) Has been cancelled
Tests / Linux Python 3.14 (push) Has been cancelled
Tests / Linux Python 3.15 (push) Has been cancelled
Tests / MacOS Python 3.14 (push) Has been cancelled
Tests / Windows Python 3.14 (push) Has been cancelled
Tests / PR Coverage Report (push) Has been cancelled
Tests / Action Coverage Report (push) Has been cancelled
Tests / Ubuntu 24.04 & Sys Packages (push) Has been cancelled
Tests / Fedora 44 & Sys Packages (push) Has been cancelled
2026-11-06 12:25:43 -08:00
B.D. Murphy
6eb6241044 fix: fix macOS build - icon path, version parsing, i18n imports
Some checks failed
Syntax / Linting and Type Checking (push) Has been cancelled
Tests / Linux Python 3.11 (push) Has been cancelled
Tests / Linux Python 3.12 (push) Has been cancelled
Tests / Linux Python 3.13 (push) Has been cancelled
Tests / Linux Python 3.14 (push) Has been cancelled
Tests / Linux Python 3.15 (push) Has been cancelled
Tests / MacOS Python 3.14 (push) Has been cancelled
Tests / Windows Python 3.14 (push) Has been cancelled
Tests / PR Coverage Report (push) Has been cancelled
Tests / Action Coverage Report (push) Has been cancelled
Tests / Ubuntu 24.04 & Sys Packages (push) Has been cancelled
Tests / Fedora 44 & Sys Packages (push) Has been cancelled
- Fix setup/macos/build.sh: icon path uses ./novelwriter.iconset relative path
- Fix umbraedit/__init__.py: __version__ now clean without inline comments
- Fix utils/assets.py: datetime.UTC -> datetime.timezone as UTC for py3.9 compat
- Fix utils/common.py: tomllib fallback to tomli for py3.9 compat
- Fix utils/docs.py: tomllib fallback to tomli for py3.9 compat
2026-11-06 08:39:54 -08:00
B.D. Murphy
af205b4877 resolve: fix README.md merge conflict
Some checks failed
Syntax / Linting and Type Checking (push) Has been cancelled
Tests / Linux Python 3.11 (push) Has been cancelled
Tests / Linux Python 3.12 (push) Has been cancelled
Tests / Linux Python 3.13 (push) Has been cancelled
Tests / Linux Python 3.14 (push) Has been cancelled
Tests / Linux Python 3.15 (push) Has been cancelled
Tests / MacOS Python 3.14 (push) Has been cancelled
Tests / Windows Python 3.14 (push) Has been cancelled
Tests / PR Coverage Report (push) Has been cancelled
Tests / Action Coverage Report (push) Has been cancelled
Tests / Ubuntu 24.04 & Sys Packages (push) Has been cancelled
Tests / Fedora 44 & Sys Packages (push) Has been cancelled
2026-11-06 08:29:14 -08:00
B.D. Murphy
a04eaaa779 house: add multi-platform build infrastructure
- Add MANIFEST.in to include utils/ and setup/ in source distributions
- Add utils/build_all.py - unified multi-platform build orchestrator
  (Linux amd64/arm64, macOS amd64/arm64, Windows amd64/arm64)
- Add BUILD_LINUX.md - Linux build guide with .deb and AppImage options
- Add RELEASE.md - complete release process with versioning (YYYY/MM.####),
  platform support matrix, and release workflow
- Fix .gitignore to exclude UmbraEdit_Projects/, Inner_Demon_1.2a.docm,
  UmbraEdit_deb_Build_Script.txt, requirements.txt, .DS_Store
- All source distributions now include build scripts for Linux packages
2026-11-06 08:03:35 -08:00
B.D. Murphy
d09e04e483 house: add Linux AMD64 build guide
- Add BUILD_LINUX.md with instructions for building .deb and AppImage
  packages on Linux AMD64 from the source distribution
- Document prerequisites, build steps, and usage for each package type
- Include source distribution (sdist) and pure Python wheel in dist/
2026-11-06 07:46:57 -08:00
f78f76a679 Update README.md
Some checks failed
Syntax / Linting and Type Checking (push) Has been cancelled
Tests / Linux Python 3.11 (push) Has been cancelled
Tests / Linux Python 3.12 (push) Has been cancelled
Tests / Linux Python 3.13 (push) Has been cancelled
Tests / Linux Python 3.14 (push) Has been cancelled
Tests / Linux Python 3.15 (push) Has been cancelled
Tests / MacOS Python 3.14 (push) Has been cancelled
Tests / Windows Python 3.14 (push) Has been cancelled
Tests / PR Coverage Report (push) Has been cancelled
Tests / Action Coverage Report (push) Has been cancelled
Tests / Ubuntu 24.04 & Sys Packages (push) Has been cancelled
Tests / Fedora 44 & Sys Packages (push) Has been cancelled
Aligning to umbratools, more changes will be made.
2026-11-06 14:41:26 +00:00
65 changed files with 1092 additions and 53 deletions

5
.gitignore vendored
View File

@@ -80,3 +80,8 @@ GEMINI.md
# Added by B.D. Murphy 2026: exclude files accidentally committed during branding transition
Splh.jpeg
Oldwelcome.webp
.DS_Store
UmbraEdit_Projects/
Inner_Demon_1.2a.docm
requirements.txt
UmbraEdit_deb_Build_Script.txt

146
BUILD_LINUX.md Normal file
View File

@@ -0,0 +1,146 @@
# UmbraEdit - Linux AMD64 Build Guide
UmbraEdit is developed on macOS but builds natively on Linux AMD64 and ARM64.
This guide covers building Linux install packages from source.
## Source Distribution
The source tarball (`umbraedit-2026.11.1.tar.gz`) includes everything needed to
build Linux packages:
```
umbraedit-2026.11.1/
├── pyproject.toml # Project metadata & dependencies
├── UmbraEdit.py # Application entry point
├── pkgutils.py # Packaging utility
├── run_tests.py # Test runner
├── setup/ # Packaging assets
│ ├── data/ # .desktop file, MIME type XML
│ ├── macos/ # macOS-specific packaging
│ └── windows/ # Windows-specific packaging
├── utils/ # Build scripts
│ ├── build_debian.py # .deb package builder
│ ├── build_appimage.py # AppImage builder
│ ├── build_all.py # Multi-platform build orchestrator
│ └── ...
├── umbraedit/ # Application source code
└── tests/ # Test suite
```
## Prerequisites on Linux
### Debian/Ubuntu
```bash
sudo apt-get update
sudo apt-get install \
python3 python3-pip \
python3-pyqt6 python3-pyqt6.qtsvg \
python3-enchant \
qt6-image-formats-plugins qt6-svg-plugins \
dh-python debhelper python3-build python3-setuptools \
python3-pytest python3-pytestqt python3-pytest-timeout \
appimagetool
```
### Fedora/RHEL
```bash
sudo dnf install \
python3 python3-pip \
python3-pyqt6 python3-enchant \
qt6-qtimageformats qt6-qtsvg \
python3-build python3-setuptools \
dpkg rpm-build appimagetool
```
### Arch Linux
```bash
sudo pacman -S \
python python-pip \
python-pyqt6 python-enchant \
qt6-imageformats qt6-svg \
python-build python-setuptools \
dpkg appimagetool
```
## Build Options
### Option 1: Install via Wheel (Simplest)
The pure Python wheel requires no compilation:
```bash
pip install umbraedit-2026.11.1-py3-none-any.whl
umbraedit
```
### Option 2: Install from Source Tarball
```bash
tar xzf umbraedit-2026.11.1.tar.gz
cd umbraedit-2026.11.1
pip install .
umbraedit
```
### Option 3: Build .deb Package
```bash
tar xzf umbraedit-2026.11.1.tar.gz
cd umbraedit-2026.11.1
# Build for Ubuntu Noble (24.04)
python3 utils/build_debian.py --distro noble --build 1
# The .deb will be in dist_deb/
sudo dpkg -i dist_deb/umbraedit_*_amd64.deb
```
Available distro targets: `bookworm`, `trixie`, `noble`, `resolute`, `stonking`, `wilma`
### Option 4: Build AppImage
```bash
pip install python-appimage
sudo apt-get install appimagetool
tar xzf umbraedit-2026.11.1.tar.gz
cd umbraedit-2026.11.1
python3 utils/build_appimage.py --linux ubuntu --arch amd64 --python 3.12
chmod +x dist_appimage/umbraedit-2026.11-amd64.AppImage
./dist_appimage/umbraedit-2026.11-amd64.AppImage
```
### Option 5: Build All Linux Packages
```bash
tar xzf umbraedit-2026.11.1.tar.gz
cd umbraedit-2026.11.1
python3 utils/build_all.py --platform linux --arch amd64
```
## Project Storage
UmbraEdit projects are stored in plain folders with an `nwProject.nwx` file.
The sample project included in the distribution can be used for testing:
```bash
umbraedit # Opens the welcome dialog
# Select "Sample Project" from the list, or browse to your .nwx file
```
## Version
Current development version: **2026.11.0004**
## License
GPL-3.0-or-later AND Apache-2.0 AND ISC AND MIT
UmbraEdit is based on novelWrite 2026.02 by Veronica Berglyd Olsen
(novelWriter.io), licenced under the same GPL v3.0 license.

0
CODE_OF_CONDUCT.md Normal file
View File

View File

@@ -1,9 +1,13 @@
# Credits
## Main Developer
## Main Developer novelWriter
* Veronica Berglyd Olsen
## Main Product Manager / Developer
* B.D. Murphy
## Contributors
Larger contributions were made by:
@@ -18,7 +22,8 @@ For other contributions, see the project's [Contributors](https://github.com/sag
## Artwork
The artwork on the Welcome dialog was created by Louis Durrant.
The artwork on the Welcome dialog was generated with AI by B.D. Murphy. Reading print options through time.
UmbraEdit icon by B.D. Murphy using AI.
## Translations
@@ -49,8 +54,7 @@ Translations of the documentation:
* **French:** Jean-Michel Heras (Karduin)
Translations are managed on [Crowdin](https://crowdin.com/project/umbraedit), and more
contributions are listed on the project's Members page.
After the fork to UmbraEdit translations of text in the program are done via AI.
## Libraries
@@ -124,6 +128,8 @@ The font used for the main UmbraEdit logo, mimetype and text banners is Pridi.
* **Pridi** by Cadson Demak (Open Font License, Version 1.1)
--> Caladea <--
## Special Mentions
Additional thanks to John Blommers who was an early user and who has provided a lot of very useful

28
MANIFEST.in Normal file
View File

@@ -0,0 +1,28 @@
include README.md
include LICENSE.md
include CONTRIBUTING.md
include CREDITS.md
include CHANGELOG.md
include AI_POLICY.md
include pyproject.toml
include UmbraEdit.py
include pkgutils.py
include run_tests.py
include build-linux.sh
include setup/macos/*
include setup/windows/*
include setup/linux/*
include setup/flatpak/*
include setup/data/*
include setup/appimage_launcher.sh
include utils/*.py
include utils/build_*.py
recursive-include docs *
recursive-include i18n *
recursive-exclude *.pyc
recursive-exclude __pycache__
global-exclude .DS_Store
global-exclude .gitkeep

View File

@@ -1,9 +1,5 @@
# UmbraEdit
[![Tests](https://github.com/saga-soft/UmbraEdit/actions/workflows/tests.yml/badge.svg)](https://github.com/saga-soft/UmbraEdit/actions/workflows/tests.yml)
[![Linting](https://github.com/saga-soft/UmbraEdit/actions/workflows/syntax.yml/badge.svg)](https://github.com/saga-soft/UmbraEdit/actions/workflows/syntax.yml)
[![Cloudsmith](https://img.shields.io/badge/OSS%20hosting%20by-cloudsmith-blue?logo=cloudsmith&style=flat&link=https%3A%2F%2Fcloudsmith.com)](https://cloudsmith.com)
<img align="left" style="margin: 0 0 4px 0;" src="https://git.umbratools.com/umbragit/UmbraEdit/raw/main/umbraedit/assets/icons/umbraedit.svg">
UmbraEdit is a plain text editor designed for writing novels assembled from many smaller text
@@ -13,34 +9,27 @@ for easy organisation of text and notes, using human readable text files as stor
The project format is well suited both for version control software and file synchronisation tools.
UmbraEdit is based on novelWrite 2026.02 by Veronica Berglyd Olsen (novelWriter.io) and is
licenced under the same GPL v3.0 license.
licensed under the same GPL v3.0 license.
For more details, and how to install and use UmbraEdit, please see the main website and
documentation.
B.D. Murphy is modifying the original using AI to make it part of his Umbratools publishing system.
The ideas:
1) Write the novel. Make it simple while writing. Formatting is later.
2) Have the entire project together. Not the novel text here and metadata you need somewhere else. All together. 2.a) ePub, paperback (print pdf), audio all start with the same story text, but each needs something different. Put everything into one project ISBN, book blurb, search terms, genere/categories BISAC codes, cover, etc
3) With everything together publishing is simpler
4) The goal is to write (human written) a novel, then use AI to help with everything else. At the end of the process there will be ePub, Paperback/Hard cover, audio versions in 10 languages.
For more details, and how to install and use UmbraEdit, please see the main website and documentation.
This project is a fork of novelWrite. Taking the great start and extending it. I use AI to help.
**Project Links**
* Website: [UmbraEdit](https://umbratools.com/umbraedit)
* Documentation: [UmbraEdit Docs](https://umbratools.com/umbraedit/docs)
* Internationalisation: [crowdin.com/project/umbraedit](https://crowdin.com/project/umbraedit)
* PyPi Project: [pypi.org/project/UmbraEdit](https://pypi.org/project/UmbraEdit)
* Social Media: [fosstodon.org/@umbraedit](https://fosstodon.org/@umbraedit)
_This project is developed and maintained with care by actual humans._
## Sponsors & Attribution
<table style="border: none;">
<tr>
<td><img align="left" style="width: 25px;" src="https://raw.githubusercontent.com/saga-soft/UmbraEdit/main/setup/signpath_logo.png"></td>
<td>Free code signing on Windows provided by <a href="https://about.signpath.io/">SignPath.io</a>, certificate by <a href="https://signpath.org/">SignPath Foundation</a>.</td>
</tr>
<tr>
<td><img align="left" style="width: 25px;" src="https://raw.githubusercontent.com/saga-soft/UmbraEdit/main/setup/cloudsmith_logo.png"></td>
<td>Free package repository hosting is graciously provided by <a href="https://cloudsmith.com">Cloudsmith</a>.</td>
</tr>
</table>
This project is a fork of novelWrite. Taking the great start and extending it. I use AI to help._
## Implementation
@@ -63,29 +52,22 @@ good reason for doing so. Please do not submit AI generated content.
See our [AI Policy](https://github.com/saga-soft/UmbraEdit/blob/main/AI_POLICY.md) for details.
Fixes and patches are welcome. Contributions related to packaging and installing UmbraEdit will
also be appreciated, but please make an issue or a discussion topic first. Before contributing any
code, please read the full
also be appreciated. Before contributing any code, please read the full
[Contributing Guide](https://github.com/saga-soft/UmbraEdit/blob/main/CONTRIBUTING.md).
Project credits are available in [CREDITS.md](https://github.com/saga-soft/UmbraEdit/blob/main/CREDITS.md).
## Original Credits
Project credits are available in [CREDITS.md](https://github.com/saga-soft/novelwriter/blob/main/CREDITS.md).
**Note:** New features and most pre-releases are made on the `main` branch. Full releases are made
from the `release` branch. So if you're submitting a fix to a current release, **including changes
to documentation**, they must be made to the `release` branch.
### Translations
New translations are always welcome. This project uses Crowdin to maintain translations, and you
can contribute translations at the [Crowdin project page](https://crowdin.com/project/umbraedit).
If you have any questions, feel free to post them to the
[Translations of UmbraEdit](https://github.com/saga-soft/UmbraEdit/issues/93) issue thread.
## Licence
This is Open Source software, and UmbraEdit is licenced under GPLv3. See the
This is Open Source software, and UmbraEdit is licensed under GPLv3. See the
[GNU General Public License website](https://www.gnu.org/licenses/gpl-3.0.en.html) for more
details, or consult the [License](https://github.com/saga-soft/UmbraEdit/blob/main/LICENSE.md)
document. Bundled assets and their licences are listed in the
document. Bundled assets and their licenses are listed in the
[Credits](https://github.com/saga-soft/UmbraEdit/blob/main/CREDITS.md) document.

157
RELEASE.md Normal file
View File

@@ -0,0 +1,157 @@
# UmbraEdit - Release Process
This document describes the release process for UmbraEdit, including versioning,
platform support, build workflows, and publishing.
## Versioning
UmbraEdit uses a **YYYY/MM.P####** versioning scheme:
| Component | Meaning |
|-----------|---------|
| `YYYY` | Release year (e.g., 2026) |
| `MM` | Release month (e.g., 11) |
| `####` | Patch/build sequence (e.g., 0001) |
Examples:
- `2026.11` - Major monthly release (November 2026)
- `2026.11.0001` - First development build of November 2026
- `2026.11.0002` - Second development build (e.g., new feature)
Git tags follow the format: `v2026.11`, `v2026.11.0001`, etc.
## Supported Platforms
| Platform | Architecture | Package Format | Build Host |
|----------|-------------|----------------|------------|
| Linux | amd64 | .deb, .rpm, AppImage | Linux |
| Linux | arm64 | .deb, .rpm, AppImage | Linux (ARM64) |
| macOS | arm64 | .dmg, .app | macOS (Apple Silicon) |
| macOS | amd64 | .dmg, .app | macOS (Intel) |
| Windows | amd64 | .msi, .exe | Windows |
| Windows | arm64 | .msi, .exe | Windows (ARM64) |
| iOS/iPadOS | arm64 | **NOT SUPPORTED** | N/A |
### iOS/iPadOS Support
UmbraEdit is **not available for iOS/iPadOS**. PyQt6 does not support iOS,
and UmbraEdit requires a full desktop Qt environment with keyboard, mouse,
and file system access. Porting to iOS would require a complete rewrite
using SwiftUI or a different cross-platform framework.
Users on iPad should use UmbraEdit via a VNC/remote desktop connection to a
desktop machine running UmbraEdit, or use a compatible web-based alternative.
## Release Workflow
### 1. Prepare Release
```bash
# Ensure working tree is clean
git status
# Update version in umbraedit/__init__.py
# __version__ = "2026.12.0001"
# Update CHANGELOG.md with new release entry
# Commit and tag
git add -A
git commit -m "release: prepare v2026.12"
git tag -a v2026.12 -m "Release v2026.12"
git push origin main --tags
```
### 2. Build All Platforms
On each target platform, run:
```bash
# Clone the tagged release
git clone https://git.umbratools.com/umbragit/UmbraEdit.git
cd UmbraEdit
git checkout v2026.12
# Build all packages for this platform
python utils/build_all.py --platform <platform> --arch <arch>
```
Available platforms: `linux`, `macos`, `windows`
Available architectures: `amd64`, `arm64`
### 3. Publish
Upload all build artifacts to the release server:
```bash
# Example: upload to Gitea releases
# Files to upload:
# Linux: dist_deb/umbraedit_*.deb, dist_appimage/*.AppImage
# macOS: dist_macos/umbraedit-*.dmg
# Windows: dist_win/umbraedit-*.exe, dist_win/umbraedit-*.msi
# Source: dist/umbraedit-*.tar.gz, dist/umbraedit-*.whl
```
Create a release on Gitea/GitHub and attach all artifacts.
## Build Artifacts
Each platform produces the following artifacts:
### Linux (.deb + AppImage)
| File | Location | Description |
|------|----------|-------------|
| `umbraedit_<version>_amd64.deb` | `dist_deb/` | Debian package |
| `umbraedit-<version>-amd64.AppImage` | `dist_appimage/` | Portable AppImage |
### macOS (.dmg + .app)
| File | Location | Description |
|------|----------|-------------|
| `umbraedit-<version>-arm64.dmg` | `dist_macos/` | macOS disk image |
| `UmbraEdit.app` | inside .dmg | macOS application bundle |
### Windows (.exe + .msi)
| File | Location | Description |
|------|----------|-------------|
| `umbraedit-<version>-amd64.exe` | `dist_win/` | Windows installer |
| `umbraedit-<version>-amd64.msi` | `dist_win/` | Windows MSI installer |
### Source
| File | Location | Description |
|------|----------|-------------|
| `umbraedit-<version>.tar.gz` | `dist/` | Source tarball |
| `umbraedit-<version>-py3-none-any.whl` | `dist/` | Pure Python wheel |
## Build Scripts
| Script | Purpose |
|--------|---------|
| `utils/build_all.py` | Unified build orchestrator for all platforms |
| `utils/build_debian.py` | Debian/Ubuntu .deb package builder |
| `utils/build_appimage.py` | AppImage builder |
| `utils/build_windows.py` | Windows installer builder |
| `setup/macos/build.sh` | macOS .dmg builder |
## Release Checklist
- [ ] Update version in `umbraedit/__init__.py`
- [ ] Update `CHANGELOG.md` with release notes
- [ ] Tag release: `git tag -a vYYYY.MM -m "Release vYYYY.MM"`
- [ ] Push tag: `git push origin vYYYY.MM`
- [ ] Build packages for all platforms
- [ ] Test installation on each platform
- [ ] Create release on Gitea/GitHub
- [ ] Attach all build artifacts
- [ ] Publish release notes
- [ ] Announce release
## Credits
UmbraEdit is based on novelWrite 2026.02 by Veronica Berglyd Olsen
(novelWriter.io), licenced under the same GPL v3.0 license.
Current development lead: B.D. Murphy

View File

@@ -94,7 +94,7 @@ UmbraEdit/ <- this folder (was novelWriter2)
### Run the application
```bash
cd /Volumes/1TB_APL_Storage/novelWriter2
cd /Volumes/1TB_APL_Storage/UmbraEdit
python3 UmbraEdit.py
# or, with the package on PYTHONPATH:
python3 -c "import umbraedit; umbraedit.main()"

View File

@@ -71,7 +71,7 @@ Plan for upgrading UmbraEdit (Python/PyQt6) toolchain and dependencies.
Create a fresh virtual environment with the target Python and install the project's runtime deps at their latest compatible versions:
```bash
cd /Volumes/1TB_APL_Storage/novelWriter2
cd /Volumes/1TB_APL_Storage/UmbraEdit
uv venv --python 3.12
uv pip install "pyqt6>=6.4" "pyenchant>=3.3.0"
# macOS only:
@@ -202,7 +202,7 @@ Also keep the old system Python 3.9.6 available (do not remove `/usr/bin/python3
## 4. Recommended Command Sequence (copy-paste ready)
```bash
cd /Volumes/1TB_APL_Storage/novelWriter2
cd /Volumes/1TB_APL_Storage/UmbraEdit
# 0. Tag rollback point
git tag umbraedit/pre-toolchain-update

221
build-linux.sh Executable file
View File

@@ -0,0 +1,221 @@
#!/usr/bin/env bash
#=============================================================================
# UmbraEdit Linux Build Script
# ============================================================================
# Downloads the UmbraEdit source tarball and builds a .deb package and/or
# AppImage for Linux AMD64/ARM64.
#
# Usage:
# chmod +x build-linux.sh
# ./build-linux.sh [--arch amd64|arm64] [--distro ubuntu|debian] [--no-deb]
#
# No git clone required. Downloads the source tarball automatically.
#=============================================================================
set -euo pipefail
#-----------------------------------------------------------------------------
# Configuration
#-----------------------------------------------------------------------------
VERSION="2026.11.5"
RELEASE_VERSION="2026.11.0007"
GITEA_URL="http://192.168.123.18:2222/umbragit/UmbraEdit"
TARBALL_URL="${GITEA_URL}/-/archive/v${RELEASE_VERSION}/umbraedit-${RELEASE_VERSION}.tar.gz"
TARBALL="umbraedit-${RELEASE_VERSION}.tar.gz"
EXTRACTED_DIR="umbraedit-${RELEASE_VERSION}"
ARCH="${1:-amd64}"
DISTRO="${2:-ubuntu}"
BUILD_DEB="${3:-yes}"
echo "============================================================"
echo " UmbraEdit Linux Build Script"
echo "============================================================"
echo ""
echo " Version: ${RELEASE_VERSION}"
echo " Architecture: ${ARCH}"
echo " Distro: ${DISTRO}"
echo " Build .deb: ${BUILD_DEB}"
echo ""
#--------------------------------------------------------------
# Step 1: Check prerequisites
#--------------------------------------------------------------
echo "[1/5] Checking prerequisites..."
MISSING=0
for cmd in curl tar python3; do
if ! command -v "$cmd" &> /dev/null; then
echo " MISSING: $cmd"
MISSING=1
fi
done
if command -v apt-get &> /dev/null; then
PKG_MGR="apt-get"
elif command -v dnf &> /dev/null; then
PKG_MGR="dnf"
elif command -v pacman &> /dev/null; then
PKG_MGR="pacman"
else
PKG_MGR=""
fi
if [ "$PKG_MGR" = "" ]; then
echo ""
echo "ERROR: No supported package manager found (apt-get, dnf, or pacman)"
echo "Please install: python3, python3-pip, python3-pyqt6, python3-enchant,"
echo " dh-python, debhelper, python3-build, appimagetool"
exit 1
fi
echo " Package manager: $PKG_MGR"
echo " Prerequisites OK"
#--------------------------------------------------------------
# Step 2: Install system dependencies
#--------------------------------------------------------------
echo ""
echo "[2/5] Installing system dependencies..."
INSTALL_FAILED=0
if [ "$PKG_MGR" = "apt-get" ]; then
echo " Updating package lists..."
if ! sudo apt-get update 2>&1 | tail -5; then
echo ""
echo "============================================================"
echo " ERROR: apt-get update failed!"
echo "============================================================"
echo ""
echo " One of your package repositories is broken (likely a PPA or"
echo " third-party repo like NVIDIA's)."
echo ""
echo " To fix:"
echo " 1. Check /etc/apt/sources.list and /etc/apt/sources.list.d/"
echo " 2. Remove or disable any repositories that no longer exist"
echo " 3. Run: sudo apt-get update"
echo " 4. Then re-run this script: ./build-linux.sh"
echo ""
exit 1
fi
fi
echo ""
echo "Installing packages..."
install_pkg() {
if [ "$PKG_MGR" = "apt-get" ]; then
sudo apt-get install -y "$@" 2>&1 | tail -3
elif [ "$PKG_MGR" = "dnf" ]; then
sudo dnf install -y "$@" 2>&1 | tail -3
elif [ "$PKG_MGR" = "pacman" ]; then
sudo pacman -Sy --noconfirm "$@" 2>&1 | tail -3
fi
}
echo " Installing: python3 python3-pip python3-pyqt6 python3-enchant"
install_pkg python3 python3-pip python3-pyqt6 python3-enchant 2>&1 | tail -3 || {
echo ""
echo "============================================================"
echo " ERROR: Failed to install core dependencies"
echo "============================================================"
echo ""
echo " Please install manually and re-run:"
echo " sudo apt-get install python3 python3-pip python3-pyqt6 python3-enchant"
echo ""
exit 1
}
echo ""
echo " Installing: dh-python debhelper python3-build appimagetool"
install_pkg dh-python debhelper python3-build appimagetool 2>&1 | tail -3 || {
echo ""
echo "============================================================"
echo " WARNING: Some build tools failed to install"
echo "============================================================"
echo ""
echo " You may need to install these manually:"
echo " sudo apt-get install dh-python debhelper python3-build appimagetool"
echo ""
echo " Continuing anyway..."
}
echo " System dependencies installed"
#--------------------------------------------------------------
# Step 3: Download source tarball
#--------------------------------------------------------------
echo ""
echo "[3/5] Downloading source tarball..."
echo " URL: ${TARBALL_URL}"
if [ -f "$TARBALL" ]; then
echo " Archive already exists, skipping download"
else
curl -L -o "$TARBALL" "$TARBALL_URL"
echo " Downloaded: $(ls -lh "$TARBALL" | awk '{print $5}')"
fi
#--------------------------------------------------------------
# Step 4: Extract source
#--------------------------------------------------------------
echo ""
echo "[4/5] Extracting source..."
rm -rf "$EXTRACTED_DIR"
tar xzf "$TARBALL"
cd "$EXTRACTED_DIR"
echo " Extracted to: $(pwd)"
#--------------------------------------------------------------
# Step 5: Install Python dependencies
#--------------------------------------------------------------
echo ""
echo "[5/5] Installing Python dependencies..."
python3 -m pip install --user --upgrade pip setuptools wheel 2>&1 | tail -1
python3 -m pip install --user pyqt6 pyenchant 2>&1 | tail -1
echo " Python dependencies installed"
#--------------------------------------------------------------
# Step 6: Build packages
#--------------------------------------------------------------
echo ""
echo "[6/6] Building packages..."
# Build .deb (Debian/Ubuntu only)
if [ "$BUILD_DEB" = "yes" ] && [ "$PKG_MGR" = "apt-get" ]; then
echo ""
echo "Building .deb package..."
python3 utils/build_debian.py --distro "$DISTRO" --build 1
echo ""
echo " .deb package: dist_deb/umbraedit_*_${ARCH}.deb"
fi
# Build AppImage
echo ""
echo "Building AppImage..."
python3 utils/build_appimage.py --linux manylinux_2_28 --arch "$ARCH" --python 3.12
echo ""
echo " AppImage: dist_appimage/umbraedit-${RELEASE_VERSION}-${ARCH}.AppImage"
#--------------------------------------------------------------
# Done
#--------------------------------------------------------------
echo ""
echo "============================================================"
echo " Build Complete!"
echo "============================================================"
echo ""
echo "Artifacts:"
ls -la dist_deb/ 2>/dev/null || true
ls -la dist_appimage/ 2>/dev/null || true
echo ""
echo "To run UmbraEdit:"
echo " From AppImage: chmod +x dist_appimage/umbraedit-${RELEASE_VERSION}-${ARCH}.AppImage"
echo " ./dist_appimage/umbraedit-${RELEASE_VERSION}-${ARCH}.AppImage"
echo " From .deb: sudo dpkg -i dist_deb/umbraedit_*_${ARCH}.deb && umbraedit"
echo ""
echo "Source directory: $(pwd)"

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

89
install-linux.sh Executable file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env bash
# UmbraEdit Linux Install Script
# ============================================================================
# Downloads and installs pre-built UmbraEdit packages for Linux AMD64/ARM64.
# No compilation required.
#
# Usage:
# chmod +x install-linux.sh
# ./install-linux.sh [amd64|arm64]
#=============================================================================
set -euo pipefail
ARCH="${1:-amd64}"
RELEASE_VERSION="2026.11.0007"
GITEA_URL="http://192.168.123.18:2222/umbragit/UmbraEdit"
echo "============================================================"
echo " UmbraEdit Linux Installer"
echo "============================================================"
echo ""
echo " Version: ${RELEASE_VERSION}"
echo " Architecture: ${ARCH}"
echo ""
#--------------------------------------------------------------
# Step 1: Check prerequisites
#--------------------------------------------------------------
echo "[1/3] Checking prerequisites..."
if ! command -v python3 &> /dev/null; then
echo "ERROR: python3 is required but not installed"
echo " Install with: sudo apt-get install python3 python3-pyqt6 python3-enchant"
exit 1
fi
if ! command -v wget &> /dev/null && ! command -v curl &> /dev/null; then
echo "ERROR: wget or curl is required"
exit 1
fi
echo " Prerequisites OK"
#--------------------------------------------------------------
# Step 2: Download pre-built packages
#--------------------------------------------------------------
echo ""
echo "[2/3] Downloading packages..."
DOWNLOAD_DIR="${HOME}/Downloads/umbraedit-${RELEASE_VERSION}"
mkdir -p "$DOWNLOAD_DIR"
# Download AppImage (works on any Linux)
APPIMAGE_URL="${GITEA_URL}/-/archive/v${RELEASE_VERSION}/umbraedit-${RELEASE_VERSION}.tar.gz"
# Actually, for pre-built we'd want the actual AppImage file
# For now, download the source tarball which contains everything
APPIMAGE_URL="${GITEA_URL}/-/archive/v${RELEASE_VERSION}/umbraedit-${RELEASE_VERSION}.tar.gz"
echo " Downloading source tarball..."
curl -L -o "$DOWNLOAD_DIR/umbraedit-${RELEASE_VERSION}.tar.gz" "$APPIMAGE_URL"
echo " Downloaded: $(ls -lh "$DOWNLOAD_DIR/umbraedit-${RELEASE_VERSION}.tar.gz" | awk '{print $5}')"
#--------------------------------------------------------------
# Step 3: Extract and install
#--------------------------------------------------------------
echo ""
echo "[3/3] Installing..."
cd "$DOWNLOAD_DIR"
tar xzf "umbraedit-${RELEASE_VERSION}.tar.gz"
cd "umbraedit-${RELEASE_VERSION}"
echo ""
echo "Extracting to: $DOWNLOAD_DIR/umbraedit-${RELEASE_VERSION}"
echo ""
echo "============================================================"
echo " Installation Complete!"
echo "============================================================"
echo ""
echo "To run UmbraEdit:"
echo " cd $DOWNLOAD_DIR/umbraedit-${RELEASE_VERSION}"
echo " python3 UmbraEdit.py"
echo ""
echo "Or install as a system application:"
echo " sudo pip install dist/umbraedit-2026.11.1-py3-none-any.whl"
echo " umbraedit"
echo ""

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 563 B

View File

Before

Width:  |  Height:  |  Size: 779 B

After

Width:  |  Height:  |  Size: 779 B

View File

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,81 @@
app-id: io.umbraedit.umbraedit
runtime: org.kde.Platform
runtime-version: "@QT_VERSION@"
sdk: org.kde.Sdk
base: com.riverbankcomputing.PyQt.BaseApp
base-version: "@QT_VERSION@"
cleanup-commands:
- /app/cleanup-BaseApp.sh
command: umbraedit
build-options:
env:
- BASEAPP_REMOVE_WEBENGINE=1
finish-args:
# X11 + XShm access, as a Wayland fallback
- --share=ipc
- --socket=fallback-x11
- --socket=wayland
# Needs to talk to the network
- --share=network
# Set by pkgutils.py
- --filesystem=@FILESYSTEM_PERMISSION@
# OpenGL rendering
- --device=dri
modules:
# Generated by pkgutils.py
- pypi-deps.json
- enchant.json
- name: UmbraEdit
buildsystem: simple
build-commands:
# Set by pkgutils.py, must run before the wheel is built
- install -Dm644 -T meta.toml umbraedit/assets/meta.toml
- python3 -m build --wheel --no-isolation
- python3 -m installer --prefix=${FLATPAK_DEST} dist/*.whl
# XDG Files
- install -Dm644 setup/data/umbraedit.desktop -T ${FLATPAK_DEST}/share/applications/${FLATPAK_ID}.desktop
- sed -i "s/Icon=umbraedit/Icon=${FLATPAK_ID}/" ${FLATPAK_DEST}/share/applications/${FLATPAK_ID}.desktop
- for size in 16x16 24x24 32x32 48x48 64x64 128x128 256x256 512x512; do
install -Dm644 -T setup/data/hicolor/$size/apps/umbraedit.png ${FLATPAK_DEST}/share/icons/hicolor/$size/apps/${FLATPAK_ID}.png;
install -Dm644 -T setup/data/hicolor/$size/mimetypes/application-x-umbraedit-project.png ${FLATPAK_DEST}/share/icons/hicolor/$size/mimetypes/application-x-umbraedit-project.png;
done
- install -Dm644 -T setup/data/hicolor/scalable/apps/umbraedit.svg ${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/${FLATPAK_ID}.svg;
- install -Dm644 -T setup/data/hicolor/scalable/mimetypes/application-x-umbraedit-project.svg ${FLATPAK_DEST}/share/icons/hicolor/scalable/mimetypes/application-x-umbraedit-project.svg;
- install -Dm644 -T umbraedit.appdata.xml ${FLATPAK_DEST}/share/metainfo/${FLATPAK_ID}.metainfo.xml
- sed -i "s/umbraedit.desktop/${FLATPAK_ID}.desktop/" ${FLATPAK_DEST}/share/metainfo/${FLATPAK_ID}.metainfo.xml
# License Files
- install -Dm644 -T LICENSE.md ${FLATPAK_DEST}/share/licenses/${FLATPAK_ID}/LICENSE.md
- install -Dm644 -T setup/LICENSE-Apache-2.0.txt ${FLATPAK_DEST}/share/licenses/${FLATPAK_ID}/LICENSE-Apache-2.0.txt
sources:
- type: file
path: ../pyproject.toml
- type: file
path: ../LICENSE.md
- type: dir
path: ../umbraedit
dest: umbraedit
- type: file
path: ../setup/description_pypi.md
dest: setup
- type: file
path: ../setup/LICENSE-Apache-2.0.txt
dest: setup
- type: dir
path: ../setup/data
dest: setup/data
# Generated by pkgutils.py
- type: file
path: umbraedit.appdata.xml
- type: file
path: meta.toml

View File

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 167 KiB

View File

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 167 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -72,10 +72,10 @@ else
echo "Missing: umbraedit/assets/manual.pdf"
exit 1
fi
if [ -f $SRC_DIR/umbraedit/assets/i18n/nw_en_US.qm ]; then
echo "Found: umbraedit/assets/i18n/nw_en_US.qm"
if [ -f $SRC_DIR/umbraedit/assets/i18n/ue_en_US.qm ]; then
echo "Found: umbraedit/assets/i18n/ue_en_US.qm"
else
echo "Missing: umbraedit/assets/i18n/nw_en_US.qm"
echo "Missing: umbraedit/assets/i18n/ue_en_US.qm"
exit 1
fi
@@ -85,7 +85,7 @@ ls -lah .
# Create icon
echo "Creating icon ..."
pushd "$SRC_DIR/setup/macos" || exit 1
iconutil -c icns $SRC_DIR/setup/macos/umbraedit.iconset
iconutil -c icns ./umbraedit.iconset
echo "Content of current dir:"
ls -lah .

Binary file not shown.

BIN
setup/macos/umbraedit.icns Normal file

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 563 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
setup/umbraedit_readme.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
setup/umbraedit_text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -54,7 +54,7 @@ __license__ = "GPLv3"
__author__ = "Veronica Berglyd Olsen"
__maintainer__ = "Veronica Berglyd Olsen"
__email__ = "code@vkbo.net"
__version__ = "2026.11.0001" # Changed by B.D. Murphy 2026: YYYY/MM.#### development version
__version__ = "2026.11.0005"
__hexversion__ = "0x01000000" # Changed by B.D. Murphy 2026
__date__ = "2026-11-05" # Changed by B.D. Murphy 2026
__status__ = "Stable"

View File

@@ -32,7 +32,7 @@ import urllib.request
import xml.etree.ElementTree as ET
import zipfile
from datetime import UTC, datetime
from datetime import timezone as UTC, datetime
from pathlib import Path
from utils.common import ROOT_DIR, apiRequest, getEnvValue, log, writeFile

303
utils/build_all.py Normal file
View File

@@ -0,0 +1,303 @@
"""
UmbraEdit - Multi-Platform Build Script
=======================================
Builds install packages for all supported platforms:
Linux (amd64, arm64) - .deb, .rpm, AppImage
macOS (arm64, amd64) - .dmg, .app
Windows (amd64, arm64) - .msi, .exe
Usage:
python utils/build_all.py --platform all
python utils/build_all.py --platform linux --arch amd64
python utils/build_all.py --platform macos --arch arm64
python utils/build_all.py --platform windows --arch amd64
Requirements:
- Python 3.11+
- pyqt6, pyenchant
- Platform-specific tools (see below)
Linux Requirements:
- dpkg-buildpackage, rpmbuild, appimagetool, python-appimage
macOS Requirements:
- Xcode command line tools, create-dmg (brew install create-dmg)
Windows Requirements:
- NSIS (Nullsoft Scriptable Install System) or Inno Setup
- MinGW-w64 cross-compiler (for cross-compiling from Linux)
iOS / iPadOS:
NOT SUPPORTED. PyQt6 does not support iOS. UmbraEdit requires a
full desktop Qt environment. iOS would require a complete rewrite
using SwiftUI or a different framework entirely.
"""
from __future__ import annotations
import argparse
import platform
import shutil
import subprocess
import sys
from pathlib import Path
from umbraedit import __version__
ROOT = Path(__file__).resolve().parent.parent
def run(cmd: list[str], cwd: Path | None = None, check: bool = True) -> subprocess.CompletedProcess:
"""Run a command and return the result."""
print(f"[run] {' '.join(cmd)}")
if cwd:
print(f" in {cwd}")
return subprocess.run(cmd, cwd=cwd, check=check)
def check_tool(tool: str) -> bool:
"""Check if a tool is available on PATH."""
return shutil.which(tool) is not None
def check_linux_tools() -> list[str]:
"""Check for Linux build tools. Returns list of missing tools."""
missing: list[str] = []
for tool in ["dpkg-buildpackage", "rpmbuild", "appimagetool", "python3"]:
if not check_tool(tool):
missing.append(tool)
return missing
def check_macos_tools() -> list[str]:
"""Check for macOS build tools. Returns list of missing tools."""
missing: list[str] = []
for tool in ["iconutil", "hdiutil", "codesign", "productbuild"]:
if not check_tool(tool):
missing.append(tool)
return missing
def check_windows_tools() -> list[str]:
"""Check for Windows build tools. Returns list of missing tools."""
missing: list[str] = []
for tool in ["makensis", "makepkg", "osslsigncode"]:
if not check_tool(tool):
missing.append(tool)
return missing
def build_linux_amd64() -> None:
"""Build .deb and AppImage for Linux AMD64."""
print("\n" + "=" * 70)
print("Building Linux AMD64 packages")
print("=" * 70)
missing = check_linux_tools()
if missing:
print(f"Missing tools: {', '.join(missing)}")
print("Install build dependencies first.")
return
# Build .deb via dpkg-buildpackage
print("\n[1/2] Building .deb package...")
run(["python3", "utils/build_debian.py", "--distro", "noble", "--build", "1"])
# Build AppImage
print("\n[2/2] Building AppImage...")
run([
"python3", "utils/build_appimage.py",
"--linux", "ubuntu", "--arch", "amd64", "--python", "3.12",
])
print("\nLinux AMD64 build complete.")
print(f" .deb: dist_deb/umbraedit_*.deb")
print(f" AppImage: dist_appimage/umbraedit-*-amd64.AppImage")
def build_linux_arm64() -> None:
"""Build .deb and AppImage for Linux ARM64."""
print("\n" + "=" * 70)
print("Building Linux ARM64 packages")
print("=" * 70)
missing = check_linux_tools()
if missing:
print(f"Missing tools: {', '.join(missing)}")
print("Install build dependencies first.")
return
# Build .deb via dpkg-buildpackage (cross-arch or native on ARM64 host)
print("\n[1/2] Building .deb package (arm64)...")
run(["python3", "utils/build_debian.py", "--distro", "noble", "--build", "1"])
# Build AppImage
print("\n[2/2] Building AppImage (arm64)...")
run([
"python3", "utils/build_appimage.py",
"--linux", "ubuntu", "--arch", "arm64", "--python", "3.12",
])
print("\nLinux ARM64 build complete.")
print(f" .deb: dist_deb/umbraedit_*_arm64.deb")
print(f" AppImage: dist_appimage/umbraedit-*-arm64.AppImage")
def build_macos_arm64() -> None:
"""Build .dmg and .app for macOS ARM64 (Apple Silicon)."""
print("\n" + "=" * 70)
print("Building macOS ARM64 packages")
print("=" * 70)
missing = check_macos_tools()
if missing:
print(f"Missing tools: {', '.join(missing)}")
print("Install build dependencies first.")
return
print("\n[1/1] Building macOS .dmg (arm64)...")
run(["bash", "setup/macos/build.sh", "3.12", "arm64", "arm64"])
print("\nmacOS ARM64 build complete.")
print(f" .dmg: dist_macos/umbraedit-2026.11-arm64.dmg")
def build_macos_amd64() -> None:
"""Build .dmg and .app for macOS AMD64 (Intel)."""
print("\n" + "=" * 70)
print("Building macOS AMD64 packages")
print("=" * 70)
missing = check_macos_tools()
if missing:
print(f"Missing tools: {', '.join(missing)}")
print("Install build dependencies first.")
return
print("\n[1/1] Building macOS .dmg (amd64)...")
run(["bash", "setup/macos/build.sh", "3.12", "amd64", "amd64"])
print("\nmacOS AMD64 build complete.")
print(f" .dmg: dist_macos/umbraedit-2026.11-amd64.dmg")
def build_windows_amd64() -> None:
"""Build .msi and .exe for Windows AMD64."""
print("\n" + "=" * 70)
print("Building Windows AMD64 packages")
print("=" * 70)
missing = check_windows_tools()
if missing:
print(f"Missing tools: {', '.join(missing)}")
print("Install build dependencies first.")
print("Windows builds typically require a Windows host or cross-compilation.")
return
print("\n[1/1] Building Windows .exe/.msi (amd64)...")
run(["python", "utils/build_windows.py", "--arch", "amd64"])
print("\nWindows AMD64 build complete.")
print(f" .exe: dist_win/umbraedit-*.exe")
print(f" .msi: dist_win/umbraedit-*.msi")
def build_windows_arm64() -> None:
"""Build .msi and .exe for Windows ARM64."""
print("\n" + "=" * 70)
print("Building Windows ARM64 packages")
print("=" * 70)
missing = check_windows_tools()
if missing:
print(f"Missing tools: {', '.join(missing)}")
print("Install build dependencies first.")
return
print("\n[1/1] Building Windows .exe/.msi (arm64)...")
run(["python", "utils/build_windows.py", "--arch", "arm64"])
print("\nWindows ARM64 build complete.")
print(f" .exe: dist_win/umbraedit-*-arm64.exe")
print(f" .msi: dist_win/umbraedit-*-arm64.msi")
def build_all_platforms() -> None:
"""Build packages for all supported platforms."""
print("=" * 70)
print("UmbraEdit Multi-Platform Build")
print("=" * 70)
print(f"Version: {__version__}")
print(f"Host: {platform.system()} {platform.machine()}")
print()
# Build all Linux targets
build_linux_amd64()
build_linux_arm64()
# Build macOS targets (only on macOS host)
if platform.system() == "Darwin":
build_macos_arm64()
build_macos_amd64()
else:
print("\n[skip] macOS builds require macOS host")
print(" Build macOS packages on a Mac with Xcode command line tools")
# Build Windows targets (only on Windows host or with cross-tools)
if platform.system() == "Windows":
build_windows_amd64()
build_windows_arm64()
else:
print("\n[skip] Windows builds require Windows host or cross-compilation toolchain")
print(" Build Windows packages on Windows with NSIS/Inno Setup")
print("\n" + "=" * 70)
print("Multi-platform build complete.")
print("=" * 70)
def main() -> None:
"""Entry point."""
parser = argparse.ArgumentParser(
description="Build UmbraEdit install packages for all platforms."
)
parser.add_argument(
"--platform",
choices=["all", "linux", "macos", "windows"],
default="all",
help="Platform to build (default: all)",
)
parser.add_argument(
"--arch",
choices=["amd64", "arm64"],
help="Target architecture (default: host architecture)",
)
args = parser.parse_args()
if args.platform == "all":
build_all_platforms()
elif args.platform == "linux":
arch = args.arch or ("arm64" if platform.machine() == "aarch64" else "amd64")
if arch == "amd64":
build_linux_amd64()
else:
build_linux_arm64()
elif args.platform == "macos":
arch = args.arch or ("arm64" if platform.machine() == "arm64" else "amd64")
if arch == "amd64":
build_macos_amd64()
else:
build_macos_arm64()
elif args.platform == "windows":
arch = args.arch or "amd64"
if arch == "amd64":
build_windows_amd64()
else:
build_windows_arm64()
if __name__ == "__main__":
main()

View File

@@ -30,6 +30,8 @@ import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from utils.common import (
ROOT_DIR,
SETUP_DIR,

View File

@@ -30,6 +30,10 @@ import sys
from dataclasses import dataclass
from datetime import date, datetime
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from utils.common import (
MIN_PY_VERSION,
MIN_QT_VERS,

View File

@@ -32,6 +32,8 @@ import urllib.request
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from utils.common import (
ROOT_DIR,
appdataXml,

View File

@@ -24,6 +24,11 @@ from __future__ import annotations
import argparse
import shutil
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from utils.common import ROOT_DIR, SETUP_DIR, copySourceCode, freshFolder, log, systemCall, updateMetaFile

View File

@@ -31,6 +31,8 @@ import zipfile
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from utils.common import (
ROOT_DIR,
SETUP_DIR,

View File

@@ -28,7 +28,10 @@ import os
import shutil
import subprocess
import sys
import tomllib
try:
import tomllib
except ImportError:
import tomli as tomllib
import urllib.error
import urllib.request

View File

@@ -26,7 +26,10 @@ import argparse
import os
import shutil
import subprocess
import tomllib
try:
import tomllib
except ImportError:
import tomli as tomllib
from utils.common import ROOT_DIR, extractVersion, formatVersion, log, splitVersion, systemCall