Skip to content

Commit

Permalink
Fix pacman install within a parallel bundler install -jX
Browse files Browse the repository at this point in the history
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 rubygems/rubygems#8248 .

Fixes #397
  • Loading branch information
larskanis committed Dec 30, 2024
1 parent e94bd18 commit 852af43
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 16 deletions.
35 changes: 21 additions & 14 deletions lib/ruby_installer/build/msys2_installation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions test/helper/testgem/Gemfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
source "https://dummy-url.nonexit"
gem "testgem2", "1.0.0"
gem "testgem", "1.0.0"
8 changes: 8 additions & 0 deletions test/helper/testgem/ext2/extconf2.rb
Original file line number Diff line number Diff line change
@@ -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")
17 changes: 17 additions & 0 deletions test/helper/testgem/ext2/testgem2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <sys/types.h>
#include <stdio.h>
#include <ruby.h>
#include <idn2.h>

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);
}
15 changes: 15 additions & 0 deletions test/helper/testgem/testgem2.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Gem::Specification.new do |s|
s.name = 'testgem2'
s.version = '1.0.0'
s.author = 'Lars Kanis'
s.email = '[email protected]'
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
9 changes: 7 additions & 2 deletions test/test_gem_install.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 852af43

Please sign in to comment.