lib/uffizzi/services/compose_file_service.rb in uffizzi-cli-1.0.3 vs lib/uffizzi/services/compose_file_service.rb in uffizzi-cli-1.0.4
- old
+ new
@@ -1,42 +1,98 @@
# frozen_string_literal: true
require 'psych'
require 'pathname'
require 'base64'
+require 'minitar'
+require 'zlib'
+require 'uffizzi/services/project_service'
+require 'uffizzi/services/volume_parser_service'
class ComposeFileService
+ MAX_HOST_VOLUME_GZIP_FILE_SIZE = 1024 * 900
+ DEPENDENCY_CONFIG_USE_KIND = :config_map
+ DEPENDENCY_VOLUME_USE_KIND = :volume
+
class << self
- def parse(compose_content, compose_file_path)
+ def parse(compose_content, compose_file_dir)
compose_data = parse_compose_content_to_object(compose_content)
- env_files = prepare_services_env_files(compose_data['services']).flatten.uniq
- config_files = fetch_configs(compose_data['configs'])
- prepare_dependencies(env_files, config_files, compose_file_path)
+ services = compose_data['services']
+ env_files_paths = prepare_env_files_paths(services).flatten.uniq
+ config_files_paths = prepare_config_files_paths(compose_data['configs'])
+ host_volumes_paths = prepare_host_volumes_paths(services)
+ prepare_dependencies(compose_file_dir, env_files_paths, config_files_paths, host_volumes_paths)
end
private
- def prepare_dependencies(env_files, config_files, compose_file_path)
- prepare_dependency_files_data(env_files + config_files, compose_file_path)
+ def prepare_dependencies(compose_file_dir, env_files_paths, config_files_paths, host_volumes_paths)
+ config_files_attrs = prepare_dependency_configs_files(env_files_paths + config_files_paths, compose_file_dir)
+ host_volumes_attrs = prepare_dependency_host_volumes_files(host_volumes_paths, compose_file_dir)
+
+ config_files_attrs + host_volumes_attrs
end
- def prepare_dependency_files_data(dependency_files, compose_file_path)
- dependency_files.map do |dependency_file|
- dependency_file_data = Psych.load(File.read("#{compose_file_path}/#{dependency_file}"))
+ def prepare_dependency_configs_files(dependency_file_paths, compose_file_dir)
+ dependency_file_paths.map do |dependency_file_path|
+ dependency_file_content = Psych.load(File.read("#{compose_file_dir}/#{dependency_file_path}"))
+
{
- path: dependency_file,
- source: dependency_file,
- content: Base64.encode64(dependency_file_data),
+ path: dependency_file_path,
+ source: dependency_file_path,
+ content: Base64.encode64(dependency_file_content),
+ use_kind: DEPENDENCY_CONFIG_USE_KIND,
}
end
rescue Errno::ENOENT => e
dependency_path = e.message.split('- ').last
raise Uffizzi::Error.new("The config file #{dependency_path} does not exist")
end
- def fetch_configs(configs_data)
+ def prepare_dependency_host_volumes_files(dependency_file_paths, compose_file_dir)
+ base_dependency_paths = dependency_file_paths.map do |dependency_file_path|
+ dependency_pathname = Pathname.new(dependency_file_path)
+ next dependency_file_path if dependency_pathname.absolute?
+ next "#{compose_file_dir}/#{dependency_pathname.cleanpath}" if dependency_file_path.start_with?('./')
+ next "#{compose_file_dir}/#{dependency_pathname}" if dependency_file_path.start_with?('../')
+
+ raise Uffizzi::Error.new("Unsupported path #{dependency_pathname}")
+ end
+
+ base_dependency_paths.zip(dependency_file_paths).map do |base_dependency_path, dependency_file_path|
+ absolute_dependency_path = Pathname.new(base_dependency_path).realpath.to_s
+ dependency_file_content = prepare_host_volume_file_content(absolute_dependency_path)
+
+ {
+ path: absolute_dependency_path,
+ source: dependency_file_path,
+ content: dependency_file_content,
+ use_kind: DEPENDENCY_VOLUME_USE_KIND,
+ is_file: Pathname.new(absolute_dependency_path).file?,
+ }
+ end
+ rescue Errno::ENOENT => e
+ dependency_path = e.message.split('- ').last
+ raise Uffizzi::Error.new("No such file or directory: #{dependency_path}")
+ end
+
+ def prepare_host_volume_file_content(path)
+ tmp_tar_name = Base64.encode64(path)[0..20]
+ tmp_tar_path = "/tmp/#{tmp_tar_name}.tar.gz"
+
+ Minitar.pack(path, Zlib::GzipWriter.new(File.open(tmp_tar_path, 'wb')))
+ gzipped_file_size = Pathname.new(tmp_tar_path).size
+
+ if gzipped_file_size > MAX_HOST_VOLUME_GZIP_FILE_SIZE
+ Uffizzi.ui.say("File/Directory too big by path: #{path}. Gzipped tar archive size is #{gzipped_file_size}")
+ end
+
+ Base64.encode64(File.binread(tmp_tar_path))
+ end
+
+ def prepare_config_files_paths(configs_data)
return [] if configs_data.nil?
Uffizzi.ui.say("Unsupported type of #{:configs} option") unless configs_data.is_a?(Hash)
configs = []
@@ -66,40 +122,42 @@
else
Uffizzi.ui.say("Unsupported type of #{:env_file} option")
end
end
- def prepare_services_env_files(services)
+ def prepare_env_files_paths(services)
return [] if services.nil?
- services.keys.map do |service|
- service_env_files = prepare_service_env_files(services.fetch(service))
-
- service_env_files
- end
+ services
+ .values
+ .select { |s| s.has_key?('env_file') }
+ .map { |s| parse_env_file(s['env_file']) }
+ .flatten
+ .compact
+ .uniq
end
- def prepare_service_env_files(service_data)
- env_files_data = []
- service_data.each_pair do |key, value|
- key_sym = key.to_sym
- if key_sym == :env_file
- env_files_data << parse_env_file(value)
- end
- end
-
- env_files_data
- end
-
def parse_compose_content_to_object(compose_content)
begin
compose_data = Psych.safe_load(compose_content, aliases: true)
rescue Psych::SyntaxError
Uffizzi.ui.say('Invalid compose file')
end
Uffizzi.ui.say('Unsupported compose file') if compose_data.nil?
compose_data
+ end
+
+ def prepare_host_volumes_paths(services)
+ return [] if services.nil?
+
+ services
+ .values
+ .select { |s| s.has_key?('volumes') }
+ .map { |s| VolumeParserService.parse(s['volumes']) }
+ .flatten
+ .compact
+ .uniq
end
end
end