aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/brew.rb
blob: 2906fd93d8691105a02e0f9bc17bc39e9f09a8d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
unless ENV["HOMEBREW_BREW_FILE"]
  raise "HOMEBREW_BREW_FILE was not exported! Please call bin/brew directly!"
end

std_trap = trap("INT") { exit! 130 } # no backtrace thanks

# check ruby version before requiring any modules.
RUBY_TWO = RUBY_VERSION.split(".").first.to_i >= 2
raise "Homebrew must be run under Ruby 2!" unless RUBY_TWO

require "pathname"
HOMEBREW_LIBRARY_PATH = Pathname.new(__FILE__).realpath.parent
require "English"
unless $LOAD_PATH.include?(HOMEBREW_LIBRARY_PATH.to_s)
  $LOAD_PATH.unshift(HOMEBREW_LIBRARY_PATH.to_s)
end
require "global"
require "tap"

if ARGV == %w[--version] || ARGV == %w[-v]
  puts "Homebrew #{HOMEBREW_VERSION}"
  puts "Homebrew/homebrew-core #{CoreTap.instance.version_string}"
  exit 0
end

begin
  trap("INT", std_trap) # restore default CTRL-C handler

  empty_argv = ARGV.empty?
  help_flag_list = %w[-h --help --usage -?]
  help_flag = !ENV["HOMEBREW_HELP"].nil?
  internal_cmd = true
  cmd = nil

  ARGV.dup.each_with_index do |arg, i|
    break if help_flag && cmd

    if arg == "help" && !cmd
      # Command-style help: `help <cmd>` is fine, but `<cmd> help` is not.
      help_flag = true
    elsif !cmd && !help_flag_list.include?(arg)
      cmd = ARGV.delete_at(i)
    end
  end

  path = PATH.new(ENV["PATH"])
  homebrew_path = PATH.new(ENV["HOMEBREW_PATH"])

  # Add contributed commands to PATH before checking.
  tap_cmds = Pathname.glob(Tap::TAP_DIRECTORY/"*/*/cmd")
  path.append(tap_cmds)
  homebrew_path.append(tap_cmds)

  # Add SCM wrappers.
  path.append(HOMEBREW_SHIMS_PATH/"scm")
  homebrew_path.append(HOMEBREW_SHIMS_PATH/"scm")

  ENV["PATH"] = path

  if cmd
    internal_cmd = require? HOMEBREW_LIBRARY_PATH/"cmd"/cmd

    unless internal_cmd
      internal_cmd = require? HOMEBREW_LIBRARY_PATH/"dev-cmd"/cmd
      if internal_cmd && !ARGV.homebrew_developer?
        system "git", "config", "--file=#{HOMEBREW_REPOSITORY}/.git/config",
                                "--replace-all", "homebrew.devcmdrun", "true"
        ENV["HOMEBREW_DEV_CMD_RUN"] = "1"
      end
    end
  end

  # Usage instructions should be displayed if and only if one of:
  # - a help flag is passed AND a command is matched
  # - a help flag is passed AND there is no command specified
  # - no arguments are passed
  if empty_argv || help_flag
    require "cmd/help"
    Homebrew.help cmd, empty_argv: empty_argv
    # `Homebrew.help` never returns, except for external/unknown commands.
  end

  # Migrate LinkedKegs/PinnedKegs if update didn't already do so
  migrate_legacy_keg_symlinks_if_necessary

  # Uninstall old brew-cask if it's still around; we just use the tap now.
  if cmd == "cask" && (HOMEBREW_CELLAR/"brew-cask").exist?
    system(HOMEBREW_BREW_FILE, "uninstall", "--force", "brew-cask")
  end

  # External commands expect a normal PATH
  ENV["PATH"] = homebrew_path unless internal_cmd

  if internal_cmd
    Homebrew.send cmd.to_s.tr("-", "_").downcase
  elsif which "brew-#{cmd}"
    %w[CACHE LIBRARY_PATH].each do |e|
      ENV["HOMEBREW_#{e}"] = Object.const_get("HOMEBREW_#{e}").to_s
    end
    exec "brew-#{cmd}", *ARGV
  elsif (path = which("brew-#{cmd}.rb")) && require?(path)
    exit Homebrew.failed? ? 1 : 0
  else
    require "tap"
    possible_tap = OFFICIAL_CMD_TAPS.find { |_, cmds| cmds.include?(cmd) }
    possible_tap = Tap.fetch(possible_tap.first) if possible_tap

    odie "Unknown command: #{cmd}" if !possible_tap || possible_tap.installed?

    brew_uid = HOMEBREW_BREW_FILE.stat.uid
    tap_commands = []
    if Process.uid.zero? && !brew_uid.zero?
      tap_commands += %W[/usr/bin/sudo -u ##{brew_uid}]
    end
    tap_commands += %W[#{HOMEBREW_BREW_FILE} tap #{possible_tap}]
    safe_system(*tap_commands)
    exec HOMEBREW_BREW_FILE, cmd, *ARGV
  end
rescue UsageError => e
  require "cmd/help"
  Homebrew.help cmd, usage_error: e.message
rescue SystemExit => e
  onoe "Kernel.exit" if ARGV.verbose? && !e.success?
  $stderr.puts e.backtrace if ARGV.debug?
  raise
rescue Interrupt
  $stderr.puts # seemingly a newline is typical
  exit 130
rescue BuildError => e
  Utils::Analytics.report_build_error(e)
  e.dump
  exit 1
rescue RuntimeError, SystemCallError => e
  raise if e.message.empty?
  onoe e
  $stderr.puts e.backtrace if ARGV.debug?
  exit 1
rescue MethodDeprecatedError => e
  onoe e
  if e.issues_url
    $stderr.puts "If reporting this issue please do so at (not Homebrew/brew or Homebrew/core):"
    $stderr.puts "  #{Formatter.url(e.issues_url)}"
  end
  exit 1
rescue Exception => e
  onoe e
  if internal_cmd && defined?(OS::ISSUES_URL) &&
     !ENV["HOMEBREW_NO_AUTO_UPDATE"]
    $stderr.puts "#{Tty.bold}Please report this bug:#{Tty.reset}"
    $stderr.puts "  #{Formatter.url(OS::ISSUES_URL)}"
  end
  $stderr.puts e.backtrace
  exit 1
else
  exit 1 if Homebrew.failed?
end