uvm_detect 1.1.1

Unity project detection and version extraction library
Documentation
# uvm_detect

A Rust library for detecting Unity projects and extracting Unity version information from project directories.

## Overview

`uvm_detect` provides utilities to:
- 🔍 **Detect Unity projects** by searching for Unity project structure markers
- 📋 **Extract Unity version information** from ProjectVersion.txt files
- 🔄 **Support configurable recursive searching** with depth control
-**Builder pattern API** similar to `std::fs::OpenOptions` for clean configuration
- 🎯 **Follow Rust conventions** with proper error handling and idiomatic patterns

## Features

- **Builder Pattern API**: Clean, chainable configuration similar to `std::fs::OpenOptions`
- **Project Detection**: Automatically locate Unity projects in directories
- **Version Parsing**: Extract Unity editor versions from project files
- **Flexible Search**: Support both current-directory and recursive searching
- **Depth Control**: Configure maximum search depth to prevent excessive traversal
- **Robust Error Handling**: Distinguish between different failure modes
- **Cross-Platform**: Works consistently on Windows, macOS, and Linux
- **Minimal Dependencies**: Only `unity-version` for version parsing

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
uvm_detect = "0.1.0"
```

## Usage

### Basic Project Detection

```rust
use std::path::Path;
use uvm_detect::DetectOptions;

// Search for Unity project in current directory only
match DetectOptions::new().detect_unity_project_dir(Path::new(".")) {
    Ok(project_path) => {
        println!("Found Unity project at: {}", project_path.display());
    }
    Err(_) => {
        println!("No Unity project found in current directory");
    }
}
```

### Recursive Project Search

```rust
use std::path::Path;
use uvm_detect::DetectOptions;

// Search recursively through subdirectories
match DetectOptions::new()
    .recursive(true)
    .detect_unity_project_dir(Path::new("./projects")) {
    Ok(project_path) => {
        println!("Found Unity project at: {}", project_path.display());
    }
    Err(_) => {
        println!("No Unity project found in projects directory or subdirectories");
    }
}
```

### Recursive Search with Depth Limit

```rust
use std::path::Path;
use uvm_detect::DetectOptions;

// Search recursively but only 3 levels deep
match DetectOptions::new()
    .recursive(true)
    .max_depth(3)
    .detect_unity_project_dir(Path::new("./projects")) {
    Ok(project_path) => {
        println!("Found Unity project at: {}", project_path.display());
    }
    Err(_) => {
        println!("No Unity project found within 3 directory levels");
    }
}
```

### Extract Unity Version

```rust
use std::path::Path;
use uvm_detect::DetectOptions;

// Get Unity version from a project directory
match DetectOptions::new()
    .recursive(true)
    .max_depth(5)
    .detect_project_version(Path::new("./my-unity-project")) {
    Ok(version) => {
        println!("Unity version: {}", version);
    }
    Err(e) => {
        println!("Failed to detect Unity version: {}", e);
    }
}
```

### Convenience Functions

For simple use cases, convenience functions are available:

```rust
use std::path::Path;
use uvm_detect::{detect_unity_project_dir, detect_project_version, try_get_project_version};

// Simple project detection (non-recursive)
if let Ok(project_path) = detect_unity_project_dir(Path::new(".")) {
    println!("Found Unity project at: {}", project_path.display());
}

// Simple version detection (non-recursive)
if let Ok(version) = detect_project_version(Path::new("./my-unity-project")) {
    println!("Unity version: {}", version);
}

// Check if a directory contains Unity project structure
if let Some(version_file_path) = try_get_project_version(Path::new("./suspected-unity-project")) {
    println!("Found Unity project! ProjectVersion.txt at: {}", version_file_path.display());
} else {
    println!("Not a Unity project directory");
}
```

## Unity Project Structure

This library detects Unity projects by looking for the standard Unity project structure:

```
UnityProject/
├── ProjectSettings/
│   └── ProjectVersion.txt    ← This file is the detection marker
├── Assets/
├── Library/
└── ...
```

The `ProjectVersion.txt` file contains Unity editor version information in formats like:

```
m_EditorVersion: 2021.3.16f1
m_EditorVersionWithRevision: 2021.3.16f1 (4016570cf34f)
```

## API Reference

### DetectOptions

The main configuration struct that provides a builder-style API for configuring Unity project detection.

#### Methods

##### `DetectOptions::new() -> Self`

Creates a new `DetectOptions` with default settings:
- `recursive`: false (search only in specified directory)
- `max_depth`: u32::MAX (unlimited depth when recursive)
- `case_sensitive`: true (for future use)

##### `recursive(&mut self, recursive: bool) -> &mut Self`

Sets whether to search recursively through subdirectories.

##### `max_depth(&mut self, max_depth: u32) -> &mut Self`

Sets the maximum depth to search when recursive search is enabled. Use `u32::MAX` for unlimited depth.

##### `case_sensitive(&mut self, case_sensitive: bool) -> &mut Self`

Sets whether to use case-sensitive path matching (reserved for future functionality).

##### `detect_unity_project_dir(&self, dir: &Path) -> io::Result<PathBuf>`

Detects a Unity project directory using the configured options.

##### `detect_project_version(&self, dir: &Path) -> io::Result<Version>`

Detects and parses the Unity version from a Unity project using the configured options.

### Convenience Functions

#### `detect_unity_project_dir(dir: &Path) -> io::Result<PathBuf>`

Detects a Unity project directory using default options (non-recursive search).

#### `detect_project_version(project_path: &Path) -> io::Result<Version>`

Detects and parses the Unity version from a Unity project using default options.

#### `try_get_project_version<P: AsRef<Path>>(base_dir: P) -> Option<PathBuf>`

Attempts to get the path to the Unity ProjectVersion.txt file if it exists.

## Configuration Examples

### Complex Configuration

```rust
use std::path::Path;
use uvm_detect::DetectOptions;

let result = DetectOptions::new()
    .recursive(true)                // Enable recursive search
    .max_depth(10)                  // Limit to 10 directory levels
    .case_sensitive(true)           // Use case-sensitive matching (future)
    .detect_unity_project_dir(Path::new("./workspace"));

match result {
    Ok(project_path) => {
        println!("Found Unity project at: {}", project_path.display());
        
        // Now get the version from the found project
        let version = DetectOptions::new()
            .detect_project_version(&project_path)?;
        println!("Unity version: {}", version);
    }
    Err(e) => println!("No Unity project found: {}", e),
}
```

### Performance Considerations

```rust
// For large directory trees, limit depth to improve performance
let result = DetectOptions::new()
    .recursive(true)
    .max_depth(5)  // Only search 5 levels deep
    .detect_unity_project_dir(Path::new("./large-workspace"));
```

## Error Handling

The library uses Rust's standard error handling patterns:

- **`io::Result<T>`** for operations that can fail due to I/O errors or missing projects
- **`Option<T>`** for simple existence checks where absence isn't an error
- **Specific error messages** that help identify the type of failure

Common error scenarios:
- **NotFound**: No Unity project found in the specified directory (or within max_depth if recursive)
- **InvalidInput**: ProjectVersion.txt found but contains invalid version information
- **I/O errors**: Permission denied, file not accessible, etc.

## Testing

Run the test suite:

```bash
cargo test
```

The library includes comprehensive tests covering:
- ✅ Valid Unity project detection
- ❌ Non-Unity directory handling
- 🔄 Recursive search functionality
- 📏 Max depth limiting
- 📋 Version parsing with different formats
- 🚫 Malformed version handling
- 📁 Nested project structures
- 🛠️ Builder pattern chaining
- 🎯 Convenience functions

## Performance

- **Efficient traversal**: Stops at first Unity project found
- **Depth limiting**: Prevents excessive directory traversal
- **Early termination**: Returns immediately when project is found
- **Minimal allocations**: Uses efficient path handling

## Dependencies

- `unity-version` - For parsing Unity version strings
- `tempfile` (dev-dependency) - For creating temporary test directories

## License

This project is part of the Unity Version Manager (UVM) toolkit.

## Contributing

Contributions are welcome! Please ensure that:
- All tests pass (`cargo test`)
- Documentation tests compile (`cargo test --doc`)
- Code follows Rust conventions
- New features include appropriate tests
- Documentation is updated for API changes

## Related Projects

This crate is part of the larger Unity Version Manager ecosystem:
- `unity-version` - Unity version parsing and manipulation
- `uvm_install` - Unity installation management  
- `uvm` - Main CLI application

## Changelog

### v0.1.0
- Initial release with builder pattern API
- Support for recursive search with depth limiting
- Cross-platform compatibility
- Comprehensive test coverage
- Clean separation of concerns between detection and version parsing