carat 1.9.9.pre1
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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.travis.yml +24 -0
- data/CHANGELOG.md +2006 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +23 -0
- data/DEVELOPMENT.md +119 -0
- data/ISSUES.md +96 -0
- data/LICENSE.md +23 -0
- data/README.md +32 -0
- data/Rakefile +308 -0
- data/bin/carat +21 -0
- data/bin/carat_ruby +56 -0
- data/carat.gemspec +32 -0
- data/lib/carat.rb +446 -0
- data/lib/carat/anonymizable_uri.rb +32 -0
- data/lib/carat/capistrano.rb +16 -0
- data/lib/carat/cli.rb +407 -0
- data/lib/carat/cli/binstubs.rb +38 -0
- data/lib/carat/cli/cache.rb +35 -0
- data/lib/carat/cli/check.rb +35 -0
- data/lib/carat/cli/clean.rb +26 -0
- data/lib/carat/cli/common.rb +56 -0
- data/lib/carat/cli/config.rb +84 -0
- data/lib/carat/cli/console.rb +38 -0
- data/lib/carat/cli/exec.rb +44 -0
- data/lib/carat/cli/gem.rb +195 -0
- data/lib/carat/cli/init.rb +33 -0
- data/lib/carat/cli/inject.rb +33 -0
- data/lib/carat/cli/install.rb +156 -0
- data/lib/carat/cli/open.rb +23 -0
- data/lib/carat/cli/outdated.rb +80 -0
- data/lib/carat/cli/package.rb +45 -0
- data/lib/carat/cli/platform.rb +43 -0
- data/lib/carat/cli/show.rb +74 -0
- data/lib/carat/cli/update.rb +73 -0
- data/lib/carat/cli/viz.rb +27 -0
- data/lib/carat/constants.rb +5 -0
- data/lib/carat/current_ruby.rb +183 -0
- data/lib/carat/definition.rb +628 -0
- data/lib/carat/dep_proxy.rb +43 -0
- data/lib/carat/dependency.rb +110 -0
- data/lib/carat/deployment.rb +59 -0
- data/lib/carat/deprecate.rb +15 -0
- data/lib/carat/dsl.rb +331 -0
- data/lib/carat/endpoint_specification.rb +76 -0
- data/lib/carat/env.rb +75 -0
- data/lib/carat/environment.rb +42 -0
- data/lib/carat/fetcher.rb +423 -0
- data/lib/carat/friendly_errors.rb +85 -0
- data/lib/carat/gem_helper.rb +180 -0
- data/lib/carat/gem_helpers.rb +26 -0
- data/lib/carat/gem_installer.rb +9 -0
- data/lib/carat/gem_path_manipulation.rb +8 -0
- data/lib/carat/gem_tasks.rb +2 -0
- data/lib/carat/graph.rb +169 -0
- data/lib/carat/index.rb +197 -0
- data/lib/carat/injector.rb +64 -0
- data/lib/carat/installer.rb +339 -0
- data/lib/carat/lazy_specification.rb +83 -0
- data/lib/carat/lockfile_parser.rb +167 -0
- data/lib/carat/match_platform.rb +13 -0
- data/lib/carat/psyched_yaml.rb +26 -0
- data/lib/carat/remote_specification.rb +57 -0
- data/lib/carat/resolver.rb +334 -0
- data/lib/carat/retry.rb +60 -0
- data/lib/carat/ruby_dsl.rb +11 -0
- data/lib/carat/ruby_version.rb +117 -0
- data/lib/carat/rubygems_ext.rb +170 -0
- data/lib/carat/rubygems_integration.rb +619 -0
- data/lib/carat/runtime.rb +289 -0
- data/lib/carat/settings.rb +208 -0
- data/lib/carat/setup.rb +24 -0
- data/lib/carat/shared_helpers.rb +149 -0
- data/lib/carat/similarity_detector.rb +63 -0
- data/lib/carat/source.rb +46 -0
- data/lib/carat/source/git.rb +294 -0
- data/lib/carat/source/git/git_proxy.rb +162 -0
- data/lib/carat/source/path.rb +226 -0
- data/lib/carat/source/path/installer.rb +43 -0
- data/lib/carat/source/rubygems.rb +381 -0
- data/lib/carat/source_list.rb +101 -0
- data/lib/carat/spec_set.rb +154 -0
- data/lib/carat/ssl_certs/.document +1 -0
- data/lib/carat/ssl_certs/AddTrustExternalCARoot-2048.pem +25 -0
- data/lib/carat/ssl_certs/AddTrustExternalCARoot.pem +32 -0
- data/lib/carat/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +14 -0
- data/lib/carat/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +23 -0
- data/lib/carat/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +28 -0
- data/lib/carat/ssl_certs/GeoTrustGlobalCA.pem +20 -0
- data/lib/carat/ssl_certs/certificate_manager.rb +66 -0
- data/lib/carat/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +21 -0
- data/lib/carat/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem +23 -0
- data/lib/carat/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem +25 -0
- data/lib/carat/templates/Executable +16 -0
- data/lib/carat/templates/Executable.standalone +12 -0
- data/lib/carat/templates/Gemfile +4 -0
- data/lib/carat/templates/newgem/.travis.yml.tt +3 -0
- data/lib/carat/templates/newgem/CODE_OF_CONDUCT.md.tt +13 -0
- data/lib/carat/templates/newgem/Gemfile.tt +4 -0
- data/lib/carat/templates/newgem/LICENSE.txt.tt +21 -0
- data/lib/carat/templates/newgem/README.md.tt +39 -0
- data/lib/carat/templates/newgem/Rakefile.tt +25 -0
- data/lib/carat/templates/newgem/bin/console.tt +14 -0
- data/lib/carat/templates/newgem/bin/setup.tt +7 -0
- data/lib/carat/templates/newgem/exe/newgem.tt +3 -0
- data/lib/carat/templates/newgem/ext/newgem/extconf.rb.tt +3 -0
- data/lib/carat/templates/newgem/ext/newgem/newgem.c.tt +9 -0
- data/lib/carat/templates/newgem/ext/newgem/newgem.h.tt +6 -0
- data/lib/carat/templates/newgem/gitignore.tt +16 -0
- data/lib/carat/templates/newgem/lib/newgem.rb.tt +12 -0
- data/lib/carat/templates/newgem/lib/newgem/version.rb.tt +7 -0
- data/lib/carat/templates/newgem/newgem.gemspec.tt +43 -0
- data/lib/carat/templates/newgem/rspec.tt +2 -0
- data/lib/carat/templates/newgem/spec/newgem_spec.rb.tt +11 -0
- data/lib/carat/templates/newgem/spec/spec_helper.rb.tt +2 -0
- data/lib/carat/templates/newgem/test/minitest_helper.rb.tt +4 -0
- data/lib/carat/templates/newgem/test/test_newgem.rb.tt +11 -0
- data/lib/carat/ui.rb +7 -0
- data/lib/carat/ui/rg_proxy.rb +21 -0
- data/lib/carat/ui/shell.rb +103 -0
- data/lib/carat/ui/silent.rb +44 -0
- data/lib/carat/vendor/molinillo/lib/molinillo.rb +5 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/dependency_graph.rb +266 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/errors.rb +69 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/gem_metadata.rb +3 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +90 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/modules/ui.rb +63 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/resolution.rb +415 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/resolver.rb +43 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/state.rb +43 -0
- data/lib/carat/vendor/net/http/faster.rb +26 -0
- data/lib/carat/vendor/net/http/persistent.rb +1230 -0
- data/lib/carat/vendor/net/http/persistent/ssl_reuse.rb +128 -0
- data/lib/carat/vendor/thor/lib/thor.rb +484 -0
- data/lib/carat/vendor/thor/lib/thor/actions.rb +319 -0
- data/lib/carat/vendor/thor/lib/thor/actions/create_file.rb +103 -0
- data/lib/carat/vendor/thor/lib/thor/actions/create_link.rb +59 -0
- data/lib/carat/vendor/thor/lib/thor/actions/directory.rb +118 -0
- data/lib/carat/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
- data/lib/carat/vendor/thor/lib/thor/actions/file_manipulation.rb +316 -0
- data/lib/carat/vendor/thor/lib/thor/actions/inject_into_file.rb +107 -0
- data/lib/carat/vendor/thor/lib/thor/base.rb +656 -0
- data/lib/carat/vendor/thor/lib/thor/command.rb +133 -0
- data/lib/carat/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +77 -0
- data/lib/carat/vendor/thor/lib/thor/core_ext/io_binary_read.rb +10 -0
- data/lib/carat/vendor/thor/lib/thor/core_ext/ordered_hash.rb +98 -0
- data/lib/carat/vendor/thor/lib/thor/error.rb +32 -0
- data/lib/carat/vendor/thor/lib/thor/group.rb +281 -0
- data/lib/carat/vendor/thor/lib/thor/invocation.rb +178 -0
- data/lib/carat/vendor/thor/lib/thor/line_editor.rb +17 -0
- data/lib/carat/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
- data/lib/carat/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
- data/lib/carat/vendor/thor/lib/thor/parser.rb +4 -0
- data/lib/carat/vendor/thor/lib/thor/parser/argument.rb +73 -0
- data/lib/carat/vendor/thor/lib/thor/parser/arguments.rb +175 -0
- data/lib/carat/vendor/thor/lib/thor/parser/option.rb +125 -0
- data/lib/carat/vendor/thor/lib/thor/parser/options.rb +218 -0
- data/lib/carat/vendor/thor/lib/thor/rake_compat.rb +71 -0
- data/lib/carat/vendor/thor/lib/thor/runner.rb +322 -0
- data/lib/carat/vendor/thor/lib/thor/shell.rb +81 -0
- data/lib/carat/vendor/thor/lib/thor/shell/basic.rb +421 -0
- data/lib/carat/vendor/thor/lib/thor/shell/color.rb +149 -0
- data/lib/carat/vendor/thor/lib/thor/shell/html.rb +126 -0
- data/lib/carat/vendor/thor/lib/thor/util.rb +267 -0
- data/lib/carat/vendor/thor/lib/thor/version.rb +3 -0
- data/lib/carat/vendored_fileutils.rb +9 -0
- data/lib/carat/vendored_molinillo.rb +2 -0
- data/lib/carat/vendored_persistent.rb +11 -0
- data/lib/carat/vendored_thor.rb +3 -0
- data/lib/carat/version.rb +6 -0
- data/lib/carat/vlad.rb +11 -0
- data/lib/carat/worker.rb +73 -0
- data/man/carat-config.ronn +178 -0
- data/man/carat-exec.ronn +136 -0
- data/man/carat-install.ronn +383 -0
- data/man/carat-package.ronn +66 -0
- data/man/carat-platform.ronn +42 -0
- data/man/carat-update.ronn +188 -0
- data/man/carat.ronn +98 -0
- data/man/gemfile.5.ronn +473 -0
- data/man/index.txt +7 -0
- metadata +321 -0
data/lib/carat/retry.rb
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
# General purpose class for retrying code that may fail
|
|
3
|
+
class Retry
|
|
4
|
+
DEFAULT_ATTEMPTS = 2
|
|
5
|
+
attr_accessor :name, :total_runs, :current_run
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
attr_accessor :attempts
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(name, exceptions = nil, attempts = nil)
|
|
12
|
+
@name = name
|
|
13
|
+
attempts ||= default_attempts
|
|
14
|
+
@exceptions = Array(exceptions) || []
|
|
15
|
+
@total_runs = attempts.next # will run once, then upto attempts.times
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def default_attempts
|
|
19
|
+
return Integer(self.class.attempts) if self.class.attempts
|
|
20
|
+
DEFAULT_ATTEMPTS
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def attempt(&block)
|
|
24
|
+
@current_run = 0
|
|
25
|
+
@failed = false
|
|
26
|
+
@error = nil
|
|
27
|
+
while keep_trying? do
|
|
28
|
+
run(&block)
|
|
29
|
+
end
|
|
30
|
+
@result
|
|
31
|
+
end
|
|
32
|
+
alias :attempts :attempt
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
def run(&block)
|
|
36
|
+
@failed = false
|
|
37
|
+
@current_run += 1
|
|
38
|
+
@result = block.call
|
|
39
|
+
rescue => e
|
|
40
|
+
fail(e)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def fail(e)
|
|
44
|
+
@failed = true
|
|
45
|
+
raise e if last_attempt? || @exceptions.any?{ |k| e.is_a?(k) }
|
|
46
|
+
return true unless name
|
|
47
|
+
Carat.ui.warn "Retrying#{" #{name}" if name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def keep_trying?
|
|
51
|
+
return true if current_run.zero?
|
|
52
|
+
return false if last_attempt?
|
|
53
|
+
return true if @failed
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def last_attempt?
|
|
57
|
+
current_run >= total_runs
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
module RubyDsl
|
|
3
|
+
def ruby(ruby_version, options = {})
|
|
4
|
+
raise GemfileError, "Please define :engine_version" if options[:engine] && options[:engine_version].nil?
|
|
5
|
+
raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil?
|
|
6
|
+
|
|
7
|
+
raise GemfileError, "ruby_version must match the :engine_version for MRI" if options[:engine] == "ruby" && options[:engine_version] && ruby_version != options[:engine_version]
|
|
8
|
+
@ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version])
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
class RubyVersion
|
|
3
|
+
attr_reader :version, :patchlevel, :engine, :engine_version
|
|
4
|
+
|
|
5
|
+
def initialize(version, patchlevel, engine, engine_version)
|
|
6
|
+
# The parameters to this method must satisfy the
|
|
7
|
+
# following constraints, which are verified in
|
|
8
|
+
# the DSL:
|
|
9
|
+
#
|
|
10
|
+
# * If an engine is specified, an engine version
|
|
11
|
+
# must also be specified
|
|
12
|
+
# * If an engine version is specified, an engine
|
|
13
|
+
# must also be specified
|
|
14
|
+
# * If the engine is "ruby", the engine version
|
|
15
|
+
# must not be specified, or the engine version
|
|
16
|
+
# specified must match the version.
|
|
17
|
+
|
|
18
|
+
@version = version
|
|
19
|
+
@engine = engine || "ruby"
|
|
20
|
+
# keep track of the engine specified by the user
|
|
21
|
+
@input_engine = engine
|
|
22
|
+
@engine_version = engine_version || version
|
|
23
|
+
@patchlevel = patchlevel
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_s
|
|
27
|
+
output = "ruby #{version}"
|
|
28
|
+
output << "p#{patchlevel}" if patchlevel
|
|
29
|
+
output << " (#{engine} #{engine_version})" unless engine == "ruby"
|
|
30
|
+
|
|
31
|
+
output
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def ==(other)
|
|
35
|
+
version == other.version &&
|
|
36
|
+
engine == other.engine &&
|
|
37
|
+
engine_version == other.engine_version &&
|
|
38
|
+
patchlevel == other.patchlevel
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Returns a tuple of these things:
|
|
42
|
+
# [diff, this, other]
|
|
43
|
+
# The priority of attributes are
|
|
44
|
+
# 1. engine
|
|
45
|
+
# 2. ruby_version
|
|
46
|
+
# 3. engine_version
|
|
47
|
+
def diff(other)
|
|
48
|
+
if engine != other.engine && @input_engine
|
|
49
|
+
[ :engine, engine, other.engine ]
|
|
50
|
+
elsif version != other.version
|
|
51
|
+
[ :version, version, other.version ]
|
|
52
|
+
elsif engine_version != other.engine_version && @input_engine
|
|
53
|
+
[ :engine_version, engine_version, other.engine_version ]
|
|
54
|
+
elsif patchlevel != other.patchlevel && @patchlevel
|
|
55
|
+
[ :patchlevel, patchlevel, other.patchlevel ]
|
|
56
|
+
else
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def host
|
|
62
|
+
@host ||= [
|
|
63
|
+
RbConfig::CONFIG["host_cpu"],
|
|
64
|
+
RbConfig::CONFIG["host_vendor"],
|
|
65
|
+
RbConfig::CONFIG["host_os"]
|
|
66
|
+
].join("-")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# A subclass of RubyVersion that implements version,
|
|
71
|
+
# engine and engine_version based upon the current
|
|
72
|
+
# information in the system. It can be used anywhere
|
|
73
|
+
# a RubyVersion object is expected, and can be
|
|
74
|
+
# compared with a RubyVersion object.
|
|
75
|
+
class SystemRubyVersion < RubyVersion
|
|
76
|
+
def initialize(*)
|
|
77
|
+
# override the default initialize, because
|
|
78
|
+
# we will implement version, engine and
|
|
79
|
+
# engine_version dynamically
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def version
|
|
83
|
+
RUBY_VERSION.dup
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def gem_version
|
|
87
|
+
@gem_version ||= Gem::Version.new(version)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def engine
|
|
91
|
+
if defined?(RUBY_ENGINE)
|
|
92
|
+
RUBY_ENGINE.dup
|
|
93
|
+
else
|
|
94
|
+
# not defined in ruby 1.8.7
|
|
95
|
+
"ruby"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def engine_version
|
|
100
|
+
case engine
|
|
101
|
+
when "ruby"
|
|
102
|
+
RUBY_VERSION.dup
|
|
103
|
+
when "rbx"
|
|
104
|
+
Rubinius::VERSION.dup
|
|
105
|
+
when "jruby"
|
|
106
|
+
JRUBY_VERSION.dup
|
|
107
|
+
else
|
|
108
|
+
raise CaratError, "RUBY_ENGINE value #{RUBY_ENGINE} is not recognized"
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def patchlevel
|
|
114
|
+
RUBY_PATCHLEVEL.to_s
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
if defined?(Gem::QuickLoader)
|
|
4
|
+
# Gem Prelude makes me a sad panda :'(
|
|
5
|
+
Gem::QuickLoader.load_full_rubygems_library
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'rubygems'
|
|
9
|
+
require 'rubygems/specification'
|
|
10
|
+
require 'carat/match_platform'
|
|
11
|
+
|
|
12
|
+
module Gem
|
|
13
|
+
@loaded_stacks = Hash.new { |h,k| h[k] = [] }
|
|
14
|
+
|
|
15
|
+
class Specification
|
|
16
|
+
attr_accessor :source_uri, :location, :relative_loaded_from
|
|
17
|
+
|
|
18
|
+
remove_method :source if instance_methods(false).include?(:source)
|
|
19
|
+
attr_accessor :source
|
|
20
|
+
|
|
21
|
+
alias_method :rg_full_gem_path, :full_gem_path
|
|
22
|
+
alias_method :rg_loaded_from, :loaded_from
|
|
23
|
+
|
|
24
|
+
def full_gem_path
|
|
25
|
+
source.respond_to?(:path) ?
|
|
26
|
+
Pathname.new(loaded_from).dirname.expand_path(Carat.root).to_s.untaint :
|
|
27
|
+
rg_full_gem_path
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def loaded_from
|
|
31
|
+
relative_loaded_from ?
|
|
32
|
+
source.path.join(relative_loaded_from).to_s :
|
|
33
|
+
rg_loaded_from
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def load_paths
|
|
37
|
+
return full_require_paths if respond_to?(:full_require_paths)
|
|
38
|
+
|
|
39
|
+
require_paths.map do |require_path|
|
|
40
|
+
if require_path.include?(full_gem_path)
|
|
41
|
+
require_path
|
|
42
|
+
else
|
|
43
|
+
File.join(full_gem_path, require_path)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if method_defined?(:extension_dir)
|
|
49
|
+
alias_method :rg_extension_dir, :extension_dir
|
|
50
|
+
def extension_dir
|
|
51
|
+
@extension_dir ||= source.respond_to?(:extension_dir_name) ?
|
|
52
|
+
File.expand_path(File.join(extensions_dir, source.extension_dir_name)) :
|
|
53
|
+
rg_extension_dir
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# RubyGems 1.8+ used only.
|
|
58
|
+
methods = instance_methods(false)
|
|
59
|
+
gem_dir = methods.first.is_a?(String) ? "gem_dir" : :gem_dir
|
|
60
|
+
remove_method :gem_dir if methods.include?(gem_dir)
|
|
61
|
+
def gem_dir
|
|
62
|
+
full_gem_path
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def groups
|
|
66
|
+
@groups ||= []
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def git_version
|
|
70
|
+
return unless loaded_from && source.is_a?(Carat::Source::Git)
|
|
71
|
+
" #{source.revision[0..6]}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def to_gemfile(path = nil)
|
|
75
|
+
gemfile = "source 'https://rubygems.org'\n"
|
|
76
|
+
gemfile << dependencies_to_gemfile(nondevelopment_dependencies)
|
|
77
|
+
unless development_dependencies.empty?
|
|
78
|
+
gemfile << "\n"
|
|
79
|
+
gemfile << dependencies_to_gemfile(development_dependencies, :development)
|
|
80
|
+
end
|
|
81
|
+
gemfile
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def nondevelopment_dependencies
|
|
85
|
+
dependencies - development_dependencies
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def dependencies_to_gemfile(dependencies, group = nil)
|
|
91
|
+
gemfile = ''
|
|
92
|
+
if dependencies.any?
|
|
93
|
+
gemfile << "group :#{group} do\n" if group
|
|
94
|
+
dependencies.each do |dependency|
|
|
95
|
+
gemfile << ' ' if group
|
|
96
|
+
gemfile << %|gem "#{dependency.name}"|
|
|
97
|
+
req = dependency.requirements_list.first
|
|
98
|
+
gemfile << %|, "#{req}"| if req
|
|
99
|
+
gemfile << "\n"
|
|
100
|
+
end
|
|
101
|
+
gemfile << "end\n" if group
|
|
102
|
+
end
|
|
103
|
+
gemfile
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class Dependency
|
|
109
|
+
attr_accessor :source, :groups
|
|
110
|
+
|
|
111
|
+
alias eql? ==
|
|
112
|
+
|
|
113
|
+
def encode_with(coder)
|
|
114
|
+
to_yaml_properties.each do |ivar|
|
|
115
|
+
coder[ivar.to_s.sub(/^@/, '')] = instance_variable_get(ivar)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def to_yaml_properties
|
|
120
|
+
instance_variables.reject { |p| ["@source", "@groups"].include?(p.to_s) }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def to_lock
|
|
124
|
+
out = " #{name}"
|
|
125
|
+
unless requirement == Gem::Requirement.default
|
|
126
|
+
reqs = requirement.requirements.map{|o,v| "#{o} #{v}" }.sort.reverse
|
|
127
|
+
out << " (#{reqs.join(', ')})"
|
|
128
|
+
end
|
|
129
|
+
out
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Backport of performance enhancement added to Rubygems 1.4
|
|
133
|
+
def matches_spec?(spec)
|
|
134
|
+
# name can be a Regexp, so use ===
|
|
135
|
+
return false unless name === spec.name
|
|
136
|
+
return true if requirement.none?
|
|
137
|
+
|
|
138
|
+
requirement.satisfied_by?(spec.version)
|
|
139
|
+
end unless allocate.respond_to?(:matches_spec?)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
class Requirement
|
|
143
|
+
# Backport of performance enhancement added to Rubygems 1.4
|
|
144
|
+
def none?
|
|
145
|
+
@none ||= (to_s == ">= 0")
|
|
146
|
+
end unless allocate.respond_to?(:none?)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
class Platform
|
|
150
|
+
JAVA = Gem::Platform.new('java') unless defined?(JAVA)
|
|
151
|
+
MSWIN = Gem::Platform.new('mswin32') unless defined?(MSWIN)
|
|
152
|
+
MSWIN64 = Gem::Platform.new('mswin64') unless defined?(MSWIN64)
|
|
153
|
+
MINGW = Gem::Platform.new('x86-mingw32') unless defined?(MINGW)
|
|
154
|
+
X64_MINGW = Gem::Platform.new('x64-mingw32') unless defined?(X64_MINGW)
|
|
155
|
+
|
|
156
|
+
undef_method :hash if method_defined? :hash
|
|
157
|
+
def hash
|
|
158
|
+
@cpu.hash ^ @os.hash ^ @version.hash
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
undef_method :eql? if method_defined? :eql?
|
|
162
|
+
alias eql? ==
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
module Gem
|
|
167
|
+
class Specification
|
|
168
|
+
include ::Carat::MatchPlatform
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
require 'monitor'
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
require 'rubygems/config_file'
|
|
4
|
+
|
|
5
|
+
module Carat
|
|
6
|
+
class RubygemsIntegration
|
|
7
|
+
|
|
8
|
+
def self.version
|
|
9
|
+
@version ||= Gem::Version.new(Gem::VERSION)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.provides?(req_str)
|
|
13
|
+
Gem::Requirement.new(req_str).satisfied_by?(version)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def version
|
|
17
|
+
self.class.version
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def provides?(req_str)
|
|
21
|
+
self.class.provides?(req_str)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def build_args
|
|
25
|
+
Gem::Command.build_args
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def build_args=(args)
|
|
29
|
+
Gem::Command.build_args = args
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def loaded_specs(name)
|
|
33
|
+
Gem.loaded_specs[name]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def mark_loaded(spec)
|
|
37
|
+
Gem.loaded_specs[spec.name] = spec
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def path(obj)
|
|
41
|
+
obj.to_s
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def platforms
|
|
45
|
+
Gem.platforms
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def configuration
|
|
49
|
+
Gem.configuration
|
|
50
|
+
rescue Gem::SystemExitException => e
|
|
51
|
+
Carat.ui.error "#{e.class}: #{e.message}"
|
|
52
|
+
Carat.ui.trace e
|
|
53
|
+
raise Gem::SystemExitException
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def ruby_engine
|
|
57
|
+
Gem.ruby_engine
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def read_binary(path)
|
|
61
|
+
Gem.read_binary(path)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def inflate(obj)
|
|
65
|
+
Gem.inflate(obj)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def sources=(val)
|
|
69
|
+
# Gem.configuration creates a new Gem::ConfigFile, which by default will read ~/.gemrc
|
|
70
|
+
# If that file exists, its settings (including sources) will overwrite the values we
|
|
71
|
+
# are about to set here. In order to avoid that, we force memoizing the config file now.
|
|
72
|
+
configuration
|
|
73
|
+
|
|
74
|
+
Gem.sources = val
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def sources
|
|
78
|
+
Gem.sources
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def gem_dir
|
|
82
|
+
Gem.dir
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def gem_bindir
|
|
86
|
+
Gem.bindir
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def user_home
|
|
90
|
+
Gem.user_home
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def gem_path
|
|
94
|
+
Gem.path
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def gem_cache
|
|
98
|
+
gem_path.map{|p| File.expand_path("cache", p) }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def spec_cache_dirs
|
|
102
|
+
@spec_cache_dirs ||= begin
|
|
103
|
+
dirs = gem_path.map {|dir| File.join(dir, 'specifications')}
|
|
104
|
+
dirs << Gem.spec_cache_dir if Gem.respond_to?(:spec_cache_dir) # Not in Rubygems 2.0.3 or earlier
|
|
105
|
+
dirs.uniq.select {|dir| File.directory? dir}
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def marshal_spec_dir
|
|
110
|
+
Gem::MARSHAL_SPEC_DIR
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def config_map
|
|
114
|
+
Gem::ConfigMap
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def repository_subdirectories
|
|
118
|
+
%w[cache doc gems specifications]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def clear_paths
|
|
122
|
+
Gem.clear_paths
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def bin_path(gem, bin, ver)
|
|
126
|
+
Gem.bin_path(gem, bin, ver)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def preserve_paths
|
|
130
|
+
# this is a no-op outside of Rubygems 1.8
|
|
131
|
+
yield
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def ui=(obj)
|
|
135
|
+
Gem::DefaultUserInteraction.ui = obj
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def ext_lock
|
|
139
|
+
@ext_lock ||= Monitor.new
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def fetch_specs(all, pre, &blk)
|
|
143
|
+
specs = Gem::SpecFetcher.new.list(all, pre)
|
|
144
|
+
specs.each { yield } if block_given?
|
|
145
|
+
specs
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def fetch_prerelease_specs
|
|
149
|
+
fetch_specs(false, true)
|
|
150
|
+
rescue Gem::RemoteFetcher::FetchError
|
|
151
|
+
[] # if we can't download them, there aren't any
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def fetch_all_remote_specs
|
|
155
|
+
# Fetch all specs, minus prerelease specs
|
|
156
|
+
spec_list = fetch_specs(true, false)
|
|
157
|
+
# Then fetch the prerelease specs
|
|
158
|
+
fetch_prerelease_specs.each {|k, v| spec_list[k] += v }
|
|
159
|
+
|
|
160
|
+
return spec_list
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def with_build_args(args)
|
|
164
|
+
ext_lock.synchronize do
|
|
165
|
+
old_args = self.build_args
|
|
166
|
+
begin
|
|
167
|
+
self.build_args = args
|
|
168
|
+
yield
|
|
169
|
+
ensure
|
|
170
|
+
self.build_args = old_args
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def gem_from_path(path, policy = nil)
|
|
176
|
+
require 'rubygems/format'
|
|
177
|
+
Gem::Format.from_file_by_path(path, policy)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def spec_from_gem(path, policy = nil)
|
|
181
|
+
require 'rubygems/security'
|
|
182
|
+
gem_from_path(path, security_policies[policy]).spec
|
|
183
|
+
rescue Gem::Package::FormatError
|
|
184
|
+
raise GemspecError, "Could not read gem at #{path}. It may be corrupted."
|
|
185
|
+
rescue Exception, Gem::Exception, Gem::Security::Exception => e
|
|
186
|
+
if e.is_a?(Gem::Security::Exception) ||
|
|
187
|
+
e.message =~ /unknown trust policy|unsigned gem/i ||
|
|
188
|
+
e.message =~ /couldn't verify (meta)?data signature/i
|
|
189
|
+
raise SecurityError,
|
|
190
|
+
"The gem #{File.basename(path, '.gem')} can't be installed because " \
|
|
191
|
+
"the security policy didn't allow it, with the message: #{e.message}"
|
|
192
|
+
else
|
|
193
|
+
raise e
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def build(spec, skip_validation = false)
|
|
198
|
+
require 'rubygems/builder'
|
|
199
|
+
Gem::Builder.new(spec).build
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def build_gem(gem_dir, spec)
|
|
203
|
+
build(spec)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def download_gem(spec, uri, path)
|
|
207
|
+
uri = Carat::Source.mirror_for(uri)
|
|
208
|
+
fetcher = Gem::RemoteFetcher.new(configuration[:http_proxy])
|
|
209
|
+
fetcher.download(spec, uri, path)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def security_policy_keys
|
|
213
|
+
%w{High Medium Low AlmostNo No}.map { |level| "#{level}Security" }
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def security_policies
|
|
217
|
+
@security_policies ||= begin
|
|
218
|
+
require 'rubygems/security'
|
|
219
|
+
Gem::Security::Policies
|
|
220
|
+
rescue LoadError, NameError
|
|
221
|
+
{}
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def reverse_rubygems_kernel_mixin
|
|
226
|
+
# Disable rubygems' gem activation system
|
|
227
|
+
::Kernel.class_eval do
|
|
228
|
+
if private_method_defined?(:gem_original_require)
|
|
229
|
+
alias rubygems_require require
|
|
230
|
+
alias require gem_original_require
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
undef gem
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def replace_gem(specs)
|
|
238
|
+
reverse_rubygems_kernel_mixin
|
|
239
|
+
|
|
240
|
+
executables = specs.map { |s| s.executables }.flatten
|
|
241
|
+
|
|
242
|
+
::Kernel.send(:define_method, :gem) do |dep, *reqs|
|
|
243
|
+
if executables.include? File.basename(caller.first.split(':').first)
|
|
244
|
+
return
|
|
245
|
+
end
|
|
246
|
+
reqs.pop if reqs.last.is_a?(Hash)
|
|
247
|
+
|
|
248
|
+
unless dep.respond_to?(:name) && dep.respond_to?(:requirement)
|
|
249
|
+
dep = Gem::Dependency.new(dep, reqs)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
spec = specs.find { |s| s.name == dep.name }
|
|
253
|
+
|
|
254
|
+
if spec.nil?
|
|
255
|
+
|
|
256
|
+
e = Gem::LoadError.new "#{dep.name} is not part of the bundle. Add it to Gemfile."
|
|
257
|
+
e.name = dep.name
|
|
258
|
+
if e.respond_to?(:requirement=)
|
|
259
|
+
e.requirement = dep.requirement
|
|
260
|
+
else
|
|
261
|
+
e.version_requirement = dep.requirement
|
|
262
|
+
end
|
|
263
|
+
raise e
|
|
264
|
+
elsif dep !~ spec
|
|
265
|
+
e = Gem::LoadError.new "can't activate #{dep}, already activated #{spec.full_name}. " \
|
|
266
|
+
"Make sure all dependencies are added to Gemfile."
|
|
267
|
+
e.name = dep.name
|
|
268
|
+
if e.respond_to?(:requirement=)
|
|
269
|
+
e.requirement = dep.requirement
|
|
270
|
+
else
|
|
271
|
+
e.version_requirement = dep.requirement
|
|
272
|
+
end
|
|
273
|
+
raise e
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
true
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def stub_source_index(specs)
|
|
281
|
+
Gem::SourceIndex.send(:alias_method, :old_initialize, :initialize)
|
|
282
|
+
redefine_method(Gem::SourceIndex, :initialize) do |*args|
|
|
283
|
+
@gems = {}
|
|
284
|
+
# You're looking at this thinking: Oh! This is how I make those
|
|
285
|
+
# rubygems deprecations go away!
|
|
286
|
+
#
|
|
287
|
+
# You'd be correct BUT using of this method in production code
|
|
288
|
+
# must be approved by the rubygems team itself!
|
|
289
|
+
#
|
|
290
|
+
# This is your warning. If you use this and don't have approval
|
|
291
|
+
# we can't protect you.
|
|
292
|
+
#
|
|
293
|
+
Deprecate.skip_during do
|
|
294
|
+
self.spec_dirs = *args
|
|
295
|
+
add_specs(*specs)
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Used to make bin stubs that are not created by carat work
|
|
301
|
+
# under carat. The new Gem.bin_path only considers gems in
|
|
302
|
+
# +specs+
|
|
303
|
+
def replace_bin_path(specs)
|
|
304
|
+
gem_class = (class << Gem ; self ; end)
|
|
305
|
+
redefine_method(gem_class, :bin_path) do |name, *args|
|
|
306
|
+
exec_name = args.first
|
|
307
|
+
|
|
308
|
+
if exec_name == 'carat'
|
|
309
|
+
return ENV['BUNDLE_BIN_PATH']
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
spec = nil
|
|
313
|
+
|
|
314
|
+
if exec_name
|
|
315
|
+
spec = specs.find { |s| s.executables.include?(exec_name) }
|
|
316
|
+
spec or raise Gem::Exception, "can't find executable #{exec_name}"
|
|
317
|
+
unless spec.name == name
|
|
318
|
+
warn "Carat is using a binstub that was created for a different gem.\n" \
|
|
319
|
+
"This is deprecated, in future versions you may need to `carat binstub #{name}` " \
|
|
320
|
+
"to work around a system/carat conflict."
|
|
321
|
+
end
|
|
322
|
+
else
|
|
323
|
+
spec = specs.find { |s| s.name == name }
|
|
324
|
+
exec_name = spec.default_executable or raise Gem::Exception, "no default executable for #{spec.full_name}"
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name)
|
|
328
|
+
gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name)
|
|
329
|
+
File.exist?(gem_bin) ? gem_bin : gem_from_path_bin
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Because Carat has a static view of what specs are available,
|
|
334
|
+
# we don't #refresh, so stub it out.
|
|
335
|
+
def replace_refresh
|
|
336
|
+
gem_class = (class << Gem ; self ; end)
|
|
337
|
+
redefine_method(gem_class, :refresh) { }
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Replace or hook into Rubygems to provide a caratized view
|
|
341
|
+
# of the world.
|
|
342
|
+
def replace_entrypoints(specs)
|
|
343
|
+
replace_gem(specs)
|
|
344
|
+
|
|
345
|
+
stub_rubygems(specs)
|
|
346
|
+
|
|
347
|
+
replace_bin_path(specs)
|
|
348
|
+
replace_refresh
|
|
349
|
+
|
|
350
|
+
Gem.clear_paths
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# This backports the correct segment generation code from Rubygems 1.4+
|
|
354
|
+
# by monkeypatching it into the method in Rubygems 1.3.6 and 1.3.7.
|
|
355
|
+
def backport_segment_generation
|
|
356
|
+
redefine_method(Gem::Version, :segments) do
|
|
357
|
+
@segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
|
|
358
|
+
/^\d+$/ =~ s ? s.to_i : s
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# This backport fixes the marshaling of @segments.
|
|
364
|
+
def backport_yaml_initialize
|
|
365
|
+
redefine_method(Gem::Version, :yaml_initialize) do |tag, map|
|
|
366
|
+
@version = map['version']
|
|
367
|
+
@segments = nil
|
|
368
|
+
@hash = nil
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# This backports base_dir which replaces installation path
|
|
373
|
+
# Rubygems 1.8+
|
|
374
|
+
def backport_base_dir
|
|
375
|
+
redefine_method(Gem::Specification, :base_dir) do
|
|
376
|
+
return Gem.dir unless loaded_from
|
|
377
|
+
File.dirname File.dirname loaded_from
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def backport_cache_file
|
|
382
|
+
redefine_method(Gem::Specification, :cache_dir) do
|
|
383
|
+
@cache_dir ||= File.join base_dir, "cache"
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
redefine_method(Gem::Specification, :cache_file) do
|
|
387
|
+
@cache_file ||= File.join cache_dir, "#{full_name}.gem"
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def backport_spec_file
|
|
392
|
+
redefine_method(Gem::Specification, :spec_dir) do
|
|
393
|
+
@spec_dir ||= File.join base_dir, "specifications"
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
redefine_method(Gem::Specification, :spec_file) do
|
|
397
|
+
@spec_file ||= File.join spec_dir, "#{full_name}.gemspec"
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def redefine_method(klass, method, &block)
|
|
402
|
+
if klass.instance_methods(false).include?(method)
|
|
403
|
+
klass.send(:remove_method, method)
|
|
404
|
+
end
|
|
405
|
+
klass.send(:define_method, method, &block)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# Rubygems 1.4 through 1.6
|
|
409
|
+
class Legacy < RubygemsIntegration
|
|
410
|
+
def initialize
|
|
411
|
+
super
|
|
412
|
+
backport_base_dir
|
|
413
|
+
backport_cache_file
|
|
414
|
+
backport_spec_file
|
|
415
|
+
backport_yaml_initialize
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def stub_rubygems(specs)
|
|
419
|
+
# Rubygems versions lower than 1.7 use SourceIndex#from_gems_in
|
|
420
|
+
source_index_class = (class << Gem::SourceIndex ; self ; end)
|
|
421
|
+
source_index_class.send(:define_method, :from_gems_in) do |*args|
|
|
422
|
+
source_index = Gem::SourceIndex.new
|
|
423
|
+
source_index.spec_dirs = *args
|
|
424
|
+
source_index.add_specs(*specs)
|
|
425
|
+
source_index
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def all_specs
|
|
430
|
+
Gem.source_index.gems.values
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def find_name(name)
|
|
434
|
+
Gem.source_index.find_name(name)
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
# Rubygems versions 1.3.6 and 1.3.7
|
|
439
|
+
class Ancient < Legacy
|
|
440
|
+
def initialize
|
|
441
|
+
super
|
|
442
|
+
backport_segment_generation
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
# Rubygems 1.7
|
|
447
|
+
class Transitional < Legacy
|
|
448
|
+
def stub_rubygems(specs)
|
|
449
|
+
stub_source_index(specs)
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Rubygems 1.8.5-1.8.19
|
|
454
|
+
class Modern < RubygemsIntegration
|
|
455
|
+
def stub_rubygems(specs)
|
|
456
|
+
Gem::Specification.all = specs
|
|
457
|
+
|
|
458
|
+
Gem.post_reset {
|
|
459
|
+
Gem::Specification.all = specs
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
stub_source_index(specs)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
def all_specs
|
|
466
|
+
Gem::Specification.to_a
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def find_name(name)
|
|
470
|
+
Gem::Specification.find_all_by_name name
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
# Rubygems 1.8.0 to 1.8.4
|
|
475
|
+
class AlmostModern < Modern
|
|
476
|
+
# Rubygems [>= 1.8.0, < 1.8.5] has a bug that changes Gem.dir whenever
|
|
477
|
+
# you call Gem::Installer#install with an :install_dir set. We have to
|
|
478
|
+
# change it back for our sudo mode to work.
|
|
479
|
+
def preserve_paths
|
|
480
|
+
old_dir, old_path = gem_dir, gem_path
|
|
481
|
+
yield
|
|
482
|
+
Gem.use_paths(old_dir, old_path)
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
# Rubygems 1.8.20+
|
|
487
|
+
class MoreModern < Modern
|
|
488
|
+
# Rubygems 1.8.20 and adds the skip_validation parameter, so that's
|
|
489
|
+
# when we start passing it through.
|
|
490
|
+
def build(spec, skip_validation = false)
|
|
491
|
+
require 'rubygems/builder'
|
|
492
|
+
Gem::Builder.new(spec).build(skip_validation)
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
# Rubygems 2.0
|
|
497
|
+
class Future < RubygemsIntegration
|
|
498
|
+
def stub_rubygems(specs)
|
|
499
|
+
Gem::Specification.all = specs
|
|
500
|
+
|
|
501
|
+
Gem.post_reset do
|
|
502
|
+
Gem::Specification.all = specs
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def all_specs
|
|
507
|
+
Gem::Specification.to_a
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
def find_name(name)
|
|
511
|
+
Gem::Specification.find_all_by_name name
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
def fetch_specs(source, name)
|
|
515
|
+
path = source + "#{name}.#{Gem.marshal_version}.gz"
|
|
516
|
+
string = Gem::RemoteFetcher.fetcher.fetch_path(path)
|
|
517
|
+
Carat.load_marshal(string)
|
|
518
|
+
rescue Gem::RemoteFetcher::FetchError => e
|
|
519
|
+
# it's okay for prerelease to fail
|
|
520
|
+
raise e unless name == "prerelease_specs"
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def fetch_all_remote_specs
|
|
524
|
+
# Since SpecFetcher now returns NameTuples, we just fetch directly
|
|
525
|
+
# and unmarshal the array ourselves.
|
|
526
|
+
hash = {}
|
|
527
|
+
|
|
528
|
+
Gem.sources.each do |source|
|
|
529
|
+
source = URI.parse(source.to_s) unless source.is_a?(URI)
|
|
530
|
+
hash[source] = fetch_specs(source, "specs")
|
|
531
|
+
|
|
532
|
+
pres = fetch_specs(source, "prerelease_specs")
|
|
533
|
+
hash[source].push(*pres) if pres && !pres.empty?
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
hash
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
def download_gem(spec, uri, path)
|
|
540
|
+
require 'resolv'
|
|
541
|
+
uri = Carat::Source.mirror_for(uri)
|
|
542
|
+
proxy, dns = configuration[:http_proxy], Resolv::DNS.new
|
|
543
|
+
fetcher = Gem::RemoteFetcher.new(proxy, dns)
|
|
544
|
+
fetcher.download(spec, uri, path)
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
def gem_from_path(path, policy = nil)
|
|
548
|
+
require 'rubygems/package'
|
|
549
|
+
p = Gem::Package.new(path)
|
|
550
|
+
p.security_policy = policy if policy
|
|
551
|
+
return p
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
def build(spec, skip_validation = false)
|
|
555
|
+
require 'rubygems/package'
|
|
556
|
+
Gem::Package.build(spec, skip_validation)
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def repository_subdirectories
|
|
560
|
+
Gem::REPOSITORY_SUBDIRECTORIES
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
class MoreFuture < Future
|
|
565
|
+
def initialize
|
|
566
|
+
super
|
|
567
|
+
backport_ext_builder_monitor
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def backport_ext_builder_monitor
|
|
571
|
+
require 'rubygems/ext'
|
|
572
|
+
|
|
573
|
+
Gem::Ext::Builder.class_eval do
|
|
574
|
+
if !const_defined?(:CHDIR_MONITOR)
|
|
575
|
+
const_set(:CHDIR_MONITOR, Monitor.new)
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
if const_defined?(:CHDIR_MUTEX)
|
|
579
|
+
remove_const(:CHDIR_MUTEX)
|
|
580
|
+
const_set(:CHDIR_MUTEX, const_get(:CHDIR_MONITOR))
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
def ext_lock
|
|
586
|
+
Gem::Ext::Builder::CHDIR_MONITOR
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
def find_name(name)
|
|
590
|
+
Gem::Specification.stubs.find_all do |spec|
|
|
591
|
+
spec.name == name
|
|
592
|
+
end.map(&:to_spec)
|
|
593
|
+
end
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
if RubygemsIntegration.provides?(">= 2.1.0")
|
|
599
|
+
@rubygems = RubygemsIntegration::MoreFuture.new
|
|
600
|
+
elsif RubygemsIntegration.provides?(">= 1.99.99")
|
|
601
|
+
@rubygems = RubygemsIntegration::Future.new
|
|
602
|
+
elsif RubygemsIntegration.provides?('>= 1.8.20')
|
|
603
|
+
@rubygems = RubygemsIntegration::MoreModern.new
|
|
604
|
+
elsif RubygemsIntegration.provides?('>= 1.8.5')
|
|
605
|
+
@rubygems = RubygemsIntegration::Modern.new
|
|
606
|
+
elsif RubygemsIntegration.provides?('>= 1.8.0')
|
|
607
|
+
@rubygems = RubygemsIntegration::AlmostModern.new
|
|
608
|
+
elsif RubygemsIntegration.provides?('>= 1.7.0')
|
|
609
|
+
@rubygems = RubygemsIntegration::Transitional.new
|
|
610
|
+
elsif RubygemsIntegration.provides?('>= 1.4.0')
|
|
611
|
+
@rubygems = RubygemsIntegration::Legacy.new
|
|
612
|
+
else # Rubygems 1.3.6 and 1.3.7
|
|
613
|
+
@rubygems = RubygemsIntegration::Ancient.new
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
class << self
|
|
617
|
+
attr_reader :rubygems
|
|
618
|
+
end
|
|
619
|
+
end
|