summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>2009-07-28 12:59:09 -0700
committerYehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>2009-07-28 13:00:20 -0700
commit14e5a6a8010c9f8b671c287246c4b2a2783a78f2 (patch)
tree90bb91ea07f366ca1c423cf0ee6c5ae634eb2db3
parentf8c47aaab83f61dd25ec6ab25c4c63e503b53a10 (diff)
downloadbundler-14e5a6a8010c9f8b671c287246c4b2a2783a78f2.tar.gz
Start extracting Gem repository logic into a Repository class
* Removed Bundler::Installer * Started to rewrite specs in installer_spec.rb
-rw-r--r--lib/bundler.rb2
-rw-r--r--lib/bundler/cli.rb3
-rw-r--r--lib/bundler/installer.rb42
-rw-r--r--lib/bundler/manifest.rb21
-rw-r--r--lib/bundler/repository.rb87
-rw-r--r--spec/bundler/installer_spec.rb236
6 files changed, 243 insertions, 148 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb
index e0775b08dd..a0f16896a1 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -7,7 +7,6 @@ require "rubygems/remote_fetcher"
require "rubygems/installer"
require "bundler/gem_bundle"
-require "bundler/installer"
require "bundler/finder"
require "bundler/gem_ext"
require "bundler/resolver"
@@ -16,6 +15,7 @@ require "bundler/manifest"
require "bundler/dependency"
require "bundler/runtime"
require "bundler/cli"
+require "bundler/repository"
module Bundler
VERSION = "0.5.0"
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index ffb2d15f96..a591449b10 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -26,6 +26,9 @@ module Bundler
rescue InvalidEnvironmentName => e
Bundler.logger.error "Gemfile error: #{e.message}"
exit
+ rescue InvalidRepository => e
+ Bundler.logger.error e.message
+ exit
rescue VersionConflict => e
Bundler.logger.error e.message
exit
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
deleted file mode 100644
index a55300188c..0000000000
--- a/lib/bundler/installer.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-module Bundler
- class Installer
- def self.install(gem_path, bindir = nil)
- new(gem_path, bindir).install
- end
-
- def initialize(gem_path, bindir)
- if !gem_path.directory?
- raise ArgumentError, "#{gem_path} is not a directory"
- elsif !gem_path.join("cache").directory?
- raise ArgumentError, "#{gem_path} is not a valid environment (it does not contain a cache directory)"
- end
-
- @gem_path = gem_path
-
- @bindir = bindir || gem_path.join("bin")
- @gems = Dir[@gem_path.join("cache", "*.gem")]
- end
-
- def install
- specs = Dir[File.join(@gem_path, "specifications", "*.gemspec")]
- gems = Dir[File.join(@gem_path, "gems", "*")]
-
- @gems.each do |gem|
- name = File.basename(gem).gsub(/\.gem$/, '')
- installed = specs.any? { |g| File.basename(g) == "#{name}.gemspec" } &&
- gems.any? { |g| File.basename(g) == name }
-
- unless installed
- Bundler.logger.info "Installing #{name}.gem"
- installer = Gem::Installer.new(gem, :install_dir => @gem_path,
- :ignore_dependencies => true,
- :env_shebang => true,
- :wrappers => true,
- :bin_dir => @bindir)
- installer.install
- end
- end
- self
- end
- end
-end
diff --git a/lib/bundler/manifest.rb b/lib/bundler/manifest.rb
index 7d765ac31e..e0e07a30de 100644
--- a/lib/bundler/manifest.rb
+++ b/lib/bundler/manifest.rb
@@ -6,26 +6,26 @@ module Bundler
class Manifest
attr_reader :sources, :dependencies, :path
- def initialize(sources, dependencies, bindir, gem_path, rubygems)
+ def initialize(sources, dependencies, bindir, repository_path, rubygems)
sources.map! {|s| s.is_a?(URI) ? s : URI.parse(s) }
@sources = sources
@dependencies = dependencies
@bindir = bindir
- @gem_path = gem_path
+ @repository = Repository.new(repository_path)
@rubygems = rubygems
end
def install
fetch
- Installer.install(@gem_path, @bindir)
+ @repository.install_cached_gems(:bin_dir => @bindir || @repository.path.join("bin"))
cleanup_removed_gems
- create_load_paths_files(@gem_path.join("environments"))
- create_fake_rubygems(@gem_path.join("environments"))
+ create_load_paths_files(@repository.path.join("environments"))
+ create_fake_rubygems(@repository.path.join("environments"))
Bundler.logger.info "Done."
end
def activate(environment = "default")
- require @gem_path.join("environments", "#{environment}.rb")
+ require @repository.path.join("environments", "#{environment}.rb")
end
def require_all
@@ -38,8 +38,7 @@ module Bundler
deps = dependencies
deps = deps.select { |d| d.in?(environment) } if environment
deps = deps.map { |d| d.to_gem_dependency }
- index = Gem::SourceIndex.from_gems_in(@gem_path.join("specifications"))
- Resolver.resolve(deps, index)
+ Resolver.resolve(deps, @repository.source_index)
end
alias gems gems_for
@@ -59,7 +58,7 @@ module Bundler
raise VersionConflict, "No compatible versions could be found for:\n#{gems}"
end
- bundle.download(@gem_path)
+ bundle.download(@repository.path)
end
def gem_dependencies
@@ -69,7 +68,7 @@ module Bundler
def all_gems_installed?
downloaded_gems = {}
- Dir[@gem_path.join("cache", "*.gem")].each do |file|
+ Dir[@repository.path.join("cache", "*.gem")].each do |file|
file =~ /\/([^\/]+)-([\d\.]+)\.gem$/
name, version = $1, $2
downloaded_gems[name] = Gem::Version.new(version)
@@ -83,7 +82,7 @@ module Bundler
def cleanup_removed_gems
glob = gems.map { |g| g.full_name }.join(',')
- base = @gem_path.join("{cache,specifications,gems}")
+ base = @repository.path.join("{cache,specifications,gems}")
(Dir[base.join("*")] - Dir[base.join("{#{glob}}{.gemspec,.gem,}")]).each do |file|
Bundler.logger.info "Deleting gem: #{File.basename(file, ".gem")}" if File.basename(file) =~ /\.gem$/
diff --git a/lib/bundler/repository.rb b/lib/bundler/repository.rb
new file mode 100644
index 0000000000..7880342cb6
--- /dev/null
+++ b/lib/bundler/repository.rb
@@ -0,0 +1,87 @@
+module Bundler
+ class InvalidRepository < StandardError ; end
+
+ class Repository
+
+ attr_reader :path
+
+ def initialize(path)
+ @path = Pathname.new(path)
+ unless valid?
+ raise InvalidRepository, "'#{path}' is not a valid gem repository"
+ end
+ end
+
+ # Returns the source index for all gems installed in the
+ # repository
+ def source_index
+ Gem::SourceIndex.from_gems_in(@path.join("specifications"))
+ end
+
+ def valid?
+ (Dir[@path.join("*")] - Dir[@path.join("{cache,doc,gems,environments,specifications}")]).empty?
+ end
+
+ # Checks whether a gem is installed
+ def install_cached_gems(options = {})
+ cached_gems.each do |name, version|
+ unless installed?(name, version)
+ install_cached_gem(name, version, options)
+ end
+ end
+ end
+
+ def install_cached_gem(name, version, options = {})
+ cached_gem = cache_path.join("#{name}-#{version}.gem")
+ if cached_gem.file?
+ Bundler.logger.info "Installing #{name}-#{version}.gem"
+ installer = Gem::Installer.new(cached_gem.to_s, options.merge(
+ :install_dir => @path,
+ :ignore_dependencies => true,
+ :env_shebang => true,
+ :wrappers => true
+ ))
+ installer.install
+ end
+ end
+
+ private
+
+ def cache_path
+ @path.join("cache")
+ end
+
+ def cache_files
+ Dir[cache_path.join("*.gem")]
+ end
+
+ def cached_gems
+ cache_files.map do |f|
+ full_name = File.basename(f).gsub(/\.gem$/, '')
+ full_name.split(/-(?=[\d.]+$)/)
+ end
+ end
+
+ def spec_path
+ @path.join("specifications")
+ end
+
+ def spec_files
+ Dir[spec_path.join("*.gemspec")]
+ end
+
+ def gem_path
+ @path.join("gems")
+ end
+
+ def gems
+ Dir[gem_path.join("*")]
+ end
+
+ def installed?(name, version)
+ spec_files.any? { |g| File.basename(g) == "#{name}-#{version}.gemspec" } &&
+ gems.any? { |g| File.basename(g) == "#{name}-#{version}" }
+ end
+
+ end
+end \ No newline at end of file
diff --git a/spec/bundler/installer_spec.rb b/spec/bundler/installer_spec.rb
index ab51a28516..e946b3372e 100644
--- a/spec/bundler/installer_spec.rb
+++ b/spec/bundler/installer_spec.rb
@@ -1,107 +1,155 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
-describe "Bundler::Installer" do
-
- before(:each) do
- @finder = Bundler::Finder.new("file://#{gem_repo1}", "file://#{gem_repo2}")
- end
-
- describe "without native gems" do
- before(:each) do
- @bundle = @finder.resolve(build_dep('rails', '>= 0'))
- @bundle.download(tmp_dir)
- end
-
- it "raises an ArgumentError if the path does not exist" do
- lambda { Bundler::Installer.install(tmp_dir.join("omgomgbadpath")) }.should raise_error(ArgumentError)
+describe "Installing gems" do
+
+ describe "the bundle directory" do
+ def setup
+ @manifest = build_manifest <<-Gemfile
+ sources.clear
+ source "file://#{gem_repo1}"
+ source "file://#{gem_repo2}"
+ bundle_path "#{tmp_file('hello')}"
+ gem "rails"
+ Gemfile
end
- it "raises an ArgumentError if the path does not contain a 'cache' directory" do
- lambda { Bundler::Installer.install(gem_repo1) }.should raise_error(ArgumentError)
- end
-
- describe "installing gems" do
-
- before(:each) do
- FileUtils.rm_rf(tmp_file("gems"))
- FileUtils.rm_rf(tmp_file("specifications"))
- end
-
- it "installs the bins in the directory you specify" do
- FileUtils.mkdir_p tmp_file("omgbinz")
- @environment = Bundler::Installer.install(tmp_dir, tmp_file("omgbinz"))
- File.exist?(tmp_file("omgbinz", "rails")).should be_true
- end
-
- it "does not modify any .gemspec files that are to be installed if a directory of the same name exists" do
- dir = tmp_file("gems", "rails-2.3.2")
- FileUtils.mkdir_p(dir)
- FileUtils.mkdir_p(tmp_file("specifications"))
- spec = tmp_file("specifications", "rails-2.3.2.gemspec")
- FileUtils.touch(spec)
- lambda { Bundler::Installer.install(tmp_dir) }.should_not change { [File.mtime(dir), File.mtime(spec)] }
- end
-
- it "deletes a .gemspec file that is to be installed if a directory of the same name does not exist" do
- spec = tmp_file("specifications", "rails-2.3.2.gemspec")
- FileUtils.mkdir_p(tmp_file("specifications"))
- FileUtils.touch(spec)
- lambda { Bundler::Installer.install(tmp_dir) }.should change { File.mtime(spec) }
- end
-
- it "deletes a directory that is to be installed if a .gemspec of the same name does not exist" do
- dir = tmp_file("gems", "rails-2.3.2")
- FileUtils.mkdir_p(dir)
- lambda { Bundler::Installer.install(tmp_dir) }.should change { File.mtime(dir) }
- end
-
- it "keeps bin files for already installed gems" do
- Bundler::Installer.install(tmp_dir)
- Bundler::Installer.install(tmp_dir)
- tmp_file("bin", "rails").should exist
- end
+ it "creates the bundle directory if it does not exist" do
+ setup
+ @manifest.install
+ tmp_file("hello").should have_cached_gems("rails-2.3.2")
end
- describe "after installing gems" do
-
- before(:each) do
- @environment = Bundler::Installer.install(tmp_dir)
- end
-
- it "each thing in the bundle has a directory in gems" do
- @bundle.each do |spec|
- Dir[File.join(tmp_dir, 'gems', "#{spec.full_name}")].should have(1).item
- end
- end
-
- it "creates a specification for each gem" do
- @bundle.each do |spec|
- Dir[File.join(tmp_dir, 'specifications', "#{spec.full_name}.gemspec")].should have(1).item
- end
- end
-
- it "copies gem executables to a specified path" do
- File.exist?(File.join(tmp_dir, 'bin', 'rails')).should be_true
- end
+ it "uses the bundle directory if it is empty" do
+ tmp_file("hello").mkdir
+ setup
+ @manifest.install
+ tmp_file("hello").should have_cached_gems("rails-2.3.2")
end
- it "outputs a logger message for each gem that is installed" do
- @environment = Bundler::Installer.install(tmp_dir)
- @bundle.each do |spec|
- @log_output.should have_log_message("Installing #{spec.full_name}.gem")
- end
+ it "uses the bundle directory if it is a valid gem repo" do
+ tmp_file("hello").mkdir
+ %w(cache doc gems environments specifications).each { |dir| tmp_file("hello", dir).mkdir }
+ setup
+ @manifest.install
+ tmp_file("hello").should have_cached_gems("rails-2.3.2")
end
- end
- describe "with native gems" do
-
- it "compiles binary gems" do
- FileUtils.rm_rf(tmp_dir)
- @bundle = @finder.resolve(build_dep('json', '>= 0'))
- @bundle.download(tmp_dir)
- Bundler::Installer.install(tmp_dir)
- Dir[File.join(tmp_dir, 'gems', "json-*", "**", "*.bundle")].should have_at_least(1).item
+ it "does not use the bundle directory if it is not a valid gem repo" do
+ tmp_file("hello").mkdir
+ FileUtils.touch(tmp_file("hello", "fail"))
+ lambda {
+ setup
+ }.should raise_error(Bundler::InvalidRepository)
end
-
end
end
+#
+# describe "Bundler::Installer" do
+#
+# before(:each) do
+# pending
+# end
+#
+# before(:each) do
+# @finder = Bundler::Finder.new("file://#{gem_repo1}", "file://#{gem_repo2}")
+# end
+#
+# describe "without native gems" do
+# before(:each) do
+# @bundle = @finder.resolve(build_dep('rails', '>= 0'))
+# @bundle.download(tmp_dir)
+# end
+#
+# it "raises an ArgumentError if the path does not exist" do
+# lambda { Bundler::Installer.install(tmp_dir.join("omgomgbadpath")) }.should raise_error(ArgumentError)
+# end
+#
+# it "raises an ArgumentError if the path does not contain a 'cache' directory" do
+# lambda { Bundler::Installer.install(gem_repo1) }.should raise_error(ArgumentError)
+# end
+#
+# describe "installing gems" do
+#
+# before(:each) do
+# FileUtils.rm_rf(tmp_file("gems"))
+# FileUtils.rm_rf(tmp_file("specifications"))
+# end
+#
+# it "installs the bins in the directory you specify" do
+# FileUtils.mkdir_p tmp_file("omgbinz")
+# @environment = Bundler::Installer.install(tmp_dir, tmp_file("omgbinz"))
+# File.exist?(tmp_file("omgbinz", "rails")).should be_true
+# end
+#
+# it "does not modify any .gemspec files that are to be installed if a directory of the same name exists" do
+# dir = tmp_file("gems", "rails-2.3.2")
+# FileUtils.mkdir_p(dir)
+# FileUtils.mkdir_p(tmp_file("specifications"))
+# spec = tmp_file("specifications", "rails-2.3.2.gemspec")
+# FileUtils.touch(spec)
+# lambda { Bundler::Installer.install(tmp_dir) }.should_not change { [File.mtime(dir), File.mtime(spec)] }
+# end
+#
+# it "deletes a .gemspec file that is to be installed if a directory of the same name does not exist" do
+# spec = tmp_file("specifications", "rails-2.3.2.gemspec")
+# FileUtils.mkdir_p(tmp_file("specifications"))
+# FileUtils.touch(spec)
+# lambda { Bundler::Installer.install(tmp_dir) }.should change { File.mtime(spec) }
+# end
+#
+# it "deletes a directory that is to be installed if a .gemspec of the same name does not exist" do
+# dir = tmp_file("gems", "rails-2.3.2")
+# FileUtils.mkdir_p(dir)
+# lambda { Bundler::Installer.install(tmp_dir) }.should change { File.mtime(dir) }
+# end
+#
+# it "keeps bin files for already installed gems" do
+# Bundler::Installer.install(tmp_dir)
+# Bundler::Installer.install(tmp_dir)
+# tmp_file("bin", "rails").should exist
+# end
+# end
+#
+# describe "after installing gems" do
+#
+# before(:each) do
+# @environment = Bundler::Installer.install(tmp_dir)
+# end
+#
+# it "each thing in the bundle has a directory in gems" do
+# @bundle.each do |spec|
+# Dir[File.join(tmp_dir, 'gems', "#{spec.full_name}")].should have(1).item
+# end
+# end
+#
+# it "creates a specification for each gem" do
+# @bundle.each do |spec|
+# Dir[File.join(tmp_dir, 'specifications', "#{spec.full_name}.gemspec")].should have(1).item
+# end
+# end
+#
+# it "copies gem executables to a specified path" do
+# File.exist?(File.join(tmp_dir, 'bin', 'rails')).should be_true
+# end
+# end
+#
+# it "outputs a logger message for each gem that is installed" do
+# @environment = Bundler::Installer.install(tmp_dir)
+# @bundle.each do |spec|
+# @log_output.should have_log_message("Installing #{spec.full_name}.gem")
+# end
+# end
+# end
+#
+# describe "with native gems" do
+#
+# it "compiles binary gems" do
+# FileUtils.rm_rf(tmp_dir)
+# @bundle = @finder.resolve(build_dep('json', '>= 0'))
+# @bundle.download(tmp_dir)
+# Bundler::Installer.install(tmp_dir)
+# Dir[File.join(tmp_dir, 'gems', "json-*", "**", "*.bundle")].should have_at_least(1).item
+# end
+#
+# end
+# end