aggkit 0.3.1.8768 → 0.3.4
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 +5 -5
- data/.rubocop.yml +27 -4
- data/Gemfile +3 -0
- data/Gemfile.lock +12 -6
- data/aggkit.gemspec +3 -2
- data/bin/agg +52 -33
- data/bin/aggci +31 -26
- data/bin/aggconsul +16 -15
- data/bin/agggen +31 -34
- data/bin/agglock +5 -4
- data/bin/aggmerge +33 -28
- data/bin/aggstart +19 -22
- data/bin/aggterm +3 -2
- data/bin/aggwait +5 -3
- data/bin/aggwrap +250 -0
- data/lib/aggkit/ci.rb +62 -67
- data/lib/aggkit/env.rb +119 -103
- data/lib/aggkit/option_parser.rb +10 -7
- data/lib/aggkit/runner.rb +2 -3
- data/lib/aggkit/version.rb +2 -1
- data/lib/aggkit/watcher.rb +5 -4
- data/lib/aggkit.rb +1 -0
- metadata +5 -3
data/lib/aggkit/ci.rb
CHANGED
@@ -9,75 +9,76 @@ module Aggkit
|
|
9
9
|
|
10
10
|
module Ci
|
11
11
|
|
12
|
-
def log_action
|
12
|
+
def log_action(action)
|
13
13
|
puts " => #{action}"
|
14
14
|
end
|
15
15
|
|
16
|
-
def info
|
16
|
+
def info(message)
|
17
17
|
puts " => #{message}"
|
18
18
|
end
|
19
19
|
|
20
|
-
def execute
|
20
|
+
def execute(cmd)
|
21
21
|
puts " - executing: #{cmd}"
|
22
22
|
result = `#{cmd}`
|
23
23
|
puts result
|
24
|
-
|
25
|
-
|
26
|
-
end
|
24
|
+
raise "Execution failed cmd: #{cmd.inspect}" unless $?.success?
|
25
|
+
|
27
26
|
result
|
28
27
|
end
|
29
28
|
|
30
|
-
|
29
|
+
# Уровни образов
|
31
30
|
# 1. Без модификатора - не протестирован, отсутсвует в репозитории.
|
32
31
|
# 2. С модификатором dev - протестирован автотестами, ДОЛЖЕН быть в репозитории.
|
33
32
|
# 3. С модификатором stage - протестирован руками, ДОЛЖЕН быть в репозитории(как и его предшественник dev).
|
34
33
|
# 4. С модификатором release - помечен для релиза, ДОЛЖЕН быть в репозитории(как и его предшественник dev и stage).
|
35
34
|
|
36
|
-
|
35
|
+
# Работа должна вестить ТОЛЬКО с workimage
|
37
36
|
|
38
37
|
# Базовое имя образа
|
39
38
|
# Например docker.rnds.pro/aggredator-mq
|
40
|
-
def baseimage
|
39
|
+
def baseimage(service)
|
41
40
|
raise "Service name invalid: #{service.inspect}" if service.to_s.length < 2
|
41
|
+
|
42
42
|
"docker.rnds.pro/aggredator-#{service}"
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
45
|
# Текущее имя образа без модификаторов продвижения, но с тегом
|
47
46
|
# Например docker.rnds.pro/aggredator-mq:7e6420b5
|
48
|
-
def workimage
|
47
|
+
def workimage(service, tag)
|
49
48
|
raise "Service tag invalid: #{tag.inspect}" if tag.to_s.length < 2
|
49
|
+
|
50
50
|
"#{baseimage(service)}:#{tag}"
|
51
51
|
end
|
52
52
|
|
53
53
|
# Образ с модификатором версии
|
54
54
|
# Например docker.rnds.pro/aggredator-mq-dev:7e6420b5
|
55
|
-
def promotedimage
|
55
|
+
def promotedimage(service, stage, tag)
|
56
56
|
raise "Service stage invalid: #{stage.inspect}" if stage.to_s.length < 2
|
57
57
|
raise "Service tag invalid: #{tag.inspect}" if tag.to_s.length < 2
|
58
|
+
|
58
59
|
"#{baseimage(service)}-#{stage}:#{tag}"
|
59
60
|
end
|
60
61
|
|
61
62
|
# Образ с модификатором протестированной автотестами версии
|
62
63
|
# Например docker.rnds.pro/aggredator-mq-dev:7e6420b5
|
63
|
-
def devimage
|
64
|
+
def devimage(service, tag)
|
64
65
|
promotedimage(service, 'dev', tag)
|
65
66
|
end
|
66
67
|
|
67
68
|
# Образ с модификатором стабильной версии
|
68
69
|
# Например docker.rnds.pro/aggredator-mq-stage:7e6420b5
|
69
|
-
def stageimage
|
70
|
+
def stageimage(service, tag)
|
70
71
|
promotedimage(service, 'stage', tag)
|
71
72
|
end
|
72
73
|
|
73
74
|
# Образ с модификатором релизной версии
|
74
|
-
|
75
|
-
def releaseimage
|
75
|
+
# Например docker.rnds.pro/aggredator-mq-release:7e6420b5
|
76
|
+
def releaseimage(service, tag)
|
76
77
|
promotedimage(service, 'release', tag)
|
77
78
|
end
|
78
79
|
|
79
|
-
# Протегировать образ тегом
|
80
|
-
def tagimage!
|
80
|
+
# Протегировать образ тегом
|
81
|
+
def tagimage!(image, newimage, push: false, ignoreerror: false)
|
81
82
|
log_action "Tag #{image.inspect} as #{newimage.inspect}"
|
82
83
|
|
83
84
|
if ignoreerror
|
@@ -86,28 +87,26 @@ module Aggkit
|
|
86
87
|
execute("docker tag #{image} #{newimage}")
|
87
88
|
end
|
88
89
|
|
89
|
-
if push
|
90
|
-
execute("docker push #{newimage}")
|
91
|
-
end
|
90
|
+
execute("docker push #{newimage}") if push
|
92
91
|
|
93
|
-
|
92
|
+
newimage
|
94
93
|
end
|
95
94
|
|
96
|
-
|
97
|
-
def rmimage!
|
95
|
+
# Удалить образ образ тегом
|
96
|
+
def rmimage!(image)
|
98
97
|
log_action "Remove #{image.inspect}"
|
99
98
|
execute("docker rmi #{image} &> /dev/null || true")
|
100
99
|
end
|
101
100
|
|
102
|
-
def label!
|
101
|
+
def label!(image, label, value)
|
103
102
|
raise "Image label invalid: #{label.inspect}" if label.to_s.length < 2
|
104
103
|
raise "Image label value invalid: #{value.inspect}" if value.to_s.length < 2
|
105
104
|
|
106
|
-
execute("echo #{image} | docker build -t #{image} --label=\"#{label
|
105
|
+
execute("echo #{image} | docker build -t #{image} --label=\"#{label}=#{value}\" - ")
|
107
106
|
end
|
108
107
|
|
109
108
|
# Растегировать все модификатора образа сервиса и возможно удалить его
|
110
|
-
def untagservice
|
109
|
+
def untagservice(service, tag)
|
111
110
|
if tag != 'latest'
|
112
111
|
rmimage! workimage(service, tag)
|
113
112
|
rmimage! devimage(service, tag)
|
@@ -117,7 +116,7 @@ module Aggkit
|
|
117
116
|
end
|
118
117
|
|
119
118
|
# Продвинуть текущий образ сервиса по уровню - добавить модификатор и залить в репозиторий
|
120
|
-
def promote!
|
119
|
+
def promote!(service, tag, stage, fromstage: nil)
|
121
120
|
fromimage = if fromstage
|
122
121
|
promotedimage(service, fromstage, tag)
|
123
122
|
else
|
@@ -127,52 +126,50 @@ module Aggkit
|
|
127
126
|
toimage = promotedimage(service, stage, tag)
|
128
127
|
|
129
128
|
log_action "Promote #{fromimage} to #{toimage}"
|
130
|
-
|
129
|
+
tagimage! fromimage, toimage, push: true
|
131
130
|
end
|
132
131
|
|
133
132
|
# Продвинуть текущий образ по уровню - добавить модификатор dev(протестировано) и залить в репозиторий
|
134
|
-
def promote_to_dev!
|
133
|
+
def promote_to_dev!(service, tag)
|
135
134
|
promote!(service, tag, 'dev')
|
136
135
|
end
|
137
136
|
|
138
137
|
# Продвинуть текущий образ по уровню - добавить модификатор stage(стабильно) и залить в репозиторий
|
139
|
-
def promote_to_stage!
|
138
|
+
def promote_to_stage!(service, tag)
|
140
139
|
promoted = tagimage!(devimage(service, tag), stageimage(service, tag), push: true)
|
141
140
|
# Тегируем этот образ как latest
|
142
|
-
|
141
|
+
tagimage!(promoted, stageimage(service, 'latest'), push: true)
|
143
142
|
end
|
144
143
|
|
145
144
|
# Продвинуть стабильный образ до указанного тега
|
146
|
-
def promote_to_tag!
|
147
|
-
|
145
|
+
def promote_to_tag!(service, tag, newtag)
|
146
|
+
tagimage!(devimage(service, tag), stageimage(service, newtag), push: true)
|
148
147
|
end
|
149
148
|
|
150
149
|
# Продвинуть список образов или упасть с ошибкой
|
151
|
-
def promote_services_to_dev!
|
150
|
+
def promote_services_to_dev!(services, tag)
|
152
151
|
[services].flatten.each do |service|
|
153
152
|
promote_to_dev!(service, tag)
|
154
153
|
end
|
155
154
|
end
|
156
155
|
|
157
156
|
# Продвинуть список образов или упасть с ошибкой
|
158
|
-
def promote_services_to_stage!
|
157
|
+
def promote_services_to_stage!(services, tag)
|
159
158
|
[services].flatten.each do |service|
|
160
159
|
promote_to_stage!(service, tag)
|
161
160
|
end
|
162
161
|
end
|
163
162
|
|
164
|
-
|
165
|
-
def promote_services_to_tag!
|
163
|
+
# Протегировать образы до указанного тега
|
164
|
+
def promote_services_to_tag!(services, tag, newtag)
|
166
165
|
[services].flatten.each do |service|
|
167
166
|
promote_to_tag!(service, tag, newtag)
|
168
167
|
end
|
169
168
|
end
|
170
169
|
|
171
|
-
|
172
|
-
|
173
170
|
# Попытаться взять все модификаторы образов из репозитория
|
174
171
|
# Скачивает образы и тегирует их как workimage
|
175
|
-
def pull_images_cache
|
172
|
+
def pull_images_cache(services, tag)
|
176
173
|
log_action "Puling images#{[services].flatten.inspect} from cache...."
|
177
174
|
[services].flatten.each do |service|
|
178
175
|
execute("docker pull #{workimage(service, tag)} 2> /dev/null || true")
|
@@ -186,15 +183,15 @@ module Aggkit
|
|
186
183
|
end
|
187
184
|
|
188
185
|
# Залить образы в репозиторий
|
189
|
-
def push_images_cache
|
186
|
+
def push_images_cache(services, tag)
|
190
187
|
log_action "Pushing images#{[services].flatten.inspect} to cache...."
|
191
188
|
[services].flatten.each do |service|
|
192
189
|
tagimage! workimage(service, tag), workimage(service, tag), push: true
|
193
190
|
end
|
194
191
|
end
|
195
192
|
|
196
|
-
|
197
|
-
def clean_services
|
193
|
+
# Растегировать все образы для дальнейшего удаления. Помечает как latest для поддержки кеширования docker
|
194
|
+
def clean_services(services, tag)
|
198
195
|
[services].flatten.each do |service|
|
199
196
|
tagimage! workimage(service, tag), workimage(service, 'latest'), ignoreerror: true
|
200
197
|
tagimage! devimage(service, tag), workimage(service, 'latest'), ignoreerror: true
|
@@ -204,17 +201,17 @@ module Aggkit
|
|
204
201
|
end
|
205
202
|
end
|
206
203
|
|
207
|
-
def ssh_deploy
|
208
|
-
with_remote_docker services, env, sshserver, tag, stage do |config,
|
204
|
+
def ssh_deploy(services, env, sshserver, tag, stage)
|
205
|
+
with_remote_docker services, env, sshserver, tag, stage do |config, _environment|
|
209
206
|
config_file = config['config_file'].to_s
|
210
207
|
|
211
208
|
execute('docker-compose ps')
|
212
209
|
execute('docker-compose pull')
|
213
210
|
|
214
|
-
consul = execute('docker ps | grep consul').split(' ').first.strip
|
211
|
+
consul = execute('docker-compose ps | grep consul').split(' ').first.strip
|
215
212
|
puts "CONSULT ID: #{consul}"
|
216
213
|
|
217
|
-
|
214
|
+
unless config_file.empty?
|
218
215
|
execute("docker exec -i #{consul} aggwait -t 20 --consul")
|
219
216
|
execute("docker exec -i #{consul} aggconsul --init --override --config - < #{config_file}")
|
220
217
|
end
|
@@ -223,38 +220,38 @@ module Aggkit
|
|
223
220
|
end
|
224
221
|
end
|
225
222
|
|
226
|
-
def ssh_core_deploy
|
227
|
-
with_remote_docker services, env, sshserver, tag, stage do |config,
|
223
|
+
def ssh_core_deploy(services, env, sshserver, tag, stage)
|
224
|
+
with_remote_docker services, env, sshserver, tag, stage do |config, _environment|
|
228
225
|
config_file = config['config_file'].to_s
|
229
226
|
|
230
227
|
execute('docker-compose ps')
|
231
228
|
execute('docker-compose pull')
|
232
229
|
execute('docker-compose up -t 30 -d consul')
|
233
230
|
|
234
|
-
consul = execute('docker ps | grep consul').split(' ').first.strip
|
231
|
+
consul = execute('docker-compose ps | grep consul').split(' ').first.strip
|
235
232
|
puts "CONSULT ID: #{consul}"
|
236
233
|
|
237
|
-
|
234
|
+
unless config_file.empty?
|
238
235
|
execute("docker exec -i #{consul} aggwait -t 20 --consul")
|
239
236
|
execute("docker exec -i #{consul} aggconsul --init --override --config - < #{config_file}")
|
240
237
|
end
|
241
238
|
|
242
|
-
#echo " * Consul ready"
|
243
|
-
#echo " * Updatting database..."
|
239
|
+
# echo " * Consul ready"
|
240
|
+
# echo " * Updatting database..."
|
244
241
|
execute('docker-compose up -t 30 -d db')
|
245
242
|
sleep 5
|
246
|
-
#echo " * Db ready"
|
247
|
-
#echo " * Bootstrapping admin..."
|
243
|
+
# echo " * Db ready"
|
244
|
+
# echo " * Bootstrapping admin..."
|
248
245
|
execute('docker-compose run --rm -T admin /home/app/docker/bootstrap.rb')
|
249
246
|
sleep 5
|
250
|
-
#echo " * Bootstrapping complete"
|
251
|
-
#echo " * Updating all containers..."
|
247
|
+
# echo " * Bootstrapping complete"
|
248
|
+
# echo " * Updating all containers..."
|
252
249
|
execute('docker-compose up -t 30 -d')
|
253
|
-
#echo " * Containers ready"
|
250
|
+
# echo " * Containers ready"
|
254
251
|
end
|
255
252
|
end
|
256
253
|
|
257
|
-
def with_remote_docker
|
254
|
+
def with_remote_docker(services, env, sshserver, tag, stage)
|
258
255
|
services = [services].flatten
|
259
256
|
log_action "Deploy [#{services.inspect}] tag:#{tag.inspect} stage:#{stage.inspect} to #{sshserver.inspect}"
|
260
257
|
with_ssh sshserver do |sockname|
|
@@ -265,14 +262,12 @@ module Aggkit
|
|
265
262
|
envs['CORE_TAG'] = tag
|
266
263
|
envs['CORE_SUFFIX'] = "-#{stage}"
|
267
264
|
|
268
|
-
localid = execute(
|
265
|
+
localid = execute('docker info | grep ID').strip
|
269
266
|
|
270
267
|
Aggkit::Env.with_env(envs) do |environment|
|
271
|
-
remoteid = execute(
|
268
|
+
remoteid = execute('docker info | grep ID').strip
|
272
269
|
|
273
|
-
if localid == remoteid
|
274
|
-
raise "Can't get access to remote Docker"
|
275
|
-
end
|
270
|
+
raise "Can't get access to remote Docker" if localid == remoteid
|
276
271
|
|
277
272
|
yield(env_config, environment)
|
278
273
|
|
@@ -282,12 +277,11 @@ module Aggkit
|
|
282
277
|
tagimage! deployed, current
|
283
278
|
untagservice(service, tag)
|
284
279
|
end
|
285
|
-
|
286
280
|
end
|
287
281
|
end
|
288
282
|
end
|
289
283
|
|
290
|
-
def with_ssh
|
284
|
+
def with_ssh(server, user: 'root')
|
291
285
|
file = Tempfile.new
|
292
286
|
@ssh_sockname = file.path
|
293
287
|
file.unlink
|
@@ -304,3 +298,4 @@ module Aggkit
|
|
304
298
|
end
|
305
299
|
|
306
300
|
end
|
301
|
+
|
data/lib/aggkit/env.rb
CHANGED
@@ -4,6 +4,7 @@ require 'English'
|
|
4
4
|
require 'dotenv'
|
5
5
|
|
6
6
|
module Dotenv
|
7
|
+
|
7
8
|
module_function
|
8
9
|
|
9
10
|
def load_without_export(*filenames)
|
@@ -13,19 +14,21 @@ module Dotenv
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
17
|
+
|
16
18
|
end
|
17
19
|
|
18
20
|
module Aggkit
|
19
21
|
|
20
22
|
class Env
|
23
|
+
|
21
24
|
attr_accessor :project, :name, :env_root, :environment
|
22
25
|
|
23
|
-
def self.list
|
26
|
+
def self.list(path = Dir.pwd)
|
24
27
|
root = Project.new(path).project_root
|
25
28
|
Pathfinder.new(root).each_env
|
26
29
|
end
|
27
30
|
|
28
|
-
def self.with_env
|
31
|
+
def self.with_env(env)
|
29
32
|
current_env = ENV.to_h
|
30
33
|
env.each_pair do |k, v|
|
31
34
|
ENV[k.to_s] = v.to_s
|
@@ -41,7 +44,7 @@ module Aggkit
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
44
|
-
def initialize
|
47
|
+
def initialize(path)
|
45
48
|
@project = if File.directory?(File.expand_path(path))
|
46
49
|
@name = File.basename(File.realpath(File.expand_path(path)))
|
47
50
|
Project.new(path)
|
@@ -50,19 +53,19 @@ module Aggkit
|
|
50
53
|
Project.new(Dir.pwd)
|
51
54
|
end
|
52
55
|
|
53
|
-
|
56
|
+
unless self.class.list.include?(@name)
|
54
57
|
raise "There no env #{@name.inspect} in project: #{project.project_root.inspect}"
|
55
58
|
end
|
56
59
|
|
57
60
|
@env_root = File.join(project_root, 'envs', @name)
|
58
61
|
end
|
59
62
|
|
60
|
-
def prepare
|
63
|
+
def prepare(release: false)
|
61
64
|
@environment = prepare_environment(release: release)
|
62
65
|
end
|
63
66
|
|
64
|
-
def with_env
|
65
|
-
Env.with_env(environment) &block
|
67
|
+
def with_env(&block)
|
68
|
+
Env.with_env(environment) & block
|
66
69
|
end
|
67
70
|
|
68
71
|
def project_root
|
@@ -82,148 +85,161 @@ module Aggkit
|
|
82
85
|
end
|
83
86
|
|
84
87
|
def core_dot_file
|
85
|
-
|
88
|
+
begin
|
89
|
+
File.join(core_root, '.env')
|
90
|
+
rescue StandardError
|
91
|
+
nil
|
92
|
+
end
|
86
93
|
end
|
87
94
|
|
88
95
|
def env_files
|
89
|
-
[core_dot_file, project_dot_file, dot_file].compact.select{|f| File.
|
96
|
+
[core_dot_file, project_dot_file, dot_file].compact.select{|f| File.exist?(f) }.uniq
|
90
97
|
end
|
91
98
|
|
92
99
|
def config_file
|
93
|
-
[File.join(env_root, 'config.yml'), File.join(env_root, 'config.yaml')].compact.select{|f| File.
|
100
|
+
[File.join(env_root, 'config.yml'), File.join(env_root, 'config.yaml')].compact.select{|f| File.exist?(f) }.uniq.first
|
94
101
|
end
|
95
102
|
|
96
103
|
def show
|
97
104
|
{
|
98
|
-
name:
|
105
|
+
name: name,
|
99
106
|
project_root: project_root,
|
100
|
-
core_root:
|
101
|
-
envfiles:
|
102
|
-
config_file:
|
103
|
-
envs:
|
107
|
+
core_root: core_root,
|
108
|
+
envfiles: env_files,
|
109
|
+
config_file: config_file,
|
110
|
+
envs: environment
|
104
111
|
}
|
105
112
|
end
|
106
113
|
|
107
|
-
private
|
108
|
-
|
114
|
+
private
|
109
115
|
|
110
|
-
def prepare_environment release: false
|
111
|
-
base_env = {
|
112
|
-
'ENV_ROOT' => env_root,
|
113
|
-
'PROJECT_ROOT' => project_root,
|
114
|
-
'CORE_ROOT' => core_root,
|
115
|
-
'PATH' => check_path_variable(env_root),
|
116
|
-
}
|
117
116
|
|
118
|
-
|
117
|
+
def prepare_environment(release: false)
|
118
|
+
base_env = {
|
119
|
+
'ENV_ROOT' => env_root,
|
120
|
+
'PROJECT_ROOT' => project_root,
|
121
|
+
'CORE_ROOT' => core_root,
|
122
|
+
'PATH' => check_path_variable(env_root)
|
123
|
+
}
|
119
124
|
|
120
|
-
|
125
|
+
dot_env = prepare_dot(base_env)
|
121
126
|
|
122
|
-
|
123
|
-
end
|
127
|
+
compose_env = prepare_compose(dot_env.merge(base_env), release: release)
|
124
128
|
|
125
|
-
|
126
|
-
Env.with_env(env) do
|
127
|
-
Dotenv.load_without_export(*env_files)
|
129
|
+
dot_env.merge(base_env).merge(compose_env)
|
128
130
|
end
|
129
|
-
end
|
130
131
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
File.join(env_root, "docker-compose.yml")
|
136
|
-
elsif File.exists?(File.join(env_root, "docker-compose.yaml"))
|
137
|
-
File.join(env_root, "docker-compose.yaml")
|
132
|
+
def prepare_dot(env)
|
133
|
+
Env.with_env(env) do
|
134
|
+
Dotenv.load_without_export(*env_files)
|
135
|
+
end
|
138
136
|
end
|
139
137
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
138
|
+
def prepare_compose(env, release: false)
|
139
|
+
compose_files = if env['COMPOSE_FILE']
|
140
|
+
env['COMPOSE_FILE']
|
141
|
+
elsif File.exist?(File.join(env_root, 'docker-compose.yml'))
|
142
|
+
File.join(env_root, 'docker-compose.yml')
|
143
|
+
elsif File.exist?(File.join(env_root, 'docker-compose.yaml'))
|
144
|
+
File.join(env_root, 'docker-compose.yaml')
|
145
|
+
end
|
146
|
+
|
147
|
+
if compose_files
|
148
|
+
result_file = File.join(env_root, 'compose-result.yml')
|
149
|
+
Env.with_env(env.merge('COMPOSE_FILE' => compose_files)) do
|
150
|
+
if release
|
151
|
+
`aggmerge #{result_file} --skip-build`
|
152
|
+
else
|
153
|
+
`aggmerge #{result_file}`
|
154
|
+
end
|
147
155
|
end
|
156
|
+
{
|
157
|
+
'COMPOSE_FILE' => result_file
|
158
|
+
}
|
159
|
+
else
|
160
|
+
{}
|
148
161
|
end
|
149
|
-
{
|
150
|
-
'COMPOSE_FILE' => result_file
|
151
|
-
}
|
152
|
-
else
|
153
|
-
{}
|
154
162
|
end
|
155
|
-
end
|
156
163
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
164
|
+
def check_path_variable(path)
|
165
|
+
if ENV['PATH'][path]
|
166
|
+
ENV['PATH']
|
167
|
+
else
|
168
|
+
"#{ENV['PATH']}:#{path}"
|
169
|
+
end
|
162
170
|
end
|
163
|
-
end
|
164
171
|
|
165
|
-
|
166
|
-
attr_accessor :path
|
172
|
+
class Pathfinder
|
167
173
|
|
168
|
-
def initialize path
|
169
|
-
@path = File.realpath(File.expand_path(path))
|
170
|
-
end
|
171
174
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
175
|
+
attr_accessor :path
|
176
|
+
|
177
|
+
def initialize(path)
|
178
|
+
@path = File.realpath(File.expand_path(path))
|
179
|
+
end
|
180
|
+
|
181
|
+
def each_parent
|
182
|
+
current = path.split(File::SEPARATOR)
|
183
|
+
Enumerator.new do |y|
|
184
|
+
until current.empty?
|
185
|
+
y << current.join(File::SEPARATOR)
|
186
|
+
current.pop
|
187
|
+
end
|
178
188
|
end
|
179
189
|
end
|
180
|
-
end
|
181
190
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
191
|
+
def each_env
|
192
|
+
Dir.chdir(File.join(path, 'envs')) do
|
193
|
+
Dir.glob('**/*').select do |f|
|
194
|
+
File.directory? f
|
195
|
+
end.select do |f|
|
196
|
+
File.exist?(File.join(f, '.env')) || File.exist?(File.join(f, 'docker-compose.yml')) || File.exist?(File.join(f, 'docker-compose.yaml'))
|
197
|
+
end.sort
|
198
|
+
end
|
189
199
|
end
|
190
|
-
end
|
191
|
-
end
|
192
200
|
|
193
|
-
class Project
|
194
|
-
attr_accessor :env_root
|
195
201
|
|
196
|
-
def initialize path
|
197
|
-
raise "env path #{path} is not directory!" if !File.directory?(File.expand_path(path))
|
198
|
-
@env_root = File.realpath(File.expand_path(path))
|
199
202
|
end
|
200
203
|
|
201
|
-
|
202
|
-
|
203
|
-
root?(path)
|
204
|
-
end || (raise "Can't find project root")
|
205
|
-
end
|
204
|
+
class Project
|
205
|
+
|
206
206
|
|
207
|
-
|
208
|
-
|
209
|
-
|
207
|
+
attr_accessor :env_root
|
208
|
+
|
209
|
+
def initialize(path)
|
210
|
+
raise "env path #{path} is not directory!" unless File.directory?(File.expand_path(path))
|
211
|
+
|
212
|
+
@env_root = File.realpath(File.expand_path(path))
|
210
213
|
end
|
211
|
-
end
|
212
214
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
end
|
215
|
+
def project_root
|
216
|
+
@project_root = Pathfinder.new(env_root).each_parent.find do |path|
|
217
|
+
root?(path)
|
218
|
+
end || (raise "Can't find project root")
|
219
|
+
end
|
219
220
|
|
220
|
-
|
221
|
-
|
222
|
-
|
221
|
+
def core_root
|
222
|
+
@core_root = Pathfinder.new(project_root).each_parent.find do |path|
|
223
|
+
core?(path)
|
224
|
+
end
|
225
|
+
end
|
223
226
|
|
224
|
-
|
227
|
+
def root?(path)
|
228
|
+
return File.realpath(File.expand_path(path)) if File.directory?("#{path}/.git") ||
|
229
|
+
File.exist?("#{path}/base-service.yml") ||
|
230
|
+
File.exist?("#{path}/common-services.yml") ||
|
231
|
+
File.directory?("#{path}/envs")
|
232
|
+
end
|
233
|
+
|
234
|
+
def core?(path)
|
235
|
+
return File.realpath(File.expand_path(path)) if File.exist?("#{path}/.core")
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
end
|
225
240
|
|
226
241
|
|
227
242
|
end
|
228
243
|
|
229
244
|
end
|
245
|
+
|