Module: Git::Parsers::Status Private
- Defined in:
- lib/git/parsers/status.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Parser for git status --porcelain=v2 -z output
Builds one StatusFileInfo per entry. With -z every entry is
NUL-terminated and paths are emitted verbatim (no quoting), so a path may
contain spaces but never a NUL. The original path of a rename or copy
entry is the NUL-terminated token that follows the entry.
Every entry type of the porcelain v2 format is handled: 1 (ordinary),
2 (rename or copy), u (unmerged), ? (untracked), and ! (ignored).
# header lines, emitted with --branch or --show-stash, are skipped.
StatusFileInfo lives at the top-level Git:: namespace rather than
within Git::Parsers:: because it is public API returned to callers,
while this parser is infrastructure.
Constant Summary collapse
- ENTRY_SEPARATOR =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Separator between entries (and between a rename entry and its original path)
"\0"- FIELD_SEPARATOR =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Separator between the fields of one entry
/ /- ORDINARY_ENTRY =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
First character of an ordinary (changed, added, or deleted) entry
'1'- RENAMED_ENTRY =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
First character of a rename or copy entry
'2'- UNMERGED_ENTRY =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
First character of an unmerged entry
'u'- UNTRACKED_ENTRY =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
First character of an untracked entry
'?'- IGNORED_ENTRY =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
First character of an ignored entry
'!'- HEADER_LINE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
First character of a header line
'#'- ORDINARY_FIELD_COUNT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Field count of an ordinary entry:
1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path> 9- RENAMED_FIELD_COUNT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Field count of a rename or copy entry, which adds
<X><score>before the path 10- UNMERGED_FIELD_COUNT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Field count of an unmerged entry:
u <XY> <sub> <m1> <m2> <m3> <mW> <h1> <h2> <h3> <path> 11- PATH_ONLY_FIELD_COUNT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Field count of an untracked or ignored entry:
? <path>or! <path> 2- EMPTY_MEMBERS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Every StatusFileInfo member set to
nil, for entries that lack a field Git::StatusFileInfo.members.to_h { |member| [member, nil] }.freeze
Class Method Summary collapse
-
.build_file_info(statuses, **members) ⇒ Git::StatusFileInfo
private
Build a StatusFileInfo, defaulting every member not given to
nil. -
.parse(stdout) ⇒ Array<Git::StatusFileInfo>
private
Parse
git status --porcelain=v2 -zoutput into StatusFileInfo objects. -
.parse_entry(entry, tokens) ⇒ Git::StatusFileInfo
private
Parse one entry, consuming its original path from
tokensfor renames and copies. -
.parse_ordinary(entry) ⇒ Git::StatusFileInfo
private
Parse an ordinary (
1) entry. -
.parse_path_only(entry) ⇒ Git::StatusFileInfo
private
Parse an untracked (
?) or ignored (!) entry. -
.parse_renamed(entry, original_path) ⇒ Git::StatusFileInfo
private
Parse a rename or copy (
2) entry. -
.parse_unmerged(entry) ⇒ Git::StatusFileInfo
private
Parse an unmerged (
u) entry. -
.split_fields(entry, count) ⇒ Array<String>
private
Split an entry into exactly
countfields, the last of which is the path. -
.unexpected_entry_error(entry) ⇒ String
private
Generate the error message for an entry that does not match the format.
-
.unmerged_stages(modes, shas) ⇒ Hash{Integer => Hash{Symbol => String}}
private
Build the frozen stage hash of an unmerged entry.
Class Method Details
.build_file_info(statuses, **members) ⇒ Git::StatusFileInfo
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Build a StatusFileInfo, defaulting every member not given to nil
234 235 236 237 238 |
# File 'lib/git/parsers/status.rb', line 234 def build_file_info(statuses, **members) Git::StatusFileInfo.new( **EMPTY_MEMBERS, index_status: statuses[0], worktree_status: statuses[1], **members ) end |
.parse(stdout) ⇒ Array<Git::StatusFileInfo>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse git status --porcelain=v2 -z output into StatusFileInfo objects
89 90 91 92 93 94 95 96 97 |
# File 'lib/git/parsers/status.rb', line 89 def parse(stdout) tokens = stdout.split(ENTRY_SEPARATOR) files = [] until tokens.empty? entry = tokens.shift files << parse_entry(entry, tokens) unless entry.start_with?(HEADER_LINE) end files end |
.parse_entry(entry, tokens) ⇒ Git::StatusFileInfo
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse one entry, consuming its original path from tokens for renames and copies
110 111 112 113 114 115 116 117 118 |
# File 'lib/git/parsers/status.rb', line 110 def parse_entry(entry, tokens) case entry[0] when ORDINARY_ENTRY then parse_ordinary(entry) when RENAMED_ENTRY then parse_renamed(entry, tokens.shift) when UNMERGED_ENTRY then parse_unmerged(entry) when UNTRACKED_ENTRY, IGNORED_ENTRY then parse_path_only(entry) else raise Git::UnexpectedResultError, unexpected_entry_error(entry) end end |
.parse_ordinary(entry) ⇒ Git::StatusFileInfo
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse an ordinary (1) entry
128 129 130 131 132 |
# File 'lib/git/parsers/status.rb', line 128 def parse_ordinary(entry) _type, xy, submodule, mode_head, mode_index, mode_worktree, sha_head, sha_index, path = split_fields(entry, ORDINARY_FIELD_COUNT) build_file_info(xy, path:, submodule:, mode_head:, mode_index:, mode_worktree:, sha_head:, sha_index:) end |
.parse_path_only(entry) ⇒ Git::StatusFileInfo
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse an untracked (?) or ignored (!) entry
The entry's single status character is used for both status positions,
matching the ?? and !! codes of the short format.
185 186 187 188 |
# File 'lib/git/parsers/status.rb', line 185 def parse_path_only(entry) type, path = split_fields(entry, PATH_ONLY_FIELD_COUNT) build_file_info(type * 2, path: path) end |
.parse_renamed(entry, original_path) ⇒ Git::StatusFileInfo
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse a rename or copy (2) entry
146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/git/parsers/status.rb', line 146 def parse_renamed(entry, original_path) _type, xy, submodule, mode_head, mode_index, mode_worktree, sha_head, sha_index, score, path = split_fields(entry, RENAMED_FIELD_COUNT) raise Git::UnexpectedResultError, unexpected_entry_error(entry) if original_path.nil? build_file_info( xy, path:, submodule:, mode_head:, mode_index:, mode_worktree:, sha_head:, sha_index:, original_path:, rename_score: score[1..].to_i ) end |
.parse_unmerged(entry) ⇒ Git::StatusFileInfo
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse an unmerged (u) entry
167 168 169 170 171 172 |
# File 'lib/git/parsers/status.rb', line 167 def parse_unmerged(entry) _type, xy, submodule, mode1, mode2, mode3, mode_worktree, sha1, sha2, sha3, path = split_fields(entry, UNMERGED_FIELD_COUNT) stages = unmerged_stages([mode1, mode2, mode3], [sha1, sha2, sha3]) build_file_info(xy, path:, submodule:, mode_worktree:, unmerged_stages: stages) end |
.split_fields(entry, count) ⇒ Array<String>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Split an entry into exactly count fields, the last of which is the path
The path may contain spaces, so the split is limited to count fields.
202 203 204 205 206 207 |
# File 'lib/git/parsers/status.rb', line 202 def split_fields(entry, count) fields = entry.split(FIELD_SEPARATOR, count) return fields if fields.length == count raise Git::UnexpectedResultError, unexpected_entry_error(entry) end |
.unexpected_entry_error(entry) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Generate the error message for an entry that does not match the format
246 247 248 |
# File 'lib/git/parsers/status.rb', line 246 def unexpected_entry_error(entry) "Unexpected entry in output from `git status --porcelain=v2 -z`: #{entry.inspect}" end |
.unmerged_stages(modes, shas) ⇒ Hash{Integer => Hash{Symbol => String}}
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Build the frozen stage hash of an unmerged entry
218 219 220 221 222 |
# File 'lib/git/parsers/status.rb', line 218 def unmerged_stages(modes, shas) modes.zip(shas).each_with_index.to_h do |(mode, sha), index| [index + 1, { mode: mode, sha: sha }.freeze] end.freeze end |