aggkit 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +20 -0
  3. data/.gitignore +109 -0
  4. data/.gitlab-ci.yml +66 -0
  5. data/.rspec +4 -0
  6. data/.rubocop.yml +98 -0
  7. data/.travis.yml +30 -0
  8. data/Gemfile +12 -0
  9. data/Gemfile.lock +55 -0
  10. data/README.md +96 -0
  11. data/aggkit.gemspec +38 -0
  12. data/bin/agg +167 -0
  13. data/bin/aggconsul +222 -0
  14. data/bin/agglock +71 -0
  15. data/bin/aggmerge +118 -0
  16. data/bin/aggwait +262 -0
  17. data/bin/consul.rb +222 -0
  18. data/bin/locker.rb +71 -0
  19. data/bin/merger.rb +118 -0
  20. data/bin/terminator.rb +71 -0
  21. data/bin/waiter.rb +262 -0
  22. data/docker/Dockerfile +112 -0
  23. data/docker/docker-compose.yml +12 -0
  24. data/docker/down.sh +4 -0
  25. data/docker/run_tests.sh +23 -0
  26. data/lib/aggkit/childprocess/abstract_io.rb +38 -0
  27. data/lib/aggkit/childprocess/abstract_process.rb +194 -0
  28. data/lib/aggkit/childprocess/errors.rb +28 -0
  29. data/lib/aggkit/childprocess/jruby/io.rb +17 -0
  30. data/lib/aggkit/childprocess/jruby/process.rb +161 -0
  31. data/lib/aggkit/childprocess/jruby/pump.rb +55 -0
  32. data/lib/aggkit/childprocess/jruby.rb +58 -0
  33. data/lib/aggkit/childprocess/tools/generator.rb +148 -0
  34. data/lib/aggkit/childprocess/unix/fork_exec_process.rb +72 -0
  35. data/lib/aggkit/childprocess/unix/io.rb +22 -0
  36. data/lib/aggkit/childprocess/unix/lib.rb +188 -0
  37. data/lib/aggkit/childprocess/unix/platform/i386-linux.rb +14 -0
  38. data/lib/aggkit/childprocess/unix/platform/i386-solaris.rb +13 -0
  39. data/lib/aggkit/childprocess/unix/platform/x86_64-linux.rb +14 -0
  40. data/lib/aggkit/childprocess/unix/platform/x86_64-macosx.rb +13 -0
  41. data/lib/aggkit/childprocess/unix/posix_spawn_process.rb +135 -0
  42. data/lib/aggkit/childprocess/unix/process.rb +91 -0
  43. data/lib/aggkit/childprocess/unix.rb +11 -0
  44. data/lib/aggkit/childprocess/version.rb +5 -0
  45. data/lib/aggkit/childprocess/windows/handle.rb +93 -0
  46. data/lib/aggkit/childprocess/windows/io.rb +25 -0
  47. data/lib/aggkit/childprocess/windows/lib.rb +418 -0
  48. data/lib/aggkit/childprocess/windows/process.rb +132 -0
  49. data/lib/aggkit/childprocess/windows/process_builder.rb +177 -0
  50. data/lib/aggkit/childprocess/windows/structs.rb +151 -0
  51. data/lib/aggkit/childprocess/windows.rb +35 -0
  52. data/lib/aggkit/childprocess.rb +213 -0
  53. data/lib/aggkit/env.rb +219 -0
  54. data/lib/aggkit/runner.rb +80 -0
  55. data/lib/aggkit/version.rb +5 -0
  56. data/lib/aggkit/watcher.rb +239 -0
  57. data/lib/aggkit.rb +15 -0
  58. metadata +196 -0
@@ -0,0 +1,151 @@
1
+ module Aggkit
2
+ module ChildProcess
3
+ module Windows
4
+ # typedef struct _STARTUPINFO {
5
+ # DWORD cb;
6
+ # LPTSTR lpReserved;
7
+ # LPTSTR lpDesktop;
8
+ # LPTSTR lpTitle;
9
+ # DWORD dwX;
10
+ # DWORD dwY;
11
+ # DWORD dwXSize;
12
+ # DWORD dwYSize;
13
+ # DWORD dwXCountChars;
14
+ # DWORD dwYCountChars;
15
+ # DWORD dwFillAttribute;
16
+ # DWORD dwFlags;
17
+ # WORD wShowWindow;
18
+ # WORD cbReserved2;
19
+ # LPBYTE lpReserved2;
20
+ # HANDLE hStdInput;
21
+ # HANDLE hStdOutput;
22
+ # HANDLE hStdError;
23
+ # } STARTUPINFO, *LPSTARTUPINFO;
24
+
25
+ class StartupInfo < FFI::Struct
26
+ layout :cb, :ulong,
27
+ :lpReserved, :pointer,
28
+ :lpDesktop, :pointer,
29
+ :lpTitle, :pointer,
30
+ :dwX, :ulong,
31
+ :dwY, :ulong,
32
+ :dwXSize, :ulong,
33
+ :dwYSize, :ulong,
34
+ :dwXCountChars, :ulong,
35
+ :dwYCountChars, :ulong,
36
+ :dwFillAttribute, :ulong,
37
+ :dwFlags, :ulong,
38
+ :wShowWindow, :ushort,
39
+ :cbReserved2, :ushort,
40
+ :lpReserved2, :pointer,
41
+ :hStdInput, :pointer, # void ptr
42
+ :hStdOutput, :pointer, # void ptr
43
+ :hStdError, :pointer # void ptr
44
+ end
45
+
46
+ #
47
+ # typedef struct _PROCESS_INFORMATION {
48
+ # HANDLE hProcess;
49
+ # HANDLE hThread;
50
+ # DWORD dwProcessId;
51
+ # DWORD dwThreadId;
52
+ # } PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
53
+ #
54
+
55
+ class ProcessInfo < FFI::Struct
56
+ layout :hProcess, :pointer, # void ptr
57
+ :hThread, :pointer, # void ptr
58
+ :dwProcessId, :ulong,
59
+ :dwThreadId, :ulong
60
+ end
61
+
62
+ #
63
+ # typedef struct _SECURITY_ATTRIBUTES {
64
+ # DWORD nLength;
65
+ # LPVOID lpSecurityDescriptor;
66
+ # BOOL bInheritHandle;
67
+ # } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
68
+ #
69
+
70
+ class SecurityAttributes < FFI::Struct
71
+ layout :nLength, :ulong,
72
+ :lpSecurityDescriptor, :pointer, # void ptr
73
+ :bInheritHandle, :int
74
+
75
+ def initialize(opts = {})
76
+ super()
77
+
78
+ self[:nLength] = self.class.size
79
+ self[:lpSecurityDescriptor] = nil
80
+ self[:bInheritHandle] = opts[:inherit] ? 1 : 0
81
+ end
82
+ end
83
+
84
+ #
85
+ # typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION {
86
+ # LARGE_INTEGER PerProcessUserTimeLimit;
87
+ # LARGE_INTEGER PerJobUserTimeLimit;
88
+ # DWORD LimitFlags;
89
+ # SIZE_T MinimumWorkingSetSize;
90
+ # SIZE_T MaximumWorkingSetSize;
91
+ # DWORD ActiveProcessLimit;
92
+ # ULONG_PTR Affinity;
93
+ # DWORD PriorityClass;
94
+ # DWORD SchedulingClass;
95
+ # } JOBOBJECT_BASIC_LIMIT_INFORMATION, *PJOBOBJECT_BASIC_LIMIT_INFORMATION;
96
+ #
97
+ class JobObjectBasicLimitInformation < FFI::Struct
98
+ layout :PerProcessUserTimeLimit, :int64,
99
+ :PerJobUserTimeLimit, :int64,
100
+ :LimitFlags, :ulong,
101
+ :MinimumWorkingSetSize, :size_t,
102
+ :MaximumWorkingSetSize, :size_t,
103
+ :ActiveProcessLimit, :ulong,
104
+ :Affinity, :pointer,
105
+ :PriorityClass, :ulong,
106
+ :SchedulingClass, :ulong
107
+ end
108
+
109
+ #
110
+ # typedef struct _IO_COUNTERS {
111
+ # ULONGLONG ReadOperationCount;
112
+ # ULONGLONG WriteOperationCount;
113
+ # ULONGLONG OtherOperationCount;
114
+ # ULONGLONG ReadTransferCount;
115
+ # ULONGLONG WriteTransferCount;
116
+ # ULONGLONG OtherTransferCount;
117
+ # } IO_COUNTERS, *PIO_COUNTERS;
118
+ #
119
+
120
+ class IoCounters < FFI::Struct
121
+ layout :ReadOperationCount, :ulong_long,
122
+ :WriteOperationCount, :ulong_long,
123
+ :OtherOperationCount, :ulong_long,
124
+ :ReadTransferCount, :ulong_long,
125
+ :WriteTransferCount, :ulong_long,
126
+ :OtherTransferCount, :ulong_long
127
+ end
128
+ #
129
+ # typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
130
+ # JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
131
+ # IO_COUNTERS IoInfo;
132
+ # SIZE_T ProcessMemoryLimit;
133
+ # SIZE_T JobMemoryLimit;
134
+ # SIZE_T PeakProcessMemoryUsed;
135
+ # SIZE_T PeakJobMemoryUsed;
136
+ # } JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;
137
+ #
138
+
139
+ class JobObjectExtendedLimitInformation < FFI::Struct
140
+ layout :BasicLimitInformation, JobObjectBasicLimitInformation,
141
+ :IoInfo, IoCounters,
142
+ :ProcessMemoryLimit, :size_t,
143
+ :JobMemoryLimit, :size_t,
144
+ :PeakProcessMemoryUsed, :size_t,
145
+ :PeakJobMemoryUsed, :size_t
146
+ end
147
+
148
+
149
+ end # Windows
150
+ end # ChildProcess
151
+ end
@@ -0,0 +1,35 @@
1
+ require "ffi"
2
+ require "rbconfig"
3
+
4
+ module Aggkit
5
+ module ChildProcess
6
+ module Windows
7
+ module Lib
8
+ extend FFI::Library
9
+
10
+ def self.msvcrt_name
11
+ host_part = RbConfig::CONFIG['host_os'].split("_")[1]
12
+ manifest = File.join(RbConfig::CONFIG['bindir'], 'ruby.exe.manifest')
13
+
14
+ if host_part && host_part.to_i > 80 && File.exists?(manifest)
15
+ "msvcr#{host_part}"
16
+ else
17
+ "msvcrt"
18
+ end
19
+ end
20
+
21
+ ffi_lib "kernel32", msvcrt_name
22
+ ffi_convention :stdcall
23
+
24
+
25
+ end # Library
26
+ end # Windows
27
+ end # ChildProcess
28
+ end Aggkit
29
+
30
+ require "aggkit/childprocess/windows/lib"
31
+ require "aggkit/childprocess/windows/structs"
32
+ require "aggkit/childprocess/windows/handle"
33
+ require "aggkit/childprocess/windows/io"
34
+ require "aggkit/childprocess/windows/process_builder"
35
+ require "aggkit/childprocess/windows/process"
@@ -0,0 +1,213 @@
1
+ require 'aggkit/childprocess/version'
2
+ require 'aggkit/childprocess/errors'
3
+ require 'aggkit/childprocess/abstract_process'
4
+ require 'aggkit/childprocess/abstract_io'
5
+ require 'fcntl'
6
+ require 'logger'
7
+
8
+ module Aggkit
9
+
10
+ module ChildProcess
11
+
12
+
13
+ @posix_spawn = false
14
+
15
+ class << self
16
+
17
+
18
+ attr_writer :logger
19
+
20
+ def new(*args)
21
+ case os
22
+ when :macosx, :linux, :solaris, :bsd, :cygwin, :aix
23
+ if posix_spawn?
24
+ Unix::PosixSpawnProcess.new(args)
25
+ elsif jruby?
26
+ JRuby::Process.new(args)
27
+ else
28
+ Unix::ForkExecProcess.new(args)
29
+ end
30
+ when :windows
31
+ Windows::Process.new(args)
32
+ else
33
+ raise Error.new("unsupported platform #{platform_name.inspect}")
34
+ end
35
+ end
36
+ alias build new
37
+
38
+ def logger
39
+ return @logger if defined?(@logger) && @logger
40
+
41
+ @logger = Logger.new($stderr)
42
+ @logger.level = $DEBUG ? Logger::DEBUG : Logger::INFO
43
+
44
+ @logger
45
+ end
46
+
47
+ def platform
48
+ if RUBY_PLATFORM == 'java'
49
+ :jruby
50
+ elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ironruby'
51
+ :ironruby
52
+ else
53
+ os
54
+ end
55
+ end
56
+
57
+ def platform_name
58
+ @platform_name ||= "#{arch}-#{os}"
59
+ end
60
+
61
+ def unix?
62
+ !windows?
63
+ end
64
+
65
+ def linux?
66
+ os == :linux
67
+ end
68
+
69
+ def jruby?
70
+ platform == :jruby
71
+ end
72
+
73
+ def windows?
74
+ os == :windows
75
+ end
76
+
77
+ def posix_spawn?
78
+ enabled = @posix_spawn || %w[1 true].include?(ENV['CHILDPROCESS_POSIX_SPAWN'])
79
+ return false unless enabled
80
+
81
+ require 'ffi'
82
+ begin
83
+ require "childprocess/unix/platform/#{ChildProcess.platform_name}"
84
+ rescue LoadError
85
+ raise ChildProcess::MissingPlatformError
86
+ end
87
+
88
+ require 'childprocess/unix/lib'
89
+ require 'childprocess/unix/posix_spawn_process'
90
+
91
+ true
92
+ rescue ChildProcess::MissingPlatformError => ex
93
+ warn_once ex.message
94
+ false
95
+ end
96
+
97
+ #
98
+ # Set this to true to enable experimental use of posix_spawn.
99
+ #
100
+
101
+ attr_writer :posix_spawn
102
+
103
+ def os
104
+ @os ||= begin
105
+ require 'rbconfig'
106
+ host_os = RbConfig::CONFIG['host_os'].downcase
107
+
108
+ case host_os
109
+ when /linux/
110
+ :linux
111
+ when /darwin|mac os/
112
+ :macosx
113
+ when /mswin|msys|mingw32/
114
+ :windows
115
+ when /cygwin/
116
+ :cygwin
117
+ when /solaris|sunos/
118
+ :solaris
119
+ when /bsd|dragonfly/
120
+ :bsd
121
+ when /aix/
122
+ :aix
123
+ else
124
+ raise Error.new("unknown os: #{host_os.inspect}")
125
+ end
126
+ end
127
+ end
128
+
129
+ def arch
130
+ @arch ||= begin
131
+ host_cpu = RbConfig::CONFIG['host_cpu'].downcase
132
+ case host_cpu
133
+ when /i[3456]86/
134
+ if workaround_older_macosx_misreported_cpu?
135
+ # Workaround case: older 64-bit Darwin Rubies misreported as i686
136
+ 'x86_64'
137
+ else
138
+ 'i386'
139
+ end
140
+ when /amd64|x86_64/
141
+ 'x86_64'
142
+ when /ppc|powerpc/
143
+ 'powerpc'
144
+ else
145
+ host_cpu
146
+ end
147
+ end
148
+ end
149
+
150
+ #
151
+ # By default, a child process will inherit open file descriptors from the
152
+ # parent process. This helper provides a cross-platform way of making sure
153
+ # that doesn't happen for the given file/io.
154
+ #
155
+
156
+ def close_on_exec(file)
157
+ if file.respond_to?(:close_on_exec=)
158
+ file.close_on_exec = true
159
+ elsif file.respond_to?(:fcntl) && defined?(Fcntl::FD_CLOEXEC)
160
+ file.fcntl Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
161
+
162
+ if jruby? && posix_spawn?
163
+ # on JRuby, the fcntl call above apparently isn't enough when
164
+ # we're launching the process through posix_spawn.
165
+ fileno = JRuby.posix_fileno_for(file)
166
+ Unix::Lib.fcntl fileno, Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
167
+ end
168
+ elsif windows?
169
+ Windows::Lib.dont_inherit file
170
+ else
171
+ raise Error.new("not sure how to set close-on-exec for #{file.inspect} on #{platform_name.inspect}")
172
+ end
173
+ end
174
+
175
+ private
176
+
177
+ def warn_once(msg)
178
+ @warnings ||= {}
179
+
180
+ unless @warnings[msg]
181
+ @warnings[msg] = true
182
+ logger.warn msg
183
+ end
184
+ end
185
+
186
+ # Workaround: detect the situation that an older Darwin Ruby is actually
187
+ # 64-bit, but is misreporting cpu as i686, which would imply 32-bit.
188
+ #
189
+ # @return [Boolean] `true` if:
190
+ # (a) on Mac OS X
191
+ # (b) actually running in 64-bit mode
192
+ def workaround_older_macosx_misreported_cpu?
193
+ os == :macosx && is_64_bit?
194
+ end
195
+
196
+ # @return [Boolean] `true` if this Ruby represents `1` in 64 bits (8 bytes).
197
+ def is_64_bit?
198
+ 1.size == 8
199
+ end
200
+
201
+
202
+ end # class << self
203
+
204
+
205
+ end # ChildProcess
206
+
207
+ end # Aggkit
208
+
209
+ require 'jruby' if Aggkit::ChildProcess.jruby?
210
+
211
+ require 'aggkit/childprocess/unix' if Aggkit::ChildProcess.unix?
212
+ require 'aggkit/childprocess/windows' if Aggkit::ChildProcess.windows?
213
+ require 'aggkit/childprocess/jruby' if Aggkit::ChildProcess.jruby?
data/lib/aggkit/env.rb ADDED
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'English'
4
+ require 'dotenv'
5
+
6
+ module Dotenv
7
+ module_function
8
+
9
+ def load_without_export(*filenames)
10
+ with(*filenames) do |f|
11
+ ignoring_nonexistent_files do
12
+ Environment.new(f, true)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ module Aggkit
19
+
20
+ class Env
21
+ attr_accessor :project, :name, :env_root, :environment
22
+
23
+ def self.list path = Dir.pwd
24
+ root = Project.new(path).project_root
25
+ Pathfinder.new(root).each_env
26
+ end
27
+
28
+ def self.with_env env, &block
29
+ current_env = ENV.to_h
30
+ env.each_pair do |k, v|
31
+ ENV[k.to_s] = v.to_s
32
+ end
33
+ yield
34
+ ensure
35
+ (env.keys.map(&:to_s) - current_env.keys).each do |key|
36
+ ENV.delete(key.to_s)
37
+ end
38
+
39
+ current_env.each_pair do |k, v|
40
+ ENV[k.to_s] = v.to_s
41
+ end
42
+ end
43
+
44
+ def initialize path
45
+ @project = if File.directory?(File.expand_path(path))
46
+ @name = File.basename(File.realpath(File.expand_path(path)))
47
+ Project.new(path)
48
+ else
49
+ @name = path.strip
50
+ Project.new(Dir.pwd)
51
+ end
52
+
53
+ if !self.class.list.include?(@name)
54
+ raise "There no env #{@name.inspect} in project: #{project.project_root.inspect}"
55
+ end
56
+
57
+ @env_root = File.join(project_root, 'envs', @name)
58
+
59
+ @environment = prepare_environment
60
+ end
61
+
62
+ def with_env &block
63
+ Env.with_env(environment) &block
64
+ end
65
+
66
+ def project_root
67
+ project.project_root
68
+ end
69
+
70
+ def core_root
71
+ project.core_root
72
+ end
73
+
74
+ def dot_file
75
+ File.join(env_root, '.env')
76
+ end
77
+
78
+ def project_dot_file
79
+ File.join(project_root, '.env')
80
+ end
81
+
82
+ def core_dot_file
83
+ File.join(core_root, '.env') rescue nil
84
+ end
85
+
86
+ def env_files
87
+ [core_dot_file, project_dot_file, dot_file].compact.select{|f| File.exists?(f)}.uniq
88
+ end
89
+
90
+ def show
91
+ {
92
+ name: name,
93
+ project_root: project_root,
94
+ core_root: core_root,
95
+ envfiles: env_files,
96
+ envs: environment,
97
+ }
98
+ end
99
+
100
+ private
101
+
102
+
103
+ def prepare_environment
104
+ base_env = {
105
+ 'ENV_ROOT' => env_root,
106
+ 'PROJECT_ROOT' => project_root,
107
+ 'CORE_ROOT' => core_root,
108
+ 'PATH' => check_path_variable(env_root),
109
+ }
110
+
111
+ dot_env = prepare_dot(base_env)
112
+
113
+ compose_env = prepare_compose(dot_env.merge(base_env))
114
+
115
+ dot_env.merge(base_env).merge(compose_env)
116
+ end
117
+
118
+ def prepare_dot env
119
+ Env.with_env(env) do
120
+ Dotenv.load_without_export(*env_files)
121
+ end
122
+ end
123
+
124
+ def prepare_compose env
125
+ compose_files = if env['COMPOSE_FILE']
126
+ env['COMPOSE_FILE']
127
+ elsif File.exists?(File.join(env_root, "docker-compose.yml"))
128
+ File.join(env_root, "docker-compose.yml")
129
+ elsif File.exists?(File.join(env_root, "docker-compose.yaml"))
130
+ File.join(env_root, "docker-compose.yaml")
131
+ end
132
+
133
+ if compose_files
134
+ result_file = File.join(env_root, "compose-result.yml")
135
+ Env.with_env(env.merge('COMPOSE_FILE' => compose_files)) do
136
+ result_content = `merger.rb`
137
+ File.write(result_file, result_content)
138
+ end
139
+ {
140
+ 'COMPOSE_FILE' => result_file
141
+ }
142
+ else
143
+ {}
144
+ end
145
+ end
146
+
147
+ def check_path_variable path
148
+ if ENV['PATH'][path]
149
+ ENV['PATH']
150
+ else
151
+ "#{ENV['PATH']}:#{path}"
152
+ end
153
+ end
154
+
155
+ class Pathfinder
156
+ attr_accessor :path
157
+
158
+ def initialize path
159
+ @path = File.realpath(File.expand_path(path))
160
+ end
161
+
162
+ def each_parent
163
+ current = path.split(File::SEPARATOR)
164
+ Enumerator.new do |y|
165
+ while !current.empty? do
166
+ y << current.join(File::SEPARATOR)
167
+ current.pop
168
+ end
169
+ end
170
+ end
171
+
172
+ def each_env
173
+ Dir.chdir(File.join(path, 'envs')) do
174
+ Dir.glob('**/*').select do |f|
175
+ File.directory? f
176
+ end.select do |f|
177
+ File.exists?(File.join(f, '.env')) || File.exists?(File.join(f, 'docker-compose.yml')) || File.exists?(File.join(f, 'docker-compose.yaml'))
178
+ end.sort
179
+ end
180
+ end
181
+ end
182
+
183
+ class Project
184
+ attr_accessor :env_root
185
+
186
+ def initialize path
187
+ raise "env path #{path} is not directory!" if !File.directory?(File.expand_path(path))
188
+ @env_root = File.realpath(File.expand_path(path))
189
+ end
190
+
191
+ def project_root
192
+ @project_root = Pathfinder.new(env_root).each_parent.find do |path|
193
+ root?(path)
194
+ end || (raise "Can't find project root")
195
+ end
196
+
197
+ def core_root
198
+ @core_root = Pathfinder.new(project_root).each_parent.find do |path|
199
+ core?(path)
200
+ end
201
+ end
202
+
203
+ def root? path
204
+ return File.realpath(File.expand_path(path)) if File.directory?("#{path}/.git") ||
205
+ File.exists?("#{path}/base-service.yml") ||
206
+ File.exists?("#{path}/common-services.yml") ||
207
+ File.directory?("#{path}/envs")
208
+ end
209
+
210
+ def core? path
211
+ return File.realpath(File.expand_path(path)) if File.exists?("#{path}/.core")
212
+ end
213
+
214
+ end
215
+
216
+
217
+ end
218
+
219
+ end
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'English'
4
+
5
+ module Aggkit
6
+
7
+ module Runner
8
+
9
+ def init_service(service)
10
+ STDOUT.sync = true
11
+ STDERR.sync = true
12
+
13
+ puts "Starting #{service}..."
14
+
15
+ trap('EXIT') do
16
+ puts "Stopping #{service}..."
17
+ end
18
+ end
19
+
20
+ def error(message)
21
+ STDERR.puts "Error: #{message}"
22
+ end
23
+
24
+ def die(message)
25
+ error(message)
26
+ exit 1
27
+ end
28
+
29
+ def load_envs(string, env = ENV)
30
+ envs = Dotenv::Parser.new(string).call
31
+ envs.each_pair do |k, v|
32
+ env[k] = v
33
+ end
34
+ envs
35
+ end
36
+
37
+ def load_envs_from_consul(consul, service)
38
+ envs = execute!("consul.rb --consul=http://#{consul}:8500 --env services/env/#{service} --pristine -d", "Can't load envs")
39
+ load_envs(envs)
40
+ end
41
+
42
+ def execute(cmd)
43
+ puts "Executing: #{cmd}"
44
+ output = `#{cmd}`
45
+ @last_result = $?
46
+ output
47
+ end
48
+
49
+ def execute!(cmd, error = nil)
50
+ output = execute(cmd)
51
+ ($? || @last_result).success? || die(error || "Can't execute: #{cmd}")
52
+ output
53
+ end
54
+
55
+ def ensure_env_defined!(key, env = ENV)
56
+ env.key?(key) || die("Environment variable #{key} must present!")
57
+ env[key]
58
+ end
59
+
60
+ def envsubst(*paths)
61
+ paths = paths.flatten.map{|c| c.to_s.strip }.reject(&:empty?)
62
+ paths.each do |path|
63
+ Dir.glob("#{path}/**/*.in") do |templ|
64
+ output = templ.sub(/\.in$/, '')
65
+ cmd = "cat '#{templ}' | envsubst > '#{output}'"
66
+ system(cmd) || die("envsubst failed: #{cmd}")
67
+ end
68
+ end
69
+ end
70
+
71
+ def envsubst_file(templ, output = nil)
72
+ output ||= templ.sub(/\.in$/, '')
73
+ die('filename must ends with .in or output must be provided') if output.strip == templ.strip
74
+ cmd = "cat '#{templ}' | envsubst > '#{output}'"
75
+ system(cmd) || die("envsubst failed: #{cmd}")
76
+ end
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,5 @@
1
+ module Aggkit
2
+
3
+ VERSION = '0.2.5'.freeze
4
+
5
+ end