Module: GemManagement

Includes:
ColorfulMessages
Included in:
Merb::RakeHelper
Defined in:
lib/merb-core/tasks/gem_management.rb

Instance Method Summary collapse

Methods included from ColorfulMessages

#error, #info, #note, #success, #warning

Instance Method Details

#clobber(source_dir) ⇒ Object



195
196
197
198
199
# File 'lib/merb-core/tasks/gem_management.rb', line 195

def clobber(source_dir)
  Dir.chdir(source_dir) do 
    system "#{Gem.ruby} -S rake -s clobber" unless File.exists?('Thorfile')
  end
end

#ensure_bin_wrapper_for(gem_dir, bin_dir, *gems) ⇒ Object

Create a modified executable wrapper in the specified bin directory.



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/merb-core/tasks/gem_management.rb', line 267

def ensure_bin_wrapper_for(gem_dir, bin_dir, *gems)
  options = gems.last.is_a?(Hash) ? gems.last : {}
  options[:no_minigems] ||= []
  if bin_dir && File.directory?(bin_dir)
    gems.each do |gem|
      if gemspec_path = Dir[File.join(gem_dir, 'specifications', "#{gem}-*.gemspec")].last
        spec = Gem::Specification.load(gemspec_path)
        enable_minigems = !options[:no_minigems].include?(spec.name)
        spec.executables.each do |exec|
          executable = File.join(bin_dir, exec)
          message "Writing executable wrapper #{executable}"
          File.open(executable, 'w', 0755) do |f|
            f.write(executable_wrapper(spec, exec, enable_minigems))
          end
        end
      end
    end
  end
end

#install_gem(gem, options = {}) ⇒ Object

Install a gem - looks remotely and local gem cache; won’t process rdoc or ri options.



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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/merb-core/tasks/gem_management.rb', line 46

def install_gem(gem, options = {})
  refresh = options.delete(:refresh) || []
  from_cache = (options.key?(:cache) && options.delete(:cache))
  if from_cache
    install_gem_from_cache(gem, options)
  else
    version = options.delete(:version)
    Gem.configuration.update_sources = false

    # Limit source index to install dir
    update_source_index(options[:install_dir]) if options[:install_dir]

    installer = Gem::DependencyInstaller.new(options.merge(:user_install => false))
    
    # Force-refresh certain gems by excluding them from the current index
    if !options[:ignore_dependencies] && refresh.respond_to?(:include?) && !refresh.empty?
      source_index = installer.instance_variable_get(:@source_index)
      source_index.gems.each do |name, spec| 
        source_index.gems.delete(name) if refresh.include?(spec.name)
      end
    end
    
    exception = nil
    begin
      installer.install gem, version
    rescue Gem::InstallError => e
      exception = e
    rescue Gem::GemNotFoundException => e
      if from_cache && gem_file = find_gem_in_cache(gem, version)
        puts "Located #{gem} in gem cache..."
        installer.install gem_file
      else
        exception = e
      end
    rescue => e
      exception = e
    end
    if installer.installed_gems.empty? && exception
      error "Failed to install gem '#{gem} (#{version || 'any version'})' (#{exception.message})"
    end
    installer.installed_gems.each do |spec|
      success "Successfully installed #{spec.full_name}"
    end
    return !installer.installed_gems.empty?
  end
end

#install_gem_from_cache(gem, options = {}) ⇒ Object

Install a gem - looks in the system’s gem cache instead of remotely; won’t process rdoc or ri options.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/merb-core/tasks/gem_management.rb', line 95

def install_gem_from_cache(gem, options = {})
  version = options.delete(:version)
  Gem.configuration.update_sources = false
  installer = Gem::DependencyInstaller.new(options.merge(:user_install => false))
  exception = nil
  begin
    if gem_file = find_gem_in_cache(gem, version)
      puts "Located #{gem} in gem cache..."
      installer.install gem_file
    else
      raise Gem::InstallError, "Unknown gem #{gem}"
    end
  rescue Gem::InstallError => e
    exception = e
  end
  if installer.installed_gems.empty? && exception
    error "Failed to install gem '#{gem}' (#{e.message})"
  end
  installer.installed_gems.each do |spec|
    success "Successfully installed #{spec.full_name}"
  end
end

#install_gem_from_source(source_dir, *args) ⇒ Object

Install a gem from source - builds and packages it first then installs.

Examples: install_gem_from_source(source_dir, :install_dir => …) install_gem_from_source(source_dir, gem_name) install_gem_from_source(source_dir, :skip => […])



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/merb-core/tasks/gem_management.rb', line 124

def install_gem_from_source(source_dir, *args)
  installed_gems = []
  Dir.chdir(source_dir) do
    opts = args.last.is_a?(Hash) ? args.pop : {}
    gem_name     = args[0] || File.basename(source_dir)
    gem_pkg_dir  = File.join(source_dir, 'pkg')
    gem_pkg_glob = File.join(gem_pkg_dir, "#{gem_name}-*.gem")
    skip_gems    = opts.delete(:skip) || []

    # Cleanup what's already there
    clobber(source_dir)
    FileUtils.mkdir_p(gem_pkg_dir) unless File.directory?(gem_pkg_dir)

    # Recursively process all gem packages within the source dir
    skip_gems << gem_name
    packages = package_all(source_dir, skip_gems)
    
    if packages.length == 1
      # The are no subpackages for the main package
      refresh = [gem_name]
    else
      # Gather all packages into the top-level pkg directory
      packages.each do |pkg|
        FileUtils.copy_entry(pkg, File.join(gem_pkg_dir, File.basename(pkg)))
      end
      
      # Finally package the main gem - without clobbering the already copied pkgs
      package(source_dir, false)
      
      # Gather subgems to refresh during installation of the main gem
      refresh = packages.map do |pkg|
        File.basename(pkg, '.gem')[/^(.*?)-([\d\.]+)$/, 1] rescue nil
      end.compact
      
      # Install subgems explicitly even if ignore_dependencies is set
      if opts[:ignore_dependencies]
        refresh.each do |name| 
          gem_pkg = Dir[File.join(gem_pkg_dir, "#{name}-*.gem")][0]
          install_pkg(gem_pkg, opts)
        end
      end
    end
    
    # Finally install the main gem
    if install_pkg(Dir[gem_pkg_glob][0], opts.merge(:refresh => refresh))
      installed_gems = refresh
    else
      installed_gems = []
    end
  end
  installed_gems
end

#install_pkg(gem_pkg, opts = {}) ⇒ Object



177
178
179
180
181
182
183
184
# File 'lib/merb-core/tasks/gem_management.rb', line 177

def install_pkg(gem_pkg, opts = {})
  if (gem_pkg && File.exists?(gem_pkg))
    # Needs to be executed from the directory that contains all packages
    Dir.chdir(File.dirname(gem_pkg)) { install_gem(gem_pkg, opts) }
  else
    false
  end
end

#package(source_dir, clobber = true) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
# File 'lib/merb-core/tasks/gem_management.rb', line 201

def package(source_dir, clobber = true)
  Dir.chdir(source_dir) do 
    if File.exists?('Thorfile')
      thor ":package"
    elsif File.exists?('Rakefile')
      rake "clobber" if clobber
      rake "package"
    end
  end
  Dir[File.join(source_dir, 'pkg/*.gem')]
end

#package_all(source_dir, skip = [], packages = []) ⇒ Object



213
214
215
216
217
218
219
220
221
222
# File 'lib/merb-core/tasks/gem_management.rb', line 213

def package_all(source_dir, skip = [], packages = [])
  if Dir[File.join(source_dir, '{Rakefile,Thorfile}')][0]
    name = File.basename(source_dir)
    Dir[File.join(source_dir, '*', '{Rakefile,Thorfile}')].each do |taskfile|
      package_all(File.dirname(taskfile), skip, packages)
    end
    packages.push(*package(source_dir)) unless skip.include?(name)
  end
  packages.uniq
end

#partition_dependencies(dependencies, gem_dir) ⇒ Object

Partition gems into system, local and missing gems



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/merb-core/tasks/gem_management.rb', line 244

def partition_dependencies(dependencies, gem_dir)
  system_specs, local_specs, missing_deps = [], [], []
  if gem_dir && File.directory?(gem_dir)
    gem_dir = File.expand_path(gem_dir)
    ::Gem.clear_paths; ::Gem.path.unshift(gem_dir)
    ::Gem.source_index.refresh!
    dependencies.each do |dep|
      gemspecs = ::Gem.source_index.search(dep)
      local = gemspecs.reverse.find { |s| s.loaded_from.index(gem_dir) == 0 }
      if local
        local_specs  << local
      elsif gemspecs.last
        system_specs << gemspecs.last
      else
        missing_deps << dep
      end
    end
    ::Gem.clear_paths
  end
  [system_specs, local_specs, missing_deps]
end

#rake(cmd) ⇒ Object



224
225
226
227
# File 'lib/merb-core/tasks/gem_management.rb', line 224

def rake(cmd)
  cmd << " >/dev/null" if $SILENT && !Gem.win_platform?
  system "#{Gem.ruby} -S #{which('rake')} -s #{cmd} >/dev/null"
end

#thor(cmd) ⇒ Object



229
230
231
232
# File 'lib/merb-core/tasks/gem_management.rb', line 229

def thor(cmd)
  cmd << " >/dev/null" if $SILENT && !Gem.win_platform?
  system "#{Gem.ruby} -S #{which('thor')} #{cmd}"
end

#uninstall_gem(gem, options = {}) ⇒ Object

Uninstall a gem.



187
188
189
190
191
192
193
# File 'lib/merb-core/tasks/gem_management.rb', line 187

def uninstall_gem(gem, options = {})
  if options[:version] && !options[:version].is_a?(Gem::Requirement)
    options[:version] = Gem::Requirement.new ["= #{options[:version]}"]
  end
  update_source_index(options[:install_dir]) if options[:install_dir]
  Gem::Uninstaller.new(gem, options).uninstall
end

#which(executable) ⇒ Object

Use the local bin/* executables if available.



235
236
237
238
239
240
241
# File 'lib/merb-core/tasks/gem_management.rb', line 235

def which(executable)
  if File.executable?(exec = File.join(Dir.pwd, 'bin', executable))
    exec
  else
    executable
  end
end