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.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +10 -0
  3. data/.gitignore +3 -0
  4. data/.rspec +2 -0
  5. data/CHANGELOG.md +125 -0
  6. data/DoD.md +5 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +71 -0
  9. data/Guardfile +14 -0
  10. data/Hemfile +43 -0
  11. data/LICENSE +21 -0
  12. data/README.md +42 -0
  13. data/Rakefile +23 -0
  14. data/bin/hem +64 -0
  15. data/features/deps.feature +43 -0
  16. data/features/hem/basic.feature +43 -0
  17. data/features/hem/help.feature +16 -0
  18. data/features/hem/subcommands.feature +15 -0
  19. data/features/seed/plant.feature +64 -0
  20. data/features/step_definitions/env.rb +6 -0
  21. data/features/step_definitions/seed.rb +11 -0
  22. data/features/support/env.rb +6 -0
  23. data/hem.gemspec +47 -0
  24. data/lib/hem/asset_applicator.rb +33 -0
  25. data/lib/hem/asset_applicators/files.rb +5 -0
  26. data/lib/hem/asset_applicators/sqldump.rb +38 -0
  27. data/lib/hem/cli.rb +252 -0
  28. data/lib/hem/config/file.rb +22 -0
  29. data/lib/hem/config.rb +5 -0
  30. data/lib/hem/error_handlers/debug.rb +12 -0
  31. data/lib/hem/error_handlers/exit_code_map.rb +17 -0
  32. data/lib/hem/error_handlers/friendly.rb +58 -0
  33. data/lib/hem/errors.rb +89 -0
  34. data/lib/hem/help_formatter.rb +118 -0
  35. data/lib/hem/helper/file_locator.rb +44 -0
  36. data/lib/hem/helper/github.rb +10 -0
  37. data/lib/hem/helper/http_download.rb +41 -0
  38. data/lib/hem/helper/shell.rb +101 -0
  39. data/lib/hem/helper/vm_command.rb +30 -0
  40. data/lib/hem/lib/github/api.rb +48 -0
  41. data/lib/hem/lib/github/client.rb +52 -0
  42. data/lib/hem/lib/host_check/deps.rb +39 -0
  43. data/lib/hem/lib/host_check/git.rb +76 -0
  44. data/lib/hem/lib/host_check/ruby.rb +53 -0
  45. data/lib/hem/lib/host_check/vagrant.rb +45 -0
  46. data/lib/hem/lib/host_check.rb +34 -0
  47. data/lib/hem/lib/s3/local/file.rb +40 -0
  48. data/lib/hem/lib/s3/local/iohandler.rb +36 -0
  49. data/lib/hem/lib/s3/remote/file.rb +57 -0
  50. data/lib/hem/lib/s3/remote/iohandler.rb +38 -0
  51. data/lib/hem/lib/s3/sync.rb +134 -0
  52. data/lib/hem/lib/seed/project.rb +71 -0
  53. data/lib/hem/lib/seed/replacer.rb +56 -0
  54. data/lib/hem/lib/seed/seed.rb +111 -0
  55. data/lib/hem/lib/self_signed_cert_generator.rb +38 -0
  56. data/lib/hem/lib/vm/command.rb +131 -0
  57. data/lib/hem/lib/vm/inspector.rb +73 -0
  58. data/lib/hem/logging.rb +20 -0
  59. data/lib/hem/metadata.rb +42 -0
  60. data/lib/hem/null.rb +31 -0
  61. data/lib/hem/patches/deepstruct.rb +21 -0
  62. data/lib/hem/patches/rake.rb +101 -0
  63. data/lib/hem/patches/rubygems.rb +6 -0
  64. data/lib/hem/patches/slop.rb +69 -0
  65. data/lib/hem/paths.rb +96 -0
  66. data/lib/hem/tasks/assets.rb +92 -0
  67. data/lib/hem/tasks/config.rb +15 -0
  68. data/lib/hem/tasks/deps.rb +103 -0
  69. data/lib/hem/tasks/exec.rb +3 -0
  70. data/lib/hem/tasks/magento.rb +281 -0
  71. data/lib/hem/tasks/ops.rb +6 -0
  72. data/lib/hem/tasks/pr.rb +45 -0
  73. data/lib/hem/tasks/seed.rb +61 -0
  74. data/lib/hem/tasks/self.rb +45 -0
  75. data/lib/hem/tasks/shell_init.rb +25 -0
  76. data/lib/hem/tasks/system/completions.rb +76 -0
  77. data/lib/hem/tasks/system.rb +18 -0
  78. data/lib/hem/tasks/tools.rb +17 -0
  79. data/lib/hem/tasks/vm.rb +140 -0
  80. data/lib/hem/ui.rb +182 -0
  81. data/lib/hem/util.rb +76 -0
  82. data/lib/hem/version.rb +3 -0
  83. data/lib/hem.rb +72 -0
  84. data/lib/hobo/tasks/magento.rb +3 -0
  85. data/spec/hem/asset_applicator_spec.rb +30 -0
  86. data/spec/hem/cli_spec.rb +166 -0
  87. data/spec/hem/config/file_spec.rb +55 -0
  88. data/spec/hem/error_handlers/debug_spec.rb +43 -0
  89. data/spec/hem/error_handlers/friendly_spec.rb +97 -0
  90. data/spec/hem/error_spec.rb +0 -0
  91. data/spec/hem/help_formatter_spec.rb +162 -0
  92. data/spec/hem/helpers/file_locator_spec.rb +11 -0
  93. data/spec/hem/helpers/github_spec.rb +31 -0
  94. data/spec/hem/helpers/shell_spec.rb +22 -0
  95. data/spec/hem/helpers/vm_command_spec.rb +96 -0
  96. data/spec/hem/lib/github/api_spec.rb +92 -0
  97. data/spec/hem/lib/s3/sync_spec.rb +16 -0
  98. data/spec/hem/lib/seed/project_spec.rb +80 -0
  99. data/spec/hem/lib/seed/replacer_spec.rb +45 -0
  100. data/spec/hem/lib/seed/seed_spec.rb +127 -0
  101. data/spec/hem/logging_spec.rb +27 -0
  102. data/spec/hem/metadata_spec.rb +55 -0
  103. data/spec/hem/null_spec.rb +30 -0
  104. data/spec/hem/patches/rake_spec.rb +230 -0
  105. data/spec/hem/paths_spec.rb +75 -0
  106. data/spec/hem/ui_spec.rb +189 -0
  107. data/spec/hem/util_spec.rb +74 -0
  108. data/spec/spec_helper.rb +12 -0
  109. data/ssl/ca-bundle-s3.crt +3554 -0
  110. data/test_files/vagrant_fail/vagrant +2 -0
  111. 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