Skip to content

Commit 06e6317

Browse files
Merge pull request #1097 from rd4398/iterative-bootstrap-proposal
docs(proposal): add iterative bootstrap proposal
2 parents a19dea7 + ec28ac2 commit 06e6317

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

docs/proposals/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Fromager Enhancement Proposals
44
.. toctree::
55
:maxdepth: 1
66

7+
iterative-bootstrap
78
new-patcher-config
89
new-resolver-config
910
release-cooldown
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
Proposal: Convert Bootstrapper from Recursive to Iterative
2+
==========================================================
3+
4+
Problem
5+
-------
6+
7+
The ``Bootstrapper`` class processes dependency trees using recursive calls.
8+
When bootstrapping packages with deep or wide dependency graphs — especially
9+
with ``--multiple-versions`` enabled — this hits Python's recursion depth limit
10+
and causes stack overflow errors. The recursion occurs at two points: processing
11+
install dependencies after building a package, and processing build
12+
dependencies before building.
13+
14+
Proposed Solution
15+
-----------------
16+
17+
Replace the recursive depth-first traversal with an iterative approach using an
18+
explicit work stack. Each package version to bootstrap is represented as a
19+
``BootstrapWorkItem`` dataclass that flows through five linear phases:
20+
21+
1. **START** — Add to dependency graph and check if already seen (early exit if so)
22+
2. **EXTRACT_BUILD_DEPS** — Collect build dependencies and push them onto the stack
23+
3. **BUILD_PACKAGE** — Build sdist and/or wheel, record in build order
24+
4. **EXTRACT_INSTALL_DEPS** — Extract install dependencies and push onto the stack
25+
5. **COMPLETE** — Clean up build directories
26+
27+
The LIFO stack ensures depth-first traversal order is preserved. Build
28+
dependencies are pushed in reverse order so they pop in the correct sequence
29+
(BUILD_SYSTEM before BUILD_BACKEND before BUILD_SDIST). Each dependency
30+
completes all five phases before its parent continues to the next phase.
31+
32+
This pattern already exists in the codebase: ``dependency_graph.py`` and
33+
``commands/graph.py`` both use stack-based DFS traversals.
34+
35+
Scope
36+
-----
37+
38+
This is a pure refactoring — no behavior changes. The external interface
39+
(``bootstrap()`` method signature, CLI flags, output files) remains identical.
40+
All existing error handling modes (normal fail-fast, ``--test-mode``,
41+
``--multiple-versions``) are preserved. Progress bar semantics are unchanged.
42+
43+
The change is limited to ``src/fromager/bootstrapper.py``. No other files
44+
require modification. All existing tests must pass without changes.
45+
46+
Benefits
47+
--------
48+
49+
- Eliminates recursion depth limits entirely (work stack lives on the heap)
50+
- Handles arbitrarily deep and wide dependency graphs
51+
- Improves debuggability with explicit state in work items
52+
- Follows proven patterns already established in the codebase
53+
54+
Verification
55+
------------
56+
57+
- All existing unit and e2e tests must pass unchanged
58+
- Bootstrap output for the same inputs must be identical
59+
- Performance should remain within 10% of the recursive version
60+
- Rollback via ``git revert`` if issues are discovered post-merge

0 commit comments

Comments
 (0)