hem 1.0.1.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +10 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +125 -0
- data/DoD.md +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +71 -0
- data/Guardfile +14 -0
- data/Hemfile +43 -0
- data/LICENSE +21 -0
- data/README.md +42 -0
- data/Rakefile +23 -0
- data/bin/hem +64 -0
- data/features/deps.feature +43 -0
- data/features/hem/basic.feature +43 -0
- data/features/hem/help.feature +16 -0
- data/features/hem/subcommands.feature +15 -0
- data/features/seed/plant.feature +64 -0
- data/features/step_definitions/env.rb +6 -0
- data/features/step_definitions/seed.rb +11 -0
- data/features/support/env.rb +6 -0
- data/hem.gemspec +47 -0
- data/lib/hem/asset_applicator.rb +33 -0
- data/lib/hem/asset_applicators/files.rb +5 -0
- data/lib/hem/asset_applicators/sqldump.rb +38 -0
- data/lib/hem/cli.rb +252 -0
- data/lib/hem/config/file.rb +22 -0
- data/lib/hem/config.rb +5 -0
- data/lib/hem/error_handlers/debug.rb +12 -0
- data/lib/hem/error_handlers/exit_code_map.rb +17 -0
- data/lib/hem/error_handlers/friendly.rb +58 -0
- data/lib/hem/errors.rb +89 -0
- data/lib/hem/help_formatter.rb +118 -0
- data/lib/hem/helper/file_locator.rb +44 -0
- data/lib/hem/helper/github.rb +10 -0
- data/lib/hem/helper/http_download.rb +41 -0
- data/lib/hem/helper/shell.rb +101 -0
- data/lib/hem/helper/vm_command.rb +30 -0
- data/lib/hem/lib/github/api.rb +48 -0
- data/lib/hem/lib/github/client.rb +52 -0
- data/lib/hem/lib/host_check/deps.rb +39 -0
- data/lib/hem/lib/host_check/git.rb +76 -0
- data/lib/hem/lib/host_check/ruby.rb +53 -0
- data/lib/hem/lib/host_check/vagrant.rb +45 -0
- data/lib/hem/lib/host_check.rb +34 -0
- data/lib/hem/lib/s3/local/file.rb +40 -0
- data/lib/hem/lib/s3/local/iohandler.rb +36 -0
- data/lib/hem/lib/s3/remote/file.rb +57 -0
- data/lib/hem/lib/s3/remote/iohandler.rb +38 -0
- data/lib/hem/lib/s3/sync.rb +134 -0
- data/lib/hem/lib/seed/project.rb +71 -0
- data/lib/hem/lib/seed/replacer.rb +56 -0
- data/lib/hem/lib/seed/seed.rb +111 -0
- data/lib/hem/lib/self_signed_cert_generator.rb +38 -0
- data/lib/hem/lib/vm/command.rb +131 -0
- data/lib/hem/lib/vm/inspector.rb +73 -0
- data/lib/hem/logging.rb +20 -0
- data/lib/hem/metadata.rb +42 -0
- data/lib/hem/null.rb +31 -0
- data/lib/hem/patches/deepstruct.rb +21 -0
- data/lib/hem/patches/rake.rb +101 -0
- data/lib/hem/patches/rubygems.rb +6 -0
- data/lib/hem/patches/slop.rb +69 -0
- data/lib/hem/paths.rb +96 -0
- data/lib/hem/tasks/assets.rb +92 -0
- data/lib/hem/tasks/config.rb +15 -0
- data/lib/hem/tasks/deps.rb +103 -0
- data/lib/hem/tasks/exec.rb +3 -0
- data/lib/hem/tasks/magento.rb +281 -0
- data/lib/hem/tasks/ops.rb +6 -0
- data/lib/hem/tasks/pr.rb +45 -0
- data/lib/hem/tasks/seed.rb +61 -0
- data/lib/hem/tasks/self.rb +45 -0
- data/lib/hem/tasks/shell_init.rb +25 -0
- data/lib/hem/tasks/system/completions.rb +76 -0
- data/lib/hem/tasks/system.rb +18 -0
- data/lib/hem/tasks/tools.rb +17 -0
- data/lib/hem/tasks/vm.rb +140 -0
- data/lib/hem/ui.rb +182 -0
- data/lib/hem/util.rb +76 -0
- data/lib/hem/version.rb +3 -0
- data/lib/hem.rb +72 -0
- data/lib/hobo/tasks/magento.rb +3 -0
- data/spec/hem/asset_applicator_spec.rb +30 -0
- data/spec/hem/cli_spec.rb +166 -0
- data/spec/hem/config/file_spec.rb +55 -0
- data/spec/hem/error_handlers/debug_spec.rb +43 -0
- data/spec/hem/error_handlers/friendly_spec.rb +97 -0
- data/spec/hem/error_spec.rb +0 -0
- data/spec/hem/help_formatter_spec.rb +162 -0
- data/spec/hem/helpers/file_locator_spec.rb +11 -0
- data/spec/hem/helpers/github_spec.rb +31 -0
- data/spec/hem/helpers/shell_spec.rb +22 -0
- data/spec/hem/helpers/vm_command_spec.rb +96 -0
- data/spec/hem/lib/github/api_spec.rb +92 -0
- data/spec/hem/lib/s3/sync_spec.rb +16 -0
- data/spec/hem/lib/seed/project_spec.rb +80 -0
- data/spec/hem/lib/seed/replacer_spec.rb +45 -0
- data/spec/hem/lib/seed/seed_spec.rb +127 -0
- data/spec/hem/logging_spec.rb +27 -0
- data/spec/hem/metadata_spec.rb +55 -0
- data/spec/hem/null_spec.rb +30 -0
- data/spec/hem/patches/rake_spec.rb +230 -0
- data/spec/hem/paths_spec.rb +75 -0
- data/spec/hem/ui_spec.rb +189 -0
- data/spec/hem/util_spec.rb +74 -0
- data/spec/spec_helper.rb +12 -0
- data/ssl/ca-bundle-s3.crt +3554 -0
- data/test_files/vagrant_fail/vagrant +2 -0
- metadata +339 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module HostCheck
|
4
|
+
class << self
|
5
|
+
include Hem::Lib::HostCheck
|
6
|
+
def check opts = {}
|
7
|
+
opts = {
|
8
|
+
:filter => nil,
|
9
|
+
:raise => false
|
10
|
+
}.merge(opts)
|
11
|
+
|
12
|
+
results = {}
|
13
|
+
methods = Hem::Lib::HostCheck.public_instance_methods(false)
|
14
|
+
methods.each do |method|
|
15
|
+
next if opts[:filter] && !method.match(opts[:filter])
|
16
|
+
|
17
|
+
if opts[:raise]
|
18
|
+
self.send method, opts
|
19
|
+
else
|
20
|
+
begin
|
21
|
+
self.send method, opts
|
22
|
+
results[method] = :ok
|
23
|
+
rescue Hem::Error => error
|
24
|
+
results[method] = error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
return results
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module S3
|
4
|
+
module Local
|
5
|
+
class File
|
6
|
+
def initialize file
|
7
|
+
@file = file
|
8
|
+
end
|
9
|
+
|
10
|
+
def buffer
|
11
|
+
# NOP
|
12
|
+
end
|
13
|
+
|
14
|
+
def size
|
15
|
+
@file.size
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@file.close
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_io
|
23
|
+
@file
|
24
|
+
end
|
25
|
+
|
26
|
+
def copy_from io, opts = {}, &block
|
27
|
+
begin
|
28
|
+
while (data = io.readpartial 16984) do
|
29
|
+
@file.write data
|
30
|
+
yield data if block_given?
|
31
|
+
end
|
32
|
+
rescue EOFError
|
33
|
+
# NOP
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module S3
|
4
|
+
module Local
|
5
|
+
class IoHandler
|
6
|
+
include Hem::Logging
|
7
|
+
|
8
|
+
def initialize path
|
9
|
+
@path = path
|
10
|
+
end
|
11
|
+
|
12
|
+
def ls
|
13
|
+
logger.debug("s3sync: Listing local directory: #{@path}")
|
14
|
+
out = {}
|
15
|
+
dir = "#{@path.chomp('/')}/"
|
16
|
+
files = Dir.glob("#{dir}**/*")
|
17
|
+
files.each do |file|
|
18
|
+
out[file.gsub(/^#{dir}/, '')] = Digest::MD5.file(file).hexdigest
|
19
|
+
end
|
20
|
+
return out
|
21
|
+
end
|
22
|
+
|
23
|
+
def open file, mode
|
24
|
+
file_path = ::File.join(@path, file)
|
25
|
+
FileUtils.mkdir_p ::File.dirname(file_path)
|
26
|
+
File.new ::File.open(file_path, mode)
|
27
|
+
end
|
28
|
+
|
29
|
+
def rm file
|
30
|
+
::File.unlink ::File.join(@path, file)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module S3
|
4
|
+
module Remote
|
5
|
+
class File
|
6
|
+
def initialize object, prefix
|
7
|
+
@object = object
|
8
|
+
@prefix = prefix
|
9
|
+
@r_buffer, @w_buffer = IO.pipe
|
10
|
+
@buffer_thread = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def buffer
|
14
|
+
@buffer_thread = Thread.new do
|
15
|
+
@object.get do |chunk|
|
16
|
+
@w_buffer.write chunk
|
17
|
+
end
|
18
|
+
@w_buffer.close # required for EOF
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def size
|
23
|
+
@object.content_length
|
24
|
+
end
|
25
|
+
|
26
|
+
def close
|
27
|
+
@r_buffer.close unless @r_buffer.closed?
|
28
|
+
@w_buffer.close unless @w_buffer.closed?
|
29
|
+
@buffer_thread.exit if @buffer_thread
|
30
|
+
end
|
31
|
+
|
32
|
+
def read_io
|
33
|
+
@r_buffer
|
34
|
+
end
|
35
|
+
|
36
|
+
# This is a bit nasty but it gets the job done
|
37
|
+
def copy_from io, opts = {}, &block
|
38
|
+
ninety_gb = 1024 * (90000000) # arbitrarily high number
|
39
|
+
opts[:multipart_threshold] = ninety_gb
|
40
|
+
|
41
|
+
if block_given?
|
42
|
+
io.instance_eval "
|
43
|
+
def read bytes
|
44
|
+
data = super bytes
|
45
|
+
@block.call(data)
|
46
|
+
data
|
47
|
+
end"
|
48
|
+
io.instance_variable_set '@block', block
|
49
|
+
end
|
50
|
+
|
51
|
+
@object.upload_file(io, opts)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module S3
|
4
|
+
module Remote
|
5
|
+
class IoHandler
|
6
|
+
include Hem::Logging
|
7
|
+
|
8
|
+
def initialize s3, bucket, prefix
|
9
|
+
@s3 = s3
|
10
|
+
@bucket = bucket
|
11
|
+
@prefix = prefix ? "#{prefix.gsub(/^\//, '').chomp('/')}/" : ""
|
12
|
+
end
|
13
|
+
|
14
|
+
def ls
|
15
|
+
out = {}
|
16
|
+
logger.debug("s3sync: Listing remote bucket: #{@bucket} w/ prefix #{@prefix}")
|
17
|
+
@s3.bucket(@bucket).objects(:prefix => @prefix).each do |file|
|
18
|
+
filename = file.key.gsub(/^#{@prefix}/, '')
|
19
|
+
next if filename == ""
|
20
|
+
out[filename] = file.etag.gsub('"', '')
|
21
|
+
end
|
22
|
+
return out
|
23
|
+
end
|
24
|
+
|
25
|
+
def open file, mode
|
26
|
+
s3_key = ::File.join(@prefix, file)
|
27
|
+
File.new @s3.bucket(@bucket).object(s3_key), @prefix
|
28
|
+
end
|
29
|
+
|
30
|
+
def rm file
|
31
|
+
s3_key = ::File.join(@prefix, file)
|
32
|
+
@s3.bucket(@bucket).object(s3_key).delete
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module S3
|
4
|
+
class Sync
|
5
|
+
include Hem::Logging
|
6
|
+
|
7
|
+
def initialize opts = {}
|
8
|
+
require 'aws-sdk'
|
9
|
+
|
10
|
+
@opts = {
|
11
|
+
:access_key_id => nil,
|
12
|
+
:secret_access_key => nil,
|
13
|
+
:region => 'eu-west-1',
|
14
|
+
:retry_limit => 15
|
15
|
+
}.merge(opts)
|
16
|
+
|
17
|
+
if Hem.windows?
|
18
|
+
Aws.config[:ssl_ca_bundle] = File.expand_path('../../../../../ssl/ca-bundle-s3.crt', __FILE__)
|
19
|
+
end
|
20
|
+
|
21
|
+
handle_s3_error do
|
22
|
+
# AWS::S3 is flakey about actually raising this error when nil is provided
|
23
|
+
[:access_key_id, :secret_access_key].each do |k|
|
24
|
+
raise Aws::Errors::MissingCredentialsError if @opts[k].nil?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
logger.debug("s3sync: Options #{@opts}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def sync source, dest, opts = {}
|
32
|
+
delta = {:add => [], :remove => []}
|
33
|
+
|
34
|
+
handle_s3_error do
|
35
|
+
opts = {
|
36
|
+
:delete => true,
|
37
|
+
:dry => false,
|
38
|
+
:progress => Hem.method(:progress)
|
39
|
+
}.merge(opts)
|
40
|
+
|
41
|
+
source_io = io_handler(source)
|
42
|
+
destination_io = io_handler(dest)
|
43
|
+
|
44
|
+
logger.debug("s3sync: Synchronzing (#{source_io.class.name} -> #{destination_io.class.name}")
|
45
|
+
|
46
|
+
raise "S3 -> S3 synchronisation not supported" if source_io.is_a? Remote and destination_io.is_a? Remote
|
47
|
+
|
48
|
+
source_listing = source_io.ls
|
49
|
+
destination_listing = destination_io.ls
|
50
|
+
logger.debug("s3sync: Source listing - #{source_listing}")
|
51
|
+
logger.debug("s3sync: Destination listing - #{destination_listing}")
|
52
|
+
|
53
|
+
delta = delta(source_listing, destination_listing)
|
54
|
+
logger.debug("s3sync: Delta #{delta}")
|
55
|
+
break if opts[:dry]
|
56
|
+
|
57
|
+
delta[:add].each do |file|
|
58
|
+
logger.debug("s3sync: Synchronizing #{file}")
|
59
|
+
source_file = source_io.open(file, "r")
|
60
|
+
destination_file = destination_io.open(file, "wb+")
|
61
|
+
|
62
|
+
source_file.buffer
|
63
|
+
|
64
|
+
size = source_file.size
|
65
|
+
destination_file.copy_from(source_file.read_io, :content_length => size) do |chunk|
|
66
|
+
opts[:progress].call(file, (chunk || '').length, size, :update)
|
67
|
+
end
|
68
|
+
|
69
|
+
destination_file.close
|
70
|
+
source_file.close
|
71
|
+
|
72
|
+
opts[:progress].call(file, 0, size, :finish)
|
73
|
+
end
|
74
|
+
break unless opts[:delete]
|
75
|
+
|
76
|
+
delta[:remove].each do |file|
|
77
|
+
logger.debug("s3sync: Removing #{file}")
|
78
|
+
destination_io.rm(file)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
return delta
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def s3
|
88
|
+
@s3 ||= Aws::S3::Resource.new @opts
|
89
|
+
end
|
90
|
+
|
91
|
+
def handle_s3_error
|
92
|
+
exception = Hem::Error.new("Could not sync assets")
|
93
|
+
begin
|
94
|
+
yield
|
95
|
+
rescue Errno::ENETUNREACH
|
96
|
+
Hem.ui.error " Could not contact Amazon servers."
|
97
|
+
Hem.ui.error " This can sometimes be caused by missing AWS credentials"
|
98
|
+
raise exception
|
99
|
+
rescue Aws::S3::Errors::NoSuchBucket
|
100
|
+
Hem.ui.error " Asset bucket #{Hem.project_config.asset_bucket} does not exist!"
|
101
|
+
# We allow this one to be skipped as there are obviously no assets to sync
|
102
|
+
rescue Aws::S3::Errors::AccessDenied
|
103
|
+
Hem.ui.error " Your AWS key does not have access to the #{Hem.project_config.asset_bucket} S3 bucket!"
|
104
|
+
Hem.ui.error " Please request access to this bucket from your TTL or via an internal support request"
|
105
|
+
raise exception
|
106
|
+
rescue Aws::Errors::MissingCredentialsError
|
107
|
+
Hem.ui.warning " AWS credentials not set!"
|
108
|
+
Hem.ui.warning " Please request credentials from internalsupport@inviqa.com or in #devops and configure them with `hem config`"
|
109
|
+
raise exception
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def delta source, dest
|
114
|
+
to_add = (source.sort - dest.sort).map(&:first)
|
115
|
+
to_remove = (dest.sort - source.sort).map(&:first)
|
116
|
+
to_remove = to_remove - to_add
|
117
|
+
|
118
|
+
{
|
119
|
+
:add => to_add,
|
120
|
+
:remove => to_remove
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def io_handler uri
|
125
|
+
require 'uri'
|
126
|
+
parsed = URI.parse(uri)
|
127
|
+
parsed.scheme == 's3' ?
|
128
|
+
Remote::IoHandler.new(s3, parsed.host, parsed.path) :
|
129
|
+
Local::IoHandler.new(uri)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module Seed
|
4
|
+
class Project
|
5
|
+
def initialize(opts = {})
|
6
|
+
@opts = {
|
7
|
+
:replacer => Replacer.new,
|
8
|
+
:config_class => Hem::Config::File,
|
9
|
+
:project_config_file => Hem.project_config_file,
|
10
|
+
:ssl_cert_generator => Hem::Lib::SelfSignedCertGenerator
|
11
|
+
}.merge! opts
|
12
|
+
end
|
13
|
+
|
14
|
+
def setup seed, config
|
15
|
+
seed.update
|
16
|
+
seed.export config[:project_path], config
|
17
|
+
config[:seed][:version] = seed.version
|
18
|
+
config[:hostname] = "#{config[:name]}.dev"
|
19
|
+
config[:asset_bucket] = "inviqa-assets-#{config[:name]}"
|
20
|
+
config[:vm] = {
|
21
|
+
:project_mount_path => "/vagrant"
|
22
|
+
}
|
23
|
+
config[:ssl] = @opts[:ssl_cert_generator].generate config[:hostname]
|
24
|
+
config[:chef_ssl] = {}
|
25
|
+
config[:ssl].each do |k, v|
|
26
|
+
config[:chef_ssl][k] = v.gsub("\n", "\\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
@opts[:replacer].replace(config[:project_path], config)
|
30
|
+
load_seed_init(config)
|
31
|
+
|
32
|
+
project_path = config[:project_path]
|
33
|
+
config.delete :project_path
|
34
|
+
config.delete :ssl
|
35
|
+
config.delete :chef_ssl
|
36
|
+
@opts[:config_class].save @opts[:project_config_file], config
|
37
|
+
|
38
|
+
initialize_git project_path, config[:git_url]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def load_seed_init config
|
44
|
+
Hem.project_config = DeepStruct.wrap(config)
|
45
|
+
seed_init_file = File.join(config[:project_path], 'seedinit.rb')
|
46
|
+
if File.exists?(seed_init_file)
|
47
|
+
require seed_init_file
|
48
|
+
File.unlink(seed_init_file)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize_git path, git_url
|
53
|
+
Dir.chdir path do
|
54
|
+
Hem::Helper.shell 'git', 'init'
|
55
|
+
Hem::Helper.shell 'git', 'add', '--all'
|
56
|
+
Hem::Helper.shell 'git', 'commit', '-m', "'Initial hem project'"
|
57
|
+
Hem::Helper.shell 'git', 'checkout', '-b', 'develop'
|
58
|
+
|
59
|
+
# Github for windows gets clever adding origin / upstream remotes in system level gitconfig
|
60
|
+
# :facepalm:
|
61
|
+
begin
|
62
|
+
Hem::Helper.shell 'git', 'remote', 'add', 'origin', git_url
|
63
|
+
rescue Hem::ExternalCommandError
|
64
|
+
Hem::Helper.shell 'git', 'remote', 'set-url', 'origin', git_url
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module Seed
|
4
|
+
class Replacer
|
5
|
+
# Matching files/directories to be excluded from replacements
|
6
|
+
EXCLUDES = ["\\.git/", "^./bin", "^./lib", "^./spec"]
|
7
|
+
|
8
|
+
def replace(path, tokens)
|
9
|
+
if tokens.instance_of? Hash
|
10
|
+
tokens = flat_hash(tokens)
|
11
|
+
elsif !tokens.instance_of? Array
|
12
|
+
raise "Invalid token list (expected Array or Hash)"
|
13
|
+
end
|
14
|
+
|
15
|
+
return search_replace(path, tokens)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def search_replace(path, tokens, &block)
|
21
|
+
require 'find'
|
22
|
+
files = []
|
23
|
+
excludes = Regexp.new(EXCLUDES.join("|"))
|
24
|
+
Find.find(path) do |candidate|
|
25
|
+
Find.prune if candidate =~ excludes # Skip excluded
|
26
|
+
next unless FileTest.file? candidate # Skip unless file
|
27
|
+
|
28
|
+
content = File.read(candidate)
|
29
|
+
next unless content.force_encoding("UTF-8").valid_encoding? # Skip unless file can be valid UTF-8
|
30
|
+
|
31
|
+
match = false
|
32
|
+
tokens.each do |token, replacement|
|
33
|
+
token = "{{#{token.join('.')}}}"
|
34
|
+
match = content.match(token)
|
35
|
+
if match
|
36
|
+
content.gsub!(token, replacement)
|
37
|
+
files.push(candidate)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
File.write(candidate, content) if files.include? candidate
|
42
|
+
end
|
43
|
+
return files.uniq
|
44
|
+
end
|
45
|
+
|
46
|
+
# http://stackoverflow.com/questions/9647997/converting-a-nested-hash-into-a-flat-hash
|
47
|
+
def flat_hash(hash, k = [])
|
48
|
+
return {k => hash} unless hash.is_a?(Hash)
|
49
|
+
hash.inject({}) do |h, v|
|
50
|
+
h.merge! flat_hash(v[-1], k + [v[0]])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
module Seed
|
4
|
+
class Seed
|
5
|
+
include Hem::Logging
|
6
|
+
|
7
|
+
def initialize(seed_path, url)
|
8
|
+
@seed_path = seed_path
|
9
|
+
@url = url
|
10
|
+
end
|
11
|
+
|
12
|
+
def tags
|
13
|
+
tags = []
|
14
|
+
Dir.chdir @seed_path do
|
15
|
+
tag_output = Hem::Helper.shell "git tag", :capture => true
|
16
|
+
tags = tag_output.split("\n")
|
17
|
+
end
|
18
|
+
tags
|
19
|
+
end
|
20
|
+
|
21
|
+
def export path, opts = {}
|
22
|
+
opts = {
|
23
|
+
:name => 'seed',
|
24
|
+
:ref => 'master'
|
25
|
+
}.merge(opts)
|
26
|
+
|
27
|
+
path = File.expand_path(path)
|
28
|
+
FileUtils.mkdir_p path
|
29
|
+
|
30
|
+
Hem.ui.success "Exporting #{opts[:name]} to #{path}"
|
31
|
+
|
32
|
+
tmp_path = Dir.mktmpdir("hem-seed-export")
|
33
|
+
|
34
|
+
Dir.chdir @seed_path do
|
35
|
+
Hem::Helper.shell "git clone --branch #{opts[:ref].shellescape} . #{tmp_path}"
|
36
|
+
end
|
37
|
+
|
38
|
+
Dir.chdir tmp_path do
|
39
|
+
Hem::Helper.shell "git archive #{opts[:ref].shellescape} | tar -x -C #{path.shellescape}"
|
40
|
+
|
41
|
+
submodules = Hem::Helper.shell "git submodule status", :capture => true, :strip => false
|
42
|
+
|
43
|
+
next if submodules.empty?
|
44
|
+
|
45
|
+
Hem.ui.success "Cloning submodules"
|
46
|
+
Hem::Helper.shell "git submodule update --init", :realtime => true, :indent => 2
|
47
|
+
|
48
|
+
# Export submodules
|
49
|
+
# git submodule foreach does not play nice on windows so we fake it here
|
50
|
+
submodules.split("\n").each do |line|
|
51
|
+
matches = line.match /^[\s-][a-z0-9]+ (.+)/
|
52
|
+
next unless matches
|
53
|
+
submodule_path = matches[1]
|
54
|
+
Hem.ui.success "Exporting '#{submodule_path}' #{opts[:name]} submodule"
|
55
|
+
Hem::Helper.shell "cd #{tmp_path}/#{submodule_path.shellescape} && git archive HEAD | tar -x -C #{path}/#{submodule_path.shellescape}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
FileUtils.rm_f tmp_path
|
60
|
+
end
|
61
|
+
|
62
|
+
def update
|
63
|
+
Hem.ui.success "Fetching / Updating seed"
|
64
|
+
FileUtils.mkdir_p @seed_path
|
65
|
+
if File.exists? File.join(@seed_path, 'HEAD')
|
66
|
+
Dir.chdir @seed_path do
|
67
|
+
logger.info "Updating seed in #{@seed_path}"
|
68
|
+
# Need to be specific here as GH for windows adds an invalid "upstream" remote to all repos
|
69
|
+
Hem::Helper.shell 'git', 'fetch', 'origin'
|
70
|
+
end
|
71
|
+
else
|
72
|
+
logger.info "Cloning seed from #{@url} to #{@seed_path}"
|
73
|
+
Hem::Helper.shell 'git', 'clone', @url, @seed_path, '--mirror'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def vm_ip
|
78
|
+
[
|
79
|
+
10,
|
80
|
+
10,
|
81
|
+
[*0..255].sample,
|
82
|
+
[*2..255].sample
|
83
|
+
].join('.')
|
84
|
+
end
|
85
|
+
|
86
|
+
def version
|
87
|
+
Dir.chdir @seed_path do
|
88
|
+
Hem::Helper.shell 'git', 'rev-parse', '--short', 'HEAD', :capture => true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class << self
|
93
|
+
def name_to_url name, options = {}
|
94
|
+
options = {
|
95
|
+
:use_short_seed_name => true
|
96
|
+
}.merge(options)
|
97
|
+
|
98
|
+
path = File.expand_path name
|
99
|
+
if name.include?(':')
|
100
|
+
name
|
101
|
+
elsif !options[:use_short_seed_name] || (name.match(/^(\.|\/|~)/) && path)
|
102
|
+
path
|
103
|
+
else
|
104
|
+
"git@github.com:inviqa/hem-seed-#{name}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hem
|
2
|
+
module Lib
|
3
|
+
class SelfSignedCertGenerator
|
4
|
+
def self.generate domain
|
5
|
+
require 'openssl'
|
6
|
+
key = OpenSSL::PKey::RSA.new(2048)
|
7
|
+
public_key = key.public_key
|
8
|
+
|
9
|
+
subject = "/C=UK/ST=/O=Inviqa/localityName=London/commonName=*.#{domain}/organizationalUnitName=/emailAddress=support@inviqa.com"
|
10
|
+
|
11
|
+
cert = OpenSSL::X509::Certificate.new
|
12
|
+
cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
|
13
|
+
cert.not_before = Time.now
|
14
|
+
cert.not_after = Time.now + 365 * 24 * 60 * 60
|
15
|
+
cert.public_key = public_key
|
16
|
+
cert.serial = 0x0
|
17
|
+
cert.version = 2
|
18
|
+
|
19
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
20
|
+
ef.subject_certificate = cert
|
21
|
+
ef.issuer_certificate = cert
|
22
|
+
cert.extensions = [
|
23
|
+
ef.create_extension("basicConstraints","CA:TRUE", true),
|
24
|
+
ef.create_extension("subjectKeyIdentifier", "hash")
|
25
|
+
]
|
26
|
+
|
27
|
+
cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
|
28
|
+
|
29
|
+
cert.sign key, OpenSSL::Digest::SHA1.new
|
30
|
+
|
31
|
+
{
|
32
|
+
:key => key.to_pem.to_s.strip,
|
33
|
+
:cert => cert.to_pem.to_s.strip
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|