hobo-inviqa 0.0.4 → 0.0.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.
- data/Gemfile.lock +27 -6
- data/README.md +1 -10
- data/bin/hobo +20 -0
- data/features/hobo/help.feature +5 -1
- data/hobo.gemspec +4 -0
- data/lib/hobo.rb +17 -14
- data/lib/hobo/asset_applicator.rb +16 -0
- data/lib/hobo/cli.rb +40 -20
- data/lib/hobo/config.rb +5 -0
- data/lib/hobo/config/file.rb +3 -1
- data/lib/hobo/errors.rb +8 -1
- data/lib/hobo/help_formatter.rb +8 -1
- data/lib/hobo/helper/file_locator.rb +8 -5
- data/lib/hobo/helper/shell.rb +12 -4
- data/lib/hobo/helper/vm_command.rb +67 -0
- data/lib/hobo/lib/host_check.rb +23 -0
- data/lib/hobo/lib/host_check/deps.rb +21 -0
- data/lib/hobo/lib/host_check/git.rb +52 -0
- data/lib/hobo/lib/host_check/ruby.rb +42 -0
- data/lib/hobo/lib/host_check/vagrant.rb +15 -0
- data/lib/hobo/lib/s3sync.rb +233 -0
- data/lib/hobo/lib/seed/project.rb +12 -0
- data/lib/hobo/lib/seed/seed.rb +19 -0
- data/lib/hobo/logging.rb +22 -0
- data/lib/hobo/metadata.rb +7 -1
- data/lib/hobo/null.rb +31 -0
- data/lib/hobo/patches/deepstruct.rb +23 -0
- data/lib/hobo/patches/rake.rb +14 -1
- data/lib/hobo/patches/slop.rb +11 -1
- data/lib/hobo/paths.rb +8 -3
- data/lib/hobo/tasks/assets.rb +96 -0
- data/lib/hobo/tasks/console.rb +18 -0
- data/lib/hobo/tasks/debug.rb +2 -2
- data/lib/hobo/tasks/deps.rb +1 -1
- data/lib/hobo/tasks/host.rb +17 -0
- data/lib/hobo/tasks/vm.rb +2 -2
- data/lib/hobo/ui.rb +21 -16
- data/lib/hobo/version.rb +1 -1
- data/spec/hobo/asset_applicator_spec.rb +31 -0
- data/spec/hobo/cli_spec.rb +115 -97
- data/spec/hobo/config/file_spec.rb +13 -3
- data/spec/hobo/help_formatter_spec.rb +50 -18
- data/spec/hobo/helpers/file_locator_spec.rb +5 -1
- data/spec/hobo/helpers/shell_spec.rb +15 -1
- data/spec/hobo/helpers/vm_command_spec.rb +85 -0
- data/spec/hobo/lib/s3sync_spec.rb +13 -0
- data/spec/hobo/lib/seed/project_spec.rb +7 -8
- data/spec/hobo/lib/seed/seed_spec.rb +3 -4
- data/spec/hobo/logging_spec.rb +28 -0
- data/spec/hobo/metadata_spec.rb +10 -0
- data/spec/hobo/null_spec.rb +31 -0
- data/spec/hobo/paths_spec.rb +6 -6
- data/spec/hobo/ui_spec.rb +4 -0
- metadata +93 -6
- data/features/vm.feature +0 -0
data/lib/hobo/helper/shell.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'tempfile'
|
3
|
+
|
1
4
|
module Hobo
|
2
5
|
module Helper
|
6
|
+
|
3
7
|
def bundle_shell *args, &block
|
4
8
|
has_bundle = begin
|
5
9
|
shell "bundle", "exec", "ruby -v"
|
@@ -20,11 +24,14 @@ module Hobo
|
|
20
24
|
opts = {
|
21
25
|
:capture => false,
|
22
26
|
:indent => 0,
|
23
|
-
:realtime => false
|
27
|
+
:realtime => false,
|
28
|
+
:env => {}
|
24
29
|
}.merge! opts
|
25
30
|
|
31
|
+
Hobo::Logging.logger.debug("helper.shell: Invoking '#{args.join(" ")}' with #{opts.to_s}")
|
32
|
+
|
26
33
|
indent = " " * opts[:indent]
|
27
|
-
::Open3.popen3 *args do |stdin, out, err, external|
|
34
|
+
::Open3.popen3 opts[:env], *args do |stdin, out, err, external|
|
28
35
|
buffer = ::Tempfile.new 'hobo_run_buf'
|
29
36
|
buffer.sync = true
|
30
37
|
threads = [external]
|
@@ -33,8 +40,9 @@ module Hobo
|
|
33
40
|
{ :out => out, :err => err }.each do |key, stream|
|
34
41
|
threads.push(::Thread.new do
|
35
42
|
until (line = stream.gets).nil? do
|
36
|
-
line = ::Hobo.ui.color(line, :error) if key == :err
|
37
|
-
buffer.write(line)
|
43
|
+
line = ::Hobo.ui.color(line.strip, :error) if key == :err
|
44
|
+
buffer.write("#{line.strip}\n")
|
45
|
+
Hobo::Logging.logger.debug("helper.shell: #{line.strip}")
|
38
46
|
line = yield line if block
|
39
47
|
puts indent + line if opts[:realtime] && !line.nil?
|
40
48
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'hobo/helper/shell'
|
2
|
+
|
3
|
+
module Hobo
|
4
|
+
module Helper
|
5
|
+
def vm_shell command
|
6
|
+
shell VmCommand.new(command).to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def vm_mysql opts = {}
|
10
|
+
opts = {
|
11
|
+
:auto_echo => true,
|
12
|
+
:db => "",
|
13
|
+
:user => maybe(Hobo.project_config.mysql.username) || "root",
|
14
|
+
:pass => maybe(Hobo.project_config.mysql.password) || "root"
|
15
|
+
}.merge(opts)
|
16
|
+
|
17
|
+
VmCommand.new "mysql -u#{opts[:user].shellescape} -p#{opts[:pass].shellescape} #{opts[:db].shellescape}", opts
|
18
|
+
end
|
19
|
+
|
20
|
+
def vm_command command = nil
|
21
|
+
VmCommand.new command
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
class VmCommand
|
27
|
+
attr_accessor :opts, :command
|
28
|
+
|
29
|
+
def initialize command, opts = {}
|
30
|
+
@command = command
|
31
|
+
@opts = {
|
32
|
+
: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) || ""
|
37
|
+
}.merge(opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
def << pipe
|
41
|
+
pipe = "echo #{pipe.shellescape}" if opts[:auto_echo]
|
42
|
+
@pipe = pipe
|
43
|
+
@opts[:psuedo_tty] = false
|
44
|
+
return self
|
45
|
+
end
|
46
|
+
|
47
|
+
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}",
|
51
|
+
@command
|
52
|
+
].compact.join(" -- ")
|
53
|
+
|
54
|
+
[
|
55
|
+
@pipe,
|
56
|
+
command
|
57
|
+
].compact.join(" | ")
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_str
|
61
|
+
to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
include Hobo::Helper
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Hobo
|
2
|
+
module Lib
|
3
|
+
module HostCheck
|
4
|
+
class << self
|
5
|
+
include Hobo::Lib::HostCheck
|
6
|
+
|
7
|
+
def check silent = true
|
8
|
+
methods = Hobo::Lib::HostCheck.public_instance_methods(false)
|
9
|
+
methods.each do |method|
|
10
|
+
name = method.to_s.gsub('_', ' ')
|
11
|
+
name[0] = name[0].upcase
|
12
|
+
begin
|
13
|
+
self.send method
|
14
|
+
Hobo.ui.success "#{name}: OK" unless silent
|
15
|
+
rescue
|
16
|
+
Hobo.ui.error "#{name}: FAILED" unless silent
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Hobo
|
2
|
+
module Lib
|
3
|
+
module HostCheck
|
4
|
+
def ssh_present
|
5
|
+
begin
|
6
|
+
shell "ssh -V"
|
7
|
+
rescue Errno::ENOENT
|
8
|
+
raise Hobo::MissingDependency.new("ssh")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def php_present
|
13
|
+
begin
|
14
|
+
shell "php -v"
|
15
|
+
rescue Errno::ENOENT
|
16
|
+
raise Hobo::MissingDependency.new("php")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Hobo
|
2
|
+
module Lib
|
3
|
+
module HostCheck
|
4
|
+
def git_present
|
5
|
+
begin
|
6
|
+
shell "git --version"
|
7
|
+
rescue Errno::ENOENT
|
8
|
+
raise Hobo::MissingDependency.new("ssh")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def git_config_name_set
|
13
|
+
begin
|
14
|
+
shell "git config user.name"
|
15
|
+
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}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def git_config_email_set
|
23
|
+
begin
|
24
|
+
shell "git config user.email"
|
25
|
+
rescue Hobo::ExternalCommandError
|
26
|
+
email = Hobo.ui.ask "Email address"
|
27
|
+
shell "git config --global user.email #{email.shellescape}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def git_autocrlf_disabled
|
32
|
+
return true
|
33
|
+
begin
|
34
|
+
value = shell "git config core.autocrlf", :capture => true
|
35
|
+
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
|
+
|
45
|
+
end
|
46
|
+
rescue Hobo::ExternalCommandError
|
47
|
+
# NOP
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Hobo
|
2
|
+
module Lib
|
3
|
+
module HostCheck
|
4
|
+
def not_using_system_ruby
|
5
|
+
return if Gem.win_platform?
|
6
|
+
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"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def system_paths_for_ruby
|
18
|
+
return if Gem.win_platform?
|
19
|
+
paths = ENV['PATH'].split(':')
|
20
|
+
system_path_found = false
|
21
|
+
ruby_path_found = false
|
22
|
+
paths.each do |path|
|
23
|
+
system_before_ruby = system_path_found && !ruby_path_found
|
24
|
+
ruby_after_system = path =~ /\.rbenv|\.rvm/ && system_path_found
|
25
|
+
raise "Bad system paths" if system_before_ruby or ruby_after_system
|
26
|
+
|
27
|
+
ruby_path_found = true if path =~ /\.rbenv|\.rvm/
|
28
|
+
system_path_found = true if path =~ /\/usr\/bin|\/usr\/local\/bin/
|
29
|
+
end
|
30
|
+
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
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'semantic'
|
2
|
+
|
3
|
+
module Hobo
|
4
|
+
module Lib
|
5
|
+
module HostCheck
|
6
|
+
def vagrant_version
|
7
|
+
version = shell "vagrant --version", :capture => true
|
8
|
+
version.gsub!(/^Vagrant /, '')
|
9
|
+
version = ::Semantic::Version.new version
|
10
|
+
minimum_version = ::Semantic::Version.new "1.3.5"
|
11
|
+
raise "Vagrant too old" if version < minimum_version
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'ruby-progressbar'
|
4
|
+
|
5
|
+
module Hobo
|
6
|
+
module Lib
|
7
|
+
class S3Sync
|
8
|
+
include Hobo::Logging
|
9
|
+
|
10
|
+
def initialize key_id, secret
|
11
|
+
opts = {
|
12
|
+
:access_key_id => key_id,
|
13
|
+
:secret_access_key => secret,
|
14
|
+
:verify_response_body_content_length => false
|
15
|
+
}
|
16
|
+
|
17
|
+
logger.debug("s3sync: Options #{opts}")
|
18
|
+
|
19
|
+
@s3 = AWS::S3.new opts
|
20
|
+
end
|
21
|
+
|
22
|
+
def delta source, dest
|
23
|
+
to_add = (source.sort - dest.sort).map(&:first)
|
24
|
+
to_remove = (dest.sort - source.sort).map(&:first)
|
25
|
+
to_remove = to_remove - to_add
|
26
|
+
|
27
|
+
{
|
28
|
+
:add => to_add,
|
29
|
+
:remove => to_remove
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def io_handler uri
|
34
|
+
parsed = URI.parse(uri)
|
35
|
+
parsed.scheme == 's3' ?
|
36
|
+
Remote.new(@s3, parsed.host, parsed.path) :
|
37
|
+
Local.new(uri)
|
38
|
+
end
|
39
|
+
|
40
|
+
def sync source, dest, opts = {}
|
41
|
+
opts = { :progress => method(:progress) }.merge(opts)
|
42
|
+
|
43
|
+
source_io = io_handler(source)
|
44
|
+
destination_io = io_handler(dest)
|
45
|
+
|
46
|
+
logger.debug("s3sync: Synchronzing (#{source_io.class.name} -> #{destination_io.class.name}")
|
47
|
+
|
48
|
+
raise "S3 -> S3 synchronisation not supported" if source_io.is_a? Remote and destination_io.is_a? Remote
|
49
|
+
|
50
|
+
source_listing = source_io.ls
|
51
|
+
destination_listing = destination_io.ls
|
52
|
+
logger.debug("s3sync: Source listing - #{source_listing}")
|
53
|
+
logger.debug("s3sync: Destination listing - #{destination_listing}")
|
54
|
+
|
55
|
+
delta = delta(source_listing, destination_listing)
|
56
|
+
logger.debug("s3sync: Delta #{delta}")
|
57
|
+
|
58
|
+
delta[:add].each do |file|
|
59
|
+
logger.debug("s3sync: Synchronizing #{file}")
|
60
|
+
source_file = source_io.open(file, "r")
|
61
|
+
destination_file = destination_io.open(file, "wb+")
|
62
|
+
|
63
|
+
source_file.buffer
|
64
|
+
|
65
|
+
written = 0
|
66
|
+
size = source_file.size
|
67
|
+
destination_file.write({ :size => source_file.size }) do |buffer, bytes|
|
68
|
+
chunk = source_file.read(bytes)
|
69
|
+
buffer.write(chunk)
|
70
|
+
written += chunk.length
|
71
|
+
opts[:progress].call(file, written, size, :update)
|
72
|
+
end
|
73
|
+
|
74
|
+
destination_file.close
|
75
|
+
source_file.close
|
76
|
+
|
77
|
+
opts[:progress].call(file, written, size, :finish)
|
78
|
+
end
|
79
|
+
|
80
|
+
delta[:remove].each do |file|
|
81
|
+
logger.debug("s3sync: Removing #{file}")
|
82
|
+
destination_io.rm(file)
|
83
|
+
end
|
84
|
+
|
85
|
+
return delta
|
86
|
+
end
|
87
|
+
|
88
|
+
def progress file, written, total, type
|
89
|
+
@progress ||= {}
|
90
|
+
@progress[file] ||= ProgressBar.create(
|
91
|
+
:title => file,
|
92
|
+
:total => total,
|
93
|
+
:format => "%t [%B] %p%% %e",
|
94
|
+
)
|
95
|
+
|
96
|
+
case type
|
97
|
+
when :update
|
98
|
+
@progress[file].progress = written
|
99
|
+
when :finished
|
100
|
+
@progress[file].finish
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
class Local
|
106
|
+
include Hobo::Logging
|
107
|
+
|
108
|
+
def initialize path
|
109
|
+
@path = path
|
110
|
+
end
|
111
|
+
|
112
|
+
def ls
|
113
|
+
logger.debug("s3sync: Listing local directory: #{@path}")
|
114
|
+
out = {}
|
115
|
+
dir = "#{@path.chomp('/')}/"
|
116
|
+
files = Dir.glob("#{dir}**/*")
|
117
|
+
files.each do |file|
|
118
|
+
out[file.gsub(/^#{dir}/, '')] = Digest::MD5.file(file).hexdigest
|
119
|
+
end
|
120
|
+
return out
|
121
|
+
end
|
122
|
+
|
123
|
+
def open file, mode
|
124
|
+
file_path = File.join(@path, file)
|
125
|
+
FileUtils.mkdir_p File.dirname(file_path)
|
126
|
+
LocalFile.new File.open(file_path, mode)
|
127
|
+
end
|
128
|
+
|
129
|
+
def rm file
|
130
|
+
File.unlink file
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class Remote
|
135
|
+
include Hobo::Logging
|
136
|
+
|
137
|
+
def initialize s3, bucket, prefix
|
138
|
+
@s3 = s3
|
139
|
+
@bucket = bucket
|
140
|
+
@prefix = prefix ? "#{prefix.gsub(/^\//, '').chomp('/')}/" : ""
|
141
|
+
end
|
142
|
+
|
143
|
+
def ls
|
144
|
+
out = {}
|
145
|
+
logger.debug("s3sync: Listing remote bucket: #{@bucket} w/ prefix #{@prefix}")
|
146
|
+
@s3.buckets[@bucket].objects.with_prefix(@prefix).each do |file|
|
147
|
+
filename = file.key.gsub(/^#{@prefix}/, '')
|
148
|
+
next if filename == ""
|
149
|
+
out[filename] = file.etag.gsub('"', '')
|
150
|
+
end
|
151
|
+
return out
|
152
|
+
end
|
153
|
+
|
154
|
+
def open file, mode
|
155
|
+
s3_key = File.join(@prefix, file)
|
156
|
+
RemoteFile.new @s3.buckets[@bucket].objects[s3_key], @prefix
|
157
|
+
end
|
158
|
+
|
159
|
+
def rm file
|
160
|
+
s3_key = File.join(@prefix, file)
|
161
|
+
@s3.buckets[@bucket].objects[s3_key].delete
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
class LocalFile
|
166
|
+
def initialize file
|
167
|
+
@file = file
|
168
|
+
end
|
169
|
+
|
170
|
+
def buffer
|
171
|
+
# NOP
|
172
|
+
end
|
173
|
+
|
174
|
+
def read bytes
|
175
|
+
@file.read bytes
|
176
|
+
end
|
177
|
+
|
178
|
+
def write opts = {}
|
179
|
+
opts = { :chunk_size => 4096 }.merge(opts)
|
180
|
+
while @file.size < opts[:size] do
|
181
|
+
yield @file, opts[:chunk_size]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def size
|
186
|
+
@file.size
|
187
|
+
end
|
188
|
+
|
189
|
+
def close
|
190
|
+
@file.close
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class RemoteFile
|
195
|
+
def initialize object, prefix
|
196
|
+
@object = object
|
197
|
+
@prefix = prefix
|
198
|
+
@r_buffer, @w_buffer = IO.pipe
|
199
|
+
@buffer_thread = nil
|
200
|
+
end
|
201
|
+
|
202
|
+
def buffer
|
203
|
+
@buffer_thread = Thread.new do
|
204
|
+
@object.read do |chunk|
|
205
|
+
@w_buffer.write chunk
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def read bytes
|
211
|
+
@r_buffer.readpartial(bytes)
|
212
|
+
end
|
213
|
+
|
214
|
+
def write opts = {}
|
215
|
+
s3_opts = { :single_request => true, :content_length => opts[:size] }
|
216
|
+
@object.write s3_opts do |buffer, bytes|
|
217
|
+
yield buffer, bytes
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def size
|
222
|
+
@object.content_length
|
223
|
+
end
|
224
|
+
|
225
|
+
def close
|
226
|
+
@r_buffer.close
|
227
|
+
@w_buffer.close
|
228
|
+
@buffer_thread.exit if @buffer_thread
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|