# frozen_string_literal: true module License module Management class ToolBox C_BASED_TOOLS = [:php, :python, :ruby].freeze attr_reader :project_path, :shell def initialize(shell, project_path) @shell = shell @project_path = project_path end def install(tool:, version: version_of(tool), env: {}) Dir.chdir(project_path) do deb = deb_for(tool, version) if deb&.exist? shell.execute([:dpkg, '-i', deb], capture: false) else shell.execute([:asdf, "plugin-update", tool.to_s], env: env, capture: false) shell.execute(['/opt/asdf/plugins/nodejs/bin/import-release-team-keyring'], capture: false) if tool == :nodejs end install_common_libraries(env: env) if C_BASED_TOOLS.include?(tool.to_sym) shell.execute([:asdf, :install, tool.to_s, version], env: env, capture: false) shell.execute([:asdf, :local, tool.to_s, version], env: env, capture: false) shell.execute([:asdf, :reshim], env: env, capture: false) end install_certificates_into_java_keystore(env, version) if tool == :java end def install_common_libraries(env: {}) shell.execute(['apt-get', 'install', '-y', '-f', '--no-install-recommends', '/opt/toolcache/common/*.deb'], env: env) end def version_of(tool, env: ENV) Dir.chdir(project_path) do case tool when :java java_version(env: env) when :python python_version(env: env) else asdf_detected_version_of(tool) end end end def default_version_for(tool) default_versions[tool.to_sym] end def uninstall(tool:, version:) Dir.chdir(project_path) do return unless deb_for(tool, version)&.exist? shell.execute([:dpkg, '-r', "#{tool}-#{version}"], capture: false) shell.execute([:asdf, :reshim], capture: false) end end def closest_match_to(tool:, version:) deb = deb_for(tool, version) deb.basename.to_s.gsub("#{tool}-", "").split('_', 2)[0] if deb&.exist? end private def deb_for(tool, version) Pathname.glob("/opt/toolcache/#{tool}-#{version}*.deb")[0] end def version_error_for(tool) /\Aversion\s(?.+)\sis not installed for #{tool}\z/ end def default_versions @default_versions ||= IO.read('/opt/gitlab/.tool-versions').each_line.each_with_object({}) do |line, memo| name, version = line.chomp.split(' ', 2) memo[name.to_sym] = version end end def asdf_detected_version_of(tool) stdout, stderr, status = shell.execute([:asdf, :current, tool.to_s]) if status.success? version, _ = stdout.split(' ', 2) version else match = stderr.chomp.match(version_error_for(tool)) match ? match[:version] : default_version_for(tool) end end def python_version(env:) case env['LM_PYTHON_VERSION'] when '3' default_version_for(:python) when '2' closest_match_to(tool: :python, version: "2.") else major, minor, _rest = (env['ASDF_PYTHON_VERSION'] || asdf_detected_version_of(:python)).split('.') closest_match_to(tool: :python, version: "#{major}.#{minor}") end end def java_version(env:) lm_version = env['LM_JAVA_VERSION'] return lm_version if lm_version && %w[8 11].include?(lm_version) asdf_version = env['ASDF_JAVA_VERSION'] return asdf_version.gsub('adopt-openjdk', 'adoptopenjdk') if asdf_version asdf_detected_version_of(:java) end def install_certificates_into_java_keystore(env, version) java_home = Pathname.new(env['JAVA_HOME']) keystore_path = java_home.join("8" == version ? "jre/lib/security/cacerts" : "lib/security/cacerts") Dir.chdir shell.custom_certificate_path.dirname do Dir.glob('custom.*.crt').each do |path| shell.execute([:keytool, '-importcert', '-alias', Time.now.to_i, '-file', File.expand_path(path), '-trustcacerts', '-noprompt', '-storepass', 'changeit', '-keystore', keystore_path], env: env, capture: false) shell.execute([:keytool, '-list', '-v', '-storepass changeit', '-keystore', keystore_path], env: env, capture: false) end end end end end end