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.
- data/Gemfile +4 -0
- data/Gemfile.lock +93 -0
- data/Guardfile +14 -0
- data/Hobofile +34 -0
- data/Rakefile +2 -0
- data/bin/hobo +23 -0
- data/features/deps.feature +43 -0
- data/features/hobo/basic.feature +30 -0
- data/features/hobo/help.feature +12 -0
- data/features/hobo/subcommands.feature +16 -0
- data/features/seed/plant.feature +64 -0
- data/features/step_definitions/seed.rb +11 -0
- data/features/support/env.rb +6 -0
- data/features/vm.feature +0 -0
- data/hobo.gemspec +37 -0
- data/lib/hobo.rb +44 -0
- data/lib/hobo/cli.rb +185 -0
- data/lib/hobo/config/file.rb +21 -0
- data/lib/hobo/error_handlers/debug.rb +9 -0
- data/lib/hobo/error_handlers/friendly.rb +52 -0
- data/lib/hobo/errors.rb +60 -0
- data/lib/hobo/help_formatter.rb +111 -0
- data/lib/hobo/helper/file_locator.rb +39 -0
- data/lib/hobo/helper/shell.rb +59 -0
- data/lib/hobo/lib/seed/project.rb +41 -0
- data/lib/hobo/lib/seed/replacer.rb +57 -0
- data/lib/hobo/lib/seed/seed.rb +43 -0
- data/lib/hobo/metadata.rb +28 -0
- data/lib/hobo/patches/rake.rb +56 -0
- data/lib/hobo/patches/slop.rb +22 -0
- data/lib/hobo/paths.rb +49 -0
- data/lib/hobo/tasks/debug.rb +22 -0
- data/lib/hobo/tasks/deps.rb +45 -0
- data/lib/hobo/tasks/seed.rb +43 -0
- data/lib/hobo/tasks/tools.rb +13 -0
- data/lib/hobo/tasks/vm.rb +49 -0
- data/lib/hobo/ui.rb +96 -0
- data/lib/hobo/util.rb +7 -0
- data/lib/hobo/version.rb +3 -0
- data/spec/hobo/cli_spec.rb +135 -0
- data/spec/hobo/config/file_spec.rb +48 -0
- data/spec/hobo/error_handlers/debug_spec.rb +10 -0
- data/spec/hobo/error_handlers/friendly_spec.rb +81 -0
- data/spec/hobo/error_spec.rb +0 -0
- data/spec/hobo/help_formatter_spec.rb +131 -0
- data/spec/hobo/helpers/file_locator_spec.rb +7 -0
- data/spec/hobo/helpers/shell_spec.rb +7 -0
- data/spec/hobo/lib/seed/project_spec.rb +83 -0
- data/spec/hobo/lib/seed/replacer_spec.rb +47 -0
- data/spec/hobo/lib/seed/seed_spec.rb +95 -0
- data/spec/hobo/metadata_spec.rb +46 -0
- data/spec/hobo/patches/rake_spec.rb +0 -0
- data/spec/hobo/paths_spec.rb +77 -0
- data/spec/hobo/ui_spec.rb +64 -0
- data/spec/spec_helper.rb +6 -0
- 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
|