Skip to content

Commit

Permalink
sentinel value and checks for common substring
Browse files Browse the repository at this point in the history
This is mainly for fetch, which doesn't output anything. Without this,
it crashes after trying to get the first message.

The common substring code is a bit ugly to handle potentially empty
messages, but with use of options this should always return a bool,
rather than crashing on indexing.
  • Loading branch information
ChrisDavison committed Feb 26, 2024
1 parent 581dbd9 commit 4eba5a5
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 46 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "repoutil"
version = "0.27.1"
version = "0.27.2"
authors = ["Chris Davison <c.jr.davison@gmail.com>"]
edition = "2018"
license = "MIT"
Expand Down
45 changes: 22 additions & 23 deletions src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,38 +43,41 @@ pub fn stat(p: &Path, as_json: bool) -> Result<Option<String>> {
// We have an 'ahead', 'behind' or similar, so free to return the status early
if as_json {
Ok(Some(format!(
"{{\"title\": \"{}\", \"subtitle\": \"{}\"}}",
p.display(),
out_lines[0]
"{{\"title\": \"{}\", \"subtitle\": \"{}\"}}",
p.display(),
out_lines[0]
)))
} else {
Ok(Some(format!("{}\n{}\n", p.display(), out_lines.join("\n"))))
}
} else {
// We aren't ahead or behind etc, but may have local uncommitted changes
let status: String = out_lines.iter().skip(1).map(|x| x.to_string()).collect::<Vec<String>>().join("\n");
let status: String = out_lines
.iter()
.skip(1)
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("\n");
if status.is_empty() {
Ok(None)
} else if as_json {
Ok(Some(format!(
"{{\"title\": \"{}\", \"subtitle\": \"{}\"}}",
p.display(),
status
)))
} else {
if as_json {
Ok(Some(format!(
"{{\"title\": \"{}\", \"subtitle\": \"{}\"}}",
p.display(),
status
))
)
} else {
Ok(Some(format!("{}\n{}\n", p.display(), status)))
}
Ok(Some(format!("{}\n{}\n", p.display(), status)))
}
}
}

fn ahead_behind(p: &Path) -> Result<Option<String>> {
let response: String = command_output(
p,
"status --porcelain --ahead-behind -b",
)?.into_iter().next().filter(|x| x.contains("[")).unwrap_or(String::new());
let response: String = command_output(p, "status --porcelain --ahead-behind -b")?
.into_iter()
.next()
.filter(|x| x.contains('['))
.unwrap_or(String::new());
Ok(if response.is_empty() {
None
} else {
Expand Down Expand Up @@ -160,11 +163,7 @@ pub fn branchstat(p: &Path, as_json: bool) -> Result<Option<String>> {
p.display(),
)
} else {
format!(
"{:50} | {}",
p.display(),
outputs
)
format!("{:50} | {}", p.display(), outputs)
}))
}
}
Expand Down
56 changes: 35 additions & 21 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anyhow::{anyhow, Result};
use rayon::prelude::*;
use std::fs::read_dir;
use std::path::{Path, PathBuf};
use structopt::StructOpt;
use rayon::prelude::*;

use shellexpand::tilde;

Expand Down Expand Up @@ -45,32 +45,43 @@ enum OptCommand {

fn common_substring<T: ToString>(ss: &[T]) -> String {
let mut idx = 0;
let charlists = ss.iter().map(|x| x.to_string().chars().collect()).collect::<Vec<Vec<char>>>();
if charlists.is_empty() {
return "".to_string();
}
let first_charlist = &charlists[0];
loop {
if !index_is_common(ss, idx) {
let first = first_charlist.iter().nth(idx);
if !charlists
.iter()
.all(|w| w.iter().nth(idx) == first)
{
break;
}
idx += 1;
}
ss[0].to_string().chars().take(idx).collect()
}

fn index_is_common<T: ToString>(ss: &[T], idx: usize) -> bool {
let first = ss[0].to_string().chars().nth(idx).unwrap();
ss.iter().all(|w| w.to_string().chars().nth(idx).unwrap() == first)
}

#[cfg(test)]
mod tests {
use super::common_substring;

#[test]
fn test_common_substring() {
assert_eq!(common_substring(&["aaa", "aab", "aac"]), "aa");
assert_eq!(common_substring(&["/home/cdavison/code", "/home/cdavison/code/recipes", "/home/cdavison/strathclyde"]), "/home/cdavison/");
assert_eq!(common_substring::<&str>(&[]), "");
assert_eq!(
common_substring(&[
"/home/cdavison/code",
"/home/cdavison/code/recipes",
"/home/cdavison/strathclyde"
]),
"/home/cdavison/"
);
}
}


type Command = fn(&Path, bool) -> Result<Option<String>>;

fn parse_args() -> (Command, bool) {
Expand All @@ -92,16 +103,17 @@ fn parse_args() -> (Command, bool) {

fn main() {
let (cmd, json) = parse_args();

let all_repos = get_repos_from_config().expect("Couldn't get repos");

let mut messages: Vec<_> = all_repos.par_iter().map(|repo| {
match cmd(repo, json) {
let mut messages: Vec<_> = all_repos
.par_iter()
.map(|repo| match cmd(repo, json) {
Ok(Some(out)) => out,
Err(e) => format!("ERR Repo {}: {}", repo.display(), e),
_ => String::new(),
}
}).collect();
})
.collect();

messages.sort();
let messages = messages.iter().filter(|msg| !msg.is_empty());
Expand All @@ -114,10 +126,12 @@ fn main() {
.join(",")
);
} else {
let messages = messages
.map(|x| x.to_string())
.collect::<Vec<String>>();
let common = common_substring(&messages);
let messages = messages.map(|x| x.to_string()).collect::<Vec<String>>();
let common = if messages.is_empty() {
String::new()
} else {
common_substring(&messages)
};
for msg in messages {
println!("{}", msg.replace(&common, ""))
}
Expand All @@ -130,14 +144,14 @@ fn get_dirs_from_config() -> Result<(Vec<PathBuf>, Vec<PathBuf>)> {

if !p.exists() {
return Err(anyhow!("No ~/.repoutilrc, or passed dirs"));
}
}

let mut includes = Vec::new();
let mut excludes = Vec::new();
for line in std::fs::read_to_string(p)?.lines() {
if line.starts_with('!') {
if let Some(stripped) = line.strip_prefix('!') {
// Strip 'exclusion-marking' ! from start of path, and add to excludes list
excludes.push(PathBuf::from(tilde(&line[1..]).to_string()));
excludes.push(PathBuf::from(tilde(stripped).to_string()));
} else {
includes.push(PathBuf::from(tilde(&line).to_string()));
}
Expand Down

0 comments on commit 4eba5a5

Please sign in to comment.