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,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Exit cleanly from an early interrupt
4
+ Signal.trap("INT") { exit 1 }
5
+
6
+ require 'carat'
7
+ # Check if an older version of carat is installed
8
+ $LOAD_PATH.each do |path|
9
+ if path =~ %r'/carat-0\.(\d+)' && $1.to_i < 9
10
+ err = "Looks like you have a version of carat that's older than 0.9.\n"
11
+ err << "Please remove your old versions.\n"
12
+ err << "An easy way to do this is by running `gem cleanup carat`."
13
+ abort(err)
14
+ end
15
+ end
16
+
17
+ require 'carat/friendly_errors'
18
+ Carat.with_friendly_errors do
19
+ require 'carat/cli'
20
+ Carat::CLI.start(ARGV, :debug => true)
21
+ end
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Signal.trap("INT") { exit 1 }
4
+
5
+ require 'carat/ruby_version'
6
+ require 'carat/ruby_dsl'
7
+ require 'carat/shared_helpers'
8
+
9
+ module Carat
10
+ class GemfileError < RuntimeError; end
11
+ class Dsl
12
+ include RubyDsl
13
+
14
+ attr_accessor :ruby_version
15
+
16
+ def initialize
17
+ @ruby_version = nil
18
+ end
19
+
20
+ def eval_gemfile(gemfile, contents = nil)
21
+ contents ||= File.open(gemfile, "rb") { |f| f.read }
22
+ instance_eval(contents, gemfile.to_s, 1)
23
+ rescue SyntaxError => e
24
+ bt = e.message.split("\n")[1..-1]
25
+ raise GemfileError, ["Gemfile syntax error:", *bt].join("\n")
26
+ rescue ScriptError, RegexpError, NameError, ArgumentError => e
27
+ e.backtrace[0] = "#{e.backtrace[0]}: #{e.message} (#{e.class})"
28
+ STDERR.puts e.backtrace.join("\n ")
29
+ raise GemfileError, "There was an error in your Gemfile," \
30
+ " and Carat cannot continue."
31
+ end
32
+
33
+ def source(source, options = {})
34
+ end
35
+
36
+ def gem(name, *args)
37
+ end
38
+
39
+ def group(*args, &blk)
40
+ end
41
+ end
42
+ end
43
+
44
+ dsl = Carat::Dsl.new
45
+ begin
46
+ dsl.eval_gemfile(Carat::SharedHelpers.default_gemfile)
47
+ ruby_version = dsl.ruby_version
48
+ if ruby_version
49
+ puts ruby_version
50
+ else
51
+ puts "No ruby version specified"
52
+ end
53
+ rescue Carat::GemfileError => e
54
+ puts e.message
55
+ exit(-1)
56
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+ require 'carat/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'carat'
8
+ s.version = Carat::VERSION
9
+ s.licenses = ['MIT']
10
+ s.authors = ["Justin Searls", "Aaron Patterson", "Eileen Uchitelle", "Sam Phippen", "André Arko", "Terence Lee", "Carl Lerche", "Yehuda Katz"]
11
+ s.email = ["searls@gmail.com"]
12
+ s.homepage = "https://github.com/caratrb/carat"
13
+ s.summary = %q{One way to manage your application's dependencies}
14
+ s.description = %q{Carat manages an application's dependencies through its entire life, across many machines, systematically and repeatably}
15
+
16
+ s.required_ruby_version = '>= 2.2.2'
17
+ s.required_rubygems_version = '>= 1.3.6'
18
+
19
+ s.add_development_dependency 'mustache', '0.99.6'
20
+ s.add_development_dependency 'rdiscount', '~> 1.6'
21
+ s.add_development_dependency 'ronn', '~> 0.7.3'
22
+ s.add_development_dependency 'rspec', '~> 3.0'
23
+ s.add_development_dependency 'rake'
24
+
25
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ # we don't check in man pages, but we need to ship them because
27
+ # we use them to generate the long-form help for each command.
28
+ s.files += Dir.glob('lib/carat/man/**/*')
29
+
30
+ s.executables = %w(carat)
31
+ s.require_paths = ["lib"]
32
+ end
@@ -0,0 +1,446 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+ require 'rbconfig'
4
+ require 'carat/gem_path_manipulation'
5
+ require 'carat/rubygems_ext'
6
+ require 'carat/rubygems_integration'
7
+ require 'carat/version'
8
+ require 'carat/constants'
9
+ require 'carat/current_ruby'
10
+
11
+ module Carat
12
+ preserve_gem_path
13
+ ORIGINAL_ENV = ENV.to_hash
14
+
15
+ autoload :AnonymizableURI, 'carat/anonymizable_uri'
16
+ autoload :Definition, 'carat/definition'
17
+ autoload :Dependency, 'carat/dependency'
18
+ autoload :DepProxy, 'carat/dep_proxy'
19
+ autoload :Deprecate, 'carat/deprecate'
20
+ autoload :Dsl, 'carat/dsl'
21
+ autoload :EndpointSpecification, 'carat/endpoint_specification'
22
+ autoload :Environment, 'carat/environment'
23
+ autoload :Env, 'carat/env'
24
+ autoload :Fetcher, 'carat/fetcher'
25
+ autoload :GemHelper, 'carat/gem_helper'
26
+ autoload :GemHelpers, 'carat/gem_helpers'
27
+ autoload :GemInstaller, 'carat/gem_installer'
28
+ autoload :Graph, 'carat/graph'
29
+ autoload :Index, 'carat/index'
30
+ autoload :Installer, 'carat/installer'
31
+ autoload :Injector, 'carat/injector'
32
+ autoload :LazySpecification, 'carat/lazy_specification'
33
+ autoload :LockfileParser, 'carat/lockfile_parser'
34
+ autoload :MatchPlatform, 'carat/match_platform'
35
+ autoload :RemoteSpecification, 'carat/remote_specification'
36
+ autoload :Resolver, 'carat/resolver'
37
+ autoload :Retry, 'carat/retry'
38
+ autoload :RubyVersion, 'carat/ruby_version'
39
+ autoload :RubyDsl, 'carat/ruby_dsl'
40
+ autoload :Runtime, 'carat/runtime'
41
+ autoload :Settings, 'carat/settings'
42
+ autoload :SharedHelpers, 'carat/shared_helpers'
43
+ autoload :SpecSet, 'carat/spec_set'
44
+ autoload :Source, 'carat/source'
45
+ autoload :SourceList, 'carat/source_list'
46
+ autoload :Specification, 'carat/shared_helpers'
47
+ autoload :SystemRubyVersion, 'carat/ruby_version'
48
+ autoload :UI, 'carat/ui'
49
+
50
+ class CaratError < StandardError
51
+ def self.status_code(code)
52
+ define_method(:status_code) { code }
53
+ end
54
+ end
55
+
56
+ class GemfileNotFound < CaratError; status_code(10) ; end
57
+ class GemNotFound < CaratError; status_code(7) ; end
58
+ class GemfileError < CaratError; status_code(4) ; end
59
+ class InstallError < CaratError; status_code(5) ; end
60
+ class InstallHookError < CaratError; status_code(8) ; end
61
+ class PathError < CaratError; status_code(13) ; end
62
+ class GitError < CaratError; status_code(11) ; end
63
+ class DeprecatedError < CaratError; status_code(12) ; end
64
+ class GemspecError < CaratError; status_code(14) ; end
65
+ class InvalidOption < CaratError; status_code(15) ; end
66
+ class ProductionError < CaratError; status_code(16) ; end
67
+ class HTTPError < CaratError; status_code(17) ; end
68
+ class RubyVersionMismatch < CaratError; status_code(18) ; end
69
+ class SecurityError < CaratError; status_code(19) ; end
70
+ class LockfileError < CaratError; status_code(20) ; end
71
+ class CyclicDependencyError < CaratError; status_code(21) ; end
72
+ class GemfileLockNotFound < CaratError; status_code(22) ; end
73
+
74
+ # Internal errors, should be rescued
75
+ class VersionConflict < CaratError
76
+ attr_reader :conflicts
77
+
78
+ def initialize(conflicts, msg = nil)
79
+ super(msg)
80
+ @conflicts = conflicts
81
+ end
82
+
83
+ status_code(6)
84
+ end
85
+
86
+ class MarshalError < StandardError; end
87
+
88
+ class << self
89
+ attr_writer :ui, :bundle_path
90
+
91
+ def configure
92
+ @configured ||= configure_gem_home_and_path
93
+ end
94
+
95
+ def ui
96
+ @ui ||= UI::Silent.new
97
+ end
98
+
99
+ # Returns absolute path of where gems are installed on the filesystem.
100
+ def bundle_path
101
+ @bundle_path ||= Pathname.new(settings.path).expand_path(root)
102
+ end
103
+
104
+ # Returns absolute location of where binstubs are installed to.
105
+ def bin_path
106
+ @bin_path ||= begin
107
+ path = settings[:bin] || "bin"
108
+ path = Pathname.new(path).expand_path(root).expand_path
109
+ FileUtils.mkdir_p(path)
110
+ path
111
+ end
112
+ end
113
+
114
+ def setup(*groups)
115
+ # Just return if all groups are already loaded
116
+ return @setup if defined?(@setup)
117
+
118
+ definition.validate_ruby!
119
+
120
+ if groups.empty?
121
+ # Load all groups, but only once
122
+ @setup = load.setup
123
+ else
124
+ @completed_groups ||= []
125
+ # Figure out which groups haven't been loaded yet
126
+ unloaded = groups - @completed_groups
127
+ # Record groups that are now loaded
128
+ @completed_groups = groups
129
+ unloaded.any? ? load.setup(*groups) : load
130
+ end
131
+ end
132
+
133
+ def require(*groups)
134
+ setup(*groups).require(*groups)
135
+ end
136
+
137
+ def load
138
+ @load ||= Runtime.new(root, definition)
139
+ end
140
+
141
+ def environment
142
+ Carat::Environment.new(root, definition)
143
+ end
144
+
145
+ # Returns an instance of Carat::Definition for given Gemfile and lockfile
146
+ #
147
+ # @param unlock [Hash, Boolean, nil] Gems that have been requested
148
+ # to be updated or true if all gems should be updated
149
+ # @return [Carat::Definition]
150
+ def definition(unlock = nil)
151
+ @definition = nil if unlock
152
+ @definition ||= begin
153
+ configure
154
+ upgrade_lockfile
155
+ Definition.build(default_gemfile, default_lockfile, unlock)
156
+ end
157
+ end
158
+
159
+ def locked_gems
160
+ return @locked_gems if defined?(@locked_gems)
161
+ if Carat.default_lockfile.exist?
162
+ lock = Carat.read_file(Carat.default_lockfile)
163
+ @locked_gems = LockfileParser.new(lock)
164
+ else
165
+ @locked_gems = nil
166
+ end
167
+ end
168
+
169
+ def ruby_scope
170
+ "#{Carat.rubygems.ruby_engine}/#{Carat.rubygems.config_map[:ruby_version]}"
171
+ end
172
+
173
+ def user_bundle_path
174
+ Pathname.new(Carat.rubygems.user_home).join(".carat")
175
+ end
176
+
177
+ def home
178
+ bundle_path.join("carat")
179
+ end
180
+
181
+ def install_path
182
+ home.join("gems")
183
+ end
184
+
185
+ def specs_path
186
+ bundle_path.join("specifications")
187
+ end
188
+
189
+ def cache
190
+ bundle_path.join("cache/carat")
191
+ end
192
+
193
+ def root
194
+ @root ||= begin
195
+ default_gemfile.dirname.expand_path
196
+ rescue GemfileNotFound
197
+ bundle_dir = default_bundle_dir
198
+ raise GemfileNotFound, "Could not locate Gemfile or .carat/ directory" unless bundle_dir
199
+ Pathname.new(File.expand_path("..", bundle_dir))
200
+ end
201
+ end
202
+
203
+ def app_config_path
204
+ ENV['BUNDLE_APP_CONFIG'] ?
205
+ Pathname.new(ENV['BUNDLE_APP_CONFIG']).expand_path(root) :
206
+ root.join('.carat')
207
+ end
208
+
209
+ def app_cache(custom_path = nil)
210
+ path = custom_path || root
211
+ path.join(self.settings.app_cache_path)
212
+ end
213
+
214
+ def tmp(name = Process.pid.to_s)
215
+ Pathname.new(Dir.mktmpdir(["carat", name]))
216
+ end
217
+
218
+ def rm_rf(path)
219
+ FileUtils.remove_entry_secure(path) if path && File.exist?(path)
220
+ end
221
+
222
+ def settings
223
+ return @settings if defined?(@settings)
224
+ @settings = Settings.new(app_config_path)
225
+ rescue GemfileNotFound
226
+ @settings = Settings.new(Pathname.new(".carat").expand_path)
227
+ end
228
+
229
+ def with_original_env
230
+ bundled_env = ENV.to_hash
231
+ ENV.replace(ORIGINAL_ENV)
232
+ yield
233
+ ensure
234
+ ENV.replace(bundled_env.to_hash)
235
+ end
236
+
237
+ def with_clean_env
238
+ with_original_env do
239
+ ENV['MANPATH'] = ENV['BUNDLE_ORIG_MANPATH']
240
+ ENV.delete_if { |k,_| k[0,7] == 'BUNDLE_' }
241
+ if ENV.has_key? 'RUBYOPT'
242
+ ENV['RUBYOPT'] = ENV['RUBYOPT'].sub '-rcarat/setup', ''
243
+ ENV['RUBYOPT'] = ENV['RUBYOPT'].sub "-I#{File.expand_path('..', __FILE__)}", ''
244
+ end
245
+ yield
246
+ end
247
+ end
248
+
249
+ def clean_system(*args)
250
+ with_clean_env { Kernel.system(*args) }
251
+ end
252
+
253
+ def clean_exec(*args)
254
+ with_clean_env { Kernel.exec(*args) }
255
+ end
256
+
257
+ def default_gemfile
258
+ SharedHelpers.default_gemfile
259
+ end
260
+
261
+ def default_lockfile
262
+ SharedHelpers.default_lockfile
263
+ end
264
+
265
+ def default_bundle_dir
266
+ SharedHelpers.default_bundle_dir
267
+ end
268
+
269
+ def system_bindir
270
+ # Gem.bindir doesn't always return the location that Rubygems will install
271
+ # system binaries. If you put '-n foo' in your .gemrc, Rubygems will
272
+ # install binstubs there instead. Unfortunately, Rubygems doesn't expose
273
+ # that directory at all, so rather than parse .gemrc ourselves, we allow
274
+ # the directory to be set as well, via `carat config bindir foo`.
275
+ Carat.settings[:system_bindir] || Carat.rubygems.gem_bindir
276
+ end
277
+
278
+ def requires_sudo?
279
+ return @requires_sudo if defined?(@requires_sudo_ran)
280
+
281
+ if settings.allow_sudo?
282
+ sudo_present = which "sudo"
283
+ end
284
+
285
+ if sudo_present
286
+ # the bundle path and subdirectories need to be writable for Rubygems
287
+ # to be able to unpack and install gems without exploding
288
+ path = bundle_path
289
+ path = path.parent until path.exist?
290
+
291
+ # bins are written to a different location on OS X
292
+ bin_dir = Pathname.new(Carat.system_bindir)
293
+ bin_dir = bin_dir.parent until bin_dir.exist?
294
+
295
+ # if any directory is not writable, we need sudo
296
+ files = [path, bin_dir] | Dir[path.join('build_info/*').to_s] | Dir[path.join('*').to_s]
297
+ sudo_needed = files.any?{|f| !File.writable?(f) }
298
+ end
299
+
300
+ @requires_sudo_ran = true
301
+ @requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed
302
+ end
303
+
304
+ def mkdir_p(path)
305
+ if requires_sudo?
306
+ sudo "mkdir -p '#{path}'" unless File.exist?(path)
307
+ else
308
+ FileUtils.mkdir_p(path)
309
+ end
310
+ end
311
+
312
+ def which(executable)
313
+ if File.file?(executable) && File.executable?(executable)
314
+ executable
315
+ elsif ENV['PATH']
316
+ path = ENV['PATH'].split(File::PATH_SEPARATOR).find do |p|
317
+ abs_path = File.join(p, executable)
318
+ File.file?(abs_path) && File.executable?(abs_path)
319
+ end
320
+ path && File.expand_path(executable, path)
321
+ end
322
+ end
323
+
324
+ def sudo(str)
325
+ prompt = "\n\n" + <<-PROMPT.gsub(/^ {6}/, '').strip + " "
326
+ Your user account isn't allowed to install to the system Rubygems.
327
+ You can cancel this installation and run:
328
+
329
+ carat install --path vendor/bundle
330
+
331
+ to install the gems into ./vendor/bundle/, or you can enter your password
332
+ and install the bundled gems to Rubygems using sudo.
333
+
334
+ Password:
335
+ PROMPT
336
+
337
+ `sudo -p "#{prompt}" #{str}`
338
+ end
339
+
340
+ def read_file(file)
341
+ File.open(file, "rb") { |f| f.read }
342
+ end
343
+
344
+ def load_marshal(data)
345
+ Marshal.load(data)
346
+ rescue => e
347
+ raise MarshalError, "#{e.class}: #{e.message}"
348
+ end
349
+
350
+ def load_gemspec(file)
351
+ @gemspec_cache ||= {}
352
+ key = File.expand_path(file)
353
+ spec = ( @gemspec_cache[key] ||= load_gemspec_uncached(file) )
354
+ # Protect against caching side-effected gemspecs by returning a
355
+ # new instance each time.
356
+ spec.dup if spec
357
+ end
358
+
359
+ def load_gemspec_uncached(file)
360
+ path = Pathname.new(file)
361
+ # Eval the gemspec from its parent directory, because some gemspecs
362
+ # depend on "./" relative paths.
363
+ SharedHelpers.chdir(path.dirname.to_s) do
364
+ contents = path.read
365
+ if contents[0..2] == "---" # YAML header
366
+ eval_yaml_gemspec(path, contents)
367
+ else
368
+ eval_gemspec(path, contents)
369
+ end
370
+ end
371
+ end
372
+
373
+ def clear_gemspec_cache
374
+ @gemspec_cache = {}
375
+ end
376
+
377
+ def git_present?
378
+ return @git_present if defined?(@git_present)
379
+ @git_present = Carat.which("git") || Carat.which("git.exe")
380
+ end
381
+
382
+ def ruby_version
383
+ @ruby_version ||= SystemRubyVersion.new
384
+ end
385
+
386
+ def reset!
387
+ @definition = nil
388
+ end
389
+
390
+ private
391
+
392
+ def eval_yaml_gemspec(path, contents)
393
+ # If the YAML is invalid, Syck raises an ArgumentError, and Psych
394
+ # raises a Psych::SyntaxError. See psyched_yaml.rb for more info.
395
+ Gem::Specification.from_yaml(contents)
396
+ rescue YamlSyntaxError, ArgumentError, Gem::EndOfYAMLException, Gem::Exception
397
+ eval_gemspec(path, contents)
398
+ end
399
+
400
+ def eval_gemspec(path, contents)
401
+ eval(contents, TOPLEVEL_BINDING, path.expand_path.to_s)
402
+ rescue ScriptError, StandardError => e
403
+ original_line = e.backtrace.find { |line| line.include?(path.to_s) }
404
+ msg = "There was a #{e.class} while loading #{path.basename}: \n#{e.message}"
405
+ msg << " from\n #{original_line}" if original_line
406
+ msg << "\n"
407
+
408
+ if e.is_a?(LoadError) && RUBY_VERSION >= "1.9"
409
+ msg << "\nDoes it try to require a relative path? That's been removed in Ruby 1.9."
410
+ end
411
+
412
+ raise GemspecError, msg
413
+ end
414
+
415
+ def configure_gem_home_and_path
416
+ blank_home = ENV['GEM_HOME'].nil? || ENV['GEM_HOME'].empty?
417
+ if settings[:disable_shared_gems]
418
+ ENV['GEM_PATH'] = ''
419
+ elsif blank_home || Carat.rubygems.gem_dir != bundle_path.to_s
420
+ possibles = [Carat.rubygems.gem_dir, Carat.rubygems.gem_path]
421
+ paths = possibles.flatten.compact.uniq.reject { |p| p.empty? }
422
+ ENV["GEM_PATH"] = paths.join(File::PATH_SEPARATOR)
423
+ end
424
+
425
+ configure_gem_home
426
+ bundle_path
427
+ end
428
+
429
+ def configure_gem_home
430
+ # TODO: This mkdir_p is only needed for JRuby <= 1.5 and should go away (GH #602)
431
+ FileUtils.mkdir_p bundle_path.to_s rescue nil
432
+
433
+ ENV['GEM_HOME'] = File.expand_path(bundle_path, root)
434
+ Carat.rubygems.clear_paths
435
+ end
436
+
437
+ def upgrade_lockfile
438
+ lockfile = default_lockfile
439
+ if lockfile.exist? && lockfile.read(3) == "---"
440
+ Carat.ui.warn "Detected Gemfile.lock generated by 0.9, deleting..."
441
+ lockfile.rmtree
442
+ end
443
+ end
444
+
445
+ end
446
+ end