123456789_123456789_123456789_123456789_123456789_

Class: RubyInstaller::Build::Msys2Installation

Do not use. This class is for internal use only.
Relationships & Source Files
Namespace Children
Exceptions:
Inherits: Object
Defined in: lib/ruby_installer/build/msys2_installation.rb

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Instance Attribute Details

#mingw_package_prefix (readonly)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 17

attr_reader :mingw_package_prefix

#mingwarch (readonly)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 16

attr_reader :mingwarch

#mingwdir (readonly)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 15

attr_reader :mingwdir

#ruby_bin_dir (readonly)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 18

attr_reader :ruby_bin_dir

Instance Method Details

#backslachs(path) (private)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 141

private def backslachs(path)
  path.gsub("/", "\\")
end

#disable_dll_search_paths

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 136

def disable_dll_search_paths
  @mingwdir.remove if @mingwdir
  @mingwdir = nil
end

#disable_msys_apps(if_no_msys: :hint)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 238

def disable_msys_apps(if_no_msys: :hint)
  vars = with_msys_install_hint(if_no_msys) do
    msys_apps_envvars
  end
  changed = false
  if path=vars.delete("PATH")
    old_path = ENV['PATH']
    ENV['PATH'] = old_path.gsub(path + ";", "")
    changed = ENV['PATH'] != old_path
  end
  vars.each do |key, val|
    changed = true if ENV[key]
    ENV.delete(key)
  end

  changed
end

#disable_msys_apps_per_cmd

This method is used for the ridk command.

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 286

def disable_msys_apps_per_cmd
  vars = with_msys_install_hint{ msys_apps_envvars }
  str = "".dup
  if path=vars.delete("PATH")
    str << "PATH=#{ ENV['PATH'].gsub(path + ";", "") }\n"
  end
  str << vars.map do |key, val|
    "#{key}="
  end.join("\n")
end

#disable_msys_apps_per_ps1

This method is used for the ridk command.

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 309

def disable_msys_apps_per_ps1
  vars = with_msys_install_hint{ msys_apps_envvars }
  str = "".dup
  if path=vars.delete("PATH")
    str << "$env:PATH=\"#{ ENV['PATH'].gsub(path + ";", "").gsub('"', '`"') }\";"
  end
  str << vars.map do |key, val|
    "$env:#{key}=''"
  end.join(";")
end

#enable_dll_search_paths

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 126

def enable_dll_search_paths
  @mingwdir ||= begin
    DllDirectory.set_defaults
    path = mingw_bin_path
    DllDirectory.new(path) if File.directory?(path)
  rescue MsysNotFound
    # We silently ignore this error to allow Ruby installations without MSYS2.
  end
end

#enable_msys_apps(if_no_msys: :hint, for_gem_install: false)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 213

def enable_msys_apps(if_no_msys: :hint, for_gem_install: false)
  vars = with_msys_install_hint(if_no_msys) do
    msys_apps_envvars
  end

  changed = false

  if (path=vars.delete("PATH")) && !ENV['PATH'].include?(path)
    phrase = "Temporarily enhancing PATH for MSYS/MINGW..."
    if for_gem_install && defined?(Gem)
      Gem.ui.say(phrase) if Gem.configuration.verbose
    elsif $DEBUG
      $stderr.puts phrase
    end
    changed = true
    ENV['PATH'] = path + ";" + ENV['PATH']
  end
  vars.each do |key, val|
    changed = true if ENV[key] != val
    ENV[key] = val
  end

  changed
end

#enable_msys_apps_per_cmd

This method is used for the ridk command.

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 275

def enable_msys_apps_per_cmd
  vars = with_msys_install_hint{ msys_apps_envvars }
  if (path=vars.delete("PATH")) && !ENV['PATH'].include?(path)
    vars['PATH'] = path + ";" + ENV['PATH']
  end
  vars.map do |key, val|
    "#{key}=#{val}"
  end.join("\n")
end

#enable_msys_apps_per_ps1

This method is used for the ridk command.

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 298

def enable_msys_apps_per_ps1
  vars = with_msys_install_hint{ msys_apps_envvars }
  if (path=vars.delete("PATH")) && !ENV['PATH'].include?(path)
    vars['PATH'] = path + ";" + ENV['PATH']
  end
  vars.map do |key, val|
    "$env:#{key}=\"#{val.gsub('"', '`"')}\""
  end.join(";")
end

#install_mingw_packages(packages, verbose: false)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 347

def install_mingw_packages(packages, verbose: false)
  packages = packages.map{|pack| "#{mingw_package_prefix}-#{pack}" }
  install_packages(packages, verbose: verbose)
end

#install_packages(packages, verbose: false)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 320

def install_packages(packages, verbose: false)
  return if packages.empty?

  with_msys_apps_enabled do
    # Find packages that are already installed
    skips, installs = packages.partition do |package|
      IO.popen(["pacman", "-Q", package], err: :out, &:read)
      $?.success?
    end

    Gem.ui.say("Using msys2 packages: #{skips.join(" ")}") if verbose && skips.any?

    # Install required packages
    if installs.any?
      Gem.ui.say("Installing required msys2 packages: #{installs.join(" ")}") if verbose

      args = ["pacman", "-S", "--needed", "--noconfirm", *installs]
      Gem.ui.say("> #{args.join(" ")}") if verbose==1

      res = IO.popen(args, &:read)
      raise CommandError, "pacman failed with the following output:\n#{res}" if !$? || $?.exitstatus != 0

      Gem.ui.say(res) if verbose==1
    end
  end
end

#iterate_msys_paths {|File.join(RbConfig::TOPDIR, "msys64")| ... }

Yields:

  • (File.join(RbConfig::TOPDIR, "msys64"))

Raises:

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 48

def iterate_msys_paths
  # Prefer MSYS2_PATH if ENV set
  if ENV["MSYS2_PATH"]
    yield ENV["MSYS2_PATH"]
  end
  # Prefer MSYS2 when installed within the ruby directory.
  yield File.join(RbConfig::TOPDIR, "msys64")
  yield File.join(RbConfig::TOPDIR, "msys32")

  # Then try MSYS2 next to the ruby directory.
  yield File.join(File.dirname(RbConfig::TOPDIR), "msys64")
  yield File.join(File.dirname(RbConfig::TOPDIR), "msys32")

  # If msys2 is installed at the default location
  yield "c:/msys64"
  yield "c:/msys32"

  # If msys2 is installed per installer.exe
  require "win32/registry"
  [
    [Win32::Registry::HKEY_CURRENT_USER, MSYS2_INSTALL_KEY],
    [Win32::Registry::HKEY_CURRENT_USER, MSYS2_INSTALL_KEY_WOW],
    [Win32::Registry::HKEY_LOCAL_MACHINE, MSYS2_INSTALL_KEY],
    [Win32::Registry::HKEY_LOCAL_MACHINE, MSYS2_INSTALL_KEY_WOW],
  ].each do |reg_root, base_key|
    begin
      reg_root.open(backslachs(base_key)) do |reg|
        reg.each_key do |subkey|
          subreg = reg.open(subkey)
          begin
            if subreg['DisplayName'] =~ /^MSYS2 / && File.directory?(il=subreg['InstallLocation'])
              yield il
            end
          rescue Encoding::InvalidByteSequenceError, Win32::Registry::Error
            # Ignore entries without valid installer data or broken character encoding
          end
        end
      end
    rescue Win32::Registry::Error
    end
  end

  ENV['PATH'] && ENV['PATH'].split(";").each do |path|
    # If /path/to/msys64 is in the PATH (e.g. Chocolatey)
    yield path
  end

  # If msys2 is installed by scoop package manager
  begin
    yield IO.popen(["scoop", "prefix", "msys2"], &:read).strip
  rescue SystemCallError
  end

  raise MsysNotFound, "MSYS2 could not be found"
end

#mingw_bin_path

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 118

def mingw_bin_path
  backslachs( File.join(msys_path, mingwarch, "bin") )
end

#mingw_prefix

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 122

def mingw_prefix
  "/#{mingwarch}"
end

#msys_apps_envvars (private)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 145

private def msys_apps_envvars
  vars = {}
  msys_bin = msys_bin_path
  mingw_bin = mingw_bin_path
  ruby_bin = backslachs( ruby_bin_dir )
  ridkusepath = ENV["RIDK_USE_PATH"]

  vars['PATH'] = [ridkusepath, ruby_bin, mingw_bin, msys_bin].compact.join(";")
  vars['RI_DEVKIT'] = msys_path
  vars['MSYSTEM'] = mingwarch.upcase
  vars['PKG_CONFIG_PATH'] = "#{mingw_prefix}/lib/pkgconfig:#{mingw_prefix}/share/pkgconfig"
  vars['ACLOCAL_PATH'] = "#{mingw_prefix}/share/aclocal:/usr/share/aclocal"
  vars['MANPATH'] = "#{mingw_prefix}/share/man"
  vars['MINGW_PACKAGE_PREFIX'] = mingw_package_prefix
  if ENV['TMP'] !~ /\A[ -~]*\z/
    # TMP has some Unicode characters -> use MSYS2's /tmp to work around incompat with gcc's temporary files
    vars['TMP'] = backslachs( msys_path + "/tmp" )
  end

  case mingwarch
    when 'mingw32'
      vars['MSYSTEM_PREFIX'] = '/mingw32'
      vars['MSYSTEM_CARCH'] = 'i686'
      vars['MSYSTEM_CHOST'] = 'i686-w64-mingw32'
      vars['MINGW_CHOST'] = vars['MSYSTEM_CHOST']
      vars['MINGW_PREFIX'] = vars['MSYSTEM_PREFIX']
    when 'mingw64'
      vars['MSYSTEM_PREFIX'] = '/mingw64'
      vars['MSYSTEM_CARCH'] = 'x86_64'
      vars['MSYSTEM_CHOST'] = 'x86_64-w64-mingw32'
      vars['MINGW_CHOST'] = vars['MSYSTEM_CHOST']
      vars['MINGW_PREFIX'] = vars['MSYSTEM_PREFIX']
    when 'ucrt64'
      vars['MSYSTEM_PREFIX'] = '/ucrt64'
      vars['MSYSTEM_CARCH'] = 'x86_64'
      vars['MSYSTEM_CHOST'] = 'x86_64-w64-mingw32'
      vars['MINGW_CHOST'] = vars['MSYSTEM_CHOST']
      vars['MINGW_PREFIX'] = vars['MSYSTEM_PREFIX']
    else raise "unknown mingwarch #{@mingwarch.inspect}"
  end

  begin
    locale = IO.popen([File.join(msys_bin, "locale"), "-uU"], &:read)
  rescue SystemCallError
  else
    vars['LANG'] = locale=~/UTF-8/ ? locale.to_s.strip : 'C'
  end

  vars
end

#msys_bin_path

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 114

def msys_bin_path
  backslachs( File.join(msys_path, "/usr/bin") )
end

#msys_path

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 104

def msys_path
  @msys_path ||= begin
    iterate_msys_paths do |path|
      if File.exist?(File.join(path, "usr/bin/msys-2.0.dll"))
        break backslachs(path)
      end
    end
  end
end

#reset_cache

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 44

def reset_cache
  @msys_path = nil unless @msys_path_fixed
end

#with_msys_apps_disabled(**args)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 265

def with_msys_apps_disabled(**args)
  changed = disable_msys_apps(**args)
  begin
    yield
  ensure
    enable_msys_apps(**args) if changed
  end
end

#with_msys_apps_enabled(**args)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 256

def with_msys_apps_enabled(**args)
  changed = enable_msys_apps(**args)
  begin
    yield
  ensure
    disable_msys_apps(**args) if changed
  end
end

#with_msys_install_hint(if_no_msys = :hint) (private)

[ GitHub ]

  
# File 'lib/ruby_installer/build/msys2_installation.rb', line 196

private def with_msys_install_hint(if_no_msys = :hint)
  case if_no_msys
  when :hint
    begin
      yield
    rescue MsysNotFound
      $stderr.puts "MSYS2 could not be found. Please run 'ridk install'"
      $stderr.puts "or download and install MSYS2 manually from https://msys2.github.io/"
      exit 1
    end
  when :raise
    yield
  else
    raise ArgumentError, "invalid value #{if_no_msys.inspect} for variable if_no_msys"
  end
end