| Crates.io | lmrc-cargo-workspace |
| lib.rs | lmrc-cargo-workspace |
| version | 0.3.16 |
| created_at | 2025-11-26 17:43:56.420383+00 |
| updated_at | 2025-12-11 13:27:54.433896+00 |
| description | Cargo workspace management library for the LMRC Stack - comprehensive library for managing Cargo workspaces programmatically |
| homepage | https://gitlab.com/lemarco/lmrc-stack/tree/main/libs/cargo-workspace-manager |
| repository | https://gitlab.com/lemarco/lmrc-stack |
| max_upload_size | |
| id | 1951913 |
| size | 156,880 |
Part of the LMRC Stack - Infrastructure-as-Code toolkit for building production-ready Rust applications
A comprehensive Rust library for managing Cargo workspaces programmatically.
Add this to your Cargo.toml:
[dependencies]
lmrc-cargo-workspace = "0.1"
use lmrc_cargo_workspace::{
workspace::Workspace,
build::{WorkspaceBuilder, BuildConfig},
version::{VersionManager, BumpType, VersionUpdateStrategy},
dependency::DependencyGraph,
};
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Discover workspace
let workspace = Workspace::discover(Path::new("."))?;
println!("Found workspace at: {}", workspace.root.display());
// Analyze dependencies
let graph = DependencyGraph::from_workspace(&workspace)?;
let build_order = graph.topological_sort()?;
println!("Build order: {:?}", build_order);
// Build workspace
let builder = WorkspaceBuilder::new(&workspace);
let result = builder.build_all(&BuildConfig::default())?;
if result.success {
println!("Build succeeded!");
}
// Bump versions
let version_mgr = VersionManager::new(&workspace);
let changes = version_mgr.preview_changes(
VersionUpdateStrategy::BumpAll(BumpType::Patch)
)?;
for change in &changes {
println!("{}", change.description());
}
// Apply version changes
version_mgr.apply_changes(&changes)?;
Ok(())
}
use lmrc_cargo_workspace::workspace::Workspace;
use std::path::Path;
// Discover workspace from current directory
let workspace = Workspace::discover(Path::new("."))?;
// Or load from specific path
let workspace = Workspace::from_path(Path::new("/path/to/workspace"))?;
// Access workspace members
for member in &workspace.members {
println!("Member: {} at {}", member.name, member.path.display());
if member.is_library() {
println!(" Type: Library");
}
if member.is_binary() {
println!(" Type: Binary");
}
}
use lmrc_cargo_workspace::{workspace::Workspace, dependency::DependencyGraph};
let workspace = Workspace::discover(Path::new("."))?;
let graph = DependencyGraph::from_workspace(&workspace)?;
// Get dependencies of a crate
let deps = graph.workspace_dependencies("my-crate");
for dep in deps {
println!("Depends on: {}", dep.name);
}
// Get reverse dependencies (what depends on this crate)
let dependents = graph.dependents("my-lib");
println!("Crates depending on my-lib: {:?}", dependents);
// Get build order (topological sort)
let order = graph.topological_sort()?;
println!("Build in this order: {:?}", order);
// Check for circular dependencies
graph.check_circular_dependencies()?;
use lmrc_cargo_workspace::{
workspace::Workspace,
version::{VersionManager, BumpType, VersionUpdateStrategy},
};
use semver::Version;
let workspace = Workspace::discover(Path::new("."))?;
let version_mgr = VersionManager::new(&workspace);
// Bump all crates by patch version
let changes = version_mgr.update_versions(
VersionUpdateStrategy::BumpAll(BumpType::Patch)
)?;
// Or bump specific crates
let mut bumps = std::collections::HashMap::new();
bumps.insert("crate-a".to_string(), BumpType::Major);
bumps.insert("crate-b".to_string(), BumpType::Minor);
let changes = version_mgr.update_versions(
VersionUpdateStrategy::BumpIndividual(bumps)
)?;
// Set all crates to same version
let changes = version_mgr.update_versions(
VersionUpdateStrategy::Unified(Version::new(2, 0, 0))
)?;
// Preview changes before applying
for change in &changes {
println!("{}", change.description());
}
// Apply changes
version_mgr.apply_changes(&changes)?;
use lmrc_cargo_workspace::{
workspace::Workspace,
build::{WorkspaceBuilder, BuildConfig, TestConfig, BuildProfile},
};
let workspace = Workspace::discover(Path::new("."))?;
let builder = WorkspaceBuilder::new(&workspace);
// Build all members in release mode
let mut config = BuildConfig::default();
config.profile = BuildProfile::Release;
config.all_features = true;
let result = builder.build_all(&config)?;
// Build specific member
let result = builder.build_member("my-crate", &config)?;
// Run tests
let mut test_config = TestConfig::default();
test_config.nocapture = true;
let result = builder.test_all(&test_config)?;
// Check code without building
let result = builder.check_all(&BuildConfig::default())?;
use lmrc_cargo_workspace::manifest::Manifest;
use semver::Version;
use std::path::Path;
let mut manifest = Manifest::from_path(Path::new("Cargo.toml"))?;
// Update package version
manifest.set_package_version(&Version::new(2, 0, 0))?;
// Update dependency version
manifest.update_dependency("serde", "2.0", "dependencies")?;
// Check if it's a workspace
if manifest.is_workspace() {
let members = manifest.workspace_members()?;
println!("Workspace members: {:?}", members);
}
// Save changes (preserves formatting and comments)
manifest.save()?;
use lmrc_cargo_workspace::{
selective::MemberSelector,
build::{BuildConfig, TestConfig},
};
let workspace = Workspace::discover(Path::new("."))?;
// Build only binaries
let results = MemberSelector::new(&workspace)
.binaries_only()
.build(&BuildConfig::default())?;
// Build crates matching a pattern
let results = MemberSelector::new(&workspace)
.by_pattern("*-core")?
.build(&BuildConfig::default())?;
// Test only changed crates since a git ref
let results = MemberSelector::new(&workspace)
.changed_since("main")?
.with_dependents()? // Include crates that depend on changes
.test(&TestConfig::default())?;
// Build in parallel respecting dependency order
let results = MemberSelector::new(&workspace)
.all()
.build_parallel(&BuildConfig::default())?;
use lmrc_cargo_workspace::metadata::CargoMetadata;
let metadata = CargoMetadata::load(&workspace.root)?;
// Check for duplicate dependency versions
let duplicates = metadata.find_duplicate_versions();
for (dep, versions) in duplicates {
println!("{} has versions: {}", dep, versions.join(", "));
}
// Collect license information
let licenses = metadata.collect_licenses();
for (license, packages) in licenses {
println!("{}: {} packages", license, packages.len());
}
// Access resolved dependency information
for package in metadata.workspace_packages() {
println!("{} v{}", package.name, package.version);
for dep in &package.dependencies {
if dep.is_normal() {
println!(" - {} {}", dep.name, dep.req);
}
}
}
use lmrc_cargo_workspace::validation::Validator;
let validator = Validator::new(&workspace);
// Check version consistency
let issues = validator.check_version_consistency()?;
// Check for circular dependencies
let issues = validator.check_circular_dependencies()?;
// Check code formatting
let issues = validator.check_formatting()?;
// Check with clippy
let issues = validator.check_clippy()?;
// Run all validations
let result = validator.validate_all()?;
if result.has_errors() {
println!("Errors: {}", result.errors().len());
}
if result.has_warnings() {
println!("Warnings: {}", result.warnings().len());
}
println!("{}", result.summary());
Full API documentation is available at docs.rs.
workspace: Workspace discovery and member enumerationmanifest: Cargo.toml parsing and manipulation with format preservationdependency: Dependency graph analysis and topological sortingversion: Semver version management and updatesbuild: Programmatic build and test operationsselective: Selective build/test operations based on patterns, changes, or dependenciesmetadata: Cargo metadata integration for resolved dependency informationvalidation: Workspace validation and lintingerror: Comprehensive error typesAll operations return Result<T, Error> with detailed error information:
use lmrc_cargo_workspace::{workspace::Workspace, error::Error};
match Workspace::discover(Path::new(".")) {
Ok(workspace) => println!("Found workspace!"),
Err(Error::WorkspaceNotFound(path)) => {
eprintln!("No workspace found at: {}", path.display());
}
Err(Error::InvalidManifest { path, reason }) => {
eprintln!("Invalid manifest at {}: {}", path.display(), reason);
}
Err(e) => eprintln!("Error: {}", e),
}
Contributions are welcome! Please feel free to submit issues and pull requests.
Part of the LMRC Stack project. Licensed under either of:
at your option.
This library uses: