diff options
author | Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com> | 2009-07-28 12:59:09 -0700 |
---|---|---|
committer | Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com> | 2009-07-28 13:00:20 -0700 |
commit | 14e5a6a8010c9f8b671c287246c4b2a2783a78f2 (patch) | |
tree | 90bb91ea07f366ca1c423cf0ee6c5ae634eb2db3 | |
parent | f8c47aaab83f61dd25ec6ab25c4c63e503b53a10 (diff) | |
download | bundler-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.rb | 2 | ||||
-rw-r--r-- | lib/bundler/cli.rb | 3 | ||||
-rw-r--r-- | lib/bundler/installer.rb | 42 | ||||
-rw-r--r-- | lib/bundler/manifest.rb | 21 | ||||
-rw-r--r-- | lib/bundler/repository.rb | 87 | ||||
-rw-r--r-- | spec/bundler/installer_spec.rb | 236 |
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 |