Separate Borg 1.x legacy code into borg.legacy package
- Dominant language
- Python
- Stars
- 13.7k
- Forks
- 875
- Avg merge
- 11h 15m
- Merged PRs (30d)
- 192
Description
### Problem
Borg 2.x code is tangled with 1.x legacy code across ~15 files. `manifest.py` has 15+ `if not self.legacy:` branches in the `Archives` class alone. `legacyrepository.py` and `legacyremote.py` already have "legacy" in the name but sit at the package root. `src/borg/legacy/` exists but is empty.
### What this does
Move the bulk of 1.x code into `src/borg/legacy/`. The goal is to eliminate almost every last `# legacy` comment , some one-liner branches are worse to extract than to keep. But the major classes and branch-heavy code (LegacyRepository, LegacyRemoteRepository, RepoObj1, the 4 legacy key types, the entire Archives legacy path) all move out.
After this:
- v2 core modules are mostly free of legacy code
- `borg transfer --from-borg1` keeps working via `borg.legacy`
- Dropping v1 support later = delete `borg.legacy` + remove a handful of scattered one-liners
### Plan (7 phases)
Each phase is a separate PR.
| Phase | What happens |
|---|---|
| 1 | `git mv` of `legacyrepository.py` + `legacyremote.py` into `legacy/` |
| 2 | Extract `RepoObj1`, move legacy key types (`KeyfileKey`, `RepoKey`, etc.) into `legacy/` with imported base classes |
| 3 | Extract `LegacyArchives` from `Archives`, remove all `self.legacy` branches in `manifest.py` |
| 4 | Switch `remote.py` to lazy-import `LegacyRepository` only inside `RepositoryServer.open()` |
| 5 | `git mv` of `upgrade.py` into `legacy/` |
| 6 | Inventory remaining scattered legacy markers, split what can be split, document what stays |
| 7 | Audit and expand unit test coverage for the borg1 compatibility path: `borg transfer --from-borg1` and the upgrade internals (`UpgraderFrom12To20`, `Pbkdf2FileMixin`, hardlink helpers, `NSIndex1`); end-to-end transfer tests exist but unit coverage of the upgrade internals is thin |
done:
- #9559 legacy: move LegacyRepository, LegacyRemoteRepository, RepoObj1 into borg.legacy package
- #9600 legacy: move legacy AES-CTR key classes into borg.legacy.crypto
- #9644 legacy: extract LegacyArchives into legacy/archives.py, add ArchivesInterface
- #9648 testsuite: add Archives and LegacyArchives unit tests
- #9650 legacy: lazy-import legacy classes inside v1 branches only
- #9655 legacy: move upgrade.py into borg.legacy
- #9664 legacy: move AES, hardlink helpers, NSIndex1, Pbkdf2FileMixin into borg.legacy
- #9668 legacy: move pbkdf2 static method from FlexiKey to Pbkdf2FileMixin
- #9675 testsuite: add UpgraderFrom12To20 unit tests
pending:
- #9685 testsuite: add borg1_hardlink_master/slave/hardlinkable unit tests
- #9686 testsuite: add Pbkdf2FileMixin unit tests
### Target structure
```
src/borg/legacy/
├── __init__.py
├── repository.py <- LegacyRepository
├── remote.py <- LegacyRemoteRepository
├── repoobj.py <- RepoObj1
├── archives.py <- LegacyArchives
├── upgrade.py <- UpgraderFrom12To20, UpgraderNoOp
├── helpers.py <- borg1 hardlink helpers
├── hashindex.py <- NSIndex1
└── crypto/
├── __init__.py
├── key.py <- legacy AES-CTR key types (imports bases from crypto/key.py)
└── low_level.pyx <- AES-256-CTR Cython extension
```
Some scattered one-liners can't be moved like `version == 1` checks in `archive.py`, legacy exit codes in `helpers/errors.py`, `repository.version == 1` in `cache.py`. As extracting those would mean duplicating entire methods for one branch. They go away when v1 support is dropped.
### Constraints
- `borg transfer --from-borg1` must keep working after every phase
- `borg serve` must handle both v1 and v2 clients (lazy import in `RepositoryServer.open()`)
- No stubs at old paths, using `git mv` for whole-file moves (per feedback on #9559). Re-exports only where the original file still has v2 code (`repoobj.py`)
### Testing
```bash
python -m pytest src/borg/testsuite/ -x -v
python -m pytest src/borg/testsuite/ -x -v -k "transfer"
```
Contributor guide
Assessment
This issue has not been assessed yet.