Class: Gem::Commands::SandboxCommand

Inherits:
Gem::Command
  • Object
show all
Defined in:
lib/rubygems/commands/sandbox_command.rb

Constant Summary collapse

VERSION =
"1.2.0"

Instance Method Summary collapse

Constructor Details

#initializeSandboxCommand

Returns a new instance of SandboxCommand.



21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/rubygems/commands/sandbox_command.rb', line 21

def initialize
  defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge(
    :generate_rdoc     => false,
    :generate_ri       => false,
    :document          => [],
    :format_executable => false,
    :version           => Gem::Requirement.default
  )

  super("sandbox", "Privately install a command-line tool", defaults)

  @scripts = []
end

Instance Method Details

#argumentsObject

:nodoc:



36
37
38
39
# File 'lib/rubygems/commands/sandbox_command.rb', line 36

def arguments # :nodoc:
  ['SUBCOMMAND    one of: list, install, help, etc... see help for full list',
   'GEMNAME       name of a gem to sandbox'].join "\n"
end

#cleanObject



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/rubygems/commands/sandbox_command.rb', line 180

def clean
  require 'rubygems/uninstaller'

  options[:args] = sandboxes if options[:args].empty?

  get_all_gem_names.each do |gem_name|
    dir = sandbox_dir gem_name

    # Forces reset of known installed gems so subsequent repeats work
    Gem.use_paths dir, dir # FUCK ME this is the worst code ever
    Gem.refresh

    primary_gems = {}

    Gem::Specification.each do |spec|
      if primary_gems[spec.name].nil? or
          primary_gems[spec.name].version < spec.version then
        primary_gems[spec.name] = spec
      end
    end

    gems_to_cleanup = Gem::Specification.to_a

    gems_to_cleanup = gems_to_cleanup.select { |spec|
      primary_gems[spec.name].version != spec.version
    }

    deplist = Gem::DependencyList.new
    gems_to_cleanup.uniq.each do |spec| deplist.add spec end

    deps = deplist.strongly_connected_components.flatten.reverse

    deps.each do |spec|
      options[:args] = [spec.name]

      uninstall_options = {
        :executables => false,
        :version => "= #{spec.version}",
      }

      uninstaller = Gem::Uninstaller.new spec.name, uninstall_options

      begin
        uninstaller.uninstall
      rescue Gem::DependencyRemovalException, Gem::InstallError,
        Gem::GemNotInHomeException, Gem::FilePermissionError => e
        say "Unable to uninstall #{spec.full_name}:"
        say "\t#{e.class}: #{e.message}"
      end
    end
  end
end

#descriptionObject



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
# File 'lib/rubygems/commands/sandbox_command.rb', line 45

def description
  <<-EOF

`gem sandbox` helps you manage your command-line tools and their
dependencies. Sandboxed gems are installed in their own private
repositories with their dependencies. This means that you don't have
to have a rats nest of gems in your global repository in order to run
popular command-tools like rdoc, flog, flay, rcov, etc.

`gem sandbox` has the following sub-commands:

* list                               - list current sandboxes
* install   gem_name ...             - install 1 or more gems
* outdated  gem_name ...             - check 1 or more gems for outdated deps
* plugin    gem_name plugin_name ... - install a gem and plugins for it
* uninstall gem_name ...             - uninstall 1 or more gems
* cleanup   gem_name ...             - remove older gem deps
* update    gem_name ...             - update 1 or more gems
* help                               - show this output

Once you install `gem sandbox` will output something like:

  Copy the following scripts to any directory in your path to use them:

  cp /Users/USER/.gem/sandboxes/TOOL/bin/TOOL _in_your_$PATH_

Copy the scripts to a directory in your path (eg ~/bin or /usr/bin)
and you're good to go.
  EOF
end

#executeObject



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
# File 'lib/rubygems/commands/sandbox_command.rb', line 76

def execute
  cmd = options[:args].shift

  case cmd
  when "list" then
    list
  when "install" then
    install
  when "outdated" then
    outdated
  when "update" then
    update
  when "clean" then
    clean
  when "plugin" then
    plugin
  when "uninstall" then
    uninstall
  when "help", "usage" then
    show_help
    abort
  else
    alert_error "Unknown sandbox subcommand: #{cmd}"
    show_help
    abort
  end
end

#installObject



121
122
123
124
125
126
127
# File 'lib/rubygems/commands/sandbox_command.rb', line 121

def install
  get_all_gem_names.each do |gem_name|
    install_gem gem_name
  end

  list_scripts
end

#install_gem(gem_name, dir = sandbox_dir(gem_name)) ⇒ Object



262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/rubygems/commands/sandbox_command.rb', line 262

def install_gem gem_name, dir = sandbox_dir(gem_name)
  # Forces reset of known installed gems so subsequent repeats work
  Gem.use_paths nil, nil

  inst = Gem::DependencyInstaller.new options.merge(:install_dir => dir)
  inst.install gem_name, options[:version]

  spec = inst.installed_gems.find { |s| s.name == gem_name }
  rewrite_executables dir, spec

  say "Successfully installed #{gem_name}"
end

#listObject



112
113
114
115
116
117
118
119
# File 'lib/rubygems/commands/sandbox_command.rb', line 112

def list
  boxes = self.sandboxes
  if boxes then
    say boxes.join "\n"
  else
    say "No sandboxes installed."
  end
end

#list_scriptsObject



247
248
249
250
251
252
# File 'lib/rubygems/commands/sandbox_command.rb', line 247

def list_scripts
  say ""
  say "Copy the following scripts to any directory in your path to use them:"
  say ""
  say "cp #{@scripts.join ' '} _in_your_$PATH_"
end

#outdatedObject



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/rubygems/commands/sandbox_command.rb', line 138

def outdated
  get_all_gem_names.each do |gem_name|
    dir = sandbox_dir(gem_name)

    # Forces reset of known installed gems so subsequent repeats work
    Gem.use_paths dir, dir
    Gem.refresh

    Gem::Specification.outdated.sort.each do |name|
      local   = Gem::Specification.find_all_by_name(name).max
      dep     = Gem::Dependency.new local.name, ">= #{local.version}"
      remotes = Gem::SpecFetcher.fetcher.fetch dep

      next if remotes.empty?

      remote = remotes.last.first
      say "#{local.name} (#{local.version} < #{remote.version})"
    end
  end
end

#pluginObject



233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/rubygems/commands/sandbox_command.rb', line 233

def plugin
  gem_name, *plugins = options[:args]
  dir                = sandbox_dir gem_name

  install_gem gem_name, dir

  plugins.each do |plugin_name|
    inst = Gem::DependencyInstaller.new options.merge(:install_dir => dir)
    inst.install plugin_name, options[:version]
  end

  list_scripts
end

#rewrite_executables(dir, spec) ⇒ Object



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/rubygems/commands/sandbox_command.rb', line 284

def rewrite_executables dir, spec
  spec.executables.each do |filename|
    path = File.join dir, "bin", filename
    env  = "ENV['GEM_HOME'] = ENV['GEM_PATH'] = #{dir.inspect}"

    script = File.read path
    script.sub!(/require 'rubygems'/, "#{env}\n\\&")

    File.open path, "w" do |f|
      f.write script
    end

    @scripts << path
  end
end

#sandbox_dir(gem_name) ⇒ Object



258
259
260
# File 'lib/rubygems/commands/sandbox_command.rb', line 258

def sandbox_dir gem_name
  File.join sandbox_home, gem_name
end

#sandbox_homeObject



254
255
256
# File 'lib/rubygems/commands/sandbox_command.rb', line 254

def sandbox_home
  File.join Gem.user_home, '.gem', "sandboxes"
end

#sandboxesObject



104
105
106
107
108
109
110
# File 'lib/rubygems/commands/sandbox_command.rb', line 104

def sandboxes
  if File.directory? sandbox_home then
    Dir.chdir sandbox_home do
      Dir["*"]
    end
  end
end

#uninstallObject



129
130
131
132
133
134
135
136
# File 'lib/rubygems/commands/sandbox_command.rb', line 129

def uninstall
  get_all_gem_names.each do |gem_name|
    uninstall_gem gem_name
  end

  say ""
  say "You will need to manually clean up any script wrappers you copied."
end

#uninstall_gem(gem_name, dir = sandbox_dir(gem_name)) ⇒ Object



275
276
277
278
279
280
281
282
# File 'lib/rubygems/commands/sandbox_command.rb', line 275

def uninstall_gem gem_name, dir = sandbox_dir(gem_name)
  # Forces reset of known installed gems so subsequent repeats work
  Gem.use_paths nil, nil

  require "fileutils"

  FileUtils.rm_rf dir, :verbose => true
end

#updateObject



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/rubygems/commands/sandbox_command.rb', line 159

def update
  require 'rubygems/commands/update_command'

  get_all_gem_names.each do |gem_name|
    dir = sandbox_dir gem_name

    # Forces reset of known installed gems so subsequent repeats work
    Gem.use_paths dir, dir
    Gem.refresh

    updater = Gem::Commands::UpdateCommand.new
    updater.updated = [] # HACK: this is stupid
    updater.installer =
      Gem::DependencyInstaller.new(options.merge(:install_dir => dir))

    Gem::Specification.outdated.sort.each do |name|
      updater.update_gem name
    end
  end
end

#usageObject

:nodoc:



41
42
43
# File 'lib/rubygems/commands/sandbox_command.rb', line 41

def usage # :nodoc:
  "#{program_name} SUBCOMMAND GEMNAME(S)"
end