Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-03-16
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
## Context

The current installation flow in UVM has a `ProgressHandler` trait defined but is barely utilized. The `Loader` struct in `uvm_install/src/install/loader.rs` has optional progress handler support, but it's never actually wired up from the CLI layer. Users see only initial and final messages during what can be multi-gigabyte downloads and complex multi-component installations.

The existing architecture is already structured for progress reporting:
- `ProgressHandler` trait exists with `finish()`, `inc()`, `set_length()`, `set_position()` methods
- `Loader` has optional progress handler support
- `DownloadProgress` wrapper implements incremental progress updates during HTTP transfers

The `uvm` CLI binary already depends on `indicatif` 0.18.0, which provides cross-platform progress bars and multi-progress support for concurrent operations.

## Goals / Non-Goals

**Goals:**
- Provide real-time visual feedback during download operations with size/speed metrics
- Show clear phase transitions (fetching metadata → downloading → extracting → installing)
- Display component-level progress when installing multiple modules
- Summarize installation results (time taken, data downloaded, components installed)
- Maintain backward compatibility with existing error handling

**Non-Goals:**
- Progress reporting for non-installation operations (launch, list, detect)
- Machine-readable progress output (JSON/structured logging)
- Progress persistence across process restarts
- Parallel download optimization (only progress reporting, not concurrency changes)

## Decisions

### Decision 1: Use `indicatif` for progress rendering
**Rationale:** Already a dependency in `uvm` crate, mature library with excellent cross-platform support, handles multi-progress scenarios elegantly.

**Alternatives considered:**
- Custom progress implementation → Too much complexity for terminal handling, cursor control, etc.
- `pbr` crate → Less active maintenance, fewer features
- Simple print statements → Poor UX, no dynamic updates

### Decision 2: Implement progress at CLI layer, not library layer
**Rationale:** Keep `uvm_install` library agnostic of terminal UI concerns. The CLI creates and passes progress handlers to the library, maintaining separation of concerns.

**Alternatives considered:**
- Build `indicatif` into `uvm_install` → Creates unnecessary dependency for library users
- Create abstract progress types in library → Over-engineering for single use case

**Implementation approach:**
- Create concrete `ProgressHandler` implementation in `uvm/src/commands/install.rs`
- Pass it to `InstallOptions` via new builder method
- Wire through to `Loader` and installer implementations

### Decision 3: Multi-progress for component installations
**Rationale:** When installing editor + multiple modules, show overall progress plus individual component progress. Uses `indicatif::MultiProgress` to handle the hierarchy.

**Structure:**
```
Overall: [===========> ] 3/7 components
├─ Editor 2022.3.0f1: [================] 2.1 GB/2.1 GB
├─ Android Support: [=====> ] 512 MB/1.5 GB
└─ iOS Support: [ ] Waiting...
```

### Decision 4: Progress phases
**Phases to report:**
1. **Fetching metadata** - GraphQL API call (spinner, no progress bar)
2. **Resolving dependencies** - Graph construction (spinner)
3. **Downloading** - Per-component progress bars with size/speed
4. **Installing** - Per-component spinner/progress (platform-specific)
5. **Summary** - Final statistics

**Rationale:** Matches natural user mental model of installation flow.

### Decision 5: Extend `ProgressHandler` trait minimally
**Current trait is sufficient for downloads.** For installation phases (extraction), add optional method:
```rust
fn set_message(&self, msg: &str) {} // Default no-op
```

This allows spinners to show context ("Extracting pkg...", "Running installer...") without breaking existing interface.

### Decision 6: Integrate logging with indicatif
**Rationale:** UVM uses `flexi_logger` with `log` crate. When progress bars are active, log messages must be routed through indicatif to prevent corruption of progress display.

**Implementation approach:**
- Use `indicatif::MultiProgress::println()` or `ProgressBar::suspend()` for log output
- Create custom log writer that detects active progress bars and routes accordingly
- Check `std::io::IsTerminal` for stdout/stderr to detect piping
- In non-interactive mode, use normal logging without indicatif routing

**TTY/Pipe detection:**
```rust
use std::io::IsTerminal;

let is_interactive = std::io::stdout().is_terminal()
&& std::io::stderr().is_terminal()
&& std::env::var("CI").is_err();
```

**Alternatives considered:**
- Ignore logging compatibility → Log messages would corrupt progress bars at verbose levels
- Disable logging when progress active → Loses important debug information
- Use separate terminal for logs → Not practical for CLI tool

## Risks / Trade-offs

**Risk:** Progress bars may flicker or display incorrectly on exotic terminals
→ **Mitigation:** `indicatif` handles this well; fallback to simple logging if progress rendering fails

**Risk:** Installation phases without deterministic progress (platform installers) may show indefinite spinners
→ **Mitigation:** Acceptable UX - spinner indicates activity, better than silence

**Risk:** Added overhead from progress updates in tight loops
→ **Mitigation:** `indicatif` is optimized for this; updates are rate-limited automatically

**Trade-off:** Multi-progress output requires terminal height; may not fit on small terminals
→ **Mitigation:** `indicatif` handles overflow by scrolling; users on tiny terminals are rare edge case

**Trade-off:** Dependency on `indicatif` already exists in CLI but not in `uvm_install`
→ **Decision:** Keep it this way - library stays lean, CLI handles presentation

**Risk:** Logging integration with `flexi_logger` may be complex
→ **Mitigation:** Use MultiProgress as global state accessible to custom log writer; fallback to standard output if setup fails

**Risk:** Piped output may still show progress artifacts
→ **Mitigation:** Strict TTY detection on both stdout and stderr before enabling progress bars

## Migration Plan

**Deployment:**
1. Add progress handler implementation to CLI (`uvm/src/commands/install.rs`)
2. Extend `InstallOptions` builder with `with_progress_handler()` method
3. Wire progress through `Loader` and installer create functions
4. Add optional progress calls to platform-specific installers

**Rollback strategy:**
- Progress is additive only; no breaking changes
- If issues arise, can disable progress by not passing handler (defaults to `None`)
- Feature can be controlled via flag if needed: `--no-progress`

**Testing:**
- Manual testing on macOS, Linux, Windows
- Test with single component and multi-component installations
- Verify graceful degradation in non-TTY environments (CI, redirected output)

## Open Questions

None - design is straightforward enhancement to existing architecture.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Why

The current Unity installation process provides minimal progress feedback, making it difficult for users to understand what's happening during downloads and installations. Users only see initial request messages and final success/failure messages, leaving them in the dark during the lengthy download and installation phases. This poor user experience makes the tool feel unresponsive and creates uncertainty about whether the installation is proceeding correctly.

## What Changes

- Add visual progress indicators for download operations showing current progress, total size, and download speed
- Display clear status messages for each installation phase (downloading, extracting, installing, verifying)
- Show component-level progress when installing modules with dependencies
- Provide summary statistics at completion (total time, data downloaded, components installed)
- Maintain current error handling while improving error context presentation

## Capabilities

### New Capabilities
- `installation-progress`: Visual progress reporting for downloads, extraction, and installation phases with component tracking and summary statistics

### Modified Capabilities
<!-- Existing capabilities whose REQUIREMENTS are changing (not just implementation).
Only list here if spec-level behavior changes. Each needs a delta spec file.
Use existing spec names from openspec/specs/. Leave empty if no requirement changes. -->

## Impact

- **CLI**: `uvm/src/commands/install.rs` - integrate progress reporting into install command
- **Installer Core**: `uvm_install/src/lib.rs` - wire up progress handlers during installation
- **Download Logic**: `uvm_install/src/install/loader.rs` - enhance ProgressHandler implementation with download metrics
- **Platform Installers**: `uvm_install/src/sys/*/` - add progress hooks to extraction/installation phases
- **Dependencies**: Add progress bar library (e.g., `indicatif`) for cross-platform terminal progress display
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
## ADDED Requirements

### Requirement: Display download progress with metrics
The system SHALL display real-time download progress for each installer component including current size, total size, download speed, and estimated time remaining.

#### Scenario: Download progress updates during file transfer
- **WHEN** a Unity installer package is being downloaded
- **THEN** the system displays a progress bar showing bytes downloaded, total bytes, current speed in MB/s, and updates at least once per second

#### Scenario: Multiple components show individual progress
- **WHEN** installing Unity editor with multiple modules
- **THEN** each component displays its own progress bar with individual download metrics

#### Scenario: Download completes successfully
- **WHEN** a component download reaches 100%
- **THEN** the progress bar shows completion state and total time taken

### Requirement: Display installation phase status
The system SHALL clearly indicate the current installation phase with descriptive status messages for metadata fetching, dependency resolution, downloading, extracting, and installing.

#### Scenario: Metadata fetch phase
- **WHEN** installation begins
- **THEN** system displays a spinner with message "Fetching Unity version metadata..."

#### Scenario: Dependency resolution phase
- **WHEN** metadata is fetched and dependency graph is being built
- **THEN** system displays a spinner with message "Resolving component dependencies..."

#### Scenario: Download phase with component name
- **WHEN** downloading a specific component
- **THEN** system displays the component name and version being downloaded

#### Scenario: Extraction phase
- **WHEN** extracting an installer package
- **THEN** system displays a spinner with message indicating extraction is in progress

#### Scenario: Installation phase
- **WHEN** running platform-specific installer
- **THEN** system displays a spinner with message indicating installation is in progress

### Requirement: Show multi-component installation hierarchy
The system SHALL display overall installation progress when multiple components are being installed, showing total component count and individual component status.

#### Scenario: Overall progress with component count
- **WHEN** installing editor and 3 modules
- **THEN** system displays "Installing 4 components" with overall progress indicator

#### Scenario: Component status hierarchy
- **WHEN** multiple components are being installed
- **THEN** system displays a hierarchical view with overall progress at top and individual component progress below

#### Scenario: Pending components indication
- **WHEN** some components are waiting for dependencies
- **THEN** those components display "Waiting..." or "Pending..." status

### Requirement: Provide installation summary statistics
The system SHALL display summary statistics upon completion including total time elapsed, total data downloaded, number of components installed, and final installation path.

#### Scenario: Successful installation summary
- **WHEN** installation completes successfully
- **THEN** system displays total time, data downloaded in GB/MB, component count, and installation directory path

#### Scenario: Summary includes all downloaded data
- **WHEN** multiple components are downloaded
- **THEN** summary aggregates total bytes downloaded across all components

#### Scenario: Time formatting
- **WHEN** displaying elapsed time
- **THEN** system formats time appropriately (seconds for <60s, minutes:seconds for <1h, hours:minutes:seconds for >=1h)

### Requirement: Handle non-TTY and piped output gracefully
The system SHALL detect non-interactive terminal environments (CI, piped stdout/stderr) and disable progress bars entirely, falling back to simple text milestone messages.

#### Scenario: Non-TTY detection via stdout
- **WHEN** stdout is not a TTY (e.g., redirected to file)
- **THEN** system outputs simple text progress messages without progress bars or escape codes

#### Scenario: Piped output detection
- **WHEN** stdout or stderr is piped to another process
- **THEN** system disables progress bars and outputs only milestone messages

#### Scenario: Progress messages in non-interactive mode
- **WHEN** running in non-interactive mode
- **THEN** system outputs milestone messages like "Downloading component X...", "Downloaded X (Y MB)", "Installing X..."

#### Scenario: CI environment detection
- **WHEN** running in CI environment (CI=true env var or non-TTY)
- **THEN** system disables all progress bars and spinners

### Requirement: Integrate with logging system
The system SHALL route log messages through indicatif when progress bars are active to prevent log output from corrupting progress display, and SHALL respect log level settings.

#### Scenario: Log messages with active progress bars
- **WHEN** progress bars are displayed and log messages are emitted
- **THEN** system routes log output through indicatif's println/suspend methods to appear above progress bars

#### Scenario: Verbose logging compatibility
- **WHEN** user sets verbose log levels (debug, trace)
- **THEN** log messages appear correctly without interfering with progress bar rendering

#### Scenario: Log output in non-interactive mode
- **WHEN** running in non-interactive mode (no progress bars)
- **THEN** log messages output normally via standard logging without indicatif routing

#### Scenario: Logger initialization with progress support
- **WHEN** installing with progress bars enabled
- **THEN** system configures logging to use indicatif-compatible output methods

### Requirement: Preserve error reporting
The system SHALL maintain existing error messages and context when errors occur during any installation phase, ensuring errors are visible regardless of progress display state.

#### Scenario: Error during download
- **WHEN** a download fails with network error
- **THEN** system clears progress display and shows error message with context

#### Scenario: Error during installation
- **WHEN** platform installer fails
- **THEN** system clears progress display and shows error message with exit code and component name

#### Scenario: Error message visibility
- **WHEN** any error occurs during installation
- **THEN** error message is displayed prominently and not obscured by progress indicators
Loading
Loading