holocron-sync 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ mirror-data/
2
+ .venv/
3
+ .git/
4
+ __pycache__/
5
+ .env
6
+ .DS_Store
7
+ *.pyc
@@ -0,0 +1,31 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.12"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v3
21
+ with:
22
+ version: "0.4.15"
23
+
24
+ - name: Set up Python ${{ matrix.python-version }}
25
+ run: uv python install ${{ matrix.python-version }}
26
+
27
+ - name: Install dependencies
28
+ run: uv sync --all-extras --dev
29
+
30
+ - name: Run tests
31
+ run: uv run pytest
@@ -0,0 +1,27 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ pypi-publish:
9
+ name: Upload to PyPI
10
+ runs-on: ubuntu-latest
11
+ environment:
12
+ name: pypi
13
+ url: https://pypi.org/p/holocron-sync
14
+ permissions:
15
+ id-token: write # IMPORTANT: this permission is mandatory for Trusted Publishing
16
+ steps:
17
+ - name: Checkout code
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v5
22
+
23
+ - name: Build package
24
+ run: uv build
25
+
26
+ - name: Publish to PyPI
27
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,61 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / Packaging
7
+ .Python
8
+ build/
9
+ develop-eggs/
10
+ dist/
11
+ downloads/
12
+ eggs/
13
+ .eggs/
14
+ lib/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ share/python-wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+ MANIFEST
25
+
26
+ # Virtual Environments
27
+ .env
28
+ .venv
29
+ env/
30
+ venv/
31
+ ENV/
32
+ env.bak/
33
+ venv.bak/
34
+
35
+ # Testing and Coverage
36
+ .coverage
37
+ .coverage.*
38
+ .cache
39
+ nosetests.xml
40
+ coverage.xml
41
+ *.cover
42
+ *.py,cover
43
+ .hypothesis/
44
+ .pytest_cache/
45
+ cover/
46
+
47
+ # G2G-Sync / Holocron specific
48
+ mirror-data/
49
+ *.git
50
+
51
+ # Environment Variables
52
+ .env
53
+
54
+ # MacOS
55
+ .DS_Store
56
+
57
+ # IDEs
58
+ .idea/
59
+ .vscode/
60
+ *.swp
61
+ *.swo
@@ -0,0 +1,22 @@
1
+ FROM python:3.12-alpine
2
+
3
+ # Install git (required for mirroring)
4
+ RUN apk add --no-cache git
5
+
6
+ WORKDIR /app
7
+
8
+ # Copy requirements first to leverage cache
9
+ COPY requirements.txt .
10
+ RUN pip install --no-cache-dir -r requirements.txt
11
+
12
+ # Copy source code
13
+ COPY src/ src/
14
+
15
+ # Create directory for mirror data
16
+ RUN mkdir -p mirror-data
17
+
18
+ # Default entrypoint
19
+ ENTRYPOINT ["python", "-m", "holocron"]
20
+
21
+ # Default command (can be overridden)
22
+ CMD ["--watch", "--interval", "60"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Wouter Bloeyaert
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.4
2
+ Name: holocron-sync
3
+ Version: 0.1.0
4
+ Summary: Holocron: The Ultimate Git Mirroring Tool
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.9
7
+ Requires-Dist: python-dotenv
8
+ Requires-Dist: requests>=2.28.0
9
+ Description-Content-Type: text/markdown
10
+
11
+ # Holocron
12
+ > **The "Ultimate" Git Mirroring Tool**
13
+
14
+ ```
15
+ /\
16
+ / \
17
+ / /\ \
18
+ / / \ \
19
+ / / \ \
20
+ /_/______\_\
21
+ \ \ / /
22
+ \ \ / /
23
+ \ \ / /
24
+ \ \/ /
25
+ \ /
26
+ \/
27
+ ```
28
+
29
+ **Holocron** is a powerful Python application designed to mirror your GitHub repositories to a local directory or a self-hosted GitLab instance. It supports parallel syncing, continuous watch mode, and local-only backups (no GitLab required).
30
+
31
+ ## Features
32
+ - **Parallel Syncing**: Sync multiple repositories concurrently for maximum speed.
33
+ - **Continuous Watch Mode**: Polls for changes and syncs only when necessary (smart redundancy checks).
34
+ - **Two-Way Mirroring**: Creates a bare mirror (`.git` folder) for safety AND an optional checkout for visibility.
35
+ - **Dockerized**: Runs as a lightweight container.
36
+ - **Backup Level**:
37
+ - Full: GitHub -> Local -> GitLab
38
+ - Backup-Only: GitHub -> Local (No GitLab token needed)
39
+
40
+ ## Quick Start
41
+
42
+ ### 1. Docker (Recommended)
43
+ ```bash
44
+ docker-compose up -d --build
45
+ ```
46
+ This starts Holocron in watch mode.
47
+
48
+ ### 2. Manual Run
49
+ ```bash
50
+ # Install dependencies
51
+ uv sync
52
+
53
+ # Run a one-time backup of all your repos locally (visible files)
54
+ export GITHUB_TOKEN=your_token
55
+ uv run python src/holocron.py --backup-only --checkout --concurrency 10
56
+ ```
57
+
58
+ ## Configuration
59
+ Holocron uses environment variables for secrets:
60
+
61
+ | Variable | Description | Required |
62
+ | :--- | :--- | :--- |
63
+ | `GITHUB_TOKEN` | Your GitHub Personal Access Token (repo scope) | **Yes** |
64
+ | `GITLAB_TOKEN` | Your GitLab Personal Access Token (api scope) | No (if `--backup-only`) |
65
+ | `GITLAB_API_URL` | URL to your GitLab API (default: `http://gitlab.local/api/v4`) | No |
66
+
67
+ ### Command Line Arguments
68
+ | Flag | Default | Description |
69
+ | :--- | :--- | :--- |
70
+ | `--watch` | False | Run continuously in a loop |
71
+ | `--interval` | 60 | Seconds to sleep between checks in watch mode |
72
+ | `--window` | 60 | Sync only repos pushed within the last N minutes |
73
+ | `--backup-only` | False | Mirror locally only, do not push to GitLab |
74
+ | `--checkout` | False | Create a visible working directory alongside the mirror |
75
+ | `--concurrency` | 5 | Number of parallel sync threads |
76
+ | `--storage` | `./mirror-data` | Directory to store repositories |
77
+ | `--dry-run` | False | Print what would happen without doing it |
78
+ | `--verbose` | False | Enable detailed debug logging |
79
+
80
+ ## Development
81
+ Run tests with coverage:
82
+ ```bash
83
+ uv run pytest --cov=src
84
+ ```
@@ -0,0 +1,74 @@
1
+ # Holocron
2
+ > **The "Ultimate" Git Mirroring Tool**
3
+
4
+ ```
5
+ /\
6
+ / \
7
+ / /\ \
8
+ / / \ \
9
+ / / \ \
10
+ /_/______\_\
11
+ \ \ / /
12
+ \ \ / /
13
+ \ \ / /
14
+ \ \/ /
15
+ \ /
16
+ \/
17
+ ```
18
+
19
+ **Holocron** is a powerful Python application designed to mirror your GitHub repositories to a local directory or a self-hosted GitLab instance. It supports parallel syncing, continuous watch mode, and local-only backups (no GitLab required).
20
+
21
+ ## Features
22
+ - **Parallel Syncing**: Sync multiple repositories concurrently for maximum speed.
23
+ - **Continuous Watch Mode**: Polls for changes and syncs only when necessary (smart redundancy checks).
24
+ - **Two-Way Mirroring**: Creates a bare mirror (`.git` folder) for safety AND an optional checkout for visibility.
25
+ - **Dockerized**: Runs as a lightweight container.
26
+ - **Backup Level**:
27
+ - Full: GitHub -> Local -> GitLab
28
+ - Backup-Only: GitHub -> Local (No GitLab token needed)
29
+
30
+ ## Quick Start
31
+
32
+ ### 1. Docker (Recommended)
33
+ ```bash
34
+ docker-compose up -d --build
35
+ ```
36
+ This starts Holocron in watch mode.
37
+
38
+ ### 2. Manual Run
39
+ ```bash
40
+ # Install dependencies
41
+ uv sync
42
+
43
+ # Run a one-time backup of all your repos locally (visible files)
44
+ export GITHUB_TOKEN=your_token
45
+ uv run python src/holocron.py --backup-only --checkout --concurrency 10
46
+ ```
47
+
48
+ ## Configuration
49
+ Holocron uses environment variables for secrets:
50
+
51
+ | Variable | Description | Required |
52
+ | :--- | :--- | :--- |
53
+ | `GITHUB_TOKEN` | Your GitHub Personal Access Token (repo scope) | **Yes** |
54
+ | `GITLAB_TOKEN` | Your GitLab Personal Access Token (api scope) | No (if `--backup-only`) |
55
+ | `GITLAB_API_URL` | URL to your GitLab API (default: `http://gitlab.local/api/v4`) | No |
56
+
57
+ ### Command Line Arguments
58
+ | Flag | Default | Description |
59
+ | :--- | :--- | :--- |
60
+ | `--watch` | False | Run continuously in a loop |
61
+ | `--interval` | 60 | Seconds to sleep between checks in watch mode |
62
+ | `--window` | 60 | Sync only repos pushed within the last N minutes |
63
+ | `--backup-only` | False | Mirror locally only, do not push to GitLab |
64
+ | `--checkout` | False | Create a visible working directory alongside the mirror |
65
+ | `--concurrency` | 5 | Number of parallel sync threads |
66
+ | `--storage` | `./mirror-data` | Directory to store repositories |
67
+ | `--dry-run` | False | Print what would happen without doing it |
68
+ | `--verbose` | False | Enable detailed debug logging |
69
+
70
+ ## Development
71
+ Run tests with coverage:
72
+ ```bash
73
+ uv run pytest --cov=src
74
+ ```
@@ -0,0 +1,178 @@
1
+ # AGENTS.md
2
+
3
+ ## 📌 Purpose
4
+
5
+ This document defines contribution standards for both humans and AI agents working in this repo.
6
+ It enforces **consistency, security, and maintainability** across the codebase.
7
+ Think of this as our **style guide + quality contract**.
8
+
9
+ ---
10
+
11
+ ## 🔐 Security
12
+
13
+ * Treat all inputs as untrusted — always validate and sanitize.
14
+ * Avoid unsafe patterns:
15
+
16
+ * Shell exec, `eval`, unverified deserialization, raw SQL.
17
+ * Enforce explicit schemas (Pydantic, Django models, Marshmallow).
18
+ * Never expose secrets, API keys, or tokens (zero-trust assumption).
19
+ * Run linters, type checks, and tests before merging.
20
+
21
+ ---
22
+
23
+ ## 🧱 Code Design Principles
24
+
25
+ * **Clarity > Cleverness**: prioritize readability over conciseness.
26
+ * **Small functions**: ≤ 20 lines (target 10–15).
27
+ * **Single responsibility**: each function/class does one thing well.
28
+ * **Explicit over implicit**:
29
+
30
+ * Avoid dense one-liners, hidden side effects, and tricky language features.
31
+ * Prefer explicit `if` over nested ternaries.
32
+ * Limit call chaining to max 2 steps.
33
+ * **DRY but not obsessed**: reuse logic, but don’t abstract prematurely.
34
+ * **Consistent naming**: descriptive, not abbreviated.
35
+ * **Remove dead code**: no commented-out blocks or unused imports.
36
+ * **Documentation at point of use**: comments explain *why*, not *what*.
37
+
38
+ **Django specifics**:
39
+
40
+ * Use `bulk_create`/`bulk_update` for efficiency.
41
+ * Always define `UPDATE_FIELDS` constants for updates.
42
+ * Wrap multi-step writes in transactions.
43
+ * Cache repeated upserts in memory during a run.
44
+
45
+ ---
46
+
47
+ ## 🧰 Helpers & Utilities
48
+
49
+ * Keep helpers **local** if only used once; mark them private (`_helper`).
50
+ * Extract to `api/utils/<purpose>.py` if reused.
51
+ * Avoid generic “misc” utils files.
52
+ * Public helpers: type hints + docstrings; side-effect free.
53
+ * Private helpers: `_parse_*`, `_build_*`, `_apply_*`.
54
+ * Migration rule: start local, extract only when reused or file > 300 lines.
55
+
56
+ ---
57
+
58
+ ## 🧩 Models
59
+
60
+ * **One file per model**: strict rule.
61
+
62
+ * Example:
63
+
64
+ * `api/models/ticker.py` → `Ticker`
65
+ * `api/models/exchange.py` → `Exchange`
66
+ * `api/models/job.py` → `Job`
67
+ * **Re-export** in `api/models/__init__.py`:
68
+
69
+ ```python
70
+ from .ticker import Ticker
71
+ from .exchange import Exchange
72
+ from .job import Job
73
+
74
+ __all__ = ["Ticker", "Exchange", "Job"]
75
+ ```
76
+ * No side effects in model files (signals, listeners go elsewhere).
77
+ * Admin config belongs in `admin.py`.
78
+ * Tests mirror model file structure.
79
+
80
+ ---
81
+
82
+ ## ✅ Testing
83
+
84
+ * Every new feature requires tests. **No exceptions.**
85
+ * Cover: CRUD, edge cases, abuse/misuse, success paths.
86
+ * Tests must be deterministic and fast (<1s per unit test).
87
+ * Use integration tests only when needed.
88
+ * Test naming: `test_<functionality>_<expected_behavior>`.
89
+ * Test location: `/tests/` mirroring code layout.
90
+
91
+ ---
92
+
93
+ ## 🧩 Extensibility
94
+
95
+ * No hardcoded credentials/config.
96
+ * Use base classes/interfaces for provider-specific logic.
97
+ * Prefer loose coupling; modules should be swappable.
98
+
99
+ ---
100
+
101
+ ## 🗂️ File & Folder Conventions
102
+
103
+ * Each model = its own file under `src/recipes/models/`.
104
+ * No placeholder/empty boilerplate files.
105
+ * Organize by domain, not by layer (avoid `misc.py`, `common.py`).
106
+
107
+ ---
108
+
109
+ ## 🧾 Documentation
110
+
111
+ * All public classes and functions need docstrings.
112
+ * Comments should clarify *why* decisions were made.
113
+ * Update Markdown/docs when behavior changes.
114
+
115
+ ---
116
+
117
+ ## 💬 Commits & PRs
118
+
119
+ * **Commit title format**: `[scope] Short summary`
120
+
121
+ * Example: `[auth] Add password reset expiry`
122
+ * Messages must explain:
123
+
124
+ * **What** changed
125
+ * **Why** it’s needed
126
+ * **How** to test it
127
+ * Keep commits small and focused (atomic).
128
+ * No auto-generated files in commits.
129
+
130
+ ---
131
+
132
+ ## 🤖 Agents (AI Contribution Rules)
133
+
134
+ * Respect this document before generating code.
135
+ * Reuse existing patterns and naming.
136
+ * Never assume frameworks/libraries not already in the repo.
137
+ * Ensure functions are short, explicit, and modular.
138
+ * Include docstrings and type hints.
139
+ * Run security and readability checks before suggesting changes.
140
+
141
+ ---
142
+
143
+ ## 🔍 Code Review Checklist
144
+
145
+ * [ ] Functions ≤ 20 lines; single responsibility
146
+ * [ ] No dense inline logic, no multi-statement lines
147
+ * [ ] Call chaining ≤ 2 steps
148
+ * [ ] DB ops isolated; transactions around multi-step writes
149
+ * [ ] Bulk ops with `UPDATE_FIELDS`
150
+ * [ ] No dead code; imports trimmed
151
+ * [ ] Comments explain *why*
152
+ * [ ] Tests added/updated (CRUD, edge, abuse, success paths)
153
+ * [ ] No secrets/unsafe code
154
+ * [ ] Docs updated
155
+
156
+ ---
157
+
158
+ ## 🛠️ PR Template
159
+
160
+ `.github/pull_request_template.md`:
161
+
162
+ ```markdown
163
+ ## Summary
164
+ - What does this change do?
165
+
166
+ ## Checklist
167
+ - [ ] Functions ≤ 20 lines
168
+ - [ ] Single responsibility per function/class
169
+ - [ ] No chained one-liners or dense inline ternaries
170
+ - [ ] Intermediate variables for clarity
171
+ - [ ] DB I/O isolated; transactions for multi-step writes
172
+ - [ ] Narrow exceptions (no bare `except`)
173
+ - [ ] Docstrings + type hints present
174
+ - [ ] `UPDATE_FIELDS` constant used for bulk updates
175
+ - [ ] Tests mirror module layout and cover edge cases
176
+
177
+ ## 🧪 Test & Quality Tools (Backend)
178
+ All backend test and quality tooling is executed from the project root and targets the backend codebase in `src`. Configuration files for each tool live in the backend code root (`src`).
@@ -0,0 +1,11 @@
1
+ services:
2
+ holocron:
3
+ build: .
4
+ container_name: holocron
5
+ restart: unless-stopped
6
+ volumes:
7
+ - ./mirror-data:/app/mirror-data
8
+ env_file:
9
+ - .env
10
+ # Optional: Override command
11
+ # command: ["--watch", "--interval", "30", "--backup-only"]
@@ -0,0 +1,32 @@
1
+ [project]
2
+ name = "holocron-sync"
3
+ version = "0.1.0"
4
+ description = "Holocron: The Ultimate Git Mirroring Tool"
5
+ readme = "README.md"
6
+ requires-python = ">=3.9"
7
+ dependencies = [
8
+ "requests>=2.28.0",
9
+ "python-dotenv",
10
+ ]
11
+
12
+ [project.scripts]
13
+ holocron = "holocron.__main__:main"
14
+
15
+ [build-system]
16
+ requires = ["hatchling"]
17
+ build-backend = "hatchling.build"
18
+
19
+ [tool.hatch.build.targets.wheel]
20
+ packages = ["src/holocron"]
21
+
22
+ [tool.uv]
23
+ dev-dependencies = [
24
+ "pytest>=8.0.0",
25
+ "pytest-mock>=3.12.0",
26
+ "pytest-cov>=4.1.0",
27
+ ]
28
+
29
+ [tool.pytest.ini_options]
30
+ pythonpath = "src"
31
+ norecursedirs = ["mirror-data", ".venv", ".git"]
32
+ testpaths = ["tests"]
@@ -0,0 +1,2 @@
1
+ requests>=2.28.0
2
+ python-dotenv
@@ -0,0 +1,3 @@
1
+ from .__main__ import main
2
+
3
+ __all__ = ["main"]
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import sys
4
+ import time
5
+ from concurrent.futures import ThreadPoolExecutor, as_completed
6
+
7
+ # Import from local modules
8
+ from .config import parse_args
9
+ from .logger import log
10
+ from .github_provider import get_github_repos
11
+ from .mirror import needs_sync, sync_one_repo
12
+
13
+ def main():
14
+ args = parse_args()
15
+
16
+ # Load secrets
17
+ gh_token = os.environ.get("GITHUB_TOKEN")
18
+ gl_token = os.environ.get("GITLAB_TOKEN")
19
+
20
+ # Validation logic
21
+ if not gh_token:
22
+ print("CRITICAL: Missing GITHUB_TOKEN.")
23
+ sys.exit(1)
24
+
25
+ if not args.backup_only and not gl_token:
26
+ print("CRITICAL: Missing GITLAB_TOKEN.")
27
+ print("Please set GITLAB_TOKEN or use --backup-only.")
28
+ sys.exit(1)
29
+
30
+ log("Initializing Holocron...")
31
+ if args.dry_run:
32
+ log("!!! DRY RUN MODE ACTIVE !!!")
33
+
34
+ # Track the last synced push timestamp for each repo
35
+ synced_pushes = {}
36
+
37
+ while True:
38
+ repos = get_github_repos(gh_token, args.verbose)
39
+ log(f"Found {len(repos)} repositories on GitHub.", is_verbose_mode=args.verbose)
40
+
41
+ sync_count = 0
42
+ with ThreadPoolExecutor(max_workers=args.concurrency) as executor:
43
+ future_to_repo = {}
44
+ for repo in repos:
45
+ repo_name = repo['name']
46
+ pushed_at = repo.get('pushed_at')
47
+ repo_dir = os.path.join(args.storage, f"{repo_name}.git")
48
+
49
+ # If watching, use the smart filter. If running once, sync all.
50
+ if args.watch:
51
+ # 1. Skip if we already synced this exact push
52
+ if repo_name in synced_pushes and synced_pushes[repo_name] == pushed_at:
53
+ continue
54
+
55
+ # 2. Check time window (SKIP if old AND local repo exists)
56
+ # If local repo is missing, we MUST sync (bootstrap), regardless of age.
57
+ if os.path.exists(repo_dir) and not needs_sync(repo, args.window):
58
+ continue
59
+
60
+ future = executor.submit(sync_one_repo, repo, args, gh_token, gl_token)
61
+ future_to_repo[future] = repo
62
+
63
+ for future in as_completed(future_to_repo):
64
+ repo = future_to_repo[future]
65
+ try:
66
+ future.result()
67
+ sync_count += 1
68
+ # Update tracking on success
69
+ if repo.get('pushed_at'):
70
+ synced_pushes[repo['name']] = repo['pushed_at']
71
+ except Exception as exc:
72
+ log(f"[{repo['name']}] generated an exception: {exc}")
73
+
74
+ if sync_count > 0:
75
+ log(f"Sync cycle complete. Updated {sync_count} repositories.")
76
+ elif args.verbose:
77
+ log("No changes detected in this cycle.")
78
+
79
+ if not args.watch:
80
+ break
81
+
82
+ time.sleep(args.interval)
83
+
84
+ if __name__ == "__main__":
85
+ main()
@@ -0,0 +1,36 @@
1
+ import os
2
+ import argparse
3
+ from dotenv import load_dotenv
4
+
5
+ # Load env vars from .env file
6
+ load_dotenv()
7
+
8
+ # --- CONFIGURATION DEFAULTS ---
9
+ # We use Environment Variables for security.
10
+ # Never hardcode passwords in open source code!
11
+ GITHUB_API_URL = "https://api.github.com"
12
+ GITLAB_API_URL = os.environ.get("GITLAB_API_URL", "http://gitlab.local/api/v4")
13
+
14
+ def parse_args():
15
+ """
16
+ Sets up the command line arguments.
17
+ This allows the user to run: 'python g2g.py --dry-run'
18
+ """
19
+ parser = argparse.ArgumentParser(
20
+ description="Holocron: GitHub to GitLab/Local Mirroring Tool"
21
+ )
22
+
23
+ # Flags (True/False options)
24
+ parser.add_argument("--dry-run", action="store_true", help="Simulate execution without making changes")
25
+ parser.add_argument("--watch", action="store_true", help="Run continuously in a loop (Daemon mode)")
26
+ parser.add_argument("--verbose", action="store_true", help="Print detailed logs")
27
+
28
+ # value options
29
+ parser.add_argument("--interval", type=int, default=60, help="Seconds to wait between checks (default: 60)")
30
+ parser.add_argument("--window", type=int, default=10, help="Only sync repos updated in the last X minutes")
31
+ parser.add_argument("--storage", type=str, default="./mirror-data", help="Local path to store git repositories")
32
+ parser.add_argument("--concurrency", type=int, default=5, help="Number of concurrent sync threads (default: 5)")
33
+ parser.add_argument("--backup-only", action="store_true", help="Mirror locally only, skip pushing to GitLab")
34
+ parser.add_argument("--checkout", action="store_true", help="Create a checkout of the repository alongside the mirror")
35
+
36
+ return parser.parse_args()