isolate 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,8 @@
1
+ === 1.4.0 / 2009-09-30
2
+
3
+ * Added automatic cleanup.
4
+ * Minor code refactoring.
5
+
1
6
  === 1.3.0 / 2009-09-23
2
7
 
3
8
  * Add support for Gem build args. See the README for details.
data/README.rdoc CHANGED
@@ -78,11 +78,17 @@ exceptions, <tt>:source</tt> and <tt>:args</tt>.
78
78
 
79
79
  === Installing Isolated Gems
80
80
 
81
- By default, Isolate will install your gems automatically. You can pass
82
- <tt>:install</tt> and <tt>:verbose</tt> options to control things:
81
+ By default, Isolate will install and clean up your gems
82
+ automatically. You can pass the <tt>:cleanup</tt>, <tt>:install</tt>,
83
+ and <tt>:verbose</tt> options to control things:
84
+
85
+ # don't remove unnecesary gems
86
+ Isolate.gems "vendor/isolated", :cleanup => false do
87
+ ...
88
+ end
83
89
 
84
90
  # install, but quietly
85
- Isolate.gems "vendor/isolated" :verbose => false do
91
+ Isolate.gems "vendor/isolated", :verbose => false do
86
92
  ...
87
93
  end
88
94
 
@@ -129,16 +135,13 @@ the preinitializer:
129
135
  # Twitter authentication
130
136
  gem "oauth", "~> 0.3"
131
137
 
132
- environment :development, :test do
133
- gem "modelizer" # easy model factories
138
+ environment :cucumber, :development, :test do
139
+ gem "cucumber" # stories!
140
+ gem "modelizer" # easy model factories
134
141
  gem "sqlite3-ruby" # database support
135
142
  gem "vlad" # deployment
136
143
  gem "webrat" # integration tests
137
144
  end
138
-
139
- environment :cucumber do
140
- gem "cucumber" # stories!
141
- end
142
145
  end
143
146
 
144
147
  Since this is in the preinitializer, Isolate will install and activate
data/lib/isolate.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "rubygems/dependency_installer"
2
+ require "rubygems/uninstaller"
2
3
  require "rubygems/requirement"
3
4
 
4
5
  # Restricts +GEM_PATH+ and +GEM_HOME+ and provides a DSL for
@@ -14,9 +15,13 @@ class Isolate
14
15
  def matches? environment # :nodoc:
15
16
  environments.empty? || environments.include?(environment)
16
17
  end
18
+
19
+ def matches_spec? spec
20
+ self.name == spec.name and self.requirement.satisfied_by? spec.version
21
+ end
17
22
  end
18
23
 
19
- VERSION = "1.3.0" # :nodoc:
24
+ VERSION = "1.4.0" # :nodoc:
20
25
 
21
26
  attr_reader :entries # :nodoc:
22
27
 
@@ -28,6 +33,7 @@ class Isolate
28
33
 
29
34
  def self.activate environment
30
35
  instance.activate environment
36
+ instance.cleanup if instance.cleanup?
31
37
  end
32
38
 
33
39
  # Declare an isolated RubyGems environment, installed in +path+. The
@@ -36,7 +42,7 @@ class Isolate
36
42
  #
37
43
  # Option defaults:
38
44
  #
39
- # { :install => true, :verbose => true }
45
+ # { :cleanup => true, :install => true, :verbose => true }
40
46
 
41
47
  def self.gems path, options = {}, &block
42
48
  @@instance = new path, options, &block
@@ -65,9 +71,11 @@ class Isolate
65
71
  @enabled = false
66
72
  @entries = []
67
73
  @environments = []
68
- @install = options.key?(:install) ? options[:install] : true
69
74
  @path = path
70
- @verbose = options.key?(:verbose) ? options[:verbose] : true
75
+
76
+ @install = options.fetch :install, true
77
+ @verbose = options.fetch :verbose, true
78
+ @cleanup = @install && options.fetch(:cleanup, true)
71
79
 
72
80
  instance_eval(&block) if block_given?
73
81
  end
@@ -85,6 +93,34 @@ class Isolate
85
93
  self
86
94
  end
87
95
 
96
+ def cleanup
97
+ activated = Gem.loaded_specs.values.map { |s| s.full_name }
98
+ extra = Gem.source_index.gems.values.sort.reject { |spec|
99
+ activated.include? spec.full_name or
100
+ entries.any? { |e| e.matches_spec? spec }
101
+ }
102
+
103
+ log "Cleaning..." unless extra.empty?
104
+
105
+ padding = extra.size.to_s.size # omg... heaven forbid you use math
106
+ format = "[%0#{padding}d/%s] Nuking %s."
107
+ extra.each_with_index do |e, i|
108
+ log format % [i + 1, extra.size, e.full_name]
109
+
110
+ Gem::DefaultUserInteraction.use_ui Gem::SilentUI.new do
111
+ Gem::Uninstaller.new(e.name,
112
+ :version => e.version,
113
+ :ignore => true,
114
+ :executables => true,
115
+ :install_dir => self.path).uninstall
116
+ end
117
+ end
118
+ end
119
+
120
+ def cleanup? # :nodoc:
121
+ @cleanup
122
+ end
123
+
88
124
  def disable # :nodoc:
89
125
  return self unless enabled?
90
126
 
@@ -130,14 +166,12 @@ class Isolate
130
166
  # Restricts +gem+ calls inside +block+ to a set of +environments+.
131
167
 
132
168
  def environment *environments, &block
133
- old = @environments.dup
134
- @environments.concat environments.map { |e| e.to_s }
169
+ old = @environments
170
+ @environments = @environments.dup.concat environments.map { |e| e.to_s }
135
171
 
136
- begin
137
- instance_eval(&block)
138
- ensure
139
- @environments = old
140
- end
172
+ instance_eval(&block)
173
+ ensure
174
+ @environments = old
141
175
  end
142
176
 
143
177
  # Express a gem dependency. Works pretty much like RubyGems' +gem+
@@ -147,16 +181,22 @@ class Isolate
147
181
  def gem name, *requirements
148
182
  options = Hash === requirements.last ? requirements.pop : {}
149
183
 
150
- requirement = requirements.empty? ?
151
- Gem::Requirement.default :
152
- Gem::Requirement.new(requirements)
184
+ requirement = if requirements.empty? then
185
+ Gem::Requirement.default
186
+ else
187
+ Gem::Requirement.new(requirements)
188
+ end
153
189
 
154
- entry = Entry.new name, requirement, @environments.dup, options
190
+ entry = Entry.new name, requirement, @environments, options
155
191
 
156
192
  entries << entry
157
193
  entry
158
194
  end
159
195
 
196
+ def log s
197
+ $stderr.puts s if verbose?
198
+ end
199
+
160
200
  def install environment = nil # :nodoc:
161
201
  env = environment.to_s if environment
162
202
 
@@ -164,15 +204,17 @@ class Isolate
164
204
  !Gem.available?(e.name, *e.requirement.as_list) && e.matches?(env)
165
205
  end
166
206
 
207
+ log "Isolating #{environment}..." unless installable.empty?
208
+
209
+ padding = installable.size.to_s.size # omg... heaven forbid you use math
210
+ format = "[%0#{padding}d/%s] Isolating %s (%s)."
167
211
  installable.each_with_index do |e, i|
168
- if verbose?
169
- padding = installable.size.to_s.size
170
- progress = "[%0#{padding}d/%s]" % [i + 1, installable.size]
171
- warn "#{progress} Isolating #{e.name} (#{e.requirement})."
172
- end
212
+ log format % [i + 1, installable.size, e.name, e.requirement]
173
213
 
174
214
  old = Gem.sources.dup
175
- options = e.options.merge :install_dir => path
215
+ options = e.options.merge(:install_dir => path,
216
+ :generate_rdoc => false,
217
+ :generate_ri => false)
176
218
  source = options.delete :source
177
219
  args = options.delete :args
178
220
  Gem.sources = Array(source) if source
data/test/test_isolate.rb CHANGED
@@ -4,6 +4,8 @@ require "rubygems/requirement"
4
4
  require "isolate"
5
5
 
6
6
  class TestIsolate < MiniTest::Unit::TestCase
7
+ WITH_HOE = "test/fixtures/with-hoe"
8
+
7
9
  def setup
8
10
  @isolate = Isolate.new "tmp/gems", :install => false, :verbose => false
9
11
  end
@@ -11,24 +13,25 @@ class TestIsolate < MiniTest::Unit::TestCase
11
13
  def teardown
12
14
  @isolate.disable
13
15
  Isolate.instance.disable if Isolate.instance
14
- Gem::DependencyInstaller.reset_last_install
16
+ Gem::DependencyInstaller.reset_value
17
+ Gem::Uninstaller.reset_value
15
18
  FileUtils.rm_rf "tmp/gems"
16
19
  end
17
20
 
18
21
  def test_self_gems
19
22
  assert_nil Isolate.instance
20
23
 
21
- Isolate.gems "test/fixtures/with-hoe" do
24
+ Isolate.gems WITH_HOE do
22
25
  gem "hoe"
23
26
  end
24
27
 
25
28
  refute_nil Isolate.instance
26
- assert_equal "test/fixtures/with-hoe", Isolate.instance.path
29
+ assert_equal WITH_HOE, Isolate.instance.path
27
30
  assert_equal "hoe", Isolate.instance.entries.first.name
28
31
  end
29
32
 
30
33
  def test_activate
31
- @isolate = Isolate.new "test/fixtures/with-hoe"
34
+ @isolate = Isolate.new WITH_HOE
32
35
 
33
36
  assert_nil Gem.loaded_specs["hoe"]
34
37
 
@@ -39,7 +42,7 @@ class TestIsolate < MiniTest::Unit::TestCase
39
42
  end
40
43
 
41
44
  def test_activate_environment
42
- @isolate = Isolate.new "test/fixtures/with-hoe"
45
+ @isolate = Isolate.new WITH_HOE
43
46
  @isolate.gem "rubyforge"
44
47
 
45
48
  @isolate.environment "borg" do
@@ -52,7 +55,7 @@ class TestIsolate < MiniTest::Unit::TestCase
52
55
  end
53
56
 
54
57
  def test_activate_environment_explicit
55
- @isolate = Isolate.new "test/fixtures/with-hoe"
58
+ @isolate = Isolate.new WITH_HOE
56
59
 
57
60
  @isolate.gem "rubyforge"
58
61
 
@@ -74,7 +77,7 @@ class TestIsolate < MiniTest::Unit::TestCase
74
77
  begin; @isolate.activate; rescue Gem::LoadError; end
75
78
 
76
79
  assert_equal ["foo", Gem::Requirement.default],
77
- Gem::DependencyInstaller.last_install
80
+ Gem::DependencyInstaller.value.shift
78
81
  end
79
82
 
80
83
  def test_activate_install_environment
@@ -82,13 +85,29 @@ class TestIsolate < MiniTest::Unit::TestCase
82
85
  @isolate.environment(:nope) { gem "foo" }
83
86
 
84
87
  @isolate.activate
85
- assert_nil Gem::DependencyInstaller.last_install
88
+ assert_empty Gem::DependencyInstaller.value
86
89
  end
87
90
 
88
91
  def test_activate_ret
89
92
  assert_equal @isolate, @isolate.activate
90
93
  end
91
94
 
95
+ # TODO: cleanup with 2 versions of same gem, 1 activated
96
+ # TODO: install with 1 older version, 1 new gem to be installed
97
+
98
+ def test_cleanup
99
+ @isolate = Isolate.new WITH_HOE, :verbose => false
100
+ # no gems specified on purpose
101
+ @isolate.activate
102
+ @isolate.cleanup
103
+
104
+ expected = [["hoe", "2.3.3", WITH_HOE],
105
+ ["rake", "0.8.7", WITH_HOE],
106
+ ["rubyforge", "1.0.4", WITH_HOE]]
107
+
108
+ assert_equal expected, Gem::Uninstaller.value
109
+ end
110
+
92
111
  def test_disable
93
112
  home, path = ENV.values_at "GEM_HOME", "GEM_PATH"
94
113
  load_path = $LOAD_PATH.dup
@@ -111,7 +130,7 @@ class TestIsolate < MiniTest::Unit::TestCase
111
130
  end
112
131
 
113
132
  def test_enable
114
- assert !Gem.find_files("minitest/unit.rb").empty?,
133
+ refute_empty Gem.find_files("minitest/unit.rb"),
115
134
  "There's a minitest/unit in the current env, since we're running it."
116
135
 
117
136
  @isolate.enable
@@ -122,7 +141,7 @@ class TestIsolate < MiniTest::Unit::TestCase
122
141
  assert_equal [], Gem.find_files("minitest/unit.rb"),
123
142
  "Can't find minitest/unit now, 'cause we're activated!"
124
143
 
125
- assert Gem.loaded_specs.empty?
144
+ assert_empty Gem.loaded_specs
126
145
  assert_equal [@isolate.path], Gem.path
127
146
  end
128
147
 
@@ -150,7 +169,7 @@ class TestIsolate < MiniTest::Unit::TestCase
150
169
 
151
170
  def test_gem
152
171
  g = @isolate.gem "foo"
153
- assert @isolate.entries.include?(g)
172
+ assert_includes @isolate.entries, g
154
173
 
155
174
  assert_equal "foo", g.name
156
175
  assert_equal Gem::Requirement.create(">= 0"), g.requirement
@@ -175,23 +194,43 @@ class TestIsolate < MiniTest::Unit::TestCase
175
194
  i = Isolate.new "foo/gems"
176
195
  assert i.install?
177
196
  assert i.verbose?
197
+ assert i.cleanup?
198
+
199
+ i = Isolate.new "foo/gems",
200
+ :cleanup => false, :install => false, :verbose => false
178
201
 
179
- i = Isolate.new "foo/gems", :install => false, :verbose => false
202
+ refute i.cleanup?
180
203
  refute i.install?
181
204
  refute i.verbose?
205
+
206
+ i = Isolate.new "foo/gems", :install => false
207
+ refute i.cleanup?, "no install, no cleanup"
182
208
  end
183
209
  end
184
210
 
185
- # Gem::DependencyInstaller#install is brutally stubbed.
211
+ module BrutalStub
212
+ @@value = []
213
+ def value; @@value end
214
+ def reset_value; value.clear end
215
+ end
186
216
 
187
217
  class Gem::DependencyInstaller
188
- @@last_install = nil
189
- def self.last_install; @@last_install end
190
- def self.reset_last_install; @@last_install = nil end
218
+ extend BrutalStub
191
219
 
192
220
  alias old_install install
193
-
194
221
  def install name, requirement
195
- @@last_install = [name, requirement]
222
+ self.class.value << [name, requirement]
223
+ end
224
+ end
225
+
226
+ class Gem::Uninstaller
227
+ extend BrutalStub
228
+
229
+ attr_reader :gem, :version, :gem_home
230
+ alias old_uninstall uninstall
231
+ def uninstall
232
+ self.class.value << [self.gem,
233
+ self.version.to_s,
234
+ self.gem_home.sub(Dir.pwd + "/", '')]
196
235
  end
197
236
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isolate
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Barnette
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-09-23 00:00:00 -07:00
13
+ date: 2009-09-30 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency