Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
FROM mcr.microsoft.com/devcontainers/base:noble
ARG DISTRO=trixie
FROM mcr.microsoft.com/devcontainers/base:${DISTRO}

# enable deb-src repositories for apt source to work
RUN sed -i -e 's/Types: deb/Types: deb deb-src/g' /etc/apt/sources.list.d/debian.sources
# install everything required for debian package building
RUN apt-get update && apt-get -y install build-essential python3 python3-pip curl debhelper devscripts dh-python
RUN echo "/workspaces/debmagic/src" > /usr/lib/python3/dist-packages/debmagic.pth
Expand Down
17 changes: 12 additions & 5 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
// README at: https://github.com/devcontainers/templates/tree/main/src/debian
{
"name": "Ubuntu",
"name": "Debian Trixie",
"build": {
"dockerfile": "Dockerfile"
"dockerfile": "Dockerfile",
"args": {
"DISTRO": "trixie"
}
},
"postCreateCommand": "uv sync",
"postCreateCommand": "./.devcontainer/post-create.sh",

// Configure tool-specific properties.
"customizations": {
Expand All @@ -16,5 +19,9 @@
"tamasfe.even-better-toml"
]
}
}
},
// make sure we always mount the project at the same path in the container to have our debmagic.pth symlinking
// work properly to allow the debmagic package to be globally installed in the system python environment
"workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/debmagic,type=bind,consistency=uncached",
"workspaceFolder": "/workspaces/debmagic"
}
4 changes: 4 additions & 0 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

uv sync
uv run pre-commit install
109 changes: 109 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: CI

permissions: {}

on:
pull_request:
types: [opened, synchronize]
push:
branches:
- main

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Install the project
run: uv sync --locked --all-extras --dev
- name: Run Ruff Lint
run: uv run ruff check

typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Install the project
run: uv sync --locked --all-extras --dev
- name: Run Mypy
run: uv run mypy .

format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Install the project
run: uv sync --locked --all-extras --dev
- name: Run Ruff Format Check
run: uv run ruff format --check

unit-tests:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version:
- "3.12"
- "3.13"
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Install the project
run: uv sync --locked --all-extras --dev
- name: Run Unittests
run: uv run pytest tests/unit --cov=debmagic

# TODO: integration tests currently don't work in the CI since they require running apt source on debian trixie -> CI runs on ubuntu
# integration-tests:
# runs-on: ${{ matrix.os }}
# strategy:
# matrix:
# python-version:
# - "3.12"
# - "3.13"
# os: [ubuntu-latest]
# steps:
# - uses: actions/checkout@v5
# - name: Set up Python
# uses: actions/setup-python@v6
# with:
# python-version: "3.12"
# - name: Install uv
# uses: astral-sh/setup-uv@v6
# with:
# enable-cache: true
# - name: Install the project
# run: uv sync --locked --all-extras --dev
# - name: Run Integrationtests
# run: uv run pytest tests/integration
8 changes: 0 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
# project specific
config.yaml
config.devcontainer.yml
server.yaml

# python
__pycache__
*.pyc
Expand All @@ -23,8 +18,6 @@ __pycache__
pyvenv.cfg
venv*
.venv
.pdm-python
.python-version

# building
MANIFEST
Expand All @@ -33,7 +26,6 @@ src/*/*.lock

# testing
/*.conf
/*.yaml
/test
/build

Expand Down
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.6
hooks:
- id: ruff-check
args: [ --fix ]
- id: ruff-format
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,56 @@
Debian build instructions written in Python.

> Explicit is better than implicit.

```python
#!/usr/bin/env python3

from debmagic.v0 import Build, package
from debmagic.v0 import autotools as autotools_mod
from debmagic.v0 import dh as dh_mod

autotools = autotools_mod.Preset()
dh = dh_mod.Preset()

pkg = package(
preset=[dh, autotools],
maint_options="hardening=+all",
)

@pkg.stage
def configure(build: Build):
autotools_mod.autoreconf(build)
autotools.configure(
build,
["--enable-something"],
)


@dh.override
def dh_installgsettings(build: Build):
print("test dh override works :)")
build.cmd("dh_installgsettings")


@pkg.custom_function
def something_custom(some_param: int, another_param: str = "some default"):
print(f"you called {some_param=} {another_param=}")


pkg.pack()
```

## Developing

Prerequisites:

- Debian >= trixie, either roll your own environment or to get started faster use the [devcontainer](https://containers.dev/)
- Python >= 3.12
- [UV](https://docs.astral.sh/uv/)

Setup:

```bash
uv sync
uv run pre-commit install
```
3 changes: 1 addition & 2 deletions debian/rules
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#!/usr/bin/env python3

from pathlib import Path
import sys
from pathlib import Path

repo_root = Path(__file__).parent.parent / "src"
sys.path.append(str(repo_root))

from debmagic.v1 import package, python


package(
preset=python,
)
8 changes: 6 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,20 @@ requires = ["setuptools>=77.0.0", "setuptools-scm"]
build-backend = "setuptools.build_meta"

[dependency-groups]
dev = ["pytest>=8.4.2"]
dev = ["pytest>=9.0.1", "pytest-cov>=7.0.0", "ruff", "pre-commit", "mypy"]

[tool.mypy]
mypy_path = '$MYPY_CONFIG_FILE_DIR/src'
exclude_gitignore = true

[tool.ruff]
line-length = 120
target-version = "py312"
exclude = [".git", ".idea", ".mypy_cache", ".venv*", "docs"]
exclude = [".git", ".idea", ".mypy_cache", ".venv*", "docs", "debian"]

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I", "PLE", "PLW"]
ignore = ["E722"]

[tool.pytest]
testpaths = ["tests"]
18 changes: 7 additions & 11 deletions src/debmagic/_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def cmd(self, cmd: list[str] | str, **kwargs):
execute a command, auto-converts command strings/lists.
use this to supports build dry-runs.
"""
cmd_args : list[str] | str = cmd
cmd_args: list[str] | str = cmd
is_shell = kwargs.get("shell")
if not is_shell and isinstance(cmd, str):
cmd_args = shlex.split(cmd)
Expand All @@ -47,14 +47,11 @@ def cmd(self, cmd: list[str] | str, **kwargs):

@property
def install_dirs(self) -> dict[str, Path]:
""" return { binary_package_name: install_directory } """
return {
pkg.name: self.install_base_dir / pkg.name
for pkg in self.binary_packages
}
"""return { binary_package_name: install_directory }"""
return {pkg.name: self.install_base_dir / pkg.name for pkg in self.binary_packages}

def select_packages(self, names: set[str]):
""" only build those packages """
"""only build those packages"""
if not names:
self._selected_packages = None

Expand All @@ -64,9 +61,8 @@ def select_packages(self, names: set[str]):
self._selected_packages.append(pkg)

def filter_packages(self, package_filter: PackageFilter) -> None:
""" apply filter to only build those packages """
self.select_packages({pkg.name for pkg in
package_filter.get_packages(self.binary_packages)})
"""apply filter to only build those packages"""
self.select_packages({pkg.name for pkg in package_filter.get_packages(self.binary_packages)})

def is_stage_completed(self, stage: BuildStage) -> bool:
return stage in self._completed_stages
Expand All @@ -90,7 +86,7 @@ def run(

# run stage function from debian/rules.py
if rules_stage_function := self.source_package.stage_functions.get(stage):
print(f"debmagic: running stage from rules file...")
print("debmagic: running stage from rules file...")
rules_stage_function(self)
self._mark_stage_done(stage)

Expand Down
3 changes: 1 addition & 2 deletions src/debmagic/_dpkg/buildflags.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import json
import os
import re
import shlex
import subprocess
import re

from pathlib import Path


Expand Down
1 change: 1 addition & 0 deletions src/debmagic/_modules/autodetect.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
# TODO: detect build system
# autotools, cmake, python, rust, perl, go, ...


class Preset(BasePreset):
pass
17 changes: 7 additions & 10 deletions src/debmagic/_modules/autotools.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


class Preset(PresetBase):
#def clean(self, build: Build):
# def clean(self, build: Build):
# TODO: if Makefile exists and has one of distclean, realclean, clean target, run it.

def configure(self, build: Build, args: list[str] | None = None):
Expand All @@ -22,10 +22,10 @@ def configure(self, build: Build, args: list[str] | None = None):
"--sysconfdir=/etc",
"--localstatedir=/var",
"--runstatedir=/run",
#"--disable-option-checking", # TODO: activate if not strict-mode?
# "--disable-option-checking", # TODO: activate if not strict-mode?
"--disable-maintainer-mode",
"--disable-dependency-tracking",
#"--with-bugurl=https://bugs.launchpad.net/ubuntu/+source/${srcpkg}",
# "--with-bugurl=https://bugs.launchpad.net/ubuntu/+source/${srcpkg}",
]

if multiarch := build.flags["DEB_HOST_MULTIARCH"]:
Expand All @@ -51,18 +51,15 @@ def build(self, build: Build, args: list[str] = []):

build.cmd(["make"] + args, cwd=build.source_dir)


# TODO: def test(): run make test or make check

def install(self, build: Build, args: list[str] = []):
build.cmd(
["make", f"DESTDIR={build.install_dir}", "install"] + args, cwd=build.source_dir
)
# TODO: figure out installdir handling for multi package builds
destdir = build.install_dirs[build.source_package.name]
build.cmd(["make", f"DESTDIR={destdir}", "install"] + args, cwd=build.source_dir)


def autoreconf(build: Build):
configure_ac_path = build.source_dir / "configure.ac"
if configure_ac_path.is_file():
build.cmd(
["autoreconf", "--force", "--install", "--verbose"], cwd=build.source_dir
)
build.cmd(["autoreconf", "--force", "--install", "--verbose"], cwd=build.source_dir)
Loading