kuber_kit 0.5.1 → 0.5.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +5 -5
- data/TODO.md +5 -5
- data/example/configurations/review.rb +1 -1
- data/example/services/docker_app.rb +2 -1
- data/example/services/env_file.rb +1 -1
- data/example/services/ruby_app.rb +2 -1
- data/lib/kuber_kit.rb +10 -0
- data/lib/kuber_kit/actions/kubectl_get.rb +32 -0
- data/lib/kuber_kit/actions/service_checker.rb +5 -0
- data/lib/kuber_kit/actions/service_deployer.rb +85 -61
- data/lib/kuber_kit/cli.rb +14 -3
- data/lib/kuber_kit/configs.rb +10 -6
- data/lib/kuber_kit/container.rb +20 -0
- data/lib/kuber_kit/core/artifacts/artifact_store.rb +3 -0
- data/lib/kuber_kit/core/configuration.rb +4 -2
- data/lib/kuber_kit/core/configuration_definition.rb +7 -0
- data/lib/kuber_kit/core/configuration_factory.rb +1 -0
- data/lib/kuber_kit/core/dependencies/abstract_dependency_resolver.rb +75 -0
- data/lib/kuber_kit/core/env_files/abstract_env_file.rb +4 -0
- data/lib/kuber_kit/core/env_files/artifact_file.rb +4 -0
- data/lib/kuber_kit/core/env_files/env_file_store.rb +3 -0
- data/lib/kuber_kit/core/env_files/env_group.rb +12 -0
- data/lib/kuber_kit/core/image.rb +2 -1
- data/lib/kuber_kit/core/registries/registry_store.rb +3 -0
- data/lib/kuber_kit/core/service.rb +4 -2
- data/lib/kuber_kit/core/service_definition.rb +13 -6
- data/lib/kuber_kit/core/service_factory.rb +1 -0
- data/lib/kuber_kit/core/templates/template_store.rb +3 -0
- data/lib/kuber_kit/env_file_reader/env_file_parser.rb +51 -0
- data/lib/kuber_kit/env_file_reader/env_file_tempfile_creator.rb +17 -0
- data/lib/kuber_kit/env_file_reader/reader.rb +2 -0
- data/lib/kuber_kit/env_file_reader/strategies/artifact_file.rb +9 -65
- data/lib/kuber_kit/env_file_reader/strategies/env_group.rb +21 -0
- data/lib/kuber_kit/image_compiler/image_dependency_resolver.rb +5 -53
- data/lib/kuber_kit/service_deployer/service_dependency_resolver.rb +14 -0
- data/lib/kuber_kit/service_deployer/service_list_resolver.rb +11 -6
- data/lib/kuber_kit/service_deployer/strategies/docker.rb +31 -12
- data/lib/kuber_kit/service_deployer/strategies/kubernetes.rb +9 -2
- data/lib/kuber_kit/shell/commands/kubectl_commands.rb +8 -0
- data/lib/kuber_kit/shell/local_shell.rb +15 -1
- data/lib/kuber_kit/template_reader/strategies/artifact_file.rb +3 -3
- data/lib/kuber_kit/tools/logger_factory.rb +14 -0
- data/lib/kuber_kit/version.rb +1 -1
- metadata +10 -2
data/lib/kuber_kit/configs.rb
CHANGED
@@ -4,8 +4,8 @@ class KuberKit::Configs
|
|
4
4
|
AVAILABLE_CONFIGS = [
|
5
5
|
:image_dockerfile_name, :image_build_context_dir, :image_tag, :docker_ignore_list, :image_compile_dir,
|
6
6
|
:kuber_kit_dirname, :kuber_kit_min_version, :images_dirname, :services_dirname, :infra_dirname, :configurations_dirname,
|
7
|
-
:artifact_clone_dir, :service_config_dir, :deployer_strategy, :compile_simultaneous_limit,
|
8
|
-
:additional_images_paths, :deprecation_warnings_disabled, :log_file_path
|
7
|
+
:artifact_clone_dir, :service_config_dir, :deployer_strategy, :compile_simultaneous_limit, :deploy_simultaneous_limit,
|
8
|
+
:additional_images_paths, :deprecation_warnings_disabled, :log_file_path, :env_file_compile_dir
|
9
9
|
]
|
10
10
|
DOCKER_IGNORE_LIST = [
|
11
11
|
'Dockerfile',
|
@@ -34,10 +34,12 @@ class KuberKit::Configs
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def add_default_configs
|
37
|
+
home_kuber_kit_path = File.expand_path(File.join("~", ".kuber_kit"))
|
38
|
+
|
37
39
|
set :image_dockerfile_name, "Dockerfile"
|
38
40
|
set :image_build_context_dir, "build_context"
|
39
41
|
set :image_tag, 'latest'
|
40
|
-
set :image_compile_dir, "
|
42
|
+
set :image_compile_dir, File.join(home_kuber_kit_path, "image_builds")
|
41
43
|
set :docker_ignore_list, DOCKER_IGNORE_LIST
|
42
44
|
set :kuber_kit_dirname, "kuber_kit"
|
43
45
|
set :kuber_kit_min_version, KuberKit::VERSION
|
@@ -45,13 +47,15 @@ class KuberKit::Configs
|
|
45
47
|
set :services_dirname, "services"
|
46
48
|
set :infra_dirname, "infrastructure"
|
47
49
|
set :configurations_dirname, "configurations"
|
48
|
-
set :artifact_clone_dir, "
|
49
|
-
set :service_config_dir, "
|
50
|
+
set :artifact_clone_dir, File.join(home_kuber_kit_path, "artifacts")
|
51
|
+
set :service_config_dir, File.join(home_kuber_kit_path, "services")
|
50
52
|
set :deployer_strategy, :kubernetes
|
51
53
|
set :compile_simultaneous_limit, 5
|
54
|
+
set :deploy_simultaneous_limit, 5
|
52
55
|
set :additional_images_paths, []
|
53
56
|
set :deprecation_warnings_disabled, false
|
54
|
-
set :log_file_path, "
|
57
|
+
set :log_file_path, File.join(home_kuber_kit_path, "deploy.log")
|
58
|
+
set :env_file_compile_dir, File.join(home_kuber_kit_path, "env_files")
|
55
59
|
end
|
56
60
|
|
57
61
|
def items
|
data/lib/kuber_kit/container.rb
CHANGED
@@ -45,6 +45,10 @@ class KuberKit::Container
|
|
45
45
|
KuberKit::Actions::KubectlDescribe.new
|
46
46
|
end
|
47
47
|
|
48
|
+
register "actions.kubectl_get" do
|
49
|
+
KuberKit::Actions::KubectlGet.new
|
50
|
+
end
|
51
|
+
|
48
52
|
register "actions.kubectl_logs" do
|
49
53
|
KuberKit::Actions::KubectlLogs.new
|
50
54
|
end
|
@@ -225,10 +229,22 @@ class KuberKit::Container
|
|
225
229
|
KuberKit::EnvFileReader::Reader.new
|
226
230
|
end
|
227
231
|
|
232
|
+
register "env_file_reader.env_file_parser" do
|
233
|
+
KuberKit::EnvFileReader::EnvFileParser.new
|
234
|
+
end
|
235
|
+
|
236
|
+
register "env_file_reader.env_file_tempfile_creator" do
|
237
|
+
KuberKit::EnvFileReader::EnvFileTempfileCreator.new
|
238
|
+
end
|
239
|
+
|
228
240
|
register "env_file_reader.strategies.artifact_file" do
|
229
241
|
KuberKit::EnvFileReader::Strategies::ArtifactFile.new
|
230
242
|
end
|
231
243
|
|
244
|
+
register "env_file_reader.strategies.env_group" do
|
245
|
+
KuberKit::EnvFileReader::Strategies::EnvGroup.new
|
246
|
+
end
|
247
|
+
|
232
248
|
register "template_reader.action_handler" do
|
233
249
|
KuberKit::TemplateReader::ActionHandler.new
|
234
250
|
end
|
@@ -257,6 +273,10 @@ class KuberKit::Container
|
|
257
273
|
KuberKit::ServiceDeployer::ServiceListResolver.new
|
258
274
|
end
|
259
275
|
|
276
|
+
register "service_deployer.service_dependency_resolver" do
|
277
|
+
KuberKit::ServiceDeployer::ServiceDependencyResolver.new
|
278
|
+
end
|
279
|
+
|
260
280
|
register "service_deployer.strategies.kubernetes" do
|
261
281
|
KuberKit::ServiceDeployer::Strategies::Kubernetes.new
|
262
282
|
end
|
@@ -3,6 +3,7 @@ class KuberKit::Core::Artifacts::ArtifactStore
|
|
3
3
|
store.add(artifact.name, artifact)
|
4
4
|
end
|
5
5
|
|
6
|
+
Contract Symbol => Maybe[KuberKit::Core::Artifacts::AbstractArtifact]
|
6
7
|
def get(artifact_name)
|
7
8
|
artifact = get_from_configuration(artifact_name) ||
|
8
9
|
get_global(artifact_name)
|
@@ -10,10 +11,12 @@ class KuberKit::Core::Artifacts::ArtifactStore
|
|
10
11
|
artifact
|
11
12
|
end
|
12
13
|
|
14
|
+
Contract Symbol => Maybe[KuberKit::Core::Artifacts::AbstractArtifact]
|
13
15
|
def get_global(artifact_name)
|
14
16
|
store.get(artifact_name)
|
15
17
|
end
|
16
18
|
|
19
|
+
Contract Symbol => Maybe[KuberKit::Core::Artifacts::AbstractArtifact]
|
17
20
|
def get_from_configuration(artifact_name)
|
18
21
|
artifacts = KuberKit.current_configuration.artifacts
|
19
22
|
artifacts[artifact_name]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class KuberKit::Core::Configuration
|
2
2
|
attr_reader :name, :artifacts, :registries, :env_files, :templates, :kubeconfig_path,
|
3
|
-
:services_attributes, :enabled_services, :build_servers, :global_build_vars,
|
3
|
+
:services_attributes, :enabled_services, :disabled_services, :build_servers, :global_build_vars,
|
4
4
|
:deployer_strategy, :deployer_namespace, :deployer_require_confirimation
|
5
5
|
|
6
6
|
Contract KeywordArgs[
|
@@ -12,6 +12,7 @@ class KuberKit::Core::Configuration
|
|
12
12
|
kubeconfig_path: Maybe[String],
|
13
13
|
services_attributes: HashOf[Symbol => Hash],
|
14
14
|
enabled_services: ArrayOf[Symbol],
|
15
|
+
disabled_services: ArrayOf[Symbol],
|
15
16
|
build_servers: ArrayOf[KuberKit::Core::BuildServers::AbstractBuildServer],
|
16
17
|
global_build_vars: HashOf[Symbol => Any],
|
17
18
|
deployer_strategy: Symbol,
|
@@ -19,7 +20,7 @@ class KuberKit::Core::Configuration
|
|
19
20
|
deployer_require_confirimation: Bool,
|
20
21
|
] => Any
|
21
22
|
def initialize(name:, artifacts:, registries:, env_files:, templates:, kubeconfig_path:,
|
22
|
-
services_attributes:, enabled_services:, build_servers:, global_build_vars:,
|
23
|
+
services_attributes:, enabled_services:, disabled_services:, build_servers:, global_build_vars:,
|
23
24
|
deployer_strategy:, deployer_namespace:, deployer_require_confirimation:)
|
24
25
|
@name = name
|
25
26
|
@artifacts = artifacts
|
@@ -30,6 +31,7 @@ class KuberKit::Core::Configuration
|
|
30
31
|
@build_servers = build_servers
|
31
32
|
@services_attributes = services_attributes
|
32
33
|
@enabled_services = enabled_services
|
34
|
+
@disabled_services = disabled_services
|
33
35
|
@global_build_vars = global_build_vars
|
34
36
|
@deployer_strategy = deployer_strategy
|
35
37
|
@deployer_namespace = deployer_namespace
|
@@ -12,6 +12,7 @@ class KuberKit::Core::ConfigurationDefinition
|
|
12
12
|
@templates = {}
|
13
13
|
@build_servers = []
|
14
14
|
@enabled_services = []
|
15
|
+
@disabled_services = []
|
15
16
|
@services_attributes = {}
|
16
17
|
end
|
17
18
|
|
@@ -24,6 +25,7 @@ class KuberKit::Core::ConfigurationDefinition
|
|
24
25
|
templates: @templates,
|
25
26
|
kubeconfig_path: @kubeconfig_path,
|
26
27
|
enabled_services: @enabled_services,
|
28
|
+
disabled_services: @disabled_services,
|
27
29
|
build_servers: @build_servers,
|
28
30
|
services_attributes: @services_attributes,
|
29
31
|
global_build_vars: @global_build_vars,
|
@@ -116,6 +118,11 @@ class KuberKit::Core::ConfigurationDefinition
|
|
116
118
|
raise KuberKit::Error, "#enabled_services method accepts only Array or Hash"
|
117
119
|
end
|
118
120
|
|
121
|
+
def disabled_services(services)
|
122
|
+
@disabled_services += services.map(&:to_sym)
|
123
|
+
return self
|
124
|
+
end
|
125
|
+
|
119
126
|
def service_attributes(services)
|
120
127
|
@services_attributes = @services_attributes.merge(services)
|
121
128
|
self
|
@@ -29,6 +29,7 @@ class KuberKit::Core::ConfigurationFactory
|
|
29
29
|
build_servers: build_servers,
|
30
30
|
services_attributes: configuration_attrs.services_attributes,
|
31
31
|
enabled_services: configuration_attrs.enabled_services,
|
32
|
+
disabled_services: configuration_attrs.disabled_services,
|
32
33
|
global_build_vars: configuration_attrs.global_build_vars || {},
|
33
34
|
deployer_strategy: configuration_attrs.deployer_strategy || configs.deployer_strategy,
|
34
35
|
deployer_namespace: configuration_attrs.deployer_namespace,
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class KuberKit::Core::Dependencies::AbstractDependencyResolver
|
2
|
+
CircularDependencyError = Class.new(KuberKit::Error)
|
3
|
+
DependencyNotFoundError = Class.new(KuberKit::NotFoundError)
|
4
|
+
|
5
|
+
# Iterate over list of dependencies for items (including the items themself).
|
6
|
+
# Iteration will send the list to the callback block function
|
7
|
+
Contract Or[Symbol, ArrayOf[Symbol]], Proc => Any
|
8
|
+
def each_with_deps(item_names, &block)
|
9
|
+
resolved_dependencies = []
|
10
|
+
# Get first list of dependencies ready to resolve
|
11
|
+
next_dependencies = get_next(item_names, limit: dependency_batch_size)
|
12
|
+
|
13
|
+
# Call the block for each list of dependencies ready to resolve, then calculate the next list
|
14
|
+
while (next_dependencies - resolved_dependencies).any?
|
15
|
+
block.call(next_dependencies)
|
16
|
+
resolved_dependencies += next_dependencies
|
17
|
+
next_dependencies = get_next(item_names, resolved: resolved_dependencies, limit: dependency_batch_size)
|
18
|
+
end
|
19
|
+
|
20
|
+
(item_names - resolved_dependencies).each_slice(dependency_batch_size) do |group|
|
21
|
+
block.call(group)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns next list of dependencies ready to resolve.
|
26
|
+
# Item is not ready to resolve if it has personal dependency.
|
27
|
+
# E.g. if "A" depends on "B" and "C", "C" depends on "D", then only "B" and "D" will be returned.
|
28
|
+
Contract Or[Symbol, ArrayOf[Symbol]], KeywordArgs[
|
29
|
+
resolved: Optional[ArrayOf[Symbol]],
|
30
|
+
limit: Optional[Maybe[Num]]
|
31
|
+
] => Any
|
32
|
+
def get_next(item_names, resolved: [], limit: nil)
|
33
|
+
deps = Array(item_names).map { |i| get_recursive_deps(i) }.flatten.uniq
|
34
|
+
|
35
|
+
# Find out which dependencies are ready to resolve,
|
36
|
+
# they should not have unresolved personal dependencies
|
37
|
+
ready_to_resolve = deps.select do |dep_name|
|
38
|
+
unresolved_deps = get_deps(dep_name) - resolved
|
39
|
+
unresolved_deps.empty?
|
40
|
+
end
|
41
|
+
unresolved_deps = ready_to_resolve - resolved
|
42
|
+
unresolved_deps = unresolved_deps.take(limit) if limit
|
43
|
+
unresolved_deps
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get all dependencies for items (including the items themself), without any limitations
|
47
|
+
Contract Or[Symbol, ArrayOf[Symbol]] => Any
|
48
|
+
def get_all(item_names)
|
49
|
+
deps = Array(item_names).map { |i| get_recursive_deps(i) }.flatten
|
50
|
+
(deps + item_names).uniq
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_recursive_deps(item_name, dependency_tree: [])
|
54
|
+
deps = get_deps(item_name)
|
55
|
+
|
56
|
+
if dependency_tree.include?(item_name)
|
57
|
+
raise CircularDependencyError, "Circular dependency found for #{item_name}. Dependency tree: #{dependency_tree.inspect}"
|
58
|
+
end
|
59
|
+
|
60
|
+
child_deps = []
|
61
|
+
deps.each do |i|
|
62
|
+
child_deps += get_recursive_deps(i, dependency_tree: dependency_tree + [item_name])
|
63
|
+
end
|
64
|
+
|
65
|
+
(deps + child_deps).uniq
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_deps(item_name)
|
69
|
+
raise "This method should be overriden"
|
70
|
+
end
|
71
|
+
|
72
|
+
def dependency_batch_size
|
73
|
+
raise "This method should be overriden"
|
74
|
+
end
|
75
|
+
end
|
@@ -3,6 +3,7 @@ class KuberKit::Core::EnvFiles::EnvFileStore
|
|
3
3
|
store.add(env_file.name, env_file)
|
4
4
|
end
|
5
5
|
|
6
|
+
Contract Symbol => Maybe[KuberKit::Core::EnvFiles::AbstractEnvFile]
|
6
7
|
def get(env_file_name)
|
7
8
|
env_file = get_from_configuration(env_file_name) ||
|
8
9
|
get_global(env_file_name)
|
@@ -10,10 +11,12 @@ class KuberKit::Core::EnvFiles::EnvFileStore
|
|
10
11
|
env_file
|
11
12
|
end
|
12
13
|
|
14
|
+
Contract Symbol => Maybe[KuberKit::Core::EnvFiles::AbstractEnvFile]
|
13
15
|
def get_global(env_file_name)
|
14
16
|
store.get(env_file_name)
|
15
17
|
end
|
16
18
|
|
19
|
+
Contract Symbol => Maybe[KuberKit::Core::EnvFiles::AbstractEnvFile]
|
17
20
|
def get_from_configuration(env_file_name)
|
18
21
|
env_files = KuberKit.current_configuration.env_files
|
19
22
|
env_files[env_file_name]
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class KuberKit::Core::EnvFiles::EnvGroup < KuberKit::Core::EnvFiles::AbstractEnvFile
|
2
|
+
attr_reader :env_files
|
3
|
+
|
4
|
+
def initialize(env_group_name, env_files:)
|
5
|
+
super(env_group_name)
|
6
|
+
@env_files = env_files
|
7
|
+
end
|
8
|
+
|
9
|
+
def uniq_name
|
10
|
+
"env-group-#{@name.to_s}"
|
11
|
+
end
|
12
|
+
end
|
data/lib/kuber_kit/core/image.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
class KuberKit::Core::Image
|
2
|
-
attr_reader :name, :dependencies, :registry, :dockerfile_path, :build_vars, :build_context_dir, :tag,
|
2
|
+
attr_reader :name, :dependencies, :registry, :dockerfile_path, :build_vars, :build_context_dir, :tag,
|
3
|
+
:before_build_callback, :after_build_callback
|
3
4
|
|
4
5
|
Contract KeywordArgs[
|
5
6
|
name: Symbol,
|
@@ -3,6 +3,7 @@ class KuberKit::Core::Registries::RegistryStore
|
|
3
3
|
store.add(registry.name, registry)
|
4
4
|
end
|
5
5
|
|
6
|
+
Contract Symbol => Maybe[KuberKit::Core::Registries::AbstractRegistry]
|
6
7
|
def get(registry_name)
|
7
8
|
registry = get_from_configuration(registry_name) ||
|
8
9
|
get_global(registry_name)
|
@@ -10,10 +11,12 @@ class KuberKit::Core::Registries::RegistryStore
|
|
10
11
|
registry
|
11
12
|
end
|
12
13
|
|
14
|
+
Contract Symbol => Maybe[KuberKit::Core::Registries::AbstractRegistry]
|
13
15
|
def get_global(registry_name)
|
14
16
|
store.get(registry_name)
|
15
17
|
end
|
16
18
|
|
19
|
+
Contract Symbol => Maybe[KuberKit::Core::Registries::AbstractRegistry]
|
17
20
|
def get_from_configuration(registry_name)
|
18
21
|
registries = KuberKit.current_configuration.registries
|
19
22
|
registries[registry_name]
|
@@ -1,18 +1,20 @@
|
|
1
1
|
class KuberKit::Core::Service
|
2
2
|
AttributeNotSet = Class.new(Indocker::Error)
|
3
3
|
|
4
|
-
attr_reader :name, :template_name, :tags, :images, :attributes, :deployer_strategy
|
4
|
+
attr_reader :name, :dependencies, :template_name, :tags, :images, :attributes, :deployer_strategy
|
5
5
|
|
6
6
|
Contract KeywordArgs[
|
7
7
|
name: Symbol,
|
8
|
+
dependencies: ArrayOf[Symbol],
|
8
9
|
template_name: Maybe[Symbol],
|
9
10
|
tags: ArrayOf[Symbol],
|
10
11
|
images: ArrayOf[Symbol],
|
11
12
|
attributes: HashOf[Symbol => Any],
|
12
13
|
deployer_strategy: Maybe[Symbol]
|
13
14
|
] => Any
|
14
|
-
def initialize(name:, template_name:, tags:, images:, attributes:, deployer_strategy:)
|
15
|
+
def initialize(name:, dependencies:, template_name:, tags:, images:, attributes:, deployer_strategy:)
|
15
16
|
@name = name
|
17
|
+
@dependencies = dependencies
|
16
18
|
@template_name = template_name
|
17
19
|
@tags = tags
|
18
20
|
@images = images
|
@@ -1,22 +1,29 @@
|
|
1
1
|
class KuberKit::Core::ServiceDefinition
|
2
|
-
attr_reader :service_name, :template_name
|
2
|
+
attr_reader :service_name, :template_name, :dependencies
|
3
3
|
|
4
4
|
Contract Or[Symbol, String] => Any
|
5
5
|
def initialize(service_name)
|
6
6
|
@service_name = service_name.to_sym
|
7
|
+
@dependencies = []
|
7
8
|
end
|
8
9
|
|
9
10
|
def to_service_attrs
|
10
11
|
OpenStruct.new(
|
11
|
-
name:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
name: @service_name,
|
13
|
+
dependencies: @dependencies,
|
14
|
+
template_name: get_value(@template_name),
|
15
|
+
tags: Array(get_value(@tags)).map(&:to_sym),
|
16
|
+
images: Array(get_value(@images)).map(&:to_sym),
|
17
|
+
attributes: get_value(@attributes),
|
16
18
|
deployer_strategy: get_value(@deployer_strategy),
|
17
19
|
)
|
18
20
|
end
|
19
21
|
|
22
|
+
def depends_on(*value, &block)
|
23
|
+
@dependencies = Array(value).flatten
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
20
27
|
def template(value = nil, &block)
|
21
28
|
@template_name = block_given? ? block : value
|
22
29
|
|
@@ -3,6 +3,7 @@ class KuberKit::Core::Templates::TemplateStore
|
|
3
3
|
store.add(template.name, template)
|
4
4
|
end
|
5
5
|
|
6
|
+
Contract Symbol => Maybe[KuberKit::Core::Templates::AbstractTemplate]
|
6
7
|
def get(template_name)
|
7
8
|
template = get_from_configuration(template_name) ||
|
8
9
|
get_global(template_name)
|
@@ -10,10 +11,12 @@ class KuberKit::Core::Templates::TemplateStore
|
|
10
11
|
template
|
11
12
|
end
|
12
13
|
|
14
|
+
Contract Symbol => Maybe[KuberKit::Core::Templates::AbstractTemplate]
|
13
15
|
def get_global(template_name)
|
14
16
|
store.get(template_name)
|
15
17
|
end
|
16
18
|
|
19
|
+
Contract Symbol => Maybe[KuberKit::Core::Templates::AbstractTemplate]
|
17
20
|
def get_from_configuration(template_name)
|
18
21
|
templates = KuberKit.current_configuration.templates
|
19
22
|
templates[template_name]
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class KuberKit::EnvFileReader::EnvFileParser
|
2
|
+
# Parser is based on:
|
3
|
+
# https://github.com/bkeepers/dotenv/blob/master/lib/dotenv/parser.rb
|
4
|
+
LINE = /
|
5
|
+
(?:^|\A) # beginning of line
|
6
|
+
\s* # leading whitespace
|
7
|
+
(?:export\s+)? # optional export
|
8
|
+
([\w\.]+) # key
|
9
|
+
(?:\s*=\s*?|:\s+?) # separator
|
10
|
+
( # optional value begin
|
11
|
+
\s*'(?:\\'|[^'])*' # single quoted value
|
12
|
+
| # or
|
13
|
+
\s*"(?:\\"|[^"])*" # double quoted value
|
14
|
+
| # or
|
15
|
+
[^\#\r\n]+ # unquoted value
|
16
|
+
)? # value end
|
17
|
+
\s* # trailing whitespace
|
18
|
+
(?:\#.*)? # optional comment
|
19
|
+
(?:$|\z) # end of line
|
20
|
+
/x
|
21
|
+
|
22
|
+
Contract String => Hash
|
23
|
+
def call(string)
|
24
|
+
hash = {}
|
25
|
+
string.gsub(/\r\n?/, "\n").scan(LINE).each do |key, value|
|
26
|
+
hash[key] = parse_value(value || "")
|
27
|
+
end
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def parse_value(value)
|
34
|
+
# Remove surrounding quotes
|
35
|
+
value = value.strip.sub(/\A(['"])(.*)\1\z/m, '\2')
|
36
|
+
|
37
|
+
if Regexp.last_match(1) == '"'
|
38
|
+
value = unescape_characters(expand_newlines(value))
|
39
|
+
end
|
40
|
+
|
41
|
+
value
|
42
|
+
end
|
43
|
+
|
44
|
+
def unescape_characters(value)
|
45
|
+
value.gsub(/\\([^$])/, '\1')
|
46
|
+
end
|
47
|
+
|
48
|
+
def expand_newlines(value)
|
49
|
+
value.gsub('\n', "\n").gsub('\r', "\r")
|
50
|
+
end
|
51
|
+
end
|