buildbox 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/buildbox.rb +1 -4
- data/lib/buildbox/build.rb +4 -0
- data/lib/buildbox/canceler.rb +18 -0
- data/lib/buildbox/command.rb +20 -20
- data/lib/buildbox/monitor.rb +10 -2
- data/lib/buildbox/runner.rb +2 -1
- data/lib/buildbox/version.rb +1 -1
- data/spec/buildbox/buildbox/command_spec.rb +17 -17
- data/spec/fixtures/sleep_script +1 -1
- metadata +3 -4
- data/bin/buildbox-pty +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17c1b2a9d1b7bc186af0aa5a3d93d7dea50e9864
|
4
|
+
data.tar.gz: dd7a3713cfed6a4f8f04eeb77fece760132833cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b15ed4fb9913f0e48dae8b18d05695b556f0714cf9a042b7f08ffec7773945e2cee92554a0f8f7a4af8870ccdbc92b0159c16df970dcd94f80a3bd16b1260a44
|
7
|
+
data.tar.gz: b266bba36f25497145ff582886caae1aa0da899119092deda3d4a304a24d4e35abc0c4caaca0a518859e19999038901c527f6bad9443ef83d6cb3c6d38af4356
|
data/Gemfile.lock
CHANGED
data/lib/buildbox.rb
CHANGED
@@ -5,6 +5,7 @@ module Buildbox
|
|
5
5
|
autoload :API, "buildbox/api"
|
6
6
|
autoload :Build, "buildbox/build"
|
7
7
|
autoload :Command, "buildbox/command"
|
8
|
+
autoload :Canceler, "buildbox/canceler"
|
8
9
|
autoload :CLI, "buildbox/cli"
|
9
10
|
autoload :Configuration, "buildbox/configuration"
|
10
11
|
autoload :Monitor, "buildbox/monitor"
|
@@ -28,10 +29,6 @@ module Buildbox
|
|
28
29
|
@logger = logger
|
29
30
|
end
|
30
31
|
|
31
|
-
def self.gem_root
|
32
|
-
path = File.expand_path(File.join(__FILE__, "..", ".."))
|
33
|
-
end
|
34
|
-
|
35
32
|
def self.root_path
|
36
33
|
path = Pathname.new File.join(ENV['HOME'], ".buildbox")
|
37
34
|
path.mkpath unless path.exist?
|
data/lib/buildbox/build.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Buildbox
|
2
|
+
class Canceler
|
3
|
+
def self.cancel(build)
|
4
|
+
new(build).cancel
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(build)
|
8
|
+
@build = build
|
9
|
+
end
|
10
|
+
|
11
|
+
def cancel
|
12
|
+
@build.cancel_started = true
|
13
|
+
|
14
|
+
# Kill that damn process, yo!
|
15
|
+
Process.kill 'INT', @build.pid
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/buildbox/command.rb
CHANGED
@@ -13,7 +13,7 @@ module Buildbox
|
|
13
13
|
# the given timeout.
|
14
14
|
class TimeoutExceeded < StandardError; end
|
15
15
|
|
16
|
-
attr_reader :output, :exit_status
|
16
|
+
attr_reader :pid, :output, :exit_status
|
17
17
|
|
18
18
|
def self.run(*args, &block)
|
19
19
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
@@ -36,7 +36,7 @@ module Buildbox
|
|
36
36
|
timeout = @options[:timeout]
|
37
37
|
|
38
38
|
# Build the command we're going to run
|
39
|
-
arguments = [
|
39
|
+
arguments = [ *@arguments ].compact.map(&:to_s) # all arguments must be a string
|
40
40
|
|
41
41
|
# Build the ChildProcess
|
42
42
|
@logger.info("Starting process: #{arguments}")
|
@@ -44,8 +44,15 @@ module Buildbox
|
|
44
44
|
process = ChildProcess.build(*arguments)
|
45
45
|
process.cwd = File.expand_path(@options[:directory] || Dir.pwd)
|
46
46
|
|
47
|
-
# Create the pipes so we can read the output in real
|
48
|
-
|
47
|
+
# Create the pipes so we can read the output in real time. PTY
|
48
|
+
# isn't avaible on all platforms (heroku) so we just fallback to IO.pipe
|
49
|
+
# if it's not presetnt.
|
50
|
+
read_pipe, write_pipe = begin
|
51
|
+
PTY.open
|
52
|
+
rescue
|
53
|
+
IO.pipe
|
54
|
+
end
|
55
|
+
|
49
56
|
process.io.stdout = write_pipe
|
50
57
|
process.io.stderr = write_pipe
|
51
58
|
process.duplex = true
|
@@ -70,6 +77,9 @@ module Buildbox
|
|
70
77
|
write_pipe.close
|
71
78
|
end
|
72
79
|
|
80
|
+
# Store the process id for later cancelling!
|
81
|
+
@pid = process.pid
|
82
|
+
|
73
83
|
# Record the start time for timeout purposes
|
74
84
|
start_time = Time.now.to_i
|
75
85
|
|
@@ -97,7 +107,7 @@ module Buildbox
|
|
97
107
|
next if data.empty?
|
98
108
|
|
99
109
|
output << cleaned_data = UTF8.clean(data)
|
100
|
-
yield cleaned_data if block_given?
|
110
|
+
yield self, cleaned_data if block_given?
|
101
111
|
end
|
102
112
|
end
|
103
113
|
|
@@ -130,7 +140,7 @@ module Buildbox
|
|
130
140
|
# If there's some that we missed
|
131
141
|
if extra_data != ""
|
132
142
|
output << cleaned_data = UTF8.clean(extra_data)
|
133
|
-
yield cleaned_data if block_given?
|
143
|
+
yield self, cleaned_data if block_given?
|
134
144
|
end
|
135
145
|
|
136
146
|
if RUBY_PLATFORM == "java"
|
@@ -145,18 +155,6 @@ module Buildbox
|
|
145
155
|
|
146
156
|
private
|
147
157
|
|
148
|
-
# on heroku, tty isn't avaiable. so we result to just running command through
|
149
|
-
# bash. the downside to this, is that stuff colors aren't outputted because
|
150
|
-
# processes don't think they're being in a terminal.
|
151
|
-
def runner
|
152
|
-
require 'pty'
|
153
|
-
PTY.spawn('whoami')
|
154
|
-
|
155
|
-
[ File.join(Buildbox.gem_root, "bin", "buildbox-pty") ]
|
156
|
-
rescue
|
157
|
-
[ "bash", "-c" ]
|
158
|
-
end
|
159
|
-
|
160
158
|
# Reads data from an IO object while it can, returning the data it reads.
|
161
159
|
# When it encounters a case when it can't read anymore, it returns the
|
162
160
|
# data.
|
@@ -190,7 +188,9 @@ module Buildbox
|
|
190
188
|
# since we use some Ruby 1.9 specific exceptions.
|
191
189
|
|
192
190
|
breakable = false
|
193
|
-
|
191
|
+
|
192
|
+
# EOFError from OSX, EIO is raised by ubuntu
|
193
|
+
if e.is_a?(EOFError) || e.is_a?(Errno::EIO)
|
194
194
|
# An `EOFError` means this IO object is done!
|
195
195
|
breakable = true
|
196
196
|
elsif defined?(IO::WaitReadable) && e.is_a?(IO::WaitReadable)
|
@@ -200,7 +200,7 @@ module Buildbox
|
|
200
200
|
# IO object is not ready to be read from yet. No problem,
|
201
201
|
# we read as much as we can, so we break.
|
202
202
|
breakable = true
|
203
|
-
elsif e.is_a?(Errno::EAGAIN)
|
203
|
+
elsif e.is_a?(Errno::EAGAIN) || e.is_a?(Errno::EWOULDBLOCK)
|
204
204
|
# Otherwise, we just look for the EAGAIN error which should be
|
205
205
|
# all that IO::WaitReadable does in Ruby 1.9.
|
206
206
|
breakable = true
|
data/lib/buildbox/monitor.rb
CHANGED
@@ -16,12 +16,20 @@ module Buildbox
|
|
16
16
|
# update_build http call, and breaking. So to make sure we're using the
|
17
17
|
# same build object throughout this call, we can just deep dup it.
|
18
18
|
build = Marshal.load(Marshal.dump(@build))
|
19
|
-
|
19
|
+
|
20
|
+
if build.started? || build.finished?
|
21
|
+
new_build = @api.update_build(build)
|
22
|
+
|
23
|
+
# Try and cancel the build if we haven't tried already
|
24
|
+
if new_build.state == 'canceled' && !@build.cancelling?
|
25
|
+
Buildbox::Canceler.cancel(@build)
|
26
|
+
end
|
27
|
+
end
|
20
28
|
|
21
29
|
if build.finished?
|
22
30
|
break
|
23
31
|
else
|
24
|
-
sleep
|
32
|
+
sleep 2 # 2 seconds seems reasonable for now
|
25
33
|
end
|
26
34
|
end
|
27
35
|
end
|
data/lib/buildbox/runner.rb
CHANGED
@@ -25,7 +25,8 @@ module Buildbox
|
|
25
25
|
@build.started_at = Time.now.utc
|
26
26
|
|
27
27
|
build.output = ""
|
28
|
-
result = Command.run(script_path, :environment => @build.env, :directory => directory_path) do |chunk|
|
28
|
+
result = Command.run(script_path, :environment => @build.env, :directory => directory_path) do |command, chunk|
|
29
|
+
build.pid = command.pid
|
29
30
|
build.output << chunk
|
30
31
|
end
|
31
32
|
|
data/lib/buildbox/version.rb
CHANGED
@@ -5,34 +5,34 @@ require "spec_helper"
|
|
5
5
|
describe Buildbox::Command do
|
6
6
|
describe "#run" do
|
7
7
|
it "is run within a tty" do
|
8
|
-
result = Buildbox::Command.run(
|
8
|
+
result = Buildbox::Command.run("ruby", "-e", "puts STDOUT.tty?")
|
9
9
|
|
10
10
|
result.output.should == "true"
|
11
11
|
end
|
12
12
|
|
13
13
|
it "successfully runs and returns the output from a simple comment" do
|
14
|
-
result = Buildbox::Command.run('echo hello world')
|
14
|
+
result = Buildbox::Command.run('echo', 'hello world')
|
15
15
|
|
16
16
|
result.exit_status.should == 0
|
17
17
|
result.output.should == "hello world"
|
18
18
|
end
|
19
19
|
|
20
|
-
it "
|
21
|
-
result = Buildbox::Command.run(
|
20
|
+
it "includes stderr" do
|
21
|
+
result = Buildbox::Command.run("ruby", "-e", "STDERR.puts 'stderr lol'")
|
22
22
|
|
23
23
|
result.exit_status.should == 0
|
24
|
-
result.output.should == "
|
24
|
+
result.output.should == "stderr lol"
|
25
25
|
end
|
26
26
|
|
27
27
|
it "handles commands that fail and returns the correct status" do
|
28
|
-
result = Buildbox::Command.run('
|
28
|
+
result = Buildbox::Command.run('bash', '-c', 'exit 123')
|
29
29
|
|
30
|
-
result.exit_status.
|
30
|
+
result.exit_status.should == 123
|
31
31
|
result.output.should == ''
|
32
32
|
end
|
33
33
|
|
34
34
|
it "handles running malformed commands" do
|
35
|
-
result = Buildbox::Command.run('if (')
|
35
|
+
result = Buildbox::Command.run('bash', '-c', 'if (')
|
36
36
|
|
37
37
|
result.exit_status.should_not == 0
|
38
38
|
# bash 3.2.48 prints "syntax error" in lowercase.
|
@@ -45,7 +45,7 @@ describe Buildbox::Command do
|
|
45
45
|
|
46
46
|
it "can collect output in chunks" do
|
47
47
|
chunked_output = ''
|
48
|
-
result = Buildbox::Command.run('echo hello world') do |chunk|
|
48
|
+
result = Buildbox::Command.run('echo', 'hello world') do |command, chunk|
|
49
49
|
unless chunk.nil?
|
50
50
|
chunked_output += chunk
|
51
51
|
end
|
@@ -60,8 +60,8 @@ describe Buildbox::Command do
|
|
60
60
|
result = nil
|
61
61
|
second_result = nil
|
62
62
|
thread = Thread.new do
|
63
|
-
result = Buildbox::Command.run('sillycommandlololol')
|
64
|
-
second_result = Buildbox::Command.run('export FOO=bar; doesntexist.rb')
|
63
|
+
result = Buildbox::Command.run('bash', '-c', 'sillycommandlololol')
|
64
|
+
second_result = Buildbox::Command.run('bash', '-c', 'export FOO=bar; doesntexist.rb')
|
65
65
|
end
|
66
66
|
thread.join
|
67
67
|
|
@@ -76,7 +76,7 @@ describe Buildbox::Command do
|
|
76
76
|
|
77
77
|
it "captures color'd output from a command" do
|
78
78
|
chunked_output = ''
|
79
|
-
result = Buildbox::Command.run(
|
79
|
+
result = Buildbox::Command.run('rspec', FIXTURES_PATH.join('rspec', 'test_spec.rb')) do |command, chunk|
|
80
80
|
chunked_output += chunk unless chunk.nil?
|
81
81
|
end
|
82
82
|
|
@@ -87,7 +87,7 @@ describe Buildbox::Command do
|
|
87
87
|
|
88
88
|
it "runs scripts in a tty" do
|
89
89
|
chunked_output = ''
|
90
|
-
result = Buildbox::Command.run(FIXTURES_PATH.join('tty_script')) do |chunk|
|
90
|
+
result = Buildbox::Command.run(FIXTURES_PATH.join('tty_script')) do |command, chunk|
|
91
91
|
chunked_output += chunk unless chunk.nil?
|
92
92
|
end
|
93
93
|
|
@@ -96,8 +96,8 @@ describe Buildbox::Command do
|
|
96
96
|
end
|
97
97
|
|
98
98
|
it "still runs even if pty isn't available" do
|
99
|
-
PTY.should_receive(:
|
100
|
-
result = Buildbox::Command.run('echo hello world')
|
99
|
+
PTY.should_receive(:open).and_raise(RuntimeError.new)
|
100
|
+
result = Buildbox::Command.run('echo', 'hello world')
|
101
101
|
|
102
102
|
result.exit_status.should == 0
|
103
103
|
result.output.should == "hello world"
|
@@ -115,11 +115,11 @@ describe Buildbox::Command do
|
|
115
115
|
it "can collect chunks from within a thread" do
|
116
116
|
chunks = []
|
117
117
|
|
118
|
-
result = Buildbox::Command.run(FIXTURES_PATH.join('sleep_script')) do |chunk|
|
118
|
+
result = Buildbox::Command.run(FIXTURES_PATH.join('sleep_script')) do |command, chunk|
|
119
119
|
chunks << chunk
|
120
120
|
end
|
121
121
|
|
122
|
-
chunks.should == ["0\r\n", "1\r\n", "2\r\n"]
|
122
|
+
chunks.should == ["test 0\r\n", "test 1\r\n", "test 2\r\n"]
|
123
123
|
end
|
124
124
|
end
|
125
125
|
end
|
data/spec/fixtures/sleep_script
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: buildbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Pitt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -99,7 +99,6 @@ email:
|
|
99
99
|
- me@keithpitt.com
|
100
100
|
executables:
|
101
101
|
- buildbox
|
102
|
-
- buildbox-pty
|
103
102
|
extensions: []
|
104
103
|
extra_rdoc_files: []
|
105
104
|
files:
|
@@ -111,12 +110,12 @@ files:
|
|
111
110
|
- README.md
|
112
111
|
- Rakefile
|
113
112
|
- bin/buildbox
|
114
|
-
- bin/buildbox-pty
|
115
113
|
- buildbox-ruby.gemspec
|
116
114
|
- lib/buildbox.rb
|
117
115
|
- lib/buildbox/agent.rb
|
118
116
|
- lib/buildbox/api.rb
|
119
117
|
- lib/buildbox/build.rb
|
118
|
+
- lib/buildbox/canceler.rb
|
120
119
|
- lib/buildbox/cli.rb
|
121
120
|
- lib/buildbox/command.rb
|
122
121
|
- lib/buildbox/configuration.rb
|
data/bin/buildbox-pty
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# Disable stdout,stderr buffering
|
4
|
-
STDERR.sync = STDOUT.sync = true
|
5
|
-
|
6
|
-
require 'pty'
|
7
|
-
|
8
|
-
# spawn the process in a pseudo terminal so colors out outputted
|
9
|
-
read_io, write_io, pid = PTY.spawn("bash", "-c", ARGV.join(" "))
|
10
|
-
|
11
|
-
# we don't need to write to the spawned io
|
12
|
-
write_io.close
|
13
|
-
|
14
|
-
loop do
|
15
|
-
fds, = IO.select([read_io], nil, nil, 1)
|
16
|
-
if fds
|
17
|
-
# should have some data to read
|
18
|
-
begin
|
19
|
-
print read_io.read_nonblock(10240)
|
20
|
-
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
21
|
-
# do select again
|
22
|
-
rescue EOFError, Errno::EIO # EOFError from OSX, EIO is raised by ubuntu
|
23
|
-
break
|
24
|
-
end
|
25
|
-
end
|
26
|
-
# if fds are empty, timeout expired - run another iteration
|
27
|
-
end
|
28
|
-
|
29
|
-
# we're done reading, yay!
|
30
|
-
read_io.close
|
31
|
-
|
32
|
-
# just wait until its finally finished closing
|
33
|
-
Process.waitpid(pid)
|
34
|
-
|
35
|
-
# exit with the status code that the process returned
|
36
|
-
exit $?.exitstatus
|