rubycut-babushka 0.10.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +31 -0
  3. data/README.markdown +246 -0
  4. data/Rakefile +26 -0
  5. data/bin/babushka +11 -0
  6. data/deps/babushka.rb +101 -0
  7. data/deps/dev.rb +12 -0
  8. data/deps/fhs.rb +31 -0
  9. data/deps/git.rb +29 -0
  10. data/deps/homebrew.rb +30 -0
  11. data/deps/os_x.rb +33 -0
  12. data/deps/packages.rb +22 -0
  13. data/deps/pkg_managers.rb +110 -0
  14. data/deps/ruby.rb +23 -0
  15. data/deps/rubygems.rb +24 -0
  16. data/deps/system.rb +10 -0
  17. data/deps/templates/app.rb +68 -0
  18. data/deps/templates/external.rb +12 -0
  19. data/deps/templates/installer.rb +31 -0
  20. data/deps/templates/managed.rb +105 -0
  21. data/deps/templates/ppa.rb +24 -0
  22. data/deps/templates/src.rb +42 -0
  23. data/deps/templates/tmbundle.rb +15 -0
  24. data/lib/babushka.rb +28 -0
  25. data/lib/babushka/accepts_block_for.rb +72 -0
  26. data/lib/babushka/accepts_list_for.rb +49 -0
  27. data/lib/babushka/accepts_value_for.rb +24 -0
  28. data/lib/babushka/base.rb +78 -0
  29. data/lib/babushka/bug_reporter.rb +55 -0
  30. data/lib/babushka/cmdline.rb +133 -0
  31. data/lib/babushka/cmdline/handler.rb +41 -0
  32. data/lib/babushka/cmdline/helpers.rb +127 -0
  33. data/lib/babushka/cmdline/parser.rb +69 -0
  34. data/lib/babushka/colorizer.rb +59 -0
  35. data/lib/babushka/core_patches/array.rb +171 -0
  36. data/lib/babushka/core_patches/blank.rb +22 -0
  37. data/lib/babushka/core_patches/bytes.rb +52 -0
  38. data/lib/babushka/core_patches/hash.rb +107 -0
  39. data/lib/babushka/core_patches/hashish.rb +14 -0
  40. data/lib/babushka/core_patches/integer.rb +25 -0
  41. data/lib/babushka/core_patches/io.rb +8 -0
  42. data/lib/babushka/core_patches/numeric.rb +16 -0
  43. data/lib/babushka/core_patches/object.rb +27 -0
  44. data/lib/babushka/core_patches/string.rb +116 -0
  45. data/lib/babushka/core_patches/symbol.rb +12 -0
  46. data/lib/babushka/core_patches/try.rb +15 -0
  47. data/lib/babushka/core_patches/uri.rb +24 -0
  48. data/lib/babushka/dep.rb +470 -0
  49. data/lib/babushka/dep_context.rb +18 -0
  50. data/lib/babushka/dep_definer.rb +115 -0
  51. data/lib/babushka/dep_pool.rb +49 -0
  52. data/lib/babushka/dep_runner.rb +85 -0
  53. data/lib/babushka/dsl.rb +26 -0
  54. data/lib/babushka/git_repo.rb +185 -0
  55. data/lib/babushka/helpers/git_helpers.rb +32 -0
  56. data/lib/babushka/helpers/log_helpers.rb +176 -0
  57. data/lib/babushka/helpers/path_helpers.rb +34 -0
  58. data/lib/babushka/helpers/run_helpers.rb +145 -0
  59. data/lib/babushka/helpers/shell_helpers.rb +229 -0
  60. data/lib/babushka/helpers/suggest_helpers.rb +16 -0
  61. data/lib/babushka/helpers/uri_helpers.rb +36 -0
  62. data/lib/babushka/ip.rb +160 -0
  63. data/lib/babushka/lambda_chooser.rb +40 -0
  64. data/lib/babushka/levenshtein.rb +125 -0
  65. data/lib/babushka/meta_dep.rb +65 -0
  66. data/lib/babushka/meta_dep_context.rb +15 -0
  67. data/lib/babushka/parameter.rb +143 -0
  68. data/lib/babushka/pkg_helper.rb +81 -0
  69. data/lib/babushka/pkg_helpers/apt_helper.rb +61 -0
  70. data/lib/babushka/pkg_helpers/base_helper.rb +19 -0
  71. data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +48 -0
  72. data/lib/babushka/pkg_helpers/binports_helper.rb +34 -0
  73. data/lib/babushka/pkg_helpers/brew_helper.rb +110 -0
  74. data/lib/babushka/pkg_helpers/gem_helper.rb +120 -0
  75. data/lib/babushka/pkg_helpers/macports_helper.rb +22 -0
  76. data/lib/babushka/pkg_helpers/npm_helper.rb +45 -0
  77. data/lib/babushka/pkg_helpers/pacman_helper.rb +27 -0
  78. data/lib/babushka/pkg_helpers/pip_helper.rb +45 -0
  79. data/lib/babushka/pkg_helpers/src_helper.rb +16 -0
  80. data/lib/babushka/pkg_helpers/yum_helper.rb +25 -0
  81. data/lib/babushka/popen.rb +40 -0
  82. data/lib/babushka/prompt.rb +176 -0
  83. data/lib/babushka/renderable.rb +67 -0
  84. data/lib/babushka/resource.rb +215 -0
  85. data/lib/babushka/run_reporter.rb +60 -0
  86. data/lib/babushka/shell.rb +108 -0
  87. data/lib/babushka/source.rb +216 -0
  88. data/lib/babushka/source_pool.rb +146 -0
  89. data/lib/babushka/system_definitions.rb +97 -0
  90. data/lib/babushka/system_profile.rb +210 -0
  91. data/lib/babushka/task.rb +142 -0
  92. data/lib/babushka/vars.rb +108 -0
  93. data/lib/babushka/version_of.rb +65 -0
  94. data/lib/babushka/version_str.rb +57 -0
  95. data/lib/babushka/xml_string.rb +28 -0
  96. data/lib/components.rb +82 -0
  97. data/lib/fancypath/fancypath.rb +200 -0
  98. data/lib/inkan/inkan.rb +76 -0
  99. data/spec/acceptance/acceptance.rb +43 -0
  100. data/spec/acceptance_helper.rb +113 -0
  101. data/spec/archives/Blah.app.zip +0 -0
  102. data/spec/archives/archive.tar +0 -0
  103. data/spec/archives/archive.tar.bz2 +0 -0
  104. data/spec/archives/archive.tar.gz +0 -0
  105. data/spec/archives/archive.tbz2 +0 -0
  106. data/spec/archives/archive.tgz +0 -0
  107. data/spec/archives/archive.zip +0 -0
  108. data/spec/archives/content.txt +5 -0
  109. data/spec/archives/invalid_archive +5 -0
  110. data/spec/archives/nested archive/content.txt +5 -0
  111. data/spec/archives/nested_archive.tar +0 -0
  112. data/spec/archives/really_a_gzip.zip +0 -0
  113. data/spec/archives/test-0.3.1.tgz +0 -0
  114. data/spec/archives/tgz_archive +0 -0
  115. data/spec/archives/zip_without_extension +0 -0
  116. data/spec/babushka/accepts_for_spec.rb +174 -0
  117. data/spec/babushka/accepts_for_support.rb +72 -0
  118. data/spec/babushka/cmdline/console_spec.rb +11 -0
  119. data/spec/babushka/cmdline/help_spec.rb +61 -0
  120. data/spec/babushka/cmdline/version_spec.rb +10 -0
  121. data/spec/babushka/core_patches_spec.rb +171 -0
  122. data/spec/babushka/dep_context_spec.rb +58 -0
  123. data/spec/babushka/dep_definer_spec.rb +152 -0
  124. data/spec/babushka/dep_definer_support.rb +36 -0
  125. data/spec/babushka/dep_spec.rb +567 -0
  126. data/spec/babushka/dep_support.rb +29 -0
  127. data/spec/babushka/deps_spec.rb +113 -0
  128. data/spec/babushka/gem_helper_spec.rb +90 -0
  129. data/spec/babushka/git_repo_spec.rb +396 -0
  130. data/spec/babushka/ip_spec.rb +131 -0
  131. data/spec/babushka/lambda_chooser_spec.rb +115 -0
  132. data/spec/babushka/meta_dep_definer_spec.rb +127 -0
  133. data/spec/babushka/meta_dep_wrapper_spec.rb +32 -0
  134. data/spec/babushka/parameter_spec.rb +135 -0
  135. data/spec/babushka/path_helpers_spec.rb +102 -0
  136. data/spec/babushka/prompt_spec.rb +188 -0
  137. data/spec/babushka/renderable_spec.rb +100 -0
  138. data/spec/babushka/resource_spec.rb +141 -0
  139. data/spec/babushka/run_helpers_spec.rb +26 -0
  140. data/spec/babushka/shell_helpers_spec.rb +244 -0
  141. data/spec/babushka/shell_spec.rb +19 -0
  142. data/spec/babushka/source_pool_spec.rb +320 -0
  143. data/spec/babushka/source_pool_support.rb +31 -0
  144. data/spec/babushka/source_spec.rb +382 -0
  145. data/spec/babushka/source_support.rb +17 -0
  146. data/spec/babushka/system_profile_spec.rb +61 -0
  147. data/spec/babushka/task_spec.rb +141 -0
  148. data/spec/babushka/uri_spec.rb +13 -0
  149. data/spec/babushka/vars_spec.rb +59 -0
  150. data/spec/babushka/version_of_spec.rb +110 -0
  151. data/spec/babushka/version_str_spec.rb +130 -0
  152. data/spec/babushka/version_str_support.rb +37 -0
  153. data/spec/babushka/xml_string_spec.rb +98 -0
  154. data/spec/deps/bad/broken.rb +7 -0
  155. data/spec/deps/bad/working.rb +3 -0
  156. data/spec/deps/good/meta.rb +14 -0
  157. data/spec/deps/good/test.rb +11 -0
  158. data/spec/deps/outer/deps.rb +19 -0
  159. data/spec/deps/outer/more deps.rb +11 -0
  160. data/spec/deps/params/params.rb +10 -0
  161. data/spec/fancypath/fancypath_spec.rb +272 -0
  162. data/spec/fancypath_support.rb +10 -0
  163. data/spec/inkan/inkan_spec.rb +217 -0
  164. data/spec/renderable/different_example.conf.erb +4 -0
  165. data/spec/renderable/example.conf.erb +3 -0
  166. data/spec/renderable/example.sh +6 -0
  167. data/spec/renderable/with_binding.conf.erb +4 -0
  168. data/spec/renderable/xml_example.conf.erb +8 -0
  169. data/spec/repos/remote.git.tgz +0 -0
  170. data/spec/spec_helper.rb +87 -0
  171. metadata +238 -0
@@ -0,0 +1,24 @@
1
+ dep 'python-software-properties.managed' do
2
+ provides 'add-apt-repository'
3
+ end
4
+
5
+ meta :ppa do
6
+ accepts_value_for :adds
7
+ template {
8
+ requires 'python-software-properties.managed'
9
+ met? {
10
+ Dir.glob("/etc/apt/sources.list.d/*").any? {|f|
11
+ f.p.read[Regexp.new('https?://' + adds.gsub(':', '.*') + '/ubuntu ')]
12
+ }
13
+ }
14
+ before {
15
+ adds[/^\w+\:\w+/] or log_error("'#{adds}' doesn't look like 'ppa:something'.")
16
+ }
17
+ meet {
18
+ sudo "sudo add-apt-repository #{adds}"
19
+ }
20
+ after {
21
+ Babushka::Base.host.pkg_helper.update_pkg_lists "Updating apt lists to load #{adds}."
22
+ }
23
+ }
24
+ end
@@ -0,0 +1,42 @@
1
+ meta :src do
2
+ accepts_list_for :source
3
+ accepts_list_for :extra_source
4
+ accepts_list_for :provides, :basename
5
+ accepts_value_for :prefix, '/usr/local'
6
+
7
+ accepts_block_for(:preconfigure) {
8
+ if './configure'.p.exists?
9
+ true # No preconfigure needed
10
+ elsif !'./configure.in'.p.exists? && !'./configure.ac'.p.exists?
11
+ true # Not pre-configurable
12
+ else
13
+ log_shell "autoconf", "autoconf"
14
+ end
15
+ }
16
+ accepts_block_for(:configure) { log_shell "configure", default_configure_command }
17
+ accepts_list_for :configure_env
18
+ accepts_list_for :configure_args
19
+
20
+ accepts_block_for(:build) { log_shell "build", "make" }
21
+ accepts_block_for(:install) { Babushka::SrcHelper.install_src! 'make install' }
22
+ accepts_block_for(:postinstall)
23
+
24
+ accepts_block_for(:process_source) {
25
+ call_task(:preconfigure) and
26
+ call_task(:configure) and
27
+ call_task(:build) and
28
+ call_task(:install) and
29
+ call_task(:postinstall)
30
+ }
31
+
32
+ def default_configure_command
33
+ "#{configure_env.map(&:to_s).join} ./configure --prefix=#{prefix} #{configure_args.map(&:to_s).join(' ')}"
34
+ end
35
+
36
+ template {
37
+ requires 'build tools', 'curl.managed'
38
+ prepare { setup_source_uris }
39
+ met? { in_path?(provides) }
40
+ meet { process_sources { call_task :process_source } }
41
+ }
42
+ end
@@ -0,0 +1,15 @@
1
+ meta :tmbundle, :for => :osx do
2
+ accepts_value_for :source
3
+
4
+ def path
5
+ '~/Library/Application Support/TextMate/Bundles' / name
6
+ end
7
+
8
+ template {
9
+ requires 'benhoskings:TextMate.app'
10
+ met? { path.dir? }
11
+ before { shell "mkdir -p '#{path.parent}'" }
12
+ meet { git source, :to => path }
13
+ after { log_shell "Telling TextMate to reload bundles", %Q{osascript -e 'tell app "TextMate" to reload bundles'} }
14
+ }
15
+ end
data/lib/babushka.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Babushka
2
+ VERSION = '0.10.6'
3
+ WorkingPrefix = '~/.babushka'
4
+ SourcePrefix = '~/.babushka/sources'
5
+ BuildPrefix = '~/.babushka/build'
6
+ DownloadPrefix = '~/.babushka/downloads'
7
+ LogPrefix = '~/.babushka/logs'
8
+ VarsPrefix = '~/.babushka/vars'
9
+ ReportPrefix = '~/.babushka/runs'
10
+
11
+ module Path
12
+ def self.binary() File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__ end
13
+ def self.bin() File.dirname(binary) end
14
+ # this is not correct in gem version
15
+ def self.path() File.dirname(bin) end
16
+ def self.lib() File.join(path, 'lib') end
17
+ def self.run_from_path?() ENV['PATH'].split(':').include? File.dirname($0) end
18
+ end
19
+ end
20
+
21
+ # First, load the component lists.
22
+ require File.join(Babushka::Path.path, 'lib', 'components')
23
+
24
+ # Load external components that babushka depends on.
25
+ Babushka::ExternalComponents.each {|c| require File.join(Babushka::Path.path, 'lib', c) }
26
+
27
+ # Next, load babushka itself.
28
+ Babushka::Components.each {|c| require File.join(Babushka::Path.path, 'lib/babushka', c) }
@@ -0,0 +1,72 @@
1
+ module Babushka
2
+ module AcceptsBlockFor
3
+ def self.included base
4
+ base.send :extend, ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def default_blocks
9
+ merged_default_blocks_for self
10
+ end
11
+ def merged_default_blocks_for klass
12
+ parent_values = klass == DepDefiner ? {} : merged_default_blocks_for(klass.superclass)
13
+ parent_values.merge(default_blocks_for(klass))
14
+ end
15
+ def default_blocks_for klass
16
+ (@@default_blocks ||= Hashish.hash)[klass]
17
+ end
18
+
19
+ def accepted_blocks
20
+ default_blocks.keys
21
+ end
22
+
23
+ def accepts_block_for method_name, &default_block
24
+ default_blocks_for(self)[method_name] = default_block
25
+ class_eval %Q{
26
+ def #{method_name} *args, &block
27
+ payload[#{method_name.inspect}] ||= {}
28
+ if block.nil?
29
+ block_for #{method_name.inspect}
30
+ else
31
+ store_block_for #{method_name.inspect}, args, block
32
+ end
33
+ end
34
+ }
35
+ end
36
+ end
37
+
38
+ def has_block? block_name
39
+ payload[block_name] ||= {}
40
+ !!specific_block_for(block_name)
41
+ end
42
+
43
+ def default_block_for block_name
44
+ differentiator = Base.host.differentiator_for payload[block_name].keys
45
+ L{
46
+ debug "#{block_name} not defined#{" for #{differentiator}" unless differentiator.nil?}."
47
+ true
48
+ }
49
+ end
50
+
51
+ def default_blocks
52
+ self.class.default_blocks
53
+ end
54
+
55
+ def store_block_for method_name, args, block
56
+ raise "#{method_name} only accepts args like :on => :linux (as well as a block arg)." unless args.empty? || args.first.is_a?(Hash)
57
+
58
+ payload[method_name] ||= {}
59
+ chosen_on = (args.first || {})[:on] || @current_platform || :all
60
+ payload[method_name][chosen_on] = block
61
+ end
62
+
63
+ def block_for method_name
64
+ specific_block_for(method_name) or default_block_for(method_name)
65
+ end
66
+
67
+ def specific_block_for method_name
68
+ payload[method_name][(Base.host.match_list & payload[method_name].keys).first] ||
69
+ default_blocks[method_name]
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,49 @@
1
+ module Babushka
2
+ module AcceptsListFor
3
+ def self.included base
4
+ base.send :extend, ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def accepts_list_for method_name, *args
9
+ opts = {:type => 'list'}.merge args.extract_options!
10
+ default = args.shift
11
+
12
+ file, line = caller.first.split(':', 2)
13
+ line = line.to_i
14
+
15
+ module_eval <<-LOL, file, line
16
+ def #{method_name} *args, &block
17
+ if !args.empty? && !block.nil?
18
+ raise ArgumentError, "You can supply arguments or a block, but not both."
19
+ elsif args.empty? && block.nil?
20
+ #{opts[:type]}_for #{method_name.inspect}, #{default.inspect}
21
+ else
22
+ store_#{opts[:type]}_for #{method_name.inspect}, block || [*args].flatten, #{opts[:choose_with].inspect}
23
+ self
24
+ end
25
+ end
26
+ LOL
27
+ end
28
+ end
29
+
30
+ def store_list_for method_name, data, choose_with
31
+ if data.respond_to? :call
32
+ store_list_for method_name, LambdaChooser.new(self, *chooser_choices, &data).choose(chooser, choose_with), choose_with
33
+ else
34
+ (payload[method_name] ||= []).concat(data || [])
35
+ end
36
+ end
37
+
38
+ def list_for method_name, default
39
+ if payload.has_key? method_name
40
+ payload[method_name].map {|i| i.respond_to?(:call) ? i.call : i }.compact
41
+ else
42
+ # Splatting on expressions instead of just a single token seems
43
+ # to break the result in rubinius. https://gist.github.com/1173301
44
+ values = default.is_a?(Symbol) ? send(default) : (default || [])
45
+ [*values]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ module Babushka
2
+ module AcceptsValueFor
3
+ def self.included base
4
+ base.send :extend, ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def accepts_value_for method_name, *args
9
+ opts = args.extract_options!
10
+ accepts_list_for method_name, *args.push(opts.merge(:type => 'value'))
11
+ end
12
+ end
13
+
14
+ def store_value_for method_name, data, choose_with
15
+ raise "Multiple values for #{method_name}" if data.respond_to?(:length) && data.length > 1
16
+ payload.delete(method_name) # otherwise new values would be #concat'ed and ignored.
17
+ store_list_for method_name, data, choose_with
18
+ end
19
+
20
+ def value_for method_name, default
21
+ list_for(method_name, default).first
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,78 @@
1
+ module Babushka
2
+ class Base
3
+ class << self
4
+
5
+ # +task+ represents the overall job that is being run, and the parts that
6
+ # are external to running the corresponding dep tree itself - logging, and
7
+ # var loading and saving in particular.
8
+ def task
9
+ Task.instance
10
+ end
11
+
12
+ # +cmdline+ is an instance of +Cmdline::Parser+ that represents the arguments
13
+ # that were passed via the commandline. It handles parsing those arguments,
14
+ # and choosing the task to perform based on the 'verb' supplied - e.g. 'meet',
15
+ # 'list', etc.
16
+ def cmdline
17
+ @cmdline ||= Cmdline::Parser.for(ARGV)
18
+ end
19
+
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
+ def host
28
+ @host ||= Babushka::SystemProfile.for_host
29
+ end
30
+
31
+ # +sources+ is an instance of Babushka::SourcePool, contains all the
32
+ # sources that babushka can currently load deps from. This means all the sources
33
+ # found in ~/.babushka/sources, plus the default sources:
34
+ # - anonymous (no source file; i.e. deps defined in an +irb+ session,
35
+ # or similar)
36
+ # - core (the builtin deps that babushka uses to install itself)
37
+ # - current dir (the contents of ./babushka-deps)
38
+ # - personal (the contents of ~/.babushka/deps)
39
+ def sources
40
+ SourcePool.instance
41
+ end
42
+
43
+ def threads
44
+ @threads ||= []
45
+ end
46
+
47
+ def in_thread &block
48
+ threads.push Thread.new(&block)
49
+ end
50
+
51
+ # The top-level entry point for babushka runs invoked at the command line.
52
+ # When the `babushka` command is run, bin/babushka.rb first triggers a load
53
+ # via lib/babushka.rb, and then calls this method.
54
+ def run
55
+ cmdline.run
56
+ ensure
57
+ threads.each(&:join)
58
+ end
59
+
60
+ def exit_on_interrupt!
61
+ if $stdin.tty?
62
+ stty_save = `stty -g`.chomp
63
+ trap("INT") {
64
+ system "stty", stty_save
65
+ unless Base.task.callstack.empty?
66
+ puts "\n#{Logging.closing_log_message("#{Base.task.callstack.first.contextual_name} (cancelled)", false, :closing_status => true)}"
67
+ end
68
+ exit false
69
+ }
70
+ end
71
+ end
72
+
73
+ def program_name
74
+ @program_name ||= ENV['PATH'].split(':').include?(File.dirname($0)) ? File.basename($0) : $0
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,55 @@
1
+ module Babushka
2
+ class BugReporter
3
+ extend LogHelpers
4
+ extend ShellHelpers
5
+
6
+ # This method creates a bug report for +dep+, by reading the debug log and
7
+ # vars associated with it and posting them as a gist. If the github user is
8
+ # set in the git config, it's marked as from that user, otherwise it's
9
+ # anonymous.
10
+ def self.report dep
11
+ Prompt.confirm "I can file a bug report for that now, if you like.", :default => 'n', :otherwise => "OK, you're on your own :)" do
12
+ post_report dep,
13
+ (which('git') && shell('git config github.user')) || 'anonymous',
14
+ Base.task.var_path_for(dep).read,
15
+ Base.task.log_path_for(dep).read
16
+ end
17
+ end
18
+
19
+
20
+ private
21
+
22
+ # gist.github.com API example at http://gist.github.com/4277
23
+ def self.post_report dep, user, vars, log
24
+ require 'net/http'
25
+ require 'uri'
26
+
27
+ Net::HTTP.post_form(
28
+ URI.parse('http://gist.github.com/api/v1/xml/new'), {
29
+ "files[from]" => user,
30
+ "files[vars.yml]" => vars,
31
+ "files[#{dep.contextual_name}.log]" => log.decolorize
32
+ }
33
+ ).tap {|response|
34
+ report_report_result dep, response
35
+ }.is_a? Net::HTTPSuccess
36
+ end
37
+
38
+ def self.report_report_result dep, response
39
+ if response.is_a? Net::HTTPSuccess
40
+ gist_id = response.body.scan(/<repo>(\d+)<\/repo>/).flatten.first
41
+ if gist_id.nil?
42
+ log "Done, but the report's URL couldn't be parsed. Here's some info:"
43
+ log response.body
44
+ else
45
+ log "You can view the report at http://gist.github.com/#{gist_id} - thanks :)"
46
+ end
47
+ else
48
+ log "Deary me, the bug report couldn't be submitted! Would you mind emailing these two files:"
49
+ log ' ' + Base.task.var_path_for(dep)
50
+ log ' ' + Base.task.log_path_for(dep)
51
+ log "to ben@hoskings.net? Thanks."
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,133 @@
1
+ # coding: utf-8
2
+
3
+ module Babushka
4
+ module Cmdline
5
+ extend LogHelpers
6
+
7
+ handle('global', "Options that are valid for any handler") {
8
+ opt '-v', '--version', "Print the current version"
9
+ opt '-h', '--help', "Show this information"
10
+ opt '-d', '--debug', "Show more verbose logging, and realtime shell command output"
11
+ opt '--[no-]color',
12
+ '--[no-]colour', "Disable color in the output"
13
+ }
14
+
15
+ handle('help', "Print usage information").run {|cmd|
16
+ Helpers.print_version :full => true
17
+ if cmd.argv.empty?
18
+ Helpers.print_usage
19
+ Helpers.print_handlers
20
+ Helpers.print_notes
21
+ elsif (handler = Handler.for(cmd.argv.first)).nil?
22
+ Helpers.log "#{cmd.argv.first.capitalize}? I have honestly never heard of that."
23
+ else
24
+ Helpers.log "\n#{handler.name} - #{handler.description}"
25
+ cmd.parse(&handler.opt_definer)
26
+ cmd.print_usage
27
+ end
28
+ Helpers.log "\n"
29
+ true
30
+ }
31
+
32
+ handle('version', "Print the current version").run {
33
+ Helpers.print_version
34
+ true
35
+ }
36
+
37
+ handle('list', "List the available deps") {
38
+ opt '-t', '--templates', "List templates instead of deps"
39
+ }.run {|cmd|
40
+ Base.sources.local_only {
41
+ Helpers.generate_list_for(cmd.opts[:templates] ? :templates : :deps, cmd.argv.first)
42
+ }
43
+ }
44
+
45
+ handle('meet', 'The main one: run a dep and all its dependencies.') {
46
+ opt '-n', '--dry-run', "Discover the curent state without making any changes"
47
+ opt '-y', '--defaults', "Assume the default value for all vars without prompting, where possible"
48
+ opt '--show-args', "Show the arguments being passed between deps as they're run"
49
+ opt '--track-blocks', "Track deps' blocks in TextMate as they're run"
50
+ }.run {|cmd|
51
+ # TODO: spec var parsing
52
+ dep_names, vars = cmd.argv.partition {|arg| arg['='].nil? }
53
+ if !(bad_var = vars.detect {|var| var[/^\w+=/].nil? }).nil?
54
+ fail_with "'#{bad_var}' looks like a var but it doesn't make sense."
55
+ elsif dep_names.empty?
56
+ 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
+ else
60
+ Base.task.process dep_names, vars.map {|i|
61
+ i.split('=', 2)
62
+ }.inject({}) {|hsh,i|
63
+ hsh[i.first] = i.last
64
+ hsh
65
+ }
66
+ end
67
+ }
68
+
69
+ handle('sources', "Manage dep sources") {
70
+ opt '-a', '--add NAME URI', "Add the source at URI as NAME"
71
+ opt '-u', '--update', "Update all known sources"
72
+ opt '-l', '--list', "List dep sources"
73
+ }.run {|cmd|
74
+ if cmd.opts.slice(:add, :update, :list).length != 1
75
+ fail_with "'sources' requires a single option."
76
+ elsif cmd.opts.has_key?(:add)
77
+ begin
78
+ Source.new(cmd.argv.first, :name => cmd.opts[:add]).add!
79
+ rescue SourceError => e
80
+ log_error e.message
81
+ end
82
+ elsif cmd.opts.has_key?(:update)
83
+ Base.sources.update!
84
+ elsif cmd.opts.has_key?(:list)
85
+ Base.sources.list!
86
+ end
87
+ }
88
+
89
+ handle('console', "Start an interactive (irb-based) babushka session").run {
90
+ exec "irb -r'#{Path.lib / 'babushka'}' --simple-prompt"
91
+ }
92
+
93
+ handle('search', "Search for deps in the community database").run {|cmd|
94
+ if cmd.argv.length != 1
95
+ fail_with "'search' requires a single argument."
96
+ else
97
+ require 'net/http'
98
+ require 'yaml'
99
+
100
+ search_term = cmd.argv.first
101
+ results = Helpers.search_results_for(search_term)
102
+
103
+ if results.empty?
104
+ log "Never seen a dep with '#{search_term}' in its name."
105
+ else
106
+ Helpers.print_search_results search_term, results
107
+ true
108
+ end
109
+ end
110
+ }
111
+
112
+ handle('edit', "Load the file containing the specified dep in $EDITOR").run {|cmd|
113
+ if cmd.argv.length != 1
114
+ fail_with "'edit' requires a single argument."
115
+ elsif (dep = Dep.find_or_suggest(cmd.argv.first)).nil?
116
+ fail_with "Can't find '#{cmd.argv.first}' to edit."
117
+ elsif dep.load_path.nil?
118
+ fail_with "Can't edit '#{dep.name}, since it wasn't loaded from a file."
119
+ else
120
+ file, line = dep.context.file_and_line
121
+ editor_var = ENV['BABUSHKA_EDITOR'] || ENV['VISUAL'] || ENV['EDITOR'] || which('mate') || which('vim') || which('vi')
122
+ case editor_var
123
+ when /^mate/
124
+ exec "mate -l#{line} '#{file}'"
125
+ when /^vim?/, /^nano/, /^pico/, /^emacs/
126
+ exec "#{editor_var} +#{line} '#{file}'"
127
+ else
128
+ exec "#{editor_var} '#{file}'"
129
+ end
130
+ end
131
+ }
132
+ end
133
+ end