hobo-inviqa 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|