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.
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