carat 1.9.9.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.travis.yml +24 -0
- data/CHANGELOG.md +2006 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +23 -0
- data/DEVELOPMENT.md +119 -0
- data/ISSUES.md +96 -0
- data/LICENSE.md +23 -0
- data/README.md +32 -0
- data/Rakefile +308 -0
- data/bin/carat +21 -0
- data/bin/carat_ruby +56 -0
- data/carat.gemspec +32 -0
- data/lib/carat.rb +446 -0
- data/lib/carat/anonymizable_uri.rb +32 -0
- data/lib/carat/capistrano.rb +16 -0
- data/lib/carat/cli.rb +407 -0
- data/lib/carat/cli/binstubs.rb +38 -0
- data/lib/carat/cli/cache.rb +35 -0
- data/lib/carat/cli/check.rb +35 -0
- data/lib/carat/cli/clean.rb +26 -0
- data/lib/carat/cli/common.rb +56 -0
- data/lib/carat/cli/config.rb +84 -0
- data/lib/carat/cli/console.rb +38 -0
- data/lib/carat/cli/exec.rb +44 -0
- data/lib/carat/cli/gem.rb +195 -0
- data/lib/carat/cli/init.rb +33 -0
- data/lib/carat/cli/inject.rb +33 -0
- data/lib/carat/cli/install.rb +156 -0
- data/lib/carat/cli/open.rb +23 -0
- data/lib/carat/cli/outdated.rb +80 -0
- data/lib/carat/cli/package.rb +45 -0
- data/lib/carat/cli/platform.rb +43 -0
- data/lib/carat/cli/show.rb +74 -0
- data/lib/carat/cli/update.rb +73 -0
- data/lib/carat/cli/viz.rb +27 -0
- data/lib/carat/constants.rb +5 -0
- data/lib/carat/current_ruby.rb +183 -0
- data/lib/carat/definition.rb +628 -0
- data/lib/carat/dep_proxy.rb +43 -0
- data/lib/carat/dependency.rb +110 -0
- data/lib/carat/deployment.rb +59 -0
- data/lib/carat/deprecate.rb +15 -0
- data/lib/carat/dsl.rb +331 -0
- data/lib/carat/endpoint_specification.rb +76 -0
- data/lib/carat/env.rb +75 -0
- data/lib/carat/environment.rb +42 -0
- data/lib/carat/fetcher.rb +423 -0
- data/lib/carat/friendly_errors.rb +85 -0
- data/lib/carat/gem_helper.rb +180 -0
- data/lib/carat/gem_helpers.rb +26 -0
- data/lib/carat/gem_installer.rb +9 -0
- data/lib/carat/gem_path_manipulation.rb +8 -0
- data/lib/carat/gem_tasks.rb +2 -0
- data/lib/carat/graph.rb +169 -0
- data/lib/carat/index.rb +197 -0
- data/lib/carat/injector.rb +64 -0
- data/lib/carat/installer.rb +339 -0
- data/lib/carat/lazy_specification.rb +83 -0
- data/lib/carat/lockfile_parser.rb +167 -0
- data/lib/carat/match_platform.rb +13 -0
- data/lib/carat/psyched_yaml.rb +26 -0
- data/lib/carat/remote_specification.rb +57 -0
- data/lib/carat/resolver.rb +334 -0
- data/lib/carat/retry.rb +60 -0
- data/lib/carat/ruby_dsl.rb +11 -0
- data/lib/carat/ruby_version.rb +117 -0
- data/lib/carat/rubygems_ext.rb +170 -0
- data/lib/carat/rubygems_integration.rb +619 -0
- data/lib/carat/runtime.rb +289 -0
- data/lib/carat/settings.rb +208 -0
- data/lib/carat/setup.rb +24 -0
- data/lib/carat/shared_helpers.rb +149 -0
- data/lib/carat/similarity_detector.rb +63 -0
- data/lib/carat/source.rb +46 -0
- data/lib/carat/source/git.rb +294 -0
- data/lib/carat/source/git/git_proxy.rb +162 -0
- data/lib/carat/source/path.rb +226 -0
- data/lib/carat/source/path/installer.rb +43 -0
- data/lib/carat/source/rubygems.rb +381 -0
- data/lib/carat/source_list.rb +101 -0
- data/lib/carat/spec_set.rb +154 -0
- data/lib/carat/ssl_certs/.document +1 -0
- data/lib/carat/ssl_certs/AddTrustExternalCARoot-2048.pem +25 -0
- data/lib/carat/ssl_certs/AddTrustExternalCARoot.pem +32 -0
- data/lib/carat/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +14 -0
- data/lib/carat/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +23 -0
- data/lib/carat/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +28 -0
- data/lib/carat/ssl_certs/GeoTrustGlobalCA.pem +20 -0
- data/lib/carat/ssl_certs/certificate_manager.rb +66 -0
- data/lib/carat/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +21 -0
- data/lib/carat/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem +23 -0
- data/lib/carat/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem +25 -0
- data/lib/carat/templates/Executable +16 -0
- data/lib/carat/templates/Executable.standalone +12 -0
- data/lib/carat/templates/Gemfile +4 -0
- data/lib/carat/templates/newgem/.travis.yml.tt +3 -0
- data/lib/carat/templates/newgem/CODE_OF_CONDUCT.md.tt +13 -0
- data/lib/carat/templates/newgem/Gemfile.tt +4 -0
- data/lib/carat/templates/newgem/LICENSE.txt.tt +21 -0
- data/lib/carat/templates/newgem/README.md.tt +39 -0
- data/lib/carat/templates/newgem/Rakefile.tt +25 -0
- data/lib/carat/templates/newgem/bin/console.tt +14 -0
- data/lib/carat/templates/newgem/bin/setup.tt +7 -0
- data/lib/carat/templates/newgem/exe/newgem.tt +3 -0
- data/lib/carat/templates/newgem/ext/newgem/extconf.rb.tt +3 -0
- data/lib/carat/templates/newgem/ext/newgem/newgem.c.tt +9 -0
- data/lib/carat/templates/newgem/ext/newgem/newgem.h.tt +6 -0
- data/lib/carat/templates/newgem/gitignore.tt +16 -0
- data/lib/carat/templates/newgem/lib/newgem.rb.tt +12 -0
- data/lib/carat/templates/newgem/lib/newgem/version.rb.tt +7 -0
- data/lib/carat/templates/newgem/newgem.gemspec.tt +43 -0
- data/lib/carat/templates/newgem/rspec.tt +2 -0
- data/lib/carat/templates/newgem/spec/newgem_spec.rb.tt +11 -0
- data/lib/carat/templates/newgem/spec/spec_helper.rb.tt +2 -0
- data/lib/carat/templates/newgem/test/minitest_helper.rb.tt +4 -0
- data/lib/carat/templates/newgem/test/test_newgem.rb.tt +11 -0
- data/lib/carat/ui.rb +7 -0
- data/lib/carat/ui/rg_proxy.rb +21 -0
- data/lib/carat/ui/shell.rb +103 -0
- data/lib/carat/ui/silent.rb +44 -0
- data/lib/carat/vendor/molinillo/lib/molinillo.rb +5 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/dependency_graph.rb +266 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/errors.rb +69 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/gem_metadata.rb +3 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +90 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/modules/ui.rb +63 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/resolution.rb +415 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/resolver.rb +43 -0
- data/lib/carat/vendor/molinillo/lib/molinillo/state.rb +43 -0
- data/lib/carat/vendor/net/http/faster.rb +26 -0
- data/lib/carat/vendor/net/http/persistent.rb +1230 -0
- data/lib/carat/vendor/net/http/persistent/ssl_reuse.rb +128 -0
- data/lib/carat/vendor/thor/lib/thor.rb +484 -0
- data/lib/carat/vendor/thor/lib/thor/actions.rb +319 -0
- data/lib/carat/vendor/thor/lib/thor/actions/create_file.rb +103 -0
- data/lib/carat/vendor/thor/lib/thor/actions/create_link.rb +59 -0
- data/lib/carat/vendor/thor/lib/thor/actions/directory.rb +118 -0
- data/lib/carat/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
- data/lib/carat/vendor/thor/lib/thor/actions/file_manipulation.rb +316 -0
- data/lib/carat/vendor/thor/lib/thor/actions/inject_into_file.rb +107 -0
- data/lib/carat/vendor/thor/lib/thor/base.rb +656 -0
- data/lib/carat/vendor/thor/lib/thor/command.rb +133 -0
- data/lib/carat/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +77 -0
- data/lib/carat/vendor/thor/lib/thor/core_ext/io_binary_read.rb +10 -0
- data/lib/carat/vendor/thor/lib/thor/core_ext/ordered_hash.rb +98 -0
- data/lib/carat/vendor/thor/lib/thor/error.rb +32 -0
- data/lib/carat/vendor/thor/lib/thor/group.rb +281 -0
- data/lib/carat/vendor/thor/lib/thor/invocation.rb +178 -0
- data/lib/carat/vendor/thor/lib/thor/line_editor.rb +17 -0
- data/lib/carat/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
- data/lib/carat/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
- data/lib/carat/vendor/thor/lib/thor/parser.rb +4 -0
- data/lib/carat/vendor/thor/lib/thor/parser/argument.rb +73 -0
- data/lib/carat/vendor/thor/lib/thor/parser/arguments.rb +175 -0
- data/lib/carat/vendor/thor/lib/thor/parser/option.rb +125 -0
- data/lib/carat/vendor/thor/lib/thor/parser/options.rb +218 -0
- data/lib/carat/vendor/thor/lib/thor/rake_compat.rb +71 -0
- data/lib/carat/vendor/thor/lib/thor/runner.rb +322 -0
- data/lib/carat/vendor/thor/lib/thor/shell.rb +81 -0
- data/lib/carat/vendor/thor/lib/thor/shell/basic.rb +421 -0
- data/lib/carat/vendor/thor/lib/thor/shell/color.rb +149 -0
- data/lib/carat/vendor/thor/lib/thor/shell/html.rb +126 -0
- data/lib/carat/vendor/thor/lib/thor/util.rb +267 -0
- data/lib/carat/vendor/thor/lib/thor/version.rb +3 -0
- data/lib/carat/vendored_fileutils.rb +9 -0
- data/lib/carat/vendored_molinillo.rb +2 -0
- data/lib/carat/vendored_persistent.rb +11 -0
- data/lib/carat/vendored_thor.rb +3 -0
- data/lib/carat/version.rb +6 -0
- data/lib/carat/vlad.rb +11 -0
- data/lib/carat/worker.rb +73 -0
- data/man/carat-config.ronn +178 -0
- data/man/carat-exec.ronn +136 -0
- data/man/carat-install.ronn +383 -0
- data/man/carat-package.ronn +66 -0
- data/man/carat-platform.ronn +42 -0
- data/man/carat-update.ronn +188 -0
- data/man/carat.ronn +98 -0
- data/man/gemfile.5.ronn +473 -0
- data/man/index.txt +7 -0
- metadata +321 -0
data/bin/carat
ADDED
|
@@ -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
|
data/bin/carat_ruby
ADDED
|
@@ -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
|
data/carat.gemspec
ADDED
|
@@ -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
|
data/lib/carat.rb
ADDED
|
@@ -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
|