Contributing
This chapter covers the development workflow, coding conventions, and testing practices for contributing to portage-ng.
Reporting issues
Please report bugs, feature requests, and other issues through GitHub:
https://github.com/pvdabeel/portage-ng/issues
Do not use email or other informal channels for issue tracking.
Development workflow
Start from clean committed state. Always begin development with no uncommitted changes.
Make changes using the project wrapper for testing:
./Source/Application/Wrapper/portage-ng-dev --mode standalone --pretend <target>Run tests to verify correctness:
make test # PLUnit tests make test-overlay # Overlay regression testsRun compare analysis to detect regressions. The compare harness lives in the tinderbox-ng repository and generates its own plan logs in fresh sessions (the legacy
--graph+.mergeregeneration loop is no longer part of this workflow):# Whole-tree matrix run (on the tinderbox host): sudo tinderbox-ng compare-matrix sudo tinderbox-ng analyze # Or a quick per-target compare while iterating locally: tinderbox-ng compare <category>/<package>tinderbox-ng analyzeproducesanalysis.json+analysis.txtin the matrix run directory, replacing the oldcompare-<date>-<hash>.json.gzsnapshots.Review the comparison table for regressions in CN, CN+V, CN+V+U match percentages, ordering concordance, and assumption counts.
Commit when regression-free.
How to run
Dev wrapper
Always use the dev wrapper for testing — never run ad-hoc swipl -g "..."
snippets, as they miss required operator definitions, libraries, and module
load order:
./Source/Application/Wrapper/portage-ng-dev --mode standalone --pretend <target>
./Source/Application/Wrapper/portage-ng-dev --mode standalone --shell
Scripted sessions (here-doc pattern)
For reproducible, non-interactive debugging:
./Source/Application/Wrapper/portage-ng-dev --mode standalone --shell --timeout 60 <<'PL'
resolver:test_stats(portage).
halt.
PL
CI mode
For automated checks:
./Source/Application/Wrapper/portage-ng-dev --mode standalone --ci --pretend <target>
echo $? # 0 = no assumptions, 1 = cycle breaks, 2 = domain assumptions
Always include --pretend to avoid mutating local state.
Source file documentation style
Every .pl source file follows a strict layout. Use
Source/Application/System/bonjour.pl as the canonical reference.
File header
/*
Author: Pieter Van den Abeele
E-mail: pvdabeel@mac.com
Copyright (c) 2005-2026, Pieter Van den Abeele
Distributed under the terms of the LICENSE file in the root directory of this
project.
*/
Module documentation (PlDoc)
/** <module> MODULE_NAME_UPPERCASE
Short one-line description.
Optional longer description.
*/
Module name in the <module> tag is UPPERCASE.
Module declaration
:- module(modulename, []).
Chapter header (one per file)
% =============================================================================
% MODULE_NAME_UPPERCASE declarations
% =============================================================================
Exactly one ===== chapter per file, immediately after :- module.
Section headers
% -----------------------------------------------------------------------------
% Section title
% -----------------------------------------------------------------------------
All subsequent sections use ----- dashes.
Predicate documentation
%! module:predicate_name(+Arg1, -Arg2)
%
% Short description of what the predicate does.
module:predicate_name(Arg1, Arg2) :-
body.
Spacing rules
| Element | Blank lines after |
|---|---|
File header */ |
1 |
PlDoc module comment */ |
1 |
:- module(...) declaration |
1 |
===== chapter header |
1 |
----- section header |
1 |
| Predicate doc + last clause | 2 |
| Between clauses of same predicate | 0 |
| End of file | 0 (no trailing blank line) |
Naming conventions
Source filenames must NOT contain hyphens (
-) or underscores (_). Use concatenated lowercase words:knowledgebase.pl, notknowledge_base.pl.Exceptions (grandfathered, do not add new ones):
portage-ng.pl(project entry point / name);binpkg_exec.pl,binpkg_index.pl,binpkg_extract.pl,ebuild_exec.plandmissing_provider.pl(underscore-named for readability of their prefixes; module names match the filenames). Host-local templates underSource/Config/Private/are configuration, not source modules, and are also exempt.Prolog module names follow the same rule:
:- module(gentoo, []).Subdirectory names under
Source/may use CamelCase:Application/,Domain/,Config/,Pipeline/.
Comment guidelines
Do not add comments that just narrate what the code does. Comments should only explain non-obvious intent, trade-offs, or constraints. Avoid:
% Get the version ← redundant
version:get(V).
Prefer:
% Suffix rank maps PMS suffix ordering to integers for compare/3
suffix_rank('_alpha', 1).
Compare tooling
Regression tooling is hosted in two places:
- Merge-vs-emerge plan comparison — driven by
tinderbox-ng via
tinderbox-ng compare/tinderbox-ng compare-matrix/tinderbox-ng analyze. The underlying Python script lives atshare/tinderbox-ng/compare-merge-emerge.pyin that repository and is invoked automatically bytinderbox-ng analyze. Outputs areanalysis.json+analysis.txtin the matrix run directory. - md5-cache extractor regression —
md5cache_validate/0,1inSource/Test/unittest.pl(re-extracts metadata viaSource/Domain/Gentoo/Ebuild/ebuild-depend.sh --batchand diffs the result key by key against the on-disk md5-cache).
Do not create ad-hoc compare scripts outside these two locations.
Further reading
- Chapter 25: Testing and Regression — testing methodology
- Chapter 26: Performance and Profiling — performance testing
- Chapter 2: Installation and Quick Start — build and run instructions