gauntlet 1.0.0

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.
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2008-12-04
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
@@ -0,0 +1,7 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/gauntlet
6
+ lib/gauntlet.rb
7
+ test/test_gauntlet.rb
@@ -0,0 +1,67 @@
1
+ = gauntlet
2
+
3
+ * http://rubyforge.org/projects/seattlerb
4
+
5
+ == DESCRIPTION:
6
+
7
+ Gauntlet is a pluggable means of running code against all the latest
8
+ gems and storing off the data.
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ * Downloads all the latest gems and converts them to tarballs for easy access.
13
+ * Iterates through all downloaded gems, unpacks them, and then runs your code.
14
+ * Automates storage of results to YAML files.
15
+ * Easily skips over projects that already have results (overridable).
16
+ * gauntlet commandline locates your gauntlet library via rubygems:
17
+ * eg. `gauntlet flog` finds gauntlet_flog.rb in the flog gem.
18
+
19
+ == SYNOPSIS:
20
+
21
+ require 'gauntlet'
22
+
23
+ class MyGauntlet < Gauntlet
24
+ def run name
25
+ data[name] = Dir["**/*.rb"]
26
+ self.dirty = true
27
+ end
28
+ end
29
+
30
+ filter = ARGV.shift
31
+ filter = Regexp.new filter if filter
32
+
33
+ gauntlet = MyGauntlet.new
34
+ gauntlet.run_the_gauntlet filter
35
+
36
+ == REQUIREMENTS:
37
+
38
+ * rubygems
39
+
40
+ == INSTALL:
41
+
42
+ * sudo gem install gauntlet
43
+
44
+ == LICENSE:
45
+
46
+ (The MIT License)
47
+
48
+ Copyright (c) 2008 Ryan Davis, Seattle.rb
49
+
50
+ Permission is hereby granted, free of charge, to any person obtaining
51
+ a copy of this software and associated documentation files (the
52
+ 'Software'), to deal in the Software without restriction, including
53
+ without limitation the rights to use, copy, modify, merge, publish,
54
+ distribute, sublicense, and/or sell copies of the Software, and to
55
+ permit persons to whom the Software is furnished to do so, subject to
56
+ the following conditions:
57
+
58
+ The above copyright notice and this permission notice shall be
59
+ included in all copies or substantial portions of the Software.
60
+
61
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
62
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
63
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
64
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
65
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
66
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
67
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,12 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/gauntlet.rb'
6
+
7
+ Hoe.new('gauntlet', Gauntlet::VERSION) do |p|
8
+ p.rubyforge_name = 'seattlerb'
9
+ p.developer('Ryan Davis', 'ryand-ruby@zenspider.com')
10
+ end
11
+
12
+ # vim: syntax=Ruby
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/ruby -ws
2
+
3
+ if ARGV.empty? then
4
+ warn "usage: gauntlet <project>"
5
+ warn " runs gauntlet_<project>.rb"
6
+ exit 1
7
+ end
8
+
9
+ name = ARGV.shift
10
+
11
+ require "rubygems"
12
+ require "gauntlet_#{name}"
@@ -0,0 +1,356 @@
1
+ require 'rubygems/remote_fetcher'
2
+ require 'thread'
3
+ require 'yaml'
4
+
5
+ $u ||= false
6
+ $f ||= false
7
+ $F ||= false
8
+
9
+ Thread.abort_on_exception = true
10
+
11
+ class Gauntlet
12
+ VERSION = '1.0.0'
13
+
14
+ GEMURL = URI.parse 'http://gems.rubyforge.org'
15
+ GEMDIR = File.expand_path "~/.gauntlet"
16
+ DATADIR = File.expand_path "~/.gauntlet/data"
17
+
18
+ # stupid dups usually because of "dash" renames
19
+ STUPID_GEMS = %w(ajax-scaffold-generator
20
+ extract_curves
21
+ flickr-fu
22
+ hpricot-scrub
23
+ html_me
24
+ merb-builder
25
+ merb-jquery
26
+ merb-parts
27
+ merb_exceptions
28
+ merb_helpers
29
+ merb_param_protection
30
+ model_graph
31
+ not_naughty
32
+ rfeedparser-ictv
33
+ spec-converter
34
+ spec_unit)
35
+
36
+ attr_accessor :dirty, :data_file, :data
37
+
38
+ def initialize
39
+ name = self.class.name.downcase.sub(/gauntlet/, '')
40
+ self.data_file = "#{DATADIR}/#{name}-data.yml"
41
+ self.dirty = false
42
+ end
43
+
44
+ def initialize_dir
45
+ Dir.mkdir GEMDIR unless File.directory? GEMDIR
46
+ Dir.mkdir DATADIR unless File.directory? DATADIR
47
+ in_gem_dir do
48
+ File.symlink ".", "cache" unless File.exist? "cache"
49
+ end
50
+ end
51
+
52
+ def source_index
53
+ @index ||= in_gem_dir do
54
+ dump = if ($u and not $F) or not File.exist? '.source_index' then
55
+ url = GEMURL + "Marshal.#{Gem.marshal_version}.Z"
56
+ dump = Gem::RemoteFetcher.fetcher.fetch_path url
57
+ require 'zlib'
58
+ dump = Gem.inflate dump
59
+ open '.source_index', 'wb' do |io| io.write dump end
60
+ dump
61
+ else
62
+ open '.source_index', 'rb' do |io| io.read end
63
+ end
64
+
65
+ Marshal.load dump
66
+ end
67
+ end
68
+
69
+ def latest_gems
70
+ @cache ||= source_index.latest_specs
71
+ end
72
+
73
+ def gems_by_name
74
+ @by_name ||= Hash[*latest_gems.map { |gem|
75
+ [gem.name, gem, gem.full_name, gem]
76
+ }.flatten]
77
+ end
78
+
79
+ def dependencies_of name
80
+ index = source_index
81
+ gems_by_name[name].dependencies.map { |dep| index.search(dep).last }
82
+ end
83
+
84
+ def dependent_upon name
85
+ latest_gems.find_all { |gem|
86
+ gem.dependencies.any? { |dep| dep.name == name }
87
+ }
88
+ end
89
+
90
+ def find_stupid_gems
91
+ gems = Hash.new { |h,k| h[k] = [] }
92
+ stupid = []
93
+ latest = {}
94
+
95
+ latest_gems.each do |spec|
96
+ name = spec.name.gsub(/-/, '_')
97
+ next unless name =~ /_/
98
+ gems[name] << spec
99
+ end
100
+
101
+ gems.reject! { |k,v| v.size == 1 || v.map { |s| s.name }.uniq.size == 1 }
102
+
103
+ gems.each do |k,v|
104
+ sorted = v.sort_by { |spec| spec.version }
105
+ latest[sorted.last.name] = true
106
+ sorted.each do |spec|
107
+ stupid << spec.name unless latest[spec.name]
108
+ end
109
+ end
110
+
111
+ stupid.uniq
112
+ end
113
+
114
+ def update_gem_tarballs
115
+ initialize_dir
116
+
117
+ latest = self.latest_gems
118
+
119
+ puts "updating mirror"
120
+
121
+ in_gem_dir do
122
+ gems = Dir["*.gem"]
123
+ tgzs = Dir["*.tgz"]
124
+
125
+ old = tgzs - latest.map { |spec| "#{spec.full_name}.tgz" }
126
+ unless old.empty? then
127
+ puts "deleting #{old.size} tgzs"
128
+ old.each do |tgz|
129
+ File.unlink tgz
130
+ end
131
+ end
132
+
133
+ tasks = Queue.new
134
+ latest.sort!
135
+ latest.reject! { |spec| tgzs.include? "#{spec.full_name}.tgz" }
136
+ tasks.push(latest.shift) until latest.empty? # LAME
137
+
138
+ puts "fetching #{tasks.size} gems"
139
+
140
+ threads = []
141
+ 10.times do
142
+ threads << Thread.new do
143
+ fetcher = Gem::RemoteFetcher.new nil # fuck proxies
144
+ until tasks.empty? do
145
+ spec = tasks.shift
146
+ full_name = spec.full_name
147
+ tgz_name = "#{full_name}.tgz"
148
+ gem_name = "#{full_name}.gem"
149
+
150
+ unless gems.include? gem_name then
151
+ begin
152
+ warn "downloading #{full_name}"
153
+ fetcher.download(spec, GEMURL, Dir.pwd)
154
+ rescue Gem::RemoteFetcher::FetchError
155
+ warn " failed"
156
+ next
157
+ end
158
+ end
159
+
160
+ warn " converting #{gem_name} to tarball"
161
+
162
+ unless File.directory? full_name then
163
+ system "gem unpack cache/#{gem_name} &> /dev/null"
164
+ system "gem spec -l cache/#{gem_name} > #{full_name}/gemspec"
165
+ end
166
+
167
+ system "chmod -R u+rwX #{full_name} && tar zmcf #{tgz_name} #{full_name} && rm -rf #{full_name} #{gem_name}"
168
+ end
169
+ end
170
+ end
171
+
172
+ threads.each do |thread|
173
+ thread.join
174
+ end
175
+ end
176
+ rescue Interrupt
177
+ warn "user cancelled... quitting"
178
+ exit 1
179
+ end
180
+
181
+ def each_gem filter = nil
182
+ filter ||= /^[\w-]+-\d+(\.\d+)*\.tgz$/
183
+ in_gem_dir do
184
+ Dir["*.tgz"].each do |tgz|
185
+ next unless tgz =~ filter
186
+
187
+ yield File.basename(tgz, ".tgz")
188
+ end
189
+ end
190
+ end
191
+
192
+ def with_gem name
193
+ in_gem_dir do
194
+ begin
195
+ system "tar zxmf #{name}.tgz 2> /dev/null"
196
+ Dir.chdir name do
197
+ yield name
198
+ end
199
+ ensure
200
+ system "rm -r #{name}"
201
+ end
202
+ end
203
+ end
204
+
205
+ def load_yaml path, default = {}
206
+ YAML.load(File.read(path)) rescue default
207
+ end
208
+
209
+ def save_yaml path, data
210
+ File.open("#{path}.new", 'w') do |f|
211
+ warn "*** saving #{path}"
212
+ YAML.dump data, f
213
+ end
214
+ File.rename "#{path}.new", path
215
+ end
216
+
217
+ def in_gem_dir
218
+ Dir.chdir GEMDIR do
219
+ yield
220
+ end
221
+ end
222
+
223
+ ##
224
+ # Override this to customize gauntlet. See run_the_gauntlet for
225
+ # other ways of adding behavior.
226
+
227
+ def run name
228
+ raise "subclass responsibility"
229
+ end
230
+
231
+ ##
232
+ # Override this to return true if the gem should be skipped.
233
+
234
+ def should_skip? name
235
+ self.data[name]
236
+ end
237
+
238
+ ##
239
+ # This is the main driver for gauntlet. filter allows you to pass in
240
+ # a regexp to only run against a subset of the gems available. You
241
+ # can pass a block to run_the_gauntlet or it will call run. Both are
242
+ # passed the name of the gem and are executed within the gem
243
+ # directory.
244
+
245
+ def run_the_gauntlet filter = nil
246
+ initialize_dir
247
+ update_gem_tarballs if $u
248
+
249
+ self.data ||= load_yaml data_file
250
+
251
+ each_gem filter do |name|
252
+ next if should_skip? name
253
+ with_gem name do
254
+ if block_given? then
255
+ yield name
256
+ else
257
+ run name
258
+ end
259
+ end
260
+ end
261
+ rescue Interrupt
262
+ warn "user cancelled. quitting"
263
+ ensure
264
+ save_yaml data_file, data if dirty
265
+ end
266
+ end
267
+
268
+ ############################################################
269
+ # Extensions and Overrides
270
+
271
+ # bug in RemoteFetcher#download prevents multithreading. Remove after 1.3.2
272
+ class Gem::RemoteFetcher
273
+ def download(spec, source_uri, install_dir = Gem.dir)
274
+ if File.writable?(install_dir)
275
+ cache_dir = File.join install_dir, 'cache'
276
+ else
277
+ cache_dir = File.join(Gem.user_dir, 'cache')
278
+ end
279
+
280
+ gem_file_name = "#{spec.full_name}.gem"
281
+ local_gem_path = File.join cache_dir, gem_file_name
282
+
283
+ FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
284
+
285
+ source_uri = URI.parse source_uri unless URI::Generic === source_uri
286
+ scheme = source_uri.scheme
287
+
288
+ # URI.parse gets confused by MS Windows paths with forward slashes.
289
+ scheme = nil if scheme =~ /^[a-z]$/i
290
+
291
+ case scheme
292
+ when 'http', 'https' then
293
+ unless File.exist? local_gem_path then
294
+ begin
295
+ say "Downloading gem #{gem_file_name}" if
296
+ Gem.configuration.really_verbose
297
+
298
+ remote_gem_path = source_uri + "gems/#{gem_file_name}"
299
+
300
+ gem = self.fetch_path remote_gem_path
301
+ rescue Gem::RemoteFetcher::FetchError
302
+ raise if spec.original_platform == spec.platform
303
+
304
+ alternate_name = "#{spec.original_name}.gem"
305
+
306
+ say "Failed, downloading gem #{alternate_name}" if
307
+ Gem.configuration.really_verbose
308
+
309
+ remote_gem_path = source_uri + "gems/#{alternate_name}"
310
+
311
+ gem = self.fetch_path remote_gem_path
312
+ end
313
+
314
+ File.open local_gem_path, 'wb' do |fp|
315
+ fp.write gem
316
+ end
317
+ end
318
+ when nil, 'file' then # TODO test for local overriding cache
319
+ begin
320
+ FileUtils.cp source_uri.to_s, local_gem_path
321
+ rescue Errno::EACCES
322
+ local_gem_path = source_uri.to_s
323
+ end
324
+
325
+ say "Using local gem #{local_gem_path}" if
326
+ Gem.configuration.really_verbose
327
+ else
328
+ raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
329
+ end
330
+
331
+ local_gem_path
332
+ end
333
+ end
334
+
335
+ class Array
336
+ def sum
337
+ sum = 0
338
+ self.each { |i| sum += i }
339
+ sum
340
+ end
341
+
342
+ def average
343
+ return self.sum / self.length.to_f
344
+ end
345
+
346
+ def sample_variance
347
+ avg = self.average
348
+ sum = 0
349
+ self.each { |i| sum += (i - avg) ** 2 }
350
+ return (1 / self.length.to_f * sum)
351
+ end
352
+
353
+ def stddev
354
+ return Math.sqrt(self.sample_variance)
355
+ end
356
+ end
File without changes
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gauntlet
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Davis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-04 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.8.2
24
+ version:
25
+ description: Gauntlet is a pluggable means of running code against all the latest gems and storing off the data.
26
+ email:
27
+ - ryand-ruby@zenspider.com
28
+ executables:
29
+ - gauntlet
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - History.txt
34
+ - Manifest.txt
35
+ - README.txt
36
+ files:
37
+ - History.txt
38
+ - Manifest.txt
39
+ - README.txt
40
+ - Rakefile
41
+ - bin/gauntlet
42
+ - lib/gauntlet.rb
43
+ - test/test_gauntlet.rb
44
+ has_rdoc: true
45
+ homepage: http://rubyforge.org/projects/seattlerb
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --main
49
+ - README.txt
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project: seattlerb
67
+ rubygems_version: 1.3.1
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: Gauntlet is a pluggable means of running code against all the latest gems and storing off the data.
71
+ test_files:
72
+ - test/test_gauntlet.rb