aggkit 0.2.5

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 (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