hobo-inviqa 0.0.6 → 0.0.7.pre.rc1

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 (60) hide show
  1. checksums.yaml +15 -0
  2. data/.editorconfig +10 -0
  3. data/Gemfile.lock +7 -3
  4. data/Guardfile +2 -2
  5. data/Hobofile +5 -1
  6. data/bin/hobo +12 -18
  7. data/hobo.gemspec +2 -0
  8. data/lib/hobo.rb +8 -1
  9. data/lib/hobo/cli.rb +14 -4
  10. data/lib/hobo/config/file.rb +1 -1
  11. data/lib/hobo/error_handlers/debug.rb +5 -2
  12. data/lib/hobo/error_handlers/exit_code_map.rb +16 -0
  13. data/lib/hobo/error_handlers/friendly.rb +13 -8
  14. data/lib/hobo/errors.rb +11 -1
  15. data/lib/hobo/helper/http_download.rb +41 -0
  16. data/lib/hobo/helper/shell.rb +21 -5
  17. data/lib/hobo/helper/vm_command.rb +127 -17
  18. data/lib/hobo/lib/host_check.rb +20 -6
  19. data/lib/hobo/lib/host_check/deps.rb +22 -4
  20. data/lib/hobo/lib/host_check/git.rb +41 -17
  21. data/lib/hobo/lib/host_check/ruby.rb +30 -20
  22. data/lib/hobo/lib/host_check/vagrant.rb +37 -6
  23. data/lib/hobo/lib/s3sync.rb +23 -40
  24. data/lib/hobo/lib/seed/project.rb +8 -1
  25. data/lib/hobo/lib/seed/seed.rb +15 -3
  26. data/lib/hobo/patches/slop.rb +21 -2
  27. data/lib/hobo/tasks/assets.rb +32 -20
  28. data/lib/hobo/tasks/config.rb +15 -0
  29. data/lib/hobo/tasks/deps.rb +29 -4
  30. data/lib/hobo/tasks/seed.rb +1 -1
  31. data/lib/hobo/tasks/system.rb +15 -0
  32. data/lib/hobo/tasks/system/completions.rb +76 -0
  33. data/lib/hobo/tasks/tools.rb +10 -6
  34. data/lib/hobo/tasks/vm.rb +74 -6
  35. data/lib/hobo/ui.rb +27 -10
  36. data/lib/hobo/util.rb +36 -2
  37. data/lib/hobo/version.rb +2 -2
  38. data/spec/hobo/asset_applicator_spec.rb +2 -2
  39. data/spec/hobo/cli_spec.rb +35 -24
  40. data/spec/hobo/config/file_spec.rb +1 -3
  41. data/spec/hobo/error_handlers/debug_spec.rb +39 -5
  42. data/spec/hobo/error_handlers/friendly_spec.rb +38 -21
  43. data/spec/hobo/help_formatter_spec.rb +3 -3
  44. data/spec/hobo/helpers/file_locator_spec.rb +2 -2
  45. data/spec/hobo/helpers/shell_spec.rb +2 -2
  46. data/spec/hobo/helpers/vm_command_spec.rb +36 -24
  47. data/spec/hobo/lib/s3sync_spec.rb +6 -3
  48. data/spec/hobo/lib/seed/project_spec.rb +2 -3
  49. data/spec/hobo/lib/seed/replacer_spec.rb +1 -2
  50. data/spec/hobo/lib/seed/seed_spec.rb +2 -3
  51. data/spec/hobo/logging_spec.rb +2 -2
  52. data/spec/hobo/metadata_spec.rb +2 -2
  53. data/spec/hobo/null_spec.rb +2 -2
  54. data/spec/hobo/paths_spec.rb +1 -2
  55. data/spec/hobo/ui_spec.rb +104 -20
  56. data/spec/hobo/util_spec.rb +75 -0
  57. data/spec/spec_helper.rb +1 -0
  58. metadata +43 -49
  59. data/lib/hobo/tasks/console.rb +0 -18
  60. data/lib/hobo/tasks/host.rb +0 -17
@@ -20,12 +20,27 @@ module Hobo
20
20
  end
21
21
 
22
22
  def shell *args, &block
23
+ def chunk_line_iterator stream
24
+ begin
25
+ until (chunk = stream.readpartial(1024)).nil? do
26
+ chunk.each_line do |outer_line|
27
+ outer_line.each_line("\r") do |line|
28
+ yield line
29
+ end
30
+ end
31
+ end
32
+ rescue EOFError
33
+ # NOP
34
+ end
35
+ end
36
+
23
37
  opts = (args.size > 1 && args.last.is_a?(Hash)) ? args.pop : {}
24
38
  opts = {
25
39
  :capture => false,
26
40
  :indent => 0,
27
41
  :realtime => false,
28
- :env => {}
42
+ :env => {},
43
+ :ignore_errors => false
29
44
  }.merge! opts
30
45
 
31
46
  Hobo::Logging.logger.debug("helper.shell: Invoking '#{args.join(" ")}' with #{opts.to_s}")
@@ -35,16 +50,17 @@ module Hobo
35
50
  buffer = ::Tempfile.new 'hobo_run_buf'
36
51
  buffer.sync = true
37
52
  threads = [external]
53
+ last_buf = ""
38
54
 
39
55
  ## Create a thread to read from each stream
40
56
  { :out => out, :err => err }.each do |key, stream|
41
57
  threads.push(::Thread.new do
42
- until (line = stream.gets).nil? do
43
- line = ::Hobo.ui.color(line.strip, :error) if key == :err
58
+ chunk_line_iterator stream do |line|
59
+ line = ::Hobo.ui.color(line, :error) if key == :err
44
60
  buffer.write("#{line.strip}\n")
45
61
  Hobo::Logging.logger.debug("helper.shell: #{line.strip}")
46
62
  line = yield line if block
47
- puts indent + line if opts[:realtime] && !line.nil?
63
+ print indent + line if opts[:realtime] && !line.nil?
48
64
  end
49
65
  end)
50
66
  end
@@ -56,7 +72,7 @@ module Hobo
56
72
  buffer.fsync
57
73
  buffer.rewind
58
74
 
59
- raise ::Hobo::ExternalCommandError.new(args.join(" "), external.value.exitstatus, buffer) if external.value.exitstatus != 0
75
+ raise ::Hobo::ExternalCommandError.new(args.join(" "), external.value.exitstatus, buffer) if external.value.exitstatus != 0 && !opts[:ignore_errors]
60
76
 
61
77
  return opts[:capture] ? buffer.read.strip : nil
62
78
  end
@@ -1,39 +1,116 @@
1
- require 'hobo/helper/shell'
1
+ require 'tempfile'
2
2
 
3
3
  module Hobo
4
4
  module Helper
5
- def vm_shell command
6
- shell VmCommand.new(command).to_s
5
+ def vm_shell command, opts = {}
6
+ shell VmCommand.new(command, opts).to_s, opts
7
7
  end
8
8
 
9
9
  def vm_mysql opts = {}
10
10
  opts = {
11
11
  :auto_echo => true,
12
12
  :db => "",
13
- :user => maybe(Hobo.project_config.mysql.username) || "root",
14
- :pass => maybe(Hobo.project_config.mysql.password) || "root"
13
+ :user => maybe(Hobo.project_config.mysql.username) || "",
14
+ :pass => maybe(Hobo.project_config.mysql.password) || "",
15
+ :mysql => 'mysql'
15
16
  }.merge(opts)
16
17
 
17
- VmCommand.new "mysql -u#{opts[:user].shellescape} -p#{opts[:pass].shellescape} #{opts[:db].shellescape}", opts
18
+ opts[:user] = "-u#{opts[:user].shellescape}" unless opts[:user].empty?
19
+ opts[:pass] = "-p#{opts[:pass].shellescape}" unless opts[:pass].empty?
20
+ opts[:db] = opts[:db].shellescape unless opts[:db].empty?
21
+
22
+ VmCommand.new "#{opts[:mysql]} #{opts[:user]} #{opts[:pass]} #{opts[:db]}".strip, opts
18
23
  end
19
24
 
20
- def vm_command command = nil
21
- VmCommand.new command
25
+ def vm_command command = nil, opts = {}
26
+ VmCommand.new command, opts
22
27
  end
23
28
 
24
29
  private
25
30
 
31
+ class VmInspector
32
+ attr_accessor :ssh_config, :project_mount_path
33
+
34
+ def project_mount_path
35
+ configured_path = maybe(Hobo.project_config.vm.project_mount_path)
36
+ return configured_path if configured_path
37
+ return @project_mount_path if @project_mount_path
38
+
39
+ tmp = Tempfile.new('vm_command_locator', Hobo.project_path)
40
+ tmp.write(Hobo.project_path)
41
+
42
+ locator_file = File.basename(tmp.path)
43
+
44
+ pattern = OS.windows? ? 'vboxsf' : Hobo.project_path.shellescape
45
+
46
+ # TODO genericise the command escaping from lib/hobo/patches/slop.rb to avoid nested shell escaping hell
47
+ sed = 's/.* on \(.*\) type.*/\\\1\\\/%%/g'.gsub('%%', locator_file)
48
+ locator_results = vm_shell(
49
+ "mount | grep #{pattern} | sed -e\"#{sed}\" | xargs md5sum",
50
+ :capture => true,
51
+ :pwd => '/',
52
+ :psuedo_tty => false,
53
+ :ignore_errors => true
54
+ )
55
+
56
+ tmp.close
57
+
58
+ match = locator_results.match(/^([a-z0-9]{32})\s+(.*)$/)
59
+
60
+ raise Exception.new("Unable to locate project mount point in VM") if !match
61
+
62
+ @project_mount_path = File.dirname(match[2])
63
+
64
+ # Stash it in config
65
+ Hobo.project_config[:vm] ||= {}
66
+ Hobo.project_config[:vm][:project_mount_path] = @vm_project_mount_path
67
+ Hobo::Config::File.save(Hobo.project_config_file, Hobo.project_config)
68
+
69
+ return @vm_project_mount_path
70
+ end
71
+
72
+ def ssh_config
73
+ return @ssh_config if @ssh_config
74
+ config = nil
75
+ locate "*Vagrantfile" do
76
+ config = bundle_shell "vagrant ssh-config", :capture => true
77
+ end
78
+
79
+ raise Exception.new "Could not retrieve VM ssh configuration" unless config
80
+
81
+ patterns = {
82
+ :ssh_user => /^\s*User (.*)$/,
83
+ :ssh_identity => /^\s*IdentityFile (.*)$/,
84
+ :ssh_host => /^\s*HostName (.*)$/,
85
+ :ssh_port => /^\s*Port (\d+)/
86
+ }
87
+
88
+ output = {}
89
+
90
+ patterns.each do |k, pattern|
91
+ match = config.match(pattern)
92
+ output[k] = match[1] if match
93
+ end
94
+
95
+ return @ssh_config = output
96
+ end
97
+ end
98
+
26
99
  class VmCommand
100
+ class << self
101
+ attr_accessor :vm_inspector
102
+ @@vm_inspector = VmInspector.new
103
+ end
104
+
27
105
  attr_accessor :opts, :command
28
106
 
29
107
  def initialize command, opts = {}
30
108
  @command = command
31
109
  @opts = {
32
110
  :auto_echo => false,
33
- :psuedo_tty => true,
34
- :ssh_identity => "#{ENV['HOME'].shellescape}/.vagrant.d/insecure_private_key",
35
- :ssh_user => "vagrant",
36
- :ssh_host => maybe(Hobo.project_config.hostname) || ""
111
+ :psuedo_tty => false,
112
+ :pwd => opts[:pwd] || @@vm_inspector.project_mount_path,
113
+ :append => ''
37
114
  }.merge(opts)
38
115
  end
39
116
 
@@ -44,12 +121,45 @@ module Hobo
44
121
  return self
45
122
  end
46
123
 
124
+ def < pipe
125
+ pipe = "echo '#{pipe.shellescape}'" if opts[:auto_echo]
126
+ @pipe_in_vm = pipe
127
+ @opts[:psuedo_tty] = false
128
+ return self
129
+ end
130
+
131
+ # TODO Speed up Vagrant SSH connections
132
+ # May need to be disabled for windows (mm_send_fd: UsePrivilegeSeparation=yes not supported)
133
+ # https://gist.github.com/jedi4ever/5657094
134
+
47
135
  def to_s
48
- psuedo_tty = @opts[:psuedo_tty] ? "-t" : ""
49
- command = [
50
- "ssh -i #{opts[:ssh_identity]} #{psuedo_tty} #{opts[:ssh_user].shellescape}@#{opts[:ssh_host].shellescape}",
136
+ opts = @@vm_inspector.ssh_config.merge(@opts)
137
+
138
+ psuedo_tty = opts[:psuedo_tty] ? "-t" : ""
139
+
140
+ ssh_command = [
141
+ "ssh",
142
+ "-o 'UserKnownHostsFile /dev/null'",
143
+ "-o 'StrictHostKeyChecking no'",
144
+ "-o 'ForwardAgent yes'",
145
+ "-o 'LogLevel FATAL'",
146
+ "-p #{opts[:ssh_port]}",
147
+ "-i #{opts[:ssh_identity].shellescape}",
148
+ psuedo_tty,
149
+ "#{opts[:ssh_user].shellescape}@#{opts[:ssh_host].shellescape}"
150
+ ].join(" ")
151
+
152
+ pwd_set_command = " -- \"cd #{@opts[:pwd].shellescape}; exec /bin/bash"
153
+
154
+ vm_command = [
155
+ @pipe_in_vm,
51
156
  @command
52
- ].compact.join(" -- ")
157
+ ].compact.join(" | ")
158
+
159
+ command = [
160
+ ssh_command + pwd_set_command,
161
+ vm_command.empty? ? nil : vm_command.shellescape
162
+ ].compact.join(" -c ") + "#{opts[:append].shellescape}\""
53
163
 
54
164
  [
55
165
  @pipe,
@@ -64,4 +174,4 @@ module Hobo
64
174
  end
65
175
  end
66
176
 
67
- include Hobo::Helper
177
+ include Hobo::Helper
@@ -4,20 +4,34 @@ module Hobo
4
4
  class << self
5
5
  include Hobo::Lib::HostCheck
6
6
 
7
- def check silent = true
7
+ def check opts = {}
8
+ opts = {
9
+ :filter => nil,
10
+ :raise => false
11
+ }.merge(opts)
12
+
13
+ results = {}
8
14
  methods = Hobo::Lib::HostCheck.public_instance_methods(false)
9
15
  methods.each do |method|
16
+ next if opts[:filter] && !method.match(opts[:filter])
17
+
10
18
  name = method.to_s.gsub('_', ' ')
11
19
  name[0] = name[0].upcase
12
- begin
20
+ if opts[:raise]
13
21
  self.send method
14
- Hobo.ui.success "#{name}: OK" unless silent
15
- rescue
16
- Hobo.ui.error "#{name}: FAILED" unless silent
22
+ else
23
+ begin
24
+ self.send method
25
+ results[name] = :ok
26
+ rescue Hobo::Error => error
27
+ results[name] = error
28
+ end
17
29
  end
18
30
  end
31
+
32
+ return results
19
33
  end
20
34
  end
21
35
  end
22
36
  end
23
- end
37
+ end
@@ -2,20 +2,38 @@ module Hobo
2
2
  module Lib
3
3
  module HostCheck
4
4
  def ssh_present
5
+ advice = "The SSH command could not be located on your system.\n\n"
6
+
7
+ if OS.windows?
8
+ advice += "To make SSH available you must re-install git using the installer from http://git-scm.com/downloads ensuring you select the 'Use git and unix tools everywhere' option."
9
+ else
10
+ advice += "Please install openssh using your package manager."
11
+ end
12
+
5
13
  begin
6
14
  shell "ssh -V"
7
15
  rescue Errno::ENOENT
8
- raise Hobo::MissingDependency.new("ssh")
16
+ raise Hobo::HostCheckError.new("SSH is missing", advice)
9
17
  end
10
18
  end
11
19
 
12
20
  def php_present
21
+ advice = <<-EOF
22
+ The PHP command could not be located on your system.
23
+
24
+ This is an optional command that can speed up composer dependency installs.
25
+
26
+ Please install it from your package manager ensuring that the following command does not produce any errors:
27
+
28
+ php -r "readfile('https://getcomposer.org/installer');" | php
29
+ EOF
30
+
13
31
  begin
14
- shell "php -v"
32
+ shell "php --version"
15
33
  rescue Errno::ENOENT
16
- raise Hobo::MissingDependency.new("php")
34
+ raise Hobo::HostCheckError.new("PHP is missing", advice)
17
35
  end
18
36
  end
19
37
  end
20
38
  end
21
- end
39
+ end
@@ -2,46 +2,70 @@ module Hobo
2
2
  module Lib
3
3
  module HostCheck
4
4
  def git_present
5
+ advice = "The Git command could not be detected on your system.\n\n"
6
+ if OS.windows?
7
+ advice += "Please install it from http://git-scm.com/downloads ensuring you select the 'Use git and unix tools everywhere' option."
8
+ else
9
+ advice += "Please install it using your package manager."
10
+ end
11
+
5
12
  begin
6
13
  shell "git --version"
7
14
  rescue Errno::ENOENT
8
- raise Hobo::MissingDependency.new("ssh")
15
+ raise Hobo::HostCheckError.new("Git is missing", advice)
9
16
  end
10
17
  end
11
18
 
12
19
  def git_config_name_set
20
+ advice = <<-EOF
21
+ You have not set your name in git config!
22
+
23
+ Please do so with the following command:
24
+ git config --global user.name <your name here>
25
+ EOF
13
26
  begin
14
27
  shell "git config user.name"
15
28
  rescue Hobo::ExternalCommandError
16
- Hobo.ui.error "You must provide git with your full name"
17
- name = Hobo.ui.ask "Full name"
18
- shell "git config --global user.name #{name.shellescape}"
29
+ raise Hobo::HostCheckError.new("Git config is incomplete (Full name)", advice)
19
30
  end
20
31
  end
21
32
 
22
33
  def git_config_email_set
34
+ advice = <<-EOF
35
+ You have not set your email in git config!
36
+
37
+ Please do so with the following command:
38
+ git config --global user.email <your email here>
39
+ EOF
40
+
23
41
  begin
24
42
  shell "git config user.email"
25
43
  rescue Hobo::ExternalCommandError
26
- email = Hobo.ui.ask "Email address"
27
- shell "git config --global user.email #{email.shellescape}"
44
+ raise Hobo::HostCheckError.new("Git config is incomplete (Email)", advice)
28
45
  end
29
46
  end
30
47
 
31
48
  def git_autocrlf_disabled
32
- return true
49
+ return unless OS.windows?
50
+
51
+ advice = <<-EOF
52
+ You're using git with the core.autocrlf option enabled.
53
+
54
+ This setting can often cause problems when you clone a repository on windows but need to execute the contents of that repository within a linux VM.
55
+
56
+ You can disable autocrlf globally with the following command:
57
+ git config --global core.autocrlf false
58
+
59
+ Disabling this setting will cause git to see all line endings as changed in a repository that was cloned with it enabled.
60
+ As such, you must either enable it just for those repositories or delete and re-clone them with the setting disabled.
61
+
62
+ You can enable the setting on a per-clone basis by ensuring that you are in the project directory and executing the following command:
63
+ git config core-autocrlf true
64
+ EOF
33
65
  begin
34
66
  value = shell "git config core.autocrlf", :capture => true
35
67
  if value != "false"
36
- Hobo.ui.error "You're using git with autocrlf!"
37
- Hobo.ui.error "This setting can cause problems executing scripts within VMs."
38
- Hobo.ui.error "If you've had it enabled for a while, you'll need to check out all of your repositories again if you change it."
39
- disable = Hobo.ui.ask "Would you like to disable this setting?", :default => true
40
- if disable
41
- shell "git config --global core.autocrlf false"
42
- Hobo.ui.success "Disabled autocrlf\nYou can re-enable it by executing `git config --global core.autocrlf true"
43
- end
44
-
68
+ raise Hobo::HostCheckError.new("Git config has autocrlf enabled", advice)
45
69
  end
46
70
  rescue Hobo::ExternalCommandError
47
71
  # NOP
@@ -49,4 +73,4 @@ module Hobo
49
73
  end
50
74
  end
51
75
  end
52
- end
76
+ end
@@ -2,41 +2,51 @@ module Hobo
2
2
  module Lib
3
3
  module HostCheck
4
4
  def not_using_system_ruby
5
- return if Gem.win_platform?
5
+ return if OS.windows?
6
+ advice = <<-EOF
7
+ You're using a system ruby install which can cause issues with installing Gems and running some older projects.
8
+
9
+ rbenv is HIGHLY recommended.
10
+
11
+ You can install it with the following command:
12
+ curl https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash
13
+
14
+ Once installed, run the following to set it as the default ruby and re-install hobo-inviqa:
15
+ rbenv install 1.9.3-p448 && rbenv global 1.9.3-448 && gem install hobo-inviqa
16
+ EOF
6
17
  which = shell "which ruby", :capture => true
7
- unless which =~ /\.rbenc|\.rvm/
8
- Hobo.ui.error "You're using a system ruby install! rbenv is HIGHLY recommended"
9
- Hobo.ui.error "You can install it with the following command:\n"
10
- Hobo.ui.error " curl https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash\n"
11
- Hobo.ui.error "Once installed, run the following:\n"
12
- Hobo.ui.error " rbenv install 1.9.3-p448 && rbenv global 1.9.3-448 && gem install hobo-inviqa"
13
- raise "System ruby in use"
18
+ unless which =~ /\.rbenv|\.rvm/
19
+ raise Hobo::HostCheckError.new("Hobo is running under a system ruby", advice)
14
20
  end
15
21
  end
16
22
 
17
23
  def system_paths_for_ruby
18
- return if Gem.win_platform?
24
+ return if OS.windows?
25
+
26
+ advice = <<-EOF
27
+ The ordering of your system paths may cause a problem with Gems.
28
+
29
+ Unfortunately we can't automatically fix this for you at this time.
30
+
31
+ Please seek assistance.
32
+
33
+ Your paths were detected as:
34
+
35
+ #{ENV['PATH'].split(':').join("\n")}
36
+ EOF
37
+
19
38
  paths = ENV['PATH'].split(':')
20
39
  system_path_found = false
21
40
  ruby_path_found = false
22
41
  paths.each do |path|
23
42
  system_before_ruby = system_path_found && !ruby_path_found
24
43
  ruby_after_system = path =~ /\.rbenv|\.rvm/ && system_path_found
25
- raise "Bad system paths" if system_before_ruby or ruby_after_system
44
+ raise Hobo::HostCheckError.new("System paths appear to be mis-ordered", advice) if system_before_ruby or ruby_after_system
26
45
 
27
46
  ruby_path_found = true if path =~ /\.rbenv|\.rvm/
28
47
  system_path_found = true if path =~ /\/usr\/bin|\/usr\/local\/bin/
29
48
  end
30
49
  end
31
-
32
- def ruby_include_paths
33
- paths = $:
34
- bad_paths = paths.reject do |path|
35
- path.match /\.rbenv|\.rvm/
36
- end.compact.length > 0
37
-
38
- raise "Bad gem paths" if bad_paths
39
- end
40
50
  end
41
51
  end
42
- end
52
+ end