Skip to content

Commit

Permalink
Merge branch 'main' into release/1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
9999years authored Apr 3, 2024
2 parents 7be09a6 + e807f8e commit 735c43b
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 92 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fs-err = "2.11.0"
itertools = "0.12.1"
miette = { version = "7.2.0", default-features = false, features = ["fancy-no-backtrace"] }
owo-colors = { version = "4.0.0", features = ["supports-colors"] }
parking_lot = "0.12.1"
regex = "1.10.4"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"
Expand All @@ -32,6 +33,7 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter", "registry"]
utf8-command = "1.0.1"

[dev-dependencies]
indoc = "2.0.5"
pretty_assertions = "1.4.0"

# See: https://github.com/crate-ci/cargo-release/blob/master/docs/reference.md
Expand Down
27 changes: 0 additions & 27 deletions src/chain.rs

This file was deleted.

16 changes: 12 additions & 4 deletions src/change_number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use std::fmt::Display;
use clap::builder::RangedU64ValueParser;
use clap::builder::TypedValueParser;
use clap::builder::ValueParserFactory;
use owo_colors::OwoColorize;
use owo_colors::Stream::Stderr;
use owo_colors::Style;

use crate::gerrit::Gerrit;

Expand Down Expand Up @@ -38,10 +41,15 @@ impl ChangeNumber {
}

pub fn pretty(&self, gerrit: &Gerrit) -> miette::Result<String> {
Ok(match gerrit.get_change(*self)?.subject {
Some(subject) => format!("{} ({})", self, subject),
None => self.to_string(),
})
let subject = gerrit.get_change(*self)?.subject;
Ok(format!(
"{}{}",
self.if_supports_color(Stderr, |change| Style::new().bold().green().style(change)),
subject
.map(|subject| format!(" ({subject})"))
.unwrap_or_default()
.if_supports_color(Stderr, |subject| Style::new().dimmed().style(subject))
))
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct Opts {
/// except the level are optional.
///
/// Try `debug` or `trace`.
#[arg(long, default_value = "info", env = "GAYRAT_LOG")]
#[arg(long, default_value = "info", env = "GIT_GR_LOG")]
pub log: String,

#[command(subcommand)]
Expand Down
88 changes: 78 additions & 10 deletions src/depends_on.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::VecDeque;
use std::sync::Arc;

use miette::miette;
use miette::Context;
use parking_lot::Mutex;

use crate::change_id::ChangeId;
use crate::change_number::ChangeNumber;
use crate::format_bulleted_list;
use crate::gerrit::Gerrit;
use crate::unicode_tree::Tree;

/// A change that the current change depends on.
#[derive(serde::Deserialize, Debug)]
Expand All @@ -34,25 +38,30 @@ pub struct DependsOnRelation {
}

/// A graph of change dependencies.
#[derive(Debug, Default)]
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct DependsOnGraph {
pub root: ChangeNumber,
dependencies: BTreeMap<ChangeNumber, ChangeNumber>,
reverse_dependencies: BTreeMap<ChangeNumber, BTreeSet<ChangeNumber>>,
}

impl DependsOnGraph {
pub fn new() -> Self {
Self::default()
pub fn new(root: ChangeNumber) -> Self {
Self {
root,
dependencies: Default::default(),
reverse_dependencies: Default::default(),
}
}

pub fn traverse(gerrit: &Gerrit, root: ChangeNumber) -> miette::Result<Self> {
let mut dependency_graph = Self::new();
let mut dependency_graph = Self::new(root);
let mut seen = BTreeSet::new();
seen.insert(root);
let mut queue = VecDeque::new();
queue.push_front(root);

while !queue.is_empty() {
let change = queue.pop_back().expect("Length is checked");
while let Some(change) = queue.pop_back() {
let dependencies = gerrit
.dependencies(change)
.wrap_err("Failed to get change dependencies")?
Expand Down Expand Up @@ -111,15 +120,15 @@ impl DependsOnGraph {
/// Get the root dependency changes in the graph.
///
/// These are the changes that do not depend on any other changes.
pub fn depends_on_roots(&mut self, change: ChangeNumber) -> BTreeSet<ChangeNumber> {
pub fn depends_on_roots(&mut self) -> BTreeSet<ChangeNumber> {
let mut roots = BTreeSet::new();

let mut seen = BTreeSet::new();
seen.insert(self.root);
let mut queue = VecDeque::new();
queue.push_front(change);
queue.push_front(self.root);

while !queue.is_empty() {
let change = queue.pop_back().expect("Length is checked");
while let Some(change) = queue.pop_back() {
match self.depends_on(change) {
Some(depends_on) => {
if !seen.contains(&depends_on) {
Expand All @@ -135,4 +144,63 @@ impl DependsOnGraph {

roots
}

pub fn dependency_root(&mut self) -> miette::Result<ChangeNumber> {
let mut roots = self.depends_on_roots();
match roots.len() {
1 => Ok(roots.pop_first().expect("Length is checked")),
_ => Err(miette!(
"Expected to find exactly one root change, but found {}:\n{}",
roots.len(),
format_bulleted_list(roots.iter())
)),
}
}

pub fn format_tree(
&mut self,
gerrit: &Gerrit,
mut extra_label: impl FnMut(ChangeNumber) -> miette::Result<Vec<String>>,
) -> miette::Result<String> {
let mut trees = BTreeMap::<ChangeNumber, Arc<Mutex<Tree>>>::new();
let root = self.dependency_root()?;

let mut seen = BTreeSet::new();
seen.insert(root);
let mut queue = VecDeque::new();
queue.push_front(root);

while let Some(change) = queue.pop_back() {
let tree = Arc::clone(match trees.entry(change) {
Entry::Vacant(entry) => {
let mut label = vec![change.pretty(gerrit)?];
label.extend(extra_label(change)?);
entry.insert(Arc::new(Mutex::new(Tree::leaf(label))))
}
Entry::Occupied(entry) => entry.into_mut(),
});

let needed_by = self.needed_by(change);
for reverse_dependency in needed_by {
let reverse_dependency_tree = Arc::clone(match trees.entry(*reverse_dependency) {
Entry::Vacant(entry) => {
let mut label = vec![reverse_dependency.pretty(gerrit)?];
label.extend(extra_label(*reverse_dependency)?);
entry.insert(Arc::new(Mutex::new(Tree::leaf(label))))
}
Entry::Occupied(entry) => entry.into_mut(),
});
tree.lock().children.push(reverse_dependency_tree);

if !seen.contains(reverse_dependency) {
seen.insert(*reverse_dependency);
queue.push_front(*reverse_dependency);
}
}
}

let tree = trees.get(&root).expect("Root should have a tree").lock();

Ok(tree.to_string())
}
}
9 changes: 6 additions & 3 deletions src/gerrit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use regex::Regex;
use serde::de::DeserializeOwned;
use utf8_command::Utf8Output;

use crate::chain::Chain;
use crate::change_number::ChangeNumber;
use crate::depends_on::DependsOnGraph;
use crate::format_bulleted_list;
use crate::git::Git;
use crate::query::Query;
Expand Down Expand Up @@ -171,10 +171,13 @@ impl Gerrit {
.ok_or_else(|| miette!("Didn't find change {change}"))
}

pub fn dependency_graph<'a>(&self, change: impl Into<Query<'a>>) -> miette::Result<Chain> {
pub fn dependency_graph<'a>(
&self,
change: impl Into<Query<'a>>,
) -> miette::Result<DependsOnGraph> {
let change = change.into();
let change = self.get_change(change)?;
Chain::new(self, change.number)
DependsOnGraph::traverse(self, change.number)
}

fn cl_ref<'a>(&self, change: impl Into<Query<'a>>) -> miette::Result<String> {
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
mod approval;
mod author;
mod chain;
mod change_id;
mod change_number;
mod cli;
Expand All @@ -16,6 +15,7 @@ mod query_result;
mod restack;
mod restack_push;
mod tmpdir;
mod unicode_tree;

use calm_io::stdoutln;
use clap::CommandFactory;
Expand Down
Loading

0 comments on commit 735c43b

Please sign in to comment.