summaryrefslogtreecommitdiff
path: root/lib/license/finder/ext/bundler.rb
blob: d362be352281725a12d4d1a70bf549dbcc41b640 (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
# frozen_string_literal: true

module LicenseFinder
  class Bundler < PackageManager
    def prepare
      vendor_path = Pathname.pwd.join('.gitlab', 'cache', 'vendor')
      shell.execute([:mkdir, '-p', vendor_path.to_s])

      with_clean_bundler do
        _stdout, _stderr, status = shell.execute([:asdf, :current, :ruby], env: default_env)
        shell.execute([:asdf, :install], env: default_env) unless status.success?
        shell.execute([:bundle, :config, '--local', :path, vendor_path.to_s], env: default_env)
        shell.execute([:bundle, :install, '--verbose'], env: default_env)
      end
    end

    def current_packages
      with_clean_bundler do
        stdout, _stderr, status = shell.execute(scan_command, env: default_env)
        return super unless status.success?

        stdout.each_line.map do |line|
          map_from(JSON.parse(line, symbolize_names: true))
        end
      end
    end

    def possible_package_paths
      if ENV['BUNDLE_GEMFILE'] && File.exist?(ENV['BUNDLE_GEMFILE'])
        [project_path.join(File.basename(ENV['BUNDLE_GEMFILE']))]
      else
        [project_path.join('Gemfile'), project_path.join('gems.rb')]
      end
    end

    private

    def gemfile
      if ENV['BUNDLE_GEMFILE']
        custom_gemfile = project_path.join(File.basename(ENV['BUNDLE_GEMFILE']))
        return custom_gemfile.basename.to_s if custom_gemfile.exist?
      end

      project_path.join("gems.rb").exist? ? "gems.rb" : "Gemfile"
    end

    def lockfile
      gemfile == 'gems.rb' ? 'gems.locked' : "#{gemfile}.lock"
    end

    def lockfile_path
      project_path.join(lockfile)
    end

    def scan_command
      [
        '/opt/asdf/shims/ruby',
        '-W0',
        ::License::Management.root.join('exe', 'scan_bundler').to_s,
        detected_package_path.to_s,
        lockfile_path.to_s
      ]
    end

    def default_env
      @default_env ||= {
        'BUNDLE_ALLOW_OFFLINE_INSTALL' => 'true',
        'BUNDLE_DISABLE_VERSION_CHECK' => 'true',
        'BUNDLE_ERROR_ON_STDERR' => 'true',
        'BUNDLE_GEMFILE' => "#{project_path}/#{gemfile}",
        'BUNDLE_IGNORE_MESSAGES' => 'true',
        'BUNDLE_JOBS' => ENV.fetch('BUNDLE_JOBS', `nproc`.chomp),
        'BUNDLE_SILENCE_ROOT_WARNING' => 'true',
        'BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES' => 'true',
        'BUNDLE_WITHOUT' => ENV.fetch('BUNDLE_WITHOUT', ignored_groups.to_a.join(':')),
        'PATH' => "/opt/asdf/shims:/opt/asdf/bin:#{ENV['PATH']}"
      }.tap do |env|
        env['BUNDLE_FROZEN'] = 'true' if lockfile_path.exist?
        env['BUNDLE_SSL_CA_CERT'] = shell.custom_certificate_path.to_s if shell.custom_certificate_installed?
      end
    end

    def with_clean_bundler
      ::Gem.clear_paths
      ::Bundler.reset!
      ::Bundler.configure
      Dir.chdir(project_path) do
        if ::Bundler.respond_to?(:with_unbundled_env)
          ::Bundler.with_unbundled_env { yield }
        else
          ::Bundler.with_clean_env { yield }
        end
      end
    end

    def map_from(gem)
      Dependency.new(
        'Bundler',
        gem[:name],
        gem[:version],
        description: gem[:description],
        detection_path: lockfile_path,
        homepage: gem[:homepage],
        install_path: gem[:full_gem_path] || '/dev/null',
        spec_licenses: gem[:licenses],
        summary: gem[:summary]
      )
    end
  end
end