right_scraper 1.0.4 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/right_scraper/scraper.rb +6 -2
- data/lib/right_scraper/scraper_base.rb +35 -3
- data/lib/right_scraper/scrapers/download_scraper.rb +2 -2
- data/lib/right_scraper/scrapers/git_scraper.rb +20 -31
- data/lib/right_scraper/scrapers/svn_scraper.rb +5 -9
- data/lib/right_scraper/watcher.rb +141 -0
- data/right_scraper.gemspec +1 -1
- data/spec/__origin/config +5 -0
- data/spec/download_scraper_spec.rb +1 -1
- data/spec/git_scraper_spec.rb +2 -1
- data/spec/scraper_base_spec.rb +1 -1
- data/spec/svn_scraper_spec.rb +1 -1
- data/spec/watcher_spec.rb +62 -0
- metadata +5 -2
@@ -40,8 +40,12 @@ module RightScale
|
|
40
40
|
#
|
41
41
|
# === Parameters
|
42
42
|
# scrape_dir(String):: Scrape destination directory
|
43
|
-
|
43
|
+
# max_bytes(Integer):: Maximum size allowed for repos, -1 for no limit (default)
|
44
|
+
# max_seconds(Integer):: Maximum number of seconds a single scrape operation should take, -1 for no limit (default)
|
45
|
+
def initialize(scrape_dir, max_bytes = -1, max_seconds = -1)
|
44
46
|
@scrape_dir = scrape_dir
|
47
|
+
@max_bytes = max_bytes
|
48
|
+
@max_seconds = max_seconds
|
45
49
|
@scrapers = {}
|
46
50
|
end
|
47
51
|
|
@@ -70,7 +74,7 @@ module RightScale
|
|
70
74
|
def scrape(repo, &callback)
|
71
75
|
repo = RightScale::Repository.from_hash(repo) if repo.is_a?(Hash)
|
72
76
|
raise "Invalid repository type" unless SCRAPERS.include?(repo.repo_type)
|
73
|
-
@scraper = @scrapers[repo.repo_type] ||= SCRAPERS[repo.repo_type].new(@scrape_dir)
|
77
|
+
@scraper = @scrapers[repo.repo_type] ||= SCRAPERS[repo.repo_type].new(@scrape_dir, @max_bytes, @max_seconds)
|
74
78
|
@scraper.scrape(repo, &callback)
|
75
79
|
@last_repo_dir = @scraper.current_repo_dir
|
76
80
|
@scraper.succeeded?
|
@@ -41,12 +41,15 @@ module RightScale
|
|
41
41
|
# (String) Path to local directory where repository was downloaded
|
42
42
|
attr_reader :current_repo_dir
|
43
43
|
|
44
|
-
# Set path to directory containing all scraped repos
|
44
|
+
# Set path to directory containing all scraped repos as well as space and time upperbounds
|
45
45
|
#
|
46
46
|
# === Parameters
|
47
47
|
# root_dir(String):: Path to scraped repos parent directory
|
48
|
-
|
48
|
+
# max_bytes(Integer):: Maximum size allowed for repos, -1 for no limit (default)
|
49
|
+
# max_seconds(Integer):: Maximum number of seconds a single scrape operation should take, -1 for no limit (default)
|
50
|
+
def initialize(root_dir, max_bytes, max_seconds)
|
49
51
|
@root_dir = root_dir
|
52
|
+
@watcher = Watcher.new(max_bytes, max_seconds)
|
50
53
|
end
|
51
54
|
|
52
55
|
# Common implementation of scrape method for all repository types.
|
@@ -108,6 +111,35 @@ module RightScale
|
|
108
111
|
def scrape_imp
|
109
112
|
raise "Method not implemented"
|
110
113
|
end
|
111
|
-
|
114
|
+
|
115
|
+
# Update state of scraper according to status returned by watcher
|
116
|
+
#
|
117
|
+
# === Parameters
|
118
|
+
# res(RightScale::WatchResult):: Watcher status to be analyzed
|
119
|
+
# msg_title(String):: Error message title in case of failure
|
120
|
+
# update(TrueClass|FalseClass):: Whether the process was launch to incrementally update the repo
|
121
|
+
# ok_codes:: Successful process return codes, only 0 by default
|
122
|
+
#
|
123
|
+
# === Return
|
124
|
+
# true:: Always return true
|
125
|
+
def handle_watcher_result(res, msg_title, update, ok_codes=[0])
|
126
|
+
if res.status == :timeout
|
127
|
+
@errors << "#{msg_title} is taking more time than #{@watcher.max_seconds / 60} minutes, aborting..."
|
128
|
+
FileUtils.rm_rf(@current_repo_dir)
|
129
|
+
elsif res.status == :size_exceeded
|
130
|
+
@errors << "#{msg_title} is taking more space than #{@watcher.max_bytes / 1048576} MB, aborting..."
|
131
|
+
FileUtils.rm_rf(@current_repo_dir)
|
132
|
+
elsif !ok_codes.include?(res.exit_code)
|
133
|
+
if update
|
134
|
+
@callback.call("#{msg_title} failed: #{res.output}, reverting to non incremental update", is_step=false) if @callback
|
135
|
+
FileUtils.rm_rf(@current_repo_dir)
|
136
|
+
@incremental = false
|
137
|
+
else
|
138
|
+
@errors << "#{msg_title} failed: #{res.output}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
112
144
|
end
|
113
145
|
end
|
@@ -36,8 +36,8 @@ module RightScale
|
|
36
36
|
user_opt = @repo.first_credential && @repo.second_credential ? "--user #{@repo.first_credential}:#{@repo.second_credential}" : ''
|
37
37
|
cmd = "curl --fail --silent --show-error --insecure --location #{user_opt} --output \"#{@current_repo_dir}/#{filename}\" '#{@repo.url}' 2>&1"
|
38
38
|
FileUtils.mkdir_p(@current_repo_dir)
|
39
|
-
res =
|
40
|
-
|
39
|
+
res = @watcher.launch_and_watch(cmd, @current_repo_dir)
|
40
|
+
handle_watcher_result(res, 'Download', update=false)
|
41
41
|
if succeeded?
|
42
42
|
unzip_opt = case @repo.url[/\.(.*)$/]
|
43
43
|
when 'bzip', 'bzip2', 'bz2' then 'j'
|
@@ -48,19 +48,17 @@ module RightScale
|
|
48
48
|
msg += "git repository '#{@repo.display_name}'"
|
49
49
|
@callback.call(msg, is_step=true) if @callback
|
50
50
|
ssh_cmd = ssh_command
|
51
|
-
res = ''
|
52
51
|
is_tag = nil
|
53
52
|
is_branch = nil
|
54
|
-
update_failed = false
|
55
53
|
|
56
54
|
if @incremental
|
57
55
|
Dir.chdir(@current_repo_dir) do
|
58
|
-
analysis = git_fetch_and_analyze(ssh_cmd)
|
59
|
-
if
|
56
|
+
analysis = git_fetch_and_analyze(ssh_cmd, update=true)
|
57
|
+
if succeeded? && @incremental
|
60
58
|
is_tag = analysis[:tag]
|
61
59
|
is_branch = analysis[:branch]
|
62
60
|
if !is_tag && !is_branch
|
63
|
-
@callback.call('Nothing to update: repo tag refers to neither a branch nor a tag', is_step=false)
|
61
|
+
@callback.call('Nothing to update: repo tag refers to neither a branch nor a tag', is_step=false) if @callback
|
64
62
|
return true
|
65
63
|
end
|
66
64
|
if is_tag && is_branch
|
@@ -70,35 +68,25 @@ module RightScale
|
|
70
68
|
res = `git checkout #{tag} 2>&1`
|
71
69
|
if $? != 0
|
72
70
|
@callback.call("Failed to checkout #{tag}: #{res}, falling back to cloning", is_step=false) if @callback
|
73
|
-
|
71
|
+
FileUtils.rm_rf(@current_repo_dir)
|
72
|
+
@incremental = false
|
74
73
|
end
|
75
74
|
end
|
76
|
-
else
|
77
|
-
@callback.call("Failed to update repo: #{analysis[:output]}, falling back to cloning", is_step=false) if @callback
|
78
|
-
update_failed = true
|
79
75
|
end
|
80
76
|
end
|
81
77
|
end
|
82
|
-
if update_failed
|
83
|
-
FileUtils.rm_rf(@current_repo_dir)
|
84
|
-
@incremental = false
|
85
|
-
end
|
86
78
|
if !@incremental && succeeded?
|
87
|
-
|
88
|
-
|
79
|
+
git_cmd = "#{ssh_cmd} git clone --quiet --depth 1 \"#{@repo.url}\" \"#{@current_repo_dir}\" 2>&1"
|
80
|
+
res = @watcher.launch_and_watch(git_cmd, @current_repo_dir)
|
81
|
+
handle_watcher_result(res, 'git clone', update=false)
|
89
82
|
if !@repo.tag.nil? && !@repo.tag.empty? && @repo.tag != 'master' && succeeded?
|
90
83
|
Dir.chdir(@current_repo_dir) do
|
91
84
|
if is_tag.nil?
|
92
|
-
analysis = git_fetch_and_analyze(ssh_cmd)
|
93
|
-
|
94
|
-
|
95
|
-
is_branch = analysis[:branch]
|
96
|
-
res += analysis[:output]
|
97
|
-
else
|
98
|
-
@errors << "Failed to analyze repo: #{res}"
|
99
|
-
end
|
85
|
+
analysis = git_fetch_and_analyze(ssh_cmd, update=false)
|
86
|
+
is_tag = analysis[:tag]
|
87
|
+
is_branch = analysis[:branch]
|
100
88
|
end
|
101
|
-
if
|
89
|
+
if succeeded?
|
102
90
|
if is_tag && is_branch
|
103
91
|
@errors << 'Repository tag ambiguous: could be git tag or git branch'
|
104
92
|
elsif is_branch
|
@@ -202,26 +190,27 @@ module RightScale
|
|
202
190
|
# Shallow fetch
|
203
191
|
# Resolves whehter repository tag is a git tag or a git branch
|
204
192
|
# Return output of run commands too
|
193
|
+
# Update errors collection upon failure (check for succeeded? after call)
|
205
194
|
# Note: Assume that current working directory is a git directory
|
206
195
|
#
|
207
196
|
# === Parameters
|
208
197
|
# ssh_cmd(String):: SSH command to be used with git if any
|
198
|
+
# update(FalseClass|TrueClass):: Whether analysis is done as part of an update
|
209
199
|
#
|
210
200
|
# === Return
|
211
201
|
# res(Hash)::
|
212
|
-
# - resp[:success]:: true if fetch was successful, false otherwise
|
213
|
-
# - res[:output] contains the git output
|
214
202
|
# - res[:tag]:: is true if git repo has a tag with a name corresponding to the repository tag
|
215
203
|
# - res[:branch] is true if git repo has a branch with a name corresponding to the repository tag
|
216
|
-
def git_fetch_and_analyze(ssh_cmd)
|
217
|
-
|
218
|
-
|
204
|
+
def git_fetch_and_analyze(ssh_cmd, update)
|
205
|
+
git_cmd = "#{ssh_cmd} git fetch --tags --depth 1 2>&1"
|
206
|
+
res = @watcher.launch_and_watch(git_cmd, @current_repo_dir)
|
207
|
+
handle_watcher_result(res, 'git fetch', update, ok_codes=[0, 1]) # git fetch returns 1 when there is nothing to fetch
|
219
208
|
is_tag = is_branch = false
|
220
|
-
if
|
209
|
+
if succeeded? && (!update || @incremental)
|
221
210
|
is_tag = `git tag`.split("\n").include?(@repo.tag)
|
222
211
|
is_branch = `git branch -r`.split("\n").map { |t| t.strip }.include?("origin/#{@repo.tag}")
|
223
212
|
end
|
224
|
-
{ :
|
213
|
+
{ :tag => is_tag, :branch => is_branch }
|
225
214
|
end
|
226
215
|
|
227
216
|
end
|
@@ -53,22 +53,18 @@ module RightScale
|
|
53
53
|
(@repo.second_credential ? " --password #{@repo.second_credential}" : '') +
|
54
54
|
' 2>&1'
|
55
55
|
Dir.chdir(@current_repo_dir) do
|
56
|
-
res =
|
57
|
-
|
58
|
-
@callback.call("Failed to update repo: #{res}, falling back to checkout", is_step=false) if @callback
|
59
|
-
FileUtils.rm_rf(@current_repo_dir)
|
60
|
-
@incremental = false
|
61
|
-
end
|
56
|
+
res = @watcher.launch_and_watch(svn_cmd, @current_repo_dir)
|
57
|
+
handle_watcher_result(res, 'SVN update', update=true)
|
62
58
|
end
|
63
59
|
end
|
64
|
-
if !@incremental
|
60
|
+
if !@incremental && succeeded?
|
65
61
|
svn_cmd = "svn checkout \"#{@repo.url}\" \"#{@current_repo_dir}\" --no-auth-cache --non-interactive --quiet" +
|
66
62
|
(!@repo.tag.nil? && !@repo.tag.empty? ? " --revision #{@repo.tag}" : '') +
|
67
63
|
(@repo.first_credential ? " --username #{@repo.first_credential}" : '') +
|
68
64
|
(@repo.second_credential ? " --password #{@repo.second_credential}" : '') +
|
69
65
|
' 2>&1'
|
70
|
-
res =
|
71
|
-
|
66
|
+
res = @watcher.launch_and_watch(svn_cmd, @current_repo_dir)
|
67
|
+
handle_watcher_result(res, 'SVN checkout', update=false)
|
72
68
|
end
|
73
69
|
true
|
74
70
|
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright: Copyright (c) 2010 RightScale, Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# 'Software'), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
require 'find'
|
25
|
+
|
26
|
+
module RightScale
|
27
|
+
|
28
|
+
# Encapsulate information returned by watcher
|
29
|
+
class WatchStatus
|
30
|
+
|
31
|
+
# Potential outcome of watcher
|
32
|
+
VALID_STATUSES = [ :success, :timeout, :size_exceeded ]
|
33
|
+
|
34
|
+
attr_reader :status # One of VALID_STATUSES
|
35
|
+
attr_reader :exit_code # Watched process exit code or -1 if process was killed
|
36
|
+
attr_reader :output # Watched process combined output
|
37
|
+
|
38
|
+
# Initialize attibutes
|
39
|
+
def initialize(status, exit_code, output)
|
40
|
+
@status = status
|
41
|
+
@exit_code = exit_code
|
42
|
+
@output = output
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class Watcher
|
48
|
+
|
49
|
+
attr_reader :max_bytes # Maximum size in bytes of watched directory before process is killed
|
50
|
+
attr_reader :max_seconds # Maximum number of elapased seconds before external process is killed
|
51
|
+
|
52
|
+
# Initialize attributes
|
53
|
+
#
|
54
|
+
# max_bytes(Integer):: Maximum size in bytes of watched directory before process is killed
|
55
|
+
# max_seconds(Integer):: Maximum number of elapased seconds before external process is killed
|
56
|
+
def initialize(max_bytes, max_seconds)
|
57
|
+
@max_bytes = max_bytes
|
58
|
+
@max_seconds = max_seconds
|
59
|
+
end
|
60
|
+
|
61
|
+
# Launch given command as external process and watch given directory
|
62
|
+
# so it doesn't exceed given size. Also watch time elapsed and kill
|
63
|
+
# external process if either the size of the watched directory exceed
|
64
|
+
# @max_bytes or the time elapsed exceeds @max_seconds.
|
65
|
+
# Note: This method is not thread-safe, instantiate one watcher per thread
|
66
|
+
#
|
67
|
+
# === Parameters
|
68
|
+
# cmd(String):: Command line to be launched
|
69
|
+
# dest_dir(String):: Watched directory
|
70
|
+
#
|
71
|
+
# === Return
|
72
|
+
# res(RightScale::WatchStatus):: Outcome of watch, see RightScale::WatchStatus
|
73
|
+
def launch_and_watch(cmd, dest_dir)
|
74
|
+
status = nil
|
75
|
+
output = ''
|
76
|
+
|
77
|
+
# Run external process and monitor it in a new thread
|
78
|
+
r = IO.popen(cmd)
|
79
|
+
Thread.new do
|
80
|
+
Process.wait(r.pid)
|
81
|
+
status = $?
|
82
|
+
end
|
83
|
+
|
84
|
+
# Loop until process is done or times out or takes too much space
|
85
|
+
timed_out = repeat(1, @max_seconds) do
|
86
|
+
output += r.readlines.join
|
87
|
+
size = 0
|
88
|
+
Find.find(dest_dir) { |f| size += File.stat(f).size unless File.directory?(f) } if File.directory?(dest_dir)
|
89
|
+
size > @max_bytes || status
|
90
|
+
end
|
91
|
+
|
92
|
+
# Cleanup and report status
|
93
|
+
output += r.readlines.join
|
94
|
+
Process.kill('TERM', r.pid) unless status
|
95
|
+
r.close
|
96
|
+
s = status ? :success : (timed_out ? :timeout : :size_exceeded)
|
97
|
+
exit_code = status && status.exitstatus || -1
|
98
|
+
res = WatchStatus.new(s, exit_code, output)
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
# Run given block in thread and time execution
|
104
|
+
#
|
105
|
+
# === Block
|
106
|
+
# Block whose execution is timed
|
107
|
+
#
|
108
|
+
# === Return
|
109
|
+
# elapsed(Integer):: Number of seconds elapsed while running given block
|
110
|
+
def timed
|
111
|
+
start_at = Time.now
|
112
|
+
yield
|
113
|
+
elapsed = Time.now - start_at
|
114
|
+
end
|
115
|
+
|
116
|
+
# Repeat given block at regular intervals
|
117
|
+
#
|
118
|
+
# === Parameters
|
119
|
+
# seconds(Integer):: Number of seconds between executions
|
120
|
+
# timeout(Integer):: Timeout after which execution stops and method returns
|
121
|
+
#
|
122
|
+
# === Block
|
123
|
+
# Given block gets executed every period seconds until timeout is reached
|
124
|
+
# *or* block returns true
|
125
|
+
#
|
126
|
+
# === Return
|
127
|
+
# res(TrueClass|FalseClass):: true if timeout is reached, false otherwise.
|
128
|
+
def repeat(period, timeout)
|
129
|
+
end_at = Time.now + timeout
|
130
|
+
while res = (Time.now < end_at)
|
131
|
+
exit = false
|
132
|
+
elapsed = timed { exit = yield }
|
133
|
+
break if exit
|
134
|
+
sleep(period - elapsed) if elapsed < period
|
135
|
+
end
|
136
|
+
!res
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
data/right_scraper.gemspec
CHANGED
@@ -23,7 +23,7 @@ require 'rubygems'
|
|
23
23
|
|
24
24
|
spec = Gem::Specification.new do |spec|
|
25
25
|
spec.name = 'right_scraper'
|
26
|
-
spec.version = '1.0.
|
26
|
+
spec.version = '1.0.5'
|
27
27
|
spec.authors = ['Raphael Simon']
|
28
28
|
spec.email = 'raphael@rightscale.com'
|
29
29
|
spec.homepage = 'https://github.com/rightscale/right_scraper'
|
@@ -65,7 +65,7 @@ describe RightScale::DownloadScraper do
|
|
65
65
|
end
|
66
66
|
|
67
67
|
before(:each) do
|
68
|
-
@scraper = RightScale::DownloadScraper.new(@repo_path)
|
68
|
+
@scraper = RightScale::DownloadScraper.new(@repo_path, max_bytes=1024**2, max_seconds=20)
|
69
69
|
@repo = RightScale::Repository.from_hash(:display_name => 'test repo',
|
70
70
|
:repo_type => :download,
|
71
71
|
:url => "file:///#{@download_file}")
|
data/spec/git_scraper_spec.rb
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
25
25
|
require 'scraper_base'
|
26
26
|
require 'repository'
|
27
|
+
require 'watcher'
|
27
28
|
require File.join('scrapers', 'git_scraper')
|
28
29
|
|
29
30
|
describe RightScale::GitScraper do
|
@@ -70,7 +71,7 @@ describe RightScale::GitScraper do
|
|
70
71
|
end
|
71
72
|
|
72
73
|
before(:each) do
|
73
|
-
@scraper = RightScale::GitScraper.new(@repo_path)
|
74
|
+
@scraper = RightScale::GitScraper.new(@repo_path, max_bytes=1024**2, max_seconds=20)
|
74
75
|
@repo = RightScale::Repository.from_hash(:display_name => 'test repo',
|
75
76
|
:repo_type => :git,
|
76
77
|
:url => @origin_path)
|
data/spec/scraper_base_spec.rb
CHANGED
@@ -27,7 +27,7 @@ require 'scraper_base'
|
|
27
27
|
describe RightScale::ScraperBase do
|
28
28
|
|
29
29
|
before(:each) do
|
30
|
-
@base = RightScale::ScraperBase.new('/tmp')
|
30
|
+
@base = RightScale::ScraperBase.new('/tmp', max_bytes=1024**2, max_seconds=20)
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'should initialize the scrape directory' do
|
data/spec/svn_scraper_spec.rb
CHANGED
@@ -66,7 +66,7 @@ describe RightScale::SvnScraper do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
before(:each) do
|
69
|
-
@scraper = RightScale::SvnScraper.new(@repo_path)
|
69
|
+
@scraper = RightScale::SvnScraper.new(@repo_path, max_bytes=1024**2, max_seconds=20)
|
70
70
|
@repo = RightScale::Repository.from_hash(:display_name => 'test repo',
|
71
71
|
:repo_type => :svn,
|
72
72
|
:url => "file://#{@svn_repo_path}")
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright: Copyright (c) 2010 RightScale, Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# 'Software'), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
25
|
+
require 'watcher'
|
26
|
+
|
27
|
+
describe RightScale::Watcher do
|
28
|
+
|
29
|
+
before(:each) do
|
30
|
+
@dest_dir = File.join(File.dirname(__FILE__), '__destdir')
|
31
|
+
FileUtils.mkdir_p(@dest_dir)
|
32
|
+
end
|
33
|
+
|
34
|
+
after(:each) do
|
35
|
+
FileUtils.rm_rf(@dest_dir)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should launch and watch well-behaved processes' do
|
39
|
+
watcher = RightScale::Watcher.new(max_bytes=1, max_seconds=5)
|
40
|
+
status = watcher.launch_and_watch('ruby -e "puts 42; exit 42"', @dest_dir)
|
41
|
+
status.status.should == :success
|
42
|
+
status.exit_code.should == 42
|
43
|
+
status.output.should == "42\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should report timeouts' do
|
47
|
+
watcher = RightScale::Watcher.new(max_bytes=1, max_seconds=2)
|
48
|
+
status = watcher.launch_and_watch('ruby -e "puts 42; sleep 3"', @dest_dir)
|
49
|
+
status.status.should == :timeout
|
50
|
+
status.exit_code.should == -1
|
51
|
+
status.output.should == "42\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should report size exceeded' do
|
55
|
+
watcher = RightScale::Watcher.new(max_bytes=1, max_seconds=5)
|
56
|
+
status = watcher.launch_and_watch("ruby -e 'puts 42; File.open(File.join(\"#{@dest_dir}\", \"test\"), \"w\") { |f| f.puts \"MORE THAN 2 CHARS\" }'", @dest_dir)
|
57
|
+
status.status.should == :size_exceeded
|
58
|
+
status.exit_code.should == -1
|
59
|
+
status.output.should == "42\n"
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_scraper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raphael Simon
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-08 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -32,7 +32,9 @@ files:
|
|
32
32
|
- lib/right_scraper/scrapers/download_scraper.rb
|
33
33
|
- lib/right_scraper/scrapers/git_scraper.rb
|
34
34
|
- lib/right_scraper/scrapers/svn_scraper.rb
|
35
|
+
- lib/right_scraper/watcher.rb
|
35
36
|
- right_scraper.gemspec
|
37
|
+
- spec/__origin/config
|
36
38
|
- spec/download_scraper_spec.rb
|
37
39
|
- spec/git_scraper_spec.rb
|
38
40
|
- spec/rcov.opts
|
@@ -42,6 +44,7 @@ files:
|
|
42
44
|
- spec/spec.opts
|
43
45
|
- spec/spec_helper.rb
|
44
46
|
- spec/svn_scraper_spec.rb
|
47
|
+
- spec/watcher_spec.rb
|
45
48
|
has_rdoc: true
|
46
49
|
homepage: https://github.com/rightscale/right_scraper
|
47
50
|
licenses: []
|