Merge pull request #18434 from Homebrew/unix-socket
Allow sockets to use longer paths on macOS
This commit is contained in:
commit
b38cbbc085
@ -13,7 +13,7 @@ require "build_options"
|
|||||||
require "keg"
|
require "keg"
|
||||||
require "extend/ENV"
|
require "extend/ENV"
|
||||||
require "fcntl"
|
require "fcntl"
|
||||||
require "socket"
|
require "utils/socket"
|
||||||
require "cmd/install"
|
require "cmd/install"
|
||||||
require "json/add/exception"
|
require "json/add/exception"
|
||||||
|
|
||||||
@ -221,7 +221,7 @@ begin
|
|||||||
args = Homebrew::Cmd::InstallCmd.new.args
|
args = Homebrew::Cmd::InstallCmd.new.args
|
||||||
Context.current = args.context
|
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)
|
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
||||||
|
|
||||||
trap("INT", old_trap)
|
trap("INT", old_trap)
|
||||||
|
|||||||
30
Library/Homebrew/extend/os/mac/utils/socket.rb
Normal file
30
Library/Homebrew/extend/os/mac/utils/socket.rb
Normal file
@ -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)
|
||||||
4
Library/Homebrew/extend/os/utils/socket.rb
Normal file
4
Library/Homebrew/extend/os/utils/socket.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# typed: strict
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "extend/os/mac/utils/socket" if OS.mac?
|
||||||
@ -8,7 +8,7 @@ old_trap = trap("INT") { exit! 130 }
|
|||||||
require_relative "global"
|
require_relative "global"
|
||||||
|
|
||||||
require "fcntl"
|
require "fcntl"
|
||||||
require "socket"
|
require "utils/socket"
|
||||||
require "cli/parser"
|
require "cli/parser"
|
||||||
require "cmd/postinstall"
|
require "cmd/postinstall"
|
||||||
require "json/add/exception"
|
require "json/add/exception"
|
||||||
@ -16,7 +16,7 @@ require "json/add/exception"
|
|||||||
begin
|
begin
|
||||||
ENV.delete("HOMEBREW_FORBID_PACKAGES_FROM_PATHS")
|
ENV.delete("HOMEBREW_FORBID_PACKAGES_FROM_PATHS")
|
||||||
args = Homebrew::Cmd::Postinstall.new.args
|
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)
|
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
||||||
|
|
||||||
trap("INT", old_trap)
|
trap("INT", old_trap)
|
||||||
|
|||||||
@ -11,7 +11,7 @@ require "timeout"
|
|||||||
require "formula_assertions"
|
require "formula_assertions"
|
||||||
require "formula_free_port"
|
require "formula_free_port"
|
||||||
require "fcntl"
|
require "fcntl"
|
||||||
require "socket"
|
require "utils/socket"
|
||||||
require "cli/parser"
|
require "cli/parser"
|
||||||
require "dev-cmd/test"
|
require "dev-cmd/test"
|
||||||
require "json/add/exception"
|
require "json/add/exception"
|
||||||
@ -23,7 +23,7 @@ begin
|
|||||||
args = Homebrew::DevCmd::Test.new.args
|
args = Homebrew::DevCmd::Test.new.args
|
||||||
Context.current = args.context
|
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)
|
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
||||||
|
|
||||||
trap("INT", old_trap)
|
trap("INT", old_trap)
|
||||||
|
|||||||
@ -5,9 +5,8 @@ raise "HOMEBREW_BREW_FILE was not exported! Please call bin/brew directly!" unle
|
|||||||
|
|
||||||
HOMEBREW_BREW_FILE = Pathname.new(ENV.fetch("HOMEBREW_BREW_FILE")).freeze
|
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|
|
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
|
at_exit do
|
||||||
# Child processes inherit this at_exit handler, but we don't want them
|
# 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).
|
# to clean TEST_TMPDIR up prematurely (i.e. when they exit early for a test).
|
||||||
@ -16,13 +15,6 @@ TEST_TMPDIR = ENV.fetch("HOMEBREW_TEST_TMPDIR") do |k|
|
|||||||
ENV[k] = dir
|
ENV[k] = dir
|
||||||
end.freeze
|
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
|
# Paths pointing into the Homebrew code base that persist across test runs
|
||||||
HOMEBREW_SHIMS_PATH = (HOMEBREW_LIBRARY_PATH/"shims").freeze
|
HOMEBREW_SHIMS_PATH = (HOMEBREW_LIBRARY_PATH/"shims").freeze
|
||||||
|
|
||||||
@ -40,6 +32,7 @@ HOMEBREW_PINNED_KEGS = (HOMEBREW_PREFIX.parent/"pinned").freeze
|
|||||||
HOMEBREW_LOCKS = (HOMEBREW_PREFIX.parent/"locks").freeze
|
HOMEBREW_LOCKS = (HOMEBREW_PREFIX.parent/"locks").freeze
|
||||||
HOMEBREW_CELLAR = (HOMEBREW_PREFIX.parent/"cellar").freeze
|
HOMEBREW_CELLAR = (HOMEBREW_PREFIX.parent/"cellar").freeze
|
||||||
HOMEBREW_LOGS = (HOMEBREW_PREFIX.parent/"logs").freeze
|
HOMEBREW_LOGS = (HOMEBREW_PREFIX.parent/"logs").freeze
|
||||||
|
HOMEBREW_TEMP = (HOMEBREW_PREFIX.parent/"temp").freeze
|
||||||
HOMEBREW_TAP_DIRECTORY = (HOMEBREW_LIBRARY/"Taps").freeze
|
HOMEBREW_TAP_DIRECTORY = (HOMEBREW_LIBRARY/"Taps").freeze
|
||||||
HOMEBREW_RUBY_EXEC_ARGS = [
|
HOMEBREW_RUBY_EXEC_ARGS = [
|
||||||
RUBY_PATH,
|
RUBY_PATH,
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "fcntl"
|
require "fcntl"
|
||||||
require "socket"
|
require "utils/socket"
|
||||||
|
|
||||||
module Utils
|
module Utils
|
||||||
def self.rewrite_child_error(child_error)
|
def self.rewrite_child_error(child_error)
|
||||||
@ -37,7 +37,7 @@ module Utils
|
|||||||
require "json/add/exception"
|
require "json/add/exception"
|
||||||
|
|
||||||
block = proc do |tmpdir|
|
block = proc do |tmpdir|
|
||||||
UNIXServer.open("#{tmpdir}/socket") do |server|
|
UNIXServerExt.open("#{tmpdir}/socket") do |server|
|
||||||
read, write = IO.pipe
|
read, write = IO.pipe
|
||||||
|
|
||||||
pid = fork do
|
pid = fork do
|
||||||
|
|||||||
57
Library/Homebrew/utils/socket.rb
Normal file
57
Library/Homebrew/utils/socket.rb
Normal file
@ -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"
|
||||||
Loading…
x
Reference in New Issue
Block a user