Skip to content

Commit 239e7b2

Browse files
committed
Basic entry information (#293)
1 parent 8bf585d commit 239e7b2

File tree

3 files changed

+155
-23
lines changed

3 files changed

+155
-23
lines changed

Diff for: gitoxide-core/src/index/mod.rs

+120-7
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,124 @@
1+
use std::convert::TryFrom;
12
use std::path::Path;
23

34
use git_repository as git;
45

56
pub mod entries;
67

8+
mod information {
9+
use git_repository as git;
10+
use std::convert::TryFrom;
11+
12+
#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
13+
pub(crate) struct EntryKind {
14+
dir: usize,
15+
file: usize,
16+
executable: usize,
17+
symlink: usize,
18+
submodule: usize,
19+
other: usize,
20+
}
21+
22+
#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
23+
pub(crate) struct EntryFlag {
24+
intent_to_add: usize,
25+
skip_worktree: usize,
26+
}
27+
28+
#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
29+
pub(crate) struct Entries {
30+
stage_0: usize,
31+
stage_1: usize,
32+
stage_2: usize,
33+
kind: EntryKind,
34+
flags: EntryFlag,
35+
}
36+
37+
#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
38+
pub(crate) struct Collection {
39+
version: u8,
40+
entries: Entries,
41+
}
42+
43+
impl TryFrom<git::index::File> for Collection {
44+
type Error = anyhow::Error;
45+
46+
fn try_from(f: git::index::File) -> Result<Self, Self::Error> {
47+
Ok(Collection {
48+
version: f.version() as u8,
49+
entries: {
50+
let (mut stage_0, mut stage_1, mut stage_2) = (0, 0, 0);
51+
let (mut dir, mut file, mut executable, mut symlink, mut submodule, mut other) = (0, 0, 0, 0, 0, 0);
52+
let (mut intent_to_add, mut skip_worktree) = (0, 0);
53+
for entry in f.entries() {
54+
match entry.flags.stage() {
55+
0 => stage_0 += 1,
56+
1 => stage_1 += 1,
57+
2 => stage_2 += 1,
58+
invalid => anyhow::bail!("Invalid stage {} encountered", invalid),
59+
}
60+
match entry.mode {
61+
git::index::entry::Mode::DIR => dir += 1,
62+
git::index::entry::Mode::FILE => file += 1,
63+
git::index::entry::Mode::FILE_EXECUTABLE => executable += 1,
64+
git::index::entry::Mode::SYMLINK => symlink += 1,
65+
git::index::entry::Mode::COMMIT => submodule += 1,
66+
_ => other += 1,
67+
}
68+
if entry.flags.contains(git::index::entry::Flags::INTENT_TO_ADD) {
69+
intent_to_add += 1;
70+
}
71+
if entry.flags.contains(git::index::entry::Flags::SKIP_WORKTREE) {
72+
skip_worktree += 1;
73+
}
74+
}
75+
Entries {
76+
stage_0,
77+
stage_1,
78+
stage_2,
79+
kind: EntryKind {
80+
dir,
81+
file,
82+
executable,
83+
symlink,
84+
submodule,
85+
other,
86+
},
87+
flags: EntryFlag {
88+
intent_to_add,
89+
skip_worktree,
90+
},
91+
}
92+
},
93+
})
94+
}
95+
}
96+
}
97+
98+
pub fn information(
99+
index_path: impl AsRef<Path>,
100+
out: impl std::io::Write,
101+
entries::Options { object_hash, format }: entries::Options,
102+
) -> anyhow::Result<()> {
103+
use crate::OutputFormat::*;
104+
let info = information::Collection::try_from(parse_file(index_path, object_hash)?)?;
105+
match format {
106+
Human => {
107+
anyhow::bail!("Only JSON output is implemented");
108+
}
109+
#[cfg(feature = "serde1")]
110+
Json => serde_json::to_writer_pretty(out, &info)?,
111+
}
112+
Ok(())
113+
}
114+
7115
pub fn entries(
8116
index_path: impl AsRef<Path>,
9117
mut out: impl std::io::Write,
10118
entries::Options { object_hash, format }: entries::Options,
11119
) -> anyhow::Result<()> {
12120
use crate::OutputFormat::*;
13-
let file = git::index::File::at(
14-
index_path.as_ref(),
15-
git::index::decode::Options {
16-
object_hash,
17-
..Default::default()
18-
},
19-
)?;
121+
let file = parse_file(index_path, object_hash)?;
20122

21123
#[cfg(feature = "serde1")]
22124
if let Json = format {
@@ -38,3 +140,14 @@ pub fn entries(
38140
}
39141
Ok(())
40142
}
143+
144+
fn parse_file(index_path: impl AsRef<Path>, object_hash: git::hash::Kind) -> anyhow::Result<git::index::File> {
145+
git::index::File::at(
146+
index_path.as_ref(),
147+
git::index::decode::Options {
148+
object_hash,
149+
..Default::default()
150+
},
151+
)
152+
.map_err(Into::into)
153+
}

Diff for: src/plumbing/main.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,22 @@ pub fn main() -> Result<()> {
7373
})?;
7474

7575
match cmd {
76-
Subcommands::Index(subcommands) => match subcommands {
77-
index::Subcommands::Entries {
78-
object_hash,
79-
index_path,
80-
} => prepare_and_run(
76+
Subcommands::Index(index::Platform {
77+
object_hash,
78+
index_path,
79+
cmd,
80+
}) => match cmd {
81+
index::Subcommands::Info => prepare_and_run(
82+
"index-entries",
83+
verbose,
84+
progress,
85+
progress_keep_open,
86+
None,
87+
move |_progress, out, _err| {
88+
core::index::information(index_path, out, core::index::entries::Options { object_hash, format })
89+
},
90+
),
91+
index::Subcommands::Entries => prepare_and_run(
8192
"index-entries",
8293
verbose,
8394
progress,

Diff for: src/plumbing/options.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ pub enum Subcommands {
5757
#[clap(subcommand)]
5858
CommitGraph(commitgraph::Subcommands),
5959
/// Subcommands for interacting with a worktree index, typically at .git/index
60-
#[clap(subcommand)]
61-
Index(index::Subcommands),
60+
Index(index::Platform),
6261
/// Subcommands for interacting with entire git repositories
6362
#[clap(subcommand)]
6463
Repository(repo::Subcommands),
@@ -337,18 +336,27 @@ pub mod repo {
337336
pub mod index {
338337
use std::path::PathBuf;
339338

339+
#[derive(Debug, clap::Parser)]
340+
pub struct Platform {
341+
/// The object format to assume when reading files that don't inherently know about it, or when writing files.
342+
#[clap(long, default_value_t = git_repository::hash::Kind::default(), possible_values(&["SHA1"]))]
343+
pub object_hash: git_repository::hash::Kind,
344+
345+
/// The path to the index file.
346+
#[clap(short = 'i', long, default_value = ".git/index")]
347+
pub index_path: PathBuf,
348+
349+
/// Subcommands
350+
#[clap(subcommand)]
351+
pub cmd: Subcommands,
352+
}
353+
340354
#[derive(Debug, clap::Subcommand)]
341-
#[clap(alias = "index")]
342355
pub enum Subcommands {
343356
/// Print all entries to standard output
344-
Entries {
345-
/// The object format to assume when reading files that don't inherently know about it, or when writing files.
346-
#[clap(long, default_value_t = git_repository::hash::Kind::default(), possible_values(&["SHA1"]))]
347-
object_hash: git_repository::hash::Kind,
348-
349-
/// The path to the index file.
350-
index_path: PathBuf,
351-
},
357+
Entries,
358+
/// Print information about the index structure
359+
Info,
352360
}
353361
}
354362

0 commit comments

Comments
 (0)