Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Get a simple bbl install working

  • Loading branch information...
commit ce350cca826e727909f108f6160a6bd59290a639 1 parent 1ce2f0a
Carlhuda authored
View
3  bin/bbl
@@ -0,0 +1,3 @@
+require 'bubble/cli'
+
+Bubble::CLI.start
View
19 lib/bubble.rb
@@ -1,15 +1,26 @@
+require 'pathname'
+require 'bubble/rubygems'
+
module Bubble
VERSION = "0.9.0.pre"
- autoload :Definition, 'bubble/definition'
- autoload :Dependency, 'bubble/dependency'
- autoload :Dsl, 'bubble/dsl'
- autoload :Environment, 'bubble/environment'
+ autoload :Definition, 'bubble/definition'
+ autoload :Dependency, 'bubble/dependency'
+ autoload :Dsl, 'bubble/dsl'
+ autoload :Environment, 'bubble/environment'
+ autoload :Installer, 'bubble/installer'
+ autoload :RemoteSpecification, 'bubble/remote_specification'
+ autoload :Resolver, 'bubble/resolver'
+ autoload :Source, 'bubble/source'
class GemfileNotFound < StandardError; end
class GemNotFound < StandardError; end
class VersionConflict < StandardError; end
+ def self.setup(gemfile = nil)
+ # Does nothing yet
+ end
+
def self.load(gemfile = nil)
Environment.new(definition(gemfile))
end
View
16 lib/bubble/cli.rb
@@ -0,0 +1,16 @@
+$:.unshift File.expand_path('../vendor', __FILE__)
+require 'thor'
+require 'bubble'
+require 'rubygems/config_file'
+
+# Work around a RubyGems bug
+Gem.configuration
+
+module Bubble
+ class CLI < Thor
+ desc "install", "Install the current environment to the system"
+ def install
+ Installer.install(Bubble.definition)
+ end
+ end
+end
View
2  lib/bubble/dependency.rb
@@ -2,6 +2,8 @@
module Bubble
class Dependency < Gem::Dependency
+ attr_accessor :source
+
def initialize(name, version, options = {}, &blk)
options.each do |k, v|
options[k.to_s] = v
View
35 lib/bubble/installer.rb
@@ -0,0 +1,35 @@
+require 'rubygems/dependency_installer'
+
+module Bubble
+ class Installer
+ def self.install(definition)
+ new(definition).run
+ end
+
+ def initialize(definition)
+ @definition = definition
+ end
+
+ def run
+ specs.each do |spec|
+ inst = Gem::DependencyInstaller.new(:ignore_dependencies => true)
+ inst.install spec.name, spec.version
+ end
+ end
+
+ def dependencies
+ @definition.dependencies
+ end
+
+ def specs
+ @specs ||= Resolver.resolve(dependencies, sources)
+ end
+
+ private
+
+ def sources
+ @sources ||= Gem.sources.map { |s| Source::Rubygems.new(:uri => s) }
+ end
+
+ end
+end
View
52 lib/bubble/remote_specification.rb
@@ -0,0 +1,52 @@
+module Bubble
+ # Represents a lazily loaded gem specification, where the full specification
+ # is on the source server in rubygems' "quick" index. The proxy object is to
+ # be seeded with what we're given from the source's abbreviated index - the
+ # full specification will only be fetched when necesary.
+ class RemoteSpecification
+ attr_reader :name, :version, :platform
+
+ def initialize(name, version, platform, source_uri)
+ @name = name
+ @version = version
+ @platform = platform
+ @source_uri = source_uri
+ end
+
+ def full_name
+ if platform == Gem::Platform::RUBY or platform.nil? then
+ "#{@name}-#{@version}"
+ else
+ "#{@name}-#{@version}-#{platform}"
+ end
+ end
+
+ # Because Rubyforge cannot be trusted to provide valid specifications
+ # once the remote gem is donwloaded, the backend specification will
+ # be swapped out.
+ def __swap__(spec)
+ @specification = spec
+ end
+
+ private
+
+ def _remote_uri
+ # "#{@source_uri}/quick/Marshal.4.8/#{@name}-#{@version}.gemspec.rz"
+ tuple = [@name, @version, @platform]
+ tuple = tuple - [nil, 'ruby', '']
+ "#{@source_uri}/quick/Marshal.4.8/#{tuple.join("-")}.gemspec.rz"
+ end
+
+ def _remote_specification
+ @specification ||= begin
+ deflated = Gem::RemoteFetcher.fetcher.fetch_path(_remote_uri)
+ inflated = Gem.inflate(deflated)
+ Marshal.load(inflated)
+ end
+ end
+
+ def method_missing(method, *args, &blk)
+ _remote_specification.send(method, *args, &blk)
+ end
+ end
+end
View
3  lib/bubble/resolver.rb
@@ -1,3 +1,4 @@
+require 'set'
# This is the latest iteration of the gem dependency resolving algorithm. As of now,
# it can resolve (as a success of failure) any set of gem dependencies we throw at it
# in a reasonable amount of time. The most iterations I've seen it take is about 150.
@@ -79,7 +80,7 @@ def initialize(sources, source_requirements)
@index = {}
sources.each do |source|
- source.gems.each do |name, specs|
+ source.specs.each do |name, specs|
# Hack to work with a regular Gem::SourceIndex
specs = [specs] unless specs.is_a?(Array)
specs.compact.each do |spec|
View
8 lib/bubble/rubygems.rb
@@ -0,0 +1,8 @@
+require 'rubygems'
+require 'rubygems/specification'
+
+module Gem
+ class Specification
+ attr_accessor :source
+ end
+end
View
47 lib/bubble/source.rb
@@ -0,0 +1,47 @@
+require "rubygems/remote_fetcher"
+
+module Bubble
+ module Source
+ class Rubygems
+ attr_reader :uri
+
+ def initialize(options = {})
+ @uri = options[:uri]
+ @uri = URI.parse(@uri) unless @uri.is_a?(URI)
+ raise ArgumentError, "The source must be an absolute URI" unless @uri.absolute?
+ end
+
+ def specs
+ @specs ||= fetch_specs
+ end
+
+ private
+
+ def fetch_specs
+ transform(fetch_main_specs + fetch_prerelease_specs)
+ end
+
+ def transform(index)
+ gems = Hash.new { |h,k| h[k] = [] }
+ index.each do |name, version, platform|
+ spec = RemoteSpecification.new(name, version, platform, @uri)
+ gems[spec.name] << spec if Gem::Platform.match(spec.platform)
+ end
+ gems
+ end
+
+ def fetch_main_specs
+ Marshal.load(Gem::RemoteFetcher.fetcher.fetch_path("#{uri}/specs.4.8.gz"))
+ rescue Gem::RemoteFetcher::FetchError => e
+ raise ArgumentError, "#{to_s} is not a valid source: #{e.message}"
+ end
+
+ def fetch_prerelease_specs
+ Marshal.load(Gem::RemoteFetcher.fetcher.fetch_path("#{uri}/prerelease_specs.4.8.gz"))
+ rescue Gem::RemoteFetcher::FetchError
+ Bundler.logger.warn "Source '#{uri}' does not support prerelease gems"
+ []
+ end
+ end
+ end
+end
View
4 spec/install/gems_spec.rb
@@ -1,6 +1,10 @@
require File.expand_path('../../spec_helper', __FILE__)
describe "bbl install" do
+ before :each do
+ in_app_root
+ end
+
it "works" do
gemfile <<-G
gem "rack"
View
1  spec/spec_helper.rb
@@ -27,6 +27,7 @@
config.before :each do
reset!
+ system_gems
end
config.after :each do
View
33 spec/support/helpers.rb
@@ -6,6 +6,9 @@ def reset!
FileUtils.rm_rf(dir)
end
FileUtils.mkdir_p(tmp)
+ FileUtils.mkdir_p(home)
+ Gem.sources = ["file://#{gem_repo1}/"]
+ Gem.configuration.write
end
attr_reader :out
@@ -26,11 +29,19 @@ def run(cmd)
@out = ruby(setup + cmd)
end
+ def lib
+ File.expand_path('../../../lib', __FILE__)
+ end
+
+ def bbl(cmd)
+ bbl = File.expand_path('../../../bin/bbl', __FILE__)
+ @out = %x{#{Gem.ruby} -I#{lib} #{bbl} #{cmd}}
+ end
+
def ruby(opts, ruby = nil)
ruby, opts = opts, nil unless ruby
ruby.gsub!(/(?=")/, "\\")
ruby.gsub!('$', '\\$')
- lib = File.join(File.dirname(__FILE__), '..', '..', 'lib')
%x{#{Gem.ruby} -I#{lib} #{opts} -e "#{ruby}"}.strip
end
@@ -44,16 +55,16 @@ def gemfile(*args)
end
end
- def bubble(*args)
- path = bundled_app("Gemfile")
- path = args.shift if Pathname === args.first
- str = args.shift || ""
- FileUtils.mkdir_p(path.dirname)
- Dir.chdir(path.dirname) do
- gemfile(path, str)
- Bubble.load(path)
- end
- end
+ # def bubble(*args)
+ # path = bundled_app("Gemfile")
+ # path = args.shift if Pathname === args.first
+ # str = args.shift || ""
+ # FileUtils.mkdir_p(path.dirname)
+ # Dir.chdir(path.dirname) do
+ # gemfile(path, str)
+ # Bubble.load(path)
+ # end
+ # end
def install_gems(*gems)
Dir["#{gem_repo1}/**/*.gem"].each do |path|
View
4 spec/support/path.rb
@@ -8,6 +8,10 @@ def tmp(*path)
root.join("tmp", *path)
end
+ def home
+ tmp.join("home")
+ end
+
def bundled_app(*path)
tmp.join("bundled_app", *path)
end
View
3  spec/support/rubygems.rb
@@ -7,9 +7,12 @@ def self.setup
unless File.exist?("#{Path.base_system_gems}")
FileUtils.mkdir_p(Path.base_system_gems)
+ puts "running `gem install builder --no-rdoc --no-ri`"
`gem install builder --no-rdoc --no-ri`
end
+ ENV['HOME'] = Path.home
+
Gem::DefaultUserInteraction.ui = Gem::SilentUI.new
end
Please sign in to comment.
Something went wrong with that request. Please try again.