conandeps: dedicated "level" column for the level of indirection

Show the hop count from the consumer as its own numeric column in both the
text and the HTML dependency table instead of folding it into the kind
cell as "indirect (N)".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYNdaGDrpaqDyT8QtrTQbM
This commit is contained in:
Ole-Morten Duesund 2026-08-25 15:31:30 +02:00
commit b3b6fc89a3
3 changed files with 20 additions and 17 deletions

View file

@ -92,12 +92,12 @@ profile: arch=x86_64, compiler=gcc, compiler.libcxx=libstdc++11, compiler.versio
Dependencies (4) and binary availability Dependencies (4) and binary availability
package kind ctx Release Debug RelWithDebInfo package kind level ctx Release Debug RelWithDebInfo
-------------------------------------------------------------- -----------------------------------------------------------------
MyDepA/1.0 direct host knor knor knor MyDepA/1.0 direct 1 host knor knor knor
MyDepB/1.0 direct host knor knor knor MyDepB/1.0 direct 1 host knor knor knor
boost/1.8 indirect (2) host knor knor knor boost/1.8 indirect 2 host knor knor knor
Zigma/1.0 indirect (2) host knor knor MISSING Zigma/1.0 indirect 2 host knor knor MISSING
Missing binaries (1) Missing binaries (1)
@ -128,9 +128,10 @@ produces colour codes unless you pass `--color always`. The HTML report uses
the same colour coding. the same colour coding.
Reading the table: rows are sorted with direct dependencies first Reading the table: rows are sorted with direct dependencies first
(alphabetically), then indirect ones by increasing level of indirection (alphabetically), then indirect ones by increasing level of indirection. The
`indirect (2)` is required by a direct dependency, `indirect (3)` by one of `level` column is the number of hops from your conanfile: 1 is direct, 2 is
those, and so on (shortest path counts). required by a direct dependency, 3 by one of those, and so on (shortest path
counts). The HTML report has the same column.
* `knor` (a remote name) the remote has a binary for the package_id your * `knor` (a remote name) the remote has a binary for the package_id your

View file

@ -521,8 +521,7 @@ def _override_kind(o: Override) -> str:
def _kind(dep: Dep) -> str: def _kind(dep: Dep) -> str:
"""'direct', or 'indirect (N)' where N is the number of hops from the consumer.""" return "direct" if dep.direct else "indirect"
return "direct" if dep.direct else "indirect (%d)" % dep.depth
def render_text(report: Report, color: bool = False) -> str: def render_text(report: Report, color: bool = False) -> str:
@ -538,11 +537,11 @@ def render_text(report: Report, color: bool = False) -> str:
w(pal.bold("Dependencies (%d) and binary availability" % len(report.deps))) w(pal.bold("Dependencies (%d) and binary availability" % len(report.deps)))
w("") w("")
rows = [ rows = [
[dep.ref, _kind(dep), dep.context] [dep.ref, _kind(dep), str(dep.depth), dep.context]
+ [_cell(*dep.binaries[bt], pal) for bt in report.build_types] + [_cell(*dep.binaries[bt], pal) for bt in report.build_types]
for dep in report.deps.values() for dep in report.deps.values()
] ]
out.extend(_table(["package", "kind", "ctx"] + list(report.build_types), rows, pal)) out.extend(_table(["package", "kind", "level", "ctx"] + list(report.build_types), rows, pal))
w("") w("")
# ---- missing binaries ------------------------------------------------ # ---- missing binaries ------------------------------------------------
@ -641,14 +640,14 @@ def render_html(report: Report) -> str:
w("<h2>Dependencies (%d) and binary availability</h2>" % len(report.deps)) w("<h2>Dependencies (%d) and binary availability</h2>" % len(report.deps))
rows = [] rows = []
for dep in report.deps.values(): for dep in report.deps.values():
row = [e(dep.ref), e(_kind(dep)), e(dep.context)] row = [e(dep.ref), e(_kind(dep)), str(dep.depth), e(dep.context)]
for bt in report.build_types: for bt in report.build_types:
status, pid, remote = dep.binaries[bt] status, pid, remote = dep.binaries[bt]
cls = {"Remote": "ok", "Missing": "missing", "CacheOnly": "cacheonly"}.get(status, "na") cls = {"Remote": "ok", "Missing": "missing", "CacheOnly": "cacheonly"}.get(status, "na")
text = e(_cell(status, pid, remote, _Palette(False))) text = e(_cell(status, pid, remote, _Palette(False)))
row.append('<span class="%s" title="package_id %s">%s</span>' % (cls, e(pid), text)) row.append('<span class="%s" title="package_id %s">%s</span>' % (cls, e(pid), text))
rows.append(row) rows.append(row)
w(_html_table(["package", "kind", "context"] + list(report.build_types), rows)) w(_html_table(["package", "kind", "level", "context"] + list(report.build_types), rows))
# ---- missing binaries ------------------------------------------------ # ---- missing binaries ------------------------------------------------
problems = report.problems() problems = report.problems()

View file

@ -243,8 +243,11 @@ def test_sorted_by_level_of_indirection(report):
("libdeep/1.0", 3), ("libdeep/1.0", 3),
] ]
text = conandeps.render_text(report) text = conandeps.render_text(report)
assert re.search(r"libbar/1\.1\s+indirect \(2\)", text) assert re.search(r"libbar/1\.1\s+indirect\s+2\s+host", text)
assert re.search(r"libdeep/1\.0\s+indirect \(3\)", text) assert re.search(r"libdeep/1\.0\s+indirect\s+3\s+host", text)
page = conandeps.render_html(report)
assert "<th>level</th>" in page
assert "<td>libdeep/1.0</td><td>indirect</td><td>3</td><td>host</td>" in page
def test_missing_binaries(report): def test_missing_binaries(report):