Skip to content

Contributing a Backend

Lokesh Kumar edited this page Aug 7, 2026 · 1 revision

Contributing a Backend

Adding support for a new package manager to pkgwrap is straightforward. The project is designed so that you only need to add a single class file and register it. Follow this step-by-step guide to integrate a new backend.

Step 1: Create the Backend Class

Create a new file in src/pkgwrap/backends/ named <name>_backend.py (for example, apt_backend.py or choco_backend.py).

Your class must inherit from the abstract Backend class and implement the four core package operations. Here is a starter skeleton:

# src/pkgwrap/backends/my_backend.py
import subprocess
from pkgwrap.backends.base import Backend

class MyBackend(Backend):
    @property
    def name(self) -> str:
        return "my_pm"

    def install(self, package: str, already_root: bool = False, auto_yes: bool = False) -> subprocess.CompletedProcess:
        cmd = ["my_pm", "install"]
        if auto_yes:
            cmd.append("-y")
        cmd.append(package)
        # Set require_sudo=True if this package manager always needs root to install
        return self._run_command(cmd, require_sudo=True, already_root=already_root, auto_yes=auto_yes)

    def remove(self, package: str, already_root: bool = False, auto_yes: bool = False) -> subprocess.CompletedProcess:
        cmd = ["my_pm", "remove"]
        if auto_yes:
            cmd.append("-y")
        cmd.append(package)
        return self._run_command(cmd, require_sudo=True, already_root=already_root, auto_yes=auto_yes)

    def update(self, already_root: bool = False, auto_yes: bool = False) -> subprocess.CompletedProcess:
        cmd = ["my_pm", "update"]
        return self._run_command(cmd, require_sudo=True, already_root=already_root, auto_yes=auto_yes)

    def search(self, query: str, already_root: bool = False, auto_yes: bool = False) -> subprocess.CompletedProcess:
        cmd = ["my_pm", "search", query]
        return self._run_command(cmd, require_sudo=False, already_root=already_root, auto_yes=auto_yes)

Step 2: Register the Backend

Open src/pkgwrap/backends/__init__.py.

  1. Import your new class at the top of the file.
  2. Add an entry to the _BACKENDS dictionary mapping the string identifier to your class.
from pkgwrap.backends.my_backend import MyBackend

_BACKENDS: Dict[str, Type[Backend]] = {
    # ... existing backends ...
    "my_pm": MyBackend,
}

Step 3: Add Detection Logic

Open src/pkgwrap/detector.py.

Locate the priority_managers list. Add a tuple containing the primary executable command to check for (e.g., "my_pm") and the string identifier you registered in Step 2. Place it in a logical position based on how common the package manager is.

    priority_managers = [
        ("apt", "apt"),
        # ...
        ("my_pm", "my_pm"), # Added detection
        ("brew", "brew")
    ]

(Note: If your package manager requires specific environment variable checks or OS-level detection like Termux or FreeBSD, add those checks before the priority_managers loop.)

Step 4: Write Unit Tests

Create a test file for your backend at tests/backends/test_<name>_backend.py.

You don't need to actually run the package manager in tests. Follow the pattern established in test_apt_backend.py to mock _run_command and assert that the correct flags and privileges (require_sudo, already_root, auto_yes) are being passed down appropriately.

Step 5: Update the Documentation

Finally, update the "Supported Platforms" table in README.md to proudly display your new addition. Add a row with the OS/Distro, the Backend identifier, the underlying command, and a "✅ Supported" status.

Submit a Pull Request with your changes, and we'll gladly review it!

Clone this wiki locally