summaryrefslogtreecommitdiffstats
path: root/packaging/win/meshbay-node.spec
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-14 22:20:15 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-14 22:20:15 +0200
commit422647e7898b8df67cd11f8fb060aec23dec84aa (patch)
tree7ecca0e8df1bc8a7d26cf4b471bd44906dd9cfd1 /packaging/win/meshbay-node.spec
parent28c88908b88c58cba4de08710f6bb268ede02d57 (diff)
downloadmeshbay-422647e7898b8df67cd11f8fb060aec23dec84aa.tar.gz
feat(cli): meshbay-cli, a command-line client for members
Signs in to the hub, lists the account's groups and their folders, and downloads and uploads files directly with each group's node, end-to-end encrypted. With no argument it opens a two-pane interactive mode (Textual). Session and device keys are kept encrypted under the system's key storage, or a 0600 key file where there is none; node keys are pinned at first contact; a new machine links as a device. Packaged on its own on Linux (deb and rpm, on meshbay-common's venv, with a man page generated from the parser) and frozen next to meshbay-node in the full Windows installer, not the light one, with a self-test the build runs. client/keys.py ports keyderive.js and is LGPL like it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packaging/win/meshbay-node.spec')
-rw-r--r--packaging/win/meshbay-node.spec127
1 files changed, 110 insertions, 17 deletions
diff --git a/packaging/win/meshbay-node.spec b/packaging/win/meshbay-node.spec
index a1173a2..8a6e384 100644
--- a/packaging/win/meshbay-node.spec
+++ b/packaging/win/meshbay-node.spec
@@ -1,6 +1,8 @@
-# PyInstaller spec for the bundled Windows node daemon.
+# PyInstaller spec for the bundled Windows node daemon, and the command-line
+# client beside it.
#
-# Output: dist/meshbay-node/meshbay-node.exe (--onedir, relocatable)
+# Output: dist/meshbay-node/meshbay-node.exe, meshbay-nodew.exe and
+# meshbay-cli.exe (--onedir, relocatable, one _internal\ for the three)
# Consumed by: packaging/win/build-node-runtime.ps1, which moves the tree to
# packages/meshbay-client/node-runtime/ for electron-builder to carry as an
# extraResource.
@@ -35,21 +37,27 @@ _vtuple = tuple(
int(p) for p in (_ver.split("+")[0].split(".") + ["0", "0", "0", "0"])[:4]
)
-_version_info = VSVersionInfo(
- ffi=FixedFileInfo(filevers=_vtuple, prodvers=_vtuple),
- kids=[
- StringFileInfo([StringTable("040904B0", [
- StringStruct("CompanyName", "MeshBay"),
- StringStruct("FileDescription", "MeshBay Node"),
- StringStruct("FileVersion", _ver),
- StringStruct("InternalName", "meshbay-node"),
- StringStruct("OriginalFilename", "meshbay-node.exe"),
- StringStruct("ProductName", "MeshBay Node"),
- StringStruct("ProductVersion", _ver),
- ])]),
- VarFileInfo([VarStruct("Translation", [0x0409, 1200])]),
- ],
-)
+
+
+def _version_resource(name: str, description: str) -> VSVersionInfo:
+ return VSVersionInfo(
+ ffi=FixedFileInfo(filevers=_vtuple, prodvers=_vtuple),
+ kids=[
+ StringFileInfo([StringTable("040904B0", [
+ StringStruct("CompanyName", "MeshBay"),
+ StringStruct("FileDescription", description),
+ StringStruct("FileVersion", _ver),
+ StringStruct("InternalName", name),
+ StringStruct("OriginalFilename", f"{name}.exe"),
+ StringStruct("ProductName", description),
+ StringStruct("ProductVersion", _ver),
+ ])]),
+ VarFileInfo([VarStruct("Translation", [0x0409, 1200])]),
+ ],
+ )
+
+
+_version_info = _version_resource("meshbay-node", "MeshBay Node")
# Packages taken in full: data files + shared libs + every submodule.
COLLECT_ALL = [
@@ -177,11 +185,96 @@ exe_windowless = EXE(
icon="../../packages/meshbay-client/build/icon.ico",
version=_version_info,
)
+
+# --- The command-line client ---------------------------------------------------
+# Its own analysis: another entry point, and packages the daemon does not use
+# (Textual loads its widgets lazily, Rich its Unicode tables by version,
+# Pygments its lexers by name, keyring its backends through entry points —
+# hence keyring's metadata). What both import (aiortc, av, cryptography, ...)
+# lands once in _internal\: COLLECT keeps one copy of a file the two share.
+CLI_COLLECT_ALL = [
+ "meshbay_cli",
+ "meshbay_common",
+ "aiortc",
+ "aioice",
+ "av",
+ "cryptography",
+ "pylibsrtp",
+ "pyee",
+ "google_crc32c",
+ "httpx",
+ "httpcore",
+ "h11",
+ "anyio",
+ "dns",
+ "argon2",
+ "_argon2_cffi_bindings",
+ "keyring",
+ "win32ctypes",
+ "textual",
+ "rich",
+ "pygments",
+ "markdown_it",
+ "mdit_py_plugins",
+ "linkify_it",
+ "platformdirs",
+ "blake3",
+ "msgpack",
+ "jwt",
+ "tzdata",
+]
+CLI_COPY_META = ["meshbay-cli", "meshbay-common", "keyring", "textual"]
+
+cli_datas, cli_binaries, cli_hidden = [], [], []
+for pkg in CLI_COLLECT_ALL:
+ d, b, h = collect_all(pkg)
+ cli_datas += d
+ cli_binaries += b
+ cli_hidden += h
+for dist in CLI_COPY_META:
+ cli_datas += copy_metadata(dist)
+
+cli_a = Analysis(
+ ["cli-entry.py"],
+ pathex=[],
+ binaries=cli_binaries,
+ datas=cli_datas,
+ hiddenimports=cli_hidden,
+ hookspath=[],
+ hooksconfig={},
+ runtime_hooks=[],
+ excludes=["tkinter", "pytest", "ruff", "IPython", "meshbay_node", "meshbay_hub"],
+ noarchive=False,
+)
+cli_pyz = PYZ(cli_a.pure)
+exe_cli = EXE(
+ cli_pyz,
+ cli_a.scripts,
+ [],
+ exclude_binaries=True,
+ name="meshbay-cli",
+ debug=False,
+ bootloader_ignore_signals=False,
+ strip=False,
+ upx=False,
+ console=True,
+ disable_windowed_traceback=False,
+ argv_emulation=False,
+ target_arch=None,
+ codesign_identity=None,
+ entitlements_file=None,
+ icon="../../packages/meshbay-client/build/icon.ico",
+ version=_version_resource("meshbay-cli", "MeshBay command-line client"),
+)
+
coll = COLLECT(
exe,
exe_windowless,
+ exe_cli,
a.binaries,
a.datas,
+ cli_a.binaries,
+ cli_a.datas,
strip=False,
upx=False,
upx_exclude=[],