hem 1.0.1.beta1
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.
- 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
|