Module: Utils

Defined in:
Library/Homebrew/utils/git.rb,
Library/Homebrew/utils/svn.rb,
Library/Homebrew/utils/fork.rb,
Library/Homebrew/utils/link.rb,
Library/Homebrew/utils/popen.rb,
Library/Homebrew/utils/shell.rb,
Library/Homebrew/utils/bottles.rb,
Library/Homebrew/utils/shebang.rb,
Library/Homebrew/utils/analytics.rb,
Library/Homebrew/utils/inreplace.rb,
Library/Homebrew/extend/os/mac/utils/bottles.rb,
Library/Homebrew/extend/os/mac/utils/analytics.rb,
Library/Homebrew/extend/os/linux/utils/analytics.rb

Defined Under Namespace

Modules: Analytics, Bottles, Git, Inreplace, Link, Shebang, Shell, Svn

Class Method Summary collapse

Class Method Details

.popen(args, mode, options = {}) ⇒ Object


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'Library/Homebrew/utils/popen.rb', line 26

def self.popen(args, mode, options = {})
  IO.popen("-", mode) do |pipe|
    if pipe
      return pipe.read unless block_given?

      yield pipe
    else
      options[:err] ||= :close unless ENV["HOMEBREW_STDERR"]
      begin
        exec(*args, options)
      rescue Errno::ENOENT
        $stderr.puts "brew: command not found: #{args[0]}" unless options[:err] == :close
        exit! 127
      rescue SystemCallError
        $stderr.puts "brew: exec failed: #{args[0]}" unless options[:err] == :close
        exit! 1
      end
    end
  end
end

.popen_read(*args, **options, &block) ⇒ Object


4
5
6
# File 'Library/Homebrew/utils/popen.rb', line 4

def self.popen_read(*args, **options, &block)
  popen(args, "rb", options, &block)
end

.popen_write(*args, **options, &block) ⇒ Object


15
16
17
# File 'Library/Homebrew/utils/popen.rb', line 15

def self.popen_write(*args, **options, &block)
  popen(args, "wb", options, &block)
end

.rewrite_child_error(child_error) ⇒ Object


7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'Library/Homebrew/utils/fork.rb', line 7

def self.rewrite_child_error(child_error)
  error = if child_error.inner["cmd"] &&
             child_error.inner_class == ErrorDuringExecution
    ErrorDuringExecution.new(child_error.inner["cmd"],
                             status: child_error.inner["status"],
                             output: child_error.inner["output"])
  elsif child_error.inner["cmd"] &&
        child_error.inner_class == BuildError
    # We fill `BuildError#formula` and `BuildError#options` in later,
    # when we rescue this in `FormulaInstaller#build`.
    BuildError.new(nil, child_error.inner["cmd"],
                   child_error.inner["args"], child_error.inner["env"])
  elsif child_error.inner_class == Interrupt
    Interrupt.new
  else
    # Everything other error in the child just becomes a RuntimeError.
    RuntimeError.new(child_error.message)
  end

  error.set_backtrace child_error.backtrace

  error
end

.safe_fork(&_block) ⇒ Object


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'Library/Homebrew/utils/fork.rb', line 31

def self.safe_fork(&_block)
  Dir.mktmpdir("homebrew", HOMEBREW_TEMP) do |tmpdir|
    UNIXServer.open("#{tmpdir}/socket") do |server|
      read, write = IO.pipe

      pid = fork do
        ENV["HOMEBREW_ERROR_PIPE"] = server.path
        server.close
        read.close
        write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
        yield
      rescue Exception => e # rubocop:disable Lint/RescueException
        error_hash = JSON.parse e.to_json

        # Special case: We need to recreate ErrorDuringExecutions
        # for proper error messages and because other code expects
        # to rescue them further down.
        if e.is_a?(ErrorDuringExecution)
          error_hash["cmd"] = e.cmd
          error_hash["status"] = e.status.exitstatus
          error_hash["output"] = e.output
        end

        write.puts error_hash.to_json
        write.close

        exit!
      else # rubocop:disable Layout/ElseAlignment
        exit!(true)
      end

      ignore_interrupts(:quietly) do # the child will receive the interrupt and marshal it back
        begin
          socket = server.accept_nonblock
        rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
          retry unless Process.waitpid(pid, Process::WNOHANG)
        else
          socket.send_io(write)
          socket.close
        end
        write.close
        data = read.read
        read.close
        Process.wait(pid) unless socket.nil?

        # 130 is the exit status for a process interrupted via Ctrl-C.
        # We handle it here because of the possibility of an interrupted process terminating
        # without writing its Interrupt exception to the error pipe.
        raise Interrupt if $CHILD_STATUS.exitstatus == 130

        if data && !data.empty?
          error_hash = JSON.parse(data.lines.first)

          e = ChildProcessError.new(error_hash)

          raise rewrite_child_error(e)
        end

        raise "Forked child process failed: #{$CHILD_STATUS}" unless $CHILD_STATUS.success?
      end
    end
  end
end

.safe_popen_read(*args, **options, &block) ⇒ Object


8
9
10
11
12
13
# File 'Library/Homebrew/utils/popen.rb', line 8

def self.safe_popen_read(*args, **options, &block)
  output = popen_read(*args, **options, &block)
  return output if $CHILD_STATUS.success?

  raise ErrorDuringExecution.new(args, status: $CHILD_STATUS, output: [[:stdout, output]])
end

.safe_popen_write(*args, **options, &block) ⇒ Object


19
20
21
22
23
24
# File 'Library/Homebrew/utils/popen.rb', line 19

def self.safe_popen_write(*args, **options, &block)
  output = popen_write(*args, **options, &block)
  return output if $CHILD_STATUS.success?

  raise ErrorDuringExecution.new(args, status: $CHILD_STATUS, output: [[:stdout, output]])
end