Class: Tinderbox::GemTinderbox

Inherits:
Object
  • Object
show all
Defined in:
lib/tinderbox/gem_tinderbox.rb

Overview

GemTinderbox is a tinderbox for RubyGems.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, username, password) ⇒ GemTinderbox

Creates a new GemTinderbox that will submit results to host as username using password.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/tinderbox/gem_tinderbox.rb', line 157

def initialize(host, username, password)
  @host = host
  @username = username
  @password = password
  @root = nil
  @timeout = 120

  @source_info_cache = nil 
  @seen_gem_names = []
  @wait_time = 300

  @fc = Firebrigade::Cache.new @host, @username, @password
  @target_id = nil
end

Instance Attribute Details

#rootObject

Root directory that the GemTinderbox will use.



22
23
24
# File 'lib/tinderbox/gem_tinderbox.rb', line 22

def root
  @root
end

#timeoutObject

Timeout for GemRunner.



27
28
29
# File 'lib/tinderbox/gem_tinderbox.rb', line 27

def timeout
  @timeout
end

Class Method Details

.process_args(args) ⇒ Object

Processes args into options.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/tinderbox/gem_tinderbox.rb', line 32

def self.process_args(args)
  opts_file = File.expand_path '~/.gem_tinderbox'
  options = {}

  if File.exist? opts_file then
    File.readlines(opts_file).map { |l| l.chomp.split '=', 2 }.each do |k,v|
      v = true  if v == 'true'
      v = false if v == 'false'
      v = Integer(v) if k == 'Timeout'
      options[k.intern] = v
    end
  end

  options[:Daemon] ||= false
  options[:Timeout] ||= 120

  opts = OptionParser.new do |opts|
    opts.banner = "Usage: #{File.basename $0} [options]"
    opts.separator ''
    opts.separator 'Options may also be set in the options file ~/.gem_tinderbox.'
    opts.separator ''
    opts.separator 'Example ~/.gem_tinderbox'
    opts.separator "\tServer=firebrigade.example.com"
    opts.separator "\tUsername=my username"
    opts.separator "\tPassword=my password"
    opts.separator "\tRoot=/path/to/tinderbox/root"

    opts.separator ''

    opts.on("-s", "--server HOST",
            "Firebrigade server host",
            "Default: #{options[:Server].inspect}",
            "Options file name: Server") do |server|
      options[:Server] = server
    end

    opts.on("-u", "--username USERNAME",
            "Firebrigade username",
            "Default: #{options[:Username].inspect}",
            "Options file name: Username") do |username|
      options[:Username] = username
    end

    opts.on("-p", "--password PASSWORD",
            "Firebrigade password",
            "Default: Read from ~/.gem_tinderbox",
            "Options file name: Password") do |password|
      options[:Password] = password
    end

    opts.separator ''

    opts.on("-t", "--timeout TIMEOUT",
            "Maximum time to wait for a gem's tests to",
            "finish",
            "Default: #{options[:Timeout]}",
            Numeric) do |timeout|
      options[:Timeout] = timeout
    end

    opts.on("-r", "--root ROOT",
            "Root directory for gem tinderbox",
            "Default: #{options[:Root]}",
            "Gems will be lit on fire here.") do |root|
      options[:Root] = root
    end

    opts.on("-d", "--daemonize",
            "Run as a daemon process",
            "Default: #{options[:Daemon]}") do |daemon|
      options[:Daemon] = true
    end
  end

  opts.version = Tinderbox::VERSION
  opts.release = nil

  opts.parse! args

  if options[:Server].nil? or
     options[:Username].nil? or
     options[:Password].nil? then
    $stderr.puts opts
    $stderr.puts
    $stderr.puts "Firebrigade Server not set"     if options[:Server].nil?
    $stderr.puts "Firebrigade Username not set" if options[:Username].nil?
    $stderr.puts "Firebrigade Password not set" if options[:Password].nil?
    exit 1
  end

  return options
rescue OptionParser::ParseError
  $stderr.puts opts
  exit 1
end

.run(args = ARGV) ⇒ Object

Starts a GemTinderbox.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/tinderbox/gem_tinderbox.rb', line 131

def self.run(args = ARGV)
  options = process_args args

  tinderbox = new options[:Server], options[:Username], options[:Password]
  tinderbox.root = options[:Root]
  tinderbox.timeout = options[:Timeout]

  if options[:Daemon] then
    require 'webrick/server'
    WEBrick::Daemon.start
  end

  tinderbox.run

rescue Interrupt, SystemExit
  exit
rescue Exception => e
  puts "#{e.message}(#{e.class}):"
  puts "\t#{e.backtrace.join "\n\t"}"
  exit 1
end

Instance Method Details

#new_gemsObject

Finds new gems in the source_info_cache



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/tinderbox/gem_tinderbox.rb', line 175

def new_gems
  update_gems

  latest_gems = {}
  source_info_cache.cache_data.each do |source, sic_e|
    sic_e.source_index.latest_specs.each do |name, spec|
      latest_gems[name] = spec
    end
  end

  new_gem_names = latest_gems.keys - @seen_gem_names

  @seen_gem_names = latest_gems.keys

  latest_gems.values_at(*new_gem_names)
end

#runObject

Tests all the gems, then waits a while and tests anything that is new in the index. If an unhandled error is encountered, GemTinderbox waits a minute then starts from the beginning. (Since information is cached, GemTinderbox won’t pound on Firebrigade.)



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/tinderbox/gem_tinderbox.rb', line 198

def run
  @seen_gem_names = []
  @target_id ||= @fc.get_target_id

  loop do
    new_gems.each do |spec| run_spec spec end
    sleep @wait_time
  end
rescue RCRest::CommunicationError, Gem::RemoteFetcher::FetchError,
       Gem::RemoteSourceException => e
  wait = Time.now + 60

  $stderr.puts e.message
  $stderr.puts "Will retry at #{wait}"

  unless $TESTING then
    sleep 60
    retry
  end
end

#run_spec(spec) ⇒ Object

Runs Gem::Specification spec using a GemRunner then submits the results to Firebrigade.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/tinderbox/gem_tinderbox.rb', line 223

def run_spec(spec)
  $stderr.puts "*** Checking #{spec.full_name}"

  version_id = @fc.get_version_id spec
  return if tested? version_id

  $stderr.puts "*** Igniting (http://#{@host}/gem/show/#{spec.name}/#{spec.version})"
  begin
    build = test_gem spec
  rescue Tinderbox::BuildError, Tinderbox::InstallError => e
    @seen_gem_names.delete spec.full_name
    $stderr.puts "*** Failed to install (#{e.class})"
    return
  rescue Tinderbox::InstallError => e
    $stderr.puts "*** Failed to install (#{e.class}), will try again later"
    return
  end

  if build.successful then
    $stderr.puts "*** I couldn't light #{spec.full_name} on fire"
  else
    $stderr.puts "*** I lit #{spec.full_name} on fire!"
  end

  build.submit version_id, @target_id, @host, @username, @password

  build
end

#source_info_cacheObject

Rubygems’ source info cache



255
256
257
258
# File 'lib/tinderbox/gem_tinderbox.rb', line 255

def source_info_cache
  return @source_info_cache if @source_info_cache
  @source_info_cache = Gem::SourceInfoCache.cache
end

#test_gem(spec) ⇒ Object

Tests the Gem::Specification spec and returns a Build containing its results.



264
265
266
267
268
# File 'lib/tinderbox/gem_tinderbox.rb', line 264

def test_gem(spec)
  runner = Tinderbox::GemRunner.new spec.name, spec.version.to_s, root
  runner.timeout = @timeout
  runner.run
end

#tested?(version_id) ⇒ Boolean

Checks the server to see if version_id has been tested.

Returns:

  • (Boolean)


273
274
275
# File 'lib/tinderbox/gem_tinderbox.rb', line 273

def tested?(version_id)
  !!@fc.get_build_id(version_id, @target_id)
end

#update_gemsObject

Refreshes Rubygems’ source info cache



280
281
282
# File 'lib/tinderbox/gem_tinderbox.rb', line 280

def update_gems
  source_info_cache.refresh
end