isolate 1.3.0 → 1.4.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.
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