build: decouple Cargo.toml: split crate and workspace definitions

TL;DR: cargo clippy|check|... now runs on whole workspace by default.

## Steps

- add new workspace member `cloud-hypervisor`
- move `./src` to new workspace member
- move `./tests` to new workspace member
- move relevant parts from Cargo.toml to new workspace member
- kept necessary parts in main Cargo.toml, such as profile
  configurations

## About

The main Cargo.toml historically mixes workspace and crate definitions
for cloud-hypervisor and ch-remote. This makes it hard to read and
requires `--workspace` to run cargo clippy or cargo test on all
workspace members, which is counter-intuitive.

This patch separates the workspace from the crate definition in the main
Cargo.toml file. After this, cargo clippy, cargo test, etc., work on the
whole workspace naturally, giving a smoother developer experience. The
Cargo.toml without a package definition is also called a virtual
workspace or virtual manifest by Cargo [0].

Backporting is not a concern: CHV no longer backports, but the affected
files are rarely modified anyway.

[0] https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
This commit is contained in:
Philipp Schuster
2025-11-27 19:38:11 +01:00
committed by Rob Bradford
parent f104bcdb6b
commit 3d049765bd
9 changed files with 75 additions and 69 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
// Copyright © 2025 Cyberus Technology GmbH
//
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use log::error;
/// Prints a chain of errors to the user in a consistent manner.
/// The user will see a clear chain of errors, followed by debug output
/// for opening issues.
pub fn cli_print_error_chain<'a>(
top_error: &'a (dyn Error + 'static),
component: &str,
// Function optionally returning the display representation of an error.
display_modifier: impl Fn(
/* level */ usize,
/*indention */ usize,
&'a (dyn Error + 'static),
) -> Option<String>,
) {
// Debug info.
error!("Fatal error: {top_error:?}");
eprint!("Error: {component} exited with the following ");
if top_error.source().is_none() {
eprintln!("error:");
eprintln!(" {top_error}");
} else {
eprintln!("chain of errors:");
std::iter::successors(Some(top_error), |sub_error| {
// Dereference necessary to mitigate rustc compiler bug.
// See <https://github.com/rust-lang/rust/issues/141673>
(*sub_error).source()
})
.enumerate()
.for_each(|(level, error)| {
// Special case: handling of HTTP Server responses in ch-remote
if let Some(message) = display_modifier(level, 2, error) {
eprintln!("{message}");
} else {
eprintln!(" {level}: {error}");
}
});
}
}

2018
cloud-hypervisor/src/main.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
// Copyright © 2025 Cyberus Technology GmbH
//
// SPDX-License-Identifier: Apache-2.0
//
//! Test utilities.
use std::cmp::Ordering;
use clap::Arg;
/// Ensures that all [`Arg`]s are sorted alphabetically.
pub fn assert_args_sorted<'a, F: Fn() -> R, R: Iterator<Item = &'a Arg>>(get_base_iter: F) {
let iter = get_base_iter().zip(get_base_iter().skip(1));
for (arg, next) in iter {
assert_ne!(
arg.get_id().cmp(next.get_id()),
Ordering::Greater,
"args not alphabetically sorted: arg={}, next={}",
arg.get_id(),
next.get_id()
);
}
}