rubycut-babushka 0.10.8 → 0.15.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/Gemfile.lock +17 -15
- data/README.markdown +163 -41
- data/Rakefile +1 -1
- data/bin/babushka +1 -1
- data/deps/apt.rb +44 -0
- data/deps/babushka.rb +54 -42
- data/deps/deprecated.rb +16 -0
- data/deps/dev.rb +28 -3
- data/deps/git.rb +27 -12
- data/deps/homebrew.rb +2 -2
- data/deps/packages.rb +14 -15
- data/deps/pkg_managers.rb +21 -75
- data/deps/ruby.rb +5 -19
- data/deps/rubygems.rb +3 -3
- data/deps/system.rb +2 -2
- data/deps/templates/app.rb +60 -41
- data/deps/templates/bin.rb +16 -0
- data/deps/templates/installer.rb +9 -9
- data/deps/templates/lib.rb +17 -0
- data/deps/templates/managed.rb +1 -38
- data/deps/templates/src.rb +16 -8
- data/deps/templates/task.rb +11 -0
- data/deps/templates/tmbundle.rb +16 -2
- data/lib/babushka.rb +2 -3
- data/lib/babushka/accepts_block_for.rb +5 -3
- data/lib/babushka/asset.rb +172 -0
- data/lib/babushka/base.rb +37 -8
- data/lib/babushka/bug_reporter.rb +6 -6
- data/lib/babushka/cmdline.rb +11 -10
- data/lib/babushka/cmdline/handler.rb +7 -3
- data/lib/babushka/cmdline/helpers.rb +15 -23
- data/lib/babushka/cmdline/parser.rb +1 -1
- data/lib/babushka/core_patches/object.rb +1 -1
- data/lib/babushka/core_patches/string.rb +8 -3
- data/lib/babushka/current_ruby.rb +44 -0
- data/lib/babushka/dep.rb +111 -185
- data/lib/babushka/dep_context.rb +8 -3
- data/lib/babushka/dep_definer.rb +45 -15
- data/lib/babushka/dep_pool.rb +5 -8
- data/lib/babushka/{meta_dep.rb → dep_template.rb} +21 -2
- data/lib/babushka/dsl.rb +3 -0
- data/lib/babushka/git_repo.rb +143 -49
- data/lib/babushka/helpers/git_helpers.rb +7 -6
- data/lib/babushka/helpers/log_helpers.rb +51 -13
- data/lib/babushka/helpers/path_helpers.rb +5 -7
- data/lib/babushka/helpers/run_helpers.rb +15 -55
- data/lib/babushka/helpers/shell_helpers.rb +18 -26
- data/lib/babushka/helpers/uri_helpers.rb +9 -18
- data/lib/babushka/lambda_chooser.rb +20 -13
- data/lib/babushka/parameter.rb +20 -4
- data/lib/babushka/path_checker.rb +72 -0
- data/lib/babushka/pkg_helper.rb +38 -13
- data/lib/babushka/pkg_helpers/apt_helper.rb +15 -8
- data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +15 -14
- data/lib/babushka/pkg_helpers/binports_helper.rb +7 -7
- data/lib/babushka/pkg_helpers/brew_helper.rb +17 -25
- data/lib/babushka/pkg_helpers/gem_helper.rb +36 -27
- data/lib/babushka/pkg_helpers/npm_helper.rb +9 -9
- data/lib/babushka/pkg_helpers/pacman_helper.rb +5 -4
- data/lib/babushka/pkg_helpers/pip_helper.rb +14 -10
- data/lib/babushka/pkg_helpers/unknown_pkg_helper.rb +19 -0
- data/lib/babushka/pkg_helpers/yum_helper.rb +1 -1
- data/lib/babushka/popen.rb +13 -10
- data/lib/babushka/prompt.rb +14 -1
- data/lib/babushka/renderable.rb +11 -9
- data/lib/babushka/resource.rb +5 -166
- data/lib/babushka/run_reporter.rb +12 -3
- data/lib/babushka/shell.rb +54 -44
- data/lib/babushka/source.rb +41 -20
- data/lib/babushka/source_pool.rb +20 -13
- data/lib/babushka/system_definitions.rb +11 -3
- data/lib/babushka/system_detector.rb +31 -0
- data/lib/babushka/system_matcher.rb +53 -0
- data/lib/babushka/system_profile.rb +67 -89
- data/lib/babushka/task.rb +36 -8
- data/lib/babushka/{meta_dep_context.rb → templated_dep_context.rb} +1 -1
- data/lib/babushka/vars.rb +46 -4
- data/lib/babushka/version_of.rb +35 -17
- data/lib/babushka/version_str.rb +12 -8
- data/lib/components.rb +9 -8
- data/lib/fancypath/fancypath.rb +109 -83
- data/lib/inkan/inkan.rb +14 -14
- data/lib/{babushka → levenshtein}/levenshtein.rb +0 -0
- data/spec/acceptance/acceptance.rb +4 -4
- data/spec/acceptance_helper.rb +10 -6
- data/spec/babushka/accepts_for_spec.rb +137 -142
- data/spec/babushka/accepts_for_support.rb +13 -6
- data/spec/babushka/asset_spec.rb +165 -0
- data/spec/babushka/cmdline/help_spec.rb +11 -9
- data/spec/babushka/cmdline/meet_spec.rb +15 -0
- data/spec/babushka/cmdline/version_spec.rb +1 -1
- data/spec/babushka/core_patches_spec.rb +9 -0
- data/spec/babushka/current_ruby_spec.rb +73 -0
- data/spec/babushka/dep_context_spec.rb +27 -13
- data/spec/babushka/dep_definer_spec.rb +108 -16
- data/spec/babushka/dep_spec.rb +87 -104
- data/spec/babushka/dep_template_spec.rb +176 -0
- data/spec/babushka/deps_spec.rb +48 -19
- data/spec/babushka/gem_helper_spec.rb +46 -59
- data/spec/babushka/git_repo_spec.rb +242 -51
- data/spec/babushka/ip_spec.rb +11 -11
- data/spec/babushka/lambda_chooser_spec.rb +47 -9
- data/spec/babushka/parameter_spec.rb +21 -0
- data/spec/babushka/path_checker_spec.rb +35 -0
- data/spec/babushka/path_helpers_spec.rb +51 -50
- data/spec/babushka/prompt_spec.rb +4 -4
- data/spec/babushka/renderable_spec.rb +61 -28
- data/spec/babushka/shell_helpers_spec.rb +110 -85
- data/spec/babushka/shell_spec.rb +15 -0
- data/spec/babushka/source_pool_spec.rb +204 -210
- data/spec/babushka/source_spec.rb +125 -42
- data/spec/babushka/source_support.rb +1 -1
- data/spec/babushka/system_profile_spec.rb +86 -49
- data/spec/babushka/task_spec.rb +80 -13
- data/spec/babushka/vars_spec.rb +2 -1
- data/spec/babushka/version_of_spec.rb +29 -2
- data/spec/babushka/version_str_spec.rb +91 -65
- data/spec/babushka/xml_string_spec.rb +1 -1
- data/spec/deps/bad/broken.rb +2 -2
- data/spec/deps/bad/working.rb +0 -1
- data/spec/deps/good/{meta.rb → template.rb} +0 -0
- data/spec/deps/good/test.rb +0 -3
- data/spec/deps/outer/deps.rb +0 -2
- data/spec/fancypath/fancypath_spec.rb +30 -0
- data/spec/inkan/inkan_spec.rb +34 -32
- data/spec/spec_helper.rb +7 -50
- data/spec/system_detector_spec.rb +70 -0
- metadata +163 -177
- data/deps/os_x.rb +0 -33
- data/deps/templates/ppa.rb +0 -24
- data/lib/babushka/core_patches/io.rb +0 -8
- data/lib/babushka/dep_runner.rb +0 -85
- data/lib/babushka/helpers/suggest_helpers.rb +0 -16
- data/lib/babushka/pkg_helpers/base_helper.rb +0 -19
- data/lib/babushka/pkg_helpers/macports_helper.rb +0 -22
- data/spec/babushka/dep_definer_support.rb +0 -36
- data/spec/babushka/meta_dep_definer_spec.rb +0 -127
- data/spec/babushka/meta_dep_wrapper_spec.rb +0 -32
- data/spec/babushka/resource_spec.rb +0 -141
- data/spec/babushka/run_helpers_spec.rb +0 -26
- data/spec/babushka/source_pool_support.rb +0 -31
data/lib/babushka/base.rb
CHANGED
@@ -1,7 +1,32 @@
|
|
1
1
|
module Babushka
|
2
|
+
|
3
|
+
# +host+ is an instance of Babushka::SystemProfile for the system the command
|
4
|
+
# was invoked on.
|
5
|
+
# If the current system isn't supported, SystemProfile.for_host will return
|
6
|
+
# +nil+, and Base.run will fail early. If the system is known but the
|
7
|
+
# flavour isn't (e.g. an unknown Linux variant), a generic SystemProfile
|
8
|
+
# will be used, which should work for most operations but will fail on deps
|
9
|
+
# that attempt to use the package manager, etc.
|
10
|
+
def host
|
11
|
+
@host ||= Babushka::SystemDetector.profile_for_host
|
12
|
+
end
|
13
|
+
module_function :host
|
14
|
+
|
15
|
+
def ruby
|
16
|
+
@ruby ||= Babushka::CurrentRuby.new
|
17
|
+
end
|
18
|
+
module_function :ruby
|
19
|
+
|
2
20
|
class Base
|
3
21
|
class << self
|
4
22
|
|
23
|
+
# The time at which babushka was loaded. This is used in LogHelpers to
|
24
|
+
# print profiling information via the '--profile' commandline option.
|
25
|
+
@@start_time = Time.now
|
26
|
+
def start_time
|
27
|
+
@@start_time
|
28
|
+
end
|
29
|
+
|
5
30
|
# +task+ represents the overall job that is being run, and the parts that
|
6
31
|
# are external to running the corresponding dep tree itself - logging, and
|
7
32
|
# var loading and saving in particular.
|
@@ -17,15 +42,8 @@ module Babushka
|
|
17
42
|
@cmdline ||= Cmdline::Parser.for(ARGV)
|
18
43
|
end
|
19
44
|
|
20
|
-
# +host+ is an instance of Babushka::SystemProfile for the system the command
|
21
|
-
# was invoked on.
|
22
|
-
# If the current system isn't supported, SystemProfile.for_host will return
|
23
|
-
# +nil+, and Base.run will fail early. If the system is known but the
|
24
|
-
# flavour isn't (e.g. an unknown Linux variant), a generic SystemProfile
|
25
|
-
# will be used, which should work for most operations but will fail on deps
|
26
|
-
# that attempt to use the package manager, etc.
|
27
45
|
def host
|
28
|
-
|
46
|
+
Babushka::LogHelpers.removed! :method_name => 'Babushka::Base.host', :instead => "Babushka.host"
|
29
47
|
end
|
30
48
|
|
31
49
|
# +sources+ is an instance of Babushka::SourcePool, contains all the
|
@@ -70,6 +88,17 @@ module Babushka
|
|
70
88
|
end
|
71
89
|
end
|
72
90
|
|
91
|
+
def runtime_info
|
92
|
+
@runtime_info ||= "babushka@#{ref} | #{ShellHelpers.which('ruby')}@#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def ref
|
96
|
+
@ref ||= begin
|
97
|
+
repo = GitRepo.new(Path.path)
|
98
|
+
repo.current_head if repo.exists?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
73
102
|
def program_name
|
74
103
|
@program_name ||= ENV['PATH'].split(':').include?(File.dirname($0)) ? File.basename($0) : $0
|
75
104
|
end
|
@@ -39,16 +39,16 @@ module Babushka
|
|
39
39
|
if response.is_a? Net::HTTPSuccess
|
40
40
|
gist_id = response.body.scan(/<repo>(\d+)<\/repo>/).flatten.first
|
41
41
|
if gist_id.nil?
|
42
|
-
|
43
|
-
|
42
|
+
log_stderr "Done, but the report's URL couldn't be parsed. Here's some info:"
|
43
|
+
log_stderr response.body
|
44
44
|
else
|
45
45
|
log "You can view the report at http://gist.github.com/#{gist_id} - thanks :)"
|
46
46
|
end
|
47
47
|
else
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
log_stderr "Deary me, the bug report couldn't be submitted! Would you mind emailing these two files:"
|
49
|
+
log_stderr ' ' + Base.task.var_path_for(dep)
|
50
|
+
log_stderr ' ' + Base.task.log_path_for(dep)
|
51
|
+
log_stderr "to ben@hoskings.net? Thanks."
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
data/lib/babushka/cmdline.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
module Babushka
|
4
|
-
|
4
|
+
class Cmdline
|
5
5
|
extend LogHelpers
|
6
6
|
|
7
7
|
handle('global', "Options that are valid for any handler") {
|
8
8
|
opt '-v', '--version', "Print the current version"
|
9
9
|
opt '-h', '--help', "Show this information"
|
10
10
|
opt '-d', '--debug', "Show more verbose logging, and realtime shell command output"
|
11
|
+
opt '-s', '--silent', "Only log errors, running silently on success"
|
11
12
|
opt '--[no-]color',
|
12
13
|
'--[no-]colour', "Disable color in the output"
|
13
14
|
}
|
@@ -19,13 +20,13 @@ module Babushka
|
|
19
20
|
Helpers.print_handlers
|
20
21
|
Helpers.print_notes
|
21
22
|
elsif (handler = Handler.for(cmd.argv.first)).nil?
|
22
|
-
|
23
|
+
log "#{cmd.argv.first.capitalize}? I have honestly never heard of that."
|
23
24
|
else
|
24
|
-
|
25
|
+
log "\n#{handler.name} - #{handler.description}"
|
25
26
|
cmd.parse(&handler.opt_definer)
|
26
27
|
cmd.print_usage
|
27
28
|
end
|
28
|
-
|
29
|
+
log "\n"
|
29
30
|
true
|
30
31
|
}
|
31
32
|
|
@@ -45,17 +46,15 @@ module Babushka
|
|
45
46
|
handle('meet', 'The main one: run a dep and all its dependencies.') {
|
46
47
|
opt '-n', '--dry-run', "Discover the curent state without making any changes"
|
47
48
|
opt '-y', '--defaults', "Assume the default value for all vars without prompting, where possible"
|
49
|
+
opt '-u', '--update', "Update referenced sources before loading deps from them"
|
48
50
|
opt '--show-args', "Show the arguments being passed between deps as they're run"
|
49
|
-
opt '--
|
51
|
+
opt '--profile', "Print a per-line timestamp to the debug log."
|
50
52
|
}.run {|cmd|
|
51
|
-
# TODO: spec var parsing
|
52
53
|
dep_names, vars = cmd.argv.partition {|arg| arg['='].nil? }
|
53
54
|
if !(bad_var = vars.detect {|var| var[/^\w+=/].nil? }).nil?
|
54
55
|
fail_with "'#{bad_var}' looks like a var but it doesn't make sense."
|
55
56
|
elsif dep_names.empty?
|
56
57
|
fail_with "Nothing to do."
|
57
|
-
elsif cmd.opts[:track_blocks] && !which('mate')
|
58
|
-
fail_with "The --track-blocks option requires TextMate, and the `mate` helper.\nOn a Mac, you can install them like so:\n babushka benhoskings:textmate"
|
59
58
|
else
|
60
59
|
Base.task.process dep_names, vars.map {|i|
|
61
60
|
i.split('=', 2)
|
@@ -117,9 +116,11 @@ module Babushka
|
|
117
116
|
elsif dep.load_path.nil?
|
118
117
|
fail_with "Can't edit '#{dep.name}, since it wasn't loaded from a file."
|
119
118
|
else
|
120
|
-
file, line = dep.context.
|
121
|
-
editor_var = ENV['BABUSHKA_EDITOR'] || ENV['VISUAL'] || ENV['EDITOR'] || which('mate') || which('vim') || which('vi')
|
119
|
+
file, line = dep.context.source_location
|
120
|
+
editor_var = ENV['BABUSHKA_EDITOR'] || ENV['VISUAL'] || ENV['EDITOR'] || which('subl') || which('mate') || which('vim') || which('vi')
|
122
121
|
case editor_var
|
122
|
+
when /^subl/
|
123
|
+
exec "subl -n '#{file}':#{line}"
|
123
124
|
when /^mate/
|
124
125
|
exec "mate -l#{line} '#{file}'"
|
125
126
|
when /^vim?/, /^nano/, /^pico/, /^emacs/
|
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'abbrev'
|
2
2
|
|
3
3
|
module Babushka
|
4
|
-
|
4
|
+
class Cmdline
|
5
5
|
|
6
|
-
def handle name, description, &blk
|
6
|
+
def self.handle name, description, &blk
|
7
7
|
Handler.add name, description, blk
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
|
+
def self.fail_with message
|
11
|
+
log message
|
12
|
+
exit 1
|
13
|
+
end
|
10
14
|
|
11
15
|
class Handler
|
12
16
|
def self.add name, description, opt_definer
|
@@ -1,27 +1,19 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
module Babushka
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def fail_with message
|
8
|
-
log message if message.is_a? String
|
9
|
-
exit 1
|
10
|
-
end
|
11
|
-
|
12
|
-
module Helpers
|
4
|
+
class Cmdline
|
5
|
+
class Helpers
|
13
6
|
extend LogHelpers
|
14
|
-
module_function
|
15
7
|
|
16
|
-
def print_version opts = {}
|
8
|
+
def self.print_version opts = {}
|
17
9
|
if opts[:full]
|
18
|
-
log "Babushka v#{VERSION}, (c)
|
10
|
+
log "Babushka v#{VERSION} (#{Base.ref}), (c) 2012 Ben Hoskings <ben@hoskings.net>"
|
19
11
|
else
|
20
|
-
log VERSION
|
12
|
+
log "#{VERSION} (#{Base.ref})"
|
21
13
|
end
|
22
14
|
end
|
23
15
|
|
24
|
-
def print_usage
|
16
|
+
def self.print_usage
|
25
17
|
log "\nThe gist:"
|
26
18
|
log " #{Base.program_name} <command> [options]"
|
27
19
|
log "\nAlso:"
|
@@ -30,14 +22,14 @@ module Babushka
|
|
30
22
|
log " #{Base.program_name} babushka # Update babushka itself (what babushka.me/up does)"
|
31
23
|
end
|
32
24
|
|
33
|
-
def print_handlers
|
25
|
+
def self.print_handlers
|
34
26
|
log "\nCommands:"
|
35
27
|
Handler.all.each {|handler|
|
36
28
|
log " #{handler.name.ljust(10)} #{handler.description}"
|
37
29
|
}
|
38
30
|
end
|
39
31
|
|
40
|
-
def print_examples
|
32
|
+
def self.print_examples
|
41
33
|
log "\nExamples:"
|
42
34
|
log " # Inspect the 'system' dep (and all its sub-deps) without touching the system.".colorize('grey')
|
43
35
|
log " #{Base.program_name} system --dry-run"
|
@@ -50,12 +42,12 @@ module Babushka
|
|
50
42
|
log " #{Base.program_name} 'user setup' --debug"
|
51
43
|
end
|
52
44
|
|
53
|
-
def print_notes
|
45
|
+
def self.print_notes
|
54
46
|
log "\nCommands can be abbrev'ed, as long as they remain unique."
|
55
47
|
log " e.g. '#{Base.program_name} l' is short for '#{Base.program_name} list'."
|
56
48
|
end
|
57
49
|
|
58
|
-
def search_results_for q
|
50
|
+
def self.search_results_for q
|
59
51
|
YAML.load(search_webservice_for(q).body).sort_by {|i|
|
60
52
|
-i[:runs_this_week]
|
61
53
|
}.map {|i|
|
@@ -69,7 +61,7 @@ module Babushka
|
|
69
61
|
}
|
70
62
|
end
|
71
63
|
|
72
|
-
def print_search_results search_term, results
|
64
|
+
def self.print_search_results search_term, results
|
73
65
|
log "The webservice knows about #{results.length} dep#{'s' unless results.length == 1} that match#{'es' if results.length == 1} '#{search_term}':"
|
74
66
|
log ""
|
75
67
|
Logging.log_table(
|
@@ -85,17 +77,17 @@ module Babushka
|
|
85
77
|
end
|
86
78
|
end
|
87
79
|
|
88
|
-
def github_autosource_regex
|
89
|
-
|
80
|
+
def self.github_autosource_regex
|
81
|
+
/^\w+\:\/\/github\.com\/(.*)\/babushka-deps(\.git)?/
|
90
82
|
end
|
91
83
|
|
92
|
-
def search_webservice_for q
|
84
|
+
def self.search_webservice_for q
|
93
85
|
Net::HTTP.start('babushka.me') {|http|
|
94
86
|
http.get URI.escape("/deps/search.yaml/#{q}")
|
95
87
|
}
|
96
88
|
end
|
97
89
|
|
98
|
-
def generate_list_for to_list, filter_str
|
90
|
+
def self.generate_list_for to_list, filter_str
|
99
91
|
context = to_list == :deps ? Base.program_name : ':template =>'
|
100
92
|
match_str = filter_str.try(:downcase)
|
101
93
|
Base.sources.all_present.each {|source|
|
@@ -1,14 +1,15 @@
|
|
1
1
|
class String
|
2
|
-
# Return a
|
2
|
+
# Return a DepRequirement that specifies the dep that should later be
|
3
3
|
# called, and the arguments that should be passed. This allows requiring
|
4
4
|
# deps with a less noisy syntax, and the lookup is lazy (it happens at
|
5
|
-
# the point the dep is invoked, from its parent dep in
|
5
|
+
# the point the dep is invoked, from its parent dep in
|
6
|
+
# Dep#process_requirements).
|
6
7
|
#
|
7
8
|
# dep 'user has a password', :username do
|
8
9
|
# requires 'user exists'.with(username)
|
9
10
|
# end
|
10
11
|
def with *args
|
11
|
-
Babushka::
|
12
|
+
Babushka::DepRequirement.new(self, args)
|
12
13
|
end
|
13
14
|
|
14
15
|
# Returns true iff +other+ appears exactly at the start of +self+.
|
@@ -84,6 +85,10 @@ class String
|
|
84
85
|
Babushka::VersionStr.new self
|
85
86
|
end
|
86
87
|
|
88
|
+
def colorized?
|
89
|
+
self[/\e\[\d/]
|
90
|
+
end
|
91
|
+
|
87
92
|
# Return a new string with the contents of this string surrounded in escape
|
88
93
|
# sequences such that it will render as described in +description+.
|
89
94
|
# Some examples:
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Babushka
|
2
|
+
class CurrentRuby
|
3
|
+
|
4
|
+
def path
|
5
|
+
@path ||= Babushka::ShellHelpers.which('ruby').p
|
6
|
+
end
|
7
|
+
|
8
|
+
def rbenv?
|
9
|
+
path.to_s[%r{\brbenv/}]
|
10
|
+
end
|
11
|
+
|
12
|
+
def rvm?
|
13
|
+
path.to_s[%r{\brvm/}]
|
14
|
+
end
|
15
|
+
|
16
|
+
def bin_dir
|
17
|
+
# The directory in which the binaries from gems are found. This is
|
18
|
+
# sometimes different to where `gem` itself is running from.
|
19
|
+
gem_env.val_for('EXECUTABLE DIRECTORY').p
|
20
|
+
end
|
21
|
+
|
22
|
+
def gem_dir
|
23
|
+
gem_env.val_for('INSTALLATION DIRECTORY') / 'gems'
|
24
|
+
end
|
25
|
+
|
26
|
+
def gemspec_dir
|
27
|
+
gem_env.val_for('INSTALLATION DIRECTORY') / 'specifications'
|
28
|
+
end
|
29
|
+
|
30
|
+
def version
|
31
|
+
@_version ||= Babushka::ShellHelpers.shell('ruby --version').scan(/^ruby (\S+)/).flatten.first.to_version
|
32
|
+
end
|
33
|
+
|
34
|
+
def gem_version
|
35
|
+
gem_env.val_for('RUBYGEMS VERSION').to_version
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def gem_env
|
41
|
+
@_gem_env ||= Babushka::ShellHelpers.shell('gem env')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/babushka/dep.rb
CHANGED
@@ -13,31 +13,19 @@ module Babushka
|
|
13
13
|
class DepArgumentError < DepDefinitionError
|
14
14
|
end
|
15
15
|
|
16
|
+
# A DepRequirement is a representation of a dep being called - its name,
|
17
|
+
# along with the arguments that will be passed to it.
|
18
|
+
#
|
19
|
+
# DepRequirement is used internally by babushka when deps are required with
|
20
|
+
# arguments using "name".with(args). This allows babushka to delay loading
|
21
|
+
# the dep in question until the moment it's called.
|
22
|
+
class DepRequirement < Struct.new(:name, :args)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
16
26
|
class Dep
|
17
27
|
include LogHelpers
|
18
28
|
extend LogHelpers
|
19
|
-
include PathHelpers
|
20
|
-
extend SuggestHelpers
|
21
|
-
|
22
|
-
# This class is used for deps that aren't defined against a meta dep. Using
|
23
|
-
# this class with the default values it contains means that the code below
|
24
|
-
# can be simpler, because at the code level everything is defined against
|
25
|
-
# a 'template' of some sort; some are just BaseTemplate, and some are
|
26
|
-
# actual meta deps.
|
27
|
-
class BaseTemplate
|
28
|
-
def self.contextual_name; name end
|
29
|
-
def self.suffixed?; false end
|
30
|
-
def self.context_class; DepContext end
|
31
|
-
end
|
32
|
-
|
33
|
-
# A Requirement is a representation of a dep being called - its name, along
|
34
|
-
# with the arguments that will be passed to it.
|
35
|
-
#
|
36
|
-
# Requirement is used internally by babushka when deps are required with
|
37
|
-
# arguments using "name".with(args). This allows babushka to delay loading
|
38
|
-
# the dep in question until the moment it's called.
|
39
|
-
class Requirement < Struct.new(:name, :args)
|
40
|
-
end
|
41
29
|
|
42
30
|
attr_reader :name, :params, :args, :opts, :vars, :dep_source, :load_path
|
43
31
|
attr_accessor :result_message
|
@@ -48,7 +36,7 @@ module Babushka
|
|
48
36
|
def initialize name, source, params, opts, block
|
49
37
|
if name.empty?
|
50
38
|
raise InvalidDepName, "Deps can't have empty names."
|
51
|
-
elsif
|
39
|
+
elsif /[[:cntrl:]]/mu =~ name
|
52
40
|
raise InvalidDepName, "The dep name '#{name}' contains nonprintable characters."
|
53
41
|
elsif /\// =~ name
|
54
42
|
raise InvalidDepName, "The dep name '#{name}' contains '/', which isn't allowed (logs are named after deps, and filenames can't contain '/')."
|
@@ -66,24 +54,25 @@ module Babushka
|
|
66
54
|
@dep_source = source
|
67
55
|
@load_path = Base.sources.current_load_path
|
68
56
|
@dep_source.deps.register self
|
69
|
-
assign_template if Base.sources.current_real_load_source.nil?
|
70
|
-
@dep_defined = @_cached_process = nil # false represents failure for these two.
|
71
57
|
end
|
72
58
|
end
|
73
59
|
|
74
60
|
def context
|
75
|
-
|
76
|
-
@context
|
61
|
+
@context ||= template.context_class.new(self, &@block)
|
77
62
|
end
|
78
63
|
|
64
|
+
# Attempt to retrieve the template specified in +opts[:template]+. If the
|
65
|
+
# template name includes a source prefix, it is searched for within the
|
66
|
+
# corresponding source. Otherwise, it is searched for in the current source
|
67
|
+
# and the core sources.
|
79
68
|
def template
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
69
|
+
@template ||= if opts[:template]
|
70
|
+
Base.sources.template_for(opts[:template], :from => dep_source).tap {|t|
|
71
|
+
raise TemplateNotFound, "There is no template named '#{opts[:template]}' to define '#{name}' against." if t.nil?
|
72
|
+
}
|
73
|
+
else
|
74
|
+
Base.sources.template_for(suffix, :from => dep_source) || self.class.base_template
|
75
|
+
end
|
87
76
|
end
|
88
77
|
|
89
78
|
# Look up the dep specified by +dep_name+, yielding it to the block if it
|
@@ -93,9 +82,9 @@ module Babushka
|
|
93
82
|
# this same method on the one chosen by the user, if any.
|
94
83
|
def self.find_or_suggest dep_name, opts = {}, &block
|
95
84
|
if (dep = Dep(dep_name, opts)).nil?
|
96
|
-
|
97
|
-
|
98
|
-
|
85
|
+
log_stderr "#{dep_name.to_s.colorize 'grey'} #{"<- this dep isn't defined!".colorize('red')}"
|
86
|
+
suggestions = Base.sources.current_names.similar_to(dep_name.to_s)
|
87
|
+
log "Perhaps you meant #{suggestions.map {|s| "'#{s}'" }.to_list(:conj => 'or')}?".colorize('grey') if suggestions.any?
|
99
88
|
elsif block.nil?
|
100
89
|
dep
|
101
90
|
else
|
@@ -135,7 +124,11 @@ module Babushka
|
|
135
124
|
# suffix, if any. Unlike +#basename+, this method will return anything that
|
136
125
|
# looks like a template suffix, even if it doesn't match a template.
|
137
126
|
def suffix
|
138
|
-
name.scan(
|
127
|
+
name.scan(DepTemplate::TEMPLATE_NAME_MATCH).flatten.first
|
128
|
+
end
|
129
|
+
|
130
|
+
def cache_key
|
131
|
+
DepRequirement.new(name, @params.map {|p| @args[p].try(:current_value) })
|
139
132
|
end
|
140
133
|
|
141
134
|
def with *args
|
@@ -146,6 +139,7 @@ module Babushka
|
|
146
139
|
end.map_values {|k,v|
|
147
140
|
Parameter.for(k, v)
|
148
141
|
}
|
142
|
+
@context = nil # To re-evaluate parameter.default() and friends.
|
149
143
|
self
|
150
144
|
end
|
151
145
|
|
@@ -156,15 +150,13 @@ module Babushka
|
|
156
150
|
# altering the system. It can cause failures, though, because some deps
|
157
151
|
# have requirements that need to be met before the dep can perform its
|
158
152
|
# +met?+ check.
|
159
|
-
#
|
160
|
-
# TODO: In future, there will be support for specifying that in the DSL.
|
161
153
|
def met? *args
|
162
|
-
with(*args).process :dry_run => true
|
154
|
+
with(*args).process :dry_run => true
|
163
155
|
end
|
164
156
|
|
165
157
|
# Entry point for a full met?/meet +#process+ run.
|
166
158
|
def meet *args
|
167
|
-
with(*args).process :dry_run => false
|
159
|
+
with(*args).process :dry_run => false
|
168
160
|
end
|
169
161
|
|
170
162
|
# Trigger a dep run with this dep at the top of the tree.
|
@@ -195,7 +187,7 @@ module Babushka
|
|
195
187
|
# example, if a dep detects that the existing version of a package is
|
196
188
|
# broken in some way that requires manual intervention, then there's no
|
197
189
|
# use running the +meet+ block. In this circumstance, you can call
|
198
|
-
# +#unmeetable
|
190
|
+
# +#unmeetable!+, which raises an +UnmeetableDep+ exception. Babushka will
|
199
191
|
# rescue it and consider the dep unmeetable (that is, it will just allow
|
200
192
|
# the dep to fail without attempting to meet it).
|
201
193
|
#
|
@@ -222,64 +214,21 @@ module Babushka
|
|
222
214
|
# webserver is running, for example by using `netstat` to check that
|
223
215
|
# something is listening on port 80.
|
224
216
|
def process with_opts = {}
|
225
|
-
task.
|
226
|
-
(cached? ? cached_result : process_and_cache).tap {
|
227
|
-
Base.sources.uncache! if with_opts[:top_level]
|
228
|
-
}
|
229
|
-
end
|
230
|
-
|
231
|
-
private
|
232
|
-
|
233
|
-
def define_or_complain!
|
234
|
-
@dep_defined = begin
|
235
|
-
define!
|
236
|
-
rescue StandardError => e
|
237
|
-
log_exception_in_dep(e)
|
238
|
-
false
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
# Attempt to look up the template this dep was defined against (or if no
|
243
|
-
# template was specified, BaseTemplate), and then define the dep against
|
244
|
-
# it. If an error occurs, the backtrace point within the dep from which the
|
245
|
-
# exception was triggered is logged, as well as the actual exception point.
|
246
|
-
def define!
|
247
|
-
if dep_defined?
|
248
|
-
debug "#{name}: already defined."
|
249
|
-
elsif dep_defined? == false
|
250
|
-
debug "#{name}: defining already failed."
|
251
|
-
elsif template
|
252
|
-
debug "(defining #{name} against #{template.contextual_name})"
|
253
|
-
define_dep!
|
254
|
-
end
|
255
|
-
dep_defined?
|
217
|
+
Base.task.cache { process_with_caching(with_opts) }
|
256
218
|
end
|
257
219
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
@dep_defined = true
|
220
|
+
def process_with_caching with_opts = {}
|
221
|
+
Base.task.opts.update with_opts
|
222
|
+
Base.task.cached(
|
223
|
+
cache_key, :hit => lambda {|value| log_cached(value) }
|
224
|
+
) {
|
225
|
+
log logging_name, :closing_status => (Base.task.opt(:dry_run) ? :dry_run : true) do
|
226
|
+
process!
|
227
|
+
end
|
228
|
+
}
|
268
229
|
end
|
269
230
|
|
270
|
-
|
271
|
-
# template name includes a source prefix, it is searched for within the
|
272
|
-
# corresponding source. Otherwise, it is searched for in the current source
|
273
|
-
# and the core sources.
|
274
|
-
def assign_template
|
275
|
-
@template = if opts[:template]
|
276
|
-
Base.sources.template_for(opts[:template], :from => dep_source).tap {|t|
|
277
|
-
raise TemplateNotFound, "There is no template named '#{opts[:template]}' to define '#{name}' against." if t.nil?
|
278
|
-
}
|
279
|
-
else
|
280
|
-
Base.sources.template_for(suffix, :from => dep_source) || self.class.base_template
|
281
|
-
end
|
282
|
-
end
|
231
|
+
private
|
283
232
|
|
284
233
|
def self.base_template
|
285
234
|
BaseTemplate
|
@@ -301,32 +250,22 @@ module Babushka
|
|
301
250
|
if !args.empty? && args.length != params.length
|
302
251
|
raise DepArgumentError, "The dep '#{name}' accepts #{params.length} argument#{'s' unless params.length == 1}, but #{args.length} #{args.length == 1 ? 'was' : 'were'} passed."
|
303
252
|
end
|
304
|
-
params.
|
253
|
+
Hash[params.zip(args)]
|
305
254
|
end
|
306
255
|
|
307
|
-
def
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
task.callstack.push self
|
320
|
-
process_this_dep.tap {
|
321
|
-
task.callstack.pop
|
322
|
-
}
|
323
|
-
end
|
256
|
+
def process!
|
257
|
+
if context.failed?
|
258
|
+
log_error "This dep previously failed to load."
|
259
|
+
elsif Base.task.callstack.include? self
|
260
|
+
log_error "Oh crap, endless loop! (#{Base.task.callstack.push(self).drop_while {|dep| dep != self }.map(&:name).join(' -> ')})"
|
261
|
+
elsif !opts[:for].nil? && !Babushka.host.matches?(opts[:for])
|
262
|
+
log_ok "Not required on #{Babushka.host.differentiator_for opts[:for]}."
|
263
|
+
else
|
264
|
+
Base.task.callstack.push self
|
265
|
+
process_tree.tap {
|
266
|
+
Base.task.callstack.pop
|
267
|
+
}
|
324
268
|
end
|
325
|
-
end
|
326
|
-
|
327
|
-
def process_this_dep
|
328
|
-
process_task(:setup)
|
329
|
-
process_deps and process_self
|
330
269
|
rescue UnmeetableDep => e
|
331
270
|
log_error e.message
|
332
271
|
log "I don't know how to fix that, so it's up to you. :)"
|
@@ -337,32 +276,53 @@ module Babushka
|
|
337
276
|
nil
|
338
277
|
end
|
339
278
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
279
|
+
# Process the tree descending from this dep (first the dependencies, then
|
280
|
+
# the dep itself).
|
281
|
+
def process_tree
|
282
|
+
process_task(:setup)
|
283
|
+
process_requirements and process_self
|
284
|
+
end
|
285
|
+
|
286
|
+
# Process each of the requirements of this dep in order. If this is a dry
|
287
|
+
# run, check every one; otherwise, require success from all and fail fast.
|
288
|
+
#
|
289
|
+
# Each dep recursively processes its own requirements. Hence, this is the
|
290
|
+
# method that recurses down the dep tree.
|
291
|
+
def process_requirements accessor = :requires
|
292
|
+
if Base.task.opt(:dry_run)
|
293
|
+
requirements_for(accessor).map {|r| process_requirement(r) }.all?
|
294
|
+
else
|
295
|
+
requirements_for(accessor).all? {|r| process_requirement(r) }
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def process_requirement requirement
|
300
|
+
Dep.find_or_suggest requirement.name, :from => dep_source do |dep|
|
301
|
+
dep.with(*requirement.args).process_with_caching
|
345
302
|
end
|
303
|
+
rescue SourceLoadError => e
|
304
|
+
Babushka::Logging.log_exception(e)
|
346
305
|
end
|
347
306
|
|
307
|
+
# Process this dep, assuming all its requirements are satisfied. This is
|
308
|
+
# the method that implements the met? -> meet -> met? logic that is what
|
309
|
+
# deps are all about. For details, see the documentation for Dep#process.
|
348
310
|
def process_self
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
311
|
+
process_met_task(:initial => true) {
|
312
|
+
if Base.task.opt(:dry_run)
|
313
|
+
false # unmet
|
314
|
+
else
|
315
|
+
process_task(:prepare)
|
316
|
+
if !process_requirements(:requires_when_unmet)
|
317
|
+
false # install-time deps unmet
|
353
318
|
else
|
354
|
-
|
355
|
-
|
356
|
-
false # install-time deps unmet
|
357
|
-
else
|
358
|
-
log 'meet' do
|
359
|
-
process_task(:before) and process_task(:meet) and process_task(:after)
|
360
|
-
end
|
361
|
-
process_met_task
|
319
|
+
log 'meet' do
|
320
|
+
process_task(:before) and process_task(:meet) and process_task(:after)
|
362
321
|
end
|
322
|
+
process_met_task
|
363
323
|
end
|
364
|
-
|
365
|
-
|
324
|
+
end
|
325
|
+
}
|
366
326
|
end
|
367
327
|
|
368
328
|
def process_met_task task_opts = {}, &block
|
@@ -372,7 +332,7 @@ module Babushka
|
|
372
332
|
end
|
373
333
|
|
374
334
|
def run_met_task task_opts = {}
|
375
|
-
|
335
|
+
process_task(:met?).tap {|result|
|
376
336
|
log result_message, :as => (:error unless result || task_opts[:initial]) unless result_message.nil?
|
377
337
|
self.result_message = nil
|
378
338
|
}
|
@@ -380,16 +340,15 @@ module Babushka
|
|
380
340
|
|
381
341
|
def process_task task_name
|
382
342
|
# log "calling #{name} / #{task_name}"
|
383
|
-
|
384
|
-
context.instance_eval(&context.send(task_name))
|
343
|
+
context.invoke(task_name)
|
385
344
|
end
|
386
345
|
|
387
346
|
def requirements_for list_name
|
388
347
|
context.send(list_name).map {|dep_or_requirement|
|
389
|
-
if dep_or_requirement.is_a?(
|
348
|
+
if dep_or_requirement.is_a?(DepRequirement)
|
390
349
|
dep_or_requirement
|
391
350
|
else
|
392
|
-
|
351
|
+
DepRequirement.new(dep_or_requirement, [])
|
393
352
|
end
|
394
353
|
}
|
395
354
|
end
|
@@ -403,56 +362,23 @@ module Babushka
|
|
403
362
|
end
|
404
363
|
|
405
364
|
def log_exception_in_dep e
|
406
|
-
|
365
|
+
Babushka::Logging.log_exception(e)
|
407
366
|
advice = e.is_a?(DepDefinitionError) ? "Looks like a problem with '#{name}' - check" : "Check"
|
408
367
|
log "#{advice} #{(e.backtrace.detect {|l| l[load_path.to_s] } || load_path).sub(/\:in [^:]+$/, '')}." unless load_path.nil?
|
409
|
-
debug e.backtrace * "\n"
|
410
368
|
end
|
411
369
|
|
412
|
-
def
|
413
|
-
if
|
414
|
-
|
415
|
-
|
416
|
-
|
370
|
+
def log_cached result
|
371
|
+
if result
|
372
|
+
log "#{Logging::TickChar} #{name} (cached)".colorize('green')
|
373
|
+
elsif Base.task.opt(:dry_run)
|
374
|
+
log "~ #{name} (cached)".colorize('blue')
|
417
375
|
end
|
418
376
|
end
|
419
377
|
|
420
|
-
def cached_result
|
421
|
-
cached_process.tap {|result|
|
422
|
-
if result
|
423
|
-
log "#{Logging::TickChar} #{name} (cached)".colorize('green')
|
424
|
-
elsif task.opt(:dry_run)
|
425
|
-
log "~ #{name} (cached)".colorize('blue')
|
426
|
-
else
|
427
|
-
log "#{Logging::CrossChar} #{name} (cached)".colorize('red')
|
428
|
-
end
|
429
|
-
}
|
430
|
-
end
|
431
|
-
def cached?
|
432
|
-
!@_cached_process.nil?
|
433
|
-
end
|
434
|
-
def uncache!
|
435
|
-
@_cached_process = nil
|
436
|
-
end
|
437
|
-
def cached_process
|
438
|
-
@_cached_process
|
439
|
-
end
|
440
|
-
def cache_process value
|
441
|
-
@_cached_process = (value.nil? ? false : value)
|
442
|
-
end
|
443
|
-
|
444
378
|
def suffixed?
|
445
379
|
!opts[:template] && template != BaseTemplate
|
446
380
|
end
|
447
381
|
|
448
|
-
def payload
|
449
|
-
context.payload
|
450
|
-
end
|
451
|
-
|
452
|
-
def task
|
453
|
-
Base.task
|
454
|
-
end
|
455
|
-
|
456
382
|
public
|
457
383
|
|
458
384
|
def inspect
|
@@ -460,8 +386,8 @@ module Babushka
|
|
460
386
|
end
|
461
387
|
|
462
388
|
def defined_info
|
463
|
-
if
|
464
|
-
"
|
389
|
+
if context.loaded?
|
390
|
+
"<- [#{context.requires.join(', ')}]"
|
465
391
|
else
|
466
392
|
"(not defined yet)"
|
467
393
|
end
|