git 4.4.1 → 5.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/copilot-instructions.md +67 -2705
- data/.github/pull_request_template.md +3 -1
- data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
- data/.github/skills/command-implementation/REFERENCE.md +993 -0
- data/.github/skills/command-implementation/SKILL.md +229 -0
- data/.github/skills/command-test-conventions/SKILL.md +660 -0
- data/.github/skills/command-yard-documentation/SKILL.md +426 -0
- data/.github/skills/dependency-management/SKILL.md +72 -0
- data/.github/skills/development-workflow/SKILL.md +506 -0
- data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
- data/.github/skills/extract-facade-from-base-lib/SKILL.md +586 -0
- data/.github/skills/facade-implementation/REFERENCE.md +840 -0
- data/.github/skills/facade-implementation/SKILL.md +260 -0
- data/.github/skills/facade-test-conventions/SKILL.md +380 -0
- data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
- data/.github/skills/make-skill-template/SKILL.md +176 -0
- data/.github/skills/pr-readiness-review/SKILL.md +185 -0
- data/.github/skills/project-context/SKILL.md +313 -0
- data/.github/skills/pull-request-review/SKILL.md +168 -0
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
- data/.github/skills/release-management/SKILL.md +125 -0
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
- data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
- data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
- data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
- data/.github/skills/reviewing-skills/SKILL.md +189 -0
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
- data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
- data/.github/skills/test-debugging/SKILL.md +160 -0
- data/.github/skills/yard-documentation/SKILL.md +793 -0
- data/.github/workflows/continuous_integration.yml +3 -67
- data/.github/workflows/enforce_conventional_commits.yml +1 -1
- data/.github/workflows/experimental_continuous_integration.yml +2 -2
- data/.github/workflows/release.yml +3 -4
- data/.gitignore +8 -0
- data/.husky/pre-commit +13 -0
- data/.release-please-manifest.json +1 -1
- data/.rspec +3 -0
- data/.rubocop.yml +7 -3
- data/.rubocop_todo.yml +23 -5
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -66
- data/CONTRIBUTING.md +694 -53
- data/README.md +17 -17
- data/Rakefile +61 -9
- data/commitlint.test +4 -0
- data/git.gemspec +14 -8
- data/lib/git/args_builder.rb +0 -8
- data/lib/git/base.rb +488 -412
- data/lib/git/branch.rb +117 -59
- data/lib/git/branch_delete_failure.rb +31 -0
- data/lib/git/branch_delete_result.rb +63 -0
- data/lib/git/branch_info.rb +178 -0
- data/lib/git/branches.rb +130 -24
- data/lib/git/command_line/base.rb +245 -0
- data/lib/git/command_line/capturing.rb +249 -0
- data/lib/git/command_line/result.rb +96 -0
- data/lib/git/command_line/streaming.rb +194 -0
- data/lib/git/command_line.rb +43 -322
- data/lib/git/command_line_result.rb +4 -88
- data/lib/git/commands/add.rb +131 -0
- data/lib/git/commands/am/abort.rb +43 -0
- data/lib/git/commands/am/apply.rb +252 -0
- data/lib/git/commands/am/continue.rb +43 -0
- data/lib/git/commands/am/quit.rb +43 -0
- data/lib/git/commands/am/retry.rb +47 -0
- data/lib/git/commands/am/show_current_patch.rb +64 -0
- data/lib/git/commands/am/skip.rb +42 -0
- data/lib/git/commands/am.rb +33 -0
- data/lib/git/commands/apply.rb +237 -0
- data/lib/git/commands/archive/list_formats.rb +46 -0
- data/lib/git/commands/archive.rb +140 -0
- data/lib/git/commands/arguments.rb +3510 -0
- data/lib/git/commands/base.rb +403 -0
- data/lib/git/commands/branch/copy.rb +94 -0
- data/lib/git/commands/branch/create.rb +173 -0
- data/lib/git/commands/branch/delete.rb +80 -0
- data/lib/git/commands/branch/list.rb +162 -0
- data/lib/git/commands/branch/move.rb +94 -0
- data/lib/git/commands/branch/set_upstream.rb +86 -0
- data/lib/git/commands/branch/show_current.rb +49 -0
- data/lib/git/commands/branch/unset_upstream.rb +57 -0
- data/lib/git/commands/branch.rb +34 -0
- data/lib/git/commands/cat_file/batch.rb +364 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +210 -0
- data/lib/git/commands/cat_file.rb +49 -0
- data/lib/git/commands/checkout/branch.rb +151 -0
- data/lib/git/commands/checkout/files.rb +115 -0
- data/lib/git/commands/checkout.rb +38 -0
- data/lib/git/commands/checkout_index.rb +105 -0
- data/lib/git/commands/clean.rb +100 -0
- data/lib/git/commands/clone.rb +240 -0
- data/lib/git/commands/commit.rb +272 -0
- data/lib/git/commands/commit_tree.rb +100 -0
- data/lib/git/commands/config_option_syntax/add.rb +83 -0
- data/lib/git/commands/config_option_syntax/get.rb +117 -0
- data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
- data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +102 -0
- data/lib/git/commands/config_option_syntax/list.rb +107 -0
- data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
- data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
- data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
- data/lib/git/commands/config_option_syntax/set.rb +114 -0
- data/lib/git/commands/config_option_syntax/unset.rb +89 -0
- data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
- data/lib/git/commands/config_option_syntax.rb +56 -0
- data/lib/git/commands/describe.rb +155 -0
- data/lib/git/commands/diff.rb +656 -0
- data/lib/git/commands/diff_files.rb +518 -0
- data/lib/git/commands/diff_index.rb +496 -0
- data/lib/git/commands/fetch.rb +352 -0
- data/lib/git/commands/fsck.rb +136 -0
- data/lib/git/commands/gc.rb +132 -0
- data/lib/git/commands/grep.rb +338 -0
- data/lib/git/commands/init.rb +99 -0
- data/lib/git/commands/log.rb +632 -0
- data/lib/git/commands/ls_files.rb +191 -0
- data/lib/git/commands/ls_remote.rb +155 -0
- data/lib/git/commands/ls_tree.rb +131 -0
- data/lib/git/commands/maintenance/register.rb +75 -0
- data/lib/git/commands/maintenance/run.rb +104 -0
- data/lib/git/commands/maintenance/start.rb +66 -0
- data/lib/git/commands/maintenance/stop.rb +55 -0
- data/lib/git/commands/maintenance/unregister.rb +79 -0
- data/lib/git/commands/maintenance.rb +31 -0
- data/lib/git/commands/merge/abort.rb +44 -0
- data/lib/git/commands/merge/continue.rb +44 -0
- data/lib/git/commands/merge/quit.rb +46 -0
- data/lib/git/commands/merge/start.rb +245 -0
- data/lib/git/commands/merge.rb +28 -0
- data/lib/git/commands/merge_base.rb +86 -0
- data/lib/git/commands/mv.rb +77 -0
- data/lib/git/commands/name_rev.rb +114 -0
- data/lib/git/commands/pull.rb +377 -0
- data/lib/git/commands/push.rb +246 -0
- data/lib/git/commands/read_tree.rb +149 -0
- data/lib/git/commands/remote/add.rb +91 -0
- data/lib/git/commands/remote/get_url.rb +66 -0
- data/lib/git/commands/remote/list.rb +54 -0
- data/lib/git/commands/remote/prune.rb +61 -0
- data/lib/git/commands/remote/remove.rb +52 -0
- data/lib/git/commands/remote/rename.rb +69 -0
- data/lib/git/commands/remote/set_branches.rb +63 -0
- data/lib/git/commands/remote/set_head.rb +82 -0
- data/lib/git/commands/remote/set_url.rb +71 -0
- data/lib/git/commands/remote/set_url_add.rb +61 -0
- data/lib/git/commands/remote/set_url_delete.rb +64 -0
- data/lib/git/commands/remote/show.rb +71 -0
- data/lib/git/commands/remote/update.rb +72 -0
- data/lib/git/commands/remote.rb +42 -0
- data/lib/git/commands/repack.rb +277 -0
- data/lib/git/commands/reset.rb +147 -0
- data/lib/git/commands/rev_parse.rb +297 -0
- data/lib/git/commands/revert/abort.rb +45 -0
- data/lib/git/commands/revert/continue.rb +57 -0
- data/lib/git/commands/revert/quit.rb +47 -0
- data/lib/git/commands/revert/skip.rb +44 -0
- data/lib/git/commands/revert/start.rb +153 -0
- data/lib/git/commands/revert.rb +29 -0
- data/lib/git/commands/rm.rb +114 -0
- data/lib/git/commands/show.rb +632 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
- data/lib/git/commands/show_ref/exists.rb +78 -0
- data/lib/git/commands/show_ref/list.rb +145 -0
- data/lib/git/commands/show_ref/verify.rb +120 -0
- data/lib/git/commands/show_ref.rb +42 -0
- data/lib/git/commands/stash/apply.rb +75 -0
- data/lib/git/commands/stash/branch.rb +65 -0
- data/lib/git/commands/stash/clear.rb +41 -0
- data/lib/git/commands/stash/create.rb +58 -0
- data/lib/git/commands/stash/drop.rb +67 -0
- data/lib/git/commands/stash/list.rb +39 -0
- data/lib/git/commands/stash/pop.rb +78 -0
- data/lib/git/commands/stash/push.rb +103 -0
- data/lib/git/commands/stash/show.rb +149 -0
- data/lib/git/commands/stash/store.rb +63 -0
- data/lib/git/commands/stash.rb +38 -0
- data/lib/git/commands/status.rb +169 -0
- data/lib/git/commands/symbolic_ref/delete.rb +68 -0
- data/lib/git/commands/symbolic_ref/read.rb +95 -0
- data/lib/git/commands/symbolic_ref/update.rb +76 -0
- data/lib/git/commands/symbolic_ref.rb +38 -0
- data/lib/git/commands/tag/create.rb +139 -0
- data/lib/git/commands/tag/delete.rb +55 -0
- data/lib/git/commands/tag/list.rb +143 -0
- data/lib/git/commands/tag/verify.rb +71 -0
- data/lib/git/commands/tag.rb +26 -0
- data/lib/git/commands/update_ref/batch.rb +140 -0
- data/lib/git/commands/update_ref/delete.rb +92 -0
- data/lib/git/commands/update_ref/update.rb +106 -0
- data/lib/git/commands/update_ref.rb +42 -0
- data/lib/git/commands/version.rb +52 -0
- data/lib/git/commands/worktree/add.rb +140 -0
- data/lib/git/commands/worktree/list.rb +64 -0
- data/lib/git/commands/worktree/lock.rb +58 -0
- data/lib/git/commands/worktree/management_base.rb +51 -0
- data/lib/git/commands/worktree/move.rb +66 -0
- data/lib/git/commands/worktree/prune.rb +67 -0
- data/lib/git/commands/worktree/remove.rb +63 -0
- data/lib/git/commands/worktree/repair.rb +76 -0
- data/lib/git/commands/worktree/unlock.rb +47 -0
- data/lib/git/commands/worktree.rb +43 -0
- data/lib/git/commands/write_tree.rb +68 -0
- data/lib/git/commands.rb +89 -0
- data/lib/git/detached_head_info.rb +54 -0
- data/lib/git/diff.rb +297 -7
- data/lib/git/diff_file_numstat_info.rb +29 -0
- data/lib/git/diff_file_patch_info.rb +134 -0
- data/lib/git/diff_file_raw_info.rb +127 -0
- data/lib/git/diff_info.rb +169 -0
- data/lib/git/diff_path_status.rb +78 -19
- data/lib/git/diff_result.rb +32 -0
- data/lib/git/diff_stats.rb +59 -14
- data/lib/git/dirstat_info.rb +86 -0
- data/lib/git/errors.rb +65 -2
- data/lib/git/execution_context/global.rb +56 -0
- data/lib/git/execution_context/repository.rb +147 -0
- data/lib/git/execution_context.rb +482 -0
- data/lib/git/file_ref.rb +74 -0
- data/lib/git/fsck_object.rb +9 -9
- data/lib/git/fsck_result.rb +1 -1
- data/lib/git/lib.rb +1606 -1085
- data/lib/git/log.rb +15 -2
- data/lib/git/object.rb +92 -22
- data/lib/git/parsers/branch.rb +224 -0
- data/lib/git/parsers/cat_file.rb +111 -0
- data/lib/git/parsers/diff.rb +585 -0
- data/lib/git/parsers/fsck.rb +133 -0
- data/lib/git/parsers/grep.rb +42 -0
- data/lib/git/parsers/ls_tree.rb +58 -0
- data/lib/git/parsers/stash.rb +208 -0
- data/lib/git/parsers/tag.rb +257 -0
- data/lib/git/remote.rb +133 -9
- data/lib/git/repository/branching.rb +572 -0
- data/lib/git/repository/committing.rb +191 -0
- data/lib/git/repository/configuring.rb +156 -0
- data/lib/git/repository/diffing.rb +775 -0
- data/lib/git/repository/inspecting.rb +153 -0
- data/lib/git/repository/logging.rb +247 -0
- data/lib/git/repository/merging.rb +295 -0
- data/lib/git/repository/object_operations.rb +1101 -0
- data/lib/git/repository/path_resolver.rb +207 -0
- data/lib/git/repository/remote_operations.rb +753 -0
- data/lib/git/repository/shared_private.rb +51 -0
- data/lib/git/repository/staging.rb +390 -0
- data/lib/git/repository/stashing.rb +107 -0
- data/lib/git/repository/status_operations.rb +180 -0
- data/lib/git/repository/worktree_operations.rb +159 -0
- data/lib/git/repository.rb +264 -1
- data/lib/git/stash.rb +85 -4
- data/lib/git/stash_info.rb +104 -0
- data/lib/git/stashes.rb +130 -13
- data/lib/git/status.rb +226 -18
- data/lib/git/tag_delete_failure.rb +31 -0
- data/lib/git/tag_delete_result.rb +63 -0
- data/lib/git/tag_info.rb +105 -0
- data/lib/git/version.rb +109 -2
- data/lib/git/version_constraint.rb +81 -0
- data/lib/git/worktree.rb +120 -5
- data/lib/git/worktrees.rb +107 -7
- data/lib/git.rb +117 -56
- data/redesign/1_architecture_existing.md +54 -18
- data/redesign/2_architecture_redesign.md +365 -46
- data/redesign/3_architecture_implementation.md +1451 -54
- data/tasks/gem_tasks.rake +4 -0
- data/tasks/npm_tasks.rake +7 -0
- data/tasks/rspec.rake +48 -0
- data/tasks/test.rake +13 -1
- data/tasks/yard.rake +34 -7
- metadata +349 -20
- data/lib/git/index.rb +0 -6
- data/lib/git/path.rb +0 -38
- data/lib/git/working_directory.rb +0 -6
- /data/{release-please-config.json → .release-please-config.json} +0 -0
data/lib/git/branches.rb
CHANGED
|
@@ -1,68 +1,174 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'git/base'
|
|
4
|
+
|
|
3
5
|
module Git
|
|
4
|
-
#
|
|
6
|
+
# Collection of all Git branches in a repository
|
|
7
|
+
#
|
|
8
|
+
# Wraps both local and remote-tracking branches and provides filtering,
|
|
9
|
+
# enumeration, and name-based lookup.
|
|
10
|
+
#
|
|
11
|
+
# @example Enumerate all branches
|
|
12
|
+
# branches = repo.branches
|
|
13
|
+
# branches.each { |b| puts b.name }
|
|
14
|
+
#
|
|
15
|
+
# @api public
|
|
16
|
+
#
|
|
5
17
|
class Branches
|
|
6
18
|
include Enumerable
|
|
7
19
|
|
|
20
|
+
# Creates a new Branches collection populated from the given repository
|
|
21
|
+
#
|
|
22
|
+
# @param base [Git::Base, Git::Repository] the repository to enumerate
|
|
23
|
+
# branches from
|
|
24
|
+
#
|
|
25
|
+
# @return [void]
|
|
26
|
+
#
|
|
27
|
+
# @raise [Git::FailedError] if git exits with a non-zero exit status
|
|
28
|
+
#
|
|
8
29
|
def initialize(base)
|
|
9
30
|
@branches = {}
|
|
31
|
+
@lookup = {}
|
|
10
32
|
|
|
11
33
|
@base = base
|
|
12
34
|
|
|
13
|
-
|
|
14
|
-
|
|
35
|
+
branch_repository.branches_all.each do |branch_info|
|
|
36
|
+
branch = Git::Branch.new(base, branch_info)
|
|
37
|
+
|
|
38
|
+
@branches[branch_info.refname] = branch
|
|
39
|
+
index_branch_lookup(branch, refname: branch_info.refname)
|
|
15
40
|
end
|
|
16
41
|
end
|
|
17
42
|
|
|
43
|
+
# Returns all local (non-remote-tracking) branches
|
|
44
|
+
#
|
|
45
|
+
# @example List local branch names
|
|
46
|
+
# repo.branches.local.map(&:name)
|
|
47
|
+
#
|
|
48
|
+
# @return [Array<Git::Branch>] the local branches
|
|
49
|
+
#
|
|
18
50
|
def local
|
|
19
51
|
reject(&:remote)
|
|
20
52
|
end
|
|
21
53
|
|
|
54
|
+
# Returns all remote-tracking branches
|
|
55
|
+
#
|
|
56
|
+
# @example List remote branch names
|
|
57
|
+
# repo.branches.remote.map(&:name)
|
|
58
|
+
#
|
|
59
|
+
# @return [Array<Git::Branch>] the remote-tracking branches
|
|
60
|
+
#
|
|
22
61
|
def remote
|
|
23
62
|
self.select(&:remote)
|
|
24
63
|
end
|
|
25
64
|
|
|
26
|
-
#
|
|
27
|
-
|
|
65
|
+
# Returns the number of branches in the collection
|
|
66
|
+
#
|
|
67
|
+
# @example Count all branches
|
|
68
|
+
# repo.branches.size # => 3
|
|
69
|
+
#
|
|
70
|
+
# @return [Integer] the total number of branches
|
|
71
|
+
#
|
|
28
72
|
def size
|
|
29
73
|
@branches.size
|
|
30
74
|
end
|
|
31
75
|
|
|
76
|
+
# Iterates over every branch in the collection
|
|
77
|
+
#
|
|
78
|
+
# @overload each
|
|
79
|
+
#
|
|
80
|
+
# @example Get an enumerator over all branches
|
|
81
|
+
# enum = repo.branches.each
|
|
82
|
+
#
|
|
83
|
+
# @return [Enumerator<Git::Branch>] an enumerator over all branches
|
|
84
|
+
#
|
|
85
|
+
# @overload each(&block)
|
|
86
|
+
#
|
|
87
|
+
# @example Print every branch name
|
|
88
|
+
# repo.branches.each { |b| puts b.name }
|
|
89
|
+
#
|
|
90
|
+
# @return [Array<Git::Branch>] the full list of branches
|
|
91
|
+
#
|
|
92
|
+
# @yield [branch] passes each branch to the block
|
|
93
|
+
#
|
|
94
|
+
# @yieldparam branch [Git::Branch] a branch in the repository
|
|
95
|
+
#
|
|
96
|
+
# @yieldreturn [void]
|
|
97
|
+
#
|
|
32
98
|
def each(&)
|
|
33
99
|
@branches.values.each(&)
|
|
34
100
|
end
|
|
35
101
|
|
|
36
|
-
# Returns the
|
|
102
|
+
# Returns the branch with the given name
|
|
103
|
+
#
|
|
104
|
+
# Supports short names (`'main'`), remote-qualified names
|
|
105
|
+
# (`'working/master'`), and full refspec names
|
|
106
|
+
# (`'remotes/working/master'`).
|
|
37
107
|
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# master
|
|
41
|
-
# remotes/working/master
|
|
108
|
+
# @example Look up a branch by short name
|
|
109
|
+
# repo.branches['main']
|
|
42
110
|
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
111
|
+
# @example Look up a remote-tracking branch
|
|
112
|
+
# repo.branches['working/master']
|
|
113
|
+
#
|
|
114
|
+
# @param branch_name [#to_s] the name of the branch to retrieve
|
|
115
|
+
#
|
|
116
|
+
# @return [Git::Branch, nil] the matching branch, or `nil` if not found
|
|
46
117
|
#
|
|
47
|
-
# @param [#to_s] branch_name the target branch name.
|
|
48
|
-
# @return [Git::Branch] the target branch.
|
|
49
118
|
def [](branch_name)
|
|
50
|
-
@
|
|
51
|
-
branches[branch.full] ||= branch
|
|
52
|
-
|
|
53
|
-
# This is how Git (version 1.7.9.5) works.
|
|
54
|
-
# Lets you ignore the 'remotes' if its at the beginning of the branch full
|
|
55
|
-
# name (even if is not a real remote branch).
|
|
56
|
-
branches[branch.full.sub('remotes/', '')] ||= branch if branch.full =~ %r{^remotes/.+}
|
|
57
|
-
end[branch_name.to_s]
|
|
119
|
+
@lookup[branch_name.to_s]
|
|
58
120
|
end
|
|
59
121
|
|
|
122
|
+
# Returns a string listing all branches, prefixed with `*` for the current branch
|
|
123
|
+
#
|
|
124
|
+
# @example Display all branches
|
|
125
|
+
# puts repo.branches.to_s
|
|
126
|
+
#
|
|
127
|
+
# @return [String] a formatted branch listing
|
|
128
|
+
#
|
|
60
129
|
def to_s
|
|
61
|
-
out = ''
|
|
130
|
+
out = +''
|
|
62
131
|
@branches.each_value do |b|
|
|
63
132
|
out << (b.current ? '* ' : ' ') << b.to_s << "\n"
|
|
64
133
|
end
|
|
65
134
|
out
|
|
66
135
|
end
|
|
136
|
+
|
|
137
|
+
private
|
|
138
|
+
|
|
139
|
+
# Resolves the {Git::Repository} for this collection of branches
|
|
140
|
+
#
|
|
141
|
+
# Accepts either a {Git::Repository} (new form) or a {Git::Base} (legacy).
|
|
142
|
+
# The `is_a?(Git::Base)` guard will be removed when {Git::Base} is deleted
|
|
143
|
+
# in Phase 4.
|
|
144
|
+
#
|
|
145
|
+
# @return [Git::Repository] the repository used to enumerate branches
|
|
146
|
+
#
|
|
147
|
+
# @api private
|
|
148
|
+
#
|
|
149
|
+
def branch_repository
|
|
150
|
+
@base.is_a?(Git::Base) ? @base.facade_repository : @base
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Indexes all supported lookup keys for a branch without mutating
|
|
154
|
+
# the canonical `@branches` collection used by enumeration
|
|
155
|
+
#
|
|
156
|
+
# @param branch [Git::Branch] the branch to index
|
|
157
|
+
#
|
|
158
|
+
# @param refname [String] the full refname key to use for primary lookup
|
|
159
|
+
#
|
|
160
|
+
# @return [void]
|
|
161
|
+
#
|
|
162
|
+
# @api private
|
|
163
|
+
#
|
|
164
|
+
def index_branch_lookup(branch, refname:)
|
|
165
|
+
@lookup[refname] ||= branch
|
|
166
|
+
@lookup[branch.full] ||= branch
|
|
167
|
+
|
|
168
|
+
return unless branch.full.start_with?('remotes/')
|
|
169
|
+
|
|
170
|
+
# Mirror git compatibility: allow omitting a leading "remotes/".
|
|
171
|
+
@lookup[branch.full.delete_prefix('remotes/')] ||= branch
|
|
172
|
+
end
|
|
67
173
|
end
|
|
68
174
|
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/command_line'
|
|
4
|
+
require 'git/errors'
|
|
5
|
+
|
|
6
|
+
module Git
|
|
7
|
+
module CommandLine
|
|
8
|
+
# Abstract base class for git command-line execution strategies
|
|
9
|
+
#
|
|
10
|
+
# Concrete subclasses must implement {#run} to execute a git command and
|
|
11
|
+
# return a {Git::CommandLine::Result}. Two implementations are provided:
|
|
12
|
+
#
|
|
13
|
+
# * {Git::CommandLine::Capturing} — buffers stdout and stderr in memory
|
|
14
|
+
# * {Git::CommandLine::Streaming} — streams stdout to a caller-supplied IO
|
|
15
|
+
#
|
|
16
|
+
# @example Instantiate a concrete subclass
|
|
17
|
+
# env = { 'GIT_DIR' => '/path/to/git/dir' }
|
|
18
|
+
# binary_path = '/usr/bin/git'
|
|
19
|
+
# global_opts = %w[--git-dir /path/to/git/dir]
|
|
20
|
+
# logger = Logger.new($stdout)
|
|
21
|
+
# cli = Git::CommandLine::Capturing.new(env, binary_path, global_opts, logger)
|
|
22
|
+
# cli.run('version') #=> #<Git::CommandLine::Result ...>
|
|
23
|
+
#
|
|
24
|
+
# @abstract Subclass and implement {#run}
|
|
25
|
+
#
|
|
26
|
+
# @api public
|
|
27
|
+
#
|
|
28
|
+
class Base
|
|
29
|
+
# Create a Base (or subclass) object
|
|
30
|
+
#
|
|
31
|
+
# @param env [Hash{String => String, nil}] environment variables to set or
|
|
32
|
+
# unset. String values set the variable; `nil` values unset it.
|
|
33
|
+
#
|
|
34
|
+
# @param binary_path [String] the path to the git binary
|
|
35
|
+
#
|
|
36
|
+
# @param global_opts [Array<String>] global options to pass to git
|
|
37
|
+
#
|
|
38
|
+
# @param logger [Logger] the logger to use
|
|
39
|
+
#
|
|
40
|
+
def initialize(env, binary_path, global_opts, logger)
|
|
41
|
+
@env = env
|
|
42
|
+
@binary_path = binary_path
|
|
43
|
+
@global_opts = global_opts
|
|
44
|
+
@logger = logger
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Execute a git command and return the result
|
|
48
|
+
#
|
|
49
|
+
# Concrete subclasses must override this method.
|
|
50
|
+
#
|
|
51
|
+
# @raise [NotImplementedError] always — must be implemented by subclasses
|
|
52
|
+
#
|
|
53
|
+
def run(*)
|
|
54
|
+
raise NotImplementedError, "#{self.class}#run is not implemented"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @attribute [r] env
|
|
58
|
+
#
|
|
59
|
+
# Variables to set (or unset) in the git command's environment
|
|
60
|
+
#
|
|
61
|
+
# @example
|
|
62
|
+
# env = { 'GIT_DIR' => '/path/to/git/dir' }
|
|
63
|
+
# cli = Git::CommandLine::Capturing.new(env, '/usr/bin/git', [], Logger.new(nil))
|
|
64
|
+
# cli.env #=> { 'GIT_DIR' => '/path/to/git/dir' }
|
|
65
|
+
#
|
|
66
|
+
# @return [Hash{String => String, nil}]
|
|
67
|
+
#
|
|
68
|
+
# @see https://ruby-doc.org/3.2.1/Process.html#method-c-spawn Process.spawn
|
|
69
|
+
# for details on how to set environment variables using the `env` parameter
|
|
70
|
+
#
|
|
71
|
+
attr_reader :env
|
|
72
|
+
|
|
73
|
+
# @attribute [r] binary_path
|
|
74
|
+
#
|
|
75
|
+
# The path to the command line binary to run
|
|
76
|
+
#
|
|
77
|
+
# @example
|
|
78
|
+
# cli = Git::CommandLine::Capturing.new({}, '/usr/bin/git', [], Logger.new(nil))
|
|
79
|
+
# cli.binary_path #=> '/usr/bin/git'
|
|
80
|
+
#
|
|
81
|
+
# @return [String]
|
|
82
|
+
#
|
|
83
|
+
attr_reader :binary_path
|
|
84
|
+
|
|
85
|
+
# @attribute [r] global_opts
|
|
86
|
+
#
|
|
87
|
+
# The global options to pass to git
|
|
88
|
+
#
|
|
89
|
+
# These are options that are passed to git before the command name and
|
|
90
|
+
# arguments. For example, in `git --git-dir /path/to/git/dir version`, the
|
|
91
|
+
# global options are %w[--git-dir /path/to/git/dir].
|
|
92
|
+
#
|
|
93
|
+
# @example
|
|
94
|
+
# global_opts = %w[--git-dir /path/to/git/dir]
|
|
95
|
+
# cli = Git::CommandLine::Capturing.new({}, '/usr/bin/git', global_opts, Logger.new(nil))
|
|
96
|
+
# cli.global_opts #=> %w[--git-dir /path/to/git/dir]
|
|
97
|
+
#
|
|
98
|
+
# @return [Array<String>]
|
|
99
|
+
#
|
|
100
|
+
attr_reader :global_opts
|
|
101
|
+
|
|
102
|
+
# @attribute [r] logger
|
|
103
|
+
#
|
|
104
|
+
# The logger to use for logging git commands and results
|
|
105
|
+
#
|
|
106
|
+
# @example
|
|
107
|
+
# logger = Logger.new(nil)
|
|
108
|
+
# cli = Git::CommandLine::Capturing.new({}, '/usr/bin/git', [], logger)
|
|
109
|
+
# cli.logger == logger #=> true
|
|
110
|
+
#
|
|
111
|
+
# @return [Logger]
|
|
112
|
+
#
|
|
113
|
+
attr_reader :logger
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
# Merge caller-supplied options into `defaults` and raise if any unknown keys are present
|
|
118
|
+
#
|
|
119
|
+
# @param defaults [Hash] the allowed keys and their default values (e.g. RUN_OPTION_DEFAULTS)
|
|
120
|
+
#
|
|
121
|
+
# @param options_hash [Hash] caller-supplied options
|
|
122
|
+
#
|
|
123
|
+
# @return [Hash] defaults with any supplied values overridden
|
|
124
|
+
#
|
|
125
|
+
# @raise [ArgumentError] if options_hash contains keys not present in defaults
|
|
126
|
+
#
|
|
127
|
+
# @api private
|
|
128
|
+
#
|
|
129
|
+
def merge_and_validate_options(defaults, options_hash)
|
|
130
|
+
merged = defaults.merge(options_hash)
|
|
131
|
+
extra = merged.keys - defaults.keys
|
|
132
|
+
raise ArgumentError, "Unknown options: #{extra.join(', ')}" if extra.any?
|
|
133
|
+
|
|
134
|
+
merged
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Merge the instance-level env with any per-call overrides in options_hash[:env]
|
|
138
|
+
#
|
|
139
|
+
# @param options_hash [Hash] options that may include an :env override
|
|
140
|
+
#
|
|
141
|
+
# @return [Hash{String => String, nil}]
|
|
142
|
+
#
|
|
143
|
+
# @api private
|
|
144
|
+
#
|
|
145
|
+
def merged_env(options_hash)
|
|
146
|
+
env.merge(options_hash[:env] || {})
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Yield to a block that calls ProcessExecuter and translate any ProcessExecuter
|
|
150
|
+
# errors to their ruby-git equivalents
|
|
151
|
+
#
|
|
152
|
+
# @raise [ArgumentError] in place of ProcessExecuter::ArgumentError
|
|
153
|
+
#
|
|
154
|
+
# @raise [Git::Error] in place of ProcessExecuter::SpawnError (binary not found or
|
|
155
|
+
# failed to launch)
|
|
156
|
+
#
|
|
157
|
+
# @raise [Git::ProcessIOError] in place of ProcessExecuter::ProcessIOError
|
|
158
|
+
#
|
|
159
|
+
# @return [Object] the return value of the block
|
|
160
|
+
#
|
|
161
|
+
# @api private
|
|
162
|
+
#
|
|
163
|
+
def run_process_executer
|
|
164
|
+
yield
|
|
165
|
+
rescue ProcessExecuter::ArgumentError => e
|
|
166
|
+
raise ::ArgumentError, e.message
|
|
167
|
+
rescue ProcessExecuter::SpawnError => e
|
|
168
|
+
raise Git::Error, e.message, cause: e.cause
|
|
169
|
+
rescue ProcessExecuter::ProcessIOError => e
|
|
170
|
+
raise Git::ProcessIOError, e.message, cause: e.cause
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Build the git command line from the available sources to send to `Process.spawn`
|
|
174
|
+
#
|
|
175
|
+
# @param args [Array<String>] command-line arguments to append after global options
|
|
176
|
+
#
|
|
177
|
+
# @return [Array<String>]
|
|
178
|
+
#
|
|
179
|
+
# @raise [ArgumentError] if any element of args is itself an Array
|
|
180
|
+
#
|
|
181
|
+
# @api private
|
|
182
|
+
#
|
|
183
|
+
def build_git_cmd(args)
|
|
184
|
+
raise ArgumentError, 'The args array can not contain an array' if args.any?(Array)
|
|
185
|
+
|
|
186
|
+
[binary_path, *global_opts, *args].map(&:to_s)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Log the result of a git command at info/debug level
|
|
190
|
+
#
|
|
191
|
+
# @param result [ProcessExecuter::Result] the raw process result
|
|
192
|
+
#
|
|
193
|
+
# @param command [Array<String>] the full command that was run
|
|
194
|
+
#
|
|
195
|
+
# @param processed_out [String] the post-processed stdout string
|
|
196
|
+
#
|
|
197
|
+
# @param processed_err [String] the post-processed stderr string
|
|
198
|
+
#
|
|
199
|
+
# @return [void]
|
|
200
|
+
#
|
|
201
|
+
# @api private
|
|
202
|
+
#
|
|
203
|
+
def log_result(result, command, processed_out, processed_err)
|
|
204
|
+
logger.info { "#{command} exited with status #{result}" }
|
|
205
|
+
logger.debug { "stdout:\n#{processed_out.inspect}\nstderr:\n#{processed_err.inspect}" }
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Build a {Git::CommandLine::Result} and raise on timeout, signal, or failure
|
|
209
|
+
#
|
|
210
|
+
# @param command [Array<String>] the full command that was run
|
|
211
|
+
#
|
|
212
|
+
# @param result [ProcessExecuter::Result] the raw process result
|
|
213
|
+
#
|
|
214
|
+
# @param processed_out [String] processed stdout string
|
|
215
|
+
#
|
|
216
|
+
# @param processed_err [String] processed stderr string
|
|
217
|
+
#
|
|
218
|
+
# @param timeout [Numeric, nil] the timeout value (for error context)
|
|
219
|
+
#
|
|
220
|
+
# @param raise_on_failure [Boolean] whether to raise on non-zero exit status
|
|
221
|
+
#
|
|
222
|
+
# @return [Git::CommandLine::Result]
|
|
223
|
+
#
|
|
224
|
+
# @raise [Git::TimeoutError] if the command timed out
|
|
225
|
+
#
|
|
226
|
+
# @raise [Git::SignaledError] if the command was terminated by a signal
|
|
227
|
+
#
|
|
228
|
+
# @raise [Git::FailedError] if the command failed and raise_on_failure is true
|
|
229
|
+
#
|
|
230
|
+
# @api private
|
|
231
|
+
#
|
|
232
|
+
# rubocop:disable Metrics/ParameterLists
|
|
233
|
+
def command_line_result(command, result, processed_out, processed_err, timeout, raise_on_failure)
|
|
234
|
+
Git::CommandLine::Result.new(command, result, processed_out, processed_err).tap do |processed_result|
|
|
235
|
+
raise Git::TimeoutError.new(processed_result, timeout) if result.timed_out?
|
|
236
|
+
|
|
237
|
+
raise Git::SignaledError, processed_result if result.signaled?
|
|
238
|
+
|
|
239
|
+
raise Git::FailedError, processed_result if raise_on_failure && !result.success?
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
# rubocop:enable Metrics/ParameterLists
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'git/command_line'
|
|
4
|
+
|
|
5
|
+
module Git
|
|
6
|
+
module CommandLine
|
|
7
|
+
# Executes a git command and captures both stdout and stderr in memory
|
|
8
|
+
#
|
|
9
|
+
# {Git::CommandLine::Capturing} is the buffering strategy: it calls
|
|
10
|
+
# `ProcessExecuter.run_with_capture`, which reads all subprocess output into
|
|
11
|
+
# `String` objects before returning. Use this class (via
|
|
12
|
+
# {Git::Lib#command_capturing}) for the vast majority of git subcommands whose
|
|
13
|
+
# output fits comfortably in memory.
|
|
14
|
+
#
|
|
15
|
+
# {Git::CommandLine::Streaming} is the complementary strategy for commands
|
|
16
|
+
# (such as `cat-file -p <blob>`) whose stdout may be too large to buffer.
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# capturing = Git::CommandLine::Capturing.new(
|
|
20
|
+
# {}, '/usr/bin/git', %w[--git-dir /repo/.git], Logger.new($stdout)
|
|
21
|
+
# )
|
|
22
|
+
# result = capturing.run('log', '--oneline', '-5')
|
|
23
|
+
# result.stdout # => "abc1234 Initial commit\n..."
|
|
24
|
+
# result.stderr # => ""
|
|
25
|
+
#
|
|
26
|
+
# @see Git::Lib#command_capturing
|
|
27
|
+
#
|
|
28
|
+
# @see Git::CommandLine::Streaming
|
|
29
|
+
#
|
|
30
|
+
class Capturing < Git::CommandLine::Base
|
|
31
|
+
# Default options accepted by {#run}
|
|
32
|
+
#
|
|
33
|
+
# @api private
|
|
34
|
+
RUN_OPTION_DEFAULTS = {
|
|
35
|
+
in: nil,
|
|
36
|
+
out: nil,
|
|
37
|
+
err: nil,
|
|
38
|
+
chdir: nil,
|
|
39
|
+
timeout: nil,
|
|
40
|
+
raise_on_failure: true,
|
|
41
|
+
env: {},
|
|
42
|
+
normalize: false,
|
|
43
|
+
chomp: false,
|
|
44
|
+
merge: false
|
|
45
|
+
}.freeze
|
|
46
|
+
|
|
47
|
+
# Execute a git command, capture stdout and stderr, and return the result
|
|
48
|
+
#
|
|
49
|
+
# Non-option command-line arguments to pass to git. If you collect the
|
|
50
|
+
# arguments in an array, splat the array into the parameter list.
|
|
51
|
+
#
|
|
52
|
+
# NORMALIZATION
|
|
53
|
+
#
|
|
54
|
+
# The command output is returned as a Unicode string containing the binary
|
|
55
|
+
# output from the command. If the binary output is not valid UTF-8, the
|
|
56
|
+
# output will cause problems because the encoding will be invalid.
|
|
57
|
+
#
|
|
58
|
+
# Normalization is a process that tries to convert the binary output to a
|
|
59
|
+
# valid UTF-8 string. It uses the `rchardet` gem to detect the encoding of
|
|
60
|
+
# the binary output and then converts it to UTF-8.
|
|
61
|
+
#
|
|
62
|
+
# Normalization is not enabled by default. Pass `normalize: true` to enable
|
|
63
|
+
# it. When enabled, normalization is applied to both stdout and stderr in
|
|
64
|
+
# the returned result object, regardless of the `out:` or `err:` options.
|
|
65
|
+
# Only the captured in-memory strings are normalized; any external IO you
|
|
66
|
+
# provide will receive the raw subprocess output.
|
|
67
|
+
#
|
|
68
|
+
# @example Run a command and return the output
|
|
69
|
+
# result = capturing.run('version')
|
|
70
|
+
# result.stdout #=> "git version 2.39.1\n"
|
|
71
|
+
#
|
|
72
|
+
# @example The args array should be splatted into the parameter list
|
|
73
|
+
# args = %w[log -n 1 --oneline]
|
|
74
|
+
# result = capturing.run(*args)
|
|
75
|
+
# result.stdout #=> "f5baa11 beginning of Ruby/Git project\n"
|
|
76
|
+
#
|
|
77
|
+
# @example Run a command and return the chomped output
|
|
78
|
+
# result = capturing.run('version', chomp: true)
|
|
79
|
+
# result.stdout #=> "git version 2.39.1"
|
|
80
|
+
#
|
|
81
|
+
# @example Run a command without normalizing the output
|
|
82
|
+
# capturing.run('version', normalize: false) #=> "git version 2.39.1\n"
|
|
83
|
+
#
|
|
84
|
+
# @example Capture stdout in a temporary file
|
|
85
|
+
# require 'tempfile'
|
|
86
|
+
# Tempfile.create('git') do |file|
|
|
87
|
+
# capturing.run('version', out: file)
|
|
88
|
+
# file.rewind
|
|
89
|
+
# file.read #=> "git version 2.39.1\n"
|
|
90
|
+
# end
|
|
91
|
+
#
|
|
92
|
+
# @example Capture stderr in a StringIO object
|
|
93
|
+
# require 'stringio'
|
|
94
|
+
# stderr = StringIO.new
|
|
95
|
+
# begin
|
|
96
|
+
# capturing.run('log', 'nonexistent-branch', err: stderr)
|
|
97
|
+
# rescue Git::FailedError => e
|
|
98
|
+
# stderr.string #=> "unknown revision or path not in the working tree.\n"
|
|
99
|
+
# end
|
|
100
|
+
#
|
|
101
|
+
# @param options_hash [Hash] the options to pass to the command
|
|
102
|
+
#
|
|
103
|
+
# @option options_hash [IO, nil] :in the IO object to use as stdin for the
|
|
104
|
+
# command, or nil to inherit the parent process stdin. Must be a real IO
|
|
105
|
+
# object with a file descriptor (not StringIO).
|
|
106
|
+
#
|
|
107
|
+
# @option options_hash [#write, nil] :out the object to write stdout to, or
|
|
108
|
+
# nil to capture stdout in the returned result.
|
|
109
|
+
#
|
|
110
|
+
# If this is a `StringIO` object, `stdout_writer.string` will be returned.
|
|
111
|
+
#
|
|
112
|
+
# In general, only specify a `stdout_writer` when you want to redirect
|
|
113
|
+
# stdout to a file or other `#write`-responding object. The default
|
|
114
|
+
# behaviour returns the command output.
|
|
115
|
+
#
|
|
116
|
+
# @option options_hash [#write, nil] :err the object to write stderr to, or
|
|
117
|
+
# nil to capture stderr in the returned result.
|
|
118
|
+
#
|
|
119
|
+
# @option options_hash [Boolean] :normalize (false) whether to normalize the
|
|
120
|
+
# encoding of stdout and stderr output
|
|
121
|
+
#
|
|
122
|
+
# @option options_hash [Boolean] :chomp (false) whether to chomp both stdout
|
|
123
|
+
# and stderr output
|
|
124
|
+
#
|
|
125
|
+
# @option options_hash [Boolean] :merge (false) whether to merge stdout and
|
|
126
|
+
# stderr in the returned string
|
|
127
|
+
#
|
|
128
|
+
# @option options_hash [String, nil] :chdir the directory to run the command in
|
|
129
|
+
#
|
|
130
|
+
# @option options_hash [Numeric, nil] :timeout the maximum seconds to wait for
|
|
131
|
+
# the command to complete. Zero means no timeout. A timeout kills the
|
|
132
|
+
# process via `SIGKILL` and raises {Git::TimeoutError}.
|
|
133
|
+
#
|
|
134
|
+
# @option options_hash [Boolean] :raise_on_failure (true) whether to raise
|
|
135
|
+
# {Git::FailedError} on non-zero exit status.
|
|
136
|
+
# {Git::TimeoutError} and {Git::SignaledError} are always raised regardless.
|
|
137
|
+
#
|
|
138
|
+
# @option options_hash [Hash] :env ({}) additional environment variable
|
|
139
|
+
# overrides for this command. String keys map to String values (to set) or
|
|
140
|
+
# `nil` (to unset).
|
|
141
|
+
#
|
|
142
|
+
# @return [Git::CommandLineResult] the result of the command
|
|
143
|
+
#
|
|
144
|
+
# @raise [ArgumentError] if `args` contains an array or an unknown option is
|
|
145
|
+
# passed
|
|
146
|
+
#
|
|
147
|
+
# @raise [Git::SignaledError] if the command was terminated by an uncaught signal
|
|
148
|
+
#
|
|
149
|
+
# @raise [Git::FailedError] if the command returned a non-zero exit status
|
|
150
|
+
#
|
|
151
|
+
# @raise [Git::ProcessIOError] if an exception was raised while collecting
|
|
152
|
+
# subprocess output
|
|
153
|
+
#
|
|
154
|
+
# @raise [Git::TimeoutError] if the command times out
|
|
155
|
+
#
|
|
156
|
+
def run(*, **options_hash)
|
|
157
|
+
options = merge_and_validate_options(RUN_OPTION_DEFAULTS, options_hash)
|
|
158
|
+
|
|
159
|
+
result = execute(*, **options)
|
|
160
|
+
process_result(result, options)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
# @return [ProcessExecuter::ResultWithCapture] the process result with captured output
|
|
166
|
+
#
|
|
167
|
+
# @api private
|
|
168
|
+
def execute(*args, **options_hash)
|
|
169
|
+
git_cmd = build_git_cmd(args)
|
|
170
|
+
options = execute_options(**options_hash)
|
|
171
|
+
run_process_executer do
|
|
172
|
+
ProcessExecuter.run_with_capture(merged_env(options_hash), *git_cmd, **options)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Build the ProcessExecuter options hash for a capturing run
|
|
177
|
+
#
|
|
178
|
+
# @return [Hash]
|
|
179
|
+
#
|
|
180
|
+
# @api private
|
|
181
|
+
def execute_options(**options_hash)
|
|
182
|
+
chdir = options_hash[:chdir] || :not_set
|
|
183
|
+
timeout_after = options_hash[:timeout]
|
|
184
|
+
merge_output = options_hash[:merge] || false
|
|
185
|
+
|
|
186
|
+
{ chdir:, timeout_after:, merge_output:, raise_errors: false }.tap do |options|
|
|
187
|
+
redirect_options(options_hash).each { |k, v| options[k] = v }
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Extract non-nil redirect options (`:in`, `:out`, `:err`) from options_hash
|
|
192
|
+
#
|
|
193
|
+
# @return [Hash]
|
|
194
|
+
#
|
|
195
|
+
# @api private
|
|
196
|
+
def redirect_options(options_hash)
|
|
197
|
+
%i[in out err].filter_map do |key|
|
|
198
|
+
val = options_hash[key]
|
|
199
|
+
[key, val] unless val.nil?
|
|
200
|
+
end.to_h
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Post-process and return the stdout/stderr strings from the captured result,
|
|
204
|
+
# then log and raise on failure if required.
|
|
205
|
+
#
|
|
206
|
+
# @param result [ProcessExecuter::ResultWithCapture] the raw result
|
|
207
|
+
#
|
|
208
|
+
# @param options [Hash] the merged run options
|
|
209
|
+
#
|
|
210
|
+
# @return [Git::CommandLineResult]
|
|
211
|
+
#
|
|
212
|
+
# @raise [Git::FailedError] if the command failed and raise_on_failure is true
|
|
213
|
+
#
|
|
214
|
+
# @raise [Git::SignaledError] if the command was signaled
|
|
215
|
+
#
|
|
216
|
+
# @raise [Git::TimeoutError] if the command timed out
|
|
217
|
+
#
|
|
218
|
+
# @api private
|
|
219
|
+
def process_result(result, options)
|
|
220
|
+
command = result.command
|
|
221
|
+
processed_out, processed_err = post_process_output(result, options[:normalize], options[:chomp])
|
|
222
|
+
log_result(result, command, processed_out, processed_err)
|
|
223
|
+
command_line_result(
|
|
224
|
+
command, result, processed_out, processed_err, options[:timeout], options[:raise_on_failure]
|
|
225
|
+
)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Normalize and/or chomp the raw stdout and stderr strings.
|
|
229
|
+
#
|
|
230
|
+
# @param result [ProcessExecuter::ResultWithCapture] the raw result
|
|
231
|
+
#
|
|
232
|
+
# @param normalize [Boolean]
|
|
233
|
+
#
|
|
234
|
+
# @param chomp [Boolean]
|
|
235
|
+
#
|
|
236
|
+
# @return [Array<String>] two-element array: [processed_stdout, processed_stderr]
|
|
237
|
+
#
|
|
238
|
+
# @api private
|
|
239
|
+
def post_process_output(result, normalize, chomp)
|
|
240
|
+
[result.stdout, result.stderr].map do |raw_output|
|
|
241
|
+
output = raw_output.dup
|
|
242
|
+
output = output.lines.map { |l| Git::EncodingUtils.normalize_encoding(l) }.join if normalize
|
|
243
|
+
output.chomp! if chomp
|
|
244
|
+
output
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|