Example Scenarios
Scenario 1: Initial Build
State: No DAG file exists
Flow:
init/4: Create empty DAGpopulate_sources/5: Add all sources- All files new
- Scan all dependencies
- Build complete graph
propagate_stamps/1: Propagate timestamps- Compilation proceeds
store_artifact/4: Track each.beammaybe_store/5: Save DAG to disk
Result: Full compilation, DAG saved
Scenario 2: Incremental Build (No Changes)
State: Valid DAG exists, no files modified
Flow:
init/4: Restore DAG from diskpopulate_sources/5: Check all sources- All timestamps match
- No scans needed
propagate_stamps/1: Skip (not dirty)needed_files/4: No files need compilation- Compilation skipped
maybe_store/5: Skip save (not dirty)
Result: No compilation, instant completion
Scenario 3: Single File Modified
Files:
src/mod_a.erl (modified)
src/mod_b.erl (unchanged)
src/mod_c.erl (unchanged, includes mod_a.hrl)
include/mod_a.hrl (unchanged)
DAG:
mod_a.erl (timestamp updated)
mod_b.erl → ...
mod_c.erl → mod_a.hrl
mod_a.hrl (unchanged)
Flow:
populate_sources/5: Detect mod_a.erl changed- Update vertex timestamp
propagate_stamps/1: No propagation (mod_a.hrl unchanged)- Compilation: Only mod_a.erl
store_artifact/4: Update mod_a.beam- Save DAG
Result: One file compiled
Scenario 4: Header File Modified
Files:
include/types.hrl (modified)
src/mod_a.erl → types.hrl
src/mod_b.erl → types.hrl
src/mod_c.erl (independent)
Flow:
populate_deps/3: Refresh types.hrl timestamppropagate_stamps/1:- types.hrl timestamp: 100 (new)
- mod_a.erl depends on types.hrl
- Update mod_a.erl timestamp: 100
- mod_b.erl depends on types.hrl
- Update mod_b.erl timestamp: 100
- mod_c.erl independent: unchanged
- Compilation: mod_a.erl, mod_b.erl
- Save DAG
Result: Two files compiled
Scenario 5: Transitive Dependencies
Files:
include/base.hrl (modified)
include/types.hrl → base.hrl
src/mod_a.erl → types.hrl
Flow:
- Refresh base.hrl: timestamp 100
- Propagate:
- types.hrl depends on base.hrl: update to 100
- mod_a.erl depends on types.hrl: update to 100
- Compilation: mod_a.erl
Result: Change propagates through chain
Scenario 6: Compiler Options Changed
Initial:
{erl_opts, [debug_info]}.
DAG Metadata: [{compiler_version, "8.0"}, {options, [debug_info]}]
Changed:
{erl_opts, [debug_info, inline]}.
Flow:
init/4: Restore DAG- Check critical metadata
- New options:
[debug_info, inline] - Mismatch detected (in compiler, not DAG module)
- All files marked for recompilation
- DAG updated with new metadata
- Save DAG
Result: Full rebuild with new options
Scenario 7: Inter-App Dependencies
Apps:
app_common: no deps
app_api: depends on app_common (parse_transform)
app_web: depends on app_api
DAG (file-level):
app_api/src/api_mod.erl → app_common/src/my_transform.erl
app_web/src/web_mod.erl → app_api/include/api.hrl
Flow:
compile_order/4: Build app-level DAG- Resolve file deps to apps:
- api_mod.erl in app_api
- my_transform.erl in app_common
- Add edge: app_api → app_common
- Similar for app_web → app_api
- Interleave sort
- Result:
[app_common, app_api, app_web]
Result: Apps compiled in correct order
Scenario 8: DAG Version Upgrade
Scenario: rebar3 upgraded, DAG version changes from 3 to 4
Flow:
init/4: Try restore DAG- Read file:
#dag{vsn = 3, ...} - Version mismatch: 3 ≠ 4
status/4returnsbad_vsn- Delete old DAG file
- Create new empty DAG
- Full rebuild
Result: Clean rebuild after upgrade