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
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -80,3 +80,8 @@ GEMINI.md
|
|||||||
# Added by B.D. Murphy 2026: exclude files accidentally committed during branding transition
|
# Added by B.D. Murphy 2026: exclude files accidentally committed during branding transition
|
||||||
Splh.jpeg
|
Splh.jpeg
|
||||||
Oldwelcome.webp
|
Oldwelcome.webp
|
||||||
|
.DS_Store
|
||||||
|
UmbraEdit_Projects/
|
||||||
|
Inner_Demon_1.2a.docm
|
||||||
|
requirements.txt
|
||||||
|
UmbraEdit_deb_Build_Script.txt
|
||||||
|
|||||||
149
BUILD_LINUX.md
149
BUILD_LINUX.md
@@ -1,116 +1,129 @@
|
|||||||
# UmbraEdit - Linux AMD64 Build Guide
|
# UmbraEdit - Linux AMD64 Build Guide
|
||||||
|
|
||||||
UmbraEdit is built on macOS (darwin/aarch64), so native Linux packages (.deb, .rpm, AppImage)
|
UmbraEdit is developed on macOS but builds natively on Linux AMD64 and ARM64.
|
||||||
cannot be built directly from this machine. This document describes how to build
|
This guide covers building Linux install packages from source.
|
||||||
Linux AMD64 install packages from the source artifacts provided here.
|
|
||||||
|
|
||||||
## Build Artifacts
|
## Source Distribution
|
||||||
|
|
||||||
The following files are in `dist/`:
|
The source tarball (`umbraedit-2026.11.1.tar.gz`) includes everything needed to
|
||||||
|
build Linux packages:
|
||||||
|
|
||||||
| File | Description | Purpose |
|
```
|
||||||
|------|-------------|---------|
|
umbraedit-2026.11.1/
|
||||||
| `umbraedit-2026.11.1.tar.gz` | Source distribution (sdist) | Source tarball for building on Linux |
|
├── pyproject.toml # Project metadata & dependencies
|
||||||
| `umbraedit-2026.11.1-py3-none-any.whl` | Pure Python wheel | Installable via pip on any platform |
|
├── UmbraEdit.py # Application entry point
|
||||||
|
├── pkgutils.py # Packaging utility
|
||||||
## Prerequisites on Linux AMD64
|
├── run_tests.py # Test runner
|
||||||
|
├── setup/ # Packaging assets
|
||||||
Before building, install the required system packages:
|
│ ├── data/ # .desktop file, MIME type XML
|
||||||
|
│ ├── macos/ # macOS-specific packaging
|
||||||
```bash
|
│ └── windows/ # Windows-specific packaging
|
||||||
# Debian/Ubuntu
|
├── utils/ # Build scripts
|
||||||
sudo apt-get update
|
│ ├── build_debian.py # .deb package builder
|
||||||
sudo apt-get install python3 python3-pip python3-pyqt6 python3-pyqt6.qtsvg \
|
│ ├── build_appimage.py # AppImage builder
|
||||||
python3-enchant qt6-image-formats-plugins qt6-svg-plugins \
|
│ ├── build_all.py # Multi-platform build orchestrator
|
||||||
dh-python debhelper python3-build python3-setuptools
|
│ └── ...
|
||||||
|
├── umbraedit/ # Application source code
|
||||||
# Fedora/RHEL
|
└── tests/ # Test suite
|
||||||
sudo dnf install python3 python3-pip python3-pyqt6 python3-enchant \
|
|
||||||
qt6-qtimageformats qt6-qtsvg python3-build python3-setuptools
|
|
||||||
|
|
||||||
# Arch Linux
|
|
||||||
sudo pacman -S python python-pip python-pyqt6 python-enchant qt6-imageformats qt6-svg \
|
|
||||||
python-build python-setuptools
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Option 1: Install via Wheel (Simplest)
|
## Prerequisites on Linux
|
||||||
|
|
||||||
The pure Python wheel can be installed directly on Linux AMD64 with pip:
|
### Debian/Ubuntu
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Copy the wheel to your Linux AMD64 machine
|
sudo apt-get update
|
||||||
scp umbraedit-2026.11.1-py3-none-any.whl user@linux-machine:~/
|
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
|
||||||
|
```
|
||||||
|
|
||||||
# On the Linux machine
|
### 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
|
pip install umbraedit-2026.11.1-py3-none-any.whl
|
||||||
|
|
||||||
# Run UmbraEdit
|
|
||||||
umbraedit
|
umbraedit
|
||||||
```
|
```
|
||||||
|
|
||||||
This installs the application as a Python package with the `umbraedit` console script
|
### Option 2: Install from Source Tarball
|
||||||
entry point. No compilation is required.
|
|
||||||
|
|
||||||
## Option 2: Build from Source Distribution
|
|
||||||
|
|
||||||
The source tarball contains all source files needed to build native Linux packages:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Copy the source tarball to your Linux AMD64 machine
|
|
||||||
scp umbraedit-2026.11.1.tar.gz user@linux-machine:~/
|
|
||||||
|
|
||||||
# On the Linux machine
|
|
||||||
tar xzf umbraedit-2026.11.1.tar.gz
|
tar xzf umbraedit-2026.11.1.tar.gz
|
||||||
cd umbraedit-2026.11.1
|
cd umbraedit-2026.11.1
|
||||||
|
|
||||||
# Build and install locally
|
|
||||||
pip install .
|
pip install .
|
||||||
|
umbraedit
|
||||||
```
|
```
|
||||||
|
|
||||||
## Option 3: Build Debian (.deb) Package
|
### Option 3: Build .deb Package
|
||||||
|
|
||||||
On a Debian/Ubuntu-based Linux AMD64 system:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install build dependencies
|
|
||||||
sudo apt-get install dh-python pybuild-plugin-pyproject python3-build \
|
|
||||||
python3-setuptools python3-all debhelper \
|
|
||||||
python3-pytest python3-pytestqt python3-pytest-timeout
|
|
||||||
|
|
||||||
# Extract and build
|
|
||||||
tar xzf umbraedit-2026.11.1.tar.gz
|
tar xzf umbraedit-2026.11.1.tar.gz
|
||||||
cd umbraedit-2026.11.1
|
cd umbraedit-2026.11.1
|
||||||
|
|
||||||
# Build .deb package
|
# Build for Ubuntu Noble (24.04)
|
||||||
python3 utils/build_debian.py --distro noble # or trixie, resolute, stonking
|
python3 utils/build_debian.py --distro noble --build 1
|
||||||
|
|
||||||
# The .deb will be in dist_deb/
|
# The .deb will be in dist_deb/
|
||||||
sudo dpkg -i dist_deb/umbraedit_*.deb
|
sudo dpkg -i dist_deb/umbraedit_*_amd64.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
Available distro targets: `bookworm`, `trixie`, `noble`, `resolute`, `stonking`, `wilma`
|
Available distro targets: `bookworm`, `trixie`, `noble`, `resolute`, `stonking`, `wilma`
|
||||||
|
|
||||||
## Option 4: Build AppImage
|
### Option 4: Build AppImage
|
||||||
|
|
||||||
On any Linux AMD64 system:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install AppImage build tools
|
|
||||||
pip install python-appimage
|
pip install python-appimage
|
||||||
sudo apt-get install appimagetool # or download from GitHub
|
sudo apt-get install appimagetool
|
||||||
|
|
||||||
# Extract and build
|
|
||||||
tar xzf umbraedit-2026.11.1.tar.gz
|
tar xzf umbraedit-2026.11.1.tar.gz
|
||||||
cd umbraedit-2026.11.1
|
cd umbraedit-2026.11.1
|
||||||
|
|
||||||
# Build AppImage
|
|
||||||
python3 utils/build_appimage.py --linux ubuntu --arch amd64 --python 3.12
|
python3 utils/build_appimage.py --linux ubuntu --arch amd64 --python 3.12
|
||||||
|
|
||||||
# The AppImage will be in dist_appimage/
|
|
||||||
chmod +x dist_appimage/umbraedit-2026.11-amd64.AppImage
|
chmod +x dist_appimage/umbraedit-2026.11-amd64.AppImage
|
||||||
./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
|
## Project Storage
|
||||||
|
|
||||||
UmbraEdit projects are stored in plain folders with an `nwProject.nwx` file.
|
UmbraEdit projects are stored in plain folders with an `nwProject.nwx` file.
|
||||||
@@ -123,7 +136,7 @@ umbraedit # Opens the welcome dialog
|
|||||||
|
|
||||||
## Version
|
## Version
|
||||||
|
|
||||||
Current development version: **2026.11.0003**
|
Current development version: **2026.11.0004**
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
0
CODE_OF_CONDUCT.md
Normal file
0
CODE_OF_CONDUCT.md
Normal file
14
CREDITS.md
14
CREDITS.md
@@ -1,9 +1,13 @@
|
|||||||
# Credits
|
# Credits
|
||||||
|
|
||||||
## Main Developer
|
## Main Developer novelWriter
|
||||||
|
|
||||||
* Veronica Berglyd Olsen
|
* Veronica Berglyd Olsen
|
||||||
|
|
||||||
|
## Main Product Manager / Developer
|
||||||
|
|
||||||
|
* B.D. Murphy
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
Larger contributions were made by:
|
Larger contributions were made by:
|
||||||
@@ -18,7 +22,8 @@ For other contributions, see the project's [Contributors](https://github.com/sag
|
|||||||
|
|
||||||
## Artwork
|
## 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
|
## Translations
|
||||||
|
|
||||||
@@ -49,8 +54,7 @@ Translations of the documentation:
|
|||||||
|
|
||||||
* **French:** Jean-Michel Heras (Karduin)
|
* **French:** Jean-Michel Heras (Karduin)
|
||||||
|
|
||||||
Translations are managed on [Crowdin](https://crowdin.com/project/umbraedit), and more
|
After the fork to UmbraEdit translations of text in the program are done via AI.
|
||||||
contributions are listed on the project's Members page.
|
|
||||||
|
|
||||||
## Libraries
|
## 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)
|
* **Pridi** by Cadson Demak (Open Font License, Version 1.1)
|
||||||
|
|
||||||
|
--> Caladea <--
|
||||||
|
|
||||||
## Special Mentions
|
## Special Mentions
|
||||||
|
|
||||||
Additional thanks to John Blommers who was an early user and who has provided a lot of very useful
|
Additional thanks to John Blommers who was an early user and who has provided a lot of very useful
|
||||||
|
|||||||
27
MANIFEST.in
Normal file
27
MANIFEST.in
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
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 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
|
||||||
49
README.md
49
README.md
@@ -1,9 +1,5 @@
|
|||||||
# UmbraEdit
|
# UmbraEdit
|
||||||
|
|
||||||
[](https://github.com/saga-soft/UmbraEdit/actions/workflows/tests.yml)
|
|
||||||
[](https://github.com/saga-soft/UmbraEdit/actions/workflows/syntax.yml)
|
|
||||||
[](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">
|
<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
|
UmbraEdit is a plain text editor designed for writing novels assembled from many smaller text
|
||||||
@@ -13,34 +9,26 @@ 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.
|
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
|
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.
|
||||||
|
UmbraEdit is based on novelWrite 2026.02 by Veronica Berglyd Olsen (novelWriter.io) and is licensed under the same GPL v3.0 license.
|
||||||
|
|
||||||
For more details, and how to install and use UmbraEdit, please see the main website and
|
B.D. Murphy is modifying the original using AI to make it part of his Umbratools publishing system.
|
||||||
documentation.
|
|
||||||
|
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**
|
**Project Links**
|
||||||
|
|
||||||
* Website: [UmbraEdit](https://umbratools.com/umbraedit)
|
* Website: [UmbraEdit](https://umbratools.com/umbraedit)
|
||||||
* Documentation: [UmbraEdit Docs](https://umbratools.com/umbraedit/docs)
|
* 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>
|
|
||||||
|
|
||||||
|
|
||||||
## Implementation
|
## Implementation
|
||||||
|
|
||||||
@@ -76,16 +64,13 @@ to documentation**, they must be made to the `release` branch.
|
|||||||
|
|
||||||
### Translations
|
### 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
|
## 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
|
[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)
|
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.
|
[Credits](https://github.com/saga-soft/UmbraEdit/blob/main/CREDITS.md) document.
|
||||||
|
|||||||
157
RELEASE.md
Normal file
157
RELEASE.md
Normal 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
|
||||||
@@ -94,7 +94,7 @@ UmbraEdit/ <- this folder (was novelWriter2)
|
|||||||
|
|
||||||
### Run the application
|
### Run the application
|
||||||
```bash
|
```bash
|
||||||
cd /Volumes/1TB_APL_Storage/novelWriter2
|
cd /Volumes/1TB_APL_Storage/UmbraEdit
|
||||||
python3 UmbraEdit.py
|
python3 UmbraEdit.py
|
||||||
# or, with the package on PYTHONPATH:
|
# or, with the package on PYTHONPATH:
|
||||||
python3 -c "import umbraedit; umbraedit.main()"
|
python3 -c "import umbraedit; umbraedit.main()"
|
||||||
|
|||||||
@@ -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:
|
Create a fresh virtual environment with the target Python and install the project's runtime deps at their latest compatible versions:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Volumes/1TB_APL_Storage/novelWriter2
|
cd /Volumes/1TB_APL_Storage/UmbraEdit
|
||||||
uv venv --python 3.12
|
uv venv --python 3.12
|
||||||
uv pip install "pyqt6>=6.4" "pyenchant>=3.3.0"
|
uv pip install "pyqt6>=6.4" "pyenchant>=3.3.0"
|
||||||
# macOS only:
|
# 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)
|
## 4. Recommended Command Sequence (copy-paste ready)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Volumes/1TB_APL_Storage/novelWriter2
|
cd /Volumes/1TB_APL_Storage/UmbraEdit
|
||||||
|
|
||||||
# 0. Tag rollback point
|
# 0. Tag rollback point
|
||||||
git tag umbraedit/pre-toolchain-update
|
git tag umbraedit/pre-toolchain-update
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ else
|
|||||||
echo "Missing: umbraedit/assets/manual.pdf"
|
echo "Missing: umbraedit/assets/manual.pdf"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ -f $SRC_DIR/umbraedit/assets/i18n/nw_en_US.qm ]; then
|
if [ -f $SRC_DIR/umbraedit/assets/i18n/ue_en_US.qm ]; then
|
||||||
echo "Found: umbraedit/assets/i18n/nw_en_US.qm"
|
echo "Found: umbraedit/assets/i18n/ue_en_US.qm"
|
||||||
else
|
else
|
||||||
echo "Missing: umbraedit/assets/i18n/nw_en_US.qm"
|
echo "Missing: umbraedit/assets/i18n/ue_en_US.qm"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
BIN
setup/macos/umbraedit.icns
Normal file
BIN
setup/macos/umbraedit.icns
Normal file
Binary file not shown.
@@ -32,7 +32,7 @@ import urllib.request
|
|||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
from datetime import UTC, datetime
|
from datetime import timezone as UTC, datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from utils.common import ROOT_DIR, apiRequest, getEnvValue, log, writeFile
|
from utils.common import ROOT_DIR, apiRequest, getEnvValue, log, writeFile
|
||||||
|
|||||||
303
utils/build_all.py
Normal file
303
utils/build_all.py
Normal 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()
|
||||||
@@ -28,7 +28,10 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tomllib
|
try:
|
||||||
|
import tomllib
|
||||||
|
except ImportError:
|
||||||
|
import tomli as tomllib
|
||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ import argparse
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import tomllib
|
try:
|
||||||
|
import tomllib
|
||||||
|
except ImportError:
|
||||||
|
import tomli as tomllib
|
||||||
|
|
||||||
from utils.common import ROOT_DIR, extractVersion, formatVersion, log, splitVersion, systemCall
|
from utils.common import ROOT_DIR, extractVersion, formatVersion, log, splitVersion, systemCall
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user