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
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require "cgi"
|
|
3
|
+
require "carat/vendored_thor"
|
|
4
|
+
|
|
5
|
+
module Carat
|
|
6
|
+
def self.with_friendly_errors
|
|
7
|
+
yield
|
|
8
|
+
rescue Carat::CaratError => e
|
|
9
|
+
Carat.ui.error e.message, :wrap => true
|
|
10
|
+
Carat.ui.trace e
|
|
11
|
+
exit e.status_code
|
|
12
|
+
rescue Thor::AmbiguousTaskError => e
|
|
13
|
+
Carat.ui.error e.message
|
|
14
|
+
exit 15
|
|
15
|
+
rescue Thor::UndefinedTaskError => e
|
|
16
|
+
Carat.ui.error e.message
|
|
17
|
+
exit 15
|
|
18
|
+
rescue Thor::Error => e
|
|
19
|
+
Carat.ui.error e.message
|
|
20
|
+
exit 1
|
|
21
|
+
rescue LoadError => e
|
|
22
|
+
raise e unless e.message =~ /cannot load such file -- openssl|openssl.so|libcrypto.so/
|
|
23
|
+
Carat.ui.error "\nCould not load OpenSSL."
|
|
24
|
+
Carat.ui.warn <<-WARN, :wrap => true
|
|
25
|
+
You must recompile Ruby with OpenSSL support or change the sources in your \
|
|
26
|
+
Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL \
|
|
27
|
+
using RVM are available at http://rvm.io/packages/openssl.
|
|
28
|
+
WARN
|
|
29
|
+
Carat.ui.trace e
|
|
30
|
+
exit 1
|
|
31
|
+
rescue Interrupt => e
|
|
32
|
+
Carat.ui.error "\nQuitting..."
|
|
33
|
+
Carat.ui.trace e
|
|
34
|
+
exit 1
|
|
35
|
+
rescue SystemExit => e
|
|
36
|
+
exit e.status
|
|
37
|
+
rescue Exception => e
|
|
38
|
+
request_issue_report_for(e)
|
|
39
|
+
exit 1
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.request_issue_report_for(e)
|
|
43
|
+
Carat.ui.info <<-EOS.gsub(/^ {6}/, '')
|
|
44
|
+
#{'--- ERROR REPORT TEMPLATE -------------------------------------------------------'}
|
|
45
|
+
- What did you do?
|
|
46
|
+
|
|
47
|
+
I ran the command `#{$PROGRAM_NAME} #{ARGV.join(' ')}`
|
|
48
|
+
|
|
49
|
+
- What did you expect to happen?
|
|
50
|
+
|
|
51
|
+
I expected Carat to...
|
|
52
|
+
|
|
53
|
+
- What happened instead?
|
|
54
|
+
|
|
55
|
+
Instead, what actually happened was...
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
Error details
|
|
59
|
+
|
|
60
|
+
#{e.class}: #{e.message}
|
|
61
|
+
#{e.backtrace.join("\n ")}
|
|
62
|
+
|
|
63
|
+
#{Carat::Env.new.report(:print_gemfile => false).gsub(/\n/, "\n ").strip}
|
|
64
|
+
#{'--- TEMPLATE END ----------------------------------------------------------------'}
|
|
65
|
+
|
|
66
|
+
EOS
|
|
67
|
+
|
|
68
|
+
Carat.ui.error "Unfortunately, an unexpected error occurred, and Carat cannot continue."
|
|
69
|
+
|
|
70
|
+
Carat.ui.warn <<-EOS.gsub(/^ {6}/, '')
|
|
71
|
+
|
|
72
|
+
First, try this link to see if there are any existing issue reports for this error:
|
|
73
|
+
#{issues_url(e)}
|
|
74
|
+
|
|
75
|
+
If there aren't any reports for this error yet, please create copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at:
|
|
76
|
+
https://github.com/caratrb/carat/issues/new
|
|
77
|
+
EOS
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.issues_url(exception)
|
|
81
|
+
'https://github.com/caratrb/carat/search?q=' \
|
|
82
|
+
"#{CGI.escape(exception.message.lines.first.chomp)}&type=Issues"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
require 'carat/vendored_thor' unless defined?(Thor)
|
|
2
|
+
require 'carat'
|
|
3
|
+
|
|
4
|
+
module Carat
|
|
5
|
+
class GemHelper
|
|
6
|
+
include Rake::DSL if defined? Rake::DSL
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
# set when install'd.
|
|
10
|
+
attr_accessor :instance
|
|
11
|
+
|
|
12
|
+
def install_tasks(opts = {})
|
|
13
|
+
new(opts[:dir], opts[:name]).install
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def gemspec(&block)
|
|
17
|
+
gemspec = instance.gemspec
|
|
18
|
+
block.call(gemspec) if block
|
|
19
|
+
gemspec
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :spec_path, :base, :gemspec
|
|
24
|
+
|
|
25
|
+
def initialize(base = nil, name = nil)
|
|
26
|
+
Carat.ui = UI::Shell.new
|
|
27
|
+
@base = (base ||= SharedHelpers.pwd)
|
|
28
|
+
gemspecs = name ? [File.join(base, "#{name}.gemspec")] : Dir[File.join(base, "{,*}.gemspec")]
|
|
29
|
+
raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1
|
|
30
|
+
@spec_path = gemspecs.first
|
|
31
|
+
@gemspec = Carat.load_gemspec(@spec_path)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def install
|
|
35
|
+
built_gem_path = nil
|
|
36
|
+
|
|
37
|
+
desc "Build #{name}-#{version}.gem into the pkg directory."
|
|
38
|
+
task 'build' do
|
|
39
|
+
built_gem_path = build_gem
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
desc "Build and install #{name}-#{version}.gem into system gems."
|
|
43
|
+
task 'install' => 'build' do
|
|
44
|
+
install_gem(built_gem_path)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
desc "Build and install #{name}-#{version}.gem into system gems without network access."
|
|
48
|
+
task 'install:local' => 'build' do
|
|
49
|
+
install_gem(built_gem_path, :local)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
desc "Create tag #{version_tag} and build and push #{name}-#{version}.gem to Rubygems\n" \
|
|
53
|
+
"To prevent publishing in Rubygems use `gem_push=no rake release`"
|
|
54
|
+
task 'release' => ['build', 'release:guard_clean',
|
|
55
|
+
'release:source_control_push', 'release:rubygem_push'] do
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
task 'release:guard_clean' do
|
|
59
|
+
guard_clean
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
task 'release:source_control_push' do
|
|
63
|
+
tag_version { git_push } unless already_tagged?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
task 'release:rubygem_push' do
|
|
67
|
+
rubygem_push(built_gem_path) if gem_push?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
GemHelper.instance = self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def build_gem
|
|
74
|
+
file_name = nil
|
|
75
|
+
sh("gem build -V '#{spec_path}'") { |out, code|
|
|
76
|
+
file_name = File.basename(built_gem_path)
|
|
77
|
+
FileUtils.mkdir_p(File.join(base, 'pkg'))
|
|
78
|
+
FileUtils.mv(built_gem_path, 'pkg')
|
|
79
|
+
Carat.ui.confirm "#{name} #{version} built to pkg/#{file_name}."
|
|
80
|
+
}
|
|
81
|
+
File.join(base, 'pkg', file_name)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def install_gem(built_gem_path = nil, local = false)
|
|
85
|
+
built_gem_path ||= build_gem
|
|
86
|
+
out, _ = sh_with_code("gem install '#{built_gem_path}'#{' --local' if local}")
|
|
87
|
+
raise "Couldn't install gem, run `gem install #{built_gem_path}' for more detailed output" unless out[/Successfully installed/]
|
|
88
|
+
Carat.ui.confirm "#{name} (#{version}) installed."
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
protected
|
|
92
|
+
def rubygem_push(path)
|
|
93
|
+
if Pathname.new("~/.gem/credentials").expand_path.exist?
|
|
94
|
+
sh("gem push '#{path}'")
|
|
95
|
+
Carat.ui.confirm "Pushed #{name} #{version} to rubygems.org."
|
|
96
|
+
else
|
|
97
|
+
raise "Your rubygems.org credentials aren't set. Run `gem push` to set them."
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def built_gem_path
|
|
102
|
+
Dir[File.join(base, "#{name}-*.gem")].sort_by{|f| File.mtime(f)}.last
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def git_push
|
|
106
|
+
perform_git_push
|
|
107
|
+
perform_git_push ' --tags'
|
|
108
|
+
Carat.ui.confirm "Pushed git commits and tags."
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def perform_git_push(options = '')
|
|
112
|
+
cmd = "git push #{options}"
|
|
113
|
+
out, code = sh_with_code(cmd)
|
|
114
|
+
raise "Couldn't git push. `#{cmd}' failed with the following output:\n\n#{out}\n" unless code == 0
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def already_tagged?
|
|
118
|
+
if sh('git tag').split(/\n/).include?(version_tag)
|
|
119
|
+
Carat.ui.confirm "Tag #{version_tag} has already been created."
|
|
120
|
+
true
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def guard_clean
|
|
125
|
+
clean? && committed? or raise("There are files that need to be committed first.")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def clean?
|
|
129
|
+
sh_with_code("git diff --exit-code")[1] == 0
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def committed?
|
|
133
|
+
sh_with_code("git diff-index --quiet --cached HEAD")[1] == 0
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def tag_version
|
|
137
|
+
sh "git tag -a -m \"Version #{version}\" #{version_tag}"
|
|
138
|
+
Carat.ui.confirm "Tagged #{version_tag}."
|
|
139
|
+
yield if block_given?
|
|
140
|
+
rescue
|
|
141
|
+
Carat.ui.error "Untagging #{version_tag} due to error."
|
|
142
|
+
sh_with_code "git tag -d #{version_tag}"
|
|
143
|
+
raise
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def version
|
|
147
|
+
gemspec.version
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def version_tag
|
|
151
|
+
"v#{version}"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def name
|
|
155
|
+
gemspec.name
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def sh(cmd, &block)
|
|
159
|
+
out, code = sh_with_code(cmd, &block)
|
|
160
|
+
code == 0 ? out : raise(out.empty? ? "Running `#{cmd}' failed. Run this command directly for more detailed output." : out)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def sh_with_code(cmd, &block)
|
|
164
|
+
cmd << " 2>&1"
|
|
165
|
+
outbuf = ''
|
|
166
|
+
Carat.ui.debug(cmd)
|
|
167
|
+
SharedHelpers.chdir(base) {
|
|
168
|
+
outbuf = `#{cmd}`
|
|
169
|
+
if $? == 0
|
|
170
|
+
block.call(outbuf) if block
|
|
171
|
+
end
|
|
172
|
+
}
|
|
173
|
+
[outbuf, $?]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def gem_push?
|
|
177
|
+
! %w{n no nil false off 0}.include?(ENV['gem_push'].to_s.downcase)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
module GemHelpers
|
|
3
|
+
|
|
4
|
+
GENERIC_CACHE = {}
|
|
5
|
+
GENERICS = [
|
|
6
|
+
[Gem::Platform.new('java'), Gem::Platform.new('java')],
|
|
7
|
+
[Gem::Platform.new('mswin32'), Gem::Platform.new('mswin32')],
|
|
8
|
+
[Gem::Platform.new('mswin64'), Gem::Platform.new('mswin64')],
|
|
9
|
+
[Gem::Platform.new('universal-mingw32'), Gem::Platform.new('universal-mingw32')],
|
|
10
|
+
[Gem::Platform.new('x64-mingw32'), Gem::Platform.new('x64-mingw32')],
|
|
11
|
+
[Gem::Platform.new('x86_64-mingw32'), Gem::Platform.new('x64-mingw32')],
|
|
12
|
+
[Gem::Platform.new('mingw32'), Gem::Platform.new('x86-mingw32')]
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
def generic(p)
|
|
16
|
+
return p if p == Gem::Platform::RUBY
|
|
17
|
+
|
|
18
|
+
GENERIC_CACHE[p] ||= begin
|
|
19
|
+
_, found = GENERICS.find do |match, _generic|
|
|
20
|
+
p.os == match.os && (!match.cpu || p.cpu == match.cpu)
|
|
21
|
+
end
|
|
22
|
+
found || Gem::Platform::RUBY
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
def self.preserve_gem_path
|
|
3
|
+
original_gem_path = ENV["_ORIGINAL_GEM_PATH"]
|
|
4
|
+
gem_path = ENV["GEM_PATH"]
|
|
5
|
+
ENV["_ORIGINAL_GEM_PATH"] = gem_path if original_gem_path.nil? || original_gem_path == ""
|
|
6
|
+
ENV["GEM_PATH"] = original_gem_path if gem_path.nil? || gem_path == ""
|
|
7
|
+
end
|
|
8
|
+
end
|
data/lib/carat/graph.rb
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
module Carat
|
|
3
|
+
class Graph
|
|
4
|
+
GRAPH_NAME = :Gemfile
|
|
5
|
+
|
|
6
|
+
def initialize(env, output_file, show_version = false, show_requirements = false, output_format = "png", without = [])
|
|
7
|
+
@env = env
|
|
8
|
+
@output_file = output_file
|
|
9
|
+
@show_version = show_version
|
|
10
|
+
@show_requirements = show_requirements
|
|
11
|
+
@output_format = output_format
|
|
12
|
+
@without_groups = without.map(&:to_sym)
|
|
13
|
+
|
|
14
|
+
@groups = []
|
|
15
|
+
@relations = Hash.new {|h, k| h[k] = Set.new}
|
|
16
|
+
@node_options = {}
|
|
17
|
+
@edge_options = {}
|
|
18
|
+
|
|
19
|
+
_patching_gem_dependency_class
|
|
20
|
+
_populate_relations
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :groups, :relations, :node_options, :edge_options, :output_file, :output_format
|
|
24
|
+
|
|
25
|
+
def viz
|
|
26
|
+
GraphVizClient.new(self).run
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def _populate_relations
|
|
32
|
+
parent_dependencies = _groups.values.to_set.flatten
|
|
33
|
+
while true
|
|
34
|
+
if parent_dependencies.empty?
|
|
35
|
+
break
|
|
36
|
+
else
|
|
37
|
+
tmp = Set.new
|
|
38
|
+
parent_dependencies.each do |dependency|
|
|
39
|
+
child_dependencies = dependency.to_spec.runtime_dependencies.to_set
|
|
40
|
+
@relations[dependency.name] += child_dependencies.map(&:name).to_set
|
|
41
|
+
tmp += child_dependencies
|
|
42
|
+
|
|
43
|
+
@node_options[dependency.name] = _make_label(dependency, :node)
|
|
44
|
+
child_dependencies.each do |c_dependency|
|
|
45
|
+
@edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
parent_dependencies = tmp
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def _groups
|
|
54
|
+
relations = Hash.new {|h, k| h[k] = Set.new}
|
|
55
|
+
@env.current_dependencies.each do |dependency|
|
|
56
|
+
dependency.groups.each do |group|
|
|
57
|
+
next if @without_groups.include?(group)
|
|
58
|
+
|
|
59
|
+
relations[group.to_s].add(dependency)
|
|
60
|
+
@relations[group.to_s].add(dependency.name)
|
|
61
|
+
|
|
62
|
+
@node_options[group.to_s] ||= _make_label(group, :node)
|
|
63
|
+
@edge_options["#{group}_#{dependency.name}"] = _make_label(dependency, :edge)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
@groups = relations.keys
|
|
67
|
+
relations
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def _make_label(symbol_or_string_or_dependency, element_type)
|
|
71
|
+
case element_type.to_sym
|
|
72
|
+
when :node
|
|
73
|
+
if symbol_or_string_or_dependency.is_a?(Gem::Dependency)
|
|
74
|
+
label = symbol_or_string_or_dependency.name.dup
|
|
75
|
+
label << "\n#{symbol_or_string_or_dependency.to_spec.version.to_s}" if @show_version
|
|
76
|
+
else
|
|
77
|
+
label = symbol_or_string_or_dependency.to_s
|
|
78
|
+
end
|
|
79
|
+
when :edge
|
|
80
|
+
label = nil
|
|
81
|
+
if symbol_or_string_or_dependency.respond_to?(:requirements_list) && @show_requirements
|
|
82
|
+
tmp = symbol_or_string_or_dependency.requirements_list.join(", ")
|
|
83
|
+
label = tmp if tmp != ">= 0"
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
raise ArgumentError, "2nd argument is invalid"
|
|
87
|
+
end
|
|
88
|
+
label.nil? ? {} : { :label => label }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def _patching_gem_dependency_class
|
|
92
|
+
# method borrow from rubygems/dependency.rb
|
|
93
|
+
# redefinition of matching_specs will also redefine to_spec and to_specs
|
|
94
|
+
Gem::Dependency.class_eval do
|
|
95
|
+
def matching_specs platform_only = false
|
|
96
|
+
matches = Carat.load.specs.select { |spec|
|
|
97
|
+
self.name == spec.name and
|
|
98
|
+
requirement.satisfied_by? spec.version
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if platform_only
|
|
102
|
+
matches.reject! { |spec|
|
|
103
|
+
not Gem::Platform.match spec.platform
|
|
104
|
+
}
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
matches = matches.sort_by { |s| s.sort_obj } # HACK: shouldn't be needed
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
class GraphVizClient
|
|
113
|
+
def initialize(graph_instance)
|
|
114
|
+
@graph_name = graph_instance.class::GRAPH_NAME
|
|
115
|
+
@groups = graph_instance.groups
|
|
116
|
+
@relations = graph_instance.relations
|
|
117
|
+
@node_options = graph_instance.node_options
|
|
118
|
+
@edge_options = graph_instance.edge_options
|
|
119
|
+
@output_file = graph_instance.output_file
|
|
120
|
+
@output_format = graph_instance.output_format
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def g
|
|
124
|
+
@g ||= ::GraphViz.digraph(@graph_name, {:concentrate => true, :normalize => true, :nodesep => 0.55}) do |g|
|
|
125
|
+
g.edge[:weight] = 2
|
|
126
|
+
g.edge[:fontname] = g.node[:fontname] = 'Arial, Helvetica, SansSerif'
|
|
127
|
+
g.edge[:fontsize] = 12
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def run
|
|
132
|
+
@groups.each do |group|
|
|
133
|
+
g.add_nodes(
|
|
134
|
+
group,
|
|
135
|
+
{:style => 'filled',
|
|
136
|
+
:fillcolor => '#B9B9D5',
|
|
137
|
+
:shape => "box3d",
|
|
138
|
+
:fontsize => 16}.merge(@node_options[group])
|
|
139
|
+
)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
@relations.each do |parent, children|
|
|
143
|
+
children.each do |child|
|
|
144
|
+
if @groups.include?(parent)
|
|
145
|
+
g.add_nodes(child, {:style => 'filled', :fillcolor => '#B9B9D5'}.merge(@node_options[child]))
|
|
146
|
+
g.add_edges(parent, child, {:constraint => false}.merge(@edge_options["#{parent}_#{child}"]))
|
|
147
|
+
else
|
|
148
|
+
g.add_nodes(child, @node_options[child])
|
|
149
|
+
g.add_edges(parent, child, @edge_options["#{parent}_#{child}"])
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
if @output_format.to_s == "debug"
|
|
155
|
+
$stdout.puts g.output :none => String
|
|
156
|
+
Carat.ui.info "debugging carat viz..."
|
|
157
|
+
else
|
|
158
|
+
begin
|
|
159
|
+
g.output @output_format.to_sym => "#{@output_file}.#{@output_format}"
|
|
160
|
+
Carat.ui.info "#{@output_file}.#{@output_format}"
|
|
161
|
+
rescue ArgumentError => e
|
|
162
|
+
$stderr.puts "Unsupported output format. See Ruby-Graphviz/lib/graphviz/constants.rb"
|
|
163
|
+
raise e
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|