grosser-zentest 4.0.1

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,96 @@
1
+ This is ZenTest without [AutoTest and UnitDiff](http://github.com/grosser/autotest)
2
+
3
+ ZenTest provides 2 different tools: zentest and multiruby.
4
+
5
+ ZenTest scans your target and unit-test code and writes your missing
6
+ code based on simple naming rules, enabling XP at a much quicker
7
+ pace. ZenTest only works with Ruby and Test::Unit. Nobody uses this
8
+ tool anymore but it is the package namesake, so it stays.
9
+
10
+ multiruby runs anything you want on multiple versions of ruby. Great
11
+ for compatibility checking! Use multiruby_setup to manage your
12
+ installed versions.
13
+
14
+ Install
15
+ =======
16
+ ### Requirements
17
+ * Ruby 1.6+, JRuby 1.1.2+, or rubinius
18
+ * rubygems
19
+
20
+ ###Setup
21
+ sudo gem install grosser-zentest
22
+
23
+ From Source:
24
+ git co git://github.com/grosser/zentest.git && cd zentest
25
+ rake install
26
+
27
+ Strategy
28
+ ========
29
+ There are two strategies intended for ZenTest: test conformance
30
+ auditing and rapid XP.
31
+
32
+ For auditing, ZenTest provides an excellent means of finding methods
33
+ that have slipped through the testing process. I've run it against my
34
+ own software and found I missed a lot in a well tested
35
+ package. Writing those tests found 4 bugs I had no idea existed.
36
+
37
+ ZenTest can also be used to evaluate generated code and execute your
38
+ tests, allowing for very rapid development of both tests and
39
+ implementation.
40
+
41
+ Features
42
+ ========
43
+
44
+ * Scans your ruby code and tests and generates missing methods for you.
45
+ * Test against multiple versions with multiruby.
46
+ * Enhance and automatically audit your rails tests using Test::Rails.
47
+ * Includes a LinuxJournal article on testing with ZenTest written by Pat Eyler.
48
+ * See also: http://blog.zenspider.com/archives/zentest/
49
+ * See also: http://blog.segment7.net/articles/category/zentest
50
+
51
+ Synopsis
52
+ ========
53
+ ZenTest MyProject.rb TestMyProject.rb > missing.rb
54
+
55
+ multiruby_setup mri:svn:current
56
+ multiruby ./TestMyProject.rb
57
+
58
+ (and other stuff for Test::Rails)
59
+
60
+ TODO
61
+ ====
62
+ - cleanup the readme: and insert useful examples + compact instructions + remove blabla
63
+
64
+ License
65
+ =======
66
+ ###This is only ripped from ZenTest
67
+ Ripper: [Michael Grosser](http://pragmatig.wordpress.com)
68
+
69
+ ### ZenTest Authors
70
+ - http://www.zenspider.com/ZSS/Products/ZenTest/
71
+ - http://rubyforge.org/projects/zentest/
72
+ - ryand-ruby@zenspider.com
73
+
74
+ (The MIT License)
75
+
76
+ Copyright (c) 2001-2006 Ryan Davis, Eric Hodel, Zen Spider Software
77
+
78
+ Permission is hereby granted, free of charge, to any person obtaining
79
+ a copy of this software and associated documentation files (the
80
+ "Software"), to deal in the Software without restriction, including
81
+ without limitation the rights to use, copy, modify, merge, publish,
82
+ distribute, sublicense, and/or sell copies of the Software, and to
83
+ permit persons to whom the Software is furnished to do so, subject to
84
+ the following conditions:
85
+
86
+ The above copyright notice and this permission notice shall be
87
+ included in all copies or substantial portions of the Software.
88
+
89
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
90
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
91
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
92
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
93
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
94
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
95
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
96
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 4
3
+ :minor: 0
4
+ :patch: 1
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ exec "multiruby", "-S", "gem", *ARGV
4
+
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ require 'multiruby'
4
+
5
+ root_dir = Multiruby.root_dir
6
+ versions = Multiruby.build_and_install
7
+ versions = ENV['VERSIONS'].split(/:/) if ENV.has_key? 'VERSIONS'
8
+
9
+ if ENV.has_key? 'EXCLUDED_VERSIONS' then
10
+ excludes = Regexp.union(*ENV['EXCLUDED_VERSIONS'].split(/:/))
11
+ versions = versions.delete_if { |v| v =~ excludes }
12
+ end
13
+
14
+ results = {}
15
+ versions.each do |version|
16
+ ruby = "#{root_dir}/install/#{version}/bin/ruby"
17
+
18
+ ruby.sub!(/bin.ruby/, 'bin/rbx') if version =~ /rubinius/
19
+
20
+ puts
21
+ puts "VERSION = #{version}"
22
+ cmd = [ruby, ARGV].flatten.map { |s| s =~ /\"/ ? "'#{s}'" : s }.join(' ')
23
+ cmd.sub!(/#{ENV['HOME']}/, '~')
24
+ puts "CMD = #{cmd}"
25
+ puts
26
+ system ruby, *ARGV
27
+ puts
28
+ puts "RESULT = #{$?}"
29
+ results[version] = $?
30
+ end
31
+
32
+ passed, failed = results.keys.partition { |v| results[v] == 0 }
33
+
34
+ puts
35
+ puts "TOTAL RESULT = #{failed.size} failures out of #{results.size}"
36
+ puts
37
+ puts "Passed: #{passed.join(", ")}"
38
+ puts "Failed: #{failed.join(", ")}"
39
+
40
+ exit failed.size
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ require 'multiruby'
4
+
5
+ ARGV << "help" if ARGV.empty?
6
+
7
+ Dir.chdir Multiruby.root_dir
8
+ Multiruby.setup_dirs(false)
9
+
10
+ ARGV.each do |spec|
11
+ case spec
12
+ when "-h", "--help", "help" then
13
+ Multiruby.help
14
+ exit 0
15
+ when "the_usual" then # TODO: update #help
16
+ ARGV.push(*Multiruby::TAGS.map { |v| "mri:tar:#{v.gsub(/_/, '.')}" })
17
+ ARGV << "build" << "update:rubygems"
18
+ system "multigem install --no-ri --no-rdoc rake minitest ZenTest"
19
+ when "build" then
20
+ Multiruby.build_and_install
21
+ when "clean" then
22
+ Multiruby.clean
23
+ when "list" then
24
+ Multiruby.list
25
+ when /rm:(.*)/ then
26
+ Multiruby.rm $1
27
+ when "rubygems:merge" then
28
+ Multiruby.merge_rubygems
29
+ when "rubygems:update", "update:rubygems" then
30
+ Multiruby.update_rubygems
31
+ when "update" then
32
+ Multiruby.update
33
+ when "tags" then
34
+ p Multiruby.tags
35
+ when "mri:svn:current" then
36
+ ARGV << "mri:svn:releases" << "mri:svn:branches" << "build"
37
+ when "mri:svn:releases" then
38
+ Multiruby::TAGS.each do |v|
39
+ latest = Multiruby.mri_latest_tag v
40
+ abort "Can't find tag #{v}" unless latest
41
+ ARGV << "mri:svn:tag:#{latest}:mri_rel_#{v}"
42
+ end
43
+ ARGV << "build"
44
+ when /mri:svn:branch:(.*)/ then
45
+ ver = "branches/ruby_#{$1}" unless ver == "trunk"
46
+ Multiruby.svn_co "#{Multiruby::MRI_SVN}/#{$1}", "mri_#{$1}"
47
+ ARGV << "build"
48
+ when "mri:svn:branches" then
49
+ Multiruby::BRANCHES.each do |v|
50
+ ARGV << "mri:svn:branch:#{v}"
51
+ end
52
+ ARGV << "build"
53
+ when /mri:svn:tag:(.*):(.*)/ then
54
+ Multiruby.svn_co "#{Multiruby::MRI_SVN}/tags/#{$1}", $2
55
+ ARGV << "build"
56
+ when /mri:svn:tag:(.*)/ then
57
+ ARGV << "mri:svn:tag:#{$1}:#{$1}" << "build"
58
+ when /mri:tar:(.*)/ then
59
+ Multiruby.fetch_tar $1
60
+ ARGV << "build"
61
+ when /rbx:git:current/ then
62
+ Multiruby.git_clone "#{Multiruby::RBX_GIT}/code", "rubinius"
63
+ ARGV << "build"
64
+ when /rbx:ln:(.*)/ then
65
+ Multiruby.rbx_ln $1
66
+ ARGV << "build"
67
+ else
68
+ warn "unknown spec #{spec}"
69
+ end
70
+ end
71
+
@@ -0,0 +1,28 @@
1
+ #!/usr/local/bin/ruby -swI .
2
+
3
+ require 'zentest'
4
+
5
+ $TESTING = true # for ZenWeb and any other testing infrastructure code
6
+
7
+ if defined? $v then
8
+ puts "#{File.basename $0} v#{ZenTest::VERSION}"
9
+ exit 0
10
+ end
11
+
12
+ if defined? $h then
13
+ puts "usage: #{File.basename $0} [-h -v] test-and-implementation-files..."
14
+ puts " -h display this information"
15
+ puts " -v display version information"
16
+ puts " -r Reverse mapping (ClassTest instead of TestClass)"
17
+ puts " -e (Rapid XP) eval the code generated instead of printing it"
18
+ exit 0
19
+ end
20
+
21
+ code = ZenTest.fix(*ARGV)
22
+ if defined? $e then
23
+ require 'test/unit'
24
+ eval code
25
+ else
26
+ print code
27
+ end
28
+
@@ -0,0 +1,9 @@
1
+ class Module
2
+ def focus *wanteds
3
+ wanteds.map! { |m| m.to_s }
4
+ unwanteds = public_instance_methods(false).grep(/test_/) - wanteds
5
+ unwanteds.each do |unwanted|
6
+ remove_method unwanted
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,92 @@
1
+
2
+ ########################################################################
3
+ # The Idea:
4
+ #
5
+ # This is supposed to get us thinking about the various dimensions our
6
+ # testing should address. If there are states orthogonal to each other
7
+ # (eg. readable vs unreadable, logged in vs not logged in) each of
8
+ # those states should comprise a dimension in the matrix. By
9
+ # addressing it this way, we should be able to minimize the amount of
10
+ # setup/teardown code and get full coverage across our actions for all
11
+ # these edge cases and as a result have extremely clear tests.
12
+ #
13
+ ########################################################################
14
+ # Example Test Matrix Specification:
15
+ #
16
+ # matrix :example, :edge1, :edge2, :edge3, ...
17
+ # action :action1, :OK, :e_NF, :mod, ...
18
+ # action :action2, :OK, :e_RO, :na, ...
19
+ # action ...
20
+ #
21
+ ########################################################################
22
+ # Matrix:
23
+ #
24
+ # I envision the setups being a code that combines the different
25
+ # dimensions of edge case state.
26
+ #
27
+ # Something for a CMS might look like: `[df]_[ugo]_[rRwW]` where:
28
+ #
29
+ # + `[df]` for dir/file.
30
+ # + and the rest is in the style of symbolic args to chmod:
31
+ # + u/g/o = user, group, or other
32
+ # + lowercase `X` == `X`able, uppercase `X` == un`X`able, where `X`
33
+ # is read/write.
34
+ #
35
+ ########################################################################
36
+ # Action:
37
+ #
38
+ # :new/:err/:del are just examples, they should have semantic info
39
+ # attached to them.
40
+ #
41
+ # Use :na to specify an inapplicable edge case for that action.
42
+ #
43
+ # Use :OK to specify the standard positive state. It is equivalent to
44
+ # a result with the same name as the action. (eg
45
+ # matrix_test_index). This cleans up the matrix a lot and allows for
46
+ # narrower and more readable columns.
47
+ #
48
+ # Edge cases specific to an action that fall outside the matrix are
49
+ # regular tests.
50
+ #
51
+ ########################################################################
52
+ # Matrix Methods (the legos):
53
+ #
54
+ # Everything else basically equates to lego pieces:
55
+ #
56
+ # + There is one "init" method per matrix: matrix_init_#{descr}(setup_args)
57
+ # + There is one "setup" method per action: matrix_setup_#{action}(setup, expect)
58
+ # + There is one "test" method per result: matrix_test_#{result}(setup)
59
+ #
60
+ # Thus, for the matrix "example" above, the top left-most test will
61
+ # end up calling:
62
+ #
63
+ # matrix_init_example(:edge1)
64
+ # matrix_setup_action1(:edge1, :new)
65
+ # matrix_test_new(:edge1)
66
+ #
67
+ # Read the action method for exact details.
68
+ ########################################################################
69
+
70
+ module FunctionalTestMatrix
71
+ def matrix(name, *setups)
72
+ @@matrix, @@setups = name, setups
73
+ end
74
+
75
+ def action(action, *results)
76
+ testcases = @@setups.zip(results).reject { |a,b| b == :na }
77
+ testcases = Hash[*testcases.flatten]
78
+ matrix = @@matrix # bind to local scope for define_method closure
79
+
80
+ testcases.each do |setup, expected|
81
+ expected_action = expected == :OK ? action : expected
82
+ define_method "test_#{matrix}_#{action}_#{setup}" do
83
+ @action = action
84
+ send "matrix_init_#{matrix}", *setup.to_s.split(/_/).map {|c| c.intern }
85
+ send "matrix_setup_#{action}", setup, expected
86
+ send "matrix_test_#{expected_action}", setup
87
+ end
88
+ end
89
+ end
90
+
91
+ module_function :matrix, :action
92
+ end
@@ -0,0 +1,419 @@
1
+ require 'fileutils'
2
+ require 'open-uri'
3
+
4
+ ##
5
+ # multiruby_setup is a script to help you manage multiruby.
6
+ #
7
+ # usage: multiruby_setup [-h|cmd|spec...]
8
+ #
9
+ # cmds:
10
+ #
11
+ # -h, --help, help = show this help.
12
+ # build = build and install everything. used internally.
13
+ # clean = clean scm build dirs and remove non-scm build dirs.
14
+ # list = print installed versions.
15
+ # rm:$version = remove a particular version.
16
+ # rubygems:merge = symlink all rubygem dirs to one dir.
17
+ # tags = list all tags from svn.
18
+ # update = update svn builds.
19
+ # update:rubygems = update rubygems and nuke install dirs.
20
+ #
21
+ # specs:
22
+ #
23
+ # the_usual = alias for latest versions from tar + rubygems
24
+ # mri:svn:current = alias for mri:svn:releases and mri:svn:branches.
25
+ # mri:svn:releases = alias for supported releases of mri ruby.
26
+ # mri:svn:branches = alias for active branches of mri ruby.
27
+ # mri:svn:branch:$branch = install a specific $branch of mri from svn.
28
+ # mri:svn:tag:$tag = install a specific $tag of mri from svn.
29
+ # mri:tar:$version = install a specific $version of mri from tarball.
30
+ # rbx:ln:$dir = symlink your rbx $dir
31
+ # rbx:git:current = install rbx from git
32
+ #
33
+ # environment variables:
34
+ #
35
+ # GEM_URL = url for rubygems tarballs
36
+ # MRI_SVN = url for MRI SVN
37
+ # RBX_GIT = url for rubinius git
38
+ # RUBY_URL = url for MRI tarballs
39
+ # VERSIONS = what versions to install
40
+ #
41
+ # NOTES:
42
+ #
43
+ # * you can add a symlink to your rubinius build into ~/.multiruby/install
44
+ # * I need patches/maintainers for other implementations.
45
+ #
46
+ module Multiruby
47
+ def self.env name, fallback; ENV[name] || fallback; end # :nodoc:
48
+
49
+ TAGS = %w( 1_8_6 1_8_7 1_9_1)
50
+ BRANCHES = %w(1_8 1_8_6 1_8_7 trunk)
51
+
52
+ VERSIONS = env('VERSIONS', TAGS.join(":")).split(/:/)
53
+ MRI_SVN = env 'MRI_SVN', 'http://svn.ruby-lang.org/repos/ruby'
54
+ RBX_GIT = env 'RBX_GIT', 'git://git.rubini.us'
55
+ RUBY_URL = env 'RUBY_URL', 'http://ftp.ruby-lang.org/pub/ruby'
56
+ GEM_URL = env 'GEM_URL', 'http://files.rubyforge.vm.bytemark.co.uk/rubygems'
57
+
58
+ HELP = []
59
+
60
+ File.readlines(__FILE__).each do |line|
61
+ next unless line =~ /^#( |$)/
62
+ HELP << line.sub(/^# ?/, '')
63
+ end
64
+
65
+ def self.build_and_install
66
+ root_dir = self.root_dir
67
+ versions = []
68
+
69
+ Dir.chdir root_dir do
70
+ self.setup_dirs
71
+
72
+ rubygems = Dir["versions/rubygems*.tgz"]
73
+ abort "You should delete all but one rubygem tarball" if rubygems.size > 1
74
+ rubygem_tarball = File.expand_path rubygems.last rescue nil
75
+
76
+ Dir.chdir "build" do
77
+ Dir["../versions/*"].each do |tarball|
78
+ next if tarball =~ /rubygems/
79
+
80
+ build_dir = File.basename tarball, ".tar.gz"
81
+ version = build_dir.sub(/^ruby-?/, '')
82
+ versions << version
83
+ inst_dir = "#{root_dir}/install/#{version}"
84
+
85
+ unless test ?d, inst_dir then
86
+ unless test ?d, build_dir then
87
+ if test ?d, tarball then
88
+ dir = File.basename tarball
89
+ FileUtils.ln_sf "../versions/#{dir}", "../build/#{dir}"
90
+ else
91
+ puts "creating #{inst_dir}"
92
+ Dir.mkdir inst_dir
93
+ run "tar zxf #{tarball}"
94
+ end
95
+ end
96
+ Dir.chdir build_dir do
97
+ puts "building and installing #{version}"
98
+ if test ?f, "configure.in" then
99
+ gnu_utils_build inst_dir
100
+ elsif test ?f, "Rakefile" then
101
+ rake_build inst_dir
102
+ else
103
+ raise "dunno how to build"
104
+ end
105
+
106
+ if rubygem_tarball and version !~ /1[._-]9|mri_trunk|rubinius/ then
107
+ rubygems = File.basename rubygem_tarball, ".tgz"
108
+ run "tar zxf #{rubygem_tarball}" unless test ?d, rubygems
109
+
110
+ Dir.chdir rubygems do
111
+ run "../ruby ./setup.rb --no-rdoc --no-ri &> ../log.rubygems"
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ versions
121
+ end
122
+
123
+ def self.clean
124
+ self.each_scm_build_dir do |style|
125
+ case style
126
+ when :svn, :git then
127
+ if File.exist? "Rakefile" then
128
+ run "rake clean"
129
+ elsif File.exist? "Makefile" then
130
+ run "make clean"
131
+ end
132
+ else
133
+ FileUtils.rm_rf Dir.pwd
134
+ end
135
+ end
136
+ end
137
+
138
+ def self.each_scm_build_dir
139
+ Multiruby.in_build_dir do
140
+ Dir["*"].each do |dir|
141
+ next unless File.directory? dir
142
+ Dir.chdir dir do
143
+ if File.exist?(".svn") || File.exist?(".git") then
144
+ scm = File.exist?(".svn") ? :svn : :git
145
+ yield scm
146
+ else
147
+ yield :none
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ def self.extract_latest_version url, matching=nil
155
+ file = URI.parse(url).read
156
+ versions = file.scan(/href="(ruby.*tar.gz)"/).flatten.reject { |s|
157
+ s =~ /preview|-rc\d/
158
+ }.sort_by { |s|
159
+ s.split(/\D+/).map { |i| i.to_i }
160
+ }.flatten
161
+ versions = versions.grep(/#{Regexp.escape(matching)}/) if matching
162
+ versions.last
163
+ end
164
+
165
+ def self.fetch_tar v
166
+ in_versions_dir do
167
+ warn " Determining latest version for #{v}"
168
+ ver = v[/\d+\.\d+/]
169
+ base = extract_latest_version("#{RUBY_URL}/#{ver}/", v)
170
+ abort "Could not determine release for #{v}" unless base
171
+ url = File.join RUBY_URL, ver, base
172
+ unless File.file? base then
173
+ warn " Fetching #{base} via HTTP... this might take a while."
174
+ open(url) do |f|
175
+ File.open base, 'w' do |out|
176
+ out.write f.read
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ def self.git_clone url, dir
184
+ Multiruby.in_versions_dir do
185
+ Multiruby.run "git clone #{url} #{dir}" unless File.directory? dir
186
+ FileUtils.ln_sf "../versions/#{dir}", "../build/#{dir}"
187
+ end
188
+ end
189
+
190
+ def self.gnu_utils_build inst_dir
191
+ run "autoconf" unless test ?f, "configure"
192
+ run "./configure --prefix #{inst_dir} &> log.configure" unless test ?f, "Makefile"
193
+ run "nice make -j4 &> log.build"
194
+ run "make install &> log.install"
195
+ end
196
+
197
+ def self.help
198
+ puts HELP.join
199
+ end
200
+
201
+ def self.in_build_dir
202
+ Dir.chdir File.join(self.root_dir, "build") do
203
+ yield
204
+ end
205
+ end
206
+
207
+ def self.in_install_dir
208
+ Dir.chdir File.join(self.root_dir, "install") do
209
+ yield
210
+ end
211
+ end
212
+
213
+ def self.in_root_dir
214
+ Dir.chdir self.root_dir do
215
+ yield
216
+ end
217
+ end
218
+
219
+ def self.in_tmp_dir
220
+ Dir.chdir File.join(self.root_dir, "tmp") do
221
+ yield
222
+ end
223
+ end
224
+
225
+ def self.in_versions_dir
226
+ Dir.chdir File.join(self.root_dir, "versions") do
227
+ yield
228
+ end
229
+ end
230
+
231
+ def self.list
232
+ puts "Known versions:"
233
+ in_install_dir do
234
+ Dir["*"].sort.each do |d|
235
+ puts " #{d}"
236
+ end
237
+ end
238
+ end
239
+
240
+ def self.merge_rubygems
241
+ in_install_dir do
242
+ gems = Dir["*/lib/ruby/gems"]
243
+
244
+ unless test ?d, "../gems" then
245
+ FileUtils.mv gems.first, ".."
246
+ end
247
+
248
+ gems.each do |d|
249
+ FileUtils.rm_rf d
250
+ FileUtils.ln_sf "../../../../gems", d
251
+ end
252
+ end
253
+ end
254
+
255
+ def self.mri_latest_tag v
256
+ Multiruby.tags.grep(/#{v}/).last
257
+ end
258
+
259
+ def self.rake_build inst_dir
260
+ run "rake &> log.build"
261
+ FileUtils.ln_sf "../build/#{File.basename Dir.pwd}", inst_dir
262
+ end
263
+
264
+ def self.rbx_ln dir
265
+ dir = File.expand_path dir
266
+ Multiruby.in_versions_dir do
267
+ FileUtils.ln_sf dir, "rubinius"
268
+ FileUtils.ln_sf "../versions/rubinius", "../install/rubinius"
269
+ end
270
+ end
271
+
272
+ def self.rm name
273
+ Multiruby.in_root_dir do
274
+ FileUtils.rm_rf Dir["*/#{name}"]
275
+ f = "versions/ruby-#{name}.tar.gz"
276
+ File.unlink f if test ?f, f
277
+ end
278
+ end
279
+
280
+ def self.root_dir
281
+ root_dir = File.expand_path(ENV['MULTIRUBY'] ||
282
+ File.join(ENV['HOME'], ".multiruby"))
283
+
284
+ unless test ?d, root_dir then
285
+ puts "creating #{root_dir}"
286
+ Dir.mkdir root_dir, 0700
287
+ end
288
+
289
+ root_dir
290
+ end
291
+
292
+ def self.run cmd
293
+ puts "Running command: #{cmd}"
294
+ raise "ERROR: Command failed with exit code #{$?}" unless system cmd
295
+ end
296
+
297
+ def self.setup_dirs download = true
298
+ %w(build install versions tmp).each do |dir|
299
+ unless test ?d, dir then
300
+ puts "creating #{dir}"
301
+ Dir.mkdir dir
302
+ if dir == "versions" && download then
303
+ warn " Downloading initial ruby tarballs to ~/.multiruby/versions:"
304
+ VERSIONS.each do |v|
305
+ self.fetch_tar v
306
+ end
307
+ warn " ...done"
308
+ warn " Put other ruby tarballs in ~/.multiruby/versions to use them."
309
+ end
310
+ end
311
+ end
312
+ end
313
+
314
+ def self.svn_co url, dir
315
+ Multiruby.in_versions_dir do
316
+ Multiruby.run "svn co #{url} #{dir}" unless File.directory? dir
317
+ FileUtils.ln_sf "../versions/#{dir}", "../build/#{dir}"
318
+ end
319
+ end
320
+
321
+ def self.tags
322
+ tags = nil
323
+ Multiruby.in_tmp_dir do
324
+ cache = "svn.tag.cache"
325
+ File.unlink cache if Time.now - File.mtime(cache) > 3600 rescue nil
326
+
327
+ File.open cache, "w" do |f|
328
+ f.write `svn ls #{MRI_SVN}/tags/`
329
+ end unless File.exist? cache
330
+
331
+ tags = File.read(cache).split(/\n/).grep(/^v/).reject {|s| s =~ /preview/}
332
+ end
333
+
334
+ tags = tags.sort_by { |s| s.scan(/\d+/).map { |s| s.to_i } }
335
+ end
336
+
337
+ def self.update
338
+ # TODO:
339
+ # update will look at the dir name and act accordingly rel_.* will
340
+ # figure out latest tag on that name and svn sw to it trunk and
341
+ # others will just svn update
342
+
343
+ clean = []
344
+
345
+ self.each_scm_build_dir do |style|
346
+ dir = File.basename(Dir.pwd)
347
+ warn dir
348
+
349
+ case style
350
+ when :svn then
351
+ case dir
352
+ when /mri_\d/ then
353
+ system "svn cleanup" # just in case
354
+ svn_up = `svn up`
355
+ in_build_dir do
356
+ if svn_up =~ /^[ADUCG] / then
357
+ clean << dir
358
+ else
359
+ warn " no update"
360
+ end
361
+ FileUtils.ln_sf "../build/#{dir}", "../versions/#{dir}"
362
+ end
363
+ when /mri_rel_(.+)/ then
364
+ ver = $1
365
+ url = `svn info`[/^URL: (.*)/, 1]
366
+ latest = self.mri_latest_tag(ver).chomp('/')
367
+ new_url = File.join(File.dirname(url), latest)
368
+ if new_url != url then
369
+ run "svn sw #{new_url}"
370
+ clean << dir
371
+ else
372
+ warn " no update"
373
+ end
374
+ else
375
+ warn " update in this svn dir not supported yet: #{dir}"
376
+ end
377
+ when :git then
378
+ case dir
379
+ when /rubinius/ then
380
+ run "rake git:update build" # minor cheat by building here
381
+ else
382
+ warn " update in this git dir not supported yet: #{dir}"
383
+ end
384
+ else
385
+ warn " update in non-svn dir not supported yet: #{dir}"
386
+ end
387
+ end
388
+
389
+ in_install_dir do
390
+ clean.each do |dir|
391
+ warn "removing install/#{dir}"
392
+ FileUtils.rm_rf dir
393
+ end
394
+ end
395
+ end
396
+
397
+ def self.update_rubygems
398
+ warn " Determining latest version for rubygems"
399
+ html = URI.parse(GEM_URL).read
400
+
401
+ versions = html.scan(/href="rubygems-update-(\d+(?:\.\d+)+).gem/i).flatten
402
+ latest = versions.sort_by { |s| s.scan(/\d+/).map { |s| s.to_i } }.last
403
+
404
+ Multiruby.in_versions_dir do
405
+ file = "rubygems-#{latest}.tgz"
406
+ unless File.file? file then
407
+ warn " Fetching rubygems-#{latest}.tgz via HTTP."
408
+ File.unlink(*Dir["rubygems*"])
409
+ File.open file, 'w' do |f|
410
+ f.write URI.parse(GEM_URL+"/"+file).read
411
+ end
412
+ end
413
+ end
414
+
415
+ Multiruby.in_install_dir do
416
+ FileUtils.rm_rf Dir["*"]
417
+ end
418
+ end
419
+ end