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.
Files changed (55) hide show
  1. data/Gemfile.lock +27 -6
  2. data/README.md +1 -10
  3. data/bin/hobo +20 -0
  4. data/features/hobo/help.feature +5 -1
  5. data/hobo.gemspec +4 -0
  6. data/lib/hobo.rb +17 -14
  7. data/lib/hobo/asset_applicator.rb +16 -0
  8. data/lib/hobo/cli.rb +40 -20
  9. data/lib/hobo/config.rb +5 -0
  10. data/lib/hobo/config/file.rb +3 -1
  11. data/lib/hobo/errors.rb +8 -1
  12. data/lib/hobo/help_formatter.rb +8 -1
  13. data/lib/hobo/helper/file_locator.rb +8 -5
  14. data/lib/hobo/helper/shell.rb +12 -4
  15. data/lib/hobo/helper/vm_command.rb +67 -0
  16. data/lib/hobo/lib/host_check.rb +23 -0
  17. data/lib/hobo/lib/host_check/deps.rb +21 -0
  18. data/lib/hobo/lib/host_check/git.rb +52 -0
  19. data/lib/hobo/lib/host_check/ruby.rb +42 -0
  20. data/lib/hobo/lib/host_check/vagrant.rb +15 -0
  21. data/lib/hobo/lib/s3sync.rb +233 -0
  22. data/lib/hobo/lib/seed/project.rb +12 -0
  23. data/lib/hobo/lib/seed/seed.rb +19 -0
  24. data/lib/hobo/logging.rb +22 -0
  25. data/lib/hobo/metadata.rb +7 -1
  26. data/lib/hobo/null.rb +31 -0
  27. data/lib/hobo/patches/deepstruct.rb +23 -0
  28. data/lib/hobo/patches/rake.rb +14 -1
  29. data/lib/hobo/patches/slop.rb +11 -1
  30. data/lib/hobo/paths.rb +8 -3
  31. data/lib/hobo/tasks/assets.rb +96 -0
  32. data/lib/hobo/tasks/console.rb +18 -0
  33. data/lib/hobo/tasks/debug.rb +2 -2
  34. data/lib/hobo/tasks/deps.rb +1 -1
  35. data/lib/hobo/tasks/host.rb +17 -0
  36. data/lib/hobo/tasks/vm.rb +2 -2
  37. data/lib/hobo/ui.rb +21 -16
  38. data/lib/hobo/version.rb +1 -1
  39. data/spec/hobo/asset_applicator_spec.rb +31 -0
  40. data/spec/hobo/cli_spec.rb +115 -97
  41. data/spec/hobo/config/file_spec.rb +13 -3
  42. data/spec/hobo/help_formatter_spec.rb +50 -18
  43. data/spec/hobo/helpers/file_locator_spec.rb +5 -1
  44. data/spec/hobo/helpers/shell_spec.rb +15 -1
  45. data/spec/hobo/helpers/vm_command_spec.rb +85 -0
  46. data/spec/hobo/lib/s3sync_spec.rb +13 -0
  47. data/spec/hobo/lib/seed/project_spec.rb +7 -8
  48. data/spec/hobo/lib/seed/seed_spec.rb +3 -4
  49. data/spec/hobo/logging_spec.rb +28 -0
  50. data/spec/hobo/metadata_spec.rb +10 -0
  51. data/spec/hobo/null_spec.rb +31 -0
  52. data/spec/hobo/paths_spec.rb +6 -6
  53. data/spec/hobo/ui_spec.rb +4 -0
  54. metadata +93 -6
  55. data/features/vm.feature +0 -0
@@ -14,8 +14,11 @@ module Hobo
14
14
  seed.update
15
15
  seed.export config[:project_path]
16
16
  config[:seed][:version] = seed.version
17
+ config[:hostname] = "#{config[:name]}.development.local"
18
+ config[:asset_bucket] = "inviqa-assets-#{config[:name]}"
17
19
 
18
20
  @opts[:replacer].replace(config[:project_path], config)
21
+ load_seed_init(config)
19
22
 
20
23
  project_path = config[:project_path]
21
24
  config.delete :project_path
@@ -26,6 +29,15 @@ module Hobo
26
29
 
27
30
  private
28
31
 
32
+ def load_seed_init config
33
+ Hobo.project_config = DeepStruct.wrap(config)
34
+ seed_init_file = File.join(config[:project_path], 'seedinit.rb')
35
+ if File.exists?(seed_init_file)
36
+ require seed_init_file
37
+ File.unlink(seed_init_file)
38
+ end
39
+ end
40
+
29
41
  def initialize_git path, git_url
30
42
  Dir.chdir path do
31
43
  Hobo::Helper.shell 'git', 'init'
@@ -1,7 +1,11 @@
1
+ require 'tempfile'
2
+
1
3
  module Hobo
2
4
  module Lib
3
5
  module Seed
4
6
  class Seed
7
+ include Hobo::Logging
8
+
5
9
  def initialize(seed_path, url)
6
10
  @seed_path = seed_path
7
11
  @url = url
@@ -10,18 +14,33 @@ module Hobo
10
14
  def export path
11
15
  path = File.expand_path(path)
12
16
  FileUtils.mkdir_p path
17
+
18
+ logger.info "Exporting seed to #{path}"
19
+
20
+ tmp_path = Dir.mktmpdir("hobo-seed-export")
21
+
13
22
  Dir.chdir @seed_path do
23
+ Hobo::Helper.shell "git clone . #{tmp_path.shellescape}"
24
+ end
25
+
26
+ Dir.chdir tmp_path do
27
+ Hobo::Helper.shell "git submodule update --init"
14
28
  Hobo::Helper.shell "git archive master | tar -x -C #{path.shellescape}"
29
+ Hobo::Helper.shell "git submodule foreach 'cd #{tmp_path.shellescape}/$path && git archive HEAD | tar -x -C #{path.shellescape}/$path'"
15
30
  end
31
+
32
+ FileUtils.rm_f tmp_path
16
33
  end
17
34
 
18
35
  def update
19
36
  FileUtils.mkdir_p @seed_path
20
37
  if File.exists? File.join(@seed_path, 'HEAD')
21
38
  Dir.chdir @seed_path do
39
+ logger.info "Updating seed in #{@seed_path}"
22
40
  Hobo::Helper.shell 'git', 'fetch', '--all'
23
41
  end
24
42
  else
43
+ logger.info "Cloning seed from #{@url} to #{@seed_path}"
25
44
  Hobo::Helper.shell 'git', 'clone', @url, @seed_path, '--mirror'
26
45
  end
27
46
  end
@@ -0,0 +1,22 @@
1
+ require 'logger'
2
+
3
+ module Hobo
4
+ class << self
5
+ attr_accessor :logger
6
+ end
7
+
8
+ module Logging
9
+ def logger
10
+ Hobo::Logging.logger
11
+ end
12
+
13
+ def self.logger
14
+ unless Hobo.logger
15
+ Hobo.logger = Logger.new(STDOUT)
16
+ Hobo.logger.level = Logger::WARN
17
+ end
18
+
19
+ return Hobo.logger
20
+ end
21
+ end
22
+ end
@@ -21,7 +21,13 @@ module Hobo
21
21
  data = store[type] if data.nil?
22
22
  metadata[task] ||= {}
23
23
  metadata[task][type] = data
24
- store[type] = @defaults[type] ? @defaults[type].dup : @defaults[type]
24
+ end
25
+
26
+ def reset_store
27
+ @store = {}
28
+ @defaults.each do |k, v|
29
+ @store[k] = v.nil? ? nil : v.dup
30
+ end
25
31
  end
26
32
  end
27
33
  end
@@ -0,0 +1,31 @@
1
+ module Hobo
2
+ class Null
3
+ def method_missing(method, *args, &block)
4
+ self
5
+ end
6
+
7
+ def nil?
8
+ true
9
+ end
10
+
11
+ def to_a
12
+ []
13
+ end
14
+
15
+ def to_s
16
+ ""
17
+ end
18
+
19
+ def to_f
20
+ 0.0
21
+ end
22
+
23
+ def to_i
24
+ 0
25
+ end
26
+ end
27
+ end
28
+
29
+ def maybe val
30
+ val.nil? ? nil : val
31
+ end
@@ -0,0 +1,23 @@
1
+ require 'deepstruct'
2
+
3
+ # Copied from the DeepStruct gem
4
+ # Modified to return Null on unknown key
5
+ module DeepStruct
6
+ class HashWrapper < DeepWrapper
7
+ def method_missing(method, *args, &block)
8
+ return @value.send(method, *args, &block) if @value.respond_to?(method)
9
+ method = method.to_s
10
+ if method.chomp!('?')
11
+ key = method.to_sym
12
+ self.has_key?(key) && !!self[key]
13
+ elsif method.chomp!('=')
14
+ raise ArgumentError, "wrong number of arguments (#{arg_count} for 1)", caller(1) if args.length != 1
15
+ self[method] = args[0]
16
+ elsif args.length == 0 && self.has_key?(method)
17
+ self[method]
18
+ else
19
+ Hobo::Null.new
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,11 +1,18 @@
1
+ require 'rake'
2
+
1
3
  module Rake
2
4
  class Task
3
5
  attr_accessor :opts
6
+ def opts
7
+ @opts = @opts || {}
8
+ end
4
9
  end
5
10
 
6
11
  module DSL
7
12
  def replace *args, &block
8
- Rake::Task[args[0]].clear
13
+ old = (args[0].is_a? Hash) ? args[0].keys[0] : args[0]
14
+ Hobo::Logging.logger.debug("rake.dsl: Replacing #{old} with block")
15
+ Rake::Task[old].clear
9
16
  task(*args, &block)
10
17
  end
11
18
 
@@ -25,6 +32,10 @@ module Rake
25
32
  Hobo::Metadata.add scoped_name, meta
26
33
  end
27
34
 
35
+ Hobo::Metadata.reset_store
36
+
37
+ Hobo::Logging.logger.debug("Added metadata to #{scoped_name} -- #{Hobo::Metadata.metadata[scoped_name]}")
38
+
28
39
  task = Rake::Task.define_task(*args, &block)
29
40
  end
30
41
 
@@ -47,6 +58,8 @@ module Rake
47
58
  Hobo::Metadata.add scoped_name, meta
48
59
  end
49
60
 
61
+ Hobo::Metadata.reset_store
62
+
50
63
  _old_namespace(name, &block)
51
64
  end
52
65
  end
@@ -1,5 +1,15 @@
1
+ require 'slop'
2
+
1
3
  class Slop
2
- attr_accessor :long_desc, :arg_list, :hidden
4
+ attr_accessor :long_desc, :arg_list, :hidden, :desc
5
+
6
+ # Slop has a description method but it uses @config which is inherited
7
+ # This is not desired behaviour
8
+ def description desc = nil
9
+ @desc = desc if desc
10
+ @desc
11
+ end
12
+
3
13
  def long_description desc = nil
4
14
  @long_desc = desc if desc
5
15
  @long_desc
@@ -12,11 +12,16 @@ module Hobo
12
12
 
13
13
  def project_path
14
14
  return @project_path unless @project_path.nil?
15
+ return @project_path = Dir.pwd if File.exists? "Hobofile"
16
+
15
17
  dir = Dir.pwd.split('/').reverse
16
18
  min_length = Gem.win_platform? ? 1 : 0
19
+ Hobo::Logging.logger.debug("paths.project: Searching backwards from #{Dir.pwd}")
17
20
 
18
21
  while dir.length > min_length
19
22
  test_dir = dir.reverse.join('/')
23
+ Hobo::Logging.logger.debug("paths.project: Testing #{test_dir}")
24
+
20
25
  match = [
21
26
  File.exists?(File.join(test_dir, 'Hobofile')),
22
27
  File.exists?(File.join(test_dir, 'tools', 'hobo')),
@@ -25,7 +30,7 @@ module Hobo
25
30
 
26
31
  return @project_path = test_dir if match.length > 0
27
32
 
28
- dir.pop
33
+ dir.shift
29
34
  end
30
35
  return @project_path = nil
31
36
  end
@@ -42,11 +47,11 @@ module Hobo
42
47
 
43
48
  def project_config_file
44
49
  return nil if !project_path
45
- File.join(project_path, 'tools', 'hobo', 'storage.yaml')
50
+ File.join(project_path, 'tools', 'hobo', 'config.yaml')
46
51
  end
47
52
 
48
53
  def user_config_file
49
- File.join(config_path, 'config.rb')
54
+ File.join(config_path, 'config.yaml')
50
55
  end
51
56
 
52
57
  def user_hobofile_path
@@ -0,0 +1,96 @@
1
+ require 'hobo/lib/s3sync'
2
+
3
+ desc "Project asset commands"
4
+ project_only
5
+ namespace :assets do
6
+
7
+ desc "Download project assets"
8
+ option "-e=", "--env=", "Environment"
9
+ task :download do |task, args|
10
+ Hobo.ui.success "Synchonizing assets (download)"
11
+
12
+ unless Hobo.project_config.asset_bucket.nil?
13
+ env = task.opts[:env] || args[:env] || 'development'
14
+ s3_uri = "s3://#{Hobo.project_config.asset_bucket}/#{env}/"
15
+
16
+ sync = Hobo::Lib::S3Sync.new(
17
+ maybe(Hobo.user_config.aws.access_key_id),
18
+ maybe(Hobo.user_config.aws.secret_access_key)
19
+ )
20
+
21
+ changes = sync.sync(s3_uri, "tools/assets/#{env}")
22
+ Hobo.ui.warning " No changes required" if (changes[:add] + changes[:remove]).length == 0
23
+ else
24
+ Hobo.ui.warning " No asset bucket configured. Skipping..."
25
+ end
26
+ Hobo.ui.separator
27
+ end
28
+
29
+ desc "Upload project assets"
30
+ option "-e=", "--env=", "Environment"
31
+ task :upload do |task, args|
32
+
33
+ Hobo.ui.success "Synchronzing assets (upload)"
34
+
35
+ unless Hobo.project_config.asset_bucket.nil?
36
+ env = task.opts[:env] || args[:env] || 'development'
37
+ s3_uri = "s3://#{Hobo.project_config.asset_bucket}/#{env}/"
38
+
39
+ sync = Hobo::Lib::S3Sync.new(
40
+ maybe(Hobo.user_config.aws.access_key_id),
41
+ maybe(Hobo.user_config.aws.secret_access_key)
42
+ )
43
+
44
+ changes = sync.sync("tools/assets/#{env}", s3_uri)
45
+ Hobo.ui.warning " No changes required" if (changes[:add] + changes[:remove]).length == 0
46
+ else
47
+ Hobo.ui.warning " No asset bucket configured. Skipping..."
48
+ end
49
+
50
+ Hobo.ui.separator
51
+ end
52
+
53
+ desc "Apply project assets"
54
+ option "-e=", "--env=", "Environment"
55
+ task :apply do |task, args|
56
+ env = task.opts[:env] || args[:env] || 'development'
57
+ path = "tools/assets/#{env}"
58
+
59
+ next unless File.exists? path
60
+
61
+ Dir.new(path).each do |file|
62
+ file = File.join(path, file)
63
+ next unless File.file? file
64
+ Hobo.asset_applicators.each do |matcher, proc|
65
+ proc.call(file) if matcher.match(file)
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+
72
+ # Built in applicators
73
+ Hobo.asset_applicators.register /.*\.files\.(tgz|tar\.gz|tar\.bz2)/ do |file|
74
+ Hobo.ui.title "Applying file dump (#{file})"
75
+ Dir.chdir Hobo.project_path do
76
+ shell "tar -xvf #{file.shellescape}"
77
+ end
78
+ end
79
+
80
+ Hobo.asset_applicators.register /.*\.sql\.gz/ do |file|
81
+ matches = file.match(/^([^\.]+).*\.sql\.gz/)
82
+ db = File.basename(matches[1])
83
+
84
+ begin
85
+ shell(vm_mysql << "USE #{db}")
86
+ Hobo.ui.warning "Already applied (#{file})"
87
+ next
88
+ rescue Hobo::ExternalCommandError => e
89
+ raise e if e.exit_code != 1
90
+ end
91
+
92
+ Hobo.ui.title "Applying mysqldump (#{file})"
93
+
94
+ shell(vm_mysql << "CREATE DATABASE #{db}")
95
+ shell(vm_mysql(:auto_echo => false, :db => db) << "zcat #{file.shellescape}")
96
+ end
@@ -0,0 +1,18 @@
1
+ desc "VM console shortcut commands"
2
+ project_only
3
+ namespace :console do
4
+ desc "Open an SSH connection"
5
+ task :ssh do
6
+ exec vm_command
7
+ end
8
+
9
+ desc "Open a MySQL cli connection"
10
+ task :mysql do
11
+ exec vm_mysql
12
+ end
13
+
14
+ desc "Open a Redis cli connection"
15
+ task :redis do
16
+ exec vm_command "redis-cli"
17
+ end
18
+ end
@@ -13,8 +13,8 @@ namespace 'hobo-debug' do
13
13
  :'composer.json' => "composer.json"
14
14
  }.each do |k,v|
15
15
  path = nil
16
- locate v do |p|
17
- path = p
16
+ locate v do |file, full_file|
17
+ path = full_file
18
18
  end
19
19
  Hobo.ui.info "<%=color('#{k.to_s}:', :green) %> #{path.nil? ? "none" : path}"
20
20
  end
@@ -43,7 +43,7 @@ namespace :deps do
43
43
  end
44
44
 
45
45
  desc "Install chef dependencies"
46
- task :chef do
46
+ task :chef => [ "deps:gems" ] do
47
47
  locate "*Cheffile" do
48
48
  Hobo.ui.title "Installing chef dependencies"
49
49
  Bundler.with_clean_env do
@@ -0,0 +1,17 @@
1
+ namespace :host do
2
+ task :config do
3
+ config = Hobo.user_config
4
+
5
+ config.full_name = Hobo.ui.ask "Full name", :default => config.full_name
6
+ config.email = Hobo.ui.ask "Email", :default => config.email
7
+ config.aws.access_key_id = Hobo.ui.ask "AWS access key ID", :default => config.aws.access_key_id
8
+ config.aws.secret_access_key = Hobo.ui.ask "AWS secret access key", :default => config.aws.secret_access_key
9
+
10
+ Hobo::Config::File.save(Hobo.user_config_file, config)
11
+ File.chmod(0600, Hobo.user_config_file)
12
+ end
13
+
14
+ task :check do
15
+ Hobo::HostCheck.check false
16
+ end
17
+ end
@@ -8,7 +8,7 @@ namespace :vm do
8
8
  end
9
9
 
10
10
  desc "Start & provision VM"
11
- task :up => [ 'deps:gems', 'deps:chef', 'deps:composer', 'deps:vagrant_plugins', 'vm:start', 'vm:provision' ]
11
+ task :up => [ 'deps:chef', 'deps:composer', 'assets:download', 'vm:start', 'vm:provision', 'assets:apply' ]
12
12
 
13
13
  desc "Stop VM"
14
14
  task :stop => [ "deps:gems" ] do
@@ -32,7 +32,7 @@ namespace :vm do
32
32
  end
33
33
 
34
34
  desc "Start VM without provision"
35
- task :start => [ "deps:gems" ] do
35
+ task :start => [ "deps:gems", "deps:vagrant_plugins" ] do
36
36
  vagrantfile do
37
37
  Hobo.ui.title "Starting vagrant VM"
38
38
  bundle_shell "vagrant", "up", "--no-provision", "--color", realtime: true, indent: 2
@@ -8,23 +8,22 @@ module Hobo
8
8
  class Ui
9
9
  attr_accessor :interactive
10
10
 
11
- def initialize out = $stdout, error = $stderr
12
- colors = HighLine::ColorScheme.new do |cs|
13
- cs[:debug] = [ ]
14
- cs[:info] = [ ]
15
- cs[:warning] = [ :yellow ]
16
- cs[:error] = [ :red ]
17
- cs[:success] = [ :green ]
18
- cs[:opt] = [ :green ]
19
- cs[:command] = [:green ]
20
- cs[:special] = [ :blue ]
21
- cs[:title] = [ :green ]
22
- cs[:help_title] = [ :yellow ]
23
- cs[:description] = [ :bold ]
24
- end
25
-
26
- HighLine.color_scheme = colors
11
+ COLORS = {
12
+ :debug => [ ],
13
+ :info => [ ],
14
+ :warning => [:yellow],
15
+ :error => [:red],
16
+ :success => [:green],
17
+ :opt => [:green],
18
+ :command => [:green],
19
+ :special => [:blue],
20
+ :title => [:green],
21
+ :help_title => [:yellow],
22
+ :description => [:bold]
23
+ }
27
24
 
25
+ def initialize out = $stdout, error = $stderr
26
+ HighLine.color_scheme = HighLine::ColorScheme.new COLORS
28
27
  @out = ::HighLine.new $stdin, out
29
28
  @error = ::HighLine.new $stdin, error
30
29
  end
@@ -59,6 +58,12 @@ module Hobo
59
58
  end
60
59
  end
61
60
 
61
+ def section title
62
+ Hobo.ui.title title
63
+ yield
64
+ Hobo.ui.separator
65
+ end
66
+
62
67
  def separator
63
68
  info ""
64
69
  end