Skip to content
Open
13 changes: 8 additions & 5 deletions NOTIFICATION_CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,14 @@ app:
### Testing Configuration

#### Dry Run Mode
Use dry run to test notifications without sending:
```bash
# This will test notification configuration without actually sending
docker exec -it icloud /bin/sh -c "su-exec abc python src/main.py --dry-run"
```
Note: ``--dry-run`` (added in this PR / feat/dry-run) is a sync-side
pre-flight that authenticates, summarises what *would* be synced, and
exits without writing files or sending notifications. It is NOT a
notification-test mode — notifications are intentionally suppressed
in dry-run.

To test notification delivery, use the manual-testing helpers below
(``notify._send_discord_no_throttle`` etc.) rather than ``--dry-run``.

#### Manual Testing
Test individual notification services:
Expand Down
50 changes: 49 additions & 1 deletion src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,55 @@

__author__ = "Mandar Patil (mandarons@pm.me)"

import argparse

from src import sync

if __name__ == "__main__":
sync.sync()
parser = argparse.ArgumentParser(
prog="icloud-docker",
description="iCloud Drive + Photos backup loop. See config.yaml for runtime settings.",
)
parser.add_argument(
"--dry-run",
action="store_true",
Comment thread
epheterson marked this conversation as resolved.
help=(
"Authenticate, summarise what would be synced, then exit "
"without downloading or modifying any files. Useful for "
"verifying credentials + mount paths + config before the "
"real sync loop is allowed to run."
),
)
parser.add_argument(
"--check-files",
type=int,
default=None,
metavar="N",
help=(
"Only meaningful with --dry-run. Walks N photos per library "
"and reports per-library counts of would_skip / size_mismatch "
"/ not_found / error against your on-disk tree. Use this "
"BEFORE a real sync to confirm a boredazfcuk → mandarons (or "
"any cross-tool) migration will recognise existing files "
"instead of re-downloading them. Pass 0 to walk every photo "
"(slow on large libraries — recommend 50–200 first)."
),
)
args = parser.parse_args()

# Validate the --check-files / --dry-run combination before handing off
# to sync.sync(). Without these guards, `--check-files 10` (no
# --dry-run) starts the normal sync loop and silently ignores the
# flag, and `--check-files -1` is treated as "walk everything" by
# the migration walkers (since `if sample > 0` is the cap-check) —
# both of which trip up users expecting fail-fast feedback.
if args.check_files is not None:
if not args.dry_run:
parser.error("--check-files requires --dry-run")
if args.check_files < 0:
parser.error(
"--check-files must be a non-negative integer "
"(0 means walk everything, N > 0 caps the walk at N)",
)

sync.sync(dry_run=args.dry_run, check_files=args.check_files)
Comment thread
epheterson marked this conversation as resolved.
Loading
Loading