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,38 @@
|
|
|
1
|
+
require "carat/cli/common"
|
|
2
|
+
|
|
3
|
+
module Carat
|
|
4
|
+
class CLI::Binstubs
|
|
5
|
+
attr_reader :options, :gems
|
|
6
|
+
def initialize(options, gems)
|
|
7
|
+
@options = options
|
|
8
|
+
@gems = gems
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run
|
|
12
|
+
Carat.definition.validate_ruby!
|
|
13
|
+
Carat.settings[:bin] = options["path"] if options["path"]
|
|
14
|
+
Carat.settings[:bin] = nil if options["path"] && options["path"].empty?
|
|
15
|
+
installer = Installer.new(Carat.root, Carat.definition)
|
|
16
|
+
|
|
17
|
+
if gems.empty?
|
|
18
|
+
Carat.ui.error "`carat binstubs` needs at least one gem to run."
|
|
19
|
+
exit 1
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
gems.each do |gem_name|
|
|
23
|
+
spec = installer.specs.find{|s| s.name == gem_name }
|
|
24
|
+
unless spec
|
|
25
|
+
raise GemNotFound, Carat::CLI::Common.gem_not_found_message(
|
|
26
|
+
gem_name, Carat.definition.specs)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if spec.name == "carat"
|
|
30
|
+
Carat.ui.warn "Sorry, Carat can only be run via Rubygems."
|
|
31
|
+
else
|
|
32
|
+
installer.generate_carat_executable_stubs(spec, :force => options[:force], :binstubs_cmd => true)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
class CLI::Cache
|
|
3
|
+
attr_reader :options
|
|
4
|
+
def initialize(options)
|
|
5
|
+
@options = options
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
Carat.definition.validate_ruby!
|
|
10
|
+
Carat.definition.resolve_with_cache!
|
|
11
|
+
setup_cache_all
|
|
12
|
+
Carat.settings[:cache_all_platforms] = options["all-platforms"] if options.key?("all-platforms")
|
|
13
|
+
Carat.load.cache
|
|
14
|
+
Carat.settings[:no_prune] = true if options["no-prune"]
|
|
15
|
+
Carat.load.lock
|
|
16
|
+
rescue GemNotFound => e
|
|
17
|
+
Carat.ui.error(e.message)
|
|
18
|
+
Carat.ui.warn "Run `carat install` to install missing gems."
|
|
19
|
+
exit 1
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def setup_cache_all
|
|
25
|
+
Carat.settings[:cache_all] = options[:all] if options.key?("all")
|
|
26
|
+
|
|
27
|
+
if Carat.definition.has_local_dependencies? && !Carat.settings[:cache_all]
|
|
28
|
+
Carat.ui.warn "Your Gemfile contains path and git dependencies. If you want " \
|
|
29
|
+
"to package them as well, please pass the --all flag. This will be the default " \
|
|
30
|
+
"on Carat 2.0."
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
class CLI::Check
|
|
3
|
+
attr_reader :options
|
|
4
|
+
def initialize(options)
|
|
5
|
+
@options = options
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
Carat.settings[:path] = File.expand_path(options[:path]) if options[:path]
|
|
10
|
+
begin
|
|
11
|
+
definition = Carat.definition
|
|
12
|
+
definition.validate_ruby!
|
|
13
|
+
not_installed = definition.missing_specs
|
|
14
|
+
rescue GemNotFound, VersionConflict
|
|
15
|
+
Carat.ui.error "Carat can't satisfy your Gemfile's dependencies."
|
|
16
|
+
Carat.ui.warn "Install missing gems with `carat install`."
|
|
17
|
+
exit 1
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
if not_installed.any?
|
|
21
|
+
Carat.ui.error "The following gems are missing"
|
|
22
|
+
not_installed.each { |s| Carat.ui.error " * #{s.name} (#{s.version})" }
|
|
23
|
+
Carat.ui.warn "Install missing gems with `carat install`"
|
|
24
|
+
exit 1
|
|
25
|
+
elsif !Carat.default_lockfile.exist? && Carat.settings[:frozen]
|
|
26
|
+
Carat.ui.error "This bundle has been frozen, but there is no Gemfile.lock present"
|
|
27
|
+
exit 1
|
|
28
|
+
else
|
|
29
|
+
Carat.load.lock unless options[:"dry-run"]
|
|
30
|
+
Carat.ui.info "The Gemfile's dependencies are satisfied"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
class CLI::Clean
|
|
3
|
+
attr_reader :options
|
|
4
|
+
|
|
5
|
+
def initialize(options)
|
|
6
|
+
@options = options
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def run
|
|
10
|
+
require_path_or_force
|
|
11
|
+
Carat.load.clean(options[:"dry-run"])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def require_path_or_force
|
|
17
|
+
if !Carat.settings[:path] && !options[:force]
|
|
18
|
+
Carat.ui.error "Cleaning all the gems on your system is dangerous! " \
|
|
19
|
+
"If you're sure you want to remove every system gem not in this " \
|
|
20
|
+
"bundle, run `carat clean --force`."
|
|
21
|
+
exit 1
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
module CLI::Common
|
|
3
|
+
def self.without_groups_message
|
|
4
|
+
groups = Carat.settings.without
|
|
5
|
+
group_list = [groups[0...-1].join(", "), groups[-1..-1]].
|
|
6
|
+
reject{|s| s.to_s.empty? }.join(" and ")
|
|
7
|
+
group_str = (groups.size == 1) ? "group" : "groups"
|
|
8
|
+
"Gems in the #{group_str} #{group_list} were not installed."
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.select_spec(name, regex_match = nil)
|
|
12
|
+
specs = []
|
|
13
|
+
regexp = Regexp.new(name) if regex_match
|
|
14
|
+
|
|
15
|
+
Carat.definition.specs.each do |spec|
|
|
16
|
+
return spec if spec.name == name
|
|
17
|
+
specs << spec if regexp && spec.name =~ regexp
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
case specs.count
|
|
21
|
+
when 0
|
|
22
|
+
raise GemNotFound, gem_not_found_message(name, Carat.definition.dependencies)
|
|
23
|
+
when 1
|
|
24
|
+
specs.first
|
|
25
|
+
else
|
|
26
|
+
ask_for_spec_from(specs)
|
|
27
|
+
end
|
|
28
|
+
rescue RegexpError
|
|
29
|
+
raise GemNotFound, gem_not_found_message(name, Carat.definition.dependencies)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.ask_for_spec_from(specs)
|
|
33
|
+
if !$stdout.tty? && ENV['BUNDLE_SPEC_RUN'].nil?
|
|
34
|
+
raise GemNotFound, gem_not_found_message(name, Carat.definition.dependencies)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
specs.each_with_index do |spec, index|
|
|
38
|
+
Carat.ui.info "#{index.succ} : #{spec.name}", true
|
|
39
|
+
end
|
|
40
|
+
Carat.ui.info '0 : - exit -', true
|
|
41
|
+
|
|
42
|
+
num = Carat.ui.ask('> ').to_i
|
|
43
|
+
num > 0 ? specs[num - 1] : nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.gem_not_found_message(missing_gem_name, alternatives)
|
|
47
|
+
require 'carat/similarity_detector'
|
|
48
|
+
message = "Could not find gem '#{missing_gem_name}'."
|
|
49
|
+
alternate_names = alternatives.map { |a| a.respond_to?(:name) ? a.name : a }
|
|
50
|
+
suggestions = SimilarityDetector.new(alternate_names).similar_word_list(missing_gem_name)
|
|
51
|
+
message += "\nDid you mean #{suggestions}?" if suggestions
|
|
52
|
+
message
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
class CLI::Config
|
|
3
|
+
attr_reader :options, :thor
|
|
4
|
+
attr_accessor :args
|
|
5
|
+
|
|
6
|
+
def initialize(options, args, thor)
|
|
7
|
+
@options = options
|
|
8
|
+
@args = args
|
|
9
|
+
@thor = thor
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
peek = args.shift
|
|
14
|
+
|
|
15
|
+
if peek && peek =~ /^\-\-/
|
|
16
|
+
name, scope = args.shift, $'
|
|
17
|
+
else
|
|
18
|
+
name, scope = peek, "global"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
unless name
|
|
22
|
+
Carat.ui.confirm "Settings are listed in order of priority. The top value will be used.\n"
|
|
23
|
+
|
|
24
|
+
Carat.settings.all.each do |setting|
|
|
25
|
+
Carat.ui.confirm "#{setting}"
|
|
26
|
+
thor.with_padding do
|
|
27
|
+
Carat.settings.pretty_values_for(setting).each do |line|
|
|
28
|
+
Carat.ui.info line
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
Carat.ui.confirm ""
|
|
32
|
+
end
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
case scope
|
|
37
|
+
when "delete"
|
|
38
|
+
Carat.settings.set_local(name, nil)
|
|
39
|
+
Carat.settings.set_global(name, nil)
|
|
40
|
+
when "local", "global"
|
|
41
|
+
if args.empty?
|
|
42
|
+
Carat.ui.confirm "Settings for `#{name}` in order of priority. The top value will be used"
|
|
43
|
+
thor.with_padding do
|
|
44
|
+
Carat.settings.pretty_values_for(name).each { |line| Carat.ui.info line }
|
|
45
|
+
end
|
|
46
|
+
return
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
locations = Carat.settings.locations(name)
|
|
50
|
+
|
|
51
|
+
if scope == "global"
|
|
52
|
+
if local = locations[:local]
|
|
53
|
+
Carat.ui.info "Your application has set #{name} to #{local.inspect}. This will override the " \
|
|
54
|
+
"global value you are currently setting"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if env = locations[:env]
|
|
58
|
+
Carat.ui.info "You have a carat environment variable for #{name} set to #{env.inspect}. " \
|
|
59
|
+
"This will take precedence over the global value you are setting"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if global = locations[:global]
|
|
63
|
+
Carat.ui.info "You are replacing the current global value of #{name}, which is currently #{global.inspect}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if scope == "local" && local = locations[:local]
|
|
68
|
+
Carat.ui.info "You are replacing the current local value of #{name}, which is currently #{local.inspect}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
if name.match(/\Alocal\./)
|
|
72
|
+
pathname = Pathname.new(args.join(" "))
|
|
73
|
+
self.args = [pathname.expand_path.to_s] if pathname.directory?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
Carat.settings.send("set_#{scope}", name, args.join(" "))
|
|
77
|
+
else
|
|
78
|
+
Carat.ui.error "Invalid scope --#{scope} given. Please use --local or --global."
|
|
79
|
+
exit 1
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
class CLI::Console
|
|
3
|
+
attr_reader :options, :group
|
|
4
|
+
def initialize(options, group)
|
|
5
|
+
@options = options
|
|
6
|
+
@group = group
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def run
|
|
10
|
+
group ? Carat.require(:default, *(group.split.map! {|g| g.to_sym })) : Carat.require
|
|
11
|
+
ARGV.clear
|
|
12
|
+
|
|
13
|
+
console = get_console(Carat.settings[:console] || 'irb')
|
|
14
|
+
console.start
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def get_console(name)
|
|
18
|
+
require name
|
|
19
|
+
get_constant(name)
|
|
20
|
+
rescue LoadError
|
|
21
|
+
Carat.ui.error "Couldn't load console #{name}"
|
|
22
|
+
get_constant('irb')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def get_constant(name)
|
|
26
|
+
const_name = {
|
|
27
|
+
'pry' => :Pry,
|
|
28
|
+
'ripl' => :Ripl,
|
|
29
|
+
'irb' => :IRB,
|
|
30
|
+
}[name]
|
|
31
|
+
Object.const_get(const_name)
|
|
32
|
+
rescue NameError
|
|
33
|
+
Carat.ui.error "Could not find constant #{const_name}"
|
|
34
|
+
exit 1
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Carat
|
|
2
|
+
class CLI::Exec
|
|
3
|
+
attr_reader :options, :args, :cmd
|
|
4
|
+
|
|
5
|
+
def initialize(options, args)
|
|
6
|
+
@options = options
|
|
7
|
+
@cmd = args.shift
|
|
8
|
+
@args = args
|
|
9
|
+
|
|
10
|
+
if RUBY_VERSION >= "2.0"
|
|
11
|
+
@args << { :close_others => !options.keep_file_descriptors? }
|
|
12
|
+
elsif options.keep_file_descriptors?
|
|
13
|
+
Carat.ui.warn "Ruby version #{RUBY_VERSION} defaults to keeping non-standard file descriptors on Kernel#exec."
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
raise ArgumentError if cmd.nil?
|
|
19
|
+
|
|
20
|
+
# First, try to exec directly to something in PATH
|
|
21
|
+
SharedHelpers.set_bundle_environment
|
|
22
|
+
bin_path = Carat.which(@cmd)
|
|
23
|
+
if bin_path
|
|
24
|
+
Kernel.exec(bin_path, *args)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# If that didn't work, set up the whole bundle
|
|
28
|
+
Carat.definition.validate_ruby!
|
|
29
|
+
Carat.load.setup_environment
|
|
30
|
+
Kernel.exec(@cmd, *args)
|
|
31
|
+
rescue Errno::EACCES
|
|
32
|
+
Carat.ui.error "carat: not executable: #{cmd}"
|
|
33
|
+
exit 126
|
|
34
|
+
rescue Errno::ENOENT
|
|
35
|
+
Carat.ui.error "carat: command not found: #{cmd}"
|
|
36
|
+
Carat.ui.warn "Install missing gem executables with `carat install`"
|
|
37
|
+
exit 127
|
|
38
|
+
rescue ArgumentError
|
|
39
|
+
Carat.ui.error "carat: exec needs a command to run"
|
|
40
|
+
exit 128
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
module Carat
|
|
4
|
+
class CLI::Gem
|
|
5
|
+
attr_reader :options, :gem_name, :thor, :name, :target
|
|
6
|
+
|
|
7
|
+
def initialize(options, gem_name, thor)
|
|
8
|
+
@options = options
|
|
9
|
+
@gem_name = resolve_name(gem_name)
|
|
10
|
+
@thor = thor
|
|
11
|
+
|
|
12
|
+
@name = @gem_name
|
|
13
|
+
@target = Pathname.pwd.join(gem_name)
|
|
14
|
+
|
|
15
|
+
validate_ext_name if options[:ext]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def run
|
|
19
|
+
Carat.ui.confirm "Creating gem '#{name}'..."
|
|
20
|
+
|
|
21
|
+
underscored_name = name.tr('-', '_')
|
|
22
|
+
namespaced_path = name.tr('-', '/')
|
|
23
|
+
constant_name = name.gsub(/-[_-]*(?![_-]|$)/){ '::' }.gsub(/([_-]+|(::)|^)(.|$)/){ $2.to_s + $3.upcase }
|
|
24
|
+
constant_array = constant_name.split('::')
|
|
25
|
+
|
|
26
|
+
git_user_name = `git config user.name`.chomp
|
|
27
|
+
git_user_email = `git config user.email`.chomp
|
|
28
|
+
|
|
29
|
+
config = {
|
|
30
|
+
:name => name,
|
|
31
|
+
:underscored_name => underscored_name,
|
|
32
|
+
:namespaced_path => namespaced_path,
|
|
33
|
+
:makefile_path => "#{underscored_name}/#{underscored_name}",
|
|
34
|
+
:constant_name => constant_name,
|
|
35
|
+
:constant_array => constant_array,
|
|
36
|
+
:author => git_user_name.empty? ? "TODO: Write your name" : git_user_name,
|
|
37
|
+
:email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email,
|
|
38
|
+
:test => options[:test],
|
|
39
|
+
:ext => options[:ext],
|
|
40
|
+
:bin => options[:bin],
|
|
41
|
+
:carat_version => carat_dependency_version
|
|
42
|
+
}
|
|
43
|
+
ensure_safe_gem_name(name, constant_array)
|
|
44
|
+
|
|
45
|
+
templates = {
|
|
46
|
+
"Gemfile.tt" => "Gemfile",
|
|
47
|
+
"gitignore.tt" => ".gitignore",
|
|
48
|
+
"lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb",
|
|
49
|
+
"lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb",
|
|
50
|
+
"newgem.gemspec.tt" => "#{name}.gemspec",
|
|
51
|
+
"Rakefile.tt" => "Rakefile",
|
|
52
|
+
"README.md.tt" => "README.md",
|
|
53
|
+
"bin/console.tt" => "bin/console",
|
|
54
|
+
"bin/setup.tt" => "bin/setup"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
executables = %w[
|
|
58
|
+
bin/console
|
|
59
|
+
bin/setup
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?",
|
|
63
|
+
"Codes of conduct can increase contributions to your project by contributors who " \
|
|
64
|
+
"prefer collaborative, safe spaces. You can read more about the code of conduct at " \
|
|
65
|
+
"contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \
|
|
66
|
+
"of enforcing it, so be sure that you are prepared to do that. For suggestions about " \
|
|
67
|
+
"how to enforce codes of conduct, see bit.ly/coc-enforcement."
|
|
68
|
+
)
|
|
69
|
+
templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?",
|
|
73
|
+
"This means that any other developer or company will be legally allowed to use your code " \
|
|
74
|
+
"for free as long as they admit you created it. You can read more about the MIT license " \
|
|
75
|
+
"at choosealicense.com/licenses/mit."
|
|
76
|
+
)
|
|
77
|
+
config[:mit] = true
|
|
78
|
+
templates.merge!("LICENSE.txt.tt" => "LICENSE.txt")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if test_framework = ask_and_set_test_framework
|
|
82
|
+
templates.merge!(".travis.yml.tt" => ".travis.yml")
|
|
83
|
+
|
|
84
|
+
case test_framework
|
|
85
|
+
when 'rspec'
|
|
86
|
+
templates.merge!(
|
|
87
|
+
"rspec.tt" => ".rspec",
|
|
88
|
+
"spec/spec_helper.rb.tt" => "spec/spec_helper.rb",
|
|
89
|
+
"spec/newgem_spec.rb.tt" => "spec/#{namespaced_path}_spec.rb"
|
|
90
|
+
)
|
|
91
|
+
when 'minitest'
|
|
92
|
+
templates.merge!(
|
|
93
|
+
"test/minitest_helper.rb.tt" => "test/minitest_helper.rb",
|
|
94
|
+
"test/test_newgem.rb.tt" => "test/test_#{namespaced_path}.rb"
|
|
95
|
+
)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
templates.merge!("exe/newgem.tt" => "exe/#{name}") if options[:bin]
|
|
100
|
+
|
|
101
|
+
if options[:ext]
|
|
102
|
+
templates.merge!(
|
|
103
|
+
"ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb",
|
|
104
|
+
"ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h",
|
|
105
|
+
"ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c"
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
templates.each do |src, dst|
|
|
110
|
+
thor.template("newgem/#{src}", target.join(dst), config)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
executables.each do |file|
|
|
114
|
+
path = target.join(file)
|
|
115
|
+
executable = (path.stat.mode | 0111)
|
|
116
|
+
path.chmod(executable)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
Carat.ui.info "Initializing git repo in #{target}"
|
|
120
|
+
Dir.chdir(target) { `git init`; `git add .` }
|
|
121
|
+
|
|
122
|
+
if options[:edit]
|
|
123
|
+
# Open gemspec in editor
|
|
124
|
+
thor.run("#{options["edit"]} \"#{target.join("#{name}.gemspec")}\"")
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
def resolve_name(name)
|
|
131
|
+
Pathname.pwd.join(name).basename.to_s
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def ask_and_set(key, header, message)
|
|
135
|
+
choice = options[key] || Carat.settings["gem.#{key}"]
|
|
136
|
+
|
|
137
|
+
if choice.nil?
|
|
138
|
+
Carat.ui.confirm header
|
|
139
|
+
choice = Carat.ui.yes? "#{message} y/(n):"
|
|
140
|
+
Carat.settings.set_global("gem.#{key}", choice)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
choice
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def validate_ext_name
|
|
147
|
+
return unless gem_name.index('-')
|
|
148
|
+
|
|
149
|
+
Carat.ui.error "You have specified a gem name which does not conform to the \n" \
|
|
150
|
+
"naming guidelines for C extensions. For more information, \n" \
|
|
151
|
+
"see the 'Extension Naming' section at the following URL:\n" \
|
|
152
|
+
"http://guides.rubygems.org/gems-with-extensions/\n"
|
|
153
|
+
exit 1
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def ask_and_set_test_framework
|
|
157
|
+
test_framework = options[:test] || Carat.settings["gem.test"]
|
|
158
|
+
|
|
159
|
+
if test_framework.nil?
|
|
160
|
+
Carat.ui.confirm "Do you want to generate tests with your gem?"
|
|
161
|
+
result = Carat.ui.ask "Type 'rspec' or 'minitest' to generate those test files now and " \
|
|
162
|
+
"in the future. rspec/minitest/(none):"
|
|
163
|
+
if result =~ /rspec|minitest/
|
|
164
|
+
test_framework = result
|
|
165
|
+
else
|
|
166
|
+
test_framework = false
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
if Carat.settings["gem.test"].nil?
|
|
171
|
+
Carat.settings.set_global("gem.test", test_framework)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
test_framework
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def carat_dependency_version
|
|
178
|
+
v = Gem::Version.new(Carat::VERSION)
|
|
179
|
+
req = v.segments[0..1]
|
|
180
|
+
req << 'a' if v.prerelease?
|
|
181
|
+
req.join(".")
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def ensure_safe_gem_name name, constant_array
|
|
185
|
+
if name =~ /^\d/
|
|
186
|
+
Carat.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers."
|
|
187
|
+
exit 1
|
|
188
|
+
elsif constant_array.inject(Object) {|c, s| (c.const_defined?(s) && c.const_get(s)) || break }
|
|
189
|
+
Carat.ui.error "Invalid gem name #{name} constant #{constant_array.join("::")} is already in use. Please choose another gem name."
|
|
190
|
+
exit 1
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
end
|