Permalink
Browse files

Path and Git should also be packaged.

  • Loading branch information...
josevalim committed Mar 19, 2012
1 parent 9ccaf91 commit 6ef6e7514d0e2071585a397d51a93dd26d44ab3c
Showing with 173 additions and 65 deletions.
  1. +96 −61 lib/bundler/source.rb
  2. +67 −1 spec/cache/git_spec.rb
  3. +10 −3 spec/cache/path_spec.rb
View
@@ -4,7 +4,7 @@
require "rubygems/spec_fetcher"
require "rubygems/format"
require "digest/sha1"
-require "open3"
+require "fileutils"
module Bundler
module Source
@@ -264,12 +264,37 @@ def remote_specs
Bundler.rubygems.sources = old
end
end
-
end
+
class Path
- attr_reader :path, :options
- # Kind of a hack, but needed for the lock file parser
+ class Installer < Bundler::GemInstaller
+ def initialize(spec, options = {})
+ @spec = spec
+ @bin_dir = Bundler.requires_sudo? ? "#{Bundler.tmp}/bin" : "#{Bundler.rubygems.gem_dir}/bin"
+ @gem_dir = Bundler.rubygems.path(spec.full_gem_path)
+ @wrappers = options[:wrappers] || true
+ @env_shebang = options[:env_shebang] || true
+ @format_executable = options[:format_executable] || false
+ end
+
+ def generate_bin
+ return if spec.executables.nil? || spec.executables.empty?
+
+ if Bundler.requires_sudo?
+ FileUtils.mkdir_p("#{Bundler.tmp}/bin") unless File.exist?("#{Bundler.tmp}/bin")
+ end
+ super
+ if Bundler.requires_sudo?
+ Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/bin"
+ spec.executables.each do |exe|
+ Bundler.sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Bundler.rubygems.gem_dir}/bin/"
+ end
+ end
+ end
+ end
+
+ attr_reader :path, :options
attr_writer :name
attr_accessor :version
@@ -287,8 +312,9 @@ def initialize(options)
@path = @path.expand_path(Bundler.root) unless @path.relative?
end
- @name = options["name"]
+ @name = options["name"]
@version = options["version"]
+ @path = app_cache_path if has_app_cache?
end
def remote!
@@ -330,9 +356,40 @@ def name
File.basename(path.expand_path(Bundler.root).to_s)
end
+ def install(spec)
+ Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
+ # Let's be honest, when we're working from a path, we can't
+ # really expect native extensions to work because the whole point
+ # is to just be able to modify what's in that path and go. So, let's
+ # not put ourselves through the pain of actually trying to generate
+ # the full gem.
+ Installer.new(spec).generate_bin
+ end
+
+ def cache(spec)
+ return if path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
+ FileUtils.rm_rf(app_cache_path)
+ FileUtils.cp_r("#{path}/.", app_cache_path)
+ end
+
+ def local_specs(*)
+ @local_specs ||= load_spec_files
+ end
+
+ alias :specs :local_specs
+
+ private
+
+ def app_cache_path
+ @app_cache_path ||= Bundler.app_cache.join(name)
+ end
+
+ def has_app_cache?
+ SharedHelpers.in_bundle? && app_cache_path.exist?
+ end
+
def load_spec_files
index = Index.new
-
expanded_path = path.expand_path(Bundler.root)
if File.directory?(expanded_path)
@@ -368,61 +425,10 @@ def load_spec_files
index
end
- def local_specs(*)
- @local_specs ||= load_spec_files
- end
-
- class Installer < Bundler::GemInstaller
- def initialize(spec, options = {})
- @spec = spec
- @bin_dir = Bundler.requires_sudo? ? "#{Bundler.tmp}/bin" : "#{Bundler.rubygems.gem_dir}/bin"
- @gem_dir = Bundler.rubygems.path(spec.full_gem_path)
- @wrappers = options[:wrappers] || true
- @env_shebang = options[:env_shebang] || true
- @format_executable = options[:format_executable] || false
- end
-
- def generate_bin
- return if spec.executables.nil? || spec.executables.empty?
-
- if Bundler.requires_sudo?
- FileUtils.mkdir_p("#{Bundler.tmp}/bin") unless File.exist?("#{Bundler.tmp}/bin")
- end
- super
- if Bundler.requires_sudo?
- Bundler.mkdir_p "#{Bundler.rubygems.gem_dir}/bin"
- spec.executables.each do |exe|
- Bundler.sudo "cp -R #{Bundler.tmp}/bin/#{exe} #{Bundler.rubygems.gem_dir}/bin/"
- end
- end
- end
- end
-
- def install(spec)
- Bundler.ui.info "Using #{spec.name} (#{spec.version}) from #{to_s} "
- # Let's be honest, when we're working from a path, we can't
- # really expect native extensions to work because the whole point
- # is to just be able to modify what's in that path and go. So, let's
- # not put ourselves through the pain of actually trying to generate
- # the full gem.
- Installer.new(spec).generate_bin
- end
-
- alias specs local_specs
-
- def cache(spec)
- unless path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
- Bundler.ui.warn " * #{spec.name} at `#{path}` will not be cached."
- end
- end
-
- private
-
def relative_path
if path.to_s.match(%r{^#{Bundler.root.to_s}})
return path.relative_path_from(Bundler.root)
end
-
path
end
@@ -442,7 +448,7 @@ def generate_bin(spec)
gem_file = Dir.chdir(gem_dir){ Gem::Builder.new(spec).build }
- installer = Installer.new(spec, :env_shebang => false)
+ installer = Path::Installer.new(spec, :env_shebang => false)
run_hooks(:pre_install, installer)
installer.build_extensions
run_hooks(:post_build, installer)
@@ -617,17 +623,29 @@ def allowed_in_path
attr_reader :uri, :ref, :options, :submodules
def initialize(options)
- super
+ @options = options
+ @glob = options["glob"] || DEFAULT_GLOB
- # stringify options that could be set as symbols
+ @allow_cached = false
+ @allow_remote = false
+
+ # Stringify options that could be set as symbols
%w(ref branch tag revision).each{|k| options[k] = options[k].to_s if options[k] }
@uri = options["uri"]
@ref = options["ref"] || options["branch"] || options["tag"] || 'master'
@submodules = options["submodules"]
+ @name = options["name"]
+ @version = options["version"]
+
@update = false
@installed = nil
@local = false
+
+ if has_app_cache?
+ @local = true
+ @install_path = @cache_path = app_cache_path
+ end
end
def self.from_lock(options)
@@ -690,6 +708,8 @@ def unlock!
end
def local_override!(path)
+ return false if local?
+
path = Pathname.new(path)
path = path.expand_path(Bundler.root) unless path.relative?
@@ -745,6 +765,14 @@ def install(spec)
generate_bin(spec)
end
+ def cache(spec)
+ return if path.expand_path(Bundler.root).to_s.index(Bundler.root.to_s) == 0
+ FileUtils.rm_rf(app_cache_path)
+ git_proxy.checkout
+ git_proxy.copy_to(app_cache_path, @submodules)
+ FileUtils.rm_rf(app_cache_path.join(".git"))
+ end
+
def load_spec_files
super
rescue PathError, GitError
@@ -765,6 +793,14 @@ def cache_path
private
+ def has_app_cache?
+ cached_revision && super
+ end
+
+ def app_cache_path
+ @app_cache_path ||= Bundler.app_cache.join("#{base_name}-#{shortref_for_path(revision)}")
+ end
+
def local?
@local
end
@@ -817,6 +853,5 @@ def git_proxy
@git_proxy ||= GitProxy.new(cache_path, uri, ref, cached_revision){ allow_git_ops? }
end
end
-
end
end
View
@@ -1,4 +1,5 @@
require "spec_helper"
+
describe "bundle cache with git" do
it "base_name should strip private repo uris" do
source = Bundler::Source::Git.new("uri" => "git@github.com:bundler.git")
@@ -9,4 +10,69 @@
source = Bundler::Source::Git.new("uri" => "//MachineName/ShareFolder")
source.send(:base_name).should == "ShareFolder"
end
- end
+
+ it "copies repository to vendor cache" do
+ git = build_git "foo"
+ ref = git.ref_for("master", 11)
+
+ install_gemfile <<-G
+ gem "foo", :git => '#{lib_path("foo-1.0")}'
+ G
+
+ bundle "cache"
+ bundled_app("vendor/cache/foo-1.0-#{ref}").should exist
+ bundled_app("vendor/cache/foo-1.0-#{ref}/.git").should_not exist
+
+ FileUtils.rm_rf lib_path("foo-1.0")
+ out.should == "Updating .gem files in vendor/cache"
+ should_be_installed "foo 1.0"
+ end
+
+ it "ignores local repository in favor of the cache" do
+ git = build_git "foo"
+ ref = git.ref_for("master", 11)
+
+ build_git "foo", :path => lib_path('local-foo') do |s|
+ s.write "lib/foo.rb", "raise :FAIL"
+ end
+
+ install_gemfile <<-G
+ gem "foo", :git => '#{lib_path("foo-1.0")}', :branch => :master
+ G
+
+ bundle "cache"
+ bundle %|config local.foo #{lib_path('local-foo')}|
+
+ bundle :install
+ out.should =~ /at #{bundled_app("vendor/cache/foo-1.0-#{ref}")}/
+
+ should_be_installed "foo 1.0"
+ end
+
+ it "copies repository to vendor cache, including submodules" do
+ build_git "submodule", "1.0"
+
+ git = build_git "has_submodule", "1.0" do |s|
+ s.add_dependency "submodule"
+ end
+
+ Dir.chdir(lib_path('has_submodule-1.0')) do
+ `git submodule add #{lib_path('submodule-1.0')} submodule-1.0`
+ `git commit -m "submodulator"`
+ end
+
+ install_gemfile <<-G
+ git "#{lib_path('has_submodule-1.0')}", :submodules => true do
+ gem "has_submodule"
+ end
+ G
+
+ ref = git.ref_for("master", 11)
+ bundle "cache"
+
+ bundled_app("vendor/cache/has_submodule-1.0-#{ref}").should exist
+ bundled_app("vendor/cache/has_submodule-1.0-#{ref}/submodule-1.0").should exist
+ out.should == "Updating .gem files in vendor/cache"
+ should_be_installed "has_submodule 1.0"
+ end
+end
View
@@ -2,26 +2,33 @@
describe "bundle cache" do
describe "with path sources" do
- it "is silent when the path is within the bundle" do
+ it "is no-op when the path is within the bundle" do
build_lib "foo", :path => bundled_app("lib/foo")
install_gemfile <<-G
gem "foo", :path => '#{bundled_app("lib/foo")}'
G
bundle "cache"
+ bundled_app("vendor/cache/foo-1.0").should_not exist
+
out.should == "Updating .gem files in vendor/cache"
+ should_be_installed "foo 1.0"
end
- it "warns when the path is outside of the bundle" do
+ it "copies when the path is outside the bundle " do
build_lib "foo"
install_gemfile <<-G
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
bundle "cache"
- out.should include("foo at `#{lib_path("foo-1.0")}` will not be cached")
+ bundled_app("vendor/cache/foo-1.0").should exist
+
+ FileUtils.rm_rf lib_path("foo-1.0")
+ out.should == "Updating .gem files in vendor/cache"
+ should_be_installed "foo 1.0"
end
end
end

5 comments on commit 6ef6e75

This broke my code, which used Open3 without doing a require.

Contributor

josevalim replied Sep 5, 2012

What a wonderful opportunity to fix your code then!

Contributor

josevalim replied Sep 5, 2012

Btw, thanks for reporting. But I really think your code is the one to blame this time. :) It is a bad practice to depend on other code requires.

If I felt it were a bug with bundler I would have opened a bug report. I just needed to say something somewhere after tracking down why the heck things weren't working any more, even though the fix was pretty obvious!

Contributor

josevalim replied Sep 5, 2012

I figured it out later. I replied too fast because I didn't want to miss the joke, hehe, sorry! ❤️

Please sign in to comment.