Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
7306475
Cargo.toml: Add `miette` and `thiserror` as dependencies
fischeti Jan 10, 2026
5d67d0e
error: Initial implementation of Warnings and suppression
fischeti Jan 10, 2026
026953d
errorr: Improve `emit` function
fischeti Jan 10, 2026
d8cc84d
Cargo.toml: Add `owo-colors` as dependency
fischeti Jan 10, 2026
d3c5d40
error: Nicely format warning messages
fischeti Jan 10, 2026
1f17037
sess: Add diagnostics handler
fischeti Jan 10, 2026
e6c1ce4
error: Add first warning
fischeti Jan 10, 2026
4c72646
error: Force dimming again after styled messages
fischeti Jan 10, 2026
e9a76a1
error: Add `emit_if` wrapper function
fischeti Jan 10, 2026
a57ed6e
error: Make Diagnostic a global static variable
fischeti Jan 10, 2026
113d1d1
error: Make `emit` a function of `Warning` itself
fischeti Jan 10, 2026
4bd2481
error: Drop `emitted` manually
fischeti Jan 10, 2026
c2c71ce
error: Migrate some warnings
fischeti Jan 10, 2026
4ea3b4e
error: Render multiple help messages
fischeti Jan 10, 2026
e61a777
error: Specify severity globally for `Warning`
fischeti Jan 11, 2026
e3c352d
error: Add suppression annotation below warning
fischeti Jan 11, 2026
9f5f088
error: Move W16 to `Warnings` (duplicates!)
fischeti Jan 11, 2026
7d80b3f
error: Export format macros
fischeti Jan 11, 2026
c2ae983
error: Migrate more warnings
fischeti Jan 11, 2026
4cea9ab
error: Replace deprecated `ATOMIC_BOOL_INIT`
fischeti Jan 11, 2026
b9a80d7
error: Remove `warnln` macro
fischeti Jan 11, 2026
cedb691
sess: Don't pass `suppress_warnings` anymore
fischeti Jan 11, 2026
8d528b3
error: Add unit tests
fischeti Jan 11, 2026
240b9ac
error: Add note on use of struct/tuple in enum variants
fischeti Jan 11, 2026
4facd23
error: Fix merge conflicts
fischeti Jan 12, 2026
ce302b9
cli: Fix some merge conflicts
fischeti Jan 14, 2026
05e719c
Fix clippy warnings
fischeti Jan 14, 2026
9c30dbd
Move Warnings into `diagnostics`
fischeti Jan 14, 2026
6c0a7c5
error: Rename formatting macros and move to `util`
fischeti Jan 14, 2026
02efe00
diagnostic: Differentiate W06 warnings
fischeti Jan 14, 2026
bbffaf9
diagnostics: Remove suppression hint, show code again
fischeti Jan 14, 2026
ddb5ba3
diagnostic: Consistently format `version` and `revision`
fischeti Jan 14, 2026
a02fb4d
diagnostic: Fix/duplicate W19 warning
fischeti Jan 14, 2026
b7601c1
diagnostic: Warning todo comments
fischeti Jan 14, 2026
35b4c0c
cargo: Add new dependencies
fischeti Dec 30, 2025
41c6afb
progress: Implementation and initial integration of progress bars
fischeti Dec 31, 2025
777c4e8
sess: Fix compiler warnings
fischeti Dec 31, 2025
4e00733
progress: Get rid of the `Sub` prefix for submodules
fischeti Dec 31, 2025
1e092d9
progress: Clean up a bit
fischeti Dec 31, 2025
3c6a6c3
sess: Wrap Progress handlers in `Some`
fischeti Dec 31, 2025
8ba15b8
git: Don't report progress when fetching tags
fischeti Jan 1, 2026
4a2c048
progress: Don't set length multiple times
fischeti Jan 1, 2026
6daa218
progress: Refactor
fischeti Jan 1, 2026
8c43f57
progress: Don't allow clones of Progresshandlers
fischeti Jan 1, 2026
2648fd1
Format sources
fischeti Jan 1, 2026
c8ff082
error: Suspend progress bars while printing errors and warnings
fischeti Jan 1, 2026
8293d3c
sess: Format sources
fischeti Jan 1, 2026
b048384
progress: Print completion message
fischeti Jan 2, 2026
bda0008
progress: Print duration of git operation
fischeti Jan 2, 2026
84c61fe
progress: Stylistic changes
fischeti Jan 2, 2026
2c84fdf
progress: Add `Submodule` operations
fischeti Jan 2, 2026
b959309
sess: Remove progress bars for disk operations
fischeti Jan 2, 2026
18a2c70
progress: Improve time formatting
fischeti Jan 2, 2026
1d1a5b9
progress: Mention submodules in completed message
fischeti Jan 2, 2026
5c09b3a
progress: Improve display for submodules
fischeti Jan 2, 2026
0fd7016
progress: Stylistic changes for submodules
fischeti Jan 2, 2026
d2b6b7e
error: Align styling with progress bar
fischeti Jan 2, 2026
df1bc3a
error: Add formatting macros
fischeti Jan 2, 2026
e88547d
error: Align `stageln` to other macros
fischeti Jan 2, 2026
79bae95
error: Rename `Note` to `Info`
fischeti Jan 2, 2026
22f2088
util: Move formatting duration to `util`
fischeti Jan 2, 2026
1352dbb
checkout: Print out total elapsed time for checkout
fischeti Jan 2, 2026
96efd58
progress: Print out git error messages
fischeti Jan 2, 2026
e22b228
progress: Show all submodules as tree structure
fischeti Jan 2, 2026
131afca
progress: Add more unit tests
fischeti Jan 2, 2026
371bc19
progress: Prefer `format` over `to_string()`
fischeti Jan 2, 2026
773264c
progress: Don't check for ASCII characters
fischeti Jan 2, 2026
f003b8c
progress: Change the order of functions, enums and impl blocks
fischeti Jan 2, 2026
b400287
progress: Clean up and document
fischeti Jan 2, 2026
c827f66
git: Selectively throttle git spawns
fischeti Jan 3, 2026
b53ebfc
cmd(checkout): Use public function to determine number of packages
fischeti Jan 6, 2026
c026621
util: Fix merge conflict mistake
fischeti Jan 6, 2026
cc3383a
progress: Small style changes
fischeti Jan 8, 2026
9fe1448
progress: Color in progress operations in cyan
fischeti Jan 12, 2026
ae8cc60
progress: Reword in progress messages
fischeti Jan 12, 2026
5a06e75
Fix merge conflicts
fischeti Jan 14, 2026
82924a6
diagnostic: Register multiprogressbar in `Diagnostic`
fischeti Jan 15, 2026
e5c6cbb
progress: Replace `console` with `owo_colors`
fischeti Jan 15, 2026
8564741
progress: Fix clippy warnings and clean up
fischeti Jan 15, 2026
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
362 changes: 293 additions & 69 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ glob = "0.3"
walkdir = "2"
subst = "0.3"
tera = "1.19"
miette = { version = "7.6.0", features = ["fancy"] }
thiserror = "2.0.17"
owo-colors = "4.2.3"
indicatif = "0.18.3"
regex = "1.12.2"

[target.'cfg(windows)'.dependencies]
dunce = "1.0.4"
Expand Down
46 changes: 20 additions & 26 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! Main command line tool implementation.

use std;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use std::process::Command as SysCommand;

Expand All @@ -22,6 +23,7 @@ use tokio::runtime::Runtime;
use crate::cmd;
use crate::cmd::fusesoc::FusesocArgs;
use crate::config::{Config, Manifest, Merge, PartialConfig, PrefixPaths, Validate};
use crate::diagnostic::{Diagnostics, Warnings};
use crate::error::*;
use crate::lockfile::*;
use crate::sess::{Session, SessionArenas, SessionIo};
Expand Down Expand Up @@ -113,8 +115,9 @@ pub fn main() -> Result<()> {
// Parse command line arguments.
let cli = Cli::parse();

let mut suppressed_warnings: IndexSet<String> =
let mut suppressed_warnings: HashSet<String> =
cli.suppress.into_iter().map(|s| s.to_owned()).collect();

// split suppress strings on commas and spaces
suppressed_warnings = suppressed_warnings
.into_iter()
Expand All @@ -125,9 +128,9 @@ pub fn main() -> Result<()> {
})
.collect();

if suppressed_warnings.contains("all") || suppressed_warnings.contains("Wall") {
suppressed_warnings.extend((1..24).map(|i| format!("W{:02}", i)));
}
let warn_config_loaded = !suppressed_warnings.contains("W02");

Diagnostics::init(suppressed_warnings);

#[cfg(debug_assertions)]
if cli.debug {
Expand All @@ -147,7 +150,7 @@ pub fn main() -> Result<()> {
}

let force_fetch = match cli.command {
Commands::Update(ref args) => cmd::update::setup(args, cli.local, &suppressed_warnings)?,
Commands::Update(ref args) => cmd::update::setup(args, cli.local)?,
_ => false,
};

Expand All @@ -165,14 +168,13 @@ pub fn main() -> Result<()> {

// Parse the manifest file of the package.
let manifest_path = root_dir.join("Bender.yml");
let manifest = read_manifest(&manifest_path, &suppressed_warnings)?;
let manifest = read_manifest(&manifest_path)?;
debugln!("main: {:#?}", manifest);

// Gather and parse the tool configuration.
let config = load_config(
&root_dir,
matches!(cli.command, Commands::Update(_)) && !suppressed_warnings.contains("W02"),
&suppressed_warnings,
matches!(cli.command, Commands::Update(_)) && warn_config_loaded,
)?;
debugln!("main: {:#?}", config);

Expand All @@ -189,7 +191,6 @@ pub fn main() -> Result<()> {
cli.local,
force_fetch,
git_throttle,
suppressed_warnings,
);

if let Commands::Clean(args) = cli.command {
Expand Down Expand Up @@ -252,13 +253,7 @@ pub fn main() -> Result<()> {
)
})?;
if !meta.file_type().is_symlink() {
if !sess.suppress_warnings.contains("W01") {
warnln!(
"[W01] Skipping link to package {} at {:?} since there is something there",
pkg_name,
path
);
}
Warnings::SkippingPackageLink(pkg_name.clone(), path.clone()).emit();
continue;
}
if path.read_link().map(|d| d != pkg_path).unwrap_or(true) {
Expand Down Expand Up @@ -398,7 +393,7 @@ fn find_package_root(from: &Path) -> Result<PathBuf> {
}

/// Read a package manifest from a file.
pub fn read_manifest(path: &Path, suppress_warnings: &IndexSet<String>) -> Result<Manifest> {
pub fn read_manifest(path: &Path) -> Result<Manifest> {
use crate::config::PartialManifest;
use std::fs::File;
debugln!("read_manifest: {:?}", path);
Expand All @@ -409,16 +404,12 @@ pub fn read_manifest(path: &Path, suppress_warnings: &IndexSet<String>) -> Resul
partial
.prefix_paths(path.parent().unwrap())
.map_err(|cause| Error::chain(format!("Error in manifest prefixing {:?}.", path), cause))?
.validate("", false, suppress_warnings)
.validate("", false)
.map_err(|cause| Error::chain(format!("Error in manifest {:?}.", path), cause))
}

/// Load a configuration by traversing a directory hierarchy upwards.
fn load_config(
from: &Path,
warn_config_loaded: bool,
suppress_warnings: &IndexSet<String>,
) -> Result<Config> {
fn load_config(from: &Path, warn_config_loaded: bool) -> Result<Config> {
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;

Expand Down Expand Up @@ -491,7 +482,7 @@ fn load_config(

// Validate the configuration.
let mut out = out
.validate("", false, suppress_warnings)
.validate("", false)
.map_err(|cause| Error::chain("Invalid configuration:", cause))?;

out.overrides = out
Expand All @@ -515,8 +506,11 @@ fn maybe_load_config(path: &Path, warn_config_loaded: bool) -> Result<Option<Par
let partial: PartialConfig = serde_yaml_ng::from_reader(file)
.map_err(|cause| Error::chain(format!("Syntax error in config {:?}.", path), cause))?;
if warn_config_loaded {
warnln!("[W02] Using config at {:?} for overrides.", path)
};
Warnings::UsingConfigForOverride {
path: path.to_path_buf(),
}
.emit();
}
Ok(Some(partial.prefix_paths(path.parent().unwrap())?))
}

Expand Down
10 changes: 10 additions & 0 deletions src/cmd/checkout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
//! The `checkout` subcommand.

use clap::Args;
use owo_colors::OwoColorize;
use tokio::runtime::Runtime;

use crate::error::*;
use crate::sess::{Session, SessionIo};
use crate::util::fmt_duration;

/// Checkout all dependencies referenced in the Lock file
#[derive(Args, Debug)]
Expand All @@ -26,7 +28,15 @@ pub fn run(sess: &Session, args: &CheckoutArgs) -> Result<()> {
pub fn run_plain(sess: &Session, force: bool, update_list: &[String]) -> Result<()> {
let rt = Runtime::new()?;
let io = SessionIo::new(sess);
let start_time = std::time::Instant::now();
let _srcs = rt.block_on(io.sources(force, update_list))?;
let num_dependencies = io.sess.packages().iter().flatten().count();
infoln!(
"{} {} dependencies {}",
"Checked out".dimmed(),
num_dependencies,
fmt_duration(start_time.elapsed()).dimmed()
);

Ok(())
}
11 changes: 4 additions & 7 deletions src/cmd/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use tokio::runtime::Runtime;

use crate::config;
use crate::config::{Locked, LockedSource};
use crate::diagnostic::Warnings;
use crate::error::*;
use crate::sess::{DependencyRef, DependencySource, Session, SessionIo};

Expand Down Expand Up @@ -138,8 +139,8 @@ pub fn run(sess: &Session, path: &Path, args: &CloneArgs) -> Result<()> {
{
Err(Error::new("git fetch failed".to_string()))?;
}
} else if !sess.suppress_warnings.contains("W14") {
warnln!("[W14] fetch not performed due to --local argument.");
} else {
Warnings::LocalNoFetch.emit();
}

eprintln!(
Expand Down Expand Up @@ -263,11 +264,7 @@ pub fn run(sess: &Session, path: &Path, args: &CloneArgs) -> Result<()> {
)
})?;
if !meta.file_type().is_symlink() {
warnln!(
"[W15] Skipping link to package {} at {:?} since there is something there",
pkg_name,
link_path
);
Warnings::SkippingPackageLink(pkg_name.clone(), link_path.to_path_buf()).emit();
continue;
}
if link_path.read_link().map(|d| d != pkg_path).unwrap_or(true) {
Expand Down
5 changes: 3 additions & 2 deletions src/cmd/fusesoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use itertools::Itertools;
use tokio::runtime::Runtime;
use walkdir::{DirEntry, WalkDir};

use crate::diagnostic::Warnings;
use crate::error::*;
use crate::sess::{Session, SessionIo};
use crate::src::{SourceFile, SourceGroup};
Expand Down Expand Up @@ -132,8 +133,8 @@ pub fn run_single(sess: &Session, args: &FusesocArgs) -> Result<()> {
Error::chain(format!("Unable to write corefile for {:?}.", &name), cause)
})?;

if fuse_depend_string.len() > 1 && !sess.suppress_warnings.contains("W16") {
warnln!("[W16] Depend strings may be wrong for the included dependencies!");
if fuse_depend_string.len() > 1 {
Warnings::DependStringMaybeWrong.emit();
}

Ok(())
Expand Down
36 changes: 25 additions & 11 deletions src/cmd/parents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use std::io::Write;

use crate::diagnostic::Warnings;
use clap::Args;
use indexmap::IndexMap;
use tabwriter::TabWriter;
Expand All @@ -14,6 +15,7 @@ use crate::config::Dependency;
use crate::error::*;
use crate::sess::{DependencyConstraint, DependencySource};
use crate::sess::{Session, SessionIo};
use crate::{fmt_path, fmt_pkg, fmt_version};

/// List packages calling this dependency
#[derive(Args, Debug)]
Expand Down Expand Up @@ -96,12 +98,21 @@ pub fn run(sess: &Session, args: &ParentsArgs) -> Result<()> {
}
);

if sess.config.overrides.contains_key(dep) && !sess.suppress_warnings.contains("W18") {
warnln!(
"[W18] An override is configured for {} to {:?}",
dep,
sess.config.overrides[dep]
)
if sess.config.overrides.contains_key(dep) {
Warnings::DepOverride {
pkg: dep.to_string(),
pkg_override: match sess.config.overrides[dep] {
Dependency::Version(ref v, _) => format!("version {}", fmt_version!(v)),
Dependency::Path(ref path, _) => format!("path {}", fmt_path!(path.display())),
Dependency::GitRevision(ref url, ref rev, _) => {
format!("git {} at revision {}", fmt_path!(url), fmt_version!(rev))
}
Dependency::GitVersion(ref url, ref version, _) => {
format!("git {} with version {}", fmt_path!(url), fmt_pkg!(version))
}
},
}
.emit();
}

Ok(())
Expand Down Expand Up @@ -150,9 +161,10 @@ pub fn get_parent_array(
let dep_manifest = rt.block_on(io.dependency_manifest(pkg, false, &[]))?;
// Filter out dependencies without a manifest
if dep_manifest.is_none() {
if !sess.suppress_warnings.contains("W17") {
warnln!("[W17] {} is shown to include dependency, but manifest does not have this information.", pkg_name.to_string());
Warnings::IncludeDepManifestMismatch {
pkg: pkg_name.to_string(),
}
.emit();
continue;
}
let dep_manifest = dep_manifest.unwrap();
Expand Down Expand Up @@ -182,9 +194,11 @@ pub fn get_parent_array(
],
);
}
} else if !sess.suppress_warnings.contains("W17") {
// Filter out dependencies with mismatching manifest
warnln!("[W17] {} is shown to include dependency, but manifest does not have this information.", pkg_name.to_string());
} else {
Warnings::IncludeDepManifestMismatch {
pkg: pkg_name.to_string(),
}
.emit();
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ pub fn run(sess: &Session, args: &ScriptArgs) -> Result<()> {
let srcs = srcs
.flatten()
.into_iter()
.map(|f| f.validate("", false, &sess.suppress_warnings))
.map(|f| f.validate("", false))
.collect::<Result<Vec<_>>>()?;

let mut tera_context = Context::new();
Expand Down
13 changes: 3 additions & 10 deletions src/cmd/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use tokio::runtime::Runtime;

use crate::cmd::clone::{get_path_subdeps, symlink_dir};
use crate::config::{Dependency, Locked, LockedSource};
use crate::diagnostic::Warnings;
use crate::error::*;
use crate::sess::{DependencySource, Session, SessionIo};

Expand Down Expand Up @@ -57,11 +58,7 @@ pub fn run(sess: &Session, args: &SnapshotArgs) -> Result<()> {
.is_empty()
&& !args.no_skip
{
warnln!(
"Skipping dirty dependency {}\
\t use `--no-skip` to still snapshot.",
name
);
Warnings::SkippingDirtyDep { pkg: name.clone() }.emit();
continue;
}

Expand Down Expand Up @@ -255,11 +252,7 @@ pub fn run(sess: &Session, args: &SnapshotArgs) -> Result<()> {
)
})?;
if !meta.file_type().is_symlink() {
warnln!(
"[W15] Skipping link to package {} at {:?} since there is something there",
pkg_name,
link_path
);
Warnings::SkippingPackageLink(pkg_name.clone(), link_path.to_path_buf()).emit();
continue;
}
if link_path.read_link().map(|d| d != pkg_path).unwrap_or(true) {
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ pub fn run(sess: &Session, args: &SourcesArgs) -> Result<()> {
srcs = srcs.filter_packages(packages).unwrap_or_default();
}

srcs = srcs.validate("", false, &sess.suppress_warnings)?;
srcs = srcs.validate("", false)?;

let result = {
let stdout = std::io::stdout();
Expand Down
9 changes: 4 additions & 5 deletions src/cmd/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use tabwriter::TabWriter;

use crate::cmd;
use crate::config::{Locked, LockedPackage};
use crate::diagnostic::Warnings;
use crate::error::*;
use crate::lockfile::*;
use crate::resolver::DependencyResolver;
Expand Down Expand Up @@ -42,11 +43,9 @@ pub struct UpdateArgs {
}

/// Execute the `update` subcommand.
pub fn setup(args: &UpdateArgs, local: bool, suppress_warnings: &IndexSet<String>) -> Result<bool> {
if local && args.fetch && !suppress_warnings.contains("W14") {
warnln!(
"[W14] As --local argument is set for bender command, no fetching will be performed."
);
pub fn setup(args: &UpdateArgs, local: bool) -> Result<bool> {
if local && args.fetch {
Warnings::LocalNoFetch.emit();
}
Ok(args.fetch)
}
Expand Down
Loading