buildbox 0.3.2 → 0.3.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0f89d17b118fdfeae221ddd724997ad6892fdb4c
4
- data.tar.gz: f12dab225a000454649464200d544c9e00a39b92
3
+ metadata.gz: 17c1b2a9d1b7bc186af0aa5a3d93d7dea50e9864
4
+ data.tar.gz: dd7a3713cfed6a4f8f04eeb77fece760132833cd
5
5
  SHA512:
6
- metadata.gz: c2ef1cc4e717256591146dec6b118c2bd76caf97d3cc64143616699ae50809aa4d21a1039d72f15c9e7f98a27444500ca97fbfb8068109e50eec27cf63fc3b6e
7
- data.tar.gz: d255170edfba8f35bd03bff55e8f2687584cf3b52375c9a3c31e98b51e5e9a6503d1b0f0a7580b42519ff381725045f0bee2e46411399565a8696b692c4f1c24
6
+ metadata.gz: b15ed4fb9913f0e48dae8b18d05695b556f0714cf9a042b7f08ffec7773945e2cee92554a0f8f7a4af8870ccdbc92b0159c16df970dcd94f80a3bd16b1260a44
7
+ data.tar.gz: b266bba36f25497145ff582886caae1aa0da899119092deda3d4a304a24d4e35abc0c4caaca0a518859e19999038901c527f6bad9443ef83d6cb3c6d38af4356
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- buildbox (0.3.2)
4
+ buildbox (0.3.3)
5
5
  celluloid (~> 0.14)
6
6
  childprocess (~> 0.3)
7
7
  faraday (~> 0.8)
@@ -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?
@@ -7,6 +7,10 @@ module Buildbox
7
7
  exit_status == 0
8
8
  end
9
9
 
10
+ def cancelling?
11
+ cancel_started == true
12
+ end
13
+
10
14
  def started?
11
15
  !started_at.nil?
12
16
  end
@@ -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
@@ -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 = [ *runner, *@arguments ].compact.map(&:to_s) # all arguments must be a string
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 tim
48
- read_pipe, write_pipe = IO.pipe
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
- if e.is_a?(EOFError)
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
@@ -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
- @api.update_build(build) if build.started? || build.finished?
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 3 # 3 seconds seems reasonable for now
32
+ sleep 2 # 2 seconds seems reasonable for now
25
33
  end
26
34
  end
27
35
  end
@@ -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
 
@@ -1,3 +1,3 @@
1
1
  module Buildbox
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.3"
3
3
  end
@@ -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(%{ruby -e "puts STDOUT.tty?"})
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 "redirects stdout to stderr" do
21
- result = Buildbox::Command.run('echo hello world 1>&2')
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 == "hello world"
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('(exit 1)')
28
+ result = Buildbox::Command.run('bash', '-c', 'exit 123')
29
29
 
30
- result.exit_status.should_not == 0
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("rspec #{FIXTURES_PATH.join('rspec', 'test_spec.rb')}") do |chunk|
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(:spawn).and_raise(RuntimeError.new)
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
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  3.times do |i|
4
- puts i
4
+ puts "test #{i}"
5
5
  sleep 1
6
6
  end
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.2
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-09 00:00:00.000000000 Z
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
@@ -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