rubycut-babushka 0.10.6

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.
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