Migrate to Poetry packaging and restructure codebase #21
@@ -15,6 +15,7 @@ Makefile
|
||||
build/
|
||||
dist/
|
||||
public/
|
||||
meshchatx/public/
|
||||
node_modules/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
203
.github/workflows/build.yml
vendored
203
.github/workflows/build.yml
vendored
@@ -27,102 +27,14 @@ on:
|
||||
default: 'true'
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.build_windows == 'true')
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@f1f314fca9dfce2769ece7d933488f076716723e # v1
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install Poetry
|
||||
run: python -m pip install --upgrade pip poetry
|
||||
|
||||
- name: Sync versions
|
||||
run: python scripts/sync_version.py
|
||||
|
||||
- name: Install Python Deps
|
||||
run: python -m poetry install
|
||||
|
||||
- name: Install NodeJS Deps
|
||||
run: npm install
|
||||
|
||||
- name: Build Electron App
|
||||
run: npm run dist
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1
|
||||
with:
|
||||
draft: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
omitDraftDuringUpdate: true
|
||||
omitNameDuringUpdate: true
|
||||
artifacts: "dist/*-win-installer.exe,dist/*-win-portable.exe"
|
||||
|
||||
build_mac:
|
||||
runs-on: macos-13
|
||||
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.build_mac == 'true')
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@f1f314fca9dfce2769ece7d933488f076716723e # v1
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install Poetry
|
||||
run: python -m pip install --upgrade pip poetry
|
||||
|
||||
- name: Sync versions
|
||||
run: python scripts/sync_version.py
|
||||
|
||||
- name: Install Python Deps
|
||||
run: python -m poetry install
|
||||
|
||||
- name: Install NodeJS Deps
|
||||
run: npm install
|
||||
|
||||
- name: Build Electron App
|
||||
run: npm run dist
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1
|
||||
with:
|
||||
draft: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
omitDraftDuringUpdate: true
|
||||
omitNameDuringUpdate: true
|
||||
artifacts: "dist/*-mac.dmg"
|
||||
|
||||
build_linux:
|
||||
build_frontend:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.build_linux == 'true')
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1
|
||||
@@ -137,33 +49,108 @@ jobs:
|
||||
with:
|
||||
|
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Sync versions
|
||||
run: python scripts/sync_version.py
|
||||
|
||||
- name: Install NodeJS Deps
|
||||
run: npm install
|
||||
|
||||
- name: Build Frontend
|
||||
run: npm run build-frontend
|
||||
|
||||
- name: Upload frontend artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: frontend-build
|
||||
path: meshchatx/public
|
||||
if-no-files-found: error
|
||||
|
||||
build_desktop:
|
||||
name: Build Desktop (${{ matrix.name }})
|
||||
needs: build_frontend
|
||||
runs-on: ${{ matrix.os }}
|
||||
if: |
|
||||
github.event_name == 'push' ||
|
||||
(
|
||||
github.event_name == 'workflow_dispatch' &&
|
||||
(
|
||||
(matrix.name == 'windows' && github.event.inputs.build_windows == 'true') ||
|
||||
(matrix.name == 'mac' && github.event.inputs.build_mac == 'true') ||
|
||||
(matrix.name == 'linux' && github.event.inputs.build_linux == 'true')
|
||||
)
|
||||
)
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: windows
|
||||
os: windows-latest
|
||||
node: 22
|
||||
python: "3.12"
|
||||
release_artifacts: "dist/*-win-installer.exe,dist/*-win-portable.exe"
|
||||
- name: mac
|
||||
os: macos-13
|
||||
node: 18
|
||||
python: "3.11"
|
||||
release_artifacts: "dist/*-mac.dmg"
|
||||
- name: linux
|
||||
os: ubuntu-latest
|
||||
node: 22
|
||||
python: "3.12"
|
||||
release_artifacts: "dist/*-linux.AppImage,dist/*-linux.deb,python-dist/*.whl"
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@f1f314fca9dfce2769ece7d933488f076716723e # v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Install Poetry
|
||||
run: python -m pip install --upgrade pip poetry
|
||||
|
||||
- name: Sync versions
|
||||
run: python scripts/sync_version.py
|
||||
|
||||
- name: Install Python Deps
|
||||
run: python -m poetry install
|
||||
|
||||
- name: Install NodeJS Deps
|
||||
run: npm install
|
||||
|
||||
- name: Prepare frontend directory
|
||||
run: python scripts/prepare_frontend_dir.py
|
||||
|
||||
- name: Download frontend artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: frontend-build
|
||||
path: meshchatx/public
|
||||
|
||||
- name: Install patchelf
|
||||
if: matrix.name == 'linux'
|
||||
run: sudo apt-get update && sudo apt-get install -y patchelf
|
||||
|
||||
- name: Install Poetry
|
||||
run: python -m pip install --upgrade pip poetry
|
||||
|
||||
- name: Sync versions
|
||||
run: python scripts/sync_version.py
|
||||
|
||||
- name: Install Python Deps
|
||||
run: python -m poetry install
|
||||
|
||||
- name: Build Python wheel
|
||||
if: matrix.name == 'linux'
|
||||
run: |
|
||||
python -m poetry build -f wheel
|
||||
mkdir -p python-dist
|
||||
mv dist/*.whl python-dist/
|
||||
rm -rf dist
|
||||
|
||||
- name: Install NodeJS Deps
|
||||
run: npm install
|
||||
|
||||
- name: Build Electron App
|
||||
run: npm run dist
|
||||
run: npm run dist-prebuilt
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1
|
||||
with:
|
||||
draft: true
|
||||
@@ -171,7 +158,7 @@ jobs:
|
||||
replacesArtifacts: true
|
||||
omitDraftDuringUpdate: true
|
||||
omitNameDuringUpdate: true
|
||||
artifacts: "dist/*-linux.AppImage,dist/*-linux.deb,python-dist/*.whl"
|
||||
artifacts: ${{ matrix.release_artifacts }}
|
||||
|
||||
build_docker:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
15
Dockerfile
15
Dockerfile
@@ -10,9 +10,8 @@ FROM node:${NODE_VERSION}-alpine@${NODE_ALPINE_SHA256} AS build-frontend
|
||||
WORKDIR /src
|
||||
|
||||
# Copy required source files
|
||||
COPY *.json .
|
||||
COPY *.js .
|
||||
COPY src/frontend ./src/frontend
|
||||
COPY package*.json vite.config.js ./
|
||||
COPY meshchatx ./meshchatx
|
||||
|
||||
# Install NodeJS deps, exluding electron
|
||||
RUN npm install --omit=dev && \
|
||||
@@ -34,12 +33,10 @@ RUN apk add --no-cache --virtual .build-deps \
|
||||
apk del .build-deps
|
||||
|
||||
# Copy prebuilt frontend
|
||||
COPY --from=build-frontend /src/public public
|
||||
COPY --from=build-frontend /src/meshchatx/public meshchatx/public
|
||||
|
||||
# Copy other required source files
|
||||
COPY *.py .
|
||||
COPY src/__init__.py ./src/__init__.py
|
||||
COPY src/backend ./src/backend
|
||||
COPY *.json .
|
||||
COPY meshchatx ./meshchatx
|
||||
COPY pyproject.toml poetry.lock ./
|
||||
|
||||
CMD ["python", "meshchat.py", "--host=0.0.0.0", "--reticulum-config-dir=/config/.reticulum", "--storage-dir=/config/.meshchat", "--headless"]
|
||||
CMD ["python", "-m", "meshchatx.meshchat", "--host=0.0.0.0", "--reticulum-config-dir=/config/.reticulum", "--storage-dir=/config/.meshchat", "--headless"]
|
||||
|
||||
1
Makefile
1
Makefile
@@ -39,6 +39,7 @@ clean:
|
||||
rm -rf build
|
||||
rm -rf dist
|
||||
rm -rf python-dist
|
||||
rm -rf meshchatx/public
|
||||
|
||||
sync-version:
|
||||
$(PYTHON) scripts/sync_version.py
|
||||
|
||||
@@ -49,20 +49,19 @@ def get_file_path(filename):
|
||||
datadir = os.path.dirname(sys.executable)
|
||||
return os.path.join(datadir, filename)
|
||||
|
||||
# Running from source or an installed wheel: assets live inside the meshchatx package
|
||||
# Assets live inside the meshchatx package when installed from a wheel
|
||||
package_dir = os.path.dirname(__file__)
|
||||
test_path = os.path.join(package_dir, filename)
|
||||
if os.path.exists(test_path):
|
||||
return test_path
|
||||
package_path = os.path.join(package_dir, filename)
|
||||
if os.path.exists(package_path):
|
||||
return package_path
|
||||
|
||||
# Fall back to repo root when running directly from the source tree
|
||||
# When running from the repository, fall back to the project root
|
||||
repo_root = os.path.dirname(package_dir)
|
||||
repo_path = os.path.join(repo_root, filename)
|
||||
if os.path.exists(repo_path):
|
||||
return repo_path
|
||||
|
||||
# Return the package path even if it does not exist so callers raise a clear error
|
||||
return test_path
|
||||
return package_path
|
||||
|
||||
|
||||
class ReticulumMeshChat:
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"build": "npm run build-frontend && npm run build-backend",
|
||||
"electron-postinstall": "electron-builder install-app-deps",
|
||||
"electron": "npm run electron-postinstall && npm run build && electron .",
|
||||
"dist": "npm run electron-postinstall && npm run build && electron-builder --publish=never"
|
||||
"dist": "npm run electron-postinstall && npm run build && electron-builder --publish=never",
|
||||
"dist-prebuilt": "npm run electron-postinstall && npm run build-backend && electron-builder --publish=never"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
11
scripts/prepare_frontend_dir.py
Normal file
11
scripts/prepare_frontend_dir.py
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
|
⚠️ Potential issue | 🟡 Minor Make the file executable or remove the shebang. The shebang is present but the file is not executable. Based on static analysis hints, run: Or remove the shebang if the script is only intended to be invoked via 🧰 Tools🪛 Ruff (0.14.6)1-1: Shebang is present but file is not executable (EXE001) 🤖 Prompt for AI Agents_⚠️ Potential issue_ | _🟡 Minor_
**Make the file executable or remove the shebang.**
The shebang is present but the file is not executable.
Based on static analysis hints, run:
```shell
chmod +x scripts/prepare_frontend_dir.py
```
Or remove the shebang if the script is only intended to be invoked via `python scripts/prepare_frontend_dir.py`.
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 Ruff (0.14.6)</summary>
1-1: Shebang is present but file is not executable
(EXE001)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
```
In scripts/prepare_frontend_dir.py around line 1, the file contains a shebang
but is not executable; either make the file executable by running chmod +x
scripts/prepare_frontend_dir.py so it can be run directly, or remove the shebang
line if you intend to always invoke it via the python interpreter (e.g., python
scripts/prepare_frontend_dir.py); apply one of these two changes and update any
relevant documentation/CI that assumes direct execution.
```
</details>
<!-- This is an auto-generated comment by CodeRabbit -->
✅ Addressed in commits ac839df to c98131f
🛠️ Refactor suggestion | 🟠 Major Add safety checks before removing the directory. The script unconditionally removes the target directory without validation. If the Consider adding basic safety checks: _🛠️ Refactor suggestion_ | _🟠 Major_
**Add safety checks before removing the directory.**
The script unconditionally removes the target directory without validation. If the `TARGET` path is misconfigured or if there's a symlink, this could lead to unintended data loss.
Consider adding basic safety checks:
```diff
+# Sanity check: ensure we're in the project root
+if not Path("pyproject.toml").exists():
+ raise RuntimeError("Must run from project root")
+
if TARGET.exists():
+ # Additional safety: verify it's a directory, not a symlink
+ if TARGET.is_symlink():
+ raise RuntimeError(f"{TARGET} is a symlink, refusing to remove")
shutil.rmtree(TARGET)
```
<!-- This is an auto-generated comment by CodeRabbit -->
✅ Addressed in commits ac839df to c98131f
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
TARGET = Path("meshchatx") / "public"
|
||||
|
||||
if TARGET.exists():
|
||||
shutil.rmtree(TARGET)
|
||||
|
||||
TARGET.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -28,8 +28,7 @@ print(f'meshchat module location: {meshchat.__file__}')
|
||||
|
||||
# Check if public directory exists
|
||||
meshchat_dir = os.path.dirname(meshchat.__file__)
|
||||
package_dir = os.path.dirname(os.path.dirname(meshchat_dir))
|
||||
public_path = os.path.join(package_dir, 'public')
|
||||
public_path = os.path.join(meshchat_dir, 'public')
|
||||
print(f'Checking for public at: {public_path}')
|
||||
print(f'Exists: {os.path.exists(public_path)}')
|
||||
|
||||
@@ -45,7 +44,7 @@ if os.path.exists(test_path):
|
||||
else:
|
||||
print('WARNING: public directory not found!')
|
||||
print('Checking parent directories...')
|
||||
current = package_dir
|
||||
current = meshchat_dir
|
||||
for i in range(3):
|
||||
test = os.path.join(current, 'public')
|
||||
print(f' {test}: {os.path.exists(test)}')
|
||||
|
||||
@@ -14,8 +14,8 @@ export default {
|
||||
|
||||
build: {
|
||||
|
||||
// we want to compile vite app to /public which is bundled and served by the python executable
|
||||
outDir: path.join(__dirname, "public"),
|
||||
// we want to compile vite app to meshchatx/public which is bundled and served by the python executable
|
||||
outDir: path.join(__dirname, "meshchatx", "public"),
|
||||
emptyOutDir: true,
|
||||
|
||||
rollupOptions: {
|
||||
|
||||
Reference in New Issue
Block a user
⚠️ Potential issue | 🔴 Critical
Fix shell syntax error in SHA256 checksum generation script.
The for loop at line 226 has invalid shell syntax:
2>/dev/nullcannot be placed after the glob pattern list in a for statement. This causes shellcheck to fail parsing (SC1058, SC1072, SC1073). Since the conditionalif [ -f "$file" ]already handles non-matching globs, the redirection is unnecessary.Apply this diff to fix the syntax error:
🧰 Tools
🪛 actionlint (1.7.9)
221-221: shellcheck reported issue in this script: SC1058:error:5:49: Expected 'do'
(shellcheck)
221-221: shellcheck reported issue in this script: SC1072:error:5:50: Fix any mentioned problems and try again
(shellcheck)
221-221: shellcheck reported issue in this script: SC1073:error:5:1: Couldn't parse this for loop. Fix to allow more checks
(shellcheck)
🤖 Prompt for AI Agents