Add CLAUDE.md
This commit is contained in:
1 parent
22757ece58
commit
bfcb81e90b
2 files changed
+135
No files matched your search
@@ -0,0 +1,134 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working
|
||||
with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
cura-te-ipsum is a space-efficient incremental backup utility for Linux and
|
||||
macOS. It creates hardlink-based snapshots similar to Time Machine/rsnapshot,
|
||||
where unchanged files share inodes between backups to minimize storage.
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Environment Setup
|
||||
Project uses `uv` for Python version and dependency management:
|
||||
```bash
|
||||
uv sync --all-extras --dev
|
||||
```
|
||||
|
||||
### Testing
|
||||
```bash
|
||||
uv run pytest # run all tests
|
||||
uv run pytest -v # verbose output
|
||||
uv run pytest tests/test_fs.py # run specific test file
|
||||
```
|
||||
|
||||
### Installation
|
||||
```bash
|
||||
uv pip install . # install from source
|
||||
```
|
||||
|
||||
### Running the Tool
|
||||
```bash
|
||||
cura-te-ipsum -b /path/to/backups /path/to/source
|
||||
cura-te-ipsum -b /backups /src1 /src2 --dry-run --verbose
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Modules
|
||||
|
||||
**curateipsum/backup.py**: Main backup orchestration
|
||||
- `initiate_backup()`: Main entry point - coordinates hardlinking from
|
||||
previous backup and rsync from sources
|
||||
- `cleanup_old_backups()`: Implements grandfather-father-son retention
|
||||
(daily/weekly/monthly/yearly) with configurable thresholds
|
||||
- Lock management (`set_backups_lock`, `release_backups_lock`): Prevents
|
||||
concurrent backups using PID-based lock file
|
||||
- Backup markers (`set_backup_marker`, `_is_backup`): Tracks completed vs
|
||||
incomplete backups
|
||||
|
||||
**curateipsum/fs.py**: Low-level filesystem operations
|
||||
- `rsync()`: Pure Python rsync implementation - syncs source to destination
|
||||
with delete support
|
||||
- `rsync_ext()`: Wrapper for external rsync command
|
||||
- `hardlink_dir()`: Recursively hardlinks entire directory tree (Python or
|
||||
external cp)
|
||||
- `nest_hardlink()`: Hardlinks individual files to `.backup_delta` directory
|
||||
preserving structure
|
||||
- `scantree()`: Recursive directory iterator
|
||||
- `copy_direntry()`, `update_direntry()`, `rm_direntry()`: DirEntry
|
||||
manipulation utilities
|
||||
|
||||
**curateipsum/cli.py**: Command-line interface
|
||||
- Argument parsing and validation
|
||||
- Platform check (Linux/macOS only)
|
||||
- Logging setup and execution flow
|
||||
|
||||
### Key Data Structures
|
||||
|
||||
**PseudoDirEntry**: Emulates os.DirEntry for paths that don't exist yet or
|
||||
for consistency in handling both real and pseudo entries. Used extensively
|
||||
in backup operations.
|
||||
|
||||
**Actions enum**: Tracks filesystem changes during rsync (NOTHING, DELETE,
|
||||
REWRITE, UPDATE_TIME, UPDATE_PERM, UPDATE_OWNER, CREATE, ERROR).
|
||||
|
||||
### Backup Process Flow
|
||||
|
||||
1. Acquire lock file (`.backups_lock`) with PID
|
||||
2. Clean up old backups per retention policy
|
||||
3. Hardlink entire previous backup directory to new timestamped directory
|
||||
4. Remove backup markers from hardlinked copy
|
||||
5. Delete `.backup_delta` directory from hardlinked copy
|
||||
6. Rsync each source to new backup (overwrites changed files, breaking
|
||||
hardlinks)
|
||||
7. For each changed file, hardlink to `.backup_delta` directory
|
||||
8. Set backup marker (`.backup_finished_TIMESTAMP`)
|
||||
9. Release lock
|
||||
|
||||
### Important Implementation Details
|
||||
|
||||
**Retention policy**: `cleanup_old_backups()` implements threshold-based
|
||||
retention where each threshold is inclusive. For example, `keep_weekly=1`
|
||||
on Thursday keeps one backup from current week AND one from previous week.
|
||||
|
||||
**Delta tracking**: Changed files are hardlinked to `.backup_delta/` within
|
||||
each backup to track what changed in that specific backup snapshot.
|
||||
|
||||
**Hardlink breakage**: When rsync overwrites a hardlinked file, it breaks
|
||||
the hardlink, creating a new inode. This is how changed files get tracked
|
||||
while unchanged files continue sharing inodes.
|
||||
|
||||
**External tools**: Can use external rsync (--external-rsync) or GNU cp/gcp
|
||||
for hardlinking (--external-hardlink) instead of Python implementations.
|
||||
macOS requires `gcp` (GNU cp) for external hardlinking.
|
||||
|
||||
**Dry run behavior**: Creates backup directory and performs operations but
|
||||
removes directory at end without setting backup marker.
|
||||
|
||||
## Platform Specifics
|
||||
|
||||
- Linux: Uses standard `cp` command
|
||||
- macOS: Requires `gcp` (GNU coreutils) for external hardlinking
|
||||
- Only these platforms are supported (checked in cli.py)
|
||||
|
||||
## Testing
|
||||
|
||||
Tests use unittest.TestCase with mock.patch for datetime manipulation.
|
||||
Focus is on backup cleanup logic with various retention scenarios.
|
||||
Tests create temporary backup directories and verify correct backups are
|
||||
kept/removed.
|
||||
|
||||
## Version Management
|
||||
|
||||
Version is automatically derived from git tags using `setuptools_scm`.
|
||||
The version file `curateipsum/_version.py` is auto-generated during build
|
||||
and should not be committed to version control.
|
||||
|
||||
To create a new release, tag the commit:
|
||||
```bash
|
||||
git tag -a v0.0.4 -m "Release 0.0.4"
|
||||
git push origin v0.0.4
|
||||
```
|
||||
Reference in new issue
Block a user