hobo-inviqa 0.0.2

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 (56) hide show
  1. data/Gemfile +4 -0
  2. data/Gemfile.lock +93 -0
  3. data/Guardfile +14 -0
  4. data/Hobofile +34 -0
  5. data/Rakefile +2 -0
  6. data/bin/hobo +23 -0
  7. data/features/deps.feature +43 -0
  8. data/features/hobo/basic.feature +30 -0
  9. data/features/hobo/help.feature +12 -0
  10. data/features/hobo/subcommands.feature +16 -0
  11. data/features/seed/plant.feature +64 -0
  12. data/features/step_definitions/seed.rb +11 -0
  13. data/features/support/env.rb +6 -0
  14. data/features/vm.feature +0 -0
  15. data/hobo.gemspec +37 -0
  16. data/lib/hobo.rb +44 -0
  17. data/lib/hobo/cli.rb +185 -0
  18. data/lib/hobo/config/file.rb +21 -0
  19. data/lib/hobo/error_handlers/debug.rb +9 -0
  20. data/lib/hobo/error_handlers/friendly.rb +52 -0
  21. data/lib/hobo/errors.rb +60 -0
  22. data/lib/hobo/help_formatter.rb +111 -0
  23. data/lib/hobo/helper/file_locator.rb +39 -0
  24. data/lib/hobo/helper/shell.rb +59 -0
  25. data/lib/hobo/lib/seed/project.rb +41 -0
  26. data/lib/hobo/lib/seed/replacer.rb +57 -0
  27. data/lib/hobo/lib/seed/seed.rb +43 -0
  28. data/lib/hobo/metadata.rb +28 -0
  29. data/lib/hobo/patches/rake.rb +56 -0
  30. data/lib/hobo/patches/slop.rb +22 -0
  31. data/lib/hobo/paths.rb +49 -0
  32. data/lib/hobo/tasks/debug.rb +22 -0
  33. data/lib/hobo/tasks/deps.rb +45 -0
  34. data/lib/hobo/tasks/seed.rb +43 -0
  35. data/lib/hobo/tasks/tools.rb +13 -0
  36. data/lib/hobo/tasks/vm.rb +49 -0
  37. data/lib/hobo/ui.rb +96 -0
  38. data/lib/hobo/util.rb +7 -0
  39. data/lib/hobo/version.rb +3 -0
  40. data/spec/hobo/cli_spec.rb +135 -0
  41. data/spec/hobo/config/file_spec.rb +48 -0
  42. data/spec/hobo/error_handlers/debug_spec.rb +10 -0
  43. data/spec/hobo/error_handlers/friendly_spec.rb +81 -0
  44. data/spec/hobo/error_spec.rb +0 -0
  45. data/spec/hobo/help_formatter_spec.rb +131 -0
  46. data/spec/hobo/helpers/file_locator_spec.rb +7 -0
  47. data/spec/hobo/helpers/shell_spec.rb +7 -0
  48. data/spec/hobo/lib/seed/project_spec.rb +83 -0
  49. data/spec/hobo/lib/seed/replacer_spec.rb +47 -0
  50. data/spec/hobo/lib/seed/seed_spec.rb +95 -0
  51. data/spec/hobo/metadata_spec.rb +46 -0
  52. data/spec/hobo/patches/rake_spec.rb +0 -0
  53. data/spec/hobo/paths_spec.rb +77 -0
  54. data/spec/hobo/ui_spec.rb +64 -0
  55. data/spec/spec_helper.rb +6 -0
  56. metadata +355 -0
data/lib/hobo/cli.rb ADDED
@@ -0,0 +1,185 @@
1
+ module Hobo
2
+
3
+ class Halt < Error
4
+ end
5
+
6
+ class Cli
7
+ attr_accessor :slop, :help_formatter
8
+
9
+ def initialize opts = {}
10
+ @opts = opts
11
+ @slop = opts[:slop] || Slop.new
12
+ @help_formatter = opts[:help] || Hobo::HelpFormatter.new(@slop)
13
+ @help_opts = {}
14
+ end
15
+
16
+ def start argv = ARGV
17
+ load_hobofile
18
+
19
+ tasks = structure_tasks Hobo::Metadata.metadata.keys
20
+ args = fix_args_with_equals argv
21
+ define_global_opts @slop
22
+
23
+ begin
24
+ # Parse out global args first
25
+ @slop.parse! args
26
+ opts = @slop.to_hash
27
+ @help_opts[:all] = opts[:all]
28
+ Hobo.ui.interactive = !(opts[:'non-interactive'] == true)
29
+
30
+ @slop.add_callback :empty do
31
+ show_help
32
+ end
33
+
34
+ # Necessary to make command level help work
35
+ args.push "--help" if @slop.help?
36
+
37
+ @help_formatter.command_map = define_tasks(tasks, @slop)
38
+
39
+ remaining = @slop.parse! args
40
+ raise Hobo::InvalidCommandOrOpt.new remaining.join(" "), self if remaining.size > 0
41
+
42
+ show_help if @slop.help?
43
+ rescue Halt
44
+ # NOP
45
+ end
46
+
47
+ return 0
48
+ end
49
+
50
+ def show_help(opts = {})
51
+ Hobo.ui.info @help_formatter.help(@help_opts.merge(opts))
52
+ halt
53
+ end
54
+
55
+ private
56
+
57
+ def load_hobofile
58
+ if Hobo.in_project? && File.exists?(Hobo.hobofile_path)
59
+ load Hobo.hobofile_path
60
+ end
61
+ end
62
+
63
+ def define_global_opts slop
64
+ slop.on '--debug', 'Enable debugging'
65
+ slop.on '-a', '--all', 'Show hidden commands'
66
+ slop.on '-h', '--help', 'Display help'
67
+ slop.on '--non-interactive', 'Run non-interactively. Defaults will be automaticall used where possible.'
68
+
69
+ slop.on '-v', '--version', 'Print version information' do
70
+ Hobo.ui.info "Hobo version #{Hobo::VERSION}"
71
+ halt
72
+ end
73
+ end
74
+
75
+ def halt
76
+ raise Halt.new
77
+ end
78
+
79
+ def define_tasks structured_list, scope, stack = [], map = {}
80
+ structured_list.each do |k, v|
81
+ name = (stack + [k]).join(':')
82
+ new_stack = stack + [k]
83
+ map[name] = if v.size == 0
84
+ define_command(name, scope, new_stack)
85
+ else
86
+ define_namespace(name, scope, new_stack, v, map)
87
+ end
88
+ end
89
+ return map
90
+ end
91
+
92
+ # Map rake namespace to a Slop command
93
+ def define_namespace name, scope, stack, subtasks, map
94
+ metadata = Hobo::Metadata.metadata[name]
95
+ hobo = self
96
+ new_scope = nil
97
+
98
+ scope.instance_eval do
99
+ new_scope = command stack.last do
100
+
101
+ description metadata[:desc]
102
+ long_description metadata[:long_desc]
103
+ hidden metadata[:hidden]
104
+ project_only metadata[:project_only]
105
+
106
+ # NOP; run runs help anyway
107
+ on '-h', '--help', 'Display help' do end
108
+
109
+ run do |opts, args|
110
+ hobo.show_help(target: name)
111
+ end
112
+ end
113
+ end
114
+
115
+ define_tasks subtasks, new_scope, stack, map
116
+ return new_scope
117
+ end
118
+
119
+ # Map rake task to a Slop command
120
+ def define_command name, scope, stack
121
+ metadata = Hobo::Metadata.metadata[name]
122
+ hobo = self
123
+ new_scope = nil
124
+
125
+ scope.instance_eval do
126
+ new_scope = command stack.last do
127
+ task = Rake::Task[name]
128
+
129
+ description metadata[:desc]
130
+ long_description metadata[:long_desc]
131
+ arg_list task.arg_names
132
+ hidden metadata[:hidden]
133
+ project_only metadata[:project_only]
134
+
135
+ metadata[:opts].each do |opt|
136
+ on *opt
137
+ end if metadata[:opts]
138
+
139
+ on '-h', '--help', 'Display help' do
140
+ hobo.show_help(target: name)
141
+ end
142
+
143
+ run do |opts, args|
144
+ raise ::Hobo::ProjectOnlyError.new if opts.project_only && !Hobo.in_project?
145
+ task.opts = opts.to_hash
146
+ raise ::Hobo::MissingArgumentsError.new(name, args, hobo) if args && task.arg_names.length > args.length
147
+ task.invoke *args
148
+ args.pop(task.arg_names.size)
149
+ task.opts = nil
150
+ end
151
+ end
152
+ end
153
+
154
+ return new_scope
155
+ end
156
+
157
+ # Expand flat task list in to hierarchy (non-recursive)
158
+ def structure_tasks list
159
+ out = {}
160
+ list.each do |name|
161
+ ref = out
162
+ name = name.split(":")
163
+ name.each do |n|
164
+ ref[n] ||= {}
165
+ ref = ref[n]
166
+ end
167
+ end
168
+ out
169
+ end
170
+
171
+ # Slop badly handles assignment args passed as --arg=val
172
+ # This hack fixes that by making them --arg val
173
+ def fix_args_with_equals args
174
+ items = []
175
+ args.each do |item|
176
+ if item.match /^-.*\=/
177
+ item.split('=').each { |i| items.push i }
178
+ else
179
+ items.push item
180
+ end
181
+ end
182
+ return items
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,21 @@
1
+ require 'yaml'
2
+
3
+ module Hobo
4
+ module Config
5
+ class File
6
+ def self.save(file, config)
7
+ dir = ::File.dirname file
8
+ FileUtils.mkdir_p dir unless ::File.exists? dir
9
+ ::File.open(file, 'w+') do |f|
10
+ f.puts config.to_yaml
11
+ end
12
+ end
13
+
14
+ def self.load(file)
15
+ config = ::File.exists?(file) ? YAML.load_file(file) : {}
16
+ raise "Invalid hobo configuration (#{file})" unless config
17
+ return config
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ module Hobo
2
+ module ErrorHandlers
3
+ class Debug
4
+ def handle error
5
+ raise error
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,52 @@
1
+ require 'tmpdir' # Needed for Dir.tmpdir
2
+
3
+ module Hobo
4
+ module ErrorHandlers
5
+ class Friendly
6
+ def handle error
7
+ log_file = File.join(Dir.tmpdir, 'hobo_error.log')
8
+
9
+ # Not possible to match Interrupt class unless we use class name as string for some reason!
10
+ case error.class.to_s
11
+ when "Interrupt"
12
+ Hobo.ui.warning "\n\nCaught Interrupt. Aborting\n"
13
+ return 1
14
+ when "Hobo::ExternalCommandError"
15
+ FileUtils.cp error.output.path, log_file
16
+ Hobo.ui.error <<-ERROR
17
+
18
+ The following external command appears to have failed (exit status #{error.exit_code}):
19
+ #{error.command}
20
+
21
+ The output of the command has been logged to #{log_file}
22
+ ERROR
23
+ return 3
24
+ when "Hobo::InvalidCommandOrOpt"
25
+ Hobo.ui.error "\n#{error.message}"
26
+ Hobo.ui.info error.cli.help_formatter.help if error.cli
27
+ return 4
28
+ when "Hobo::MissingArgumentsError"
29
+ Hobo.ui.error "\n#{error.message}"
30
+ Hobo.ui.info error.cli.help_formatter.help(target: error.command) if error.cli
31
+ return 5
32
+ when "Hobo::UserError"
33
+ Hobo.ui.error "\n#{error.message}\n"
34
+ return 6
35
+ when "Hobo::ProjectOnlyError"
36
+ Hobo.ui.error "\nHobo requires you to be in a project directory for this command!\n"
37
+ return 7
38
+ else
39
+ File.write(log_file, "(#{error.class}) #{error.message}\n\n#{error.backtrace.join("\n")}")
40
+ Hobo.ui.error <<-ERROR
41
+
42
+ An unexpected error has occured:
43
+ #{error.message}
44
+
45
+ The backtrace has been logged to #{log_file}
46
+ ERROR
47
+ return 128
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,60 @@
1
+ module Hobo
2
+ class Error < StandardError
3
+ end
4
+
5
+ class RubyVersionError < Error
6
+ def initialize
7
+ super("Ruby 1.9+ is required to run hobo")
8
+ end
9
+ end
10
+
11
+ class MissingDependencies < Error
12
+ def initialize deps
13
+ deps.map! { |dep| " - #{dep}"}
14
+ super("Hobo requires the following commands to be available on your path:\n\n" + deps.join("\n"))
15
+ end
16
+ end
17
+
18
+ class InvalidCommandOrOpt < Error
19
+ attr_accessor :command, :cli
20
+ def initialize command, cli = nil
21
+ @command = command
22
+ @cli = cli
23
+ super("Invalid command or option specified: '#{command}'")
24
+ end
25
+ end
26
+
27
+ class MissingArgumentsError < Error
28
+ attr_accessor :command, :cli
29
+ def initialize command, args, cli = nil
30
+ @command = command
31
+ @args = args
32
+ @cli = cli
33
+ super("Not enough arguments for #{command}")
34
+ end
35
+ end
36
+
37
+ class ExternalCommandError < Error
38
+ attr_accessor :command, :exit_code, :output
39
+
40
+ def initialize command, exit_code, output
41
+ @command = command
42
+ @exit_code = exit_code
43
+ @output = output
44
+ super("'#{command}' returned exit code #{exit_code}")
45
+ end
46
+ end
47
+
48
+ class UserError < Error
49
+ end
50
+
51
+ class ProjectOnlyError < Error
52
+ end
53
+
54
+ class NonInteractiveError < Error
55
+ def initialize question
56
+ @question = question
57
+ super("A task requested input from user but hobo is in non-interactive mode")
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,111 @@
1
+ module Hobo
2
+ class HelpFormatter
3
+ attr_accessor :command_map
4
+ ALIGN_PAD = 4
5
+
6
+ def initialize global
7
+ @global = global
8
+ @command_map = {}
9
+ end
10
+
11
+ def help opts = {}
12
+ target = opts[:target] || nil
13
+ output = [""]
14
+
15
+ command = @command_map[target]
16
+
17
+ if !command
18
+ command_opts = []
19
+ commands = commands_for(@global, opts)
20
+ command = @global
21
+ else
22
+ command_opts = options_for(command)
23
+ commands = commands_for(command, opts)
24
+ end
25
+
26
+ global_opts = options_for(@global)
27
+
28
+ align_to = longest([global_opts, command_opts, commands]) + ALIGN_PAD
29
+
30
+ if command != @global
31
+ description = [ command.long_description, command.description ].compact.first
32
+ output.push Hobo.ui.color("#{description}\n", :description) if description
33
+ end
34
+
35
+ output.push section("Usage", [usage(command, target)])
36
+ output.push section("Global options", global_opts, align_to)
37
+ output.push section("Command options", command_opts, align_to)
38
+ output.push section("Commands", commands, align_to)
39
+
40
+ return output.compact.join("\n")
41
+ end
42
+
43
+ private
44
+
45
+ def longest inputs
46
+ inputs.map do |input|
47
+ next unless input.is_a? Array
48
+ if input.size == 0
49
+ 0
50
+ else
51
+ input.map(&:first).map(&:size).max
52
+ end
53
+ end.compact.max
54
+ end
55
+
56
+ def options_for source
57
+ heads = source.options.reject(&:tail?)
58
+ tails = (source.options - heads)
59
+
60
+ (heads + tails).map do |opt|
61
+ next if source != @global && opt.short == 'h'
62
+ line = padded(opt.short ? "-#{opt.short}," : "", 4)
63
+
64
+ if opt.long
65
+ value = opt.config[:argument] ? "#{opt.long.upcase}" : ""
66
+ value = "[#{value}]" if opt.accepts_optional_argument?
67
+ value = "=#{value}" unless value.empty?
68
+
69
+ line += "--#{opt.long}#{value}"
70
+ end
71
+
72
+ [Hobo.ui.color(line, :opt), opt.description]
73
+ end.compact
74
+ end
75
+
76
+ def commands_for source, opts = {}
77
+ source.commands.map do |name, command|
78
+ next if command.hidden && !opts[:all]
79
+ next unless command.hidden == false || command.description || opts[:all]
80
+ [Hobo.ui.color(name, :command), command.description]
81
+ end.compact
82
+ end
83
+
84
+ def usage source, command = nil
85
+ banner = source.banner
86
+ if banner.nil?
87
+ arg_list = (source.arg_list || []).map do |arg|
88
+ "<#{arg}>"
89
+ end
90
+
91
+ banner = "#{File.basename($0, '.*')}"
92
+ banner << " [command]" if source.commands.any? && command.nil?
93
+ banner << " #{command.split(':').join(' ')}" if command
94
+ banner << " #{arg_list.join(' ')}" if arg_list.size > 0
95
+ banner << " [options]"
96
+ end
97
+ end
98
+
99
+ def section title, contents, align_to = false
100
+ return nil if contents.empty?
101
+ output = Hobo.ui.color("#{title}:\n", :help_title)
102
+ output += contents.map do |line|
103
+ line.is_a?(String) ? " #{line}" : " #{padded(line[0], align_to)}#{line[1]}"
104
+ end.join("\n") + "\n"
105
+ end
106
+
107
+ def padded str, target
108
+ str + (' ' * (target - str.size))
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,39 @@
1
+ require 'open3'
2
+
3
+ module Hobo
4
+ module Helper
5
+ def locate(pattern, opts = {}, &block)
6
+ match = nil
7
+
8
+ Dir.chdir Hobo.project_path do
9
+ match = locate_git(pattern, false, &block)
10
+ match = locate_git(pattern, true, &block) if !match
11
+ end
12
+
13
+ return true if match
14
+
15
+ Hobo.ui.warning opts[:missing] if opts[:missing]
16
+ return false
17
+ end
18
+
19
+ private
20
+
21
+ def locate_git pattern, others, &block
22
+ args = [ 'git', 'ls-files', pattern ]
23
+ args.push '-o' if others
24
+ output = Hobo::Helper.shell *args, :capture => true
25
+ path = output.split("\n")[0]
26
+
27
+ unless path.nil?
28
+ path.strip!
29
+ Dir.chdir File.dirname(path) do
30
+ yield path
31
+ end
32
+
33
+ return true
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ include Hobo::Helper