summaryrefslogtreecommitdiff
path: root/lib/license/management/tool_box.rb
blob: 6906cb54c652787a4e39f1722b2d23f025a45bcf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# 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?
            ::License::Management.logger.error("Installing #{deb} ...")
            shell.execute([:dpkg, '-i', deb], capture: false)
          else
            ::License::Management.logger.error("Installing #{version} via asdf ...")
            shell.execute([:asdf, "plugin-update", tool.to_s], env: env)
            shell.execute(['/opt/asdf/plugins/nodejs/bin/import-release-team-keyring']) 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)
          shell.execute([:asdf, :reshim], env: env)
        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}"])
          shell.execute([:asdf, :reshim])
        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(?<version>.+)\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)
            shell.execute([:keytool, '-list', '-v', '-storepass changeit', '-keystore', keystore_path], env: env)
          end
        end
      end
    end
  end
end