right_scraper 3.2.6 → 5.0.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 +7 -0
- data/lib/right_scraper.rb +16 -34
- data/lib/right_scraper/builders.rb +32 -0
- data/lib/right_scraper/builders/base.rb +19 -20
- data/lib/right_scraper/builders/filesystem.rb +8 -6
- data/lib/right_scraper/builders/union.rb +4 -1
- data/lib/right_scraper/loggers.rb +31 -0
- data/lib/right_scraper/loggers/base.rb +113 -0
- data/lib/right_scraper/loggers/default.rb +98 -0
- data/lib/right_scraper/{scraper.rb → main.rb} +53 -9
- data/lib/right_scraper/processes.rb +33 -0
- data/lib/right_scraper/processes/shell.rb +227 -0
- data/lib/right_scraper/processes/{ssh.rb → ssh_agent.rb} +4 -0
- data/lib/right_scraper/processes/svn_client.rb +117 -0
- data/lib/right_scraper/processes/warden.rb +358 -0
- data/lib/right_scraper/registered_base.rb +154 -0
- data/lib/right_scraper/repositories.rb +33 -0
- data/lib/right_scraper/repositories/base.rb +271 -232
- data/lib/right_scraper/repositories/download.rb +8 -6
- data/lib/right_scraper/repositories/git.rb +8 -9
- data/lib/right_scraper/repositories/svn.rb +8 -8
- data/lib/right_scraper/resources.rb +32 -0
- data/lib/right_scraper/resources/base.rb +5 -1
- data/lib/right_scraper/resources/cookbook.rb +34 -27
- data/lib/right_scraper/resources/workflow.rb +27 -28
- data/lib/right_scraper/retrievers.rb +34 -0
- data/lib/right_scraper/retrievers/base.rb +80 -84
- data/lib/right_scraper/retrievers/checkout_base.rb +178 -0
- data/lib/right_scraper/retrievers/download.rb +125 -117
- data/lib/right_scraper/retrievers/git.rb +377 -223
- data/lib/right_scraper/retrievers/svn.rb +102 -62
- data/lib/right_scraper/scanners.rb +37 -0
- data/lib/right_scraper/scanners/base.rb +77 -80
- data/lib/right_scraper/scanners/cookbook_manifest.rb +31 -30
- data/lib/right_scraper/scanners/cookbook_metadata.rb +380 -35
- data/lib/right_scraper/scanners/cookbook_s3_upload.rb +56 -53
- data/lib/right_scraper/scanners/union.rb +61 -58
- data/lib/right_scraper/scanners/workflow_manifest.rb +55 -54
- data/lib/right_scraper/scanners/workflow_metadata.rb +41 -39
- data/lib/right_scraper/scanners/workflow_s3_upload.rb +59 -55
- data/lib/right_scraper/scrapers.rb +32 -0
- data/lib/right_scraper/scrapers/base.rb +217 -205
- data/lib/right_scraper/scrapers/cookbook.rb +42 -40
- data/lib/right_scraper/scrapers/workflow.rb +57 -58
- data/lib/right_scraper/version.rb +3 -0
- data/right_scraper.gemspec +12 -16
- metadata +57 -163
- data/Gemfile +0 -15
- data/Rakefile +0 -89
- data/lib/right_scraper/logger.rb +0 -107
- data/lib/right_scraper/loggers/noisy.rb +0 -85
- data/lib/right_scraper/repositories/mock.rb +0 -70
- data/lib/right_scraper/retrievers/checkout.rb +0 -79
- data/lib/right_scraper/scraper_logger.rb +0 -66
- data/lib/right_scraper/svn_client.rb +0 -164
- data/right_scraper.rconf +0 -13
- data/spec/builder_spec.rb +0 -50
- data/spec/cookbook_helper.rb +0 -73
- data/spec/cookbook_manifest_spec.rb +0 -93
- data/spec/cookbook_s3_upload_spec.rb +0 -159
- data/spec/download/download_retriever_spec.rb +0 -118
- data/spec/download/download_retriever_spec_helper.rb +0 -72
- data/spec/download/download_spec.rb +0 -128
- data/spec/download/multi_dir_spec.rb +0 -106
- data/spec/download/multi_dir_spec_helper.rb +0 -40
- data/spec/git/cookbook_spec.rb +0 -165
- data/spec/git/demokey +0 -27
- data/spec/git/demokey.pub +0 -1
- data/spec/git/password_key +0 -30
- data/spec/git/password_key.pub +0 -1
- data/spec/git/repository_spec.rb +0 -110
- data/spec/git/retriever_spec.rb +0 -553
- data/spec/git/retriever_spec_helper.rb +0 -112
- data/spec/git/scraper_spec.rb +0 -151
- data/spec/git/ssh_spec.rb +0 -174
- data/spec/git/url_spec.rb +0 -103
- data/spec/logger_spec.rb +0 -185
- data/spec/repository_spec.rb +0 -111
- data/spec/retriever_spec_helper.rb +0 -146
- data/spec/scanner_spec.rb +0 -61
- data/spec/scraper_helper.rb +0 -88
- data/spec/scraper_spec.rb +0 -147
- data/spec/spec_helper.rb +0 -185
- data/spec/svn/cookbook_spec.rb +0 -96
- data/spec/svn/multi_svn_spec.rb +0 -64
- data/spec/svn/multi_svn_spec_helper.rb +0 -40
- data/spec/svn/repository_spec.rb +0 -72
- data/spec/svn/retriever_spec.rb +0 -266
- data/spec/svn/scraper_spec.rb +0 -90
- data/spec/svn/svn_retriever_spec_helper.rb +0 -90
- data/spec/svn/url_spec.rb +0 -47
- data/spec/url_spec.rb +0 -164
@@ -21,275 +21,429 @@
|
|
21
21
|
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#++
|
23
23
|
|
24
|
+
# ancestor
|
25
|
+
require 'right_scraper/retrievers'
|
26
|
+
|
27
|
+
require 'fileutils'
|
28
|
+
require 'shellwords'
|
24
29
|
require 'tmpdir'
|
30
|
+
require 'right_git'
|
31
|
+
require 'right_support'
|
25
32
|
|
26
|
-
|
27
|
-
# blackwinter gem and/or create a rightscale-git fork with this fix.
|
28
|
-
#
|
29
|
-
# ADDENDUM: we can't unconditionally require the git gem because git is not
|
30
|
-
# always available.
|
31
|
-
begin
|
32
|
-
require 'git'
|
33
|
-
require 'git/lib'
|
34
|
-
|
35
|
-
module Git
|
36
|
-
class Lib
|
37
|
-
# Monkey patch to prevent screw up any subsequent shell out to git
|
38
|
-
def command_with_preserved_env(cmd, opts = [], chdir = true, redirect = '', &block)
|
39
|
-
variables_to_preserve = ['GIT_DIR', 'GIT_INDEX_FILE', 'GIT_WORK_TREE']
|
40
|
-
preserved_env = Hash[variables_to_preserve.map { |var| [var, ENV[var]] }]
|
41
|
-
begin
|
42
|
-
command_without_preserved_env(cmd, opts, chdir, redirect, &block)
|
43
|
-
ensure
|
44
|
-
preserved_env.each { |var, value| ENV[var] = value }
|
45
|
-
end
|
46
|
-
end
|
33
|
+
module RightScraper::Retrievers
|
47
34
|
|
48
|
-
|
49
|
-
|
50
|
-
def run_command_with_color_stripping(git_cmd, &block)
|
51
|
-
out = run_command_without_color_stripping(git_cmd, &block)
|
52
|
-
out.gsub!(/\e\[[^m]*m/, '')
|
53
|
-
out
|
54
|
-
end
|
35
|
+
# Retriever for resources stored in a git repository.
|
36
|
+
class Git < ::RightScraper::Retrievers::CheckoutBase
|
55
37
|
|
56
|
-
|
57
|
-
alias :run_command_without_color_stripping :run_command
|
58
|
-
alias :run_command :run_command_with_color_stripping
|
59
|
-
end
|
38
|
+
@@available = false
|
60
39
|
|
61
|
-
|
62
|
-
|
63
|
-
|
40
|
+
# Determines if downloader is available.
|
41
|
+
def available?
|
42
|
+
unless @@available
|
43
|
+
begin
|
44
|
+
cmd = "git --version"
|
45
|
+
`#{cmd}`
|
46
|
+
if $?.success?
|
47
|
+
@@available = true
|
48
|
+
else
|
49
|
+
raise RetrieverError, "\"#{cmd}\" exited with #{$?.exitstatus}"
|
50
|
+
end
|
51
|
+
rescue
|
52
|
+
@logger.note_error($!, :available, "git retriever is unavailable")
|
53
|
+
end
|
64
54
|
end
|
55
|
+
@@available
|
65
56
|
end
|
66
|
-
end
|
67
|
-
rescue ::Git::GitExecuteError
|
68
|
-
# silently ignore git gem's failed attempt to execute git on load.
|
69
|
-
end
|
70
57
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
@@available = false
|
58
|
+
# Ignore .git directories.
|
59
|
+
def ignorable_paths
|
60
|
+
['.git']
|
61
|
+
end
|
76
62
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@@available = true
|
90
|
-
else
|
91
|
-
raise RetrieverError, "\"#{cmd}\" exited with #{$?.exitstatus}"
|
92
|
-
end
|
93
|
-
rescue
|
94
|
-
@logger.note_error($!, :available, "git retriever is unavailable")
|
95
|
-
end
|
63
|
+
# In addition to normal retriever initialization, if the
|
64
|
+
# underlying repository has a credential we need to initialize a
|
65
|
+
# fresh SSHAgent and add the credential to it.
|
66
|
+
def retrieve
|
67
|
+
raise RetrieverError.new("git retriever is unavailable") unless available?
|
68
|
+
private_key = @repository.first_credential
|
69
|
+
private_key = nil if private_key && private_key.empty?
|
70
|
+
if is_windows?
|
71
|
+
if private_key
|
72
|
+
with_private_key_windows(private_key) { super }
|
73
|
+
else
|
74
|
+
super
|
96
75
|
end
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
# fresh SSHAgent and add the credential to it.
|
103
|
-
def retrieve
|
104
|
-
raise RetrieverError.new("git retriever is unavailable") unless available?
|
105
|
-
|
106
|
-
start_time = nil
|
107
|
-
end_time = nil
|
108
|
-
RightScraper::Processes::SSHAgent.with do |agent|
|
109
|
-
unless @repository.first_credential.nil? || @repository.first_credential.empty?
|
110
|
-
agent.add_key(@repository.first_credential)
|
111
|
-
end
|
112
|
-
start_time = ::Time.now
|
76
|
+
else
|
77
|
+
# always start the ssh agent in Linux so we can disable strict host name
|
78
|
+
# checking, regardless of credentials.
|
79
|
+
::RightScraper::Processes::SSHAgent.with do |agent|
|
80
|
+
agent.add_key(private_key) if private_key
|
113
81
|
super
|
114
|
-
end_time = ::Time.now
|
115
82
|
end
|
83
|
+
end
|
84
|
+
true
|
85
|
+
end
|
116
86
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
87
|
+
# Return true if a checkout exists. Currently tests for .git in
|
88
|
+
# the checkout.
|
89
|
+
#
|
90
|
+
# === Returns ===
|
91
|
+
# Boolean:: true if the checkout already exists (and thus
|
92
|
+
# incremental updating can occur).
|
93
|
+
def exists?
|
94
|
+
File.exists?(File.join(@repo_dir, '.git'))
|
95
|
+
end
|
96
|
+
|
97
|
+
# Determines if the remote SHA/tag/branch referenced by the repostory
|
98
|
+
# differs from what appears on disk.
|
99
|
+
#
|
100
|
+
# @return [TrueClass|FalseClass] true if changed
|
101
|
+
def remote_differs?
|
102
|
+
remote_sha = nil
|
103
|
+
current_sha = nil
|
104
|
+
git_repo = git_repo_for(@repo_dir)
|
105
|
+
without_size_limit(git_repo) do
|
106
|
+
do_fetch(git_repo)
|
107
|
+
revision = resolve_revision
|
108
|
+
remote_name = validate_revision(git_repo, revision)
|
109
|
+
remote_sha = git_repo.sha_for(remote_name ? remote_name : revision)
|
110
|
+
current_sha = git_repo.sha_for(nil)
|
139
111
|
end
|
112
|
+
current_sha != remote_sha
|
113
|
+
end
|
140
114
|
|
141
|
-
|
142
|
-
|
143
|
-
#
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
size = 0
|
151
|
-
::Dir.glob(globbie) do |f|
|
152
|
-
size += ::File.stat(f).size rescue 0 if ::File.file?(f)
|
153
|
-
if size > @max_bytes
|
154
|
-
exceeded = true
|
155
|
-
break
|
156
|
-
end
|
157
|
-
end
|
115
|
+
# Implements CheckoutBase#do_checkout
|
116
|
+
def do_checkout
|
117
|
+
git_repo = @logger.operation(:cloning, "to #{@repo_dir}") do
|
118
|
+
without_host_key_checking do
|
119
|
+
::RightGit::Git::Repository.clone_to(
|
120
|
+
@repository.url,
|
121
|
+
@repo_dir,
|
122
|
+
:logger => git_repo_logger,
|
123
|
+
:shell => git_repo_shell)
|
158
124
|
end
|
159
|
-
exceeded
|
160
125
|
end
|
126
|
+
do_fetch(git_repo)
|
127
|
+
do_checkout_revision(git_repo)
|
128
|
+
internal_update_tag(git_repo)
|
129
|
+
true
|
130
|
+
end
|
161
131
|
|
162
|
-
|
163
|
-
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
|
168
|
-
|
169
|
-
|
132
|
+
# Implements CheckoutBase#do_update
|
133
|
+
def do_update
|
134
|
+
# note that a recent fetch was performed by remote_differs? and even if
|
135
|
+
# remotes have changed again in the brief interim it would invalidate
|
136
|
+
# the decisions already made if we refetched now.
|
137
|
+
git_repo = git_repo_for(@repo_dir)
|
138
|
+
@logger.operation(:cleanup, "ensure no untracked files in #{@repo_dir}") do
|
139
|
+
git_repo.hard_reset_to(nil)
|
140
|
+
do_clean_all(git_repo)
|
170
141
|
end
|
142
|
+
do_checkout_revision(git_repo)
|
143
|
+
do_clean_all(git_repo) # clean again once we are on requested revision
|
144
|
+
internal_update_tag(git_repo)
|
145
|
+
true
|
146
|
+
end
|
171
147
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
148
|
+
# Implements CheckoutBase#do_update_tag
|
149
|
+
def do_update_tag
|
150
|
+
git_repo = git_repo_for(@repo_dir)
|
151
|
+
without_size_limit(git_repo) do
|
152
|
+
internal_update_tag(git_repo)
|
177
153
|
end
|
154
|
+
true
|
155
|
+
end
|
178
156
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
157
|
+
private
|
158
|
+
|
159
|
+
DEFAULT_BRANCH_NAME = 'master'
|
160
|
+
|
161
|
+
def git_repo_for(dir)
|
162
|
+
::RightGit::Git::Repository.new(
|
163
|
+
dir,
|
164
|
+
:logger => git_repo_logger,
|
165
|
+
:shell => git_repo_shell)
|
166
|
+
end
|
167
|
+
|
168
|
+
def git_repo_logger
|
169
|
+
# note that info-level logging is normally suppressed by scraper so git
|
170
|
+
# repo won't log anything but warnings and errors unless logger is made
|
171
|
+
# verbose.
|
172
|
+
@logger
|
173
|
+
end
|
174
|
+
|
175
|
+
def git_repo_shell
|
176
|
+
@git_repo_shell ||= ::RightScraper::Processes::Shell.new(
|
177
|
+
:logger => git_repo_logger,
|
178
|
+
:initial_directory => repo_dir,
|
179
|
+
:max_bytes => max_bytes,
|
180
|
+
:max_seconds => max_seconds,
|
181
|
+
:watch_directory => repo_dir)
|
182
|
+
end
|
183
|
+
|
184
|
+
def internal_update_tag(git_repo)
|
185
|
+
@repository = @repository.clone
|
186
|
+
@repository.tag = git_repo.sha_for(nil)
|
187
|
+
true
|
188
|
+
end
|
189
|
+
|
190
|
+
def do_checkout_revision(git_repo)
|
191
|
+
@logger.operation(:checkout_revision) do
|
192
|
+
revision = resolve_revision
|
193
|
+
remote_name = validate_revision(git_repo, revision)
|
194
|
+
git_repo.checkout_to(revision, :force => true)
|
195
|
+
git_repo.hard_reset_to(remote_name) if remote_name
|
196
|
+
|
197
|
+
# initialize/update submodules based on current SHA.
|
198
|
+
#
|
199
|
+
# TEAL FIX: there is no support for checking-out same branch/tag in
|
200
|
+
# the submodule(s) but this could be an advanced feature.
|
201
|
+
git_repo.update_submodules(:recursive => true)
|
200
202
|
end
|
203
|
+
true
|
204
|
+
end
|
201
205
|
|
202
|
-
|
203
|
-
|
204
|
-
|
206
|
+
def do_fetch(git_repo)
|
207
|
+
@logger.operation(:fetch) do
|
208
|
+
# delete local tags, which may or may not still exist on remote.
|
209
|
+
git_repo.tags.each do |tag|
|
210
|
+
git_args = ['tag', '-d', tag.name]
|
211
|
+
git_repo.spit_output(git_args)
|
212
|
+
end
|
213
|
+
git_repo.fetch_all(:prune => true)
|
205
214
|
end
|
215
|
+
end
|
206
216
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
+
# Cleans anything that is currently untracked in the repo directory and
|
218
|
+
# any submodules. the idea is to prevent untracked items interfering with
|
219
|
+
# the normal behavior that would result if checkout were always to a clean
|
220
|
+
# directory. just switching between branches and updating submodules can
|
221
|
+
# leave untracked artifacts that affect behavior.
|
222
|
+
def do_clean_all(git_repo)
|
223
|
+
old_initial_directory = git_repo.repo_dir
|
224
|
+
clean_all_options = {
|
225
|
+
:directories => true,
|
226
|
+
:gitignored => true,
|
227
|
+
:submodules => true
|
228
|
+
}
|
229
|
+
relative_paths = [
|
230
|
+
'.',
|
231
|
+
git_repo.submodule_paths(:recursive => true)
|
232
|
+
].flatten
|
233
|
+
relative_paths.each do |relative_path|
|
234
|
+
subdir_path = ::File.expand_path(::File.join(@repo_dir, relative_path))
|
235
|
+
if ::File.directory?(subdir_path)
|
236
|
+
# reuse shell with any watch parameters already set but vary the
|
237
|
+
# initial directory for each submodule.
|
238
|
+
git_repo.shell.initial_directory = subdir_path
|
239
|
+
git_repo.clean_all(clean_all_options)
|
217
240
|
end
|
218
|
-
do_fetch(git)
|
219
|
-
do_checkout_revision(git)
|
220
|
-
do_update_tag git
|
221
241
|
end
|
242
|
+
true
|
243
|
+
rescue ::RightGit::RightGitError => e
|
244
|
+
@logger.note_warning(e.message)
|
245
|
+
false
|
246
|
+
ensure
|
247
|
+
git_repo.shell.initial_directory = old_initial_directory
|
248
|
+
end
|
249
|
+
|
250
|
+
def resolve_revision
|
251
|
+
revision = @repository.tag.to_s.strip
|
252
|
+
revision.empty? ? DEFAULT_BRANCH_NAME : revision.shellescape
|
253
|
+
end
|
222
254
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
255
|
+
# Validates the given revision string to ensure it is safe and sane before
|
256
|
+
# attempting to use it.
|
257
|
+
#
|
258
|
+
# @param [::RightGit::Git::Repository] git_repo for validation
|
259
|
+
# @param [String] revision for validation
|
260
|
+
#
|
261
|
+
# @return [String] remote_name (for branch reset) or nil
|
262
|
+
#
|
263
|
+
# @raise [RetrieverError] on validation failure
|
264
|
+
def validate_revision(git_repo, revision)
|
265
|
+
branches = git_repo.branches(:all => true)
|
266
|
+
local_branches = branches.local
|
267
|
+
remote_branches = branches.remote
|
268
|
+
by_name = lambda { |item| item.name == revision }
|
269
|
+
|
270
|
+
# determine if revision is a tag.
|
271
|
+
remote_name = nil
|
272
|
+
if git_repo.tags.any?(&by_name)
|
273
|
+
if remote_branches.any?(&by_name)
|
274
|
+
# note that git has some resolution scheme for ambiguous SHA, tag,
|
275
|
+
# branch names but we do not support ambiguity.
|
276
|
+
raise RetrieverError, "Ambiguous name is both a remote branch and a tag: #{revision.inspect}"
|
277
|
+
elsif local_branches.any?(&by_name)
|
278
|
+
# odd corner case of a name that once was a remote branch (now
|
279
|
+
# deleted) that has become a tag instead. the user is not exactly
|
280
|
+
# at fault here (aside from being indecisive) so let's attempt to
|
281
|
+
# clean up after him. try switching to another local branch
|
282
|
+
# (i.e. master) and then deleting the obsolete local branch.
|
283
|
+
error_message = "Ambiguous name is both a local branch and a tag: #{revision.inspect}"
|
284
|
+
if revision == DEFAULT_BRANCH_NAME
|
285
|
+
# Darwin Awards winner; scraping with a tag named 'master' :@
|
286
|
+
raise RetrieverError, error_message
|
232
287
|
else
|
233
|
-
|
288
|
+
begin
|
289
|
+
# checkout master and delete obsolete local branch.
|
290
|
+
git_repo.checkout_to(DEFAULT_BRANCH_NAME, :force => true)
|
291
|
+
git_repo.spit_output("branch -D #{revision}")
|
292
|
+
rescue ::RightGit::RightGitError
|
293
|
+
# ignore failed attempt to recover; raise original error.
|
294
|
+
raise RetrieverError, error_message
|
295
|
+
end
|
234
296
|
end
|
235
|
-
end
|
297
|
+
end
|
298
|
+
else
|
299
|
+
# not a tag; SHA or branch.
|
300
|
+
#
|
301
|
+
# note that we could try to trivially determine if revision was a
|
302
|
+
# SHA by matching the SHA1 pattern except that:
|
303
|
+
# 1) git accepts partial SHAs so long as they uniquely distinguish
|
304
|
+
# a commit for checkout.
|
305
|
+
# 2) a branch or tag could name could match the SHA pattern (i.e.
|
306
|
+
# 40 hexadecimal characters) with no warnings from git. git will
|
307
|
+
# even allow a user to use a SHA as a tag name when that SHA
|
308
|
+
# exists (and may represent a different commit).
|
309
|
+
# confusing tags with SHAs should be universally discouraged but we
|
310
|
+
# need to be flexible here.
|
311
|
+
#
|
312
|
+
# a local branch may no longer exist remotely or may be behind or
|
313
|
+
# have diverged from remote branch. handle all cases.
|
314
|
+
remotes = remote_branches.select(&by_name)
|
315
|
+
if remotes.size > 1
|
316
|
+
# multiple remote branches exist (from different origins); branch
|
317
|
+
# name is ambiguous.
|
318
|
+
raise RetrieverError, "Ambiguous remote branch name: #{revision.inspect}"
|
319
|
+
elsif remotes.size == 1
|
320
|
+
# a remote branch exists.
|
321
|
+
remote_name = remotes.first.fullname
|
322
|
+
elsif local_branches.any?(&by_name)
|
323
|
+
# local branch only; failure due to missing remote branch.
|
324
|
+
#
|
325
|
+
# note that obsolete local branches are not supported by retrieval
|
326
|
+
# only because it would give the user a false positive.
|
327
|
+
raise RetrieverError, "Missing remote branch: #{revision.inspect}."
|
328
|
+
end # else a full or partial SHA or unknown revision
|
236
329
|
end
|
330
|
+
remote_name
|
331
|
+
end
|
237
332
|
|
238
|
-
|
239
|
-
|
240
|
-
|
333
|
+
# Temporarily disables checking the size of the repo_dir against the
|
334
|
+
# configured size limit. This permits performing git queries against a repo
|
335
|
+
# on disk that would normally exceed the size limit if it hadn't already
|
336
|
+
# been fully checked out in the past. If a repo has been scraped in the past
|
337
|
+
# and does not have any new commits, then it is acceptable even if it
|
338
|
+
# would exceed the current size limit.
|
339
|
+
def without_size_limit(git_repo)
|
340
|
+
old_max_bytes = git_repo.shell.max_bytes
|
341
|
+
begin
|
342
|
+
git_repo.shell.max_bytes = nil
|
343
|
+
yield
|
344
|
+
ensure
|
345
|
+
git_repo.shell.max_bytes = old_max_bytes
|
241
346
|
end
|
347
|
+
end
|
242
348
|
|
243
|
-
|
244
|
-
|
349
|
+
# Temporarily disable SSH host-key checking for SSH clients invoked by Git, for the duration of the
|
350
|
+
# block that is passed to this method.
|
351
|
+
#
|
352
|
+
# @yield after disabling strict host key checking, yields to caller
|
353
|
+
def without_host_key_checking(&callback)
|
354
|
+
if is_windows?
|
355
|
+
without_host_key_checking_windows(&callback)
|
356
|
+
else
|
357
|
+
without_host_key_checking_linux(&callback)
|
245
358
|
end
|
359
|
+
end
|
246
360
|
|
247
|
-
|
248
|
-
|
249
|
-
|
361
|
+
# Temporarily disable SSH host-key checking for SSH clients invoked by Git, for the duration of the
|
362
|
+
# block that is passed to this method.
|
363
|
+
#
|
364
|
+
# @yield after disabling strict host key checking, yields to caller
|
365
|
+
def without_host_key_checking_linux
|
366
|
+
tmpdir = ::Dir.mktmpdir
|
367
|
+
ssh_cmd = ::File.join(tmpdir, 'ssh')
|
250
368
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
name
|
369
|
+
::File.open(ssh_cmd, 'w') do |cmd|
|
370
|
+
cmd.puts "#!/bin/bash"
|
371
|
+
cmd.puts "exec ssh -o StrictHostKeyChecking=no ${@}"
|
255
372
|
end
|
373
|
+
::FileUtils.chmod(0700, ssh_cmd)
|
256
374
|
|
257
|
-
|
258
|
-
|
259
|
-
|
375
|
+
old_env = ::ENV['GIT_SSH']
|
376
|
+
::ENV['GIT_SSH'] = ssh_cmd
|
377
|
+
yield
|
378
|
+
ensure
|
379
|
+
::FileUtils.rm_rf(tmpdir)
|
380
|
+
::ENV['GIT_SSH'] = old_env
|
381
|
+
end
|
260
382
|
|
261
|
-
|
262
|
-
|
263
|
-
|
383
|
+
# The "ssh.exe" that comes with msysgit doesn't appear to configure things
|
384
|
+
# properly under Windows (or it does for SYSTEM account but not user
|
385
|
+
# accounts) when disabling strict hostname checking. We can instead
|
386
|
+
# temporarily create/replace the "%USERPROFILE%\.ssh\config" file to disable
|
387
|
+
# checking for all hostnames.
|
388
|
+
#
|
389
|
+
# @yield after disabling strict host key checking, yields to caller
|
390
|
+
def without_host_key_checking_windows(&callback)
|
391
|
+
config_path = ::File.expand_path(::File.join(home_dir_windows, '.ssh', 'config'))
|
392
|
+
config_text = <<EOF
|
393
|
+
Host *
|
394
|
+
StrictHostKeyChecking no
|
395
|
+
EOF
|
396
|
+
with_replaced_file(config_path, config_text, &callback)
|
397
|
+
end
|
264
398
|
|
265
|
-
|
266
|
-
|
267
|
-
|
399
|
+
def with_private_key_windows(private_key, &callback)
|
400
|
+
private_key_path = ::File.expand_path(::File.join(home_dir_windows, '.ssh', 'id_rsa'))
|
401
|
+
with_replaced_file(private_key_path, private_key, &callback)
|
402
|
+
end
|
268
403
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
404
|
+
# Utility for replacing a file temporarily within a scope and ensuring it is
|
405
|
+
# restored afterward.
|
406
|
+
#
|
407
|
+
# @param [String] filepath to replace
|
408
|
+
# @param [String] contents to substitute
|
409
|
+
#
|
410
|
+
# @yield after replacing file
|
411
|
+
def with_replaced_file(filepath, contents)
|
412
|
+
::Dir.mktmpdir do |temp_dir|
|
413
|
+
begin
|
414
|
+
temp_path = ::File.join(temp_dir, ::File.basename(filepath))
|
415
|
+
::FileUtils.mkdir_p(::File.dirname(filepath))
|
416
|
+
if ::File.file?(filepath)
|
417
|
+
::FileUtils.mv(filepath, temp_path, :force => true)
|
418
|
+
end
|
419
|
+
::File.open(filepath, 'w') { |f| f.write(contents) }
|
420
|
+
yield
|
421
|
+
ensure
|
422
|
+
begin
|
423
|
+
if ::File.file?(temp_path)
|
424
|
+
::FileUtils.mv(temp_path, filepath, :force => true)
|
425
|
+
elsif ::File.file?(filepath)
|
426
|
+
::File.unlink(filepath)
|
427
|
+
end
|
428
|
+
rescue ::Exception => e
|
429
|
+
@logger.note_warning("Failed to restore #{filepath.inspect}: #{e.message}")
|
430
|
+
end
|
280
431
|
end
|
281
|
-
|
282
|
-
|
283
|
-
old_env = ENV['GIT_SSH']
|
284
|
-
ENV['GIT_SSH'] = ssh_cmd
|
285
|
-
|
286
|
-
result = yield
|
287
|
-
ensure
|
288
|
-
FileUtils.rm_rf(tmpdir)
|
289
|
-
ENV['GIT_SSH'] = old_env
|
432
|
+
end
|
433
|
+
end
|
290
434
|
|
291
|
-
|
435
|
+
# @return default location for git-related configuration files.
|
436
|
+
def home_dir_windows
|
437
|
+
home_dir = ::ENV['USERPROFILE']
|
438
|
+
unless home_dir && ::File.directory?(home_dir)
|
439
|
+
raise RetrieverError, "Invalid USERPROFILE directory: #{home_dir.inspect}"
|
292
440
|
end
|
441
|
+
home_dir
|
442
|
+
end
|
443
|
+
|
444
|
+
# @return [TrueClass|FalseClass] true if running on Windows
|
445
|
+
def is_windows?
|
446
|
+
!!(RUBY_PLATFORM =~ /mswin|win32|dos|mingw|cygwin/)
|
293
447
|
end
|
294
448
|
end
|
295
449
|
end
|