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
@@ -0,0 +1,59 @@
1
+ module Hobo
2
+ module Helper
3
+ def bundle_shell *args, &block
4
+ has_bundle = begin
5
+ shell "bundle", "exec", "ruby -v"
6
+ true
7
+ rescue ::Hobo::ExternalCommandError
8
+ false
9
+ end
10
+
11
+ if has_bundle
12
+ args = [ 'bundle', 'exec' ] + args
13
+ end
14
+
15
+ shell *args, &block
16
+ end
17
+
18
+ def shell *args, &block
19
+ opts = (args.size > 1 && args.last.is_a?(Hash)) ? args.pop : {}
20
+ opts = {
21
+ :capture => false,
22
+ :indent => 0,
23
+ :realtime => false
24
+ }.merge! opts
25
+
26
+ indent = " " * opts[:indent]
27
+ ::Open3.popen3 *args do |stdin, out, err, external|
28
+ buffer = ::Tempfile.new 'hobo_run_buf'
29
+ buffer.sync = true
30
+ threads = [external]
31
+
32
+ ## Create a thread to read from each stream
33
+ { :out => out, :err => err }.each do |key, stream|
34
+ threads.push(::Thread.new do
35
+ until (line = stream.gets).nil? do
36
+ line = ::Hobo.ui.color(line, :error) if key == :err
37
+ buffer.write(line)
38
+ line = yield line if block
39
+ puts indent + line if opts[:realtime] && !line.nil?
40
+ end
41
+ end)
42
+ end
43
+
44
+ threads.each do |t|
45
+ t.join
46
+ end
47
+
48
+ buffer.fsync
49
+ buffer.rewind
50
+
51
+ raise ::Hobo::ExternalCommandError.new(args.join(" "), external.value.exitstatus, buffer) if external.value.exitstatus != 0
52
+
53
+ return opts[:capture] ? buffer.read.strip : nil
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ include Hobo::Helper
@@ -0,0 +1,41 @@
1
+ module Hobo
2
+ module Lib
3
+ module Seed
4
+ class Project
5
+ def initialize(opts = {})
6
+ @opts = {
7
+ :replacer => Replacer.new,
8
+ :config_class => Hobo::Config::File,
9
+ :project_config_file => Hobo.project_config_file
10
+ }.merge! opts
11
+ end
12
+
13
+ def setup seed, config
14
+ seed.update
15
+ seed.export config[:project_path]
16
+ config[:seed][:version] = seed.version
17
+
18
+ @opts[:replacer].replace(config[:project_path], config)
19
+
20
+ project_path = config[:project_path]
21
+ config.delete :project_path
22
+ @opts[:config_class].save @opts[:project_config_file], config
23
+
24
+ initialize_git project_path, config[:git_url]
25
+ end
26
+
27
+ private
28
+
29
+ def initialize_git path, git_url
30
+ Dir.chdir path do
31
+ Hobo::Helper.shell 'git', 'init'
32
+ Hobo::Helper.shell 'git', 'remote', 'add', 'origin', git_url
33
+ Hobo::Helper.shell 'git', 'add', '*'
34
+ Hobo::Helper.shell 'git', 'commit', '-m', "'Initial hobo project'"
35
+ Hobo::Helper.shell 'git', 'checkout', '-b', 'develop'
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ require 'find'
2
+
3
+ module Hobo
4
+ module Lib
5
+ module Seed
6
+ class Replacer
7
+ # Matching files/directories to be excluded from replacements
8
+ EXCLUDES = ["\\.git/", "^./bin", "^./lib", "^./spec"]
9
+
10
+ def replace(path, tokens)
11
+ if tokens.instance_of? Hash
12
+ tokens = flat_hash(tokens)
13
+ elsif !tokens.instance_of? Array
14
+ raise "Invalid token list (expected Array or Hash)"
15
+ end
16
+
17
+ return search_replace(path, tokens)
18
+ end
19
+
20
+ private
21
+
22
+ def search_replace(path, tokens, &block)
23
+ files = []
24
+ excludes = Regexp.new(EXCLUDES.join("|"))
25
+ Find.find(path) do |candidate|
26
+ Find.prune if candidate =~ excludes # Skip excluded
27
+ next unless FileTest.file? candidate # Skip unless file
28
+
29
+ content = File.read(candidate)
30
+ next unless content.force_encoding("UTF-8").valid_encoding? # Skip unless file can be valid UTF-8
31
+
32
+ match = false
33
+ tokens.each do |token, replacement|
34
+ token = "{{#{token.join('.')}}}"
35
+ match = content.match(token)
36
+ if match
37
+ content.gsub!(token, replacement)
38
+ files.push(candidate)
39
+ end
40
+ end
41
+
42
+ File.write(candidate, content) if files.include? candidate
43
+ end
44
+ return files.uniq
45
+ end
46
+
47
+ # http://stackoverflow.com/questions/9647997/converting-a-nested-hash-into-a-flat-hash
48
+ def flat_hash(hash, k = [])
49
+ return {k => hash} unless hash.is_a?(Hash)
50
+ hash.inject({}) do |h, v|
51
+ h.merge! flat_hash(v[-1], k + [v[0]])
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,43 @@
1
+ module Hobo
2
+ module Lib
3
+ module Seed
4
+ class Seed
5
+ def initialize(seed_path, url)
6
+ @seed_path = seed_path
7
+ @url = url
8
+ end
9
+
10
+ def export path
11
+ path = File.expand_path(path)
12
+ FileUtils.mkdir_p path
13
+ Dir.chdir @seed_path do
14
+ Hobo::Helper.shell "git archive master | tar -x -C #{path.shellescape}"
15
+ end
16
+ end
17
+
18
+ def update
19
+ FileUtils.mkdir_p @seed_path
20
+ if File.exists? File.join(@seed_path, 'HEAD')
21
+ Dir.chdir @seed_path do
22
+ Hobo::Helper.shell 'git', 'fetch', '--all'
23
+ end
24
+ else
25
+ Hobo::Helper.shell 'git', 'clone', @url, @seed_path, '--mirror'
26
+ end
27
+ end
28
+
29
+ def version
30
+ Dir.chdir @seed_path do
31
+ Hobo::Helper.shell 'git', 'rev-parse', '--short', 'HEAD', :capture => true
32
+ end
33
+ end
34
+
35
+ class << self
36
+ def name_to_url name
37
+ name.match(/\./) ? name : "git@github.com:inviqa/hobo-seed-#{name}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,28 @@
1
+ module Hobo
2
+ class Metadata
3
+ class << self
4
+ attr_accessor :metadata, :store, :defaults
5
+
6
+ def store
7
+ @store ||= {}
8
+ end
9
+
10
+ def metadata
11
+ @metadata ||= {}
12
+ end
13
+
14
+ def default type, value
15
+ @defaults ||= {}
16
+ @defaults[type] = value
17
+ store[type] = value if store[type].nil?
18
+ end
19
+
20
+ def add task, type, data = nil
21
+ data = store[type] if data.nil?
22
+ metadata[task] ||= {}
23
+ metadata[task][type] = data
24
+ store[type] = @defaults[type] ? @defaults[type].dup : @defaults[type]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,56 @@
1
+ module Rake
2
+ class Task
3
+ attr_accessor :opts
4
+ end
5
+
6
+ module DSL
7
+ def replace *args, &block
8
+ Rake::Task[args[0]].clear
9
+ task(*args, &block)
10
+ end
11
+
12
+ def hidden value = true
13
+ Hobo::Metadata.store[:hidden] = value
14
+ end
15
+
16
+ def project_only
17
+ Hobo::Metadata.store[:project_only] = true
18
+ end
19
+
20
+ def task *args, &block
21
+ name = args[0].is_a?(Hash) ? args[0].keys.first.to_s : args[0]
22
+ scoped_name = Rake.application.current_scope.path_with_task_name(name).to_s
23
+
24
+ [:opts, :desc, :long_desc, :hidden, :project_only].each do |meta|
25
+ Hobo::Metadata.add scoped_name, meta
26
+ end
27
+
28
+ task = Rake::Task.define_task(*args, &block)
29
+ end
30
+
31
+ def option *args
32
+ Hobo::Metadata.store[:opts].push args
33
+ end
34
+
35
+ def desc description
36
+ Hobo::Metadata.store[:desc] = description
37
+ end
38
+
39
+ def long_desc description
40
+ Hobo::Metadata.store[:long_desc] = description
41
+ end
42
+
43
+ alias :_old_namespace :namespace
44
+ def namespace name, opts = {}, &block
45
+ scoped_name = Rake.application.current_scope.path_with_task_name(name).to_s
46
+ [:desc, :long_desc, :hidden, :project_only].each do |meta|
47
+ Hobo::Metadata.add scoped_name, meta
48
+ end
49
+
50
+ _old_namespace(name, &block)
51
+ end
52
+ end
53
+ end
54
+
55
+ Hobo::Metadata.default :opts, []
56
+ Hobo::Metadata.default :desc, nil
@@ -0,0 +1,22 @@
1
+ class Slop
2
+ attr_accessor :long_desc, :arg_list, :hidden
3
+ def long_description desc = nil
4
+ @long_desc = desc if desc
5
+ @long_desc
6
+ end
7
+
8
+ def arg_list list = nil
9
+ @arg_list = list if list
10
+ @arg_list
11
+ end
12
+
13
+ def hidden value = nil
14
+ @hidden = value if value
15
+ @hidden
16
+ end
17
+
18
+ def project_only value = nil
19
+ @config[:project_only] = value unless value.nil?
20
+ @config[:project_only]
21
+ end
22
+ end
data/lib/hobo/paths.rb ADDED
@@ -0,0 +1,49 @@
1
+ module Hobo
2
+ class << self
3
+ attr_accessor :project_path
4
+
5
+ def config_path
6
+ File.join(ENV['HOME'], '.hobo')
7
+ end
8
+
9
+ def seed_cache_path
10
+ File.join(config_path, 'seeds')
11
+ end
12
+
13
+ def project_path
14
+ return @project_path unless @project_path.nil?
15
+ dir = Dir.pwd
16
+ while File.split(dir)[1] != File.split(dir)[0]
17
+ match = [
18
+ File.exists?(File.join(dir, 'Hobofile')),
19
+ File.exists?(File.join(dir, 'tools', 'hobo')),
20
+ File.exists?(File.join(dir, 'tools', 'vagrant', 'Vagrantfile'))
21
+ ] - [false]
22
+
23
+ return @project_path = dir if match.length > 0
24
+
25
+ dir = File.split(dir)[0]
26
+ end
27
+ return @project_path = nil
28
+ end
29
+
30
+ def project_bin_path
31
+ return nil if !project_path
32
+ File.join(project_path, 'bin')
33
+ end
34
+
35
+ def hobofile_path
36
+ return nil if !project_path
37
+ File.join(project_path, 'Hobofile')
38
+ end
39
+
40
+ def project_config_file
41
+ return nil if !project_path
42
+ File.join(project_path, 'tools', 'hobo', 'storage.yaml')
43
+ end
44
+
45
+ def user_config_file
46
+ File.join(config_path, 'config.rb')
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,22 @@
1
+ desc "Internal hobo debugging tools"
2
+ hidden true
3
+ namespace 'hobo-debug' do
4
+
5
+ desc "Display project paths"
6
+ project_only
7
+ task "paths" do
8
+ Hobo.ui.info "<%=color('Project path:', :green)%> " + Hobo.project_path
9
+ {
10
+ :gemfile => "*Gemfile",
11
+ :vagrantfile => "*Vagrantfile",
12
+ :cheffile => "*Cheffile",
13
+ :'composer.json' => "composer.json"
14
+ }.each do |k,v|
15
+ path = nil
16
+ locate v do |p|
17
+ path = p
18
+ end
19
+ Hobo.ui.info "<%=color('#{k.to_s}:', :green) %> #{path.nil? ? "none" : path}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,45 @@
1
+ require 'bundler'
2
+
3
+ desc "Dependency related tasks"
4
+ hidden true
5
+ namespace :deps do
6
+
7
+ desc "Install Gem dependencies"
8
+ task :gems do
9
+ locate("*Gemfile", missing: "No Gemfile found") do
10
+ Hobo.ui.title "Installing Gem dependencies"
11
+ Bundler.with_clean_env do
12
+ shell "bundle", "install", realtime: true, indent: 2
13
+ end
14
+ Hobo.ui.separator
15
+ end
16
+ end
17
+
18
+ desc "Install composer dependencies"
19
+ task :composer do
20
+ if File.exists? File.join(Hobo.project_path, "composer.json")
21
+ Rake::Task["tools:composer"].invoke
22
+ Hobo.ui.title "Installing composer dependencies"
23
+ shell "php", File.join(Hobo.project_bin_path, 'composer.phar'), "install", "--ansi", realtime: true, indent: 2
24
+ end
25
+ Hobo.ui.separator
26
+ end
27
+
28
+ desc "Install vagrant plugins"
29
+ task :vagrant_plugins do
30
+ Hobo.ui.error "Vagrant plugins can't be installed automatically yet"
31
+ end
32
+
33
+ desc "Install chef dependencies"
34
+ task :chef do
35
+ locate("*Cheffile", missing: "No Cheffile found") do
36
+ Hobo.ui.title "Installing chef dependencies"
37
+ Bundler.with_clean_env do
38
+ bundle_shell "librarian-chef", "install", "--verbose", realtime: true, indent: 2 do |line|
39
+ line =~ /Installing.*</ ? line : nil
40
+ end
41
+ end
42
+ Hobo.ui.separator
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+
2
+ desc "Project seed commands"
3
+ namespace :seed do
4
+
5
+ desc "Create a new project from a seed repository"
6
+
7
+ option '-g=', '--git-url=', 'Git repository for project'
8
+ option '-s=', '--seed=', 'Seed name or URL to use'
9
+
10
+ task :plant, [ :name ] do |t, args|
11
+ name = args[:name]
12
+
13
+ Hobo.project_path = File.join(Dir.pwd, name)
14
+
15
+ raise Hobo::UserError.new "Name must match sprint zero guidelines" unless name.match /[a-z0-9\-]+/
16
+ raise Hobo::UserError.new "#{Hobo.project_path} already exists!" if File.exists? Hobo.project_path
17
+
18
+ config = {
19
+ :name => name,
20
+ :project_path => Hobo.project_path,
21
+ :git_url => t.opts[:'git-url'] || Hobo.ui.ask("Repository URL", default: "git@github.com:inviqa/#{name}")
22
+ }
23
+
24
+ seed_name = t.opts[:seed] || Hobo.ui.ask("Project seed", default: "default")
25
+
26
+ config[:seed] = {
27
+ :name => File.basename(seed_name),
28
+ :url => Hobo::Lib::Seed::Seed.name_to_url(seed_name)
29
+ }
30
+
31
+ seed = Hobo::Lib::Seed::Seed.new(
32
+ File.join(Hobo.seed_cache_path, config[:seed][:name]),
33
+ config[:seed][:url]
34
+ )
35
+
36
+ Hobo::Lib::Seed::Project.new().setup(seed, config)
37
+
38
+ Hobo.ui.separator
39
+ Hobo.ui.success "Your new project is available in #{Hobo.project_path}.\n"
40
+ Hobo.ui.success "You will need to review the initial commit and if all is well, push the repository to github using `git push origin --all`."
41
+ Hobo.ui.separator
42
+ end
43
+ end