Rename everything to archrepobuild
8 files modified
9 files renamed
| | |
| | | ### From Source |
| | | ```bash |
| | | # Clone the repository |
| | | git clone https://github.com/joelgrun/archbuild |
| | | cd archbuild |
| | | git clone https://github.com/joelgrun/archrepobuild |
| | | cd archrepobuild |
| | | |
| | | # Set up virtual environment and install |
| | | python -m venv .venv |
| | |
| | | ```bash |
| | | python scripts/build_binary.py |
| | | ``` |
| | | The binary will be available at `dist/archbuild-bin`. |
| | | The binary will be available at `dist/archrepobuild-bin`. |
| | | |
| | | ## Quick Start |
| | | |
| | |
| | | |
| | | 2. **Initialize repository**: |
| | | ```bash |
| | | archbuild -c config.yaml init |
| | | archrepobuild -c config.yaml init |
| | | ``` |
| | | |
| | | 3. **Add packages**: |
| | | ```bash |
| | | archbuild add yay paru |
| | | archrepobuild add yay paru |
| | | ``` |
| | | |
| | | 4. **Build all packages**: |
| | | ```bash |
| | | archbuild build-all |
| | | archrepobuild build-all |
| | | ``` |
| | | |
| | | 5. **Build a specific package**: |
| | | ```bash |
| | | archbuild build <package> |
| | | archrepobuild build <package> |
| | | ``` |
| | | |
| | | ## Commands |
| | |
| | | ## Migration from Bash Version |
| | | |
| | | ```bash |
| | | archbuild migrate-config vars.sh -o config.yaml |
| | | archrepobuild migrate-config vars.sh -o config.yaml |
| | | ``` |
| | | |
| | | ## Systemd Timer |
| | | |
| | | Create `/etc/systemd/system/archbuild.service`: |
| | | Create `/etc/systemd/system/archrepobuild.service`: |
| | | ```ini |
| | | [Unit] |
| | | Description=Build AUR packages |
| | | |
| | | [Service] |
| | | Type=oneshot |
| | | ExecStart=/usr/bin/archbuild -c /etc/archbuild/config.yaml build-all |
| | | ExecStart=/usr/bin/archrepobuild -c /etc/archrepobuild/config.yaml build-all |
| | | User=builduser |
| | | ``` |
| | | |
| | | Create `/etc/systemd/system/archbuild.timer`: |
| | | Create `/etc/systemd/system/archrepobuild.timer`: |
| | | ```ini |
| | | [Unit] |
| | | Description=Run archbuild daily |
| | | Description=Run archrepobuild daily |
| | | |
| | | [Timer] |
| | | OnCalendar=daily |
| | |
| | | # Recipient email address |
| | | to: "" |
| | | # Sender email address |
| | | from: "archbuild@localhost" |
| | | from: "archrepobuild@localhost" |
| | | # SMTP server settings |
| | | smtp_host: "localhost" |
| | | smtp_port: 25 |
| | |
| | | # Logging configuration |
| | | log_level: "INFO" # DEBUG, INFO, WARNING, ERROR, CRITICAL |
| | | # Uncomment to also log to file: |
| | | # log_file: "/var/log/archbuild.log" |
| | | # log_file: "/var/log/archrepobuild.log" |
| | |
| | | build-backend = "hatchling.build" |
| | | |
| | | [project] |
| | | name = "archbuild" |
| | | name = "archrepobuild" |
| | | version = "2.0.0" |
| | | description = "Automatic AUR package building and repository management for Arch Linux" |
| | | readme = "README.md" |
| | |
| | | ] |
| | | |
| | | [project.scripts] |
| | | archrepobuild = "archbuild.cli:main" |
| | | archrepobuild = "archrepobuild.cli:main" |
| | | |
| | | [tool.hatch.build.targets.wheel] |
| | | packages = ["src/archbuild"] |
| | | packages = ["src/archrepobuild"] |
| | | |
| | | [tool.ruff] |
| | | target-version = "py311" |
| | |
| | | #!/usr/bin/env python3 |
| | | """ |
| | | Script to build a standalone executable for archbuild using PyInstaller. |
| | | Script to build a standalone executable for archrepobuild using PyInstaller. |
| | | """ |
| | | |
| | | import subprocess |
| | |
| | | src = root / "src" |
| | | |
| | | # Create a temporary entry script |
| | | entry_script = root / "archbuild_entry.py" |
| | | entry_script.write_text("from archbuild.cli import main\nif __name__ == '__main__':\n main()\n") |
| | | entry_script = root / "archrepobuild_entry.py" |
| | | entry_script.write_text("from archrepobuild.cli import main\nif __name__ == '__main__':\n main()\n") |
| | | |
| | | # PyInstaller command |
| | | pyinstaller_exe = shutil.which("pyinstaller") |
| | |
| | | "--name", "archrepobuild", |
| | | "--paths", str(src), |
| | | "--clean", |
| | | "--collect-all", "archbuild", |
| | | "--collect-all", "archrepobuild", |
| | | "--collect-all", "rich", |
| | | str(entry_script) |
| | | ] |
| File was renamed from src/archbuild/aur.py |
| | |
| | | |
| | | import aiohttp |
| | | |
| | | from archbuild.logging import get_logger |
| | | from archrepobuild.logging import get_logger |
| | | |
| | | logger = get_logger("aur") |
| | | |
| File was renamed from src/archbuild/builder.py |
| | |
| | | from concurrent.futures import ProcessPoolExecutor |
| | | from typing import Any |
| | | |
| | | from archbuild.aur import AURClient |
| | | from archbuild.config import Config, PackageOverride |
| | | from archbuild.logging import get_logger |
| | | from archbuild.resolver import DependencyResolver |
| | | from archrepobuild.aur import AURClient |
| | | from archrepobuild.config import Config, PackageOverride |
| | | from archrepobuild.logging import get_logger |
| | | from archrepobuild.resolver import DependencyResolver |
| | | |
| | | logger = get_logger("builder") |
| | | |
| File was renamed from src/archbuild/cli.py |
| | |
| | | from rich.console import Console |
| | | from rich.table import Table |
| | | |
| | | from archbuild import __version__ |
| | | from archbuild.aur import AURClient |
| | | from archbuild.builder import Builder, BuildStatus |
| | | from archbuild.config import Config, load_config, migrate_vars_sh, save_config |
| | | from archbuild.logging import console as log_console, setup_logging |
| | | from archbuild.notifications import NotificationManager |
| | | from archbuild.repo import RepoManager |
| | | from archrepobuild import __version__ |
| | | from archrepobuild.aur import AURClient |
| | | from archrepobuild.builder import Builder, BuildStatus |
| | | from archrepobuild.config import Config, load_config, migrate_vars_sh, save_config |
| | | from archrepobuild.logging import console as log_console, setup_logging |
| | | from archrepobuild.notifications import NotificationManager |
| | | from archrepobuild.repo import RepoManager |
| | | |
| | | console = Console() |
| | | |
| | |
| | | default=Path("config.yaml"), |
| | | help="Path to configuration file", |
| | | ) |
| | | @click.version_option(__version__, prog_name="archbuild") |
| | | @click.version_option(__version__, prog_name="archrepobuild") |
| | | @click.pass_context |
| | | def cli(ctx: click.Context, config: Path) -> None: |
| | | """Archbuild - Automatic AUR package building and repository management. |
| | |
| | | |
| | | if all_official: |
| | | # Find packages now in official repos |
| | | from archbuild.resolver import DependencyResolver |
| | | from archrepobuild.resolver import DependencyResolver |
| | | resolver = DependencyResolver(aur) |
| | | |
| | | for pkg in repo.list_packages(): |
| | |
| | | |
| | | async def _check() -> None: |
| | | async with AURClient() as aur: |
| | | from archbuild.resolver import DependencyResolver |
| | | from archrepobuild.resolver import DependencyResolver |
| | | resolver = DependencyResolver(aur) |
| | | repo = RepoManager(config) |
| | | |
| | |
| | | |
| | | interval = click.prompt("How often should builds run? (systemd Calendar spec, e.g., 12h, daily)", default="12h") |
| | | |
| | | # Get absolute path to archbuild executable |
| | | # Get absolute path to archrepobuild executable |
| | | import shutil |
| | | archbuild_path = shutil.which("archbuild") |
| | | if not archbuild_path: |
| | | archrepobuild_path = shutil.which("archrepobuild") |
| | | if not archrepobuild_path: |
| | | # Fallback to current sys.executable if running as module or in venv |
| | | archbuild_path = f"{sys.executable} -m archbuild.cli" |
| | | archrepobuild_path = f"{sys.executable} -m archrepobuild.cli" |
| | | |
| | | user_systemd_dir = Path.home() / ".config" / "systemd" / "user" |
| | | user_systemd_dir.mkdir(parents=True, exist_ok=True) |
| | |
| | | |
| | | [Service] |
| | | Type=oneshot |
| | | ExecStart={archbuild_path} build-all |
| | | ExecStart={archrepobuild_path} build-all |
| | | Environment="PATH={Path.home()}/.local/bin:/usr/bin:/bin" |
| | | """ |
| | | |
| | |
| | | WantedBy=timers.target |
| | | """ |
| | | |
| | | service_file = user_systemd_dir / "archbuild.service" |
| | | timer_file = user_systemd_dir / "archbuild.timer" |
| | | service_file = user_systemd_dir / "archrepobuild.service" |
| | | timer_file = user_systemd_dir / "archrepobuild.timer" |
| | | |
| | | service_file.write_text(service_content) |
| | | timer_file.write_text(timer_content) |
| | | |
| | | try: |
| | | subprocess.run(["systemctl", "--user", "daemon-reload"], check=True) |
| | | subprocess.run(["systemctl", "--user", "enable", "--now", "archbuild.timer"], check=True) |
| | | subprocess.run(["systemctl", "--user", "enable", "--now", "archrepobuild.timer"], check=True) |
| | | console.print(f"[green]✓[/] Systemd timer enabled (running every {interval})") |
| | | except subprocess.CalledProcessError as e: |
| | | console.print(f"[red]✗[/] Failed to enable systemd timer: {e}") |
| File was renamed from src/archbuild/logging.py |
| | |
| | | handlers=handlers, |
| | | ) |
| | | |
| | | return logging.getLogger("archbuild") |
| | | return logging.getLogger("archrepobuild") |
| | | |
| | | |
| | | def get_logger(name: str) -> logging.Logger: |
| | |
| | | Returns: |
| | | Logger instance |
| | | """ |
| | | return logging.getLogger(f"archbuild.{name}") |
| | | return logging.getLogger(f"archrepobuild.{name}") |
| File was renamed from src/archbuild/notifications.py |
| | |
| | | |
| | | import aiohttp |
| | | |
| | | from archbuild.builder import BuildResult, BuildStatus |
| | | from archbuild.config import Config, EmailConfig, WebhookConfig |
| | | from archbuild.logging import get_logger |
| | | from archrepobuild.builder import BuildResult, BuildStatus |
| | | from archrepobuild.config import Config, EmailConfig, WebhookConfig |
| | | from archrepobuild.logging import get_logger |
| | | |
| | | logger = get_logger("notifications") |
| | | |
| | |
| | | |
| | | try: |
| | | msg = MIMEMultipart() |
| | | msg["From"] = self.config.from_addr or f"archbuild@localhost" |
| | | msg["From"] = self.config.from_addr or f"archrepobuild@localhost" |
| | | msg["To"] = self.config.to |
| | | msg["Subject"] = f"Build Errors - {config.repository.name}" |
| | | |
| File was renamed from src/archbuild/repo.py |
| | |
| | | from pathlib import Path |
| | | from typing import Any |
| | | |
| | | from archbuild.builder import BuildResult, BuildStatus, FileLock |
| | | from archbuild.config import Config |
| | | from archbuild.logging import get_logger |
| | | from archrepobuild.builder import BuildResult, BuildStatus, FileLock |
| | | from archrepobuild.config import Config |
| | | from archrepobuild.logging import get_logger |
| | | |
| | | logger = get_logger("repo") |
| | | |
| File was renamed from src/archbuild/resolver.py |
| | |
| | | from dataclasses import dataclass, field |
| | | from enum import Enum |
| | | |
| | | from archbuild.aur import AURClient, Package |
| | | from archbuild.logging import get_logger |
| | | from archrepobuild.aur import AURClient, Package |
| | | from archrepobuild.logging import get_logger |
| | | |
| | | logger = get_logger("resolver") |
| | | |
| | |
| | | #!/usr/bin/env python3 |
| | | """ |
| | | Integration test script for archbuild. |
| | | Integration test script for archrepobuild. |
| | | |
| | | This script creates a temporary repository, initializes it with a basic config, |
| | | adds test packages, and verifies they build and are added correctly. |
| | |
| | | # Add src to path for development |
| | | sys.path.insert(0, str(Path(__file__).parent.parent / "src")) |
| | | |
| | | from archbuild.aur import AURClient |
| | | from archbuild.builder import Builder, BuildStatus |
| | | from archbuild.config import Config, RepositoryConfig, BuildingConfig, SigningConfig, PackageOverride |
| | | from archbuild.logging import setup_logging, console |
| | | from archbuild.repo import RepoManager |
| | | from archrepobuild.aur import AURClient |
| | | from archrepobuild.builder import Builder, BuildStatus |
| | | from archrepobuild.config import Config, RepositoryConfig, BuildingConfig, SigningConfig, PackageOverride |
| | | from archrepobuild.logging import setup_logging, console |
| | | from archrepobuild.repo import RepoManager |
| | | |
| | | |
| | | # Test packages - real packages that exist in the AUR |
| | |
| | | self.failed = 0 |
| | | |
| | | def _run_cli(self, command: str, *args: str) -> subprocess.CompletedProcess: |
| | | """Run archbuild CLI command via subprocess.""" |
| | | """Run archrepobuild CLI command via subprocess.""" |
| | | if not self.config_path: |
| | | raise RuntimeError("Config path not set") |
| | | |
| | |
| | | else: |
| | | # Add src to PYTHONPATH so the CLI can find the package |
| | | env["PYTHONPATH"] = str(Path(__file__).parent.parent / "src") |
| | | cmd = [sys.executable, "-m", "archbuild.cli", "-c", str(self.config_path), command] + list(args) |
| | | cmd = [sys.executable, "-m", "archrepobuild.cli", "-c", str(self.config_path), command] + list(args) |
| | | |
| | | return subprocess.run(cmd, capture_output=True, text=True, env=env) |
| | | |
| | |
| | | console.print("\n[bold blue]═══ Setting up test environment ═══[/]") |
| | | |
| | | # Create temp directory |
| | | self.temp_dir = Path(tempfile.mkdtemp(prefix="archbuild_test_")) |
| | | self.temp_dir = Path(tempfile.mkdtemp(prefix="archrepobuild_test_")) |
| | | console.print(f" Created temp directory: {self.temp_dir}") |
| | | |
| | | # Create subdirectories |
| | |
| | | ) |
| | | |
| | | # Save config to disk for CLI to use |
| | | from archbuild.config import save_config |
| | | from archrepobuild.config import save_config |
| | | self.config_path = self.temp_dir / "config.yaml" |
| | | save_config(self.config, self.config_path) |
| | | |
| | |
| | | |
| | | if artifacts: |
| | | # Create a mock build result for add_packages |
| | | from archbuild.builder import BuildResult |
| | | from archrepobuild.builder import BuildResult |
| | | mock_result = BuildResult( |
| | | package=pkg_name, |
| | | status=BuildStatus.SUCCESS, |
| | |
| | | from unittest.mock import AsyncMock, patch, MagicMock |
| | | from datetime import datetime |
| | | |
| | | from archbuild.aur import AURClient, Package |
| | | from archrepobuild.aur import AURClient, Package |
| | | |
| | | |
| | | @pytest.fixture |
| | |
| | | |
| | | def test_parse_simple(self): |
| | | """Test parsing simple dependency.""" |
| | | from archbuild.resolver import Dependency |
| | | from archrepobuild.resolver import Dependency |
| | | dep = Dependency.parse("package") |
| | | assert dep.name == "package" |
| | | assert dep.version_constraint is None |
| | | |
| | | def test_parse_with_version(self): |
| | | """Test parsing dependency with version.""" |
| | | from archbuild.resolver import Dependency |
| | | from archrepobuild.resolver import Dependency |
| | | dep = Dependency.parse("package>=1.0") |
| | | assert dep.name == "package" |
| | | assert dep.version_constraint == ">=1.0" |
| | | |
| | | def test_parse_exact_version(self): |
| | | """Test parsing dependency with exact version.""" |
| | | from archbuild.resolver import Dependency |
| | | from archrepobuild.resolver import Dependency |
| | | dep = Dependency.parse("package=2.0") |
| | | assert dep.name == "package" |
| | | assert dep.version_constraint == "=2.0" |
| | |
| | | from pathlib import Path |
| | | from tempfile import NamedTemporaryFile |
| | | |
| | | from archbuild.config import ( |
| | | from archrepobuild.config import ( |
| | | Config, |
| | | load_config, |
| | | migrate_vars_sh, |
| | |
| | | import pytest |
| | | from unittest.mock import AsyncMock, patch |
| | | |
| | | from archbuild.resolver import DependencyResolver, Dependency, DependencyType, BuildOrder |
| | | from archrepobuild.resolver import DependencyResolver, Dependency, DependencyType, BuildOrder |
| | | |
| | | |
| | | class TestDependency: |
| | |
| | | cycles = resolver.detect_cycles(graph) |
| | | assert len(cycles) > 0 |
| | | |
| | | @patch("archbuild.resolver.subprocess.run") |
| | | @patch("archrepobuild.resolver.subprocess.run") |
| | | def test_is_in_official_repos(self, mock_run, mock_aur_client): |
| | | """Test checking official repos.""" |
| | | mock_run.return_value.returncode = 0 |