History

[hours-demo] clap

Sebastian Thiel committed 5 years ago

Commit b0e4f041 parent 17258cc3 files · +61 −34Browse files

Unified · Split

3 files
  1. Cargo.lock +13 −1
  2. examples/hours/Cargo.toml +1 −1
  3. examples/hours/src/main.rs +47 −32
Cargo.lock+13−1
@@ -272,6 +272,7 @@ dependencies = [ · 271 unmodified lines
272 "os_str_bytes",272 "os_str_bytes",
273 "strsim",273 "strsim",
274 "termcolor",274 "termcolor",
275 "terminal_size",
275 "textwrap 0.12.1",276 "textwrap 0.12.1",
276 "unicode-width",277 "unicode-width",
277 "vec_map",278 "vec_map",
@@ -1067,7 +1068,7 @@ name = "hours" · 789 unmodified lines
1067version = "0.1.0"1068version = "0.1.0"
1068dependencies = [1069dependencies = [
1069 "anyhow",1070 "anyhow",
1070 "dashmap",1071 "clap 3.0.0-beta.2",
1071 "git-hash",1072 "git-hash",
1072 "git-object",1073 "git-object",
1073 "git-odb",1074 "git-odb",
@@ -2024,6 +2025,16 @@ dependencies = [ · 950 unmodified lines
2024 "winapi-util",2025 "winapi-util",
2025]2026]
2026 2027
2028[[package]]
2029name = "terminal_size"
2030version = "0.1.16"
2031source = "registry+https://github.com/rust-lang/crates.io-index"
2032checksum = "86ca8ced750734db02076f44132d802af0b33b09942331f4459dde8636fd2406"
2033dependencies = [
2034 "libc",
2035 "winapi",
2036]
2037
2027[[package]]2038[[package]]
2028name = "termion"2039name = "termion"
2029version = "1.5.6"2040version = "1.5.6"
@@ -2051,6 +2062,7 @@ version = "0.12.1" · 21 unmodified lines
2051source = "registry+https://github.com/rust-lang/crates.io-index"2062source = "registry+https://github.com/rust-lang/crates.io-index"
2052checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"2063checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
2053dependencies = [2064dependencies = [
2065 "terminal_size",
2054 "unicode-width",2066 "unicode-width",
2055]2067]
2056 2068
examples/hours/Cargo.toml+1−1
@@ -14,5 +14,5 @@ git-traverse = { version = "0.1", path = "../../git-traverse" } · 13 unmodified lines
14git-hash = { version = "^0.3", path = "../../git-hash" }14git-hash = { version = "^0.3", path = "../../git-hash" }
15git-object = { version = "^0.8", path = "../../git-object" }15git-object = { version = "^0.8", path = "../../git-object" }
16rayon = "1.5.0"16rayon = "1.5.0"
17dashmap = "4.0.2"
18itertools = "0.10.0"17itertools = "0.10.0"
18clap = { version = "=3.0.0-beta.2", default-features = true, features = ["wrap_help"] }
examples/hours/src/main.rs+47−32
@@ -1,44 +1,59 @@
1use anyhow::{anyhow, bail};1use anyhow::{anyhow, bail};
2use clap::Clap;
2use git_hash::{bstr::ByteSlice, ObjectId};3use git_hash::{bstr::ByteSlice, ObjectId};
3use git_object::bstr::BString;4use git_object::bstr::BString;
4use git_odb::find::FindExt;5use git_odb::find::FindExt;
5use git_traverse::commit;6use git_traverse::commit;
6use itertools::Itertools;7use itertools::Itertools;
7use rayon::prelude::*;8use rayon::prelude::*;
8use std::{path::PathBuf, time::Instant};9use std::{
10 ffi::{OsStr, OsString},
11 path::PathBuf,
12 time::Instant,
13};
14
15fn is_repo_inner(dir: &OsStr) -> anyhow::Result<()> {
16 let p = PathBuf::from(dir).join(".git").canonicalize()?;
17 if p.extension().unwrap_or_default() == "git"
18 || p.file_name().unwrap_or_default() == ".git"
19 || p.join("HEAD").is_file()
20 {
21 Ok(())
22 } else {
23 Err(anyhow!(
24 "Path '{}' needs to be a directory containing '.git/'",
25 p.display()
26 ))
27 }
28}
29
30fn is_repo(dir: &OsStr) -> Result<(), String> {
31 is_repo_inner(dir).map_err(|err| err.to_string())
32}
33
34#[derive(Clap)]
35#[clap(name = "git-hours", about = "Estimate hours worked basted on a commit history", version = clap::crate_version!())]
36struct Opts {
37 /// The directory containing a '.git/' folder.
38 #[clap(parse(from_os_str))]
39 #[clap(validator_os = is_repo)]
40 working_dir: PathBuf,
41 /// The name of the ref like 'main' or 'master' at which to start iterating the commit graph.
42 refname: OsString,
43 /// Omit personally identifyable information, leaving only the summary.
44 #[clap(short = 'p' long)]
45 omit_pii: bool,
46}
9 47
10fn main() -> anyhow::Result<()> {48fn main() -> anyhow::Result<()> {
11 let mut args = std::env::args();49 let opts: Opts = Opts::parse();
12 let repo_git_dir = args50 let repo_git_dir = opts.working_dir.join(".git");
13 .nth(1)51 let commit_id = ObjectId::from_hex(
14 .ok_or_else(|| anyhow!("First argument is the .git directory to work in"))52 &std::fs::read(repo_git_dir.join("refs").join("heads").join(opts.refname))?
15 .and_then(|p| {53 .as_bstr()
16 let p = PathBuf::from(p).join(".git").canonicalize()?;54 .trim(),
17 if p.extension().unwrap_or_default() == "git"55 )?;
18 || p.file_name().unwrap_or_default() == ".git"56
19 || p.join("HEAD").is_file()
20 {
21 Ok(p)
22 } else {
23 Err(anyhow!(
24 "Path '{}' needs to be a directory containing '.git/'",
25 p.display()
26 ))
27 }
28 })?;
29 let commit_id = args
30 .next()
31 .ok_or_else(|| {
32 anyhow!("Second argument is the name of the branch from which to start iteration, like 'main' or 'master'")
33 })
34 .and_then(|name| {
35 ObjectId::from_hex(
36 &std::fs::read(repo_git_dir.join("refs").join("heads").join(name))?
37 .as_bstr()
38 .trim(),
39 )
40 .map_err(Into::into)
41 })?;
42 let repo_objects_dir = {57 let repo_objects_dir = {
43 let mut d = repo_git_dir;58 let mut d = repo_git_dir;
44 d.push("objects");59 d.push("objects");

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t