carat 1.9.9.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +24 -0
  5. data/CHANGELOG.md +2006 -0
  6. data/CODE_OF_CONDUCT.md +40 -0
  7. data/CONTRIBUTING.md +23 -0
  8. data/DEVELOPMENT.md +119 -0
  9. data/ISSUES.md +96 -0
  10. data/LICENSE.md +23 -0
  11. data/README.md +32 -0
  12. data/Rakefile +308 -0
  13. data/bin/carat +21 -0
  14. data/bin/carat_ruby +56 -0
  15. data/carat.gemspec +32 -0
  16. data/lib/carat.rb +446 -0
  17. data/lib/carat/anonymizable_uri.rb +32 -0
  18. data/lib/carat/capistrano.rb +16 -0
  19. data/lib/carat/cli.rb +407 -0
  20. data/lib/carat/cli/binstubs.rb +38 -0
  21. data/lib/carat/cli/cache.rb +35 -0
  22. data/lib/carat/cli/check.rb +35 -0
  23. data/lib/carat/cli/clean.rb +26 -0
  24. data/lib/carat/cli/common.rb +56 -0
  25. data/lib/carat/cli/config.rb +84 -0
  26. data/lib/carat/cli/console.rb +38 -0
  27. data/lib/carat/cli/exec.rb +44 -0
  28. data/lib/carat/cli/gem.rb +195 -0
  29. data/lib/carat/cli/init.rb +33 -0
  30. data/lib/carat/cli/inject.rb +33 -0
  31. data/lib/carat/cli/install.rb +156 -0
  32. data/lib/carat/cli/open.rb +23 -0
  33. data/lib/carat/cli/outdated.rb +80 -0
  34. data/lib/carat/cli/package.rb +45 -0
  35. data/lib/carat/cli/platform.rb +43 -0
  36. data/lib/carat/cli/show.rb +74 -0
  37. data/lib/carat/cli/update.rb +73 -0
  38. data/lib/carat/cli/viz.rb +27 -0
  39. data/lib/carat/constants.rb +5 -0
  40. data/lib/carat/current_ruby.rb +183 -0
  41. data/lib/carat/definition.rb +628 -0
  42. data/lib/carat/dep_proxy.rb +43 -0
  43. data/lib/carat/dependency.rb +110 -0
  44. data/lib/carat/deployment.rb +59 -0
  45. data/lib/carat/deprecate.rb +15 -0
  46. data/lib/carat/dsl.rb +331 -0
  47. data/lib/carat/endpoint_specification.rb +76 -0
  48. data/lib/carat/env.rb +75 -0
  49. data/lib/carat/environment.rb +42 -0
  50. data/lib/carat/fetcher.rb +423 -0
  51. data/lib/carat/friendly_errors.rb +85 -0
  52. data/lib/carat/gem_helper.rb +180 -0
  53. data/lib/carat/gem_helpers.rb +26 -0
  54. data/lib/carat/gem_installer.rb +9 -0
  55. data/lib/carat/gem_path_manipulation.rb +8 -0
  56. data/lib/carat/gem_tasks.rb +2 -0
  57. data/lib/carat/graph.rb +169 -0
  58. data/lib/carat/index.rb +197 -0
  59. data/lib/carat/injector.rb +64 -0
  60. data/lib/carat/installer.rb +339 -0
  61. data/lib/carat/lazy_specification.rb +83 -0
  62. data/lib/carat/lockfile_parser.rb +167 -0
  63. data/lib/carat/match_platform.rb +13 -0
  64. data/lib/carat/psyched_yaml.rb +26 -0
  65. data/lib/carat/remote_specification.rb +57 -0
  66. data/lib/carat/resolver.rb +334 -0
  67. data/lib/carat/retry.rb +60 -0
  68. data/lib/carat/ruby_dsl.rb +11 -0
  69. data/lib/carat/ruby_version.rb +117 -0
  70. data/lib/carat/rubygems_ext.rb +170 -0
  71. data/lib/carat/rubygems_integration.rb +619 -0
  72. data/lib/carat/runtime.rb +289 -0
  73. data/lib/carat/settings.rb +208 -0
  74. data/lib/carat/setup.rb +24 -0
  75. data/lib/carat/shared_helpers.rb +149 -0
  76. data/lib/carat/similarity_detector.rb +63 -0
  77. data/lib/carat/source.rb +46 -0
  78. data/lib/carat/source/git.rb +294 -0
  79. data/lib/carat/source/git/git_proxy.rb +162 -0
  80. data/lib/carat/source/path.rb +226 -0
  81. data/lib/carat/source/path/installer.rb +43 -0
  82. data/lib/carat/source/rubygems.rb +381 -0
  83. data/lib/carat/source_list.rb +101 -0
  84. data/lib/carat/spec_set.rb +154 -0
  85. data/lib/carat/ssl_certs/.document +1 -0
  86. data/lib/carat/ssl_certs/AddTrustExternalCARoot-2048.pem +25 -0
  87. data/lib/carat/ssl_certs/AddTrustExternalCARoot.pem +32 -0
  88. data/lib/carat/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +14 -0
  89. data/lib/carat/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +23 -0
  90. data/lib/carat/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +28 -0
  91. data/lib/carat/ssl_certs/GeoTrustGlobalCA.pem +20 -0
  92. data/lib/carat/ssl_certs/certificate_manager.rb +66 -0
  93. data/lib/carat/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +21 -0
  94. data/lib/carat/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem +23 -0
  95. data/lib/carat/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem +25 -0
  96. data/lib/carat/templates/Executable +16 -0
  97. data/lib/carat/templates/Executable.standalone +12 -0
  98. data/lib/carat/templates/Gemfile +4 -0
  99. data/lib/carat/templates/newgem/.travis.yml.tt +3 -0
  100. data/lib/carat/templates/newgem/CODE_OF_CONDUCT.md.tt +13 -0
  101. data/lib/carat/templates/newgem/Gemfile.tt +4 -0
  102. data/lib/carat/templates/newgem/LICENSE.txt.tt +21 -0
  103. data/lib/carat/templates/newgem/README.md.tt +39 -0
  104. data/lib/carat/templates/newgem/Rakefile.tt +25 -0
  105. data/lib/carat/templates/newgem/bin/console.tt +14 -0
  106. data/lib/carat/templates/newgem/bin/setup.tt +7 -0
  107. data/lib/carat/templates/newgem/exe/newgem.tt +3 -0
  108. data/lib/carat/templates/newgem/ext/newgem/extconf.rb.tt +3 -0
  109. data/lib/carat/templates/newgem/ext/newgem/newgem.c.tt +9 -0
  110. data/lib/carat/templates/newgem/ext/newgem/newgem.h.tt +6 -0
  111. data/lib/carat/templates/newgem/gitignore.tt +16 -0
  112. data/lib/carat/templates/newgem/lib/newgem.rb.tt +12 -0
  113. data/lib/carat/templates/newgem/lib/newgem/version.rb.tt +7 -0
  114. data/lib/carat/templates/newgem/newgem.gemspec.tt +43 -0
  115. data/lib/carat/templates/newgem/rspec.tt +2 -0
  116. data/lib/carat/templates/newgem/spec/newgem_spec.rb.tt +11 -0
  117. data/lib/carat/templates/newgem/spec/spec_helper.rb.tt +2 -0
  118. data/lib/carat/templates/newgem/test/minitest_helper.rb.tt +4 -0
  119. data/lib/carat/templates/newgem/test/test_newgem.rb.tt +11 -0
  120. data/lib/carat/ui.rb +7 -0
  121. data/lib/carat/ui/rg_proxy.rb +21 -0
  122. data/lib/carat/ui/shell.rb +103 -0
  123. data/lib/carat/ui/silent.rb +44 -0
  124. data/lib/carat/vendor/molinillo/lib/molinillo.rb +5 -0
  125. data/lib/carat/vendor/molinillo/lib/molinillo/dependency_graph.rb +266 -0
  126. data/lib/carat/vendor/molinillo/lib/molinillo/errors.rb +69 -0
  127. data/lib/carat/vendor/molinillo/lib/molinillo/gem_metadata.rb +3 -0
  128. data/lib/carat/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +90 -0
  129. data/lib/carat/vendor/molinillo/lib/molinillo/modules/ui.rb +63 -0
  130. data/lib/carat/vendor/molinillo/lib/molinillo/resolution.rb +415 -0
  131. data/lib/carat/vendor/molinillo/lib/molinillo/resolver.rb +43 -0
  132. data/lib/carat/vendor/molinillo/lib/molinillo/state.rb +43 -0
  133. data/lib/carat/vendor/net/http/faster.rb +26 -0
  134. data/lib/carat/vendor/net/http/persistent.rb +1230 -0
  135. data/lib/carat/vendor/net/http/persistent/ssl_reuse.rb +128 -0
  136. data/lib/carat/vendor/thor/lib/thor.rb +484 -0
  137. data/lib/carat/vendor/thor/lib/thor/actions.rb +319 -0
  138. data/lib/carat/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  139. data/lib/carat/vendor/thor/lib/thor/actions/create_link.rb +59 -0
  140. data/lib/carat/vendor/thor/lib/thor/actions/directory.rb +118 -0
  141. data/lib/carat/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
  142. data/lib/carat/vendor/thor/lib/thor/actions/file_manipulation.rb +316 -0
  143. data/lib/carat/vendor/thor/lib/thor/actions/inject_into_file.rb +107 -0
  144. data/lib/carat/vendor/thor/lib/thor/base.rb +656 -0
  145. data/lib/carat/vendor/thor/lib/thor/command.rb +133 -0
  146. data/lib/carat/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +77 -0
  147. data/lib/carat/vendor/thor/lib/thor/core_ext/io_binary_read.rb +10 -0
  148. data/lib/carat/vendor/thor/lib/thor/core_ext/ordered_hash.rb +98 -0
  149. data/lib/carat/vendor/thor/lib/thor/error.rb +32 -0
  150. data/lib/carat/vendor/thor/lib/thor/group.rb +281 -0
  151. data/lib/carat/vendor/thor/lib/thor/invocation.rb +178 -0
  152. data/lib/carat/vendor/thor/lib/thor/line_editor.rb +17 -0
  153. data/lib/carat/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
  154. data/lib/carat/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  155. data/lib/carat/vendor/thor/lib/thor/parser.rb +4 -0
  156. data/lib/carat/vendor/thor/lib/thor/parser/argument.rb +73 -0
  157. data/lib/carat/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  158. data/lib/carat/vendor/thor/lib/thor/parser/option.rb +125 -0
  159. data/lib/carat/vendor/thor/lib/thor/parser/options.rb +218 -0
  160. data/lib/carat/vendor/thor/lib/thor/rake_compat.rb +71 -0
  161. data/lib/carat/vendor/thor/lib/thor/runner.rb +322 -0
  162. data/lib/carat/vendor/thor/lib/thor/shell.rb +81 -0
  163. data/lib/carat/vendor/thor/lib/thor/shell/basic.rb +421 -0
  164. data/lib/carat/vendor/thor/lib/thor/shell/color.rb +149 -0
  165. data/lib/carat/vendor/thor/lib/thor/shell/html.rb +126 -0
  166. data/lib/carat/vendor/thor/lib/thor/util.rb +267 -0
  167. data/lib/carat/vendor/thor/lib/thor/version.rb +3 -0
  168. data/lib/carat/vendored_fileutils.rb +9 -0
  169. data/lib/carat/vendored_molinillo.rb +2 -0
  170. data/lib/carat/vendored_persistent.rb +11 -0
  171. data/lib/carat/vendored_thor.rb +3 -0
  172. data/lib/carat/version.rb +6 -0
  173. data/lib/carat/vlad.rb +11 -0
  174. data/lib/carat/worker.rb +73 -0
  175. data/man/carat-config.ronn +178 -0
  176. data/man/carat-exec.ronn +136 -0
  177. data/man/carat-install.ronn +383 -0
  178. data/man/carat-package.ronn +66 -0
  179. data/man/carat-platform.ronn +42 -0
  180. data/man/carat-update.ronn +188 -0
  181. data/man/carat.ronn +98 -0
  182. data/man/gemfile.5.ronn +473 -0
  183. data/man/index.txt +7 -0
  184. metadata +321 -0
@@ -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