Module: Git::Parsers::Stash Private
- Defined in:
- lib/git/parsers/stash.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.
Known limitation: If a stash message contains the field separator character (\x1f, ASCII unit separator), parsing will fail or produce incorrect results. This is extremely rare in practice since \x1f is a non-printable control character.
Parser for git stash command output
Handles parsing of git stash list output into structured data objects.
Design Note: Namespace Organization
This parser creates and returns StashInfo objects, which live at
the top-level Git:: namespace rather than within Git::Parsers::. This
is intentional:
- Parsers are infrastructure - marked
@api private, users shouldn't interact with them directly - Info classes are public API - returned by commands and used throughout the codebase
- Info classes are domain entities - represent core git concepts (stashes as data)
Keeping Info classes at Git:: improves discoverability and correctly
reflects their role as public types rather than parser internals.
Defined Under Namespace
Modules: Fields
Constant Summary collapse
- 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.
Field separator used in custom format output Using a non-printable unit separator (US, 0x1F) to avoid collisions with stash messages and author/committer fields, while still working with Process.spawn (which doesn't allow NUL bytes in arguments)
"\x1f"- STASH_FORMAT =
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.
Custom format for git stash list that extracts all available metadata %H = full commit SHA %h = abbreviated commit SHA %gd = reflog selector (stash@{n}) %gs = reflog subject (the stash message) %an = author name %ae = author email %aI = author date (ISO 8601 format, parsed into a Time) %cn = committer name %ce = committer email %cI = committer date (ISO 8601 format, parsed into a Time)
[ '%H', # 0: full SHA '%h', # 1: short SHA '%gd', # 2: reflog selector '%gs', # 3: reflog subject (message) '%an', # 4: author name '%ae', # 5: author email '%aI', # 6: author date '%cn', # 7: committer name '%ce', # 8: committer email '%cI' # 9: committer date ].join(FIELD_SEPARATOR)
- 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.
Number of fields expected in the parsed output
10- BRANCH_PATTERN =
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.
Pattern to extract branch from standard stash messages Matches "WIP on
:" or "On :" at the start /^(?:WIP on|On)\s+([^:]+):/
Class Method Summary collapse
-
.author_info(parts) ⇒ Git::AuthorInfo
private
Build the author identity from the parsed fields.
-
.build_author_info(name, email, date) ⇒ Git::AuthorInfo
private
Build a Git::AuthorInfo from identity fields.
-
.build_stash_info(parts, expected_index) ⇒ Git::StashInfo
private
Build a StashInfo from parsed format parts.
-
.committer_info(parts) ⇒ Git::AuthorInfo
private
Build the committer identity from the parsed fields.
-
.core_attrs(parts, index) ⇒ Hash<Symbol, Object>
private
Build core StashInfo attributes from parsed fields.
-
.extract_branch(message) ⇒ String?
private
Extract the branch name from a stash message.
-
.extract_index(reflog_selector) ⇒ Integer?
private
Extract the stash index from a reflog selector.
-
.parse_date(date) ⇒ Time
private
Parse a
%aIor%cIfield into a Time. -
.parse_list(stdout) ⇒ Array<Git::StashInfo>
private
Parse git stash list output into StashInfo objects.
-
.parse_stash_line(line, expected_index, all_lines) ⇒ Git::StashInfo
private
Parse a single stash list line into a StashInfo object.
-
.stash_info_attrs(parts, index) ⇒ Hash
private
Build StashInfo attributes hash from parsed parts.
-
.unexpected_stash_line_error(lines, line, index) ⇒ String
private
Generate error message for unexpected stash line format.
Class Method Details
.author_info(parts) ⇒ Git::AuthorInfo
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 author identity from the parsed fields
194 195 196 |
# File 'lib/git/parsers/stash.rb', line 194 def (parts) (parts[Fields::AUTHOR_NAME], parts[Fields::AUTHOR_EMAIL], parts[Fields::AUTHOR_DATE]) end |
.build_author_info(name, email, date) ⇒ Git::AuthorInfo
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 Git::AuthorInfo from identity fields
The date is parsed with Time.iso8601, so the UTC offset git emits for
%aI and %cI is preserved in the resulting Time.
225 226 227 |
# File 'lib/git/parsers/stash.rb', line 225 def (name, email, date) Git::AuthorInfo.new(name: name, email: email, date: parse_date(date)) end |
.build_stash_info(parts, expected_index) ⇒ Git::StashInfo
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 StashInfo from parsed format parts
154 155 156 157 158 |
# File 'lib/git/parsers/stash.rb', line 154 def build_stash_info(parts, expected_index) index = extract_index(parts[Fields::REFLOG]) || expected_index Git::StashInfo.new(**stash_info_attrs(parts, index)) end |
.committer_info(parts) ⇒ Git::AuthorInfo
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 committer identity from the parsed fields
204 205 206 207 208 |
# File 'lib/git/parsers/stash.rb', line 204 def committer_info(parts) ( parts[Fields::COMMITTER_NAME], parts[Fields::COMMITTER_EMAIL], parts[Fields::COMMITTER_DATE] ) end |
.core_attrs(parts, index) ⇒ Hash<Symbol, Object>
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 core StashInfo attributes from parsed fields
180 181 182 183 184 185 186 |
# File 'lib/git/parsers/stash.rb', line 180 def core_attrs(parts, index) { index: index, name: parts[Fields::REFLOG], oid: parts[Fields::OID], short_oid: parts[Fields::SHORT_OID], branch: extract_branch(parts[Fields::MESSAGE]), message: parts[Fields::MESSAGE] } end |
.extract_branch(message) ⇒ 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.
Extract the branch name from a stash message
261 262 263 264 |
# File 'lib/git/parsers/stash.rb', line 261 def extract_branch() match = BRANCH_PATTERN.match() match ? match[1] : nil end |
.extract_index(reflog_selector) ⇒ Integer?
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.
Extract the stash index from a reflog selector
250 251 252 253 |
# File 'lib/git/parsers/stash.rb', line 250 def extract_index(reflog_selector) match = reflog_selector&.match(/stash@\{(\d+)\}/) match ? match[1].to_i : nil end |
.parse_date(date) ⇒ Time
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 %aI or %cI field into a Time
237 238 239 240 241 242 |
# File 'lib/git/parsers/stash.rb', line 237 def parse_date(date) Time.iso8601(date) rescue ArgumentError => e raise Git::UnexpectedResultError, "Unexpected date #{date.inspect} in output from `git stash list`: #{e.}" end |
.parse_list(stdout) ⇒ Array<Git::StashInfo>
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 stash list output into StashInfo objects
122 123 124 125 |
# File 'lib/git/parsers/stash.rb', line 122 def parse_list(stdout) lines = stdout.split("\n") lines.each_with_index.map { |line, idx| parse_stash_line(line, idx, lines) } end |
.parse_stash_line(line, expected_index, all_lines) ⇒ Git::StashInfo
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 single stash list line into a StashInfo object
139 140 141 142 143 144 |
# File 'lib/git/parsers/stash.rb', line 139 def parse_stash_line(line, expected_index, all_lines) parts = line.split(FIELD_SEPARATOR, FIELD_COUNT) return build_stash_info(parts, expected_index) if parts.length == FIELD_COUNT raise Git::UnexpectedResultError, unexpected_stash_line_error(all_lines, line, expected_index) end |
.stash_info_attrs(parts, index) ⇒ Hash
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 StashInfo attributes hash from parsed parts
168 169 170 |
# File 'lib/git/parsers/stash.rb', line 168 def stash_info_attrs(parts, index) core_attrs(parts, index).merge(author: (parts), committer: committer_info(parts)) end |
.unexpected_stash_line_error(lines, line, index) ⇒ 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 error message for unexpected stash line format
276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/git/parsers/stash.rb', line 276 def unexpected_stash_line_error(lines, line, index) format_str = STASH_FORMAT.gsub(FIELD_SEPARATOR, '<FS>') <<~ERROR Unexpected line in output from `git stash list --format=#{format_str}`, at index #{index} Expected #{FIELD_COUNT} fields separated by '\\x1f' (unit separator), got #{line.split(FIELD_SEPARATOR, -1).length} Full output: #{lines.join("\n ")} Line at index #{index}: "#{line}" ERROR end |