ccgo 3.7.1

A high-performance C++ cross-platform build CLI
# Transitive Dependency Resolution

> **See also:** [`dependency-linkage.md`]dependency-linkage.md for how each fetched dep is integrated into your build product (shared-external vs static-embedded vs static-external).

## Overview

CCGO now supports automatic transitive dependency resolution. When you run `ccgo install`, it automatically discovers and installs dependencies of your dependencies, determines the correct build order, and detects circular dependencies.

## Resolution priority

For each `[[dependencies]]` entry, `ccgo fetch` decides where the bytes
come from by walking these source kinds in order. The first one that
matches the dep's declared fields wins:

1. **`path = "..."`** — local path dependency. Symlinked or copied
   from the relative/absolute path in the consumer's tree.
2. **`git = "..."` (with `branch` / `tag` / `rev`)** — Git dependency.
   Cloned shallowly into `~/.ccgo/git/<repo>/`.
3. **`zip = "..."`** — archive dependency. Downloaded (`https://`) or
   read (`file://`, local path) and extracted into `.ccgo/deps/<name>/`.
4. **Registry resolution** — when `[registries]` is non-empty AND the
   dep has no `path`/`git`/`zip` source. ccgo walks declared registries
   (or just the one named by `[[dependencies]].registry`) in TOML
   declaration order, takes the first non-yanked exact-version match,
   then chooses one of two sub-paths:
   * **Archive** — when the matched `VersionEntry.archive_url` is set:
     download those bytes, SHA-256-verify, extract.
   * **Git+tag fallback** — when `archive_url` is absent but
     `PackageEntry.repository` is set (which `ccgo publish index`
     always populates from the project's `git remote`): `git clone
     --branch <tag>` the source repo. The lockfile records
     `source = "registry+<index-url>"` and `locked.git.revision` for
     deterministic re-fetch.

   See [`features/registry.md`]features/registry.md for the index
   schema and the `[registries]` configuration syntax.
5. **Version-only local cache fallback** — when nothing above resolves
   AND the dep has a non-empty `version`. ccgo looks under
   `~/.ccgo/packages/<name>/<version>/` (the cache populated by
   `ccgo install` in the source project) and copies that into
   `.ccgo/deps/<name>/`. This mirrors the Cargo / Maven workflow where
   the dep is identified by name+version and the location lives entirely
   in a developer-machine cache.

When step 4 returns "no match" it falls through cleanly to step 5 —
existing `version`-only deps that don't appear in any configured registry
keep working unchanged. When `[registries]` is empty, step 4 is skipped
entirely. This is what makes the registry tier opt-in and incremental:
older `git`/`zip` declarations stay valid forever.

## Features

### 1. Transitive Dependency Discovery

When installing a dependency that has its own `CCGO.toml` file with dependencies, CCGO will:
- Automatically read the dependency's CCGO.toml
- Discover its dependencies (transitive dependencies)
- Recursively resolve all dependencies in the entire dependency tree
- Handle both git and path dependencies

### 2. Dependency Graph Visualization

CCGO displays a visual tree of your dependencies showing:
- Direct dependencies (declared in your CCGO.toml)
- Transitive dependencies (dependencies of dependencies)
- Shared dependencies (used by multiple packages)
- Source information (git URL, path, version)

Example output:
```
Dependency tree:
mylib v1.0.0
├── fmt v9.1.0 (git: https://github.com/fmtlib/fmt)
│   └── gtest v1.12.0 (git: https://github.com/google/googletest)
└── json v3.11.2 (git: https://github.com/nlohmann/json)

3 unique dependencies found, 4 total (1 shared)
```

### 3. Topological Sorting for Build Order

CCGO uses topological sorting to determine the correct installation order:
- Dependencies with no dependencies are installed first
- Dependencies are installed before their dependents
- Ensures builds succeed by respecting dependency chains

Example:
```
📦 Installing in dependency order:
  1. gtest
  2. fmt
  3. mylib
```

### 4. Circular Dependency Detection

CCGO detects circular dependencies and reports them with the full cycle path:

```
Error: Circular dependency detected: libA -> libB -> libC -> libA
```

### 5. Version Conflict Warnings

When multiple packages depend on different versions of the same dependency, CCGO:
- Warns about version conflicts
- Uses the first version encountered (for now)
- Displays clear warnings to help resolve conflicts

Example:
```
⚠️  Version conflict for 'fmt': have 9.1.0, need 10.0.0
```

### 6. Max Depth Protection

To prevent infinite recursion, CCGO limits dependency depth to 50 levels and reports an error if exceeded.

## Implementation

### Architecture

The dependency resolution system consists of three main components:

#### 1. Dependency Graph (`src/dependency/graph.rs`)

- **DependencyNode**: Represents a single dependency with metadata
- **DependencyGraph**: Manages the entire dependency graph
- **Cycle Detection**: DFS-based algorithm to find circular dependencies
- **Topological Sort**: Kahn's algorithm for build order
- **Tree Formatting**: Pretty-print dependency tree
- **Statistics**: Calculate unique, shared, and total dependencies

#### 2. Dependency Resolver (`src/dependency/resolver.rs`)

- **DependencyResolver**: Main resolver that orchestrates dependency resolution
- **Recursive Resolution**: Traverses dependency tree recursively
- **Path Resolution**: Handles relative paths in transitive dependencies
- **Caching**: Visited set prevents duplicate processing
- **Error Handling**: Graceful degradation on resolution failures

#### 3. Install Command Integration (`src/commands/install.rs`)

- Calls resolver to build dependency graph
- Displays dependency tree and statistics
- Uses topological sort for installation order
- Falls back to direct dependencies on errors
- Installs dependencies in correct order

### Data Structures

```rust
pub struct DependencyNode {
    pub name: String,
    pub version: String,
    pub source: String,              // git+url or path+path
    pub dependencies: Vec<String>,   // Direct dependencies
    pub depth: usize,                // Depth in dependency tree
    pub config: DependencyConfig,    // Original config
}

pub struct DependencyGraph {
    nodes: HashMap<String, DependencyNode>,
    edges: Vec<(String, String)>,    // (from, to) edges
    roots: HashSet<String>,          // Root dependencies
}
```

### Key Algorithms

#### Cycle Detection (DFS)

```rust
pub fn detect_cycles(&self) -> Option<Vec<String>>
```

Uses depth-first search with a recursion stack to detect cycles. Returns the cycle path if found.

#### Topological Sort (Kahn's Algorithm)

```rust
pub fn topological_sort(&self) -> Result<Vec<String>>
```

Implements Kahn's algorithm with in-degree calculation to determine build order.

## Usage

### Basic Usage

Simply run `ccgo install` and CCGO will automatically:
1. Resolve transitive dependencies
2. Display the dependency tree
3. Show installation order
4. Install all dependencies in correct order

```bash
ccgo install
```

### What Gets Resolved

Given this project structure:

**Project CCGO.toml:**
```toml
[package]
name = "myapp"
version = "1.0.0"

[[dependencies]]
name = "libA"
version = "1.0.0"
path = "../libA"
```

**libA CCGO.toml:**
```toml
[package]
name = "libA"
version = "1.0.0"

[[dependencies]]
name = "libB"
version = "2.0.0"
path = "../libB"
```

**libB CCGO.toml:**
```toml
[package]
name = "libB"
version = "2.0.0"
# No dependencies
```

Running `ccgo install` will:
1. Discover libA (direct dependency)
2. Read libA's CCGO.toml
3. Discover libB (transitive dependency)
4. Read libB's CCGO.toml
5. Determine order: libB → libA → myapp
6. Install libB first, then libA

## Testing

The implementation includes comprehensive tests:

### Unit Tests

Located in `src/dependency/resolver.rs` and `src/dependency/graph.rs`:

- **test_simple_resolution**: Basic single dependency
- **test_transitive_dependencies**: Chain of dependencies (A → B → C)
- **test_circular_dependency_detection**: Detect cycles (A → B → C → A)
- **test_shared_dependency**: Diamond pattern (A → C, B → C)
- **test_missing_ccgo_toml**: Handle dependencies without CCGO.toml
- **test_version_conflict_warning**: Detect version conflicts
- **test_max_depth_exceeded**: Prevent infinite recursion
- **test_simple_graph**: Basic graph operations
- **test_cycle_detection**: Cycle detection algorithm
- **test_shared_dependency** (graph): Shared dependency statistics

Run tests with:
```bash
cargo test dependency
```

## Limitations & Future Work

### Current Limitations

1. **Version Resolution**: Currently uses "first version wins" strategy. Need proper semantic versioning resolution.
2. **Workspace Dependencies**: Not yet fully implemented for workspace inheritance.
3. **Lockfile**: No lockfile generation yet for reproducible builds.
4. **Dependency Patching**: No support for overriding transitive dependencies.

### Planned Enhancements

1. **Smart Version Resolution**:
   - Semantic versioning awareness
   - Minimum version selection
   - Version constraint satisfaction

2. **Lockfile Support**:
   - Generate CCGO.lock with exact versions
   - Verify lockfile on install
   - Update command to refresh lockfile

3. **Dependency Vendoring**:
   - Download and cache dependencies
   - Offline build support
   - Reproducible builds

4. **Dependency Overrides**:
   - Patch dependencies via CCGO.toml
   - Replace URLs for mirroring
   - Version pinning

5. **Build-time Dependencies**:
   - Separate build-only dependencies
   - Development dependencies
   - Optional dependencies

## Related Files

- `src/dependency/mod.rs` - Module definition
- `src/dependency/graph.rs` - Dependency graph implementation (~450 lines)
- `src/dependency/resolver.rs` - Dependency resolver (~620 lines)
- `src/commands/install.rs` - Install command integration
- `src/config/ccgo_toml.rs` - CCGO.toml configuration

## References

- **Topological Sorting**: [Kahn's Algorithm]https://en.wikipedia.org/wiki/Topological_sorting
- **Cycle Detection**: [Depth-First Search]https://en.wikipedia.org/wiki/Cycle_detection
- **Semantic Versioning**: [semver.org]https://semver.org/

## Changelog

### v3.0.11 (2025-01-21)

- ✅ Implemented transitive dependency resolution
- ✅ Added dependency graph with cycle detection
- ✅ Added topological sorting for correct build order
- ✅ Added dependency tree visualization
- ✅ Added version conflict detection (warnings only)
- ✅ Integrated into install command
- ✅ Added comprehensive test suite (7 resolver tests + 3 graph tests)

---

*This feature is part of the Rust CLI rewrite (spec 001-rust-cli-rewrite) to achieve zero Python dependency.*