From 50832d745a2a254be7651df24d82e86cf1c62a46 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Wed, 28 Jan 2026 15:30:00 +0100 Subject: [PATCH 1/4] binary build: install cockpit,s3,sftp extras --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07d330243d..856e3aa3e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -267,13 +267,13 @@ jobs: - name: Install borgbackup run: | if [[ "$TOXENV" == *"llfuse"* ]]; then - pip install -ve ".[llfuse]" + pip install -ve ".[llfuse,cockpit,s3,sftp]" elif [[ "$TOXENV" == *"pyfuse3"* ]]; then - pip install -ve ".[pyfuse3]" + pip install -ve ".[pyfuse3,cockpit,s3,sftp]" elif [[ "$TOXENV" == *"mfusepy"* ]]; then - pip install -ve ".[mfusepy]" + pip install -ve ".[mfusepy,cockpit,s3,sftp]" else - pip install -ve . + pip install -ve ".[cockpit,s3,sftp]" fi - name: Build Borg fat binaries (${{ matrix.binary }}) @@ -425,7 +425,7 @@ jobs: pip -V python -m pip install --upgrade pip wheel pip install -r requirements.d/development.txt - pip install -e ".[mfusepy]" + pip install -e ".[mfusepy,cockpit,s3,sftp]" tox -e py311-mfusepy if [[ "${{ matrix.do_binaries }}" == "true" && "${{ startsWith(github.ref, 'refs/tags/') }}" == "true" ]]; then @@ -582,7 +582,7 @@ jobs: run: | # build borg.exe . env/bin/activate - pip install -e . + pip install -e ".[cockpit,s3,sftp]" mkdir -p dist/binary pyinstaller -y --clean --distpath=dist/binary scripts/borg.exe.spec # build sdist and wheel in dist/... From f2f2565fa16c01a1c0c4e45e77ef2d115f296839 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Wed, 28 Jan 2026 20:13:18 +0100 Subject: [PATCH 2/4] CI: add borg.exe to PATH --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 856e3aa3e8..d8602c6d2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -295,6 +295,8 @@ jobs: ./borg-dir/borg.exe -V tar czf borg.tgz borg-dir popd + # Ensure locally built binary in ./dist/binary/borg-dir is found during tests + export PATH="$GITHUB_WORKSPACE/dist/binary/borg-dir:$PATH" echo "borg.exe binary in PATH" borg.exe -V From 10ac3facdce49336ad5b97997523e35b36fd547d Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Wed, 28 Jan 2026 21:58:50 +0100 Subject: [PATCH 3/4] pyinstaller: add tcss file to spec --- scripts/borg.exe.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/borg.exe.spec b/scripts/borg.exe.spec index 4e2e717dfc..18163fbc1e 100644 --- a/scripts/borg.exe.spec +++ b/scripts/borg.exe.spec @@ -21,6 +21,7 @@ a = Analysis([os.path.join(basepath, 'src', 'borg', '__main__.py'), ], binaries=[], datas=[ (os.path.join(basepath, 'src', 'borg', 'paperkey.html'), 'borg'), + (os.path.join(basepath, 'src', 'borg', 'cockpit', 'cockpit.tcss'), os.path.join('borg', 'cockpit')), ], hiddenimports=hiddenimports, hookspath=[], From a0bace0ad360aec1a5b8cabb922c4f7824cd26e6 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 29 Jan 2026 06:14:25 +0100 Subject: [PATCH 4/4] cockpit: start the Borg runner after all widgets are mounted --- src/borg/cockpit/app.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/borg/cockpit/app.py b/src/borg/cockpit/app.py index 7d68961825..e1ed1419ed 100644 --- a/src/borg/cockpit/app.py +++ b/src/borg/cockpit/app.py @@ -53,22 +53,27 @@ def on_load(self) -> None: def on_mount(self) -> None: """Initialize components.""" - from .runner import BorgRunner - self.query_one("#logo").styles.animate("opacity", 1, duration=1) self.query_one("#slogan").styles.animate("opacity", 1, duration=1) - self.start_time = time.monotonic() - self.process_running = True - args = getattr(self, "borg_args", ["--version"]) # Default to safe command if none passed - self.runner = BorgRunner(args, self.handle_log_event) - self.runner_task = asyncio.create_task(self.runner.start()) + # Delay runner start until after widgets are fully mounted + self.call_after_refresh(self.start_runner) + + def start_runner(self) -> None: + """Start the Borg runner after all widgets are mounted.""" + from .runner import BorgRunner # Speed tracking self.total_lines_processed = 0 self.last_lines_processed = 0 self.speed_timer = self.set_interval(1.0, self.compute_speed) + self.start_time = time.monotonic() + self.process_running = True + args = getattr(self, "borg_args", ["--version"]) # Default to safe command if none passed + self.runner = BorgRunner(args, self.handle_log_event) + self.runner_task = asyncio.create_task(self.runner.start()) + def compute_speed(self) -> None: """Calculate and update speed (lines per second).""" current_lines = self.total_lines_processed