From 326a71712fe5a7e90f0d019a610b173eee7ff37c Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Fri, 27 Sep 2024 01:55:26 +0100 Subject: [PATCH 1/2] Revert "Shorten `brew tests` temporary paths." This reverts commit 27fb07c0fc622d3e010a8a9f6e0056fd09dc5b1f. --- Library/Homebrew/test/support/lib/startup/config.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Library/Homebrew/test/support/lib/startup/config.rb b/Library/Homebrew/test/support/lib/startup/config.rb index 6891a9a11bbaa..8bbba31ea374c 100644 --- a/Library/Homebrew/test/support/lib/startup/config.rb +++ b/Library/Homebrew/test/support/lib/startup/config.rb @@ -5,9 +5,8 @@ HOMEBREW_BREW_FILE = Pathname.new(ENV.fetch("HOMEBREW_BREW_FILE")).freeze -homebrew_temp = ENV.fetch("HOMEBREW_TEMP") TEST_TMPDIR = ENV.fetch("HOMEBREW_TEST_TMPDIR") do |k| - dir = Dir.mktmpdir("homebrew-tests-", homebrew_temp) + dir = Dir.mktmpdir("homebrew-tests-", ENV.fetch("HOMEBREW_TEMP")) at_exit do # Child processes inherit this at_exit handler, but we don't want them # to clean TEST_TMPDIR up prematurely (i.e. when they exit early for a test). @@ -16,13 +15,6 @@ ENV[k] = dir end.freeze -# Use a shorter HOMEBREW_TEMP path so Sequoia doesn't error out as often on long paths (> 104 bytes). -# Use the minimal amount of randomness to avoid collisions while allowing parallel tests. -require "securerandom" -random_hex = SecureRandom.hex(2) -HOMEBREW_TEMP = Pathname("#{homebrew_temp}/brewtests#{random_hex}".squeeze("/")).freeze -HOMEBREW_TEMP.mkpath - # Paths pointing into the Homebrew code base that persist across test runs HOMEBREW_SHIMS_PATH = (HOMEBREW_LIBRARY_PATH/"shims").freeze @@ -40,6 +32,7 @@ HOMEBREW_LOCKS = (HOMEBREW_PREFIX.parent/"locks").freeze HOMEBREW_CELLAR = (HOMEBREW_PREFIX.parent/"cellar").freeze HOMEBREW_LOGS = (HOMEBREW_PREFIX.parent/"logs").freeze +HOMEBREW_TEMP = (HOMEBREW_PREFIX.parent/"temp").freeze HOMEBREW_TAP_DIRECTORY = (HOMEBREW_LIBRARY/"Taps").freeze HOMEBREW_RUBY_EXEC_ARGS = [ RUBY_PATH, From 567f5eb4be2de4e2555911c6e298525aefb337de Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Fri, 27 Sep 2024 02:50:37 +0100 Subject: [PATCH 2/2] Allow sockets to use longer paths on macOS --- Library/Homebrew/build.rb | 4 +- .../Homebrew/extend/os/mac/utils/socket.rb | 30 ++++++++++ Library/Homebrew/extend/os/utils/socket.rb | 4 ++ Library/Homebrew/postinstall.rb | 4 +- Library/Homebrew/test.rb | 4 +- Library/Homebrew/utils/fork.rb | 4 +- Library/Homebrew/utils/socket.rb | 57 +++++++++++++++++++ 7 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 Library/Homebrew/extend/os/mac/utils/socket.rb create mode 100644 Library/Homebrew/extend/os/utils/socket.rb create mode 100644 Library/Homebrew/utils/socket.rb diff --git a/Library/Homebrew/build.rb b/Library/Homebrew/build.rb index 53d5e908a9285..4d782c2ed5da1 100644 --- a/Library/Homebrew/build.rb +++ b/Library/Homebrew/build.rb @@ -13,7 +13,7 @@ require "keg" require "extend/ENV" require "fcntl" -require "socket" +require "utils/socket" require "cmd/install" require "json/add/exception" @@ -221,7 +221,7 @@ def fixopt(formula) args = Homebrew::Cmd::InstallCmd.new.args Context.current = args.context - error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io) + error_pipe = Utils::UNIXSocketExt.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io) error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) trap("INT", old_trap) diff --git a/Library/Homebrew/extend/os/mac/utils/socket.rb b/Library/Homebrew/extend/os/mac/utils/socket.rb new file mode 100644 index 0000000000000..563a9b86d496a --- /dev/null +++ b/Library/Homebrew/extend/os/mac/utils/socket.rb @@ -0,0 +1,30 @@ +# typed: strict +# frozen_string_literal: true + +require "socket" + +module OS + module Mac + # Wrapper around UNIXSocket to allow > 104 characters on macOS. + module UNIXSocketExt + extend T::Helpers + + requires_ancestor { Kernel } + + sig { params(path: String).returns(String) } + def sockaddr_un(path) + if path.bytesize > 252 # largest size that can fit into a single-byte length + raise ArgumentError, "too long unix socket path (#{path.bytesize} bytes given but 252 bytes max)" + end + + [ + path.bytesize + 3, # = length (1 byte) + family (1 byte) + path (variable) + null terminator (1 byte) + 1, # AF_UNIX + path, + ].pack("CCZ*") + end + end + end +end + +Utils::UNIXSocketExt.singleton_class.prepend(OS::Mac::UNIXSocketExt) diff --git a/Library/Homebrew/extend/os/utils/socket.rb b/Library/Homebrew/extend/os/utils/socket.rb new file mode 100644 index 0000000000000..97c060d894e32 --- /dev/null +++ b/Library/Homebrew/extend/os/utils/socket.rb @@ -0,0 +1,4 @@ +# typed: strict +# frozen_string_literal: true + +require "extend/os/mac/utils/socket" if OS.mac? diff --git a/Library/Homebrew/postinstall.rb b/Library/Homebrew/postinstall.rb index db551669d6415..5b4db3f545267 100644 --- a/Library/Homebrew/postinstall.rb +++ b/Library/Homebrew/postinstall.rb @@ -8,7 +8,7 @@ require_relative "global" require "fcntl" -require "socket" +require "utils/socket" require "cli/parser" require "cmd/postinstall" require "json/add/exception" @@ -16,7 +16,7 @@ begin ENV.delete("HOMEBREW_FORBID_PACKAGES_FROM_PATHS") args = Homebrew::Cmd::Postinstall.new.args - error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io) + error_pipe = Utils::UNIXSocketExt.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io) error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) trap("INT", old_trap) diff --git a/Library/Homebrew/test.rb b/Library/Homebrew/test.rb index d20756b75b082..7a333b3606bbb 100644 --- a/Library/Homebrew/test.rb +++ b/Library/Homebrew/test.rb @@ -11,7 +11,7 @@ require "formula_assertions" require "formula_free_port" require "fcntl" -require "socket" +require "utils/socket" require "cli/parser" require "dev-cmd/test" require "json/add/exception" @@ -23,7 +23,7 @@ args = Homebrew::DevCmd::Test.new.args Context.current = args.context - error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io) + error_pipe = Utils::UNIXSocketExt.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io) error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) trap("INT", old_trap) diff --git a/Library/Homebrew/utils/fork.rb b/Library/Homebrew/utils/fork.rb index 79ffeb959f4d7..8a095941d4010 100644 --- a/Library/Homebrew/utils/fork.rb +++ b/Library/Homebrew/utils/fork.rb @@ -2,7 +2,7 @@ # frozen_string_literal: true require "fcntl" -require "socket" +require "utils/socket" module Utils def self.rewrite_child_error(child_error) @@ -37,7 +37,7 @@ def self.safe_fork(directory: nil, yield_parent: false) require "json/add/exception" block = proc do |tmpdir| - UNIXServer.open("#{tmpdir}/socket") do |server| + UNIXServerExt.open("#{tmpdir}/socket") do |server| read, write = IO.pipe pid = fork do diff --git a/Library/Homebrew/utils/socket.rb b/Library/Homebrew/utils/socket.rb new file mode 100644 index 0000000000000..7fb7139e33383 --- /dev/null +++ b/Library/Homebrew/utils/socket.rb @@ -0,0 +1,57 @@ +# typed: strict +# frozen_string_literal: true + +require "socket" + +module Utils + # Wrapper around UNIXSocket to allow > 104 characters on macOS. + module UNIXSocketExt + extend T::Generic + + sig { + type_parameters(:U).params( + path: String, + _block: T.proc.params(arg0: UNIXSocket).returns(T.type_parameter(:U)), + ).returns(T.type_parameter(:U)) + } + def self.open(path, &_block) + socket = Socket.new(:UNIX, :STREAM) + socket.connect(sockaddr_un(path)) + unix_socket = UNIXSocket.for_fd(socket.fileno) + socket.autoclose = false # Transfer autoclose responsibility to UNIXSocket + yield unix_socket + end + + sig { params(path: String).returns(String) } + def self.sockaddr_un(path) + Socket.sockaddr_un(path) + end + end + + # Wrapper around UNIXServer to allow > 104 characters on macOS. + class UNIXServerExt < Socket + extend T::Generic + + Elem = type_member(:out) { { fixed: String } } + + sig { returns(String) } + attr_reader :path + + sig { params(path: String).void } + def initialize(path) + super(:UNIX, :STREAM) + bind(UNIXSocketExt.sockaddr_un(path)) + listen(Socket::SOMAXCONN) + @path = path + end + + sig { returns(UNIXSocket) } + def accept_nonblock + socket, = super + socket.autoclose = false # Transfer autoclose responsibility to UNIXSocket + UNIXSocket.for_fd(socket.fileno) + end + end +end + +require "extend/os/utils/socket"