Module: Homebrew

Extended by:
FileUtils
Defined in:
Library/Homebrew/cmd/cat.rb,
Library/Homebrew/utils.rb,
Library/Homebrew/cmd/sh.rb,
Library/Homebrew/global.rb,
Library/Homebrew/cleanup.rb,
Library/Homebrew/cmd/diy.rb,
Library/Homebrew/cmd/irb.rb,
Library/Homebrew/cmd/log.rb,
Library/Homebrew/cmd/pin.rb,
Library/Homebrew/cmd/tap.rb,
Library/Homebrew/options.rb,
Library/Homebrew/cmd/cask.rb,
Library/Homebrew/cmd/deps.rb,
Library/Homebrew/cmd/desc.rb,
Library/Homebrew/cmd/help.rb,
Library/Homebrew/cmd/home.rb,
Library/Homebrew/cmd/info.rb,
Library/Homebrew/cmd/link.rb,
Library/Homebrew/cmd/list.rb,
Library/Homebrew/cmd/uses.rb,
Library/Homebrew/cmd/--env.rb,
Library/Homebrew/cmd/fetch.rb,
Library/Homebrew/cmd/prune.rb,
Library/Homebrew/cmd/style.rb,
Library/Homebrew/cmd/unpin.rb,
Library/Homebrew/cmd/untap.rb,
Library/Homebrew/cmd/config.rb,
Library/Homebrew/cmd/doctor.rb,
Library/Homebrew/cmd/leaves.rb,
Library/Homebrew/cmd/search.rb,
Library/Homebrew/cmd/switch.rb,
Library/Homebrew/cmd/unlink.rb,
Library/Homebrew/cmd/unpack.rb,
Library/Homebrew/diagnostic.rb,
Library/Homebrew/cmd/--cache.rb,
Library/Homebrew/cmd/cleanup.rb,
Library/Homebrew/cmd/command.rb,
Library/Homebrew/cmd/install.rb,
Library/Homebrew/cmd/migrate.rb,
Library/Homebrew/cmd/missing.rb,
Library/Homebrew/cmd/options.rb,
Library/Homebrew/cmd/readall.rb,
Library/Homebrew/cmd/tap-pin.rb,
Library/Homebrew/cmd/upgrade.rb,
Library/Homebrew/dev-cmd/man.rb,
Library/Homebrew/cmd/--cellar.rb,
Library/Homebrew/cmd/--prefix.rb,
Library/Homebrew/cmd/commands.rb,
Library/Homebrew/cmd/linkapps.rb,
Library/Homebrew/cmd/outdated.rb,
Library/Homebrew/cmd/tap-info.rb,
Library/Homebrew/dev-cmd/edit.rb,
Library/Homebrew/dev-cmd/pull.rb,
Library/Homebrew/dev-cmd/test.rb,
Library/Homebrew/cmd/--version.rb,
Library/Homebrew/cmd/analytics.rb,
Library/Homebrew/cmd/gist-logs.rb,
Library/Homebrew/cmd/reinstall.rb,
Library/Homebrew/cmd/tap-unpin.rb,
Library/Homebrew/cmd/uninstall.rb,
Library/Homebrew/dev-cmd/audit.rb,
Library/Homebrew/dev-cmd/tests.rb,
Library/Homebrew/hooks/bottles.rb,
Library/Homebrew/cmd/unlinkapps.rb,
Library/Homebrew/dev-cmd/bottle.rb,
Library/Homebrew/dev-cmd/create.rb,
Library/Homebrew/dev-cmd/mirror.rb,
Library/Homebrew/cmd/postinstall.rb,
Library/Homebrew/dev-cmd/formula.rb,
Library/Homebrew/dev-cmd/linkage.rb,
Library/Homebrew/dev-cmd/tap-new.rb,
Library/Homebrew/missing_formula.rb,
Library/Homebrew/cmd/--repository.rb,
Library/Homebrew/build_environment.rb,
Library/Homebrew/cmd/update-report.rb,
Library/Homebrew/formula_assertions.rb,
Library/Homebrew/dev-cmd/update-test.rb,
Library/Homebrew/dev-cmd/release-notes.rb,
Library/Homebrew/dev-cmd/bump-formula-pr.rb,
Library/Homebrew/extend/os/mac/diagnostic.rb,
Library/Homebrew/dev-cmd/aspell-dictionaries.rb,
Library/Homebrew/dev-cmd/boneyard-formula-pr.rb,
Library/Homebrew/extend/os/mac/missing_formula.rb

Overview

: * release-notes [--markdown] [] []: : Output the merged pull requests on Homebrew/brew between two Git refs. : If no is provided it defaults to the newest tag. : If no is provided it defaults to origin/master. : : If --markdown is passed, output as a Markdown list.

Defined Under Namespace

Modules: Assertions, Cleanup, Diagnostic, Hooks, MissingFormula Classes: BottleInfo, DependentsMessage, DeveloperDependentsMessage, FormulaInfoFromJson, NondeveloperDependentsMessage, PatchPuller, RubocopLineLocation, RubocopOffense, RubocopResults

Constant Summary

UNBREWED_EXCLUDE_FILES =
%w[.DS_Store].freeze
UNBREWED_EXCLUDE_PATHS =
%w[
  .github/*
  bin/brew
  completions/zsh/_brew
  docs/*
  lib/gdk-pixbuf-2.0/*
  lib/gio/*
  lib/node_modules/*
  lib/python[23].[0-9]/*
  lib/pypy/*
  lib/pypy3/*
  lib/ruby/gems/[12].*
  lib/ruby/site_ruby/[12].*
  lib/ruby/vendor_ruby/[12].*
  manpages/brew.1
  manpages/brew-cask.1
  share/pypy/*
  share/pypy3/*
  share/info/dir
  share/man/whatis
].freeze
SEARCH_ERROR_QUEUE =
Queue.new
SEARCHABLE_TAPS =
OFFICIAL_TAPS.map { |tap| ["Homebrew", tap] } + [
%w[Caskroom cask],
%w[Caskroom versions],
SOURCE_PATH =
HOMEBREW_LIBRARY_PATH/"manpages"
TARGET_MAN_PATH =
HOMEBREW_REPOSITORY/"manpages"
TARGET_DOC_PATH =
HOMEBREW_REPOSITORY/"docs"
UNLINKAPPS_PREFIXES =
%W[
  #{HOMEBREW_CELLAR}/
  #{HOMEBREW_PREFIX}/opt/
].freeze

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from FileUtils

make, mkdir, mktemp, rake, ruby, scons, xcodebuild

Class Attribute Details

.failed=(value) ⇒ Object (writeonly)

Sets the attribute failed



37
38
39
# File 'Library/Homebrew/global.rb', line 37

def failed=(value)
  @failed = value
end

.raise_deprecation_exceptions=(value) ⇒ Object (writeonly)

Sets the attribute raise_deprecation_exceptions



43
44
45
# File 'Library/Homebrew/global.rb', line 43

def raise_deprecation_exceptions=(value)
  @raise_deprecation_exceptions = value
end

Class Method Details

.__cacheObject



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'Library/Homebrew/cmd/--cache.rb', line 12

def __cache
  if ARGV.named.empty?
    puts HOMEBREW_CACHE
  else
    ARGV.formulae.each do |f|
      if fetch_bottle?(f)
        puts f.bottle.cached_download
      else
        puts f.cached_download
      end
    end
  end
end

.__cellarObject



12
13
14
15
16
17
18
# File 'Library/Homebrew/cmd/--cellar.rb', line 12

def __cellar
  if ARGV.named.empty?
    puts HOMEBREW_CELLAR
  else
    puts ARGV.resolved_formulae.map(&:rack)
  end
end

.__envObject



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
# File 'Library/Homebrew/cmd/--env.rb', line 11

def __env
  ENV.activate_extensions!
  ENV.deps = ARGV.formulae if superenv?
  ENV.setup_build_environment
  ENV.universal_binary if ARGV.build_universal?

  shell_value = ARGV.value("shell")

  if ARGV.include?("--plain")
    shell = nil
  elsif shell_value.nil?
    # legacy behavior
    shell = :bash unless $stdout.tty?
  elsif shell_value == "auto"
    shell = Utils::Shell.parent_shell || Utils::Shell.preferred_shell
  elsif shell_value
    shell = Utils::Shell.path_to_shell(shell_value)
  end

  env_keys = build_env_keys(ENV)
  if shell.nil?
    dump_build_env ENV
  else
    env_keys.each { |key| puts Utils::Shell.export_value(shell, key, ENV[key]) }
  end
end

.__getsObject



96
97
98
99
# File 'Library/Homebrew/dev-cmd/create.rb', line 96

def __gets
  gots = $stdin.gets.chomp
  gots.empty? ? nil : gots
end

.__prefixObject



10
11
12
13
14
15
16
17
18
# File 'Library/Homebrew/cmd/--prefix.rb', line 10

def __prefix
  if ARGV.named.empty?
    puts HOMEBREW_PREFIX
  else
    puts ARGV.resolved_formulae.map { |f|
      f.opt_prefix.exist? ? f.opt_prefix : f.installed_prefix
    }
  end
end

.__repositoryObject



13
14
15
16
17
18
19
# File 'Library/Homebrew/cmd/--repository.rb', line 13

def __repository
  if ARGV.named.empty?
    puts HOMEBREW_REPOSITORY
  else
    puts ARGV.named.map { |tap| Tap.fetch(tap).path }
  end
end

.__versionObject

Raises:



7
8
9
10
11
12
13
# File 'Library/Homebrew/cmd/--version.rb', line 7

def __version
  # As a special case, `--version` is implemented directly in `brew.rb`. This
  # file merely serves as a container for the documentation. It also catches
  # the case where running `brew --version` with additional arguments would
  # produce a rather cryptic message about a non-existent `--version` command.
  raise UsageError
end

._system(cmd, *args) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'Library/Homebrew/utils.rb', line 162

def _system(cmd, *args)
  pid = fork do
    yield if block_given?
    args.collect!(&:to_s)
    begin
      exec(cmd, *args)
    rescue
      nil
    end
    exit! 1 # never gets here unless exec failed
  end
  Process.wait(pid)
  $?.success?
end

.analyticsObject

Raises:



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
# File 'Library/Homebrew/cmd/analytics.rb', line 14

def analytics
  config_file = HOMEBREW_REPOSITORY/".git/config"

  raise UsageError if ARGV.named.size > 1
  case ARGV.named.first
  when nil, "state"
    analyticsdisabled = \
      Utils.popen_read("git config --file=#{config_file} --get homebrew.analyticsdisabled").chuzzle
    uuid = \
      Utils.popen_read("git config --file=#{config_file} --get homebrew.analyticsuuid").chuzzle
    if ENV["HOMEBREW_NO_ANALYTICS"]
      puts "Analytics is disabled (by HOMEBREW_NO_ANALYTICS)."
    elsif analyticsdisabled == "true"
      puts "Analytics is disabled."
    else
      puts "Analytics is enabled."
      puts "UUID: #{uuid}" if uuid
    end
  when "on"
    safe_system "git", "config", "--file=#{config_file}",
                                 "--replace-all", "homebrew.analyticsdisabled", "false"
    safe_system "git", "config", "--file=#{config_file}",
                                 "--replace-all", "homebrew.analyticsmessage", "true"
  when "off"
    safe_system "git", "config", "--file=#{config_file}",
                                 "--replace-all", "homebrew.analyticsdisabled", "true"
    system "git", "config", "--file=#{config_file}", "--unset-all", "homebrew.analyticsuuid"
  when "regenerate-uuid"
    # it will be regenerated in next run.
    system "git", "config", "--file=#{config_file}", "--unset-all", "homebrew.analyticsuuid"
  else
    raise UsageError
  end
end

.aspell_dictionariesObject



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
# File 'Library/Homebrew/dev-cmd/aspell-dictionaries.rb', line 12

def aspell_dictionaries
  dict_url    = "https://ftpmirror.gnu.org/aspell/dict"
  dict_mirror = "https://ftp.gnu.org/gnu/aspell/dict"
  languages   = {}

  open("#{dict_url}/0index.html") do |content|
    content.each_line do |line|
      break if %r{^</table} =~ line
      next unless /^<tr><td><a/ =~ line

      fields = line.split('"')
      lang = fields[1]
      path = fields[3]
      lang.tr!("-", "_")
      languages[lang] = path
    end
  end

  languages.inject([]) do |resources, (lang, path)|
    r = Resource.new(lang)
    r.owner = Formulary.factory("aspell")
    r.url "#{dict_url}/#{path}"
    r.mirror "#{dict_mirror}/#{path}"
    resources << r
  end.each(&:fetch).each do |r|
    puts "option \"with-lang-\#{r.name}\", \"Install \#{r.name} dictionary\"\nresource \"\#{r.name}\" do\nurl \"\#{r.url}\"\nmirror \"\#{r.mirrors.first}\"\nsha256 \"\#{r.cached_download.sha256}\"\nend\n\n"
  end
end

.auditObject



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
# File 'Library/Homebrew/dev-cmd/audit.rb', line 47

def audit
  Homebrew.inject_dump_stats!(FormulaAuditor, /^audit_/) if ARGV.switch? "D"

  formula_count = 0
  problem_count = 0

  new_formula = ARGV.include? "--new-formula"
  strict = new_formula || ARGV.include?("--strict")
  online = new_formula || ARGV.include?("--online")

  ENV.activate_extensions!
  ENV.setup_build_environment

  if ARGV.named.empty?
    ff = Formula
    files = Tap.map(&:formula_dir)
  else
    ff = ARGV.resolved_formulae
    files = ARGV.resolved_formulae.map(&:path)
  end

  if strict
    options = { fix: ARGV.flag?("--fix"), realpath: true }
    # Check style in a single batch run up front for performance
    style_results = check_style_json(files, options)
  end

  ff.each do |f|
    options = { new_formula: new_formula, strict: strict, online: online }
    options[:style_offenses] = style_results.file_offenses(f.path) if strict
    fa = FormulaAuditor.new(f, options)
    fa.audit

    next if fa.problems.empty?
    fa.problems
    formula_count += 1
    problem_count += fa.problems.size
    problem_lines = fa.problems.map { |p| "* #{p.chomp.gsub("\n", "\n    ")}" }
    if ARGV.include? "--display-filename"
      puts problem_lines.map { |s| "#{f.path}: #{s}" }
    else
      puts "#{f.full_name}:", problem_lines.map { |s| "  #{s}" }
    end
  end

  return if problem_count.zero?

  ofail "#{Formatter.pluralize(problem_count, "problem")} in #{Formatter.pluralize(formula_count, "formula")}"
end

.backup(keg) ⇒ Object



58
59
60
61
# File 'Library/Homebrew/cmd/reinstall.rb', line 58

def backup(keg)
  keg.unlink
  keg.rename backup_path(keg)
end

.backup_path(path) ⇒ Object



72
73
74
# File 'Library/Homebrew/cmd/reinstall.rb', line 72

def backup_path(path)
  Pathname.new "#{path}.reinstall"
end

.boneyard_formula_prObject



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
157
158
159
160
161
162
163
164
165
# File 'Library/Homebrew/dev-cmd/boneyard-formula-pr.rb', line 26

def boneyard_formula_pr
  local_only = ARGV.include?("--local")
  formula = ARGV.formulae.first
  reason = ARGV.value("reason")
  odie "No formula found!" unless formula

  formula_relpath = formula.path.relative_path_from(formula.tap.path)
  formula_file = "#{formula.name}.rb"
  bottle_block = File.read(formula.path).include? "  bottle do"
  boneyard_tap = Tap.fetch("homebrew", "boneyard")
  tap_migrations_path = formula.tap.path/"tap_migrations.json"
  if ARGV.dry_run?
    ohai "brew update"
    ohai "brew tap #{boneyard_tap.name}"
    ohai "cd #{formula.tap.path}"
    cd formula.tap.path
    ohai "cp #{formula_relpath} #{boneyard_tap.path}"
    ohai "git rm #{formula_relpath}"
    unless File.exist? tap_migrations_path
      ohai "Creating tap_migrations.json for #{formula.tap.name}"
      ohai "git add #{tap_migrations_path}"
    end
    ohai "Loading tap_migrations.json"
    ohai "Adding #{formula.name} to tap_migrations.json"
  else
    safe_system HOMEBREW_BREW_FILE, "update"
    safe_system HOMEBREW_BREW_FILE, "tap", boneyard_tap.name
    cd formula.tap.path
    cp formula_relpath, boneyard_tap.formula_dir
    safe_system "git", "rm", formula_relpath
    unless File.exist? tap_migrations_path
      tap_migrations_path.write "{\n}\n".undent
      safe_system "git", "add", tap_migrations_path
    end
    tap_migrations = JSON.parse(File.read(tap_migrations_path))
    tap_migrations[formula.name] = boneyard_tap.name
    tap_migrations = tap_migrations.sort.inject({}) { |acc, elem| acc.merge!(elem[0] => elem[1]) }
    tap_migrations_path.atomic_write(JSON.pretty_generate(tap_migrations) + "\n")
  end
  unless which("hub") || local_only
    if ARGV.dry_run?
      ohai "brew install hub"
    else
      safe_system HOMEBREW_BREW_FILE, "install", "hub"
    end
  end
  branch = "#{formula.name}-boneyard"

  reason = " because #{reason}" if reason

  if ARGV.dry_run?
    ohai "cd #{formula.tap.path}"
    ohai "git checkout --no-track -b #{branch} origin/master"
    ohai "git commit --no-edit --verbose --message=\"#{formula.name}: migrate to boneyard\" -- #{formula_relpath} #{tap_migrations_path.basename}"

    unless local_only
      ohai "hub fork --no-remote"
      ohai "hub fork"
      ohai "hub fork (to read $HUB_REMOTE)"
      ohai "git push $HUB_REMOTE #{branch}:#{branch}"
      ohai "hub pull-request -m $'#{formula.name}: migrate to boneyard\\n\\nCreated with `brew boneyard-formula-pr`#{reason}.'"
    end

    ohai "git checkout -"
  else
    cd formula.tap.path
    safe_system "git", "checkout", "--no-track", "-b", branch, "origin/master"
    safe_system "git", "commit", "--no-edit", "--verbose",
      "--message=#{formula.name}: migrate to boneyard",
      "--", formula_relpath, tap_migrations_path.basename

    unless local_only
      safe_system "hub", "fork", "--no-remote"
      quiet_system "hub", "fork"
      remote = Utils.popen_read("hub fork 2>&1")[/fatal: remote (.+) already exists\./, 1]
      odie "cannot get remote from 'hub'!" unless remote
      safe_system "git", "push", remote, "#{branch}:#{branch}"
      pr_message = "\#{formula.name}: migrate to boneyard\n\nCreated with `brew boneyard-formula-pr`\#{reason}.\n".undent
      pr_url = Utils.popen_read("hub", "pull-request", "-m", pr_message).chomp
    end

    safe_system "git", "checkout", "-"
  end

  if ARGV.dry_run?
    ohai "cd #{boneyard_tap.path}"
    ohai "git checkout --no-track -b #{branch} origin/master"
    if bottle_block
      ohai "Removing bottle block"
    else
      ohai "No bottle block to remove"
    end
    ohai "git add #{formula_file}"
    ohai "git commit --no-edit --verbose --message=\"#{formula.name}: migrate from #{formula.tap.repo}\" -- #{formula_file}"

    unless local_only
      ohai "hub fork --no-remote"
      ohai "hub fork"
      ohai "hub fork (to read $HUB_REMOTE)"
      ohai "git push $HUB_REMOTE #{branch}:#{branch}"
      ohai "hub pull-request --browse -m $'#{formula.name}: migrate from #{formula.tap.repo}\\n\\nGoes together with $PR_URL\\n\\nCreated with `brew boneyard-formula-pr`#{reason}.'"
    end

    ohai "git checkout -"
  else
    cd boneyard_tap.formula_dir
    safe_system "git", "checkout", "--no-track", "-b", branch, "origin/master"
    if bottle_block
      Utils::Inreplace.inreplace formula_file, /  bottle do.+?end\n\n/m, ""
    end
    safe_system "git", "add", formula_file
    safe_system "git", "commit", "--no-edit", "--verbose",
      "--message=#{formula.name}: migrate from #{formula.tap.repo}",
      "--", formula_file

    unless local_only
      safe_system "hub", "fork", "--no-remote"
      quiet_system "hub", "fork"
      remote = Utils.popen_read("hub fork 2>&1")[/fatal: remote (.+) already exists\./, 1]
      odie "cannot get remote from 'hub'!" unless remote
      safe_system "git", "push", remote, "#{branch}:#{branch}"
      safe_system "hub", "pull-request", "--browse", "-m", "\#{formula.name}: migrate from \#{formula.tap.repo}\n\nGoes together with \#{pr_url}.\n\nCreated with `brew boneyard-formula-pr`\#{reason}.\n".undent
    end

    safe_system "git", "checkout", "-"
  end
end

.bottleObject



492
493
494
495
496
497
498
499
500
# File 'Library/Homebrew/dev-cmd/bottle.rb', line 492

def bottle
  if ARGV.include? "--merge"
    merge
  else
    ARGV.resolved_formulae.each do |f|
      bottle_formula f
    end
  end
end

.bottle_formula(f) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'Library/Homebrew/dev-cmd/bottle.rb', line 154

def bottle_formula(f)
  unless f.installed?
    return ofail "Formula not installed or up-to-date: #{f.full_name}"
  end

  tap = f.tap

  unless tap
    unless ARGV.include?("--force-core-tap")
      return ofail "Formula not from core or any taps: #{f.full_name}"
    end

    tap = CoreTap.instance
  end

  if f.bottle_disabled?
    ofail "Formula has disabled bottle: #{f.full_name}"
    puts f.bottle_disable_reason
    return
  end

  unless Utils::Bottles.built_as? f
    return ofail "Formula not installed with '--build-bottle': #{f.full_name}"
  end

  return ofail "Formula has no stable version: #{f.full_name}" unless f.stable

  if ARGV.include?("--no-rebuild") || !f.tap
    rebuild = 0
  elsif ARGV.include? "--keep-old"
    rebuild = f.bottle_specification.rebuild
  else
    ohai "Determining #{f.full_name} bottle rebuild..."
    versions = FormulaVersions.new(f)
    rebuilds = versions.bottle_version_map("origin/master")[f.pkg_version]
    rebuilds.pop if rebuilds.last.to_i > 0
    rebuild = rebuilds.empty? ? 0 : rebuilds.max.to_i + 1
  end

  filename = Bottle::Filename.create(f, Utils::Bottles.tag, rebuild)
  bottle_path = Pathname.pwd/filename

  tar_filename = filename.to_s.sub(/.gz$/, "")
  tar_path = Pathname.pwd/tar_filename

  prefix = HOMEBREW_PREFIX.to_s
  repository = HOMEBREW_REPOSITORY.to_s
  cellar = HOMEBREW_CELLAR.to_s

  ohai "Bottling #{filename}..."

  keg = Keg.new(f.prefix)
  relocatable = false
  skip_relocation = false

  keg.lock do
    original_tab = nil
    changed_files = nil

    begin
      keg.delete_pyc_files!

      unless ARGV.include? "--skip-relocation"
        changed_files = keg.replace_locations_with_placeholders
      end

      Tab.clear_cache
      tab = Tab.for_keg(keg)
      original_tab = tab.dup
      tab.poured_from_bottle = false
      tab.HEAD = nil
      tab.time = nil
      tab.changed_files = changed_files
      tab.write

      keg.find do |file|
        if file.symlink?
          # Ruby does not support `File.lutime` yet.
          # Shellout using `touch` to change modified time of symlink itself.
          system "/usr/bin/touch", "-h",
                 "-t", tab.source_modified_time.strftime("%Y%m%d%H%M.%S"), file
        else
          file.utime(tab.source_modified_time, tab.source_modified_time)
        end
      end

      cd cellar do
        safe_system "tar", "cf", tar_path, "#{f.name}/#{f.pkg_version}"
        tar_path.utime(tab.source_modified_time, tab.source_modified_time)
        relocatable_tar_path = "#{f}-bottle.tar"
        mv tar_path, relocatable_tar_path
        # Use gzip, faster to compress than bzip2, faster to uncompress than bzip2
        # or an uncompressed tarball (and more bandwidth friendly).
        safe_system "gzip", "-f", relocatable_tar_path
        mv "#{relocatable_tar_path}.gz", bottle_path
      end

      if bottle_path.size > 1*1024*1024
        ohai "Detecting if #{filename} is relocatable..."
      end

      if prefix == "/usr/local"
        prefix_check = File.join(prefix, "opt")
      else
        prefix_check = prefix
      end

      ignores = []
      if f.deps.any? { |dep| dep.name == "go" }
        ignores << %r{#{Regexp.escape(HOMEBREW_CELLAR)}/go/[\d\.]+/libexec}
      end

      relocatable = true
      if ARGV.include? "--skip-relocation"
        skip_relocation = true
      else
        relocatable = false if keg_contain?(prefix_check, keg, ignores)
        relocatable = false if keg_contain?(repository, keg, ignores)
        relocatable = false if keg_contain?(cellar, keg, ignores)
        if prefix != prefix_check
          relocatable = false if keg_contain_absolute_symlink_starting_with?(prefix, keg)
          relocatable = false if keg_contain?("#{prefix}/etc", keg, ignores)
          relocatable = false if keg_contain?("#{prefix}/var", keg, ignores)
        end
        skip_relocation = relocatable && !keg.require_relocation?
      end
      puts if !relocatable && ARGV.verbose?
    rescue Interrupt
      ignore_interrupts { bottle_path.unlink if bottle_path.exist? }
      raise
    ensure
      ignore_interrupts do
        original_tab.write if original_tab
        unless ARGV.include? "--skip-relocation"
          keg.replace_placeholders_with_locations changed_files
        end
      end
    end
  end

  root_url = ARGV.value("root-url")
  # Use underscored version for legacy reasons. Remove at some point.
  root_url ||= ARGV.value("root_url")

  bottle = BottleSpecification.new
  bottle.tap = tap
  bottle.root_url(root_url) if root_url
  if relocatable
    if skip_relocation
      bottle.cellar :any_skip_relocation
    else
      bottle.cellar :any
    end
  else
    bottle.cellar cellar
    bottle.prefix prefix
  end
  bottle.rebuild rebuild
  sha256 = bottle_path.sha256
  bottle.sha256 sha256 => Utils::Bottles.tag

  old_spec = f.bottle_specification
  if ARGV.include?("--keep-old") && !old_spec.checksums.empty?
    mismatches = [:root_url, :prefix, :cellar, :rebuild].select do |key|
      old_spec.send(key) != bottle.send(key)
    end
    mismatches.delete(:cellar) if old_spec.cellar == :any && bottle.cellar == :any_skip_relocation
    unless mismatches.empty?
      bottle_path.unlink if bottle_path.exist?

      mismatches.map! do |key|
        old_value = old_spec.send(key).inspect
        value = bottle.send(key).inspect
        "#{key}: old: #{old_value}, new: #{value}"
      end

      odie "--keep-old was passed but there are changes in:\n\#{mismatches.join(\"\\n\")}\n".undent
    end
  end

  output = bottle_output bottle

  puts "./#{filename}"
  puts output

  return unless ARGV.include? "--json"
  json = {
    f.full_name => {
      "formula" => {
        "pkg_version" => f.pkg_version.to_s,
        "path" => f.path.to_s.strip_prefix("#{HOMEBREW_REPOSITORY}/"),
      },
      "bottle" => {
        "root_url" => bottle.root_url,
        "prefix" => bottle.prefix,
        "cellar" => bottle.cellar.to_s,
        "rebuild" => bottle.rebuild,
        "tags" => {
          Utils::Bottles.tag.to_s => {
            "filename" => filename.to_s,
            "sha256" => sha256,
          },
        },
      },
      "bintray" => {
        "package" => Utils::Bottles::Bintray.package(f.name),
        "repository" => Utils::Bottles::Bintray.repository(tap),
      },
    },
  }
  File.open("#{filename.prefix}.bottle.json", "w") do |file|
    file.write JSON.generate json
  end
end

.bottle_output(bottle) ⇒ Object



149
150
151
152
# File 'Library/Homebrew/dev-cmd/bottle.rb', line 149

def bottle_output(bottle)
  erb = ERB.new BOTTLE_ERB
  erb.result(bottle.instance_eval { binding }).gsub(/^\s*$\n/, "")
end

.brief_build_info(f) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
# File 'Library/Homebrew/cmd/gist-logs.rb', line 65

def brief_build_info(f)
  build_time_str = f.logs.ctime.strftime("%Y-%m-%d %H:%M:%S")
  s = "Homebrew build logs for \#{f.full_name} on \#{OS_VERSION}\n".undent
  if ARGV.include?("--with-hostname")
    hostname = Socket.gethostname
    s << "Host: #{hostname}\n"
  end
  s << "Build date: #{build_time_str}\n"
  s
end

.build_env_keys(env) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'Library/Homebrew/build_environment.rb', line 37

def build_env_keys(env)
  %w[
    CC CXX LD OBJC OBJCXX
    HOMEBREW_CC HOMEBREW_CXX
    CFLAGS CXXFLAGS CPPFLAGS LDFLAGS SDKROOT MAKEFLAGS
    CMAKE_PREFIX_PATH CMAKE_INCLUDE_PATH CMAKE_LIBRARY_PATH CMAKE_FRAMEWORK_PATH
    MACOSX_DEPLOYMENT_TARGET PKG_CONFIG_PATH PKG_CONFIG_LIBDIR
    HOMEBREW_DEBUG HOMEBREW_MAKE_JOBS HOMEBREW_VERBOSE
    HOMEBREW_SVN HOMEBREW_GIT
    HOMEBREW_SDKROOT HOMEBREW_BUILD_FROM_SOURCE
    MAKE GIT CPP
    ACLOCAL_PATH PATH CPATH
  ].select { |key| env.key?(key) }
end

.build_man_pageObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'Library/Homebrew/dev-cmd/man.rb', line 59

def build_man_page
  template = (SOURCE_PATH/"brew.1.md.erb").read
  variables = OpenStruct.new

  variables[:commands] = path_glob_commands("#{HOMEBREW_LIBRARY_PATH}/cmd/*.{rb,sh}")
  variables[:developer_commands] = path_glob_commands("#{HOMEBREW_LIBRARY_PATH}/dev-cmd/*.{rb,sh}")
  readme = HOMEBREW_REPOSITORY/"README.md"
  variables[:lead_maintainer] = readme.read[/(Homebrew's lead maintainer .*\.)/, 1]
                                      .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
  variables[:maintainers] = readme.read[/(Homebrew's current maintainers .*\.)/, 1]
                                  .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
  variables[:former_maintainers] = readme.read[/(Former maintainers .*\.)/, 1]
                                         .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')

  ERB.new(template, nil, ">").result(variables.instance_eval { binding })
end

.bump_formula_prObject



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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'Library/Homebrew/dev-cmd/bump-formula-pr.rb', line 110

def bump_formula_pr
  formula = ARGV.formulae.first

  if formula
    check_for_duplicate_pull_requests(formula)
    checked_for_duplicates = true
  end

  new_url = ARGV.value("url")
  if new_url && !formula
    is_devel = ARGV.include?("--devel")
    base_url = new_url.split("/")[0..4].join("/")
    base_url = /#{Regexp.escape(base_url)}/
    guesses = []
    Formula.each do |f|
      if is_devel && f.devel && f.devel.url && f.devel.url.match(base_url)
        guesses << f
      elsif f.stable && f.stable.url && f.stable.url.match(base_url)
        guesses << f
      end
    end
    if guesses.count == 1
      formula = guesses.shift
    elsif guesses.count > 1
      odie "Couldn't guess formula for sure: could be one of these:\n#{guesses}"
    end
  end
  odie "No formula found!" unless formula

  check_for_duplicate_pull_requests(formula) unless checked_for_duplicates

  requested_spec, formula_spec = if ARGV.include?("--devel")
    devel_message = " (devel)"
    [:devel, formula.devel]
  else
    [:stable, formula.stable]
  end
  odie "#{formula}: no #{requested_spec} specification found!" unless formula_spec

  hash_type, old_hash = if (checksum = formula_spec.checksum)
    [checksum.hash_type.to_s, checksum.hexdigest]
  end

  new_hash = ARGV.value(hash_type)
  new_tag = ARGV.value("tag")
  new_revision = ARGV.value("revision")
  new_mirror = ARGV.value("mirror")
  forced_version = ARGV.value("version")
  new_url_hash = if new_url && new_hash
    true
  elsif new_tag && new_revision
    false
  elsif !hash_type
    odie "#{formula}: no tag/revision specified!"
  elsif !new_url
    odie "#{formula}: no url specified!"
  else
    rsrc_url = if requested_spec != :devel && new_url =~ /.*ftpmirror.gnu.*/
      new_mirror = new_url.sub "ftpmirror.gnu.org", "ftp.gnu.org/gnu"
      new_mirror
    else
      new_url
    end
    rsrc = Resource.new { @url = rsrc_url }
    rsrc.download_strategy = CurlDownloadStrategy
    rsrc.owner = Resource.new(formula.name)
    rsrc.version = forced_version if forced_version
    odie "No version specified!" unless rsrc.version
    rsrc_path = rsrc.fetch
    if Utils.popen_read("/usr/bin/tar", "-tf", rsrc_path) =~ %r{/.*\.}
      new_hash = rsrc_path.sha256
    elsif new_url.include? ".tar"
      odie "#{formula}: no url/#{hash_type} specified!"
    end
  end

  if ARGV.dry_run?
    ohai "brew update"
  else
    safe_system "brew", "update"
  end

  old_formula_version = formula_version(formula, requested_spec)

  replacement_pairs = []
  if requested_spec == :stable && formula.revision.nonzero?
    replacement_pairs << [/^  revision \d+\n(\n(  head "))?/m, "\\2"]
  end

  replacement_pairs += formula_spec.mirrors.map do |mirror|
    [/ +mirror \"#{mirror}\"\n/m, ""]
  end

  replacement_pairs += if new_url_hash
    [
      [formula_spec.url, new_url],
      [old_hash, new_hash],
    ]
  else
    [
      [formula_spec.specs[:tag], new_tag],
      [formula_spec.specs[:revision], new_revision],
    ]
  end

  backup_file = File.read(formula.path) unless ARGV.dry_run?

  if new_mirror
    replacement_pairs << [/^( +)(url \"#{new_url}\"\n)/m, "\\1\\2\\1mirror \"#{new_mirror}\"\n"]
  end

  if forced_version && forced_version != "0"
    if requested_spec == :stable
      if File.read(formula.path).include?("version \"#{old_formula_version}\"")
        replacement_pairs << [old_formula_version.to_s, forced_version]
      elsif new_mirror
        replacement_pairs << [/^( +)(mirror \"#{new_mirror}\"\n)/m, "\\1\\2\\1version \"#{forced_version}\"\n"]
      else
        replacement_pairs << [/^( +)(url \"#{new_url}\"\n)/m, "\\1\\2\\1version \"#{forced_version}\"\n"]
      end
    elsif requested_spec == :devel
      replacement_pairs << [/(  devel do.+?version \")#{old_formula_version}(\"\n.+?end\n)/m, "\\1#{forced_version}\\2"]
    end
  elsif forced_version && forced_version == "0"
    if requested_spec == :stable
      replacement_pairs << [/^  version \"[a-z\d+\.]+\"\n/m, ""]
    elsif requested_spec == :devel
      replacement_pairs << [/(  devel do.+?)^ +version \"[^\n]+\"\n(.+?end\n)/m, "\\1\\2"]
    end
  end
  new_contents = inreplace_pairs(formula.path, replacement_pairs)

  new_formula_version = formula_version(formula, requested_spec, new_contents)

  if new_formula_version < old_formula_version
    formula.path.atomic_write(backup_file) unless ARGV.dry_run?
    odie "You probably need to bump this formula manually since changing the\nversion from \#{old_formula_version} to \#{new_formula_version} would be a downgrade.\n".undent
  elsif new_formula_version == old_formula_version
    formula.path.atomic_write(backup_file) unless ARGV.dry_run?
    odie "You probably need to bump this formula manually since the new version\nand old version are both \#{new_formula_version}.\n".undent
  end

  if ARGV.dry_run?
    if ARGV.include? "--strict"
      ohai "brew audit --strict #{formula.path.basename}"
    elsif ARGV.include? "--audit"
      ohai "brew audit #{formula.path.basename}"
    end
  else
    failed_audit = false
    if ARGV.include? "--strict"
      system HOMEBREW_BREW_FILE, "audit", "--strict", formula.path
      failed_audit = !$?.success?
    elsif ARGV.include? "--audit"
      system HOMEBREW_BREW_FILE, "audit", formula.path
      failed_audit = !$?.success?
    end
    if failed_audit
      formula.path.atomic_write(backup_file)
      odie "brew audit failed!"
    end
  end

  unless Formula["hub"].any_version_installed?
    if ARGV.dry_run?
      ohai "brew install hub"
    else
      safe_system "brew", "install", "hub"
    end
  end

  formula.path.parent.cd do
    branch = "#{formula.name}-#{new_formula_version}"
    if ARGV.dry_run?
      ohai "git checkout --no-track -b #{branch} origin/master"
      ohai "git commit --no-edit --verbose --message='#{formula.name} #{new_formula_version}#{devel_message}' -- #{formula.path}"
      ohai "hub fork --no-remote"
      ohai "hub fork"
      ohai "hub fork (to read $HUB_REMOTE)"
      ohai "git push --set-upstream $HUB_REMOTE #{branch}:#{branch}"
      ohai "hub pull-request --browse -m '#{formula.name} #{new_formula_version}#{devel_message}'"
      ohai "git checkout -"
    else
      safe_system "git", "checkout", "--no-track", "-b", branch, "origin/master"
      safe_system "git", "commit", "--no-edit", "--verbose",
        "--message=#{formula.name} #{new_formula_version}#{devel_message}",
        "--", formula.path
      safe_system "hub", "fork", "--no-remote"
      quiet_system "hub", "fork"
      remote = Utils.popen_read("hub fork 2>&1")[/fatal: remote (.+) already exists\./, 1]
      odie "cannot get remote from 'hub'!" if remote.to_s.empty?
      safe_system "git", "push", "--set-upstream", remote, "#{branch}:#{branch}"
      pr_message = "\#{formula.name} \#{new_formula_version}\#{devel_message}\n\nCreated with `brew bump-formula-pr`.\n".undent
      user_message = ARGV.value("message")
      if user_message
        pr_message += "\n---\n\n\#{user_message}\n".undent
      end
      safe_system "hub", "pull-request", "--browse", "-m", pr_message
      safe_system "git", "checkout", "-"
    end
  end
end

.caskObject



7
8
9
# File 'Library/Homebrew/cmd/cask.rb', line 7

def cask
  Hbc::CLI.process(ARGV)
end

.catObject



7
8
9
10
11
12
13
14
15
16
17
# File 'Library/Homebrew/cmd/cat.rb', line 7

def cat
  # do not "fix" this to support multiple arguments, the output would be
  # unparsable, if the user wants to cat multiple formula they can call
  # brew cat multiple times.
  formulae = ARGV.formulae
  raise FormulaUnspecifiedError if formulae.empty?
  raise "`brew cat` doesn't support multiple arguments" if formulae.size > 1

  cd HOMEBREW_REPOSITORY
  exec "cat", formulae.first.path, *ARGV.options_only
end

.check_bintray_mirror(name, url) ⇒ Object



608
609
610
611
612
613
614
# File 'Library/Homebrew/dev-cmd/pull.rb', line 608

def check_bintray_mirror(name, url)
  headers = curl_output("--connect-timeout", "15", "--head", url)[0]
  status_code = headers.scan(%r{^HTTP\/.* (\d+)}).last.first
  return if status_code.start_with?("3")
  opoo "The Bintray mirror #{url} is not reachable (HTTP status code #{status_code})."
  opoo "Do you need to upload it with `brew mirror #{name}`?"
end

.check_cellarObject



279
280
281
282
283
284
285
286
# File 'Library/Homebrew/cmd/install.rb', line 279

def check_cellar
  FileUtils.mkdir_p HOMEBREW_CELLAR unless File.exist? HOMEBREW_CELLAR
rescue
  raise "Could not create \#{HOMEBREW_CELLAR}\nCheck you have permission to write to \#{HOMEBREW_CELLAR.parent}\n".undent
end

.check_development_toolsObject



269
270
271
272
273
274
275
276
277
# File 'Library/Homebrew/cmd/install.rb', line 269

def check_development_tools
  checks = Diagnostic::Checks.new
  checks.fatal_development_tools_checks.each do |check|
    out = checks.send(check)
    next if out.nil?
    ofail out
  end
  exit 1 if Homebrew.failed?
end

.check_for_dependents(kegs) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
# File 'Library/Homebrew/cmd/uninstall.rb', line 89

def check_for_dependents(kegs)
  return false unless result = Keg.find_some_installed_dependents(kegs)

  if ARGV.homebrew_developer?
    DeveloperDependentsMessage.new(*result).output
  else
    NondeveloperDependentsMessage.new(*result).output
  end

  true
end

.check_for_duplicate_pull_requests(formula) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'Library/Homebrew/dev-cmd/bump-formula-pr.rb', line 90

def check_for_duplicate_pull_requests(formula)
  pull_requests = fetch_pull_requests(formula)
  return unless pull_requests && !pull_requests.empty?
  duplicates_message = "These open pull requests may be duplicates:\n\#{pull_requests.map { |pr| \"\#{pr[\"title\"]} \#{pr[\"html_url\"]}\" }.join(\"\\n\")}\n".undent
  error_message = "Duplicate PRs should not be opened. Use --force to override this error."
  if ARGV.force? && !ARGV.flag?("--quiet")
    opoo duplicates_message
  elsif !ARGV.force? && ARGV.flag?("--quiet")
    odie error_message
  elsif !ARGV.force?
    odie "\#{duplicates_message.chomp}\n\#{error_message}\n".undent
  end
end

.check_ppcObject



254
255
256
257
258
259
260
261
262
# File 'Library/Homebrew/cmd/install.rb', line 254

def check_ppc
  case Hardware::CPU.type
  when :ppc
    abort "Sorry, Homebrew does not support your computer's CPU architecture.\nFor PPC support, see: https://github.com/mistydemeo/tigerbrew\n".undent
  end
end

.check_style_and_print(files, options = {}) ⇒ Object

Checks style for a list of files, printing simple RuboCop output. Returns true if violations were found, false otherwise.



38
39
40
# File 'Library/Homebrew/cmd/style.rb', line 38

def check_style_and_print(files, options = {})
  check_style_impl(files, :print, options)
end

.check_style_impl(files, output_type, options = {}) ⇒ Object



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
# File 'Library/Homebrew/cmd/style.rb', line 48

def check_style_impl(files, output_type, options = {})
  fix = options[:fix]
  Homebrew.install_gem_setup_path! "rubocop", HOMEBREW_RUBOCOP_VERSION

  args = %w[
    --force-exclusion
  ]
  args << "--auto-correct" if fix

  if files.nil?
    args << "--config" << HOMEBREW_LIBRARY_PATH/".rubocop.yml"
    args += [HOMEBREW_LIBRARY_PATH]
  else
    args << "--config" << HOMEBREW_LIBRARY/".rubocop.yml"
    args += files
  end

  case output_type
  when :print
    args << "--display-cop-names" if ARGV.include? "--display-cop-names"
    args << "--format" << "simple" if files
    system "rubocop", *args
    !$?.success?
  when :json
    json = Utils.popen_read_text("rubocop", "--format", "json", *args)
    # exit status of 1 just means violations were found; other numbers mean
    # execution errors.
    # exitstatus can also be nil if RuboCop process crashes, e.g. due to
    # native extension problems.
    # JSON needs to be at least 2 characters.
    if $?.exitstatus.nil? || $?.exitstatus > 1 || json.to_s.length < 2
      raise "Error running `rubocop --format json #{args.join " "}`"
    end
    RubocopResults.new(JSON.parse(json))
  else
    raise "Invalid output_type for check_style_impl: #{output_type}"
  end
end

.check_style_json(files, options = {}) ⇒ Object

Checks style for a list of files, returning results as a RubocopResults object parsed from its JSON output.



44
45
46
# File 'Library/Homebrew/cmd/style.rb', line 44

def check_style_json(files, options = {})
  check_style_impl(files, :json, options)
end

.check_writable_install_locationObject



264
265
266
267
# File 'Library/Homebrew/cmd/install.rb', line 264

def check_writable_install_location
  raise "Cannot write to #{HOMEBREW_CELLAR}" if HOMEBREW_CELLAR.exist? && !HOMEBREW_CELLAR.writable_real?
  raise "Cannot write to #{HOMEBREW_PREFIX}" unless HOMEBREW_PREFIX.writable_real? || HOMEBREW_PREFIX.to_s == "/usr/local"
end

.cleanupObject



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'Library/Homebrew/cmd/cleanup.rb', line 20

def cleanup
  if ARGV.named.empty?
    Cleanup.cleanup
  else
    ARGV.resolved_formulae.each { |f| Cleanup.cleanup_formula f }
  end

  return if Cleanup.disk_cleanup_size.zero?

  disk_space = disk_usage_readable(Cleanup.disk_cleanup_size)
  if ARGV.dry_run?
    ohai "This operation would free approximately #{disk_space} of disk space."
  else
    ohai "This operation has freed approximately #{disk_space} of disk space."
  end
end

.commandObject



9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'Library/Homebrew/cmd/command.rb', line 9

def command
  abort "This command requires a command argument" if ARGV.empty?
  cmd = ARGV.first
  cmd = HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd)

  if (path = Commands.path(cmd))
    puts path
  elsif (path = which("brew-#{cmd}") || which("brew-#{cmd}.rb"))
    puts path
  else
    odie "Unknown command: #{cmd}"
  end
end

.command_help(path) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'Library/Homebrew/cmd/help.rb', line 76

def command_help(path)
  help_lines = path.read.lines.grep(/^#:/)
  if help_lines.empty?
    opoo "No help text in: #{path}" if ARGV.homebrew_developer?
    HOMEBREW_HELP
  else
    help_lines.map do |line|
      line.slice(2..-1)
          .sub(/^  \* /, "#{Tty.bold}brew#{Tty.reset} ")
          .gsub(/`(.*?)`/, "#{Tty.bold}\\1#{Tty.reset}")
          .gsub(%r{<([^\s]+?://[^\s]+?)>}) { |url| Formatter.url(url) }
          .gsub(/<(.*?)>/, "#{Tty.underline}\\1#{Tty.reset}")
          .gsub("@hide_from_man_page", "")
    end.join.strip
  end
end

.commandsObject



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'Library/Homebrew/cmd/commands.rb', line 10

def commands
  if ARGV.include? "--quiet"
    cmds = internal_commands + external_commands
    cmds += internal_developer_commands
    cmds += HOMEBREW_INTERNAL_COMMAND_ALIASES.keys if ARGV.include? "--include-aliases"
    puts Formatter.columns(cmds.sort)
  else
    # Find commands in Homebrew/cmd
    puts "Built-in commands"
    puts Formatter.columns(internal_commands)

    # Find commands in Homebrew/dev-cmd
    puts
    puts "Built-in developer commands"
    puts Formatter.columns(internal_developer_commands)

    # Find commands in the path
    unless (exts = external_commands).empty?
      puts
      puts "External commands"
      puts Formatter.columns(exts)
    end
  end
end

.configObject



11
12
13
# File 'Library/Homebrew/cmd/config.rb', line 11

def config
  SystemConfig.dump_verbose_config
end

.convert_man_page(markup, target) ⇒ Object



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
# File 'Library/Homebrew/dev-cmd/man.rb', line 81

def convert_man_page(markup, target)
  manual = target.basename(".1")
  organisation = "Homebrew"

  # Set the manpage date to the existing one if we're checking for changes.
  # This avoids the only change being e.g. a new date.
  date = if ARGV.include?("--fail-if-changed") &&
            target.extname == ".1" && target.exist?
    /"(\d{1,2})" "([A-Z][a-z]+) (\d{4})" "#{organisation}" "#{manual}"/ =~ target.read
    Date.parse("#{$1} #{$2} #{$3}")
  else
    Date.today
  end
  date = date.strftime("%Y-%m-%d")

  shared_args = %W[
    --pipe
    --organization=#{organisation}
    --manual=#{target.basename(".1")}
    --date=#{date}
  ]

  format_flag, format_desc = target_path_to_format(target)

  puts "Writing #{format_desc} to #{target}"
  Utils.popen(["ronn", format_flag] + shared_args, "rb+") do |ronn|
    ronn.write markup
    ronn.close_write
    target.atomic_write ronn.read
  end
end

.createObject

Create a formula from a tarball URL

Raises:



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
# File 'Library/Homebrew/dev-cmd/create.rb', line 30

def create
  # Allow searching MacPorts or Fink.
  if ARGV.include? "--macports"
    opoo "`brew create --macports` is deprecated; use `brew search --macports` instead"
    exec_browser "https://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
  elsif ARGV.include? "--fink"
    opoo "`brew create --fink` is deprecated; use `brew search --fink` instead"
    exec_browser "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}"
  end

  raise UsageError if ARGV.named.empty?

  # Ensure that the cache exists so we can fetch the tarball
  HOMEBREW_CACHE.mkpath

  url = ARGV.named.first # Pull the first (and only) url from ARGV

  version = ARGV.next if ARGV.include? "--set-version"
  name = ARGV.next if ARGV.include? "--set-name"
  tap = ARGV.next if ARGV.include? "--tap"

  fc = FormulaCreator.new
  fc.name = name
  fc.version = version
  fc.tap = Tap.fetch(tap || "homebrew/core")
  raise TapUnavailableError, tap unless fc.tap.installed?
  fc.url = url

  fc.mode = if ARGV.include? "--cmake"
    :cmake
  elsif ARGV.include? "--autotools"
    :autotools
  elsif ARGV.include? "--meson"
    :meson
  end

  if fc.name.nil? || fc.name.strip.empty?
    stem = Pathname.new(url).stem
    print "Formula name [#{stem}]: "
    fc.name = __gets || stem
    fc.update_path
  end

  # Don't allow blacklisted formula, or names that shadow aliases,
  # unless --force is specified.
  unless ARGV.force?
    if reason = Homebrew::MissingFormula.blacklisted_reason(fc.name)
      raise "#{fc.name} is blacklisted for creation.\n#{reason}\nIf you really want to create this formula use --force."
    end

    if Formula.aliases.include? fc.name
      realname = Formulary.canonical_name(fc.name)
      raise "The formula \#{realname} is already aliased to \#{fc.name}\nPlease check that you are not creating a duplicate.\nTo force creation use --force.\n".undent
    end
  end

  fc.generate!

  puts "Please `brew audit --new-formula #{fc.name}` before submitting, thanks."
  exec_editor fc.path
end

.create_gist(files, description) ⇒ Object



110
111
112
113
114
115
# File 'Library/Homebrew/cmd/gist-logs.rb', line 110

def create_gist(files, description)
  url = "https://api.github.com/gists"
  data = { "public" => true, "files" => files, "description" => description }
  scopes = GitHub::CREATE_GIST_SCOPES
  GitHub.open(url, data: data, scopes: scopes)["html_url"]
end

.create_issue(repo, title, body) ⇒ Object



117
118
119
120
121
122
# File 'Library/Homebrew/cmd/gist-logs.rb', line 117

def create_issue(repo, title, body)
  url = "https://api.github.com/repos/#{repo}/issues"
  data = { "title" => title, "body" => body }
  scopes = GitHub::CREATE_ISSUE_SCOPES
  GitHub.open(url, data: data, scopes: scopes)["html_url"]
end

.current_versions_from_info_external(formula_name) ⇒ Object

Get current formula versions without loading formula definition in this process Returns info as a hash (type => version), for pull.rb's internal use Uses special key :nonexistent => true for nonexistent formulae



366
367
368
369
370
371
372
373
374
375
376
377
# File 'Library/Homebrew/dev-cmd/pull.rb', line 366

def current_versions_from_info_external(formula_name)
  info = FormulaInfoFromJson.lookup(formula_name)
  versions = {}
  if info
    [:stable, :devel, :head].each do |spec_type|
      versions[spec_type] = info.version(spec_type)
    end
  else
    versions[:nonexistent] = true
  end
  versions
end

.decorate_dependencies(dependencies) ⇒ Object



168
169
170
171
172
173
174
175
176
177
# File 'Library/Homebrew/cmd/info.rb', line 168

def decorate_dependencies(dependencies)
  deps_status = dependencies.collect do |dep|
    if dep.satisfied?([])
      pretty_installed(dep_display_s(dep))
    else
      pretty_uninstalled(dep_display_s(dep))
    end
  end
  deps_status.join(", ")
end

.decorate_requirements(requirements) ⇒ Object



179
180
181
182
183
184
185
# File 'Library/Homebrew/cmd/info.rb', line 179

def decorate_requirements(requirements)
  req_status = requirements.collect do |req|
    req_s = req.display_s
    req.satisfied? ? pretty_installed(req_s) : pretty_uninstalled(req_s)
  end
  req_status.join(", ")
end

.dep_display_name(d) ⇒ Object



75
76
77
# File 'Library/Homebrew/cmd/deps.rb', line 75

def dep_display_name(d)
  ARGV.include?("--full-name") ? d.to_formula.full_name : d.name
end

.dep_display_s(dep) ⇒ Object



187
188
189
190
# File 'Library/Homebrew/cmd/info.rb', line 187

def dep_display_s(dep)
  return dep.name if dep.option_tags.empty?
  "#{dep.name} #{dep.option_tags.map { |o| "--#{o}" }.join(" ")}"
end

.depsObject



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
# File 'Library/Homebrew/cmd/deps.rb', line 47

def deps
  mode = OpenStruct.new(
    installed?: ARGV.include?("--installed"),
    tree?: ARGV.include?("--tree"),
    all?: ARGV.include?("--all"),
    topo_order?: ARGV.include?("-n"),
    union?: ARGV.include?("--union"),
  )

  if mode.installed? && mode.tree?
    puts_deps_tree Formula.installed
  elsif mode.all?
    puts_deps Formula
  elsif mode.tree?
    raise FormulaUnspecifiedError if ARGV.named.empty?
    puts_deps_tree ARGV.formulae
  elsif ARGV.named.empty?
    raise FormulaUnspecifiedError unless mode.installed?
    puts_deps Formula.installed
  else
    all_deps = deps_for_formulae(ARGV.formulae, !ARGV.one?, &(mode.union? ? :| : :&))
    all_deps = all_deps.select(&:installed?) if mode.installed?
    all_deps = all_deps.map(&method(:dep_display_name)).uniq
    all_deps.sort! unless mode.topo_order?
    puts all_deps
  end
end

.deps_for_formula(f, recursive = false) ⇒ Object



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
# File 'Library/Homebrew/cmd/deps.rb', line 79

def deps_for_formula(f, recursive = false)
  includes = []
  ignores = []
  if ARGV.include? "--include-build"
    includes << "build?"
  else
    ignores << "build?"
  end
  if ARGV.include? "--include-optional"
    includes << "optional?"
  else
    ignores << "optional?"
  end
  ignores << "recommended?" if ARGV.include? "--skip-recommended"

  if recursive
    deps = f.recursive_dependencies do |dependent, dep|
      if dep.recommended?
        Dependency.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
      elsif dep.optional?
        Dependency.prune if !includes.include?("optional?") && !dependent.build.with?(dep)
      elsif dep.build?
        Dependency.prune unless includes.include?("build?")
      end
    end
    reqs = f.recursive_requirements do |dependent, req|
      if req.recommended?
        Requirement.prune if ignores.include?("recommended?") || dependent.build.without?(req)
      elsif req.optional?
        Requirement.prune if !includes.include?("optional?") && !dependent.build.with?(req)
      elsif req.build?
        Requirement.prune unless includes.include?("build?")
      end
    end
  else
    deps = f.deps.reject do |dep|
      ignores.any? { |ignore| dep.send(ignore) } && !includes.any? { |include| dep.send(include) }
    end
    reqs = f.requirements.reject do |req|
      ignores.any? { |ignore| req.send(ignore) } && !includes.any? { |include| req.send(include) }
    end
  end

  deps + reqs.select(&:default_formula?).map(&:to_dependency)
end

.deps_for_formulae(formulae, recursive = false, &block) ⇒ Object



125
126
127
# File 'Library/Homebrew/cmd/deps.rb', line 125

def deps_for_formulae(formulae, recursive = false, &block)
  formulae.map { |f| deps_for_formula(f, recursive) }.inject(&block)
end

.descObject



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'Library/Homebrew/cmd/desc.rb', line 16

def desc
  search_type = []
  search_type << :either if ARGV.flag? "--search"
  search_type << :name   if ARGV.flag? "--name"
  search_type << :desc   if ARGV.flag? "--description"

  if search_type.empty?
    raise FormulaUnspecifiedError if ARGV.named.empty?
    desc = {}
    ARGV.formulae.each { |f| desc[f.full_name] = f.desc }
    results = Descriptions.new(desc)
    results.print
  elsif search_type.size > 1
    odie "Pick one, and only one, of -s/--search, -n/--name, or -d/--description."
  elsif arg = ARGV.named.first
    regex = Homebrew.query_regexp(arg)
    results = Descriptions.search(regex, search_type.first)
    results.print
  else
    odie "You must provide a search term."
  end
end

.detect_name(path, version) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'Library/Homebrew/cmd/diy.rb', line 41

def detect_name(path, version)
  basename = path.basename.to_s
  detected_name = basename[/(.*?)-?#{Regexp.escape(version)}/, 1] || basename
  canonical_name = Formulary.canonical_name(detected_name)

  odie "The detected name \#{detected_name.inspect} exists in Homebrew as an alias\nof \#{canonical_name.inspect}. Consider using the canonical name instead:\nbrew diy --name=\#{canonical_name}\n\nTo continue using the detected name, pass it explicitly:\nbrew diy --name=\#{detected_name}\n".undent if detected_name != canonical_name

  detected_name
end

.detect_version(path) ⇒ Object



33
34
35
36
37
38
39
# File 'Library/Homebrew/cmd/diy.rb', line 33

def detect_version(path)
  version = path.version.to_s

  raise "Couldn't determine version, set it with --version=<version>" if version.empty?

  version
end

.diyObject



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'Library/Homebrew/cmd/diy.rb', line 16

def diy
  path = Pathname.getwd

  version = ARGV.value("version") || detect_version(path)
  name = ARGV.value("name") || detect_name(path, version)

  prefix = HOMEBREW_CELLAR/name/version

  if File.file? "CMakeLists.txt"
    puts "-DCMAKE_INSTALL_PREFIX=#{prefix}"
  elsif File.file? "configure"
    puts "--prefix=#{prefix}"
  else
    raise "Couldn't determine build system"
  end
end

.doctorObject



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
# File 'Library/Homebrew/cmd/doctor.rb', line 13

def doctor
  inject_dump_stats!(Diagnostic::Checks, /^check_*/) if ARGV.switch? "D"

  checks = Diagnostic::Checks.new

  if ARGV.include? "--list-checks"
    puts checks.all.sort
    exit
  end

  if ARGV.named.empty?
    slow_checks = %w[
      check_for_broken_symlinks
      check_missing_deps
      check_for_linked_keg_only_brews
    ]
    methods = (checks.all.sort - slow_checks) + slow_checks
  else
    methods = ARGV.named
  end

  first_warning = true
  methods.each do |method|
    $stderr.puts "Checking #{method}" if ARGV.debug?
    unless checks.respond_to?(method)
      Homebrew.failed = true
      puts "No check available by the name: #{method}"
      next
    end

    out = checks.send(method)
    next if out.nil? || out.empty?
    if first_warning
      $stderr.puts "\#{Tty.bold}Please note that these warnings are just used to help the Homebrew maintainers\nwith debugging if you file an issue. If everything you use Homebrew for is\nworking fine: please don't worry and just ignore them. Thanks!\#{Tty.reset}\n".undent
    end

    $stderr.puts
    opoo out
    Homebrew.failed = true
    first_warning = false
  end

  puts "Your system is ready to brew." unless Homebrew.failed?
end

.dump_build_env(env, f = $stdout) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'Library/Homebrew/build_environment.rb', line 52

def dump_build_env(env, f = $stdout)
  keys = build_env_keys(env)
  keys -= %w[CC CXX OBJC OBJCXX] if env["CC"] == env["HOMEBREW_CC"]

  keys.each do |key|
    value = env[key]
    s = "#{key}: #{value}"
    case key
    when "CC", "CXX", "LD"
      s << " => #{Pathname.new(value).realpath}" if File.symlink?(value)
    end
    f.puts s
  end
end

.dump_options_for_formula(f) ⇒ Object



119
120
121
122
123
124
125
# File 'Library/Homebrew/options.rb', line 119

def dump_options_for_formula(f)
  f.options.sort_by(&:flag).each do |opt|
    puts "#{opt.flag}\n\t#{opt.description}"
  end
  puts "--devel\n\tInstall development version #{f.devel.version}" if f.devel
  puts "--HEAD\n\tInstall HEAD version" if f.head
end

.editObject



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
# File 'Library/Homebrew/dev-cmd/edit.rb', line 12

def edit
  unless (HOMEBREW_REPOSITORY/".git").directory?
    raise "Changes will be lost!\nThe first time you `brew update', all local changes will be lost, you should\nthus `brew update' before you `brew edit'!\n".undent
  end

  # If no brews are listed, open the project root in an editor.
  if ARGV.named.empty?
    editor = File.basename which_editor
    if editor == "mate" || editor == "subl"
      # If the user is using TextMate or Sublime Text,
      # give a nice project view instead.
      exec_editor HOMEBREW_REPOSITORY+"bin/brew",
                  HOMEBREW_REPOSITORY+"README.md",
                  HOMEBREW_REPOSITORY+".gitignore",
                  *library_folders
    else
      exec_editor HOMEBREW_REPOSITORY
    end
  else
    # Don't use ARGV.formulae as that will throw if the file doesn't parse
    paths = ARGV.named.map do |name|
      path = Formulary.path(name)

      raise FormulaUnavailableError, name unless path.file? || ARGV.force?

      path
    end
    exec_editor(*paths)
  end
end

.external_commandsObject



43
44
45
46
47
48
49
50
51
# File 'Library/Homebrew/cmd/commands.rb', line 43

def external_commands
  paths.each_with_object([]) do |path, cmds|
    Dir["#{path}/brew-*"].each do |file|
      next unless File.executable?(file)
      cmd = File.basename(file, ".rb")[5..-1]
      cmds << cmd unless cmd.include?(".")
    end
  end.sort
end

.failed?Boolean



39
40
41
# File 'Library/Homebrew/global.rb', line 39

def failed?
  @failed == true
end

.fetchObject



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
# File 'Library/Homebrew/cmd/fetch.rb', line 30

def fetch
  raise FormulaUnspecifiedError if ARGV.named.empty?

  if ARGV.include? "--deps"
    bucket = []
    ARGV.formulae.each do |f|
      bucket << f
      bucket.concat f.recursive_dependencies.map(&:to_formula)
    end
    bucket.uniq!
  else
    bucket = ARGV.formulae
  end

  puts "Fetching: #{bucket * ", "}" if bucket.size > 1
  bucket.each do |f|
    f.print_tap_action verb: "Fetching"

    fetched_bottle = false
    if fetch_bottle?(f)
      begin
        fetch_formula(f.bottle)
      rescue Exception => e
        raise if ARGV.homebrew_developer? || e.is_a?(Interrupt)
        fetched_bottle = false
        onoe e.message
        opoo "Bottle fetch failed: fetching the source."
      else
        fetched_bottle = true
      end
    end

    next if fetched_bottle
    fetch_formula(f)
    f.resources.each { |r| fetch_resource(r) }
    f.patchlist.each { |p| fetch_patch(p) if p.external? }
  end
end

.fetch_bottle?(f) ⇒ Boolean



69
70
71
72
73
74
75
# File 'Library/Homebrew/cmd/fetch.rb', line 69

def fetch_bottle?(f)
  return true if ARGV.force_bottle? && f.bottle
  return false unless f.bottle && f.pour_bottle?
  return false if ARGV.build_formula_from_source?(f)
  return false unless f.bottle.compatible_cellar?
  true
end

.fetch_fetchable(f) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'Library/Homebrew/cmd/fetch.rb', line 111

def fetch_fetchable(f)
  f.clear_cache if ARGV.force?

  already_fetched = f.cached_download.exist?

  begin
    download = f.fetch
  rescue DownloadError
    retry if retry_fetch? f
    raise
  end

  return unless download.file?

  puts "Downloaded to: #{download}" unless already_fetched
  puts Checksum::TYPES.map { |t| "#{t.to_s.upcase}: #{download.send(t)}" }

  f.verify_download_integrity(download)
end

.fetch_formula(f) ⇒ Object



85
86
87
88
89
90
# File 'Library/Homebrew/cmd/fetch.rb', line 85

def fetch_formula(f)
  fetch_fetchable f
rescue ChecksumMismatchError => e
  retry if retry_fetch? f
  opoo "Formula reports different #{e.hash_type}: #{e.expected}"
end

.fetch_patch(p) ⇒ Object



92
93
94
95
96
97
# File 'Library/Homebrew/cmd/fetch.rb', line 92

def fetch_patch(p)
  fetch_fetchable p
rescue ChecksumMismatchError => e
  Homebrew.failed = true
  opoo "Patch reports different #{e.hash_type}: #{e.expected}"
end

.fetch_pull_requests(formula) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'Library/Homebrew/dev-cmd/bump-formula-pr.rb', line 80

def fetch_pull_requests(formula)
  GitHub.issues_for_formula(formula.name, tap: formula.tap).select do |pr|
    pr["html_url"].include?("/pull/") &&
      /(^|\s)#{Regexp.quote(formula.name)}(:|\s|$)/i =~ pr["title"]
  end
rescue GitHub::RateLimitExceededError => e
  opoo e.message
  []
end

.fetch_resource(r) ⇒ Object



77
78
79
80
81
82
83
# File 'Library/Homebrew/cmd/fetch.rb', line 77

def fetch_resource(r)
  puts "Resource: #{r.name}"
  fetch_fetchable r
rescue ChecksumMismatchError => e
  retry if retry_fetch? r
  opoo "Resource #{r.name} reports different #{e.hash_type}: #{e.expected}"
end

.files_changed_in_patch(patchfile, tap) ⇒ Object

List files changed by a patch, partitioned in to those that are (probably) formula definitions, and those which aren't. Only applies to patches on Homebrew core or taps, based simply on relative pathnames of affected files.



345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'Library/Homebrew/dev-cmd/pull.rb', line 345

def files_changed_in_patch(patchfile, tap)
  files = []
  formulae = []
  others = []
  File.foreach(patchfile) do |line|
    files << $1 if line =~ %r{^\+\+\+ b/(.*)}
  end
  files.each do |file|
    if tap && tap.formula_file?(file)
      formula_name = File.basename(file, ".rb")
      formulae << formula_name unless formulae.include?(formula_name)
    else
      others << file
    end
  end
  { files: files, formulae: formulae, others: others }
end

.filtered_listObject



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
# File 'Library/Homebrew/cmd/list.rb', line 107

def filtered_list
  names = if ARGV.named.empty?
    Formula.racks
  else
    racks = ARGV.named.map { |n| Formulary.to_rack(n) }
    racks.select do |rack|
      Homebrew.failed = true unless rack.exist?
      rack.exist?
    end
  end
  if ARGV.include? "--pinned"
    pinned_versions = {}
    names.each do |d|
      keg_pin = (HOMEBREW_PINNED_KEGS/d.basename.to_s)
      if keg_pin.exist? || keg_pin.symlink?
        pinned_versions[d] = keg_pin.readlink.basename.to_s
      end
    end
    pinned_versions.each do |d, version|
      puts d.basename.to_s.concat(ARGV.include?("--versions") ? " #{version}" : "")
    end
  else # --versions without --pinned
    names.each do |d|
      versions = d.subdirs.map { |pn| pn.basename.to_s }
      next if ARGV.include?("--multiple") && versions.length < 2
      puts "#{d.basename} #{versions*" "}"
    end
  end
end

.find_internal_commands(directory) ⇒ Object



53
54
55
56
57
# File 'Library/Homebrew/cmd/commands.rb', line 53

def find_internal_commands(directory)
  directory.children.each_with_object([]) do |f, cmds|
    cmds << f.basename.to_s.sub(/\.(?:rb|sh)$/, "") if f.file?
  end
end

.force_utf8!(str) ⇒ Object



256
257
258
# File 'Library/Homebrew/dev-cmd/pull.rb', line 256

def force_utf8!(str)
  str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
end

.formulaObject



9
10
11
12
# File 'Library/Homebrew/dev-cmd/formula.rb', line 9

def formula
  raise FormulaUnspecifiedError if ARGV.named.empty?
  ARGV.resolved_formulae.each { |f| puts f.path }
end

.formula_version(formula, spec, contents = nil) ⇒ Object



70
71
72
73
74
75
76
77
78
# File 'Library/Homebrew/dev-cmd/bump-formula-pr.rb', line 70

def formula_version(formula, spec, contents = nil)
  name = formula.name
  path = formula.path
  if contents
    Formulary.from_contents(name, path, contents, spec).version
  else
    Formulary::FormulaLoader.new(name, path).get_formula(spec).version
  end
end

.full_clone?Boolean



63
64
65
# File 'Library/Homebrew/cmd/tap.rb', line 63

def full_clone?
  ARGV.include?("--full") || ARGV.homebrew_developer?
end

.gist_logsObject



124
125
126
127
128
# File 'Library/Homebrew/cmd/gist-logs.rb', line 124

def gist_logs
  raise FormulaUnspecifiedError if ARGV.resolved_formulae.length != 1

  gistify_logs(ARGV.resolved_formulae.first)
end

.gistify_logs(f) ⇒ Object



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
# File 'Library/Homebrew/cmd/gist-logs.rb', line 20

def gistify_logs(f)
  files = load_logs(f.logs)
  build_time = f.logs.ctime
  timestamp = build_time.strftime("%Y-%m-%d_%H-%M-%S")

  s = StringIO.new
  SystemConfig.dump_verbose_config s
  # Dummy summary file, asciibetically first, to control display title of gist
  files["# #{f.name} - #{timestamp}.txt"] = { content: brief_build_info(f) }
  files["00.config.out"] = { content: s.string }
  files["00.doctor.out"] = { content: `brew doctor 2>&1` }
  unless f.core_formula?
    tap = "Formula: \#{f.name}\nTap: \#{f.tap}\nPath: \#{f.path}\n".undent
    files["00.tap.out"] = { content: tap }
  end

  # Description formatted to work well as page title when viewing gist
  if f.core_formula?
    descr = "#{f.name} on #{OS_VERSION} - Homebrew build logs"
  else
    descr = "#{f.name} (#{f.full_name}) on #{OS_VERSION} - Homebrew build logs"
  end
  url = create_gist(files, descr)

  if ARGV.include?("--new-issue") || ARGV.switch?("n")
    if GitHub.api_credentials_type == :none
      puts "You can create a new personal access token:\n\#{GitHub::ALL_SCOPES_URL}\nand then set the new HOMEBREW_GITHUB_API_TOKEN as the authentication method.\n\n".undent
      login!
    end

    url = create_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url)
  end

  puts url if url
end

.git_log(cd_dir, path = nil, tap = nil) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'Library/Homebrew/cmd/log.rb', line 20

def git_log(cd_dir, path = nil, tap = nil)
  cd cd_dir
  repo = Utils.popen_read("git rev-parse --show-toplevel").chomp
  if tap
    name = tap.to_s
    git_cd = "$(brew --repo #{tap})"
  elsif cd_dir == HOMEBREW_REPOSITORY
    name = "Homebrew/brew"
    git_cd = "$(brew --repo)"
  else
    name, git_cd = cd_dir
  end

  if File.exist? "#{repo}/.git/shallow"
    opoo "\#{name} is a shallow clone so only partial output will be shown.\nTo get a full clone run:\ngit -C \"\#{git_cd}\" fetch --unshallow\n".undent
  end
  args = ARGV.options_only
  args += ["--follow", "--", path] unless path.nil?
  exec "git", "log", *args
end

.github_info(f) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
# File 'Library/Homebrew/cmd/info.rb', line 88

def github_info(f)
  if f.tap
    if remote = f.tap.remote
      path = f.path.relative_path_from(f.tap.path)
      github_remote_path(remote, path)
    else
      f.path
    end
  else
    f.path
  end
end

.github_remote_path(remote, path) ⇒ Object



80
81
82
83
84
85
86
# File 'Library/Homebrew/cmd/info.rb', line 80

def github_remote_path(remote, path)
  if remote =~ %r{^(?:https?://|git(?:@|://))github\.com[:/](.+)/(.+?)(?:\.git)?$}
    "https://github.com/#{$1}/#{$2}/blob/master/#{path}"
  else
    "#{remote}/#{path}"
  end
end

.handle_unsatisfied_dependents(kegs_by_rack) ⇒ Object



79
80
81
82
83
84
85
86
87
# File 'Library/Homebrew/cmd/uninstall.rb', line 79

def handle_unsatisfied_dependents(kegs_by_rack)
  return if ARGV.include?("--ignore-dependencies")

  all_kegs = kegs_by_rack.values.flatten(1)
  check_for_dependents all_kegs
rescue MethodDeprecatedError
  # Silently ignore deprecations when uninstalling.
  nil
end

.help(cmd = nil, flags = {}) ⇒ Object



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
# File 'Library/Homebrew/cmd/help.rb', line 39

def help(cmd = nil, flags = {})
  # Resolve command aliases and find file containing the implementation.
  if cmd
    cmd = HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd)
    path = Commands.path(cmd)
    path ||= which("brew-#{cmd}")
    path ||= which("brew-#{cmd}.rb")
  end

  # Display command-specific (or generic) help in response to `UsageError`.
  if (error_message = flags[:usage_error])
    $stderr.puts path ? command_help(path) : HOMEBREW_HELP
    $stderr.puts
    onoe error_message
    exit 1
  end

  # Handle `brew` (no arguments).
  if flags[:empty_argv]
    $stderr.puts HOMEBREW_HELP
    exit 1
  end

  # Handle `brew (-h|--help|--usage|-?|help)` (no other arguments).
  if cmd.nil?
    puts HOMEBREW_HELP
    exit 0
  end

  # Resume execution in `brew.rb` for unknown commands.
  return if path.nil?

  # Display help for internal command (or generic help if undocumented).
  puts command_help(path)
  exit 0
end

.homeObject



10
11
12
13
14
15
16
# File 'Library/Homebrew/cmd/home.rb', line 10

def home
  if ARGV.named.empty?
    exec_browser HOMEBREW_WWW
  else
    exec_browser(*ARGV.formulae.map(&:homepage))
  end
end

.infoObject



30
31
32
33
34
35
36
37
38
39
40
# File 'Library/Homebrew/cmd/info.rb', line 30

def info
  # eventually we'll solidify an API, but we'll keep old versions
  # awhile around for compatibility
  if ARGV.json == "v1"
    print_json
  elsif ARGV.flag? "--github"
    exec_browser(*ARGV.formulae.map { |f| github_info(f) })
  else
    print_info
  end
end

.info_formula(f) ⇒ Object



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
157
158
159
160
161
162
163
164
165
166
# File 'Library/Homebrew/cmd/info.rb', line 101

def info_formula(f)
  specs = []

  if stable = f.stable
    s = "stable #{stable.version}"
    s += " (bottled)" if stable.bottled?
    specs << s
  end

  if devel = f.devel
    s = "devel #{devel.version}"
    s += " (bottled)" if devel.bottled?
    specs << s
  end

  specs << "HEAD" if f.head

  attrs = []
  attrs << "pinned at #{f.pinned_version}" if f.pinned?
  attrs << "keg-only" if f.keg_only?

  puts "#{f.full_name}: #{specs * ", "}#{" [#{attrs * ", "}]" unless attrs.empty?}"
  puts f.desc if f.desc
  puts Formatter.url(f.homepage) if f.homepage

  conflicts = f.conflicts.map(&:name).sort!
  puts "Conflicts with: #{conflicts*", "}" unless conflicts.empty?

  kegs = f.installed_kegs.sort_by(&:version)
  if kegs.empty?
    puts "Not installed"
  else
    kegs.each do |keg|
      puts "#{keg} (#{keg.abv})#{" *" if keg.linked?}"
      tab = Tab.for_keg(keg).to_s
      puts "  #{tab}" unless tab.empty?
    end
  end

  puts "From: #{Formatter.url(github_info(f))}"

  unless f.deps.empty?
    ohai "Dependencies"
    %w[build required recommended optional].map do |type|
      deps = f.deps.send(type).uniq
      puts "#{type.capitalize}: #{decorate_dependencies deps}" unless deps.empty?
    end
  end

  unless f.requirements.to_a.empty?
    ohai "Requirements"
    %w[build required recommended optional].map do |type|
      reqs = f.requirements.select(&:"#{type}?")
      next if reqs.to_a.empty?
      puts "#{type.capitalize}: #{decorate_requirements(reqs)}"
    end
  end

  unless f.options.empty?
    ohai "Options"
    Homebrew.dump_options_for_formula f
  end

  c = Caveats.new(f)
  ohai "Caveats", c.caveats unless c.empty?
end

.inject_dump_stats!(the_module, pattern) ⇒ Object



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'Library/Homebrew/utils.rb', line 227

def inject_dump_stats!(the_module, pattern)
  @injected_dump_stat_modules[the_module] ||= []
  injected_methods = @injected_dump_stat_modules[the_module]
  the_module.module_eval do
    instance_methods.grep(pattern).each do |name|
      next if injected_methods.include? name
      method = instance_method(name)
      define_method(name) do |*args, &block|
        begin
          time = Time.now
          method.bind(self).call(*args, &block)
        ensure
          $times[name] ||= 0
          $times[name] += Time.now - time
        end
      end
    end
  end

  return unless $times.nil?
  $times = {}
  at_exit do
    col_width = [$times.keys.map(&:size).max + 2, 15].max
    $times.sort_by { |_k, v| v }.each do |method, time|
      puts format("%-*s %0.4f sec", col_width, "#{method}:", time)
    end
  end
end

.inreplace_pairs(path, replacement_pairs) ⇒ Object



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
# File 'Library/Homebrew/dev-cmd/bump-formula-pr.rb', line 42

def inreplace_pairs(path, replacement_pairs)
  if ARGV.dry_run?
    contents = path.open("r") { |f| Formulary.ensure_utf8_encoding(f).read }
    contents.extend(StringInreplaceExtension)
    replacement_pairs.each do |old, new|
      unless ARGV.flag?("--quiet")
        ohai "replace #{old.inspect} with #{new.inspect}"
      end
      contents.gsub!(old, new)
    end
    unless contents.errors.empty?
      raise Utils::InreplaceError, path => contents.errors
    end
    path.atomic_write(contents) if ARGV.include?("--write")
    contents
  else
    Utils::Inreplace.inreplace(path) do |s|
      replacement_pairs.each do |old, new|
        unless ARGV.flag?("--quiet")
          ohai "replace #{old.inspect} with #{new.inspect}"
        end
        s.gsub!(old, new)
      end
    end
    path.open("r") { |f| Formulary.ensure_utf8_encoding(f).read }
  end
end

.installObject



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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'Library/Homebrew/cmd/install.rb', line 69

def install
  raise FormulaUnspecifiedError if ARGV.named.empty?

  if ARGV.include? "--head"
    raise "Specify `--HEAD` in uppercase to build from trunk."
  end

  unless ARGV.force?
    ARGV.named.each do |name|
      next if File.exist?(name)
      if name !~ HOMEBREW_TAP_FORMULA_REGEX && name !~ HOMEBREW_CASK_TAP_CASK_REGEX
        next
      end
      tap = Tap.fetch($1, $2)
      tap.install unless tap.installed?
    end
  end

  begin
    formulae = []

    unless ARGV.casks.empty?
      args = []
      args << "--force" if ARGV.force?
      args << "--debug" if ARGV.debug?
      args << "--verbose" if ARGV.verbose?

      ARGV.casks.each do |c|
        cmd = "brew", "cask", "install", c, *args
        ohai cmd.join " "
        system(*cmd)
      end
    end

    # if the user's flags will prevent bottle only-installations when no
    # developer tools are available, we need to stop them early on
    FormulaInstaller.prevent_build_flags unless DevelopmentTools.installed?

    ARGV.formulae.each do |f|
      # head-only without --HEAD is an error
      if !ARGV.build_head? && f.stable.nil? && f.devel.nil?
        raise "\#{f.full_name} is a head-only formula\nInstall with `brew install --HEAD \#{f.full_name}`\n".undent
      end

      # devel-only without --devel is an error
      if !ARGV.build_devel? && f.stable.nil? && f.head.nil?
        raise "\#{f.full_name} is a devel-only formula\nInstall with `brew install --devel \#{f.full_name}`\n".undent
      end

      if ARGV.build_stable? && f.stable.nil?
        raise "#{f.full_name} has no stable download, please choose --devel or --HEAD"
      end

      # --HEAD, fail with no head defined
      if ARGV.build_head? && f.head.nil?
        raise "No head is defined for #{f.full_name}"
      end

      # --devel, fail with no devel defined
      if ARGV.build_devel? && f.devel.nil?
        raise "No devel block is defined for #{f.full_name}"
      end

      installed_head_version = f.latest_head_version
      new_head_installed = installed_head_version &&
                           !f.head_version_outdated?(installed_head_version, fetch_head: ARGV.fetch_head?)
      prefix_installed = f.prefix.exist? && !f.prefix.children.empty?

      if f.keg_only? && f.any_version_installed? && f.optlinked? && !ARGV.force?
        # keg-only install is only possible when no other version is
        # linked to opt, because installing without any warnings can break
        # dependencies. Therefore before performing other checks we need to be
        # sure --force flag is passed.
        opoo "#{f.full_name} is a keg-only and another version is linked to opt."
        puts "Use `brew install --force` if you want to install this version"
      elsif (ARGV.build_head? && new_head_installed) || prefix_installed
        # After we're sure that --force flag is passed for linked to opt
        # keg-only we need to be sure that the version we're attempting to
        # install is not already installed.

        installed_version = if ARGV.build_head?
          f.latest_head_version
        else
          f.pkg_version
        end

        msg = "#{f.full_name}-#{installed_version} already installed"
        linked_not_equals_installed = f.linked_version != installed_version
        if f.linked? && linked_not_equals_installed
          msg << ", however linked version is #{f.linked_version}"
          opoo msg
          puts "You can use `brew switch #{f} #{installed_version}` to link this version."
        elsif !f.linked? || f.keg_only?
          msg << ", it's just not linked."
          opoo msg
        else
          opoo msg
        end
      elsif !f.any_version_installed? && old_formula = f.old_installed_formulae.first
        msg = "#{old_formula.full_name}-#{old_formula.installed_version} already installed"
        if !old_formula.linked? && !old_formula.keg_only?
          msg << ", it's just not linked."
        end
        opoo msg
      elsif f.migration_needed? && !ARGV.force?
        # Check if the formula we try to install is the same as installed
        # but not migrated one. If --force passed then install anyway.
        opoo "#{f.oldname} already installed, it's just not migrated"
        puts "You can migrate formula with `brew migrate #{f}`"
        puts "Or you can force install it with `brew install #{f} --force`"
      else
        # If none of the above is true and the formula is linked, then
        # FormulaInstaller will handle this case.
        formulae << f
      end

      # Even if we don't install this formula mark it as no longer just
      # installed as a dependency.
      next unless f.opt_prefix.directory?
      keg = Keg.new(f.opt_prefix.resolved_path)
      tab = Tab.for_keg(keg)
      tab.installed_on_request = true
      tab.write
    end

    perform_preinstall_checks

    formulae.each { |f| install_formula(f) }
  rescue FormulaClassUnavailableError => e
    # Need to rescue before `FormulaUnavailableError` (superclass of this)
    # is handled, as searching for a formula doesn't make sense here (the
    # formula was found, but there's a problem with its implementation).
    ofail e.message
  rescue FormulaUnavailableError => e
    if e.name == "updog"
      ofail "What's updog?"
      return
    end

    ofail e.message
    if (reason = Homebrew::MissingFormula.reason(e.name))
      $stderr.puts reason
      return
    end

    query = query_regexp(e.name)

    ohai "Searching for similarly named formulae..."
    formulae_search_results = search_formulae(query)
    case formulae_search_results.length
    when 0
      ofail "No similarly named formulae found."
    when 1
      puts "This similarly named formula was found:"
      puts formulae_search_results
      puts "To install it, run:\n  brew install #{formulae_search_results.first}"
    else
      puts "These similarly named formulae were found:"
      puts Formatter.columns(formulae_search_results)
      puts "To install one of them, run (for example):\n  brew install #{formulae_search_results.first}"
    end

    ohai "Searching taps..."
    taps_search_results = search_taps(query)
    case taps_search_results.length
    when 0
      ofail "No formulae found in taps."
    when 1
      puts "This formula was found in a tap:"
      puts taps_search_results
      puts "To install it, run:\n  brew install #{taps_search_results.first}"
    else
      puts "These formulae were found in taps:"
      puts Formatter.columns(taps_search_results)
      puts "To install one of them, run (for example):\n  brew install #{taps_search_results.first}"
    end
  end
end

.install_core_tap_if_necessaryObject



123
124
125
126
127
128
129
130
131
# File 'Library/Homebrew/cmd/update-report.rb', line 123

def install_core_tap_if_necessary
  return if ENV["HOMEBREW_UPDATE_TEST"]
  core_tap = CoreTap.instance
  return if core_tap.installed?
  CoreTap.ensure_installed! quiet: false
  revision = core_tap.git_head
  ENV["HOMEBREW_UPDATE_BEFORE_HOMEBREW_HOMEBREW_CORE"] = revision
  ENV["HOMEBREW_UPDATE_AFTER_HOMEBREW_HOMEBREW_CORE"] = revision
end

.install_formula(f) ⇒ Object



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'Library/Homebrew/cmd/install.rb', line 295

def install_formula(f)
  f.print_tap_action
  build_options = f.build

  fi = FormulaInstaller.new(f)
  fi.options              = build_options.used_options
  fi.invalid_option_names = build_options.invalid_option_names
  fi.ignore_deps          = ARGV.ignore_deps?
  fi.only_deps            = ARGV.only_deps?
  fi.build_bottle         = ARGV.build_bottle?
  fi.build_from_source    = ARGV.build_from_source? || ARGV.build_all_from_source?
  fi.force_bottle         = ARGV.force_bottle?
  fi.interactive          = ARGV.interactive?
  fi.git                  = ARGV.git?
  fi.verbose              = ARGV.verbose?
  fi.quieter              = ARGV.quieter?
  fi.debug                = ARGV.debug?
  fi.prelude
  fi.install
  fi.finish
rescue FormulaInstallationAlreadyAttemptedError
  # We already attempted to install f as part of the dependency tree of
  # another formula. In that case, don't generate an error, just move on.
rescue CannotInstallFormulaError => e
  ofail e.message
end

.install_gem_setup_path!(name, version = nil, executable = name) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'Library/Homebrew/utils.rb', line 182

def install_gem_setup_path!(name, version = nil, executable = name)
  # Respect user's preferences for where gems should be installed.
  ENV["GEM_HOME"] = ENV["GEM_OLD_HOME"].to_s
  ENV["GEM_HOME"] = Gem.user_dir if ENV["GEM_HOME"].empty?
  ENV["GEM_PATH"] = ENV["GEM_OLD_PATH"] unless ENV["GEM_OLD_PATH"].to_s.empty?

  # Make rubygems notice env changes.
  Gem.clear_paths
  Gem::Specification.reset

  # Add Gem binary directory and (if missing) Ruby binary directory to PATH.
  path = ENV["PATH"].split(File::PATH_SEPARATOR)
  path.unshift(RUBY_BIN) if which("ruby") != RUBY_PATH
  path.unshift(Gem.bindir)
  ENV["PATH"] = path.join(File::PATH_SEPARATOR)

  if Gem::Specification.find_all_by_name(name, version).empty?
    ohai "Installing or updating '#{name}' gem"
    install_args = %W[--no-ri --no-rdoc #{name}]
    install_args << "--version" << version if version

    # Do `gem install [...]` without having to spawn a separate process or
    # having to find the right `gem` binary for the running Ruby interpreter.
    require "rubygems/commands/install_command"
    install_cmd = Gem::Commands::InstallCommand.new
    install_cmd.handle_options(install_args)
    exit_code = 1 # Should not matter as `install_cmd.execute` always throws.
    begin
      install_cmd.execute
    rescue Gem::SystemExitException => e
      exit_code = e.exit_code
    end
    odie "Failed to install/update the '#{name}' gem." if exit_code.nonzero?
  end

  return if which(executable)
  odie "The '\#{name}' gem is installed but couldn't find '\#{executable}' in the PATH:\n\#{ENV[\"PATH\"]}\n".undent
end

.install_tap(user, repo, clone_target = nil) ⇒ Object

Deprecated.

this method will be removed in the future, if no external commands use it.



68
69
70
71
72
73
74
75
76
77
78
# File 'Library/Homebrew/cmd/tap.rb', line 68

def install_tap(user, repo, clone_target = nil)
  opoo "Homebrew.install_tap is deprecated, use Tap#install."
  tap = Tap.fetch(user, repo)
  begin
    tap.install(clone_target: clone_target, full_clone: full_clone?)
  rescue TapAlreadyTappedError
    false
  else
    true
  end
end

.internal_commandsObject



35
36
37
# File 'Library/Homebrew/cmd/commands.rb', line 35

def internal_commands
  find_internal_commands HOMEBREW_LIBRARY_PATH/"cmd"
end

.internal_developer_commandsObject



39
40
41
# File 'Library/Homebrew/cmd/commands.rb', line 39

def internal_developer_commands
  find_internal_commands HOMEBREW_LIBRARY_PATH/"dev-cmd"
end

.irbObject



30
31
32
33
34
35
36
37
38
39
40
41
# File 'Library/Homebrew/cmd/irb.rb', line 30

def irb
  if ARGV.include? "--examples"
    puts "'v8'.f # => instance of the v8 formula"
    puts ":hub.f.installed?"
    puts ":lua.f.methods - 1.methods"
    puts ":mpd.f.recursive_dependencies.reject(&:installed?)"
  else
    ohai "Interactive Homebrew Shell"
    puts "Example commands available with: brew irb --examples"
    IRB.start
  end
end

.keg_contain?(string, keg, ignores) ⇒ Boolean



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
# File 'Library/Homebrew/dev-cmd/bottle.rb', line 67

def keg_contain?(string, keg, ignores)
  @put_string_exists_header, @put_filenames = nil

  print_filename = lambda do |str, filename|
    unless @put_string_exists_header
      opoo "String '#{str}' still exists in these files:"
      @put_string_exists_header = true
    end

    @put_filenames ||= []

    return if @put_filenames.include? filename

    puts Formatter.error(filename.to_s)
    @put_filenames << filename
  end

  result = false

  keg.each_unique_file_matching(string) do |file|
    # skip document file.
    next if Metafiles::EXTENSIONS.include? file.extname

    linked_libraries = Keg.file_linked_libraries(file, string)
    result ||= !linked_libraries.empty?

    if ARGV.verbose?
      print_filename.call(string, file) unless linked_libraries.empty?
      linked_libraries.each do |lib|
        puts " #{Tty.bold}-->#{Tty.reset} links to #{lib}"
      end
    end

    text_matches = []

    # Use strings to search through the file for each string
    Utils.popen_read("strings", "-t", "x", "-", file.to_s) do |io|
      until io.eof?
        str = io.readline.chomp
        next if ignores.any? { |i| i =~ str }
        next unless str.include? string
        offset, match = str.split(" ", 2)
        next if linked_libraries.include? match # Don't bother reporting a string if it was found by otool

        result = true
        text_matches << [match, offset]
      end
    end

    next unless ARGV.verbose? && !text_matches.empty?
    print_filename.call(string, file)
    text_matches.first(MAXIMUM_STRING_MATCHES).each do |match, offset|
      puts " #{Tty.bold}-->#{Tty.reset} match '#{match}' at offset #{Tty.bold}0x#{offset}#{Tty.reset}"
    end

    if text_matches.size > MAXIMUM_STRING_MATCHES
      puts "Only the first #{MAXIMUM_STRING_MATCHES} matches were output"
    end
  end

  keg_contain_absolute_symlink_starting_with?(string, keg) || result
end


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'Library/Homebrew/dev-cmd/bottle.rb', line 130

def keg_contain_absolute_symlink_starting_with?(string, keg)
  absolute_symlinks_start_with_string = []
  keg.find do |pn|
    next unless pn.symlink? && (link = pn.readlink).absolute?
    absolute_symlinks_start_with_string << pn if link.to_s.start_with?(string)
  end

  if ARGV.verbose?
    unless absolute_symlinks_start_with_string.empty?
      opoo "Absolute symlink starting with #{string}:"
      absolute_symlinks_start_with_string.each do |pn|
        puts "  #{pn} -> #{pn.resolved_path}"
      end
    end
  end

  !absolute_symlinks_start_with_string.empty?
end

.keg_only?(rack) ⇒ Boolean



93
94
95
96
97
# File 'Library/Homebrew/cmd/link.rb', line 93

def keg_only?(rack)
  Formulary.from_rack(rack).keg_only?
rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
  false
end

.leavesObject



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'Library/Homebrew/cmd/leaves.rb', line 11

def leaves
  installed = Formula.installed
  deps_of_installed = Set.new

  installed.each do |f|
    deps = []

    f.deps.each do |dep|
      if dep.optional? || dep.recommended?
        deps << dep.to_formula.full_name if f.build.with?(dep)
      else
        deps << dep.to_formula.full_name
      end
    end

    deps_of_installed.merge(deps)
  end

  installed.each do |f|
    puts f.full_name unless deps_of_installed.include? f.full_name
  end
end

.library_foldersObject



47
48
49
50
51
52
53
# File 'Library/Homebrew/dev-cmd/edit.rb', line 47

def library_folders
  Dir["#{HOMEBREW_LIBRARY}/*"].reject do |d|
    case File.basename(d)
    when "LinkedKegs", "Aliases" then true
    end
  end
end


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
# File 'Library/Homebrew/cmd/link.rb', line 20

def link
  raise KegUnspecifiedError if ARGV.named.empty?

  mode = OpenStruct.new

  mode.overwrite = true if ARGV.include? "--overwrite"
  mode.dry_run = true if ARGV.dry_run?

  ARGV.kegs.each do |keg|
    keg_only = keg_only?(keg.rack)
    if HOMEBREW_PREFIX.to_s == "/usr/local" && keg_only &&
       keg.name.start_with?("openssl", "libressl")
      opoo "Refusing to link: \#{keg.name}\nLinking keg-only \#{keg.name} means you may end up linking against the insecure,\ndeprecated system OpenSSL while using the headers from Homebrew's \#{keg.name}.\nInstead, pass the full include/library paths to your compiler e.g.:\n-I\#{HOMEBREW_PREFIX}/opt/\#{keg.name}/include -L\#{HOMEBREW_PREFIX}/opt/\#{keg.name}/lib\n".undent
      next
    elsif keg.linked?
      opoo "Already linked: #{keg}"
      puts "To relink: brew unlink #{keg.name} && brew link #{keg.name}"
      next
    elsif keg_only && !ARGV.force?
      opoo "#{keg.name} is keg-only and must be linked with --force"
      puts "Note that doing so can interfere with building software."
      puts_keg_only_path_message(keg)
      next
    elsif mode.dry_run && mode.overwrite
      puts "Would remove:"
      keg.link(mode)

      next
    elsif mode.dry_run
      puts "Would link:"
      keg.link(mode)
      puts_keg_only_path_message(keg) if keg_only

      next
    end

    keg.lock do
      print "Linking #{keg}... "
      puts if ARGV.verbose?

      begin
        n = keg.link(mode)
      rescue Keg::LinkError
        puts
        raise
      else
        puts "#{n} symlinks created"
      end

      if keg_only && !ARGV.homebrew_developer?
        puts_keg_only_path_message(keg)
      end
    end
  end
end


305
306
307
308
309
310
311
312
313
314
315
# File 'Library/Homebrew/cmd/update-report.rb', line 305

def link_completions_manpages_and_docs(repository = HOMEBREW_REPOSITORY)
  command = "brew update"
  Utils::Link.link_completions(repository, command)
  Utils::Link.link_manpages(repository, command)
  Utils::Link.link_docs(repository, command)
rescue => e
  ofail "Failed to link all completions, docs and manpages:\n\#{e}\n".undent
end

.linkageObject



18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'Library/Homebrew/dev-cmd/linkage.rb', line 18

def linkage
  ARGV.kegs.each do |keg|
    ohai "Checking #{keg.name} linkage" if ARGV.kegs.size > 1
    result = LinkageChecker.new(keg)
    if ARGV.include?("--test")
      result.display_test_output
      Homebrew.failed = true if result.broken_dylibs?
    elsif ARGV.include?("--reverse")
      result.display_reverse_output
    else
      result.display_normal_output
    end
  end
end

.linkappsObject



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
# File 'Library/Homebrew/cmd/linkapps.rb', line 21

def linkapps
  opoo "`brew linkapps` has been deprecated and will eventually be removed!\n\nUnfortunately `brew linkapps` cannot behave nicely with e.g. Spotlight using\neither aliases or symlinks and Homebrew formulae do not build \"proper\" `.app`\nbundles that can be relocated. Instead, please consider using `brew cask` and\nmigrate formulae using `.app`s to casks.\n".undent

  target_dir = linkapps_target(local: ARGV.include?("--local"))

  unless target_dir.directory?
    opoo "#{target_dir} does not exist, stopping."
    puts "Run `mkdir #{target_dir}` first."
    exit 1
  end

  if ARGV.named.empty?
    kegs = Formula.racks.map do |rack|
      keg = rack.subdirs.map { |d| Keg.new(d) }
      next if keg.empty?
      keg.detect(&:linked?) || keg.max_by(&:version)
    end
  else
    kegs = ARGV.kegs
  end

  link_count = 0
  kegs.each do |keg|
    keg.apps.each do |app|
      puts "Linking: #{app}"
      target_app = target_dir/app.basename

      if target_app.exist? && !target_app.symlink?
        onoe "#{target_app} already exists, skipping."
        next
      end

      # We prefer system `ln` over `FileUtils.ln_sf` because the latter seems
      # to have weird failure conditions (that were observed in the past).
      system "ln", "-sf", app, target_dir
      link_count += 1
    end
  end

  if link_count.zero?
    puts "No apps linked to #{target_dir}" if ARGV.verbose?
  else
    puts "Linked #{Formatter.pluralize(link_count, "app")} to #{target_dir}"
  end
end

.linkapps_target(opts = {}) ⇒ Object



74
75
76
77
# File 'Library/Homebrew/cmd/linkapps.rb', line 74

def linkapps_target(opts = {})
  local = opts.fetch(:local, false)
  Pathname.new(local ? "~/Applications" : "/Applications").expand_path
end

.listObject



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
# File 'Library/Homebrew/cmd/list.rb', line 27

def list
  # Use of exec means we don't explicitly exit
  list_unbrewed if ARGV.flag? "--unbrewed"

  # Unbrewed uses the PREFIX, which will exist
  # Things below use the CELLAR, which doesn't until the first formula is installed.
  unless HOMEBREW_CELLAR.exist?
    raise NoSuchKegError, ARGV.named.first unless ARGV.named.empty?
    return
  end

  if ARGV.include?("--pinned") || ARGV.include?("--versions")
    filtered_list
  elsif ARGV.named.empty?
    if ARGV.include? "--full-name"
      full_names = Formula.installed.map(&:full_name).sort do |a, b|
        if a.include?("/") && !b.include?("/")
          1
        elsif !a.include?("/") && b.include?("/")
          -1
        else
          a <=> b
        end
      end
      return if full_names.empty?
      puts Formatter.columns(full_names)
    else
      ENV["CLICOLOR"] = nil
      exec "ls", *ARGV.options_only << HOMEBREW_CELLAR
    end
  elsif ARGV.verbose? || !$stdout.tty?
    exec "find", *ARGV.kegs.map(&:to_s) + %w[-not -type d -print]
  else
    ARGV.kegs.each { |keg| PrettyListing.new keg }
  end
end

.list_unbrewedObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'Library/Homebrew/cmd/list.rb', line 87

def list_unbrewed
  dirs  = HOMEBREW_PREFIX.subdirs.map { |dir| dir.basename.to_s }
  dirs -= %w[Library Cellar .git]

  # Exclude cache, logs, and repository, if they are located under the prefix.
  [HOMEBREW_CACHE, HOMEBREW_LOGS, HOMEBREW_REPOSITORY].each do |dir|
    dirs.delete dir.relative_path_from(HOMEBREW_PREFIX).to_s
  end
  dirs.delete "etc"
  dirs.delete "var"

  args = dirs + %w[-type f (]
  args.concat UNBREWED_EXCLUDE_FILES.flat_map { |f| %W[! -name #{f}] }
  args.concat UNBREWED_EXCLUDE_PATHS.flat_map { |d| %W[! -path #{d}] }
  args.concat %w[)]

  cd HOMEBREW_PREFIX
  exec "find", *args
end

.load_logs(dir) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'Library/Homebrew/cmd/gist-logs.rb', line 95

def load_logs(dir)
  logs = {}
  if dir.exist?
    dir.children.sort.each do |file|
      contents = file.size? ? file.read : "empty log"
      # small enough to avoid GitHub "unicorn" page-load-timeout errors
      max_file_size = 1_000_000
      contents = truncate_text_to_approximate_size(contents, max_file_size, front_weight: 0.2)
      logs[file.basename.to_s] = { content: contents }
    end
  end
  raise "No logs." if logs.empty?
  logs
end

.logObject



10
11
12
13
14
15
16
17
18
# File 'Library/Homebrew/cmd/log.rb', line 10

def log
  if ARGV.named.empty?
    git_log HOMEBREW_REPOSITORY
  else
    path = Formulary.path(ARGV.named.first)
    tap = Tap.from_path(path)
    git_log path.dirname, path, tap
  end
end

.login!Object



87
88
89
90
91
92
93
# File 'Library/Homebrew/cmd/gist-logs.rb', line 87

def login!
  print "GitHub User: "
  ENV["HOMEBREW_GITHUB_API_USERNAME"] = $stdin.gets.chomp
  print "Password: "
  ENV["HOMEBREW_GITHUB_API_PASSWORD"] = noecho_gets.chomp
  puts
end

.manObject

Raises:



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'Library/Homebrew/dev-cmd/man.rb', line 21

def man
  raise UsageError unless ARGV.named.empty?

  if ARGV.flag? "--link"
    odie "`brew man --link` is now done automatically by `brew update`."
  end

  regenerate_man_pages

  if system "git", "-C", HOMEBREW_REPOSITORY, "diff", "--quiet", "docs/Manpage.md", "manpages"
    puts "No changes to manpage output detected."
  elsif ARGV.include?("--fail-if-changed")
    Homebrew.failed = true
  end
end

.mergeObject



372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
# File 'Library/Homebrew/dev-cmd/bottle.rb', line 372

def merge
  write = ARGV.include? "--write"

  bottles_hash = ARGV.named.reduce({}) do |hash, json_file|
    deep_merge_hashes hash, JSON.parse(IO.read(json_file))
  end

  bottles_hash.each do |formula_name, bottle_hash|
    ohai formula_name

    bottle = BottleSpecification.new
    bottle.root_url bottle_hash["bottle"]["root_url"]
    cellar = bottle_hash["bottle"]["cellar"]
    if cellar == "any" || cellar == "any_skip_relocation"
      cellar = cellar.to_sym
    end
    bottle.cellar cellar
    bottle.prefix bottle_hash["bottle"]["prefix"]
    bottle.rebuild bottle_hash["bottle"]["rebuild"]
    bottle_hash["bottle"]["tags"].each do |tag, tag_hash|
      bottle.sha256 tag_hash["sha256"] => tag.to_sym
    end

    output = bottle_output bottle

    if write
      path = Pathname.new((HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]).to_s)
      update_or_add = nil

      Utils::Inreplace.inreplace(path) do |s|
        if s.include? "bottle do"
          update_or_add = "update"
          if ARGV.include? "--keep-old"
            mismatches = []
            bottle_block_contents = s[/  bottle do(.+?)end\n/m, 1]
            bottle_block_contents.lines.each do |line|
              line = line.strip
              next if line.empty?
              key, old_value_original, _, tag = line.split " ", 4
              valid_key = %w[root_url prefix cellar rebuild sha1 sha256].include? key
              next unless valid_key

              old_value = old_value_original.to_s.delete ":'\""
              tag = tag.to_s.delete ":"

              unless tag.empty?
                if !bottle_hash["bottle"]["tags"][tag].to_s.empty?
                  mismatches << "#{key} => #{tag}"
                else
                  bottle.send(key, old_value => tag.to_sym)
                end
                next
              end

              value_original = bottle_hash["bottle"][key]
              value = value_original.to_s
              next if key == "cellar" && old_value == "any" && value == "any_skip_relocation"
              next unless old_value.empty? || value != old_value
              old_value = old_value_original.inspect
              value = value_original.inspect
              mismatches << "#{key}: old: #{old_value}, new: #{value}"
            end

            unless mismatches.empty?
              odie "--keep-old was passed but there are changes in:\n\#{mismatches.join(\"\\n\")}\n".undent
            end
            output = bottle_output bottle
          end
          puts output
          string = s.sub!(/  bottle do.+?end\n/m, output)
          odie "Bottle block update failed!" unless string
        else
          if ARGV.include? "--keep-old"
            odie "--keep-old was passed but there was no existing bottle block!"
          end
          puts output
          update_or_add = "add"
          if s.include? "stable do"
            indent = s.slice(/^( +)stable do/, 1).length
            string = s.sub!(/^ {#{indent}}stable do(.|\n)+?^ {#{indent}}end\n/m, '\0' + output + "\n")
          else
            string = s.sub!(
              /(
                (\ {2}\#[^\n]*\n)*                                             # comments
                \ {2}(                                                         # two spaces at the beginning
                  (url|head)\ ['"][\S\ ]+['"]                                  # url or head with a string
                  (
                    ,[\S\ ]*$                                                  # url may have options
                    (\n^\ {3}[\S\ ]+$)*                                        # options can be in multiple lines
                  )?|
                  (homepage|desc|sha1|sha256|version|mirror)\ ['"][\S\ ]+['"]| # specs with a string
                  revision\ \d+                                                # revision with a number
                )\n+                                                           # multiple empty lines
               )+
             /mx, '\0' + output + "\n"
            )
          end
          odie "Bottle block addition failed!" unless string
        end
      end

      unless ARGV.include? "--no-commit"
        short_name = formula_name.split("/", -1).last
        pkg_version = bottle_hash["formula"]["pkg_version"]

        path.parent.cd do
          safe_system "git", "commit", "--no-edit", "--verbose",
            "--message=#{short_name}: #{update_or_add} #{pkg_version} bottle.",
            "--", path
        end
      end
    else
      puts output
    end
  end
end

.migrateObject



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'Library/Homebrew/cmd/migrate.rb', line 13

def migrate
  raise FormulaUnspecifiedError if ARGV.named.empty?

  ARGV.resolved_formulae.each do |f|
    if f.oldname
      unless (rack = HOMEBREW_CELLAR/f.oldname).exist? && !rack.subdirs.empty?
        raise NoSuchKegError, f.oldname
      end
      raise "#{rack} is a symlink" if rack.symlink?
    end

    migrator = Migrator.new(f)
    migrator.migrate
  end
end

.migrate_legacy_cache_if_necessaryObject



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'Library/Homebrew/cmd/update-report.rb', line 133

def migrate_legacy_cache_if_necessary
  legacy_cache = Pathname.new "/Library/Caches/Homebrew"
  return if HOMEBREW_CACHE.to_s == legacy_cache.to_s
  return unless legacy_cache.directory?
  return unless legacy_cache.readable_real?

  migration_attempted_file = legacy_cache/".migration_attempted"
  return if migration_attempted_file.exist?

  return unless legacy_cache.writable_real?
  FileUtils.touch migration_attempted_file

  # Cleanup to avoid copying files unnecessarily
  ohai "Cleaning up #{legacy_cache}..."
  Cleanup.cleanup_cache legacy_cache

  # This directory could have been compromised if it's world-writable/
  # a symlink/owned by another user so don't copy files in those cases.
  world_writable = legacy_cache.stat.mode & 0777 == 0777
  return if world_writable
  return if legacy_cache.symlink?
  return if !legacy_cache.owned? && legacy_cache.lstat.uid.nonzero?

  ohai "Migrating #{legacy_cache} to #{HOMEBREW_CACHE}..."
  HOMEBREW_CACHE.mkpath
  legacy_cache.cd do
    legacy_cache.entries.each do |f|
      next if [".", "..", ".migration_attempted"].include? f.to_s
      begin
        FileUtils.cp_r f, HOMEBREW_CACHE
      rescue
        @migration_failed ||= true
      end
    end
  end

  if @migration_failed
    opoo "Failed to migrate \#{legacy_cache} to\n\#{HOMEBREW_CACHE}. Please do so manually.\n".undent
  else
    ohai "Deleting #{legacy_cache}..."
    FileUtils.rm_rf legacy_cache
    if legacy_cache.exist?
      FileUtils.touch migration_attempted_file
      opoo "Failed to delete \#{legacy_cache}.\nPlease do so manually.\n".undent
    end
  end
end

.migrate_legacy_repository_if_necessaryObject



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'Library/Homebrew/cmd/update-report.rb', line 187

def migrate_legacy_repository_if_necessary
  return unless HOMEBREW_PREFIX.to_s == "/usr/local"
  return unless HOMEBREW_REPOSITORY.to_s == "/usr/local"

  ohai "Migrating HOMEBREW_REPOSITORY (please wait)..."

  unless HOMEBREW_PREFIX.writable_real?
    ofail "\#{HOMEBREW_PREFIX} is not writable.\n\nYou should change the ownership and permissions of \#{HOMEBREW_PREFIX}\ntemporarily back to your user account so we can complete the Homebrew\nrepository migration:\nsudo chown -R $(whoami) \#{HOMEBREW_PREFIX}\n".undent
    return
  end

  new_homebrew_repository = Pathname.new "/usr/local/Homebrew"
  if new_homebrew_repository.exist?
    ofail "\#{new_homebrew_repository} already exists.\nPlease remove it manually or uninstall and reinstall Homebrew into a new\nlocation as the migration cannot be done automatically.\n".undent
    return
  end
  new_homebrew_repository.mkpath

  repo_files = HOMEBREW_REPOSITORY.cd do
    Utils.popen_read("git ls-files").lines.map(&:chomp)
  end

  unless Utils.popen_read("git status --untracked-files=all --porcelain").empty?
    HOMEBREW_REPOSITORY.cd do
      quiet_system "git", "merge", "--abort"
      quiet_system "git", "rebase", "--abort"
      quiet_system "git", "reset", "--mixed"
      safe_system "git", "-c", "user.email=brew-update@localhost",
                         "-c", "user.name=brew update",
                         "stash", "save", "--include-untracked"
    end
    stashed = true
  end

  FileUtils.cp_r "#{HOMEBREW_REPOSITORY}/.git", "#{new_homebrew_repository}/.git"
  new_homebrew_repository.cd do
    safe_system "git", "checkout", "--force", "."
    safe_system "git", "stash", "pop" if stashed
  end

  if (HOMEBREW_REPOSITORY/"Library/Locks").exist?
    FileUtils.cp_r "#{HOMEBREW_REPOSITORY}/Library/Locks", "#{new_homebrew_repository}/Library/Locks"
  end

  if (HOMEBREW_REPOSITORY/"Library/Taps").exist?
    FileUtils.cp_r "#{HOMEBREW_REPOSITORY}/Library/Taps", "#{new_homebrew_repository}/Library/Taps"
  end

  unremovable_paths = []
  extra_remove_paths = [".git", "Library/Locks", "Library/Taps",
                        "Library/Homebrew/cask", "Library/Homebrew/test"]
  (repo_files + extra_remove_paths).each do |file|
    path = Pathname.new "#{HOMEBREW_REPOSITORY}/#{file}"
    begin
      FileUtils.rm_rf path
    rescue Errno::EACCES
      unremovable_paths << path
    end
    quiet_system "rmdir", "-p", path.parent if path.parent.exist?
  end

  unless unremovable_paths.empty?
    ofail "Could not remove old HOMEBREW_REPOSITORY paths!\nPlease do this manually with:\nsudo rm -rf \#{unremovable_paths.join \" \"}\n".undent
  end

  (Keg::ALL_TOP_LEVEL_DIRECTORIES + ["Cellar"]).each do |dir|
    FileUtils.mkdir_p "#{HOMEBREW_PREFIX}/#{dir}"
  end

  src = Pathname.new("#{new_homebrew_repository}/bin/brew")
  dst = Pathname.new("#{HOMEBREW_PREFIX}/bin/brew")
  begin
    FileUtils.ln_s(src.relative_path_from(dst.parent), dst)
  rescue Errno::EACCES, Errno::ENOENT
    ofail "Could not create symlink at \#{dst}!\nPlease do this manually with:\nsudo ln -sf \#{src} \#{dst}\nsudo chown $(whoami) \#{dst}\n".undent
  end

  link_completions_manpages_and_docs(new_homebrew_repository)

  ohai "Migrated HOMEBREW_REPOSITORY to #{new_homebrew_repository}!"
  puts "Homebrew no longer needs to have ownership of /usr/local. If you wish you can\nreturn /usr/local to its default ownership with:\nsudo chown root:wheel \#{HOMEBREW_PREFIX}\n".undent
rescue => e
  ofail "\#{Tty.bold}Failed to migrate HOMEBREW_REPOSITORY to \#{new_homebrew_repository}!\#{Tty.reset}\nThe error was:\n\#{e}\nPlease try to resolve this error yourself and then run `brew update` again to\ncomplete the migration. If you need help please +1 an existing error or comment\nwith your new error in issue:\n\#{Formatter.url(\"https://github.com/Homebrew/brew/issues/987\")}\n".undent
  $stderr.puts e.backtrace
end

.mirrorObject



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
# File 'Library/Homebrew/dev-cmd/mirror.rb', line 8

def mirror
  odie "This command requires at least formula argument!" if ARGV.named.empty?

  bintray_user = ENV["BINTRAY_USER"]
  bintray_key = ENV["BINTRAY_KEY"]
  if !bintray_user || !bintray_key
    raise "Missing BINTRAY_USER or BINTRAY_KEY variables!"
  end

  ARGV.formulae.each do |f|
    bintray_package = Utils::Bottles::Bintray.package f.name
    bintray_repo_url = "https://api.bintray.com/packages/homebrew/mirror"
    package_url = "#{bintray_repo_url}/#{bintray_package}"

    unless system "curl", "--silent", "--fail", "--output", "/dev/null", package_url
      package_blob = "{\"name\": \"\#{bintray_package}\",\n\"public_download_numbers\": true,\n\"public_stats\": true}\n".undent
      curl "--silent", "--fail", "-u#{bintray_user}:#{bintray_key}",
           "-H", "Content-Type: application/json",
           "-d", package_blob, bintray_repo_url
      puts
    end

    download = f.fetch
    f.verify_download_integrity(download)
    filename = download.basename
    destination_url = "https://dl.bintray.com/homebrew/mirror/#{filename}"

    ohai "Uploading to #{destination_url}"
    content_url = "https://api.bintray.com/content/homebrew/mirror"
    content_url += "/#{bintray_package}/#{f.pkg_version}/#{filename}"
    content_url += "?publish=1"
    curl "--silent", "--fail", "-u#{bintray_user}:#{bintray_key}",
         "-T", download, content_url
    puts
    ohai "Mirrored #{filename}!"
  end
end

.missingObject



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'Library/Homebrew/cmd/missing.rb', line 15

def missing
  return unless HOMEBREW_CELLAR.exist?

  ff = if ARGV.named.empty?
    Formula.installed
  else
    ARGV.resolved_formulae
  end

  ff.each do |f|
    missing = f.missing_dependencies(hide: ARGV.values("hide"))
    next if missing.empty?

    print "#{f}: " if ff.size > 1
    puts missing.join(" ")
  end
end

.noecho_getsObject

Hack for ruby < 1.9.3



79
80
81
82
83
84
85
# File 'Library/Homebrew/cmd/gist-logs.rb', line 79

def noecho_gets
  system "stty -echo"
  result = $stdin.gets
  system "stty echo"
  puts
  result
end

.optionsObject



17
18
19
20
21
22
23
24
25
26
# File 'Library/Homebrew/cmd/options.rb', line 17

def options
  if ARGV.include? "--all"
    puts_options Formula.to_a
  elsif ARGV.include? "--installed"
    puts_options Formula.installed
  else
    raise FormulaUnspecifiedError if ARGV.named.empty?
    puts_options ARGV.formulae
  end
end

.outdatedObject



26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'Library/Homebrew/cmd/outdated.rb', line 26

def outdated
  formulae = if ARGV.resolved_formulae.empty?
    Formula.installed
  else
    ARGV.resolved_formulae
  end
  if ARGV.json == "v1"
    outdated = print_outdated_json(formulae)
  else
    outdated = print_outdated(formulae)
  end
  Homebrew.failed = !ARGV.resolved_formulae.empty? && !outdated.empty?
end

.path_glob_commands(glob) ⇒ Object



48
49
50
51
52
53
54
55
56
57
# File 'Library/Homebrew/dev-cmd/man.rb', line 48

def path_glob_commands(glob)
  Pathname.glob(glob)
          .sort_by { |source_file| sort_key_for_path(source_file) }
          .map do |source_file|
    source_file.read.lines
               .grep(/^#:/)
               .map { |line| line.slice(2..-1) }
               .join
  end.reject { |s| s.strip.empty? || s.include?("@hide_from_man_page") }
end

.pbcopy(text) ⇒ Object



418
419
420
# File 'Library/Homebrew/dev-cmd/pull.rb', line 418

def pbcopy(text)
  Utils.popen_write("pbcopy") { |io| io.write text }
end

.perform_preinstall_checksObject



288
289
290
291
292
293
# File 'Library/Homebrew/cmd/install.rb', line 288

def perform_preinstall_checks
  check_ppc
  check_writable_install_location
  check_development_tools if DevelopmentTools.installed?
  check_cellar
end

.pinObject



10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'Library/Homebrew/cmd/pin.rb', line 10

def pin
  raise FormulaUnspecifiedError if ARGV.named.empty?

  ARGV.resolved_formulae.each do |f|
    if f.pinned?
      opoo "#{f.name} already pinned"
    elsif !f.pinnable?
      onoe "#{f.name} not installed"
    else
      f.pin
    end
  end
end

.postinstallObject



9
10
11
# File 'Library/Homebrew/cmd/postinstall.rb', line 9

def postinstall
  ARGV.resolved_formulae.each { |f| run_post_install(f) if f.post_install_defined? }
end


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
# File 'Library/Homebrew/cmd/info.rb', line 42

def print_info
  if ARGV.named.empty?
    if HOMEBREW_CELLAR.exist?
      count = Formula.racks.length
      puts "#{Formatter.pluralize(count, "keg")}, #{HOMEBREW_CELLAR.abv}"
    end
  else
    ARGV.named.each_with_index do |f, i|
      puts unless i.zero?
      begin
        if f.include?("/") || File.exist?(f)
          info_formula Formulary.factory(f)
        else
          info_formula Formulary.find_with_priority(f)
        end
      rescue FormulaUnavailableError => e
        ofail e.message
        # No formula with this name, try a missing formula lookup
        if (reason = Homebrew::MissingFormula.reason(f))
          $stderr.puts reason
        end
      end
    end
  end
end


68
69
70
71
72
73
74
75
76
77
78
# File 'Library/Homebrew/cmd/info.rb', line 68

def print_json
  ff = if ARGV.include? "--all"
    Formula
  elsif ARGV.include? "--installed"
    Formula.installed
  else
    ARGV.formulae
  end
  json = ff.map(&:to_hash)
  puts JSON.generate(json)
end


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
# File 'Library/Homebrew/cmd/outdated.rb', line 40

def print_outdated(formulae)
  verbose = ($stdout.tty? || ARGV.verbose?) && !ARGV.flag?("--quiet")
  fetch_head = ARGV.fetch_head?

  outdated_formulae = formulae.select { |f| f.outdated?(fetch_head: fetch_head) }

  outdated_formulae.each do |f|
    if verbose
      outdated_kegs = f.outdated_kegs(fetch_head: fetch_head)

      current_version = if f.alias_changed?
        latest = f.latest_formula
        "#{latest.name} (#{latest.pkg_version})"
      elsif f.head? && outdated_kegs.any? { |k| k.version.to_s == f.pkg_version.to_s }
        # There is a newer HEAD but the version number has not changed.
        "latest HEAD"
      else
        f.pkg_version.to_s
      end

      outdated_versions = outdated_kegs
                          .group_by { |keg| Formulary.from_keg(keg).full_name }
                          .sort_by { |full_name, _kegs| full_name }
                          .map do |full_name, kegs|
        "#{full_name} (#{kegs.map(&:version).join(", ")})"
      end.join(", ")

      puts "#{outdated_versions} < #{current_version}"
    else
      puts f.full_installed_specified_name
    end
  end
end


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'Library/Homebrew/cmd/outdated.rb', line 74

def print_outdated_json(formulae)
  json = []
  fetch_head = ARGV.fetch_head?
  outdated_formulae = formulae.select { |f| f.outdated?(fetch_head: fetch_head) }

  outdated = outdated_formulae.each do |f|
    outdated_versions = f.outdated_kegs(fetch_head: fetch_head).map(&:version)
    current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s }
      "HEAD"
    else
      f.pkg_version.to_s
    end

    json << { name: f.full_name,
              installed_versions: outdated_versions.collect(&:to_s),
              current_version: current_version }
  end
  puts JSON.generate(json)

  outdated
end


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
# File 'Library/Homebrew/cmd/tap-info.rb', line 39

def print_tap_info(taps)
  if taps.none?
    tap_count = 0
    formula_count = 0
    command_count = 0
    pinned_count = 0
    private_count = 0
    Tap.each do |tap|
      tap_count += 1
      formula_count += tap.formula_files.size
      command_count += tap.command_files.size
      pinned_count += 1 if tap.pinned?
      private_count += 1 if tap.private?
    end
    info = Formatter.pluralize(tap_count, "tap").to_s
    info += ", #{pinned_count} pinned"
    info += ", #{private_count} private"
    info += ", #{Formatter.pluralize(formula_count, "formula")}"
    info += ", #{Formatter.pluralize(command_count, "command")}"
    info += ", #{Tap::TAP_DIRECTORY.abv}" if Tap::TAP_DIRECTORY.directory?
    puts info
  else
    taps.each_with_index do |tap, i|
      puts unless i.zero?
      info = "#{tap}: "
      if tap.installed?
        info += tap.pinned? ? "pinned" : "unpinned"
        info += ", private" if tap.private?
        if (formula_count = tap.formula_files.size) > 0
          info += ", #{Formatter.pluralize(formula_count, "formula")}"
        end
        if (command_count = tap.command_files.size) > 0
          info += ", #{Formatter.pluralize(command_count, "command")}"
        end
        info += ", no formulae/commands" if (formula_count + command_count).zero?
        info += "\n#{tap.path} (#{tap.path.abv})"
        info += "\nFrom: #{tap.remote.nil? ? "N/A" : tap.remote}"
      else
        info += "Not installed"
      end
      puts info
    end
  end
end


84
85
86
# File 'Library/Homebrew/cmd/tap-info.rb', line 84

def print_tap_json(taps)
  puts JSON.generate(taps.map(&:to_hash))
end

.pruneObject



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
# File 'Library/Homebrew/cmd/prune.rb', line 17

def prune
  ObserverPathnameExtension.reset_counts!

  dirs = []

  Keg::PRUNEABLE_DIRECTORIES.each do |dir|
    next unless dir.directory?
    dir.find do |path|
      path.extend(ObserverPathnameExtension)
      if path.symlink?
        unless path.resolved_path_exists?
          if path.to_s =~ Keg::INFOFILE_RX
            path.uninstall_info unless ARGV.dry_run?
          end

          if ARGV.dry_run?
            puts "Would remove (broken link): #{path}"
          else
            path.unlink
          end
        end
      elsif path.directory? && !Keg::PRUNEABLE_DIRECTORIES.include?(path)
        dirs << path
      end
    end
  end

  dirs.reverse_each do |d|
    if ARGV.dry_run? && d.children.empty?
      puts "Would remove (empty directory): #{d}"
    else
      d.rmdir_if_possible
    end
  end

  unless ARGV.dry_run?
    if ObserverPathnameExtension.total.zero?
      puts "Nothing pruned" if ARGV.verbose?
    else
      n, d = ObserverPathnameExtension.counts
      print "Pruned #{n} symbolic links "
      print "and #{d} directories " if d > 0
      puts "from #{HOMEBREW_PREFIX}"
    end
  end

  unlinkapps_prune(dry_run: ARGV.dry_run?, quiet: true)
end

.publish_bottle_file_on_bintray(f, creds) ⇒ Object

Publishes the current bottle files for a given formula to Bintray



423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'Library/Homebrew/dev-cmd/pull.rb', line 423

def publish_bottle_file_on_bintray(f, creds)
  repo = Utils::Bottles::Bintray.repository(f.tap)
  package = Utils::Bottles::Bintray.package(f.name)
  info = FormulaInfoFromJson.lookup(f.name)
  if info.nil?
    raise "Failed publishing bottle: failed reading formula info for #{f.full_name}"
  end
  unless info.bottle_info_any
    opoo "No bottle defined in formula #{package}"
    return false
  end
  version = info.pkg_version
  ohai "Publishing on Bintray: #{package} #{version}"
  curl "-w", '\n', "--silent", "--fail",
       "-u#{creds[:user]}:#{creds[:key]}", "-X", "POST",
       "-H", "Content-Type: application/json",
       "-d", '{"publish_wait_for_secs": 0}',
       "https://api.bintray.com/content/homebrew/#{repo}/#{package}/#{version}/publish"
  true
rescue => e
  raise unless ARGV.include?("--warn-on-publish-failure")
  onoe e
  false
end

.publish_changed_formula_bottles(_tap, changed_formulae_names) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'Library/Homebrew/dev-cmd/pull.rb', line 260

def publish_changed_formula_bottles(_tap, changed_formulae_names)
  if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"]
    raise "Need to load formulae to publish them!"
  end

  published = []
  bintray_creds = { user: ENV["BINTRAY_USER"], key: ENV["BINTRAY_KEY"] }
  if bintray_creds[:user] && bintray_creds[:key]
    changed_formulae_names.each do |name|
      f = Formula[name]
      next if f.bottle_unneeded? || f.bottle_disabled?
      next unless publish_bottle_file_on_bintray(f, bintray_creds)
      published << f.full_name
    end
  else
    opoo "You must set BINTRAY_USER and BINTRAY_KEY to add or update bottles on Bintray!"
  end
  published
end

.pullObject



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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'Library/Homebrew/dev-cmd/pull.rb', line 58

def pull
  odie "You meant `git pull --rebase`." if ARGV[0] == "--rebase"

  if ARGV.named.empty?
    odie "This command requires at least one argument containing a URL or pull request number"
  end

  do_bump = ARGV.include?("--bump") && !ARGV.include?("--clean")

  # Formulae with affected bottles that were published
  bintray_published_formulae = []
  tap = nil

  ARGV.named.each do |arg|
    if arg.to_i > 0
      issue = arg
      url = "https://github.com/Homebrew/homebrew-core/pull/#{arg}"
      tap = CoreTap.instance
    elsif (testing_match = arg.match %r{/job/Homebrew.*Testing/(\d+)/})
      tap = ARGV.value("tap")
      tap = if tap && tap.start_with?("homebrew/")
        Tap.fetch("homebrew", tap.strip_prefix("homebrew/"))
      elsif tap
        odie "Tap option did not start with \"homebrew/\": #{tap}"
      else
        CoreTap.instance
      end
      _, testing_job = *testing_match
      url = "https://github.com/Homebrew/homebrew-#{tap.repo}/compare/master...BrewTestBot:testing-#{testing_job}"
      odie "Testing URLs require `--bottle`!" unless ARGV.include?("--bottle")
    elsif (api_match = arg.match HOMEBREW_PULL_API_REGEX)
      _, user, repo, issue = *api_match
      url = "https://github.com/#{user}/#{repo}/pull/#{issue}"
      tap = Tap.fetch(user, repo) if repo.start_with?("homebrew-")
    elsif (url_match = arg.match HOMEBREW_PULL_OR_COMMIT_URL_REGEX)
      url, user, repo, issue = *url_match
      tap = Tap.fetch(user, repo) if repo.start_with?("homebrew-")
    else
      odie "Not a GitHub pull request or commit: #{arg}"
    end

    if !testing_job && ARGV.include?("--bottle") && issue.nil?
      odie "No pull request detected!"
    end

    if tap
      tap.install unless tap.installed?
      Dir.chdir tap.path
    else
      Dir.chdir HOMEBREW_REPOSITORY
    end

    # The cache directory seems like a good place to put patches.
    HOMEBREW_CACHE.mkpath

    # Store current revision and branch
    orig_revision = `git rev-parse --short HEAD`.strip
    branch = `git symbolic-ref --short HEAD`.strip

    unless branch == "master" || ARGV.include?("--clean") || ARGV.include?("--branch-okay")
      opoo "Current branch is #{branch}: do you need to pull inside master?"
    end

    patch_puller = PatchPuller.new(url)
    patch_puller.fetch_patch
    patch_changes = files_changed_in_patch(patch_puller.patchpath, tap)

    is_bumpable = patch_changes[:formulae].length == 1 && patch_changes[:others].empty?
    if do_bump
      odie "No changed formulae found to bump" if patch_changes[:formulae].empty?
      if patch_changes[:formulae].length > 1
        odie "Can only bump one changed formula; bumped #{patch_changes[:formulae]}"
      end
      odie "Can not bump if non-formula files are changed" unless patch_changes[:others].empty?
    end
    if is_bumpable
      old_versions = current_versions_from_info_external(patch_changes[:formulae].first)
    end
    patch_puller.apply_patch

    changed_formulae_names = []

    if tap
      Utils.popen_read(
        "git", "diff-tree", "-r", "--name-only",
        "--diff-filter=AM", orig_revision, "HEAD", "--", tap.formula_dir.to_s
      ).each_line do |line|
        next unless line.end_with? ".rb\n"
        name = "#{tap.name}/#{File.basename(line.chomp, ".rb")}"
        changed_formulae_names << name
      end
    end

    fetch_bottles = false
    changed_formulae_names.each do |name|
      next if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"]

      begin
        f = Formula[name]
      # Make sure we catch syntax errors.
      rescue Exception
        next
      end

      if f.stable
        stable_urls = [f.stable.url] + f.stable.mirrors
        stable_urls.grep(%r{^https://dl.bintray.com/homebrew/mirror/}) do |mirror_url|
          check_bintray_mirror(f.full_name, mirror_url)
        end
      end

      if ARGV.include? "--bottle"
        if f.bottle_unneeded?
          ohai "#{f}: skipping unneeded bottle."
        elsif f.bottle_disabled?
          ohai "#{f}: skipping disabled bottle: #{f.bottle_disable_reason}"
        else
          fetch_bottles = true
        end
      else
        next unless f.bottle_defined?
        opoo "#{f.full_name} has a bottle: do you need to update it with --bottle?"
      end
    end

    orig_message = message = `git log HEAD^.. --format=%B`
    if issue && !ARGV.include?("--clean")
      ohai "Patch closes issue ##{issue}"
      close_message = "Closes ##{issue}."
      # If this is a pull request, append a close message.
      message += "\n#{close_message}" unless message.include? close_message
    end

    if changed_formulae_names.empty?
      odie "cannot bump: no changed formulae found after applying patch" if do_bump
      is_bumpable = false
    end

    is_bumpable = false if ARGV.include?("--clean")
    is_bumpable = false if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"]

    if is_bumpable
      formula = Formula[changed_formulae_names.first]
      new_versions = current_versions_from_info_external(patch_changes[:formulae].first)
      orig_subject = message.empty? ? "" : message.lines.first.chomp
      bump_subject = subject_for_bump(formula, old_versions, new_versions)
      if do_bump
        odie "No version changes found for #{formula.name}" if bump_subject.nil?
        unless orig_subject == bump_subject
          ohai "New bump commit subject: #{bump_subject}"
          pbcopy bump_subject unless ARGV.include? "--no-pbcopy"
          message = "#{bump_subject}\n\n#{message}"
        end
      elsif bump_subject != orig_subject && !bump_subject.nil?
        opoo "Nonstandard bump subject: #{orig_subject}"
        opoo "Subject should be: #{bump_subject}"
      end
    end

    if message != orig_message && !ARGV.include?("--clean")
      safe_system "git", "commit", "--amend", "--signoff", "--allow-empty", "-q", "-m", message
    end

    # Bottles: Pull bottle block commit and publish bottle files on Bintray
    if fetch_bottles
      bottle_commit_url = if testing_job
        bottle_branch = "testing-bottle-#{testing_job}"
        url
      else
        bottle_branch = "pull-bottle-#{issue}"
        "https://github.com/BrewTestBot/homebrew-#{tap.repo}/compare/homebrew:master...pr-#{issue}"
      end

      curl "--silent", "--fail", "-o", "/dev/null", "-I", bottle_commit_url

      safe_system "git", "checkout", "--quiet", "-B", bottle_branch, orig_revision
      pull_patch bottle_commit_url, "bottle commit"
      safe_system "git", "rebase", "--quiet", branch
      safe_system "git", "checkout", "--quiet", branch
      safe_system "git", "merge", "--quiet", "--ff-only", "--no-edit", bottle_branch
      safe_system "git", "branch", "--quiet", "-D", bottle_branch

      # Publish bottles on Bintray
      unless ARGV.include? "--no-publish"
        published = publish_changed_formula_bottles(tap, changed_formulae_names)
        bintray_published_formulae.concat(published)
      end
    end

    ohai "Patch changed:"
    safe_system "git", "diff-tree", "-r", "--stat", orig_revision, "HEAD"
  end

  # Verify bintray publishing after all patches have been applied
  bintray_published_formulae.uniq!
  verify_bintray_published(bintray_published_formulae)
end

.pull_patch(url, description = nil) ⇒ Object



280
281
282
# File 'Library/Homebrew/dev-cmd/pull.rb', line 280

def pull_patch(url, description = nil)
  PatchPuller.new(url, description).pull_patch
end

.puts_deps(formulae) ⇒ Object



129
130
131
132
133
134
# File 'Library/Homebrew/cmd/deps.rb', line 129

def puts_deps(formulae)
  formulae.each do |f|
    deps = deps_for_formula(f).sort_by(&:name).map(&method(:dep_display_name))
    puts "#{f.full_name}: #{deps.join(" ")}"
  end
end

.puts_deps_tree(formulae) ⇒ Object



136
137
138
139
140
141
142
# File 'Library/Homebrew/cmd/deps.rb', line 136

def puts_deps_tree(formulae)
  formulae.each do |f|
    puts "#{f.full_name} (required dependencies)"
    recursive_deps_tree(f, "")
    puts
  end
end

.puts_keg_only_path_message(keg) ⇒ Object



82
83
84
85
86
87
88
89
90
91
# File 'Library/Homebrew/cmd/link.rb', line 82

def puts_keg_only_path_message(keg)
  bin = keg/"bin"
  sbin = keg/"sbin"
  return if !bin.directory? && !sbin.directory?

  opt = HOMEBREW_PREFIX/"opt/#{keg.name}"
  puts "\nIf you need to have this software first in your PATH instead consider running:"
  puts "  #{Utils::Shell.prepend_path_in_shell_profile(opt)}/bin"  if bin.directory?
  puts "  #{Utils::Shell.prepend_path_in_shell_profile(opt)}/sbin" if sbin.directory?
end

.puts_options(formulae) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
# File 'Library/Homebrew/cmd/options.rb', line 28

def puts_options(formulae)
  formulae.each do |f|
    next if f.options.empty?
    if ARGV.include? "--compact"
      puts f.options.as_flags.sort * " "
    else
      puts f.full_name if formulae.length > 1
      dump_options_for_formula f
      puts
    end
  end
end

.query_regexp(query) ⇒ Object



108
109
110
111
112
113
114
115
# File 'Library/Homebrew/cmd/search.rb', line 108

def query_regexp(query)
  case query
  when %r{^/(.*)/$} then Regexp.new($1)
  else /.*#{Regexp.escape(query)}.*/i
  end
rescue RegexpError
  odie "#{query} is not a valid regex"
end

.raise_deprecation_exceptions?Boolean



45
46
47
# File 'Library/Homebrew/global.rb', line 45

def raise_deprecation_exceptions?
  @raise_deprecation_exceptions == true
end

.readallObject



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
# File 'Library/Homebrew/cmd/readall.rb', line 14

def readall
  if ARGV.include?("--syntax")
    ruby_files = []
    scan_files = %W[
      #{HOMEBREW_LIBRARY}/*.rb
      #{HOMEBREW_LIBRARY}/Homebrew/**/*.rb
    ]
    Dir.glob(scan_files).each do |rb|
      next if rb.include?("/vendor/")
      next if rb.include?("/cask/")
      ruby_files << rb
    end

    Homebrew.failed = true unless Readall.valid_ruby_syntax?(ruby_files)
  end

  options = { aliases: ARGV.include?("--aliases") }
  taps = if ARGV.named.empty?
    Tap
  else
    [Tap.fetch(ARGV.named.first)]
  end
  taps.each do |tap|
    Homebrew.failed = true unless Readall.valid_tap?(tap, options)
  end
end

.recursive_deps_tree(f, prefix) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'Library/Homebrew/cmd/deps.rb', line 144

def recursive_deps_tree(f, prefix)
  reqs = f.requirements.select(&:default_formula?)
  deps = f.deps.default
  max = reqs.length - 1
  reqs.each_with_index do |req, i|
    chr = if i == max && deps.empty?
      "└──"
    else
      "├──"
    end
    puts prefix + "#{chr} :#{dep_display_name(req.to_dependency)}"
  end
  max = deps.length - 1
  deps.each_with_index do |dep, i|
    chr = if i == max
      "└──"
    else
      "├──"
    end
    prefix_ext = i == max ? "    " : "│   "
    puts prefix + "#{chr} #{dep_display_name(dep)}"
    recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_ext)
  end
end

.regenerate_man_pagesObject



37
38
39
40
41
42
43
44
45
46
# File 'Library/Homebrew/dev-cmd/man.rb', line 37

def regenerate_man_pages
  Homebrew.install_gem_setup_path! "ronn"

  markup = build_man_page
  convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md")
  convert_man_page(markup, TARGET_MAN_PATH/"brew.1")

  cask_markup = (SOURCE_PATH/"brew-cask.1.md").read
  convert_man_page(cask_markup, TARGET_MAN_PATH/"brew-cask.1")
end

.reinstallObject



10
11
12
13
14
15
16
17
18
19
20
# File 'Library/Homebrew/cmd/reinstall.rb', line 10

def reinstall
  FormulaInstaller.prevent_build_flags unless DevelopmentTools.installed?

  ARGV.resolved_formulae.each do |f|
    if f.pinned?
      onoe "#{f.full_name} is pinned. You must unpin it to reinstall."
      next
    end
    reinstall_formula(f)
  end
end

.reinstall_formula(f) ⇒ Object



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
# File 'Library/Homebrew/cmd/reinstall.rb', line 22

def reinstall_formula(f)
  if f.opt_prefix.directory?
    keg = Keg.new(f.opt_prefix.resolved_path)
    backup keg
  end

  build_options = BuildOptions.new(Options.create(ARGV.flags_only), f.options)
  options = build_options.used_options
  options |= f.build.used_options
  options &= f.options

  fi = FormulaInstaller.new(f)
  fi.options              = options
  fi.invalid_option_names = build_options.invalid_option_names
  fi.build_bottle         = ARGV.build_bottle? || (!f.bottled? && f.build.build_bottle?)
  fi.build_from_source    = ARGV.build_from_source? || ARGV.build_all_from_source?
  fi.force_bottle         = ARGV.force_bottle?
  fi.interactive          = ARGV.interactive?
  fi.git                  = ARGV.git?
  fi.verbose              = ARGV.verbose?
  fi.debug                = ARGV.debug?
  fi.prelude

  oh1 "Reinstalling #{f.full_name} #{options.to_a.join " "}"

  fi.install
  fi.finish
rescue FormulaInstallationAlreadyAttemptedError
  # next
rescue Exception
  ignore_interrupts { restore_backup(keg, f) }
  raise
else
  backup_path(keg).rmtree if backup_path(keg).exist?
end

.release_notesObject



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
# File 'Library/Homebrew/dev-cmd/release-notes.rb', line 11

def release_notes
  previous_tag = ARGV.named.first
  unless previous_tag
    previous_tag = Utils.popen_read("git tag --list --sort=-version:refname")
                        .lines.first.chomp
  end
  odie "Could not find any previous tags!" unless previous_tag

  end_ref = ARGV.named[1] || "origin/master"

  [previous_tag, end_ref].each do |ref|
    next if quiet_system "git", "rev-parse", "--verify", "--quiet", ref
    odie "Ref #{ref} does not exist!"
  end

  output = Utils.popen_read("git log --pretty=format:'%s >> - %b%n' '#{previous_tag}'..'#{end_ref}'")
                .lines.grep(/Merge pull request/)

  output.map! do |s|
    s.gsub(/.*Merge pull request #(\d+)[^>]*(>>)*/,
           "https://github.com/Homebrew/brew/pull/\\1")
  end
  if ARGV.include?("--markdown")
    output.map! do |s|
      /(.*\d)+ - (.*)/ =~ s
      "- [#{$2}](#{$1})"
    end
  end

  puts "Release notes between #{previous_tag} and #{end_ref}:"
  puts output
end

.restore_backup(keg, formula) ⇒ Object



63
64
65
66
67
68
69
70
# File 'Library/Homebrew/cmd/reinstall.rb', line 63

def restore_backup(keg, formula)
  path = backup_path(keg)

  return unless path.directory?

  path.rename keg
  keg.link unless formula.keg_only?
end

.retry_fetch?(f) ⇒ Boolean



99
100
101
102
103
104
105
106
107
108
109
# File 'Library/Homebrew/cmd/fetch.rb', line 99

def retry_fetch?(f)
  @fetch_failed ||= Set.new
  if ARGV.include?("--retry") && @fetch_failed.add?(f)
    ohai "Retrying download"
    f.clear_cache
    true
  else
    Homebrew.failed = true
    false
  end
end

.rm_pin(rack) ⇒ Object



153
154
155
156
157
# File 'Library/Homebrew/cmd/uninstall.rb', line 153

def rm_pin(rack)
  Formulary.from_rack(rack).unpin
rescue
  nil
end

.run_post_install(formula) ⇒ Object



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
# File 'Library/Homebrew/cmd/postinstall.rb', line 13

def run_post_install(formula)
  args = %W[
    nice #{RUBY_PATH}
    -W0
    -I #{HOMEBREW_LOAD_PATH}
    --
    #{HOMEBREW_LIBRARY_PATH}/postinstall.rb
    #{formula.path}
  ].concat(ARGV.options_only)

  if formula.head?
    args << "--HEAD"
  elsif formula.devel?
    args << "--devel"
  end

  Sandbox.print_sandbox_message if Sandbox.formula?(formula)

  Utils.safe_fork do
    if Sandbox.formula?(formula)
      sandbox = Sandbox.new
      formula.logs.mkpath
      sandbox.record_log(formula.logs/"postinstall.sandbox.log")
      sandbox.allow_write_temp_and_cache
      sandbox.allow_write_log(formula)
      sandbox.allow_write_xcode
      sandbox.deny_write_homebrew_repository
      sandbox.allow_write_cellar(formula)
      Keg::TOP_LEVEL_DIRECTORIES.each do |dir|
        sandbox.allow_write_path "#{HOMEBREW_PREFIX}/#{dir}"
      end
      sandbox.exec(*args)
    else
      exec(*args)
    end
  end
end

.searchObject



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
# File 'Library/Homebrew/cmd/search.rb', line 28

def search
  if ARGV.empty?
    puts Formatter.columns(Formula.full_names)
  elsif ARGV.include? "--macports"
    exec_browser "https://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
  elsif ARGV.include? "--fink"
    exec_browser "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}"
  elsif ARGV.include? "--debian"
    exec_browser "https://packages.debian.org/search?keywords=#{ARGV.next}&searchon=names&suite=all&section=all"
  elsif ARGV.include? "--opensuse"
    exec_browser "https://software.opensuse.org/search?q=#{ARGV.next}"
  elsif ARGV.include? "--fedora"
    exec_browser "https://admin.fedoraproject.org/pkgdb/packages/%2A#{ARGV.next}%2A/"
  elsif ARGV.include? "--ubuntu"
    exec_browser "http://packages.ubuntu.com/search?keywords=#{ARGV.next}&searchon=names&suite=all&section=all"
  elsif ARGV.include? "--desc"
    query = ARGV.next
    regex = query_regexp(query)
    Descriptions.search(regex, :desc).print
  elsif ARGV.first =~ HOMEBREW_TAP_FORMULA_REGEX
    query = ARGV.first
    user, repo, name = query.split("/", 3)

    begin
      result = Formulary.factory(query).name
    rescue FormulaUnavailableError
      result = search_tap(user, repo, name)
    end

    results = Array(result)
    puts Formatter.columns(results) unless results.empty?
  else
    query = ARGV.first
    regex = query_regexp(query)
    local_results = search_formulae(regex)
    puts Formatter.columns(local_results) unless local_results.empty?
    tap_results = search_taps(regex)
    puts Formatter.columns(tap_results) unless tap_results.empty?

    if $stdout.tty?
      count = local_results.length + tap_results.length

      if reason = Homebrew::MissingFormula.reason(query, silent: true)
        if count > 0
          puts
          puts "If you meant #{query.inspect} specifically:"
        end
        puts reason
      elsif count.zero?
        puts "No formula found for #{query.inspect}."
        begin
          GitHub.print_pull_requests_matching(query)
        rescue GitHub::Error => e
          SEARCH_ERROR_QUEUE << e
        end
      end
    end
  end

  if $stdout.tty?
    metacharacters = %w[\\ | ( ) [ ] { } ^ $ * + ?]
    bad_regex = metacharacters.any? do |char|
      ARGV.any? do |arg|
        arg.include?(char) && !arg.start_with?("/")
      end
    end
    if !ARGV.empty? && bad_regex
      ohai "Did you mean to perform a regular expression search?"
      ohai "Surround your query with /slashes/ to search by regex."
    end
  end

  raise SEARCH_ERROR_QUEUE.pop unless SEARCH_ERROR_QUEUE.empty?
end

.search_formulae(regex) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'Library/Homebrew/cmd/search.rb', line 166

def search_formulae(regex)
  aliases = Formula.alias_full_names
  results = (Formula.full_names+aliases).grep(regex).sort

  results.map do |name|
    begin
      formula = Formulary.factory(name)
      canonical_name = formula.name
      canonical_full_name = formula.full_name
    rescue
      canonical_name = canonical_full_name = name
    end

    # Ignore aliases from results when the full name was also found
    next if aliases.include?(name) && results.include?(canonical_full_name)

    if (HOMEBREW_CELLAR/canonical_name).directory?
      pretty_installed(name)
    else
      name
    end
  end.compact
end

.search_tap(user, repo, regex_or_string) ⇒ Object



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
157
158
159
160
161
162
163
164
# File 'Library/Homebrew/cmd/search.rb', line 125

def search_tap(user, repo, regex_or_string)
  regex = regex_or_string.is_a?(String) ? /^#{Regexp.escape(regex_or_string)}$/ : regex_or_string

  if (HOMEBREW_LIBRARY/"Taps/#{user.downcase}/homebrew-#{repo.downcase}").directory? && \
     user != "Caskroom"
    return []
  end

  remote_tap_formulae = Hash.new do |cache, key|
    user, repo = key.split("/", 2)
    tree = {}

    GitHub.open "https://api.github.com/repos/#{user}/homebrew-#{repo}/git/trees/HEAD?recursive=1" do |json|
      json["tree"].each do |object|
        next unless object["type"] == "blob"

        subtree, file = File.split(object["path"])

        if File.extname(file) == ".rb"
          tree[subtree] ||= []
          tree[subtree] << file
        end
      end
    end

    paths = tree["Formula"] || tree["HomebrewFormula"] || tree["."] || []
    paths += tree["Casks"] || []
    cache[key] = paths.map { |path| File.basename(path, ".rb") }
  end

  names = remote_tap_formulae["#{user}/#{repo}"]
  user = user.downcase if user == "Homebrew" # special handling for the Homebrew organization
  names.select { |name| name =~ regex }.map { |name| "#{user}/#{repo}/#{name}" }
rescue GitHub::HTTPNotFoundError
  opoo "Failed to search tap: #{user}/#{repo}. Please run `brew update`"
  []
rescue GitHub::Error => e
  SEARCH_ERROR_QUEUE << e
  []
end

.search_taps(regex_or_string) ⇒ Object



117
118
119
120
121
122
123
# File 'Library/Homebrew/cmd/search.rb', line 117

def search_taps(regex_or_string)
  SEARCHABLE_TAPS.map do |user, repo|
    Thread.new { search_tap(user, repo, regex_or_string) }
  end.inject([]) do |results, t|
    results.concat(t.value)
  end
end

.shObject



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
# File 'Library/Homebrew/cmd/sh.rb', line 16

def sh
  ENV.activate_extensions!

  if superenv?
    ENV.set_x11_env_if_installed
    ENV.deps = Formula.installed.select { |f| f.keg_only? && f.opt_prefix.directory? }
  end
  ENV.setup_build_environment
  if superenv?
    # superenv stopped adding brew's bin but generally users will want it
    ENV["PATH"] = ENV["PATH"].split(File::PATH_SEPARATOR).insert(1, "#{HOMEBREW_PREFIX}/bin").join(File::PATH_SEPARATOR)
  end
  ENV["PS1"] = 'brew \[\033[1;32m\]\w\[\033[0m\]$ '
  ENV["VERBOSE"] = "1"
  puts "Your shell has been configured to use Homebrew's build environment;\nthis should help you build stuff. Notably though, the system versions of\ngem and pip will ignore our configuration and insist on using the\nenvironment they were built under (mostly). Sadly, scons will also\nignore our configuration.\nWhen done, type `exit'.\n".undent_________________________________________________________72
  $stdout.flush
  exec ENV["SHELL"]
end

.shorten_revision(revision) ⇒ Object



119
120
121
# File 'Library/Homebrew/cmd/update-report.rb', line 119

def shorten_revision(revision)
  Utils.popen_read("git", "-C", HOMEBREW_REPOSITORY, "rev-parse", "--short", revision).chomp
end

.sort_key_for_path(path) ⇒ Object



76
77
78
79
# File 'Library/Homebrew/dev-cmd/man.rb', line 76

def sort_key_for_path(path)
  # Options after regular commands (`~` comes after `z` in ASCII table).
  path.basename.to_s.sub(/\.(rb|sh)$/, "").sub(/^--/, "~~")
end

.styleObject



22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'Library/Homebrew/cmd/style.rb', line 22

def style
  target = if ARGV.named.empty?
    nil
  elsif ARGV.named.any? { |file| File.exist? file }
    ARGV.named
  elsif ARGV.named.any? { |tap| tap.count("/") == 1 }
    ARGV.named.map { |tap| Tap.fetch(tap).path }
  else
    ARGV.formulae.map(&:path)
  end

  Homebrew.failed = check_style_and_print(target, fix: ARGV.flag?("--fix"))
end

.subject_for_bump(formula, old, new) ⇒ Object



379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'Library/Homebrew/dev-cmd/pull.rb', line 379

def subject_for_bump(formula, old, new)
  if old[:nonexistent]
    # New formula
    headline_ver = if new[:stable]
      new[:stable]
    elsif new[:devel]
      new[:devel]
    else
      new[:head]
    end
    subject = "#{formula.name} #{headline_ver} (new formula)"
  else
    # Update to existing formula
    subject_strs = []
    formula_name_str = formula.name
    if old[:stable] != new[:stable]
      if new[:stable].nil?
        subject_strs << "remove stable"
        formula_name_str += ":" # just for cosmetics
      else
        subject_strs << new[:stable]
      end
    end
    if old[:devel] != new[:devel]
      if new[:devel].nil?
        # Only bother mentioning if there's no accompanying stable change
        if !new[:stable].nil? && old[:stable] == new[:stable]
          subject_strs << "remove devel"
          formula_name_str += ":" # just for cosmetics
        end
      else
        subject_strs << "#{new[:devel]} (devel)"
      end
    end
    subject = subject_strs.empty? ? nil : "#{formula_name_str} #{subject_strs.join(", ")}"
  end
  subject
end

.switchObject



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
# File 'Library/Homebrew/cmd/switch.rb', line 11

def switch
  if ARGV.named.length != 2
    onoe "Usage: brew switch <name> <version>"
    exit 1
  end

  name = ARGV.shift
  version = ARGV.shift

  rack = Formulary.to_rack(name)

  unless rack.directory?
    onoe "#{name} not found in the Cellar."
    exit 2
  end

  # Does the target version exist?
  unless (rack+version).directory?
    onoe "#{name} does not have a version \"#{version}\" in the Cellar."

    versions = rack.subdirs.map { |d| Keg.new(d).version }
    puts "Versions available: #{versions.join(", ")}"

    exit 3
  end

  # Unlink all existing versions
  rack.subdirs.each do |v|
    keg = Keg.new(v)
    puts "Cleaning #{keg}"
    keg.unlink
  end

  keg = Keg.new(rack+version)

  # Link new version, if not keg-only
  if keg_only?(rack)
    keg.optlink
    puts "Opt link created for #{keg}"
  else
    puts "#{keg.link} links created for #{keg}"
  end
end

.system(cmd, *args) ⇒ Object



177
178
179
180
# File 'Library/Homebrew/utils.rb', line 177

def system(cmd, *args)
  puts "#{cmd} #{args*" "}" if ARGV.verbose?
  _system(cmd, *args)
end

.tapObject



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'Library/Homebrew/cmd/tap.rb', line 39

def tap
  if ARGV.include? "--repair"
    Tap.each(&:link_completions_and_manpages)
  elsif ARGV.include? "--list-official"
    require "official_taps"
    puts OFFICIAL_TAPS.map { |t| "homebrew/#{t}" }
  elsif ARGV.include? "--list-pinned"
    puts Tap.select(&:pinned?).map(&:name)
  elsif ARGV.named.empty?
    puts Tap.names
  else
    tap = Tap.fetch(ARGV.named[0])
    begin
      tap.install clone_target: ARGV.named[1],
                  full_clone: full_clone?,
                  quiet: ARGV.quieter?
    rescue TapRemoteMismatchError => e
      odie e
    rescue TapAlreadyTappedError, TapAlreadyUnshallowError
      # Do nothing.
    end
  end
end

.tap_infoObject



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'Library/Homebrew/cmd/tap-info.rb', line 23

def tap_info
  if ARGV.include? "--installed"
    taps = Tap
  else
    taps = ARGV.named.map do |name|
      Tap.fetch(name)
    end
  end

  if ARGV.json == "v1"
    print_tap_json(taps)
  else
    print_tap_info(taps)
  end
end

.tap_newObject



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
# File 'Library/Homebrew/dev-cmd/tap-new.rb', line 16

def tap_new
  raise "A tap argument is required" if ARGV.named.empty?

  tap = Tap.fetch(ARGV.named.first)
  titleized_user = tap.user.dup
  titleized_repo = tap.repo.dup
  titleized_user[0] = titleized_user[0].upcase
  titleized_repo[0] = titleized_repo[0].upcase

  (tap.path/"Formula").mkpath

  readme = "# \#{titleized_user} \#{titleized_repo}\n\n## How do I install these formulae?\n`brew install \#{tap}/<formula>`\n\nOr `brew tap \#{tap}` and then `brew install <formula>`.\n\nOr install via URL (which will not receive updates):\n\n```\nbrew install https://raw.githubusercontent.com/\#{tap.user}/homebrew-\#{tap.repo}/master/Formula/<formula>.rb\n```\n\n## Documentation\n`brew help`, `man brew` or check [Homebrew's documentation](https://github.com/Homebrew/brew/tree/master/docs#readme).\n".undent
  write_path(tap, "README.md", readme)

  travis = "language: ruby\nos: osx\nenv: OSX=10.12\nosx_image: xcode8.1\nrvm: system\n\nbefore_install:\n- export TRAVIS_COMMIT=\"$(git rev-parse --verify -q HEAD)\"\n- if [ -f \".git/shallow\" ]; then\ntravis_retry git fetch --unshallow;\nfi\n- HOMEBREW_REPOSITORY=\"$(brew --repo)\"\n- sudo chown -R \"$USER\" \"$HOMEBREW_REPOSITORY\"\n- git -C \"$HOMEBREW_REPOSITORY\" reset --hard origin/master\n- brew update || brew update\n- HOMEBREW_TAP_DIR=\"$(brew --repo \"$TRAVIS_REPO_SLUG\")\"\n- mkdir -p \"$HOMEBREW_TAP_DIR\"\n- rm -rf \"$HOMEBREW_TAP_DIR\"\n- ln -s \"$PWD\" \"$HOMEBREW_TAP_DIR\"\n- export HOMEBREW_DEVELOPER=\"1\"\n- ulimit -n 1024\n\nscript:\n- brew test-bot\n\nnotifications:\nemail:\non_success: never\non_failure: always\n".undent
  write_path(tap, ".travis.yml", travis)
end

.tap_pinObject



10
11
12
13
14
15
16
17
# File 'Library/Homebrew/cmd/tap-pin.rb', line 10

def tap_pin
  ARGV.named.each do |name|
    tap = Tap.fetch(name)
    raise "pinning #{tap} is not allowed" if tap.core_tap?
    tap.pin
    ohai "Pinned #{tap}"
  end
end

.tap_unpinObject



9
10
11
12
13
14
15
16
# File 'Library/Homebrew/cmd/tap-unpin.rb', line 9

def tap_unpin
  ARGV.named.each do |name|
    tap = Tap.fetch(name)
    raise "unpinning #{tap} is not allowed" if tap.core_tap?
    tap.unpin
    ohai "Unpinned #{tap}"
  end
end

.target_path_to_format(target) ⇒ Object



113
114
115
116
117
118
119
120
# File 'Library/Homebrew/dev-cmd/man.rb', line 113

def target_path_to_format(target)
  case target.basename
  when /\.md$/    then ["--markdown", "markdown"]
  when /\.\d$/    then ["--roff", "man page"]
  else
    odie "Failed to infer output format from '#{target.basename}'."
  end
end

.testObject



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
# File 'Library/Homebrew/dev-cmd/test.rb', line 26

def test
  raise FormulaUnspecifiedError if ARGV.named.empty?

  ARGV.resolved_formulae.each do |f|
    # Cannot test uninstalled formulae
    unless f.installed?
      ofail "Testing requires the latest version of #{f.full_name}"
      next
    end

    # Cannot test formulae without a test method
    unless f.test_defined?
      ofail "#{f.full_name} defines no test"
      next
    end

    puts "Testing #{f.full_name}"

    env = ENV.to_hash

    begin
      args = %W[
        #{RUBY_PATH}
        -W0
        -I #{HOMEBREW_LOAD_PATH}
        --
        #{HOMEBREW_LIBRARY_PATH}/test.rb
        #{f.path}
      ].concat(ARGV.options_only)

      if f.head?
        args << "--HEAD"
      elsif f.devel?
        args << "--devel"
      end

      Sandbox.print_sandbox_message if Sandbox.test?

      Utils.safe_fork do
        if Sandbox.test?
          sandbox = Sandbox.new
          f.logs.mkpath
          sandbox.record_log(f.logs/"test.sandbox.log")
          sandbox.allow_write_temp_and_cache
          sandbox.allow_write_log(f)
          sandbox.allow_write_xcode
          sandbox.allow_write_path(HOMEBREW_PREFIX/"var/cache")
          sandbox.allow_write_path(HOMEBREW_PREFIX/"var/log")
          sandbox.allow_write_path(HOMEBREW_PREFIX/"var/run")
          sandbox.exec(*args)
        else
          exec(*args)
        end
      end
    rescue Assertions::FailedAssertion => e
      ofail "#{f.full_name}: failed"
      puts e.message
    rescue Exception => e
      ofail "#{f.full_name}: failed"
      puts e, e.backtrace
    ensure
      ENV.replace(env)
    end
  end
end

.testsObject



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
# File 'Library/Homebrew/dev-cmd/tests.rb', line 26

def tests
  HOMEBREW_LIBRARY_PATH.cd do
    ENV.delete("HOMEBREW_VERBOSE")
    ENV.delete("VERBOSE")
    ENV.delete("HOMEBREW_CASK_OPTS")
    ENV.delete("HOMEBREW_TEMP")
    ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1"
    ENV["HOMEBREW_DEVELOPER"] = "1"
    ENV["HOMEBREW_NO_COMPAT"] = "1" if ARGV.include? "--no-compat"
    ENV["HOMEBREW_TEST_GENERIC_OS"] = "1" if ARGV.include? "--generic"
    ENV["HOMEBREW_NO_GITHUB_API"] = "1" unless ARGV.include? "--online"

    if ARGV.