Skip to content

Commit

Permalink
Basic entry information (#293)
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Jan 24, 2022
1 parent 8bf585d commit 239e7b2
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 23 deletions.
127 changes: 120 additions & 7 deletions gitoxide-core/src/index/mod.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,124 @@
use std::convert::TryFrom;
use std::path::Path;

use git_repository as git;

pub mod entries;

mod information {
use git_repository as git;
use std::convert::TryFrom;

#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
pub(crate) struct EntryKind {
dir: usize,
file: usize,
executable: usize,
symlink: usize,
submodule: usize,
other: usize,
}

#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
pub(crate) struct EntryFlag {
intent_to_add: usize,
skip_worktree: usize,
}

#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
pub(crate) struct Entries {
stage_0: usize,
stage_1: usize,
stage_2: usize,
kind: EntryKind,
flags: EntryFlag,
}

#[cfg_attr(feature = "serde1", derive(serde::Serialize))]
pub(crate) struct Collection {
version: u8,
entries: Entries,
}

impl TryFrom<git::index::File> for Collection {
type Error = anyhow::Error;

fn try_from(f: git::index::File) -> Result<Self, Self::Error> {
Ok(Collection {
version: f.version() as u8,
entries: {
let (mut stage_0, mut stage_1, mut stage_2) = (0, 0, 0);
let (mut dir, mut file, mut executable, mut symlink, mut submodule, mut other) = (0, 0, 0, 0, 0, 0);
let (mut intent_to_add, mut skip_worktree) = (0, 0);
for entry in f.entries() {
match entry.flags.stage() {
0 => stage_0 += 1,
1 => stage_1 += 1,
2 => stage_2 += 1,
invalid => anyhow::bail!("Invalid stage {} encountered", invalid),
}
match entry.mode {
git::index::entry::Mode::DIR => dir += 1,
git::index::entry::Mode::FILE => file += 1,
git::index::entry::Mode::FILE_EXECUTABLE => executable += 1,
git::index::entry::Mode::SYMLINK => symlink += 1,
git::index::entry::Mode::COMMIT => submodule += 1,
_ => other += 1,
}
if entry.flags.contains(git::index::entry::Flags::INTENT_TO_ADD) {
intent_to_add += 1;
}
if entry.flags.contains(git::index::entry::Flags::SKIP_WORKTREE) {
skip_worktree += 1;
}
}
Entries {
stage_0,
stage_1,
stage_2,
kind: EntryKind {
dir,
file,
executable,
symlink,
submodule,
other,
},
flags: EntryFlag {
intent_to_add,
skip_worktree,
},
}
},
})
}
}
}

pub fn information(
index_path: impl AsRef<Path>,
out: impl std::io::Write,
entries::Options { object_hash, format }: entries::Options,
) -> anyhow::Result<()> {
use crate::OutputFormat::*;
let info = information::Collection::try_from(parse_file(index_path, object_hash)?)?;
match format {
Human => {
anyhow::bail!("Only JSON output is implemented");
}
#[cfg(feature = "serde1")]
Json => serde_json::to_writer_pretty(out, &info)?,
}
Ok(())
}

pub fn entries(
index_path: impl AsRef<Path>,
mut out: impl std::io::Write,
entries::Options { object_hash, format }: entries::Options,
) -> anyhow::Result<()> {
use crate::OutputFormat::*;
let file = git::index::File::at(
index_path.as_ref(),
git::index::decode::Options {
object_hash,
..Default::default()
},
)?;
let file = parse_file(index_path, object_hash)?;

#[cfg(feature = "serde1")]
if let Json = format {
Expand All @@ -38,3 +140,14 @@ pub fn entries(
}
Ok(())
}

fn parse_file(index_path: impl AsRef<Path>, object_hash: git::hash::Kind) -> anyhow::Result<git::index::File> {
git::index::File::at(
index_path.as_ref(),
git::index::decode::Options {
object_hash,
..Default::default()
},
)
.map_err(Into::into)
}
21 changes: 16 additions & 5 deletions src/plumbing/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,22 @@ pub fn main() -> Result<()> {
})?;

match cmd {
Subcommands::Index(subcommands) => match subcommands {
index::Subcommands::Entries {
object_hash,
index_path,
} => prepare_and_run(
Subcommands::Index(index::Platform {
object_hash,
index_path,
cmd,
}) => match cmd {
index::Subcommands::Info => prepare_and_run(
"index-entries",
verbose,
progress,
progress_keep_open,
None,
move |_progress, out, _err| {
core::index::information(index_path, out, core::index::entries::Options { object_hash, format })
},
),
index::Subcommands::Entries => prepare_and_run(
"index-entries",
verbose,
progress,
Expand Down
30 changes: 19 additions & 11 deletions src/plumbing/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ pub enum Subcommands {
#[clap(subcommand)]
CommitGraph(commitgraph::Subcommands),
/// Subcommands for interacting with a worktree index, typically at .git/index
#[clap(subcommand)]
Index(index::Subcommands),
Index(index::Platform),
/// Subcommands for interacting with entire git repositories
#[clap(subcommand)]
Repository(repo::Subcommands),
Expand Down Expand Up @@ -337,18 +336,27 @@ pub mod repo {
pub mod index {
use std::path::PathBuf;

#[derive(Debug, clap::Parser)]
pub struct Platform {
/// The object format to assume when reading files that don't inherently know about it, or when writing files.
#[clap(long, default_value_t = git_repository::hash::Kind::default(), possible_values(&["SHA1"]))]
pub object_hash: git_repository::hash::Kind,

/// The path to the index file.
#[clap(short = 'i', long, default_value = ".git/index")]
pub index_path: PathBuf,

/// Subcommands
#[clap(subcommand)]
pub cmd: Subcommands,
}

#[derive(Debug, clap::Subcommand)]
#[clap(alias = "index")]
pub enum Subcommands {
/// Print all entries to standard output
Entries {
/// The object format to assume when reading files that don't inherently know about it, or when writing files.
#[clap(long, default_value_t = git_repository::hash::Kind::default(), possible_values(&["SHA1"]))]
object_hash: git_repository::hash::Kind,

/// The path to the index file.
index_path: PathBuf,
},
Entries,
/// Print information about the index structure
Info,
}
}

Expand Down

0 comments on commit 239e7b2

Please sign in to comment.