///|
/// The `.git` reader, re-exported: reading a checkout is `gitx/gitz/repo`'s
/// job, but the value it produces is part of *this* package's surface.
pub using @repo {type Checkout, type RepoInfo, type RepoLocate}

///|
/// The checkout at `cwd`, read out of the files `git` itself would read.
///
/// The other half of the pair is `gitx/gitcli`, which asks a `git` executable;
/// this one opens `HEAD`, refs, `packed-refs`, the commit object and the index.
/// `moon.mod` is not involved: this is a directory in.
pub fn read_repo_info(cwd : String) -> RepoInfo {
  @repo.read_checkout(cwd).to_repo_info()
}

///|
/// Whitespace off both ends, everything else kept. A ref file written by git
/// ends in a newline, and a version string may not.
fn trim(text : String) -> String {
  let chars = text.to_array()
  let mut end = chars.length()
  while end > 0 && is_space(chars[end - 1]) {
    end = end - 1
  }
  let mut start = 0
  while start < end && is_space(chars[start]) {
    start = start + 1
  }
  let out = StringBuilder()
  for i in start.. Bool {
  ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
}

///|
/// The fields of `GitInfo` a `.git` reader can answer.
///
/// `commit_date` / `author` / `email` need the commit object, `dirty` needs the
/// index and a `stat` per file, and `ahead` / `behind` need the commit graph.
/// All four are left empty rather than guessed: `gitinfo` does not invent a
/// date to fill a hole.
pub fn to_git_info(info : RepoInfo) -> GitInfo {
  let available = info.available && info.locate is Ok
  {
    available,
    branch: trim(info.branch),
    tag: trim(info.tag),
    describe: trim(info.describe),
    commit: trim(info.commit),
    short_commit: trim(info.short_commit),
    commit_date: trim(info.commit_date),
    author: trim(info.author),
    email: trim(info.email),
    dirty: available && info.dirty,
    ahead: if available {
      info.ahead
    } else {
      0
    },
    behind: if available {
      info.behind
    } else {
      0
    },
  }
}