From 852af43dab2c60ca1c0dd76bd322ad220287314e Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Thu, 21 Nov 2024 11:32:19 +0100 Subject: [PATCH] Fix pacman install within a parallel bundler install -jX pacman invocation must be serialized to avoid locking error. Add a second gem using libidn2, so that two different libraries are requested and the test case fails if anyone isn't available after parallel pacman execution. The test case requires bundler-2.6.x to trigger the failure due to https://github.com/rubygems/rubygems/pull/8248 . Fixes #397 --- .../build/msys2_installation.rb | 35 +++++++++++-------- test/helper/testgem/Gemfile | 1 + test/helper/testgem/ext2/extconf2.rb | 8 +++++ test/helper/testgem/ext2/testgem2.c | 17 +++++++++ test/helper/testgem/testgem2.gemspec | 15 ++++++++ test/test_gem_install.rb | 9 +++-- 6 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 test/helper/testgem/ext2/extconf2.rb create mode 100644 test/helper/testgem/ext2/testgem2.c create mode 100644 test/helper/testgem/testgem2.gemspec diff --git a/lib/ruby_installer/build/msys2_installation.rb b/lib/ruby_installer/build/msys2_installation.rb index 19438ca57..9868387b0 100644 --- a/lib/ruby_installer/build/msys2_installation.rb +++ b/lib/ruby_installer/build/msys2_installation.rb @@ -319,29 +319,36 @@ def disable_msys_apps_per_ps1 end.join(";") end + @@pacman_lock = Mutex.new + private def with_pacman_lock(&block) + @@pacman_lock.synchronize(&block) + end + 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 + with_pacman_lock 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? + 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 + # 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 + 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 + 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 + Gem.ui.say(res) if verbose==1 + end end end end diff --git a/test/helper/testgem/Gemfile b/test/helper/testgem/Gemfile index 8033850c2..e01964928 100644 --- a/test/helper/testgem/Gemfile +++ b/test/helper/testgem/Gemfile @@ -1,2 +1,3 @@ source "https://dummy-url.nonexit" +gem "testgem2", "1.0.0" gem "testgem", "1.0.0" diff --git a/test/helper/testgem/ext2/extconf2.rb b/test/helper/testgem/ext2/extconf2.rb new file mode 100644 index 000000000..ea1d6b581 --- /dev/null +++ b/test/helper/testgem/ext2/extconf2.rb @@ -0,0 +1,8 @@ +require 'mkmf' + +message "checking for libidn2 package: " +pkg = pkg_config('libidn2') || raise("pkg_config should find the config") +message "#{pkg.inspect}\n" +have_func('idn2_strerror') || raise("have_func should find the pkgconfig library") + +create_makefile("testgem2") diff --git a/test/helper/testgem/ext2/testgem2.c b/test/helper/testgem/ext2/testgem2.c new file mode 100644 index 000000000..ba1925d0e --- /dev/null +++ b/test/helper/testgem/ext2/testgem2.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +static VALUE rb_idn2_strerror(VALUE self, VALUE errcode){ + const char *res; + res = idn2_strerror(NUM2INT(errcode)); + return res ? rb_str_new_cstr(res) : Qnil; +} + +void +Init_testgem2(void) +{ + VALUE lg = rb_define_class("Idn2", rb_cObject); + rb_define_singleton_method(lg, "idn2_strerror", rb_idn2_strerror, 1); +} diff --git a/test/helper/testgem/testgem2.gemspec b/test/helper/testgem/testgem2.gemspec new file mode 100644 index 000000000..50647ec1b --- /dev/null +++ b/test/helper/testgem/testgem2.gemspec @@ -0,0 +1,15 @@ +Gem::Specification.new do |s| + s.name = 'testgem2' + s.version = '1.0.0' + s.author = 'Lars Kanis' + s.email = 'lars@greiz-reinsdorf.de' + s.homepage = 'https://github.com/larskanis/rubyinstaller2' + s.summary = 'RubyInstaller2 testgem' + s.description = 'A second gem to test gem installation with RubyInstaller2' + s.files = `git ls-files`.split("\n") + s.extensions << 'ext2/extconf2.rb' + s.license = 'BSD-3-Clause' + s.require_paths << 'lib' + s.required_ruby_version = '>= 2.1.0' + s.metadata['msys2_mingw_dependencies'] = 'libidn2 gcc>=8.0' +end diff --git a/test/test_gem_install.rb b/test/test_gem_install.rb index 2c9187b71..92dcd3992 100644 --- a/test/test_gem_install.rb +++ b/test/test_gem_install.rb @@ -33,15 +33,20 @@ def test_bundle_install res = system <<-EOT.gsub("\n", "&") cd test/helper/testgem gem build testgem.gemspec + gem build testgem2.gemspec copy /b testgem-1.0.0.gem "vendor/cache/" - bundle install --local + copy /b testgem2-1.0.0.gem "vendor/cache/" + bundle install --local -j16 EOT assert res, "shell commands should succeed" out = IO.popen("bundle exec ruby -rtestgem -e \"puts Libguess.determine_encoding('abc', 'Greek')\"", chdir: "test/helper/testgem", &:read) assert_match(/UTF-8/, out.scrub, "call the ruby API of the testgem") - assert system("gem uninstall testgem --executables --force"), "uninstall testgem" + out = IO.popen("bundle exec ruby -rtestgem2 -e \"puts Idn2.idn2_strerror(0)\"", chdir: "test/helper/testgem", &:read) + assert_match(/success/i, out.scrub, "call the ruby API of the testgem2") + + assert system("gem uninstall testgem testgem2 --executables --force"), "uninstall testgem" FileUtils.rm("test/helper/testgem/testgem-1.0.0.gem") end