spitball 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/bin/spitball +3 -3
- data/bin/spitball-server +23 -10
- data/lib/ext/bundler_fake_dsl.rb +27 -0
- data/lib/ext/bundler_lockfile_parser.rb +108 -0
- data/lib/spitball/digest.rb +1 -1
- data/lib/spitball/remote.rb +9 -7
- data/lib/spitball/repo.rb +12 -8
- data/lib/spitball.rb +55 -28
- data/spec/spec_helper.rb +8 -6
- data/spec/spitball_spec.rb +84 -38
- data/spitball.gemspec +11 -10
- metadata +14 -12
- data/Gemfile.sample +0 -8
data/Rakefile
CHANGED
@@ -22,10 +22,10 @@ begin
|
|
22
22
|
gem.description = "Use bundler to generate gem tarball packages."
|
23
23
|
gem.email = "freels@twitter.com"
|
24
24
|
gem.homepage = "http://github.com/freels/spitball"
|
25
|
-
gem.authors = ["Matt Freels", "Brandon Mitchell"]
|
25
|
+
gem.authors = ["Matt Freels", "Brandon Mitchell", "Joshua Hull"]
|
26
26
|
|
27
|
-
gem.add_dependency 'bundler', '
|
28
|
-
gem.add_dependency 'sinatra', '
|
27
|
+
gem.add_dependency 'bundler', '~> 1.0.0'
|
28
|
+
gem.add_dependency 'sinatra', '~> 1.0'
|
29
29
|
|
30
30
|
gem.add_development_dependency 'rspec'
|
31
31
|
gem.add_development_dependency 'rr'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/bin/spitball
CHANGED
@@ -37,7 +37,6 @@ end
|
|
37
37
|
|
38
38
|
opts.permute!(ARGV)
|
39
39
|
|
40
|
-
|
41
40
|
args[:gemfile] = ARGV[0]
|
42
41
|
args[:destination] = ARGV[1]
|
43
42
|
|
@@ -47,9 +46,10 @@ unless args[:gemfile] and args[:destination]
|
|
47
46
|
end
|
48
47
|
|
49
48
|
gemfile = File.read(args[:gemfile])
|
49
|
+
gemfile_lock = File.read("#{args[:gemfile]}.lock")
|
50
50
|
|
51
51
|
ball = args[:host] ?
|
52
|
-
Spitball::Remote.new(gemfile, args[:host], (args[:port] || 8080).to_i) :
|
53
|
-
Spitball.new(gemfile, :without => args[:without])
|
52
|
+
Spitball::Remote.new(gemfile, gemfile_lock, :host => args[:host], :port => (args[:port] || 8080).to_i) :
|
53
|
+
Spitball.new(gemfile, gemfile_lock, :without => args[:without])
|
54
54
|
|
55
55
|
ball.copy_to args[:destination]
|
data/bin/spitball-server
CHANGED
@@ -20,6 +20,7 @@ OptionParser.new { |op|
|
|
20
20
|
set :run, true
|
21
21
|
|
22
22
|
mime_type :gemfile, 'text/plain'
|
23
|
+
mime_type :lock, 'text/plain'
|
23
24
|
mime_type :tgz, 'application/x-compressed'
|
24
25
|
|
25
26
|
# return json array of cached SHAs
|
@@ -33,7 +34,7 @@ get '/:digest.:format' do |digest, format|
|
|
33
34
|
error 400 unless ['tgz', 'gemfile'].include? format
|
34
35
|
|
35
36
|
# this returns 404 on Errno::ENOENT
|
36
|
-
send_file Spitball::Repo.
|
37
|
+
send_file Spitball::Repo.bundle_path(digest, format), :type => format
|
37
38
|
end
|
38
39
|
|
39
40
|
class Streamer
|
@@ -45,7 +46,7 @@ end
|
|
45
46
|
# 202 Accepted if it does not. The body of the response is the URI for
|
46
47
|
# the tarball.
|
47
48
|
post '/create' do
|
48
|
-
ball = Spitball.new(
|
49
|
+
ball = Spitball.new(params['gemfile'], params['gemfile_lock'])
|
49
50
|
url = "#{request.url.split("/create").first}/#{ball.digest}.tgz"
|
50
51
|
response['Location'] = url
|
51
52
|
|
@@ -55,18 +56,30 @@ post '/create' do
|
|
55
56
|
else
|
56
57
|
status 202
|
57
58
|
|
58
|
-
|
59
|
+
i,o = IO.pipe
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
# fork twice. once so we can have a pid to detach from in order to clean up,
|
62
|
+
# twice in order to properly redirect stdout for underlying shell commands.
|
63
|
+
pid = fork do
|
64
|
+
baller = open("|-")
|
65
|
+
if baller == nil # child
|
66
|
+
begin
|
67
|
+
ball.cache!
|
68
|
+
rescue Object => e
|
69
|
+
puts "#{e.class}: #{e}", e.backtrace.map{|l| "\t#{l}" }
|
70
|
+
end
|
71
|
+
else
|
72
|
+
while buf = baller.read(200)
|
73
|
+
$stdout.print buf
|
74
|
+
o.print buf
|
75
|
+
end
|
66
76
|
end
|
67
77
|
exit!
|
68
78
|
end
|
69
79
|
|
70
|
-
|
80
|
+
o.close
|
81
|
+
Process.detach(pid)
|
82
|
+
|
83
|
+
Streamer.new(i)
|
71
84
|
end
|
72
85
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Bundler
|
2
|
+
class FakeDsl
|
3
|
+
|
4
|
+
def initialize(file)
|
5
|
+
@groups = Hash.new{|h, k| h[k] = []}
|
6
|
+
instance_eval(file)
|
7
|
+
end
|
8
|
+
|
9
|
+
def __groups
|
10
|
+
@groups
|
11
|
+
end
|
12
|
+
|
13
|
+
def group(name, &blk)
|
14
|
+
@current_group = name.to_sym
|
15
|
+
instance_eval(&blk)
|
16
|
+
@current_group = nil
|
17
|
+
end
|
18
|
+
alias_method :groups, :group
|
19
|
+
|
20
|
+
def gem(*args)
|
21
|
+
@groups[@current_group] << args.first
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(*args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "strscan"
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
class FakeLockfileParser
|
5
|
+
attr_reader :sources, :dependencies, :specs, :platforms
|
6
|
+
|
7
|
+
def initialize(lockfile)
|
8
|
+
@platforms = []
|
9
|
+
@sources = []
|
10
|
+
@dependencies = []
|
11
|
+
@specs = []
|
12
|
+
@state = :source
|
13
|
+
|
14
|
+
lockfile.split(/(\r?\n)+/).each do |line|
|
15
|
+
if line == "DEPENDENCIES"
|
16
|
+
@state = :dependency
|
17
|
+
elsif line == "PLATFORMS"
|
18
|
+
@state = :platform
|
19
|
+
else
|
20
|
+
send("parse_#{@state}", line)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
TYPES = {
|
28
|
+
"GIT" => Bundler::Source::Git,
|
29
|
+
"GEM" => Bundler::Source::Rubygems,
|
30
|
+
"PATH" => Bundler::Source::Path
|
31
|
+
}
|
32
|
+
|
33
|
+
def parse_source(line)
|
34
|
+
case line
|
35
|
+
when "GIT", "GEM", "PATH"
|
36
|
+
@current_source = nil
|
37
|
+
@opts, @type = {}, line
|
38
|
+
when " specs:"
|
39
|
+
@current_source = TYPES[@type].from_lock(@opts)
|
40
|
+
@sources << @current_source
|
41
|
+
when /^ ([a-z]+): (.*)$/i
|
42
|
+
value = $2
|
43
|
+
value = true if value == "true"
|
44
|
+
value = false if value == "false"
|
45
|
+
|
46
|
+
key = $1
|
47
|
+
|
48
|
+
if @opts[key]
|
49
|
+
@opts[key] = Array(@opts[key])
|
50
|
+
@opts[key] << value
|
51
|
+
else
|
52
|
+
@opts[key] = value
|
53
|
+
end
|
54
|
+
else
|
55
|
+
parse_spec(line)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'
|
60
|
+
|
61
|
+
def parse_dependency(line)
|
62
|
+
if line =~ %r{^ {2}#{NAME_VERSION}(!)?$}
|
63
|
+
name, version, pinned = $1, $2, $4
|
64
|
+
version = version.split(",").map { |d| d.strip } if version
|
65
|
+
|
66
|
+
dep = Bundler::Dependency.new(name, version)
|
67
|
+
|
68
|
+
if pinned && dep.name != 'bundler'
|
69
|
+
spec = @specs.find { |s| s.name == dep.name }
|
70
|
+
dep.source = spec.source if spec
|
71
|
+
|
72
|
+
# Path sources need to know what the default name / version
|
73
|
+
# to use in the case that there are no gemspecs present. A fake
|
74
|
+
# gemspec is created based on the version set on the dependency
|
75
|
+
# TODO: Use the version from the spec instead of from the dependency
|
76
|
+
if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path)
|
77
|
+
dep.source.name = name
|
78
|
+
dep.source.version = $1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
@dependencies << dep
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse_spec(line)
|
87
|
+
if line =~ %r{^ {4}#{NAME_VERSION}$}
|
88
|
+
name, version = $1, Gem::Version.new($2)
|
89
|
+
platform = $3 ? Gem::Platform.new($3) : Gem::Platform::RUBY
|
90
|
+
@current_spec = LazySpecification.new(name, version, platform)
|
91
|
+
@current_spec.source = @current_source
|
92
|
+
@specs << @current_spec
|
93
|
+
elsif line =~ %r{^ {6}#{NAME_VERSION}$}
|
94
|
+
name, version = $1, $2
|
95
|
+
version = version.split(',').map { |d| d.strip } if version
|
96
|
+
dep = Gem::Dependency.new(name, version)
|
97
|
+
@current_spec.dependencies << dep
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse_platform(line)
|
102
|
+
if line =~ /^ (.*)$/
|
103
|
+
@platforms << Gem::Platform.new($1)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
data/lib/spitball/digest.rb
CHANGED
data/lib/spitball/remote.rb
CHANGED
@@ -3,10 +3,11 @@ require 'uri'
|
|
3
3
|
|
4
4
|
class Spitball::Remote
|
5
5
|
|
6
|
-
def initialize(gemfile,
|
6
|
+
def initialize(gemfile, gemfile_lock, opts = {})
|
7
7
|
@gemfile = gemfile
|
8
|
-
@
|
9
|
-
@
|
8
|
+
@gemfile_lock = gemfile_lock
|
9
|
+
@host = opts[:host]
|
10
|
+
@port = opts[:port]
|
10
11
|
end
|
11
12
|
|
12
13
|
def copy_to(path)
|
@@ -18,10 +19,11 @@ class Spitball::Remote
|
|
18
19
|
|
19
20
|
def generate_remote_tarball
|
20
21
|
url = URI.parse("http://#{@host}:#{@port}/create")
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
req = Net::HTTP::Post.new(url.path)
|
23
|
+
req.form_data = {'gemfile' => @gemfile, 'gemfile_lock' => @gemfile_lock}
|
24
|
+
|
25
|
+
res = Net::HTTP.new(url.host, url.port).start do |http|
|
26
|
+
http.request(req) {|r| puts r.read_body }
|
25
27
|
end
|
26
28
|
|
27
29
|
print "\nDownloading tarball..."; $stdout.flush
|
data/lib/spitball/repo.rb
CHANGED
@@ -3,21 +3,25 @@ module Spitball::Repo
|
|
3
3
|
|
4
4
|
WORKING_DIR = ENV['SPITBALL_CACHE'] || '/tmp/spitball'
|
5
5
|
|
6
|
-
def
|
6
|
+
def bundle_path(digest, extension = nil)
|
7
7
|
extension = ".#{extension}" unless extension.nil? or extension.empty?
|
8
8
|
File.join WORKING_DIR, "bundle_#{digest}#{extension}"
|
9
9
|
end
|
10
10
|
|
11
|
+
def gemcache_path
|
12
|
+
File.join(WORKING_DIR, "gemcache")
|
13
|
+
end
|
14
|
+
|
15
|
+
def gemfile(digest)
|
16
|
+
bundle_path digest, 'gemfile'
|
17
|
+
end
|
18
|
+
|
11
19
|
def exist?(digest)
|
12
20
|
File.exist? tarball(digest)
|
13
21
|
end
|
14
22
|
|
15
23
|
def tarball(digest)
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def gemfile(digest)
|
20
|
-
path(digest, 'gemfile')
|
24
|
+
bundle_path(digest, 'tgz')
|
21
25
|
end
|
22
26
|
|
23
27
|
def cached_digests
|
@@ -26,8 +30,8 @@ module Spitball::Repo
|
|
26
30
|
end.compact.uniq.sort
|
27
31
|
end
|
28
32
|
|
29
|
-
def
|
30
|
-
FileUtils.mkdir_p WORKING_DIR
|
33
|
+
def make_cache_dirs
|
34
|
+
FileUtils.mkdir_p File.join(WORKING_DIR, "gemcache")
|
31
35
|
end
|
32
36
|
|
33
37
|
def clean_up_unused(access_window)
|
data/lib/spitball.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'bundler'
|
4
|
+
require 'ext/bundler_lockfile_parser'
|
5
|
+
require 'ext/bundler_fake_dsl'
|
2
6
|
|
3
7
|
class Spitball
|
4
8
|
require 'spitball/digest'
|
@@ -14,11 +18,13 @@ class Spitball
|
|
14
18
|
|
15
19
|
include Spitball::Digest
|
16
20
|
|
17
|
-
attr_reader :gemfile, :options
|
21
|
+
attr_reader :gemfile, :gemfile_lock, :without, :options
|
18
22
|
|
19
|
-
def initialize(gemfile, options = {})
|
20
|
-
@gemfile
|
21
|
-
@
|
23
|
+
def initialize(gemfile, gemfile_lock, options = {})
|
24
|
+
@gemfile = gemfile
|
25
|
+
@gemfile_lock = gemfile_lock
|
26
|
+
@options = options
|
27
|
+
@without = (options[:without] || []).map{|w| w.to_sym}
|
22
28
|
end
|
23
29
|
|
24
30
|
def copy_to(dest)
|
@@ -31,14 +37,12 @@ class Spitball
|
|
31
37
|
end
|
32
38
|
|
33
39
|
def cache!(sync = true)
|
34
|
-
Spitball::Repo.
|
35
|
-
|
40
|
+
Spitball::Repo.make_cache_dirs
|
36
41
|
unless cached?
|
37
42
|
lock = Spitball::FileLock.new(bundle_path('lock'))
|
38
|
-
|
39
43
|
if lock.acquire_lock
|
40
44
|
begin
|
41
|
-
|
45
|
+
create_bundle
|
42
46
|
ensure
|
43
47
|
lock.release_lock
|
44
48
|
end
|
@@ -49,43 +53,66 @@ class Spitball
|
|
49
53
|
end
|
50
54
|
|
51
55
|
def create_bundle
|
56
|
+
ENV['BUNDLE_GEMFILE'] = gemfile_path # make bundler happy! :) *cry*
|
57
|
+
Spitball::Repo.make_cache_dirs
|
52
58
|
FileUtils.mkdir_p bundle_path
|
53
59
|
|
60
|
+
# save gemfile and lock file for future reference.
|
54
61
|
File.open(gemfile_path, 'w') {|f| f.write gemfile }
|
62
|
+
File.open(gemfile_lock_path, 'w') {|f| f.write gemfile_lock }
|
55
63
|
|
56
|
-
|
64
|
+
parsed_lockfile, dsl = Bundler::FakeLockfileParser.new(gemfile_lock), Bundler::FakeDsl.new(gemfile)
|
57
65
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
if Dir["#{bundle_path}/bin/*"].length > 0
|
62
|
-
if RUBY_PLATFORM =~ /linux/
|
63
|
-
system "cd #{bundle_path} && find bin/* -exec sed -i'' '1,1 s|^#!/.*/ruby[ ]*|#!/usr/bin/env ruby|' {} \\;"
|
64
|
-
else
|
65
|
-
system "cd #{bundle_path} && find bin/* -exec sed -i '' '1,1 s|^#!/.*/ruby[ ]*|#!/usr/bin/env ruby|' {} \\;"
|
66
|
-
end
|
66
|
+
Dir.chdir(Repo.gemcache_path) do
|
67
|
+
parsed_lockfile.specs.each do |spec|
|
68
|
+
install_gem(spec, parsed_lockfile.sources) unless without.any?{|w| dsl.__groups[w].include?(spec.name)}
|
67
69
|
end
|
70
|
+
end
|
68
71
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
72
|
+
Dir.chdir(bundle_path) do
|
73
|
+
Dir["#{bundle_path}/bin/**"].each do |file|
|
74
|
+
contents = File.read(file)
|
75
|
+
contents.gsub!(/^#!.*?\n/, "#!/usr/bin/env ruby\n")
|
76
|
+
File.open(file, 'w') {|f| f << contents}
|
77
|
+
end
|
73
78
|
end
|
74
79
|
|
80
|
+
system "rm -rf #{bundle_path}/cache"
|
81
|
+
system "tar czf #{tarball_path}.#{Process.pid} -C #{bundle_path} ."
|
82
|
+
system "mv #{tarball_path}.#{Process.pid} #{tarball_path}"
|
75
83
|
FileUtils.rm_rf bundle_path
|
76
84
|
end
|
77
85
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
86
|
+
def install_gem(spec, sources)
|
87
|
+
cache_dir = File.join(Repo.gemcache_path, "#{spec.name}-#{::Digest::MD5.hexdigest([spec.name, spec.version, sources_opt(sources)].join('/'))}")
|
88
|
+
unless File.exist?(cache_dir)
|
89
|
+
FileUtils.mkdir_p(cache_dir)
|
90
|
+
out = `gem install #{spec.name} -v'#{spec.version}' --no-rdoc --no-ri --ignore-dependencies -i#{cache_dir} #{sources_opt(sources)} 2>&1`
|
91
|
+
$? == 0 ? (puts out) : (raise BundleCreationFailure, out)
|
92
|
+
else
|
93
|
+
puts "Using cached version of #{spec.name} (#{spec.version})"
|
94
|
+
end
|
95
|
+
`cp -R #{cache_dir}/* #{bundle_path}`
|
96
|
+
end
|
81
97
|
|
82
|
-
|
98
|
+
def sources_opt(sources)
|
99
|
+
sources.
|
100
|
+
map{|s| s.remotes}.flatten.
|
101
|
+
map{|s| s.to_s}.
|
102
|
+
sort.
|
103
|
+
map{|s| %w{gemcutter rubygems rubyforge}.include?(s) ? "http://rubygems.org" : s}.
|
104
|
+
map{|s| "--source #{s}"}.
|
105
|
+
join(' ')
|
83
106
|
end
|
84
107
|
|
85
108
|
# Paths
|
86
109
|
|
87
110
|
def bundle_path(extension = nil)
|
88
|
-
Repo.
|
111
|
+
Repo.bundle_path(digest, extension)
|
112
|
+
end
|
113
|
+
|
114
|
+
def gemfile_lock_path
|
115
|
+
File.expand_path('Gemfile.lock', bundle_path)
|
89
116
|
end
|
90
117
|
|
91
118
|
def gemfile_path
|
@@ -93,6 +120,6 @@ class Spitball
|
|
93
120
|
end
|
94
121
|
|
95
122
|
def tarball_path
|
96
|
-
Repo.
|
123
|
+
Repo.bundle_path(digest, 'tgz')
|
97
124
|
end
|
98
125
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -30,6 +30,14 @@ end
|
|
30
30
|
|
31
31
|
# helper methods
|
32
32
|
|
33
|
+
def capture_stdout
|
34
|
+
$stdout = StringIO.new
|
35
|
+
yield
|
36
|
+
$stdout.string
|
37
|
+
ensure
|
38
|
+
$stdout = STDOUT
|
39
|
+
end
|
40
|
+
|
33
41
|
def purge_test_cache
|
34
42
|
FileUtils.rm_rf SPITBALL_CACHE
|
35
43
|
end
|
@@ -49,12 +57,6 @@ def use_success_bundler
|
|
49
57
|
end
|
50
58
|
end
|
51
59
|
|
52
|
-
def use_fail_bundler
|
53
|
-
make_bundler do |f|
|
54
|
-
f.puts "exit 1"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
60
|
def purge_bin
|
59
61
|
FileUtils.rm_rf File.expand_path('bin', SPEC_DIR)
|
60
62
|
end
|
data/spec/spitball_spec.rb
CHANGED
@@ -6,16 +6,30 @@ describe Spitball do
|
|
6
6
|
|
7
7
|
@gemfile = <<-end_gemfile
|
8
8
|
source :rubygems
|
9
|
-
gem "
|
9
|
+
gem "json_pure"
|
10
10
|
end_gemfile
|
11
11
|
|
12
|
-
@
|
12
|
+
@lockfile = <<-end_lockfile.strip.gsub(/\n[ ]{6}/m, "\n")
|
13
|
+
GEM
|
14
|
+
remote: http://rubygems.org/
|
15
|
+
specs:
|
16
|
+
json_pure (1.4.6)
|
17
|
+
|
18
|
+
PLATFORMS
|
19
|
+
ruby
|
20
|
+
|
21
|
+
DEPENDENCIES
|
22
|
+
json_pure
|
23
|
+
end_lockfile
|
24
|
+
|
25
|
+
@spitball = Spitball.new(@gemfile, @lockfile)
|
13
26
|
end
|
14
27
|
|
15
28
|
describe "cached?" do
|
16
29
|
it "returns true if the tarball has already been cached" do
|
17
30
|
@spitball.should_not be_cached
|
18
|
-
@spitball.
|
31
|
+
mock(@spitball).install_gem(anything, anything).times(any_times)
|
32
|
+
capture_stdout { @spitball.cache! }
|
19
33
|
@spitball.should be_cached
|
20
34
|
end
|
21
35
|
end
|
@@ -34,7 +48,6 @@ describe Spitball do
|
|
34
48
|
mock.instance_of(Spitball::FileLock).acquire_lock { true }
|
35
49
|
mock(@spitball).create_bundle
|
36
50
|
mock.instance_of(Spitball::FileLock).release_lock
|
37
|
-
|
38
51
|
@spitball.cache!
|
39
52
|
end
|
40
53
|
|
@@ -69,30 +82,56 @@ describe Spitball do
|
|
69
82
|
|
70
83
|
describe "create_bundle" do
|
71
84
|
it "generates a bundle at the bundle_path" do
|
72
|
-
@spitball.
|
73
|
-
|
85
|
+
mock(@spitball).install_gem(anything, anything).times(any_times)
|
86
|
+
capture_stdout { @spitball.create_bundle }
|
74
87
|
File.exist?(@spitball.tarball_path).should == true
|
75
88
|
end
|
76
|
-
|
77
|
-
it "raises an exception if bundle creation fails" do
|
78
|
-
use_fail_bundler
|
79
|
-
|
80
|
-
lambda { @spitball.create_bundle }.should raise_error(Spitball::BundleCreationFailure)
|
81
|
-
File.exist?(@spitball.tarball_path).should_not == true
|
82
|
-
end
|
83
89
|
end
|
84
90
|
|
85
91
|
describe "without_clause" do
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
+
before do
|
93
|
+
@gemfile = <<-end_gemfile
|
94
|
+
source :rubygems
|
95
|
+
group 'development' do
|
96
|
+
gem "activerecord"
|
97
|
+
end
|
98
|
+
end_gemfile
|
99
|
+
|
100
|
+
@lockfile = <<-end_lockfile.strip.gsub(/\n[ ]{6}/m, "\n")
|
101
|
+
GEM
|
102
|
+
remote: http://rubygems.org/
|
103
|
+
specs:
|
104
|
+
activemodel (3.0.1)
|
105
|
+
activesupport (= 3.0.1)
|
106
|
+
builder (~> 2.1.2)
|
107
|
+
i18n (~> 0.4.1)
|
108
|
+
activerecord (3.0.1)
|
109
|
+
activemodel (= 3.0.1)
|
110
|
+
activesupport (= 3.0.1)
|
111
|
+
arel (~> 1.0.0)
|
112
|
+
tzinfo (~> 0.3.23)
|
113
|
+
activesupport (3.0.1)
|
114
|
+
arel (1.0.1)
|
115
|
+
activesupport (~> 3.0.0)
|
116
|
+
builder (2.1.2)
|
117
|
+
i18n (0.4.2)
|
118
|
+
tzinfo (0.3.23)
|
119
|
+
|
120
|
+
PLATFORMS
|
121
|
+
ruby
|
122
|
+
|
123
|
+
DEPENDENCIES
|
124
|
+
activerecord
|
125
|
+
end_lockfile
|
92
126
|
end
|
93
|
-
|
94
|
-
it "
|
95
|
-
Spitball.new(
|
127
|
+
|
128
|
+
it "should use without" do
|
129
|
+
@spitball = Spitball.new(@gemfile, @lockfile)
|
130
|
+
mock(@spitball).install_gem(anything, anything).times(3)
|
131
|
+
@spitball.create_bundle
|
132
|
+
@spitball = Spitball.new(@gemfile, @lockfile, :without => 'development')
|
133
|
+
mock(@spitball).install_gem(anything, anything).times(1)
|
134
|
+
@spitball.create_bundle
|
96
135
|
end
|
97
136
|
end
|
98
137
|
end
|
@@ -100,7 +139,7 @@ end
|
|
100
139
|
describe Spitball::FileLock do
|
101
140
|
describe "acquire_lock" do
|
102
141
|
before do
|
103
|
-
Spitball::Repo.
|
142
|
+
Spitball::Repo.make_cache_dirs
|
104
143
|
@lock_path = File.expand_path('test.lock', SPITBALL_CACHE)
|
105
144
|
@lock = Spitball::FileLock.new(@lock_path)
|
106
145
|
end
|
@@ -120,50 +159,56 @@ end
|
|
120
159
|
|
121
160
|
describe Spitball::Repo do
|
122
161
|
before do
|
123
|
-
Spitball::Repo.
|
162
|
+
Spitball::Repo.make_cache_dirs
|
124
163
|
end
|
125
164
|
|
126
|
-
describe "
|
165
|
+
describe "make_cache_dirs" do
|
127
166
|
it "creates the correct cache dir" do
|
128
167
|
FileUtils.rm_rf(SPITBALL_CACHE)
|
129
168
|
|
130
169
|
File.exist?(SPITBALL_CACHE).should_not == true
|
131
|
-
Spitball::Repo.
|
170
|
+
Spitball::Repo.make_cache_dirs
|
132
171
|
File.exist?(SPITBALL_CACHE).should == true
|
133
172
|
end
|
134
173
|
end
|
135
174
|
|
136
|
-
describe "
|
175
|
+
describe "bundle_path" do
|
137
176
|
it "generates paths with the correct cache" do
|
138
|
-
Spitball::Repo.
|
177
|
+
Spitball::Repo.bundle_path('digest').should =~ %r[^#{SPITBALL_CACHE}]
|
139
178
|
end
|
140
179
|
|
141
180
|
it "generates paths with extensions" do
|
142
|
-
Spitball::Repo.
|
181
|
+
Spitball::Repo.bundle_path('digest', 'tgz').should =~ %r[\.tgz$]
|
143
182
|
end
|
144
183
|
|
145
184
|
it "generates paths prefixed with bundle_" do
|
146
|
-
Spitball::Repo.
|
185
|
+
Spitball::Repo.bundle_path('digest', 'tgz').should =~ %r[bundle_digest\.tgz$]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "gemcache_path" do
|
190
|
+
it "returns the correct path in the cache dir" do
|
191
|
+
Spitball::Repo.gemcache_path.should == File.join(SPITBALL_CACHE, "gemcache")
|
147
192
|
end
|
148
193
|
end
|
149
194
|
|
150
195
|
describe "exist?" do
|
151
196
|
it "returns true if tarball for a digest exists" do
|
152
197
|
Spitball::Repo.exist?('digest').should_not == true
|
153
|
-
File.open(Spitball::Repo.
|
198
|
+
File.open(Spitball::Repo.bundle_path('digest', 'tgz'), 'w') {|f| f.write 'tarball!' }
|
154
199
|
Spitball::Repo.exist?('digest').should == true
|
155
200
|
end
|
156
201
|
end
|
157
202
|
|
158
203
|
describe "tarball" do
|
159
204
|
it "returns the path of the cached tarball for a digest" do
|
160
|
-
Spitball::Repo.tarball('digest').should == Spitball::Repo.
|
205
|
+
Spitball::Repo.tarball('digest').should == Spitball::Repo.bundle_path('digest', 'tgz')
|
161
206
|
end
|
162
207
|
end
|
163
208
|
|
164
209
|
describe "gemfile" do
|
165
210
|
it "returns the path of the cached gemfile for a digest" do
|
166
|
-
Spitball::Repo.gemfile('digest').should == Spitball::Repo.
|
211
|
+
Spitball::Repo.gemfile('digest').should == Spitball::Repo.bundle_path('digest', 'gemfile')
|
167
212
|
end
|
168
213
|
end
|
169
214
|
|
@@ -197,15 +242,16 @@ end
|
|
197
242
|
|
198
243
|
describe Spitball::Digest do
|
199
244
|
it "generates a digest based on the spitball's options and gemfile" do
|
200
|
-
[Spitball.new('gemfile contents', :without => "system").digest,
|
201
|
-
Spitball.new('gemfile contents 2', :without => "system").digest,
|
202
|
-
Spitball.new('gemfile', :without => "other_group").digest,
|
203
|
-
Spitball.new('gemfile').digest
|
245
|
+
[Spitball.new('gemfile contents', 'gemlock', :without => "system").digest,
|
246
|
+
Spitball.new('gemfile contents 2', 'gemlock', :without => "system").digest,
|
247
|
+
Spitball.new('gemfile', 'gemlock', :without => "other_group").digest,
|
248
|
+
Spitball.new('gemfile', 'gemlock').digest,
|
249
|
+
Spitball.new('gemfile', 'gemlock2').digest
|
204
250
|
].uniq.length.should == 4
|
205
251
|
end
|
206
252
|
|
207
253
|
it "provides a hash equal to the digest's hash"do
|
208
|
-
spitball = Spitball.new('gemfile contents')
|
254
|
+
spitball = Spitball.new('gemfile contents', 'gemlock contents')
|
209
255
|
spitball.hash.should == spitball.digest.hash
|
210
256
|
end
|
211
257
|
end
|
data/spitball.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{spitball}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Matt Freels", "Brandon Mitchell"]
|
12
|
-
s.date = %q{2010-
|
11
|
+
s.authors = ["Matt Freels", "Brandon Mitchell", "Joshua Hull"]
|
12
|
+
s.date = %q{2010-10-27}
|
13
13
|
s.description = %q{Use bundler to generate gem tarball packages.}
|
14
14
|
s.email = %q{freels@twitter.com}
|
15
15
|
s.executables = ["spitball", "spitball-cache-cleanup", "spitball-server"]
|
@@ -18,13 +18,14 @@ Gem::Specification.new do |s|
|
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".gitignore",
|
21
|
-
"Gemfile.sample",
|
22
21
|
"README.md",
|
23
22
|
"Rakefile",
|
24
23
|
"VERSION",
|
25
24
|
"bin/spitball",
|
26
25
|
"bin/spitball-cache-cleanup",
|
27
26
|
"bin/spitball-server",
|
27
|
+
"lib/ext/bundler_fake_dsl.rb",
|
28
|
+
"lib/ext/bundler_lockfile_parser.rb",
|
28
29
|
"lib/spitball.rb",
|
29
30
|
"lib/spitball/digest.rb",
|
30
31
|
"lib/spitball/file_lock.rb",
|
@@ -50,19 +51,19 @@ Gem::Specification.new do |s|
|
|
50
51
|
s.specification_version = 3
|
51
52
|
|
52
53
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
53
|
-
s.add_runtime_dependency(%q<bundler>, ["
|
54
|
-
s.add_runtime_dependency(%q<sinatra>, ["
|
54
|
+
s.add_runtime_dependency(%q<bundler>, ["~> 1.0.0"])
|
55
|
+
s.add_runtime_dependency(%q<sinatra>, ["~> 1.0"])
|
55
56
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
56
57
|
s.add_development_dependency(%q<rr>, [">= 0"])
|
57
58
|
else
|
58
|
-
s.add_dependency(%q<bundler>, ["
|
59
|
-
s.add_dependency(%q<sinatra>, ["
|
59
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
60
|
+
s.add_dependency(%q<sinatra>, ["~> 1.0"])
|
60
61
|
s.add_dependency(%q<rspec>, [">= 0"])
|
61
62
|
s.add_dependency(%q<rr>, [">= 0"])
|
62
63
|
end
|
63
64
|
else
|
64
|
-
s.add_dependency(%q<bundler>, ["
|
65
|
-
s.add_dependency(%q<sinatra>, ["
|
65
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
66
|
+
s.add_dependency(%q<sinatra>, ["~> 1.0"])
|
66
67
|
s.add_dependency(%q<rspec>, [">= 0"])
|
67
68
|
s.add_dependency(%q<rr>, [">= 0"])
|
68
69
|
end
|
metadata
CHANGED
@@ -1,22 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spitball
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matt Freels
|
14
14
|
- Brandon Mitchell
|
15
|
+
- Joshua Hull
|
15
16
|
autorequire:
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
19
|
|
19
|
-
date: 2010-
|
20
|
+
date: 2010-10-27 00:00:00 -07:00
|
20
21
|
default_executable:
|
21
22
|
dependencies:
|
22
23
|
- !ruby/object:Gem::Dependency
|
@@ -25,14 +26,14 @@ dependencies:
|
|
25
26
|
requirement: &id001 !ruby/object:Gem::Requirement
|
26
27
|
none: false
|
27
28
|
requirements:
|
28
|
-
- -
|
29
|
+
- - ~>
|
29
30
|
- !ruby/object:Gem::Version
|
30
|
-
hash:
|
31
|
+
hash: 23
|
31
32
|
segments:
|
33
|
+
- 1
|
32
34
|
- 0
|
33
|
-
-
|
34
|
-
|
35
|
-
version: 0.9.5
|
35
|
+
- 0
|
36
|
+
version: 1.0.0
|
36
37
|
type: :runtime
|
37
38
|
version_requirements: *id001
|
38
39
|
- !ruby/object:Gem::Dependency
|
@@ -41,7 +42,7 @@ dependencies:
|
|
41
42
|
requirement: &id002 !ruby/object:Gem::Requirement
|
42
43
|
none: false
|
43
44
|
requirements:
|
44
|
-
- -
|
45
|
+
- - ~>
|
45
46
|
- !ruby/object:Gem::Version
|
46
47
|
hash: 15
|
47
48
|
segments:
|
@@ -90,13 +91,14 @@ extra_rdoc_files:
|
|
90
91
|
- README.md
|
91
92
|
files:
|
92
93
|
- .gitignore
|
93
|
-
- Gemfile.sample
|
94
94
|
- README.md
|
95
95
|
- Rakefile
|
96
96
|
- VERSION
|
97
97
|
- bin/spitball
|
98
98
|
- bin/spitball-cache-cleanup
|
99
99
|
- bin/spitball-server
|
100
|
+
- lib/ext/bundler_fake_dsl.rb
|
101
|
+
- lib/ext/bundler_lockfile_parser.rb
|
100
102
|
- lib/spitball.rb
|
101
103
|
- lib/spitball/digest.rb
|
102
104
|
- lib/spitball/file_lock.rb
|