aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
Diffstat (limited to 'Library')
-rw-r--r--Library/.rubocop.yml3
-rw-r--r--Library/Homebrew/blacklist.rb92
-rw-r--r--Library/Homebrew/build_options.rb1
-rw-r--r--Library/Homebrew/cask/lib/hbc/artifact/binary.rb7
-rw-r--r--Library/Homebrew/cask/lib/hbc/artifact/moved.rb18
-rw-r--r--Library/Homebrew/cask/lib/hbc/cask.rb52
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/doctor.rb2
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/uninstall.rb10
-rw-r--r--Library/Homebrew/cask/lib/hbc/container.rb4
-rw-r--r--Library/Homebrew/cask/lib/hbc/container/executable.rb18
-rw-r--r--Library/Homebrew/cask/lib/hbc/dsl/container.rb9
-rw-r--r--Library/Homebrew/cask/lib/hbc/installer.rb16
-rw-r--r--Library/Homebrew/cask/lib/hbc/metadata.rb73
-rw-r--r--Library/Homebrew/cask/lib/hbc/pkg.rb7
-rw-r--r--Library/Homebrew/cask/lib/hbc/scopes.rb3
-rw-r--r--Library/Homebrew/cask/lib/hbc/system_command.rb12
-rw-r--r--Library/Homebrew/cask/lib/hbc/utils.rb30
-rw-r--r--Library/Homebrew/caveats.rb83
-rw-r--r--Library/Homebrew/cleanup.rb47
-rw-r--r--Library/Homebrew/cmd/--env.rb4
-rw-r--r--Library/Homebrew/cmd/cleanup.rb14
-rw-r--r--Library/Homebrew/cmd/fetch.rb4
-rw-r--r--Library/Homebrew/cmd/info.rb12
-rw-r--r--Library/Homebrew/cmd/install.rb103
-rw-r--r--Library/Homebrew/cmd/link.rb19
-rw-r--r--Library/Homebrew/cmd/log.rb28
-rw-r--r--Library/Homebrew/cmd/migrate.rb2
-rw-r--r--Library/Homebrew/cmd/outdated.rb10
-rw-r--r--Library/Homebrew/cmd/reinstall.rb1
-rw-r--r--Library/Homebrew/cmd/search.rb17
-rw-r--r--Library/Homebrew/cmd/tap.rb13
-rw-r--r--Library/Homebrew/cmd/uninstall.rb2
-rw-r--r--Library/Homebrew/cmd/unpack.rb2
-rw-r--r--Library/Homebrew/cmd/update-report.rb38
-rw-r--r--Library/Homebrew/cmd/update.sh2
-rw-r--r--Library/Homebrew/cmd/upgrade.rb1
-rw-r--r--Library/Homebrew/cmd/uses.rb12
-rw-r--r--Library/Homebrew/compat.rb1
-rw-r--r--Library/Homebrew/compat/ARGV.rb2
-rw-r--r--Library/Homebrew/compat/build_options.rb7
-rw-r--r--Library/Homebrew/compat/dependency_collector.rb1
-rw-r--r--Library/Homebrew/compat/global.rb2
-rw-r--r--Library/Homebrew/compat/software_spec.rb2
-rw-r--r--Library/Homebrew/compat/tab.rb2
-rw-r--r--Library/Homebrew/compat/tap.rb2
-rw-r--r--Library/Homebrew/compat/utils.rb11
-rw-r--r--Library/Homebrew/compat/utils/shell.rb8
-rw-r--r--Library/Homebrew/dev-cmd/audit.rb203
-rw-r--r--Library/Homebrew/dev-cmd/boneyard-formula-pr.rb166
-rw-r--r--Library/Homebrew/dev-cmd/bottle.rb2
-rw-r--r--Library/Homebrew/dev-cmd/create.rb62
-rw-r--r--Library/Homebrew/dev-cmd/man.rb13
-rw-r--r--Library/Homebrew/dev-cmd/pull.rb15
-rw-r--r--Library/Homebrew/dev-cmd/tap-new.rb1
-rw-r--r--Library/Homebrew/dev-cmd/test.rb2
-rw-r--r--Library/Homebrew/dev-cmd/tests.rb14
-rw-r--r--Library/Homebrew/dev-cmd/update-test.rb14
-rw-r--r--Library/Homebrew/diagnostic.rb55
-rw-r--r--Library/Homebrew/exceptions.rb92
-rw-r--r--Library/Homebrew/extend/ENV/super.rb4
-rw-r--r--Library/Homebrew/extend/io.rb15
-rw-r--r--Library/Homebrew/extend/os/blacklist.rb2
-rw-r--r--Library/Homebrew/extend/os/linux/hardware/cpu.rb2
-rw-r--r--Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb39
-rw-r--r--Library/Homebrew/extend/os/mac/blacklist.rb16
-rw-r--r--Library/Homebrew/extend/os/mac/development_tools.rb4
-rw-r--r--Library/Homebrew/extend/os/mac/diagnostic.rb8
-rw-r--r--Library/Homebrew/extend/os/mac/formula_cellar_checks.rb8
-rw-r--r--Library/Homebrew/extend/os/mac/hardware/cpu.rb43
-rw-r--r--Library/Homebrew/extend/os/mac/keg_relocate.rb14
-rw-r--r--Library/Homebrew/extend/os/mac/missing_formula.rb22
-rw-r--r--Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb34
-rw-r--r--Library/Homebrew/extend/os/missing_formula.rb2
-rw-r--r--Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb7
-rw-r--r--Library/Homebrew/extend/pathname.rb5
-rw-r--r--Library/Homebrew/formula.rb9
-rw-r--r--Library/Homebrew/formula_cellar_checks.rb24
-rw-r--r--Library/Homebrew/formula_installer.rb57
-rw-r--r--Library/Homebrew/formula_support.rb2
-rw-r--r--Library/Homebrew/formulary.rb6
-rw-r--r--Library/Homebrew/gpg.rb9
-rw-r--r--Library/Homebrew/hardware.rb12
-rw-r--r--Library/Homebrew/keg.rb32
-rw-r--r--Library/Homebrew/keg_relocate.rb17
-rw-r--r--Library/Homebrew/language/python.rb23
-rw-r--r--Library/Homebrew/migrator.rb132
-rw-r--r--Library/Homebrew/missing_formula.rb164
-rw-r--r--Library/Homebrew/official_taps.rb24
-rw-r--r--Library/Homebrew/os/mac.rb6
-rw-r--r--Library/Homebrew/os/mac/xcode.rb26
-rw-r--r--Library/Homebrew/readall.rb23
-rw-r--r--Library/Homebrew/requirement.rb8
-rw-r--r--Library/Homebrew/requirements.rb2
-rw-r--r--Library/Homebrew/requirements/gpg2_requirement.rb4
-rw-r--r--Library/Homebrew/requirements/java_requirement.rb2
-rw-r--r--Library/Homebrew/requirements/osxfuse_requirement.rb30
-rw-r--r--Library/Homebrew/requirements/ruby_requirement.rb2
-rw-r--r--Library/Homebrew/rubocops.rb1
-rw-r--r--Library/Homebrew/rubocops/bottle_block_cop.rb27
-rw-r--r--Library/Homebrew/rubocops/extend/formula_cop.rb144
-rw-r--r--Library/Homebrew/rubocops/formula_desc_cop.rb48
-rw-r--r--Library/Homebrew/software_spec.rb4
-rw-r--r--Library/Homebrew/tab.rb5
-rw-r--r--Library/Homebrew/tap.rb13
-rw-r--r--Library/Homebrew/test/.bundle/config1
-rw-r--r--Library/Homebrew/test/Gemfile1
-rw-r--r--Library/Homebrew/test/Gemfile.lock14
-rw-r--r--Library/Homebrew/test/blacklist_spec.rb115
-rw-r--r--Library/Homebrew/test/cask/artifact/binary_spec.rb31
-rw-r--r--Library/Homebrew/test/cask/cask_spec.rb4
-rw-r--r--Library/Homebrew/test/cask/cli/style_spec.rb2
-rw-r--r--Library/Homebrew/test/cask/dsl_spec.rb2
-rw-r--r--Library/Homebrew/test/cask/installer_spec.rb10
-rw-r--r--Library/Homebrew/test/cask/pkg_spec.rb9
-rw-r--r--Library/Homebrew/test/cleanup_spec.rb33
-rw-r--r--Library/Homebrew/test/cmd/bundle_spec.rb2
-rw-r--r--Library/Homebrew/test/cmd/link_spec.rb6
-rw-r--r--Library/Homebrew/test/cmd/log_spec.rb2
-rw-r--r--Library/Homebrew/test/cmd/outdated_spec.rb92
-rw-r--r--Library/Homebrew/test/compiler_selector_spec.rb12
-rw-r--r--Library/Homebrew/test/dev-cmd/audit_spec.rb56
-rw-r--r--Library/Homebrew/test/dev-cmd/pull_spec.rb4
-rw-r--r--Library/Homebrew/test/diagnostic_spec.rb12
-rw-r--r--Library/Homebrew/test/formula_installer_spec.rb46
-rw-r--r--Library/Homebrew/test/formula_spec.rb28
-rw-r--r--Library/Homebrew/test/gpg2_requirement_spec.rb2
-rw-r--r--Library/Homebrew/test/gpg_spec.rb7
-rw-r--r--Library/Homebrew/test/hardware_spec.rb47
-rw-r--r--Library/Homebrew/test/missing_formula_spec.rb171
-rw-r--r--Library/Homebrew/test/os/linux/osxfuse_requirement_spec.rb9
-rw-r--r--Library/Homebrew/test/os/mac/hardware_spec.rb56
-rw-r--r--Library/Homebrew/test/os/mac/osxfuse_requirement_spec.rb36
-rw-r--r--Library/Homebrew/test/requirement_spec.rb10
-rw-r--r--Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb67
-rw-r--r--Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb121
-rw-r--r--Library/Homebrew/test/spec_helper.rb4
-rw-r--r--Library/Homebrew/test/support/fixtures/cask/Casks/with-non-executable-binary.rb9
-rw-r--r--Library/Homebrew/test/support/fixtures/cask/naked_non_executable2
-rw-r--r--Library/Homebrew/test/tab_spec.rb2
-rw-r--r--Library/Homebrew/test/utils/shell_spec.rb56
-rw-r--r--Library/Homebrew/test/utils_spec.rb8
-rw-r--r--Library/Homebrew/utils.rb12
-rw-r--r--Library/Homebrew/utils/github.rb1
-rw-r--r--Library/Homebrew/utils/shell.rb106
-rw-r--r--Library/Homebrew/vendor/README.md4
-rw-r--r--Library/Homebrew/vendor/macho/macho.rb27
-rw-r--r--Library/Homebrew/vendor/macho/macho/exceptions.rb12
-rw-r--r--Library/Homebrew/vendor/macho/macho/fat_file.rb202
-rw-r--r--Library/Homebrew/vendor/macho/macho/headers.rb1176
-rw-r--r--Library/Homebrew/vendor/macho/macho/load_commands.rb2158
-rw-r--r--Library/Homebrew/vendor/macho/macho/macho_file.rb258
-rw-r--r--Library/Homebrew/vendor/macho/macho/open.rb25
-rw-r--r--Library/Homebrew/vendor/macho/macho/sections.rb320
-rw-r--r--Library/Homebrew/vendor/macho/macho/structure.rb2
-rw-r--r--Library/Homebrew/vendor/macho/macho/tools.rb34
-rw-r--r--Library/Homebrew/vendor/macho/macho/utils.rb35
-rwxr-xr-x[-rw-r--r--]Library/Homebrew/vendor/plist/plist/parser.rb5
157 files changed, 4629 insertions, 3366 deletions
diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml
index 314467ef0..a782c1117 100644
--- a/Library/.rubocop.yml
+++ b/Library/.rubocop.yml
@@ -11,6 +11,9 @@ require: ./Homebrew/rubocops.rb
Homebrew/CorrectBottleBlock:
Enabled: true
+Homebrew/FormulaDesc:
+ Enabled: true
+
Metrics/AbcSize:
Enabled: false
diff --git a/Library/Homebrew/blacklist.rb b/Library/Homebrew/blacklist.rb
deleted file mode 100644
index 93c8f81a0..000000000
--- a/Library/Homebrew/blacklist.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-def blacklisted?(name)
- case name.downcase
- when "gem", /^rubygems?$/ then <<-EOS.undent
- Homebrew provides gem via: `brew install ruby`.
- EOS
- when "tex", "tex-live", "texlive", "latex" then <<-EOS.undent
- Installing TeX from source is weird and gross, requires a lot of patches,
- and only builds 32-bit (and thus can't use Homebrew dependencies)
-
- We recommend using a MacTeX distribution: https://www.tug.org/mactex/
-
- You can install it with Homebrew-Cask:
- brew cask install mactex
- EOS
- when "pip" then <<-EOS.undent
- Homebrew provides pip via: `brew install python`. However you will then
- have two Pythons installed on your Mac, so alternatively you can install
- pip via the instructions at:
- #{Formatter.url("https://pip.readthedocs.io/en/stable/installing/")}
- EOS
- when "pil" then <<-EOS.undent
- Instead of PIL, consider `pip install pillow` or `brew install Homebrew/python/pillow`.
- EOS
- when "macruby" then <<-EOS.undent
- MacRuby is not packaged and is on an indefinite development hiatus.
- You can read more about it at:
- #{Formatter.url("https://github.com/MacRuby/MacRuby")}
- EOS
- when /(lib)?lzma/
- "lzma is now part of the xz formula."
- when "gtest", "googletest", "google-test" then <<-EOS.undent
- Installing gtest system-wide is not recommended; it should be vendored
- in your projects that use it.
- EOS
- when "gmock", "googlemock", "google-mock" then <<-EOS.undent
- Installing gmock system-wide is not recommended; it should be vendored
- in your projects that use it.
- EOS
- when "sshpass" then <<-EOS.undent
- We won't add sshpass because it makes it too easy for novice SSH users to
- ruin SSH's security.
- EOS
- when "gsutil" then <<-EOS.undent
- Install gsutil with `pip install gsutil`
- EOS
- when "clojure" then <<-EOS.undent
- Clojure isn't really a program but a library managed as part of a
- project and Leiningen is the user interface to that library.
-
- To install Clojure you should install Leiningen:
- brew install leiningen
- and then follow the tutorial:
- #{Formatter.url("https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md")}
- EOS
- when "osmium" then <<-EOS.undent
- The creator of Osmium requests that it not be packaged and that people
- use the GitHub master branch instead.
- EOS
- when "gfortran" then <<-EOS.undent
- GNU Fortran is now provided as part of GCC, and can be installed with:
- brew install gcc
- EOS
- when "play" then <<-EOS.undent
- Play 2.3 replaces the play command with activator:
- brew install typesafe-activator
-
- You can read more about this change at:
- #{Formatter.url("https://www.playframework.com/documentation/2.3.x/Migration23")}
- #{Formatter.url("https://www.playframework.com/documentation/2.3.x/Highlights23")}
- EOS
- when "haskell-platform" then <<-EOS.undent
- We no longer package haskell-platform. Consider installing ghc
- and cabal-install instead:
- brew install ghc cabal-install
-
- You can install with Homebrew-Cask:
- brew cask install haskell-platform
- EOS
- when "mysqldump-secure" then <<-EOS.undent
- The creator of mysqldump-secure tried to game our popularity metrics.
- EOS
- when "ngrok" then <<-EOS.undent
- Upstream sunsetted 1.x in March 2016 and 2.x is not open-source.
-
- If you wish to use the 2.x release you can install with Homebrew-Cask:
- brew cask install ngrok
- EOS
- end
-end
-alias generic_blacklisted? blacklisted?
-
-require "extend/os/blacklist"
diff --git a/Library/Homebrew/build_options.rb b/Library/Homebrew/build_options.rb
index d9020ecba..6c6952d71 100644
--- a/Library/Homebrew/build_options.rb
+++ b/Library/Homebrew/build_options.rb
@@ -47,7 +47,6 @@ class BuildOptions
def bottle?
include? "build-bottle"
end
- alias build_bottle? bottle?
# True if a {Formula} is being built with {Formula.head} instead of {Formula.stable}.
# <pre>args << "--some-new-stuff" if build.head?</pre>
diff --git a/Library/Homebrew/cask/lib/hbc/artifact/binary.rb b/Library/Homebrew/cask/lib/hbc/artifact/binary.rb
index 06bdfe157..21d123ab9 100644
--- a/Library/Homebrew/cask/lib/hbc/artifact/binary.rb
+++ b/Library/Homebrew/cask/lib/hbc/artifact/binary.rb
@@ -9,7 +9,12 @@ module Hbc
def link
super
- FileUtils.chmod "+x", source
+ return if source.executable?
+ if source.writable?
+ FileUtils.chmod "+x", source
+ else
+ @command.run!("/bin/chmod", args: ["+x", source], sudo: true)
+ end
end
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/artifact/moved.rb b/Library/Homebrew/cask/lib/hbc/artifact/moved.rb
index 01e98ac35..eaaa49e20 100644
--- a/Library/Homebrew/cask/lib/hbc/artifact/moved.rb
+++ b/Library/Homebrew/cask/lib/hbc/artifact/moved.rb
@@ -31,20 +31,26 @@ module Hbc
ohai "Moving #{self.class.artifact_english_name} '#{source.basename}' to '#{target}'."
target.dirname.mkpath
- FileUtils.move(source, target)
+
+ if target.parent.writable?
+ FileUtils.move(source, target)
+ else
+ SystemCommand.run("/bin/mv", args: [source, target], sudo: true)
+ end
+
add_altname_metadata target, source.basename.to_s
end
def delete
ohai "Removing #{self.class.artifact_english_name} '#{target}'."
- return unless Utils.path_occupied?(target)
-
raise CaskError, "Cannot remove undeletable #{self.class.artifact_english_name}." if MacOS.undeletable?(target)
- if force
- Utils.gain_permissions_remove(target, command: @command)
- else
+ return unless Utils.path_occupied?(target)
+
+ if target.parent.writable? && !force
target.rmtree
+ else
+ Utils.gain_permissions_remove(target, command: @command)
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/cask.rb b/Library/Homebrew/cask/lib/hbc/cask.rb
index cf5f2b37a..a193a394e 100644
--- a/Library/Homebrew/cask/lib/hbc/cask.rb
+++ b/Library/Homebrew/cask/lib/hbc/cask.rb
@@ -1,10 +1,12 @@
require "forwardable"
require "hbc/dsl"
+require "hbc/metadata"
module Hbc
class Cask
extend Forwardable
+ include Metadata
attr_reader :token, :sourcefile_path
def initialize(token, sourcefile_path: nil, &block)
@@ -20,55 +22,9 @@ module Hbc
define_method(method_name) { @dsl.send(method_name) }
end
- METADATA_SUBDIR = ".metadata".freeze
-
- def metadata_master_container_path
- @metadata_master_container_path ||= caskroom_path.join(METADATA_SUBDIR)
- end
-
- def metadata_versioned_container_path
- cask_version = version ? version : :unknown
- metadata_master_container_path.join(cask_version.to_s)
- end
-
- def metadata_path(timestamp = :latest, create = false)
- if create && timestamp == :latest
- raise CaskError, "Cannot create metadata path when timestamp is :latest"
- end
- path = if timestamp == :latest
- Pathname.glob(metadata_versioned_container_path.join("*")).sort.last
- elsif timestamp == :now
- Utils.nowstamp_metadata_path(metadata_versioned_container_path)
- else
- metadata_versioned_container_path.join(timestamp)
- end
- if create
- odebug "Creating metadata directory #{path}"
- FileUtils.mkdir_p path
- end
- path
- end
-
- def metadata_subdir(leaf, timestamp = :latest, create = false)
- if create && timestamp == :latest
- raise CaskError, "Cannot create metadata subdir when timestamp is :latest"
- end
- unless leaf.respond_to?(:length) && !leaf.empty?
- raise CaskError, "Cannot create metadata subdir for empty leaf"
- end
- parent = metadata_path(timestamp, create)
- return nil unless parent.respond_to?(:join)
- subdir = parent.join(leaf)
- if create
- odebug "Creating metadata subdirectory #{subdir}"
- FileUtils.mkdir_p subdir
- end
- subdir
- end
-
def timestamped_versions
- Pathname.glob(metadata_master_container_path.join("*", "*"))
- .map { |p| p.relative_path_from(metadata_master_container_path) }
+ Pathname.glob(metadata_timestamped_path(version: "*", timestamp: "*"))
+ .map { |p| p.relative_path_from(p.parent.parent) }
.sort_by(&:basename) # sort by timestamp
.map { |p| p.split.map(&:to_s) }
end
diff --git a/Library/Homebrew/cask/lib/hbc/cli/doctor.rb b/Library/Homebrew/cask/lib/hbc/cli/doctor.rb
index 6b2f4caab..031f78824 100644
--- a/Library/Homebrew/cask/lib/hbc/cli/doctor.rb
+++ b/Library/Homebrew/cask/lib/hbc/cli/doctor.rb
@@ -92,7 +92,7 @@ module Hbc
def self.render_staging_location(path)
path = Pathname.new(user_tilde(path.to_s))
if !path.exist?
- "#{path} #{error_string "error: path does not exist"}}"
+ "#{path} #{error_string "error: path does not exist"}"
elsif !path.writable?
"#{path} #{error_string "error: not writable by current user"}"
else
diff --git a/Library/Homebrew/cask/lib/hbc/cli/uninstall.rb b/Library/Homebrew/cask/lib/hbc/cli/uninstall.rb
index 6887aaf4f..1ee3230ad 100644
--- a/Library/Homebrew/cask/lib/hbc/cli/uninstall.rb
+++ b/Library/Homebrew/cask/lib/hbc/cli/uninstall.rb
@@ -12,15 +12,9 @@ module Hbc
raise CaskNotInstalledError, cask unless cask.installed? || force
- latest_installed_version = cask.timestamped_versions.last
-
- unless latest_installed_version.nil?
- latest_installed_cask_file = cask.metadata_master_container_path
- .join(latest_installed_version.join(File::Separator),
- "Casks", "#{cask_token}.rb")
-
+ if cask.installed? && !cask.installed_caskfile.nil?
# use the same cask file that was used for installation, if possible
- cask = CaskLoader.load_from_file(latest_installed_cask_file) if latest_installed_cask_file.exist?
+ cask = CaskLoader.load_from_file(cask.installed_caskfile) if cask.installed_caskfile.exist?
end
Installer.new(cask, force: force).uninstall
diff --git a/Library/Homebrew/cask/lib/hbc/container.rb b/Library/Homebrew/cask/lib/hbc/container.rb
index fc7246f3d..961e31968 100644
--- a/Library/Homebrew/cask/lib/hbc/container.rb
+++ b/Library/Homebrew/cask/lib/hbc/container.rb
@@ -4,6 +4,7 @@ require "hbc/container/bzip2"
require "hbc/container/cab"
require "hbc/container/criteria"
require "hbc/container/dmg"
+require "hbc/container/executable"
require "hbc/container/generic_unar"
require "hbc/container/gzip"
require "hbc/container/lzma"
@@ -39,6 +40,7 @@ module Hbc
Gzip, # pure gzip
Lzma, # pure lzma
Xz, # pure xz
+ Executable,
]
# for explicit use only (never autodetected):
# Hbc::Container::Naked
@@ -59,7 +61,7 @@ module Hbc
begin
const_get(type.to_s.split("_").map(&:capitalize).join)
rescue NameError
- false
+ nil
end
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/container/executable.rb b/Library/Homebrew/cask/lib/hbc/container/executable.rb
new file mode 100644
index 000000000..848f6d4be
--- /dev/null
+++ b/Library/Homebrew/cask/lib/hbc/container/executable.rb
@@ -0,0 +1,18 @@
+require "hbc/container/naked"
+require "vendor/macho/macho"
+
+module Hbc
+ class Container
+ class Executable < Naked
+ def self.me?(criteria)
+ return true if criteria.magic_number(/^#!\s*\S+/)
+
+ begin
+ MachO.open(criteria.path).header.executable?
+ rescue MachO::MagicError
+ false
+ end
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/lib/hbc/dsl/container.rb b/Library/Homebrew/cask/lib/hbc/dsl/container.rb
index ab260c98c..caaf25bca 100644
--- a/Library/Homebrew/cask/lib/hbc/dsl/container.rb
+++ b/Library/Homebrew/cask/lib/hbc/dsl/container.rb
@@ -1,3 +1,5 @@
+require "hbc/container"
+
module Hbc
class DSL
class Container
@@ -13,9 +15,12 @@ module Hbc
@pairs = pairs
pairs.each do |key, value|
raise "invalid container key: '#{key.inspect}'" unless VALID_KEYS.include?(key)
- writer_method = "#{key}=".to_sym
- send(writer_method, value)
+ send(:"#{key}=", value)
end
+
+ return if type.nil?
+ return unless Hbc::Container.from_type(type).nil?
+ raise "invalid container type: #{type.inspect}"
end
def to_yaml
diff --git a/Library/Homebrew/cask/lib/hbc/installer.rb b/Library/Homebrew/cask/lib/hbc/installer.rb
index 51b0490f5..f02f07806 100644
--- a/Library/Homebrew/cask/lib/hbc/installer.rb
+++ b/Library/Homebrew/cask/lib/hbc/installer.rb
@@ -316,15 +316,13 @@ module Hbc
end
def save_caskfile
- unless (old_savedirs = Pathname.glob(@cask.metadata_path("*"))).empty?
- old_savedirs.each(&:rmtree)
- end
+ old_savedir = @cask.metadata_timestamped_path
return unless @cask.sourcefile_path
- savedir = @cask.metadata_subdir("Casks", :now, true)
- savedir.mkpath
+ savedir = @cask.metadata_subdir("Casks", timestamp: :now, create: true)
FileUtils.copy @cask.sourcefile_path, savedir
+ old_savedir.rmtree unless old_savedir.nil?
end
def uninstall
@@ -376,15 +374,15 @@ module Hbc
gain_permissions_remove(@cask.staged_path) if !@cask.staged_path.nil? && @cask.staged_path.exist?
# Homebrew-Cask metadata
- if @cask.metadata_versioned_container_path.respond_to?(:children) &&
- @cask.metadata_versioned_container_path.exist?
- @cask.metadata_versioned_container_path.children.each do |subdir|
+ if @cask.metadata_versioned_path.respond_to?(:children) &&
+ @cask.metadata_versioned_path.exist?
+ @cask.metadata_versioned_path.children.each do |subdir|
unless PERSISTENT_METADATA_SUBDIRS.include?(subdir.basename)
gain_permissions_remove(subdir)
end
end
end
- @cask.metadata_versioned_container_path.rmdir_if_possible
+ @cask.metadata_versioned_path.rmdir_if_possible
@cask.metadata_master_container_path.rmdir_if_possible
# toplevel staged distribution
diff --git a/Library/Homebrew/cask/lib/hbc/metadata.rb b/Library/Homebrew/cask/lib/hbc/metadata.rb
new file mode 100644
index 000000000..344c38cee
--- /dev/null
+++ b/Library/Homebrew/cask/lib/hbc/metadata.rb
@@ -0,0 +1,73 @@
+module Hbc
+ module Metadata
+ METADATA_SUBDIR = ".metadata".freeze
+
+ def metadata_master_container_path
+ @metadata_master_container_path ||= caskroom_path.join(METADATA_SUBDIR)
+ end
+
+ def metadata_versioned_path(version: self.version)
+ cask_version = (version || :unknown).to_s
+
+ if cask_version.empty?
+ raise CaskError, "Cannot create metadata path with empty version."
+ end
+
+ metadata_master_container_path.join(cask_version)
+ end
+
+ def metadata_timestamped_path(version: self.version, timestamp: :latest, create: false)
+ if create && timestamp == :latest
+ raise CaskError, "Cannot create metadata path when timestamp is :latest."
+ end
+
+ path = if timestamp == :latest
+ Pathname.glob(metadata_versioned_path(version: version).join("*")).sort.last
+ else
+ timestamp = new_timestamp if timestamp == :now
+ metadata_versioned_path(version: version).join(timestamp)
+ end
+
+ if create && !path.directory?
+ odebug "Creating metadata directory #{path}."
+ path.mkpath
+ end
+
+ path
+ end
+
+ def metadata_subdir(leaf, version: self.version, timestamp: :latest, create: false)
+ if create && timestamp == :latest
+ raise CaskError, "Cannot create metadata subdir when timestamp is :latest."
+ end
+
+ unless leaf.respond_to?(:empty?) && !leaf.empty?
+ raise CaskError, "Cannot create metadata subdir for empty leaf."
+ end
+
+ parent = metadata_timestamped_path(version: version, timestamp: timestamp, create: create)
+
+ return nil if parent.nil?
+
+ subdir = parent.join(leaf)
+
+ if create && !subdir.directory?
+ odebug "Creating metadata subdirectory #{subdir}."
+ subdir.mkpath
+ end
+
+ subdir
+ end
+
+ private
+
+ def new_timestamp(time = Time.now)
+ time = time.utc
+
+ timestamp = time.strftime("%Y%m%d%H%M%S")
+ fraction = format("%.3f", time.to_f - time.to_i)[1..-1]
+
+ timestamp.concat(fraction)
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/lib/hbc/pkg.rb b/Library/Homebrew/cask/lib/hbc/pkg.rb
index 902d56449..c9aa3180f 100644
--- a/Library/Homebrew/cask/lib/hbc/pkg.rb
+++ b/Library/Homebrew/cask/lib/hbc/pkg.rb
@@ -63,7 +63,10 @@ module Hbc
end
def pkgutil_bom_all
- @pkgutil_bom_all ||= info.fetch("paths").keys.map { |p| root.join(p) }
+ @pkgutil_bom_all ||= @command.run!("/usr/sbin/pkgutil", args: ["--files", package_id])
+ .stdout
+ .split("\n")
+ .map { |path| root.join(path) }
end
def root
@@ -71,7 +74,7 @@ module Hbc
end
def info
- @info ||= @command.run!("/usr/sbin/pkgutil", args: ["--export-plist", package_id])
+ @info ||= @command.run!("/usr/sbin/pkgutil", args: ["--pkg-info-plist", package_id])
.plist
end
diff --git a/Library/Homebrew/cask/lib/hbc/scopes.rb b/Library/Homebrew/cask/lib/hbc/scopes.rb
index db12409e5..149c2c343 100644
--- a/Library/Homebrew/cask/lib/hbc/scopes.rb
+++ b/Library/Homebrew/cask/lib/hbc/scopes.rb
@@ -6,8 +6,7 @@ module Hbc
module ClassMethods
def all
- @all_casks ||= {}
- all_tokens.map { |t| @all_casks[t] ||= load(t) }
+ all_tokens.map(&CaskLoader.public_method(:load))
end
def all_tapped_cask_dirs
diff --git a/Library/Homebrew/cask/lib/hbc/system_command.rb b/Library/Homebrew/cask/lib/hbc/system_command.rb
index c14079bc8..f1ec34025 100644
--- a/Library/Homebrew/cask/lib/hbc/system_command.rb
+++ b/Library/Homebrew/cask/lib/hbc/system_command.rb
@@ -92,17 +92,25 @@ module Hbc
def each_line_from(sources)
loop do
- readable_sources = IO.select(sources)[0]
- readable_sources.delete_if(&:eof?).first(1).each do |source|
+ selected_sources = IO.select(sources, [], [], 10)
+
+ break if selected_sources.nil?
+
+ readable_sources = selected_sources[0].delete_if(&:eof?)
+
+ readable_sources.each do |source|
type = (source == sources[0] ? :stdout : :stderr)
+
begin
yield(type, source.readline_nonblock || "")
rescue IO::WaitReadable, EOFError
next
end
end
+
break if readable_sources.empty?
end
+
sources.each(&:close_read)
end
diff --git a/Library/Homebrew/cask/lib/hbc/utils.rb b/Library/Homebrew/cask/lib/hbc/utils.rb
index 3fc817dd5..2a5acbc88 100644
--- a/Library/Homebrew/cask/lib/hbc/utils.rb
+++ b/Library/Homebrew/cask/lib/hbc/utils.rb
@@ -4,8 +4,7 @@ require "stringio"
require "hbc/utils/file"
-PREBUG_URL = "https://github.com/caskroom/homebrew-cask/blob/master/doc/reporting_bugs/pre_bug_report.md".freeze
-ISSUES_URL = "https://github.com/caskroom/homebrew-cask#reporting-bugs".freeze
+BUG_REPORTS_URL = "https://github.com/caskroom/homebrew-cask#reporting-bugs".freeze
# monkeypatch Object - not a great idea
class Object
@@ -39,7 +38,15 @@ module Hbc
module Utils
def self.gain_permissions_remove(path, command: SystemCommand)
if path.respond_to?(:rmtree) && path.exist?
- gain_permissions(path, ["-R"], command, &:rmtree)
+ gain_permissions(path, ["-R"], command) do |p|
+ if p.parent.writable?
+ p.rmtree
+ else
+ command.run("/bin/rm",
+ args: command_args + ["-r", "-f", "--", p],
+ sudo: true)
+ end
+ end
elsif File.symlink?(path)
gain_permissions(path, ["-h"], command, &FileUtils.method(:rm_f))
end
@@ -96,11 +103,7 @@ module Hbc
def self.error_message_with_suggestions
<<-EOS.undent
Follow the instructions here:
- #{Formatter.url(PREBUG_URL)}
-
- If this doesn’t fix the problem, please report this bug:
- #{Formatter.url(ISSUES_URL)}
-
+ #{Formatter.url(BUG_REPORTS_URL)}
EOS
end
@@ -112,16 +115,5 @@ module Hbc
opoo(poo.join(" ") + "\n" + error_message_with_suggestions)
end
-
- def self.nowstamp_metadata_path(container_path)
- @timenow ||= Time.now.gmtime
- return unless container_path.respond_to?(:join)
-
- precision = 3
- timestamp = @timenow.strftime("%Y%m%d%H%M%S")
- fraction = format("%.#{precision}f", @timenow.to_f - @timenow.to_i)[1..-1]
- timestamp.concat(fraction)
- container_path.join(timestamp)
- end
end
end
diff --git a/Library/Homebrew/caveats.rb b/Library/Homebrew/caveats.rb
index f5543cf49..b7c0a60c9 100644
--- a/Library/Homebrew/caveats.rb
+++ b/Library/Homebrew/caveats.rb
@@ -16,11 +16,9 @@ class Caveats
f.build = build
end
caveats << keg_only_text
- caveats << bash_completion_caveats
- caveats << zsh_completion_caveats
- caveats << fish_completion_caveats
- caveats << zsh_function_caveats
- caveats << fish_function_caveats
+ caveats << function_completion_caveats(:bash)
+ caveats << function_completion_caveats(:zsh)
+ caveats << function_completion_caveats(:fish)
caveats << plist_caveats
caveats << python_caveats
caveats << elisp_caveats
@@ -51,10 +49,10 @@ class Caveats
if f.bin.directory? || f.sbin.directory?
s << "\nIf you need to have this software first in your PATH run:\n"
if f.bin.directory?
- s << " #{Utils::Shell.prepend_path_in_shell_profile(f.opt_bin.to_s)}\n"
+ s << " #{Utils::Shell.prepend_path_in_profile(f.opt_bin.to_s)}\n"
end
if f.sbin.directory?
- s << " #{Utils::Shell.prepend_path_in_shell_profile(f.opt_sbin.to_s)}\n"
+ s << " #{Utils::Shell.prepend_path_in_profile(f.opt_sbin.to_s)}\n"
end
end
@@ -72,56 +70,35 @@ class Caveats
s << "\n"
end
- def bash_completion_caveats
+ def function_completion_caveats(shell)
return unless keg
- return unless keg.completion_installed?(:bash)
+ return unless which(shell.to_s)
- <<-EOS.undent
- Bash completion has been installed to:
- #{HOMEBREW_PREFIX}/etc/bash_completion.d
- EOS
- end
-
- def zsh_completion_caveats
- return unless keg
- return unless keg.completion_installed?(:zsh)
-
- <<-EOS.undent
- zsh completion has been installed to:
- #{HOMEBREW_PREFIX}/share/zsh/site-functions
- EOS
- end
-
- def fish_completion_caveats
- return unless keg
- return unless keg.completion_installed?(:fish)
- return unless which("fish")
+ completion_installed = keg.completion_installed?(shell)
+ functions_installed = keg.functions_installed?(shell)
+ return unless completion_installed || functions_installed
- <<-EOS.undent
- fish completion has been installed to:
- #{HOMEBREW_PREFIX}/share/fish/vendor_completions.d
- EOS
- end
+ installed = []
+ installed << "completions" if completion_installed
+ installed << "functions" if functions_installed
- def zsh_function_caveats
- return unless keg
- return unless keg.zsh_functions_installed?
-
- <<-EOS.undent
- zsh functions have been installed to:
- #{HOMEBREW_PREFIX}/share/zsh/site-functions
- EOS
- end
-
- def fish_function_caveats
- return unless keg
- return unless keg.fish_functions_installed?
- return unless which("fish")
-
- <<-EOS.undent
- fish functions have been installed to:
- #{HOMEBREW_PREFIX}/share/fish/vendor_functions.d
- EOS
+ case shell
+ when :bash
+ <<-EOS.undent
+ Bash completion has been installed to:
+ #{HOMEBREW_PREFIX}/etc/bash_completion.d
+ EOS
+ when :zsh
+ <<-EOS.undent
+ zsh #{installed.join(" and ")} have been installed to:
+ #{HOMEBREW_PREFIX}/share/zsh/site-functions
+ EOS
+ when :fish
+ fish_caveats = "fish #{installed.join(" and ")} have been installed to:"
+ fish_caveats << "\n #{HOMEBREW_PREFIX}/share/fish/vendor_completions.d" if completion_installed
+ fish_caveats << "\n #{HOMEBREW_PREFIX}/share/fish/vendor_functions.d" if functions_installed
+ fish_caveats
+ end
end
def python_caveats
diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb
index 615a7ce9e..d1f0b2516 100644
--- a/Library/Homebrew/cleanup.rb
+++ b/Library/Homebrew/cleanup.rb
@@ -6,7 +6,9 @@ module Homebrew
module Cleanup
@disk_cleanup_size = 0
- def self.cleanup
+ module_function
+
+ def cleanup
cleanup_cellar
cleanup_cache
cleanup_logs
@@ -15,34 +17,41 @@ module Homebrew
rm_ds_store
end
- def self.update_disk_cleanup_size(path_size)
+ def update_disk_cleanup_size(path_size)
@disk_cleanup_size += path_size
end
- def self.disk_cleanup_size
+ def disk_cleanup_size
@disk_cleanup_size
end
- def self.cleanup_formula(formula)
- formula.eligible_kegs_for_cleanup.each do |keg|
- cleanup_path(keg) { keg.uninstall }
- end
+ def unremovable_kegs
+ @unremovable_kegs ||= []
+ end
+
+ def cleanup_cellar(formulae = Formula.installed)
+ formulae.each(&method(:cleanup_formula))
+ end
+
+ def cleanup_formula(formula)
+ formula.eligible_kegs_for_cleanup.each(&method(:cleanup_keg))
end
- def self.cleanup_logs
+ def cleanup_keg(keg)
+ cleanup_path(keg) { keg.uninstall }
+ rescue Errno::EACCES => e
+ opoo e.message
+ unremovable_kegs << keg
+ end
+
+ def cleanup_logs
return unless HOMEBREW_LOGS.directory?
HOMEBREW_LOGS.subdirs.each do |dir|
cleanup_path(dir) { dir.rmtree } if prune?(dir, days_default: 14)
end
end
- def self.cleanup_cellar
- Formula.installed.each do |formula|
- cleanup_formula formula
- end
- end
-
- def self.cleanup_cache(cache = HOMEBREW_CACHE)
+ def cleanup_cache(cache = HOMEBREW_CACHE)
return unless cache.directory?
cache.children.each do |path|
if path.to_s.end_with? ".incomplete"
@@ -97,7 +106,7 @@ module Homebrew
end
end
- def self.cleanup_path(path)
+ def cleanup_path(path)
if ARGV.dry_run?
puts "Would remove: #{path} (#{path.abv})"
else
@@ -108,7 +117,7 @@ module Homebrew
update_disk_cleanup_size(path.disk_usage)
end
- def self.cleanup_lockfiles
+ def cleanup_lockfiles
return unless HOMEBREW_LOCK_DIR.directory?
candidates = HOMEBREW_LOCK_DIR.children
lockfiles = candidates.select(&:file?)
@@ -118,7 +127,7 @@ module Homebrew
end
end
- def self.rm_ds_store
+ def rm_ds_store
paths = Queue.new
%w[Cellar Frameworks Library bin etc include lib opt sbin share var]
.map { |p| HOMEBREW_PREFIX/p }.each { |p| paths << p if p.exist? }
@@ -136,7 +145,7 @@ module Homebrew
workers.map(&:join)
end
- def self.prune?(path, options = {})
+ def prune?(path, options = {})
@time ||= Time.now
path_modified_time = path.mtime
diff --git a/Library/Homebrew/cmd/--env.rb b/Library/Homebrew/cmd/--env.rb
index 323964dad..90beee89c 100644
--- a/Library/Homebrew/cmd/--env.rb
+++ b/Library/Homebrew/cmd/--env.rb
@@ -22,9 +22,9 @@ module Homebrew
# legacy behavior
shell = :bash unless $stdout.tty?
elsif shell_value == "auto"
- shell = Utils::Shell.parent_shell || Utils::Shell.preferred_shell
+ shell = Utils::Shell.parent || Utils::Shell.preferred
elsif shell_value
- shell = Utils::Shell.path_to_shell(shell_value)
+ shell = Utils::Shell.from_path(shell_value)
end
env_keys = build_env_keys(ENV)
diff --git a/Library/Homebrew/cmd/cleanup.rb b/Library/Homebrew/cmd/cleanup.rb
index 126309579..d8f669e85 100644
--- a/Library/Homebrew/cmd/cleanup.rb
+++ b/Library/Homebrew/cmd/cleanup.rb
@@ -21,11 +21,14 @@ module Homebrew
if ARGV.named.empty?
Cleanup.cleanup
else
- ARGV.resolved_formulae.each { |f| Cleanup.cleanup_formula f }
+ Cleanup.cleanup_cellar(ARGV.resolved_formulae)
end
- return if Cleanup.disk_cleanup_size.zero?
+ report_disk_usage unless Cleanup.disk_cleanup_size.zero?
+ report_unremovable_kegs unless Cleanup.unremovable_kegs.empty?
+ end
+ def report_disk_usage
disk_space = disk_usage_readable(Cleanup.disk_cleanup_size)
if ARGV.dry_run?
ohai "This operation would free approximately #{disk_space} of disk space."
@@ -33,4 +36,11 @@ module Homebrew
ohai "This operation has freed approximately #{disk_space} of disk space."
end
end
+
+ def report_unremovable_kegs
+ ofail <<-EOS.undent
+ Could not cleanup old kegs! Fix your permissions on:
+ #{Cleanup.unremovable_kegs.join "\n "}
+ EOS
+ end
end
diff --git a/Library/Homebrew/cmd/fetch.rb b/Library/Homebrew/cmd/fetch.rb
index 820a27e31..006c63746 100644
--- a/Library/Homebrew/cmd/fetch.rb
+++ b/Library/Homebrew/cmd/fetch.rb
@@ -8,14 +8,14 @@
#: If `-v` is passed, do a verbose VCS checkout, if the URL represents a VCS.
#: This is useful for seeing if an existing VCS cache has been updated.
#:
-#: If `--force` is passed, remove a previously cached version and re-fetch.
+#: If `--force` (or `-f`) is passed, remove a previously cached version and re-fetch.
#:
#: If `--retry` is passed, retry if a download fails or re-download if the
#: checksum of a previously cached version no longer matches.
#:
#: If `--deps` is passed, also download dependencies for any listed <formulae>.
#:
-#: If `--build-from-source` is passed, download the source rather than a
+#: If `--build-from-source` (or `-s`) is passed, download the source rather than a
#: bottle.
#:
#: If `--force-bottle` is passed, download a bottle if it exists for the
diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb
index b7de0005c..e7ad6821d 100644
--- a/Library/Homebrew/cmd/info.rb
+++ b/Library/Homebrew/cmd/info.rb
@@ -16,7 +16,7 @@
#: See the docs for examples of using the JSON output:
#: <http://docs.brew.sh/Querying-Brew.html>
-require "blacklist"
+require "missing_formula"
require "caveats"
require "options"
require "formula"
@@ -54,10 +54,12 @@ module Homebrew
else
info_formula Formulary.find_with_priority(f)
end
- rescue FormulaUnavailableError
- # No formula with this name, try a blacklist lookup
- raise unless (blacklist = blacklisted?(f))
- puts blacklist
+ 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
diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb
index c825e2796..394b31db0 100644
--- a/Library/Homebrew/cmd/install.rb
+++ b/Library/Homebrew/cmd/install.rb
@@ -4,7 +4,7 @@
#: <formula> is usually the name of the formula to install, but it can be specified
#: in several different ways. See [SPECIFYING FORMULAE][].
#:
-#: If `--debug` is passed and brewing fails, open an interactive debugging
+#: If `--debug` (or `-d`) is passed and brewing fails, open an interactive debugging
#: session with access to IRB or a shell inside the temporary build directory.
#:
#: If `--env=std` is passed, use the standard build environment instead of superenv.
@@ -24,7 +24,7 @@
#: `gcc-4.2` for Apple's GCC 4.2, or `gcc-4.9` for a Homebrew-provided GCC
#: 4.9.
#:
-#: If `--build-from-source` or `-s` is passed, compile the specified <formula> from
+#: If `--build-from-source` (or `-s`) is passed, compile the specified <formula> from
#: source even if a bottle is provided. Dependencies will still be installed
#: from bottles if they are available.
#:
@@ -48,14 +48,15 @@
#: during installation.
#:
#: * `install` `--interactive` [`--git`] <formula>:
-#: Download and patch <formula>, then open a shell. This allows the user to
-#: run `./configure --help` and otherwise determine how to turn the software
-#: package into a Homebrew formula.
+#: If `--interactive` (or `-i`) is passed, download and patch <formula>, then
+#: open a shell. This allows the user to run `./configure --help` and
+#: otherwise determine how to turn the software package into a Homebrew
+#: formula.
#:
-#: If `--git` is passed, Homebrew will create a Git repository, useful for
+#: If `--git` (or `-g`) is passed, Homebrew will create a Git repository, useful for
#: creating patches to the software.
-require "blacklist"
+require "missing_formula"
require "diagnostic"
require "cmd/search"
require "formula_installer"
@@ -193,56 +194,68 @@ module Homebrew
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
+ unless tab.installed_on_request
+ tab.installed_on_request = true
+ tab.write
+ end
end
perform_preinstall_checks
- formulae.each { |f| install_formula(f) }
- rescue FormulaClassUnavailableError => e
+ formulae.each do |f|
+ Migrator.migrate_if_needed(f)
+ install_formula(f)
+ end
+ rescue FormulaUnreadableError, FormulaClassUnavailableError,
+ TapFormulaUnreadableError, TapFormulaClassUnavailableError => 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 (blacklist = blacklisted?(e.name))
- ofail "#{e.message}\n#{blacklist}"
- elsif e.name == "updog"
+ 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
- ofail e.message
- 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
+ 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
+ # Do not search taps if the formula name is qualified
+ return if e.name.include?("/")
+ 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
diff --git a/Library/Homebrew/cmd/link.rb b/Library/Homebrew/cmd/link.rb
index 98cf98bf7..b8bd135e0 100644
--- a/Library/Homebrew/cmd/link.rb
+++ b/Library/Homebrew/cmd/link.rb
@@ -10,7 +10,7 @@
#: be linked or which would be deleted by `brew link --overwrite`, but will not
#: actually link or delete any files.
#:
-#: If `--force` is passed, Homebrew will allow keg-only formulae to be linked.
+#: If `--force` (or `-f`) is passed, Homebrew will allow keg-only formulae to be linked.
require "ostruct"
@@ -44,6 +44,7 @@ module Homebrew
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:"
@@ -53,6 +54,7 @@ module Homebrew
elsif mode.dry_run
puts "Would link:"
keg.link(mode)
+ puts_keg_only_path_message(keg) if keg_only
next
end
@@ -69,10 +71,25 @@ module Homebrew
else
puts "#{n} symlinks created"
end
+
+ if keg_only && !ARGV.homebrew_developer?
+ puts_keg_only_path_message(keg)
+ end
end
end
end
+ 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_profile(opt/"bin")}" if bin.directory?
+ puts " #{Utils::Shell.prepend_path_in_profile(opt/"sbin")}" if sbin.directory?
+ end
+
def keg_only?(rack)
Formulary.from_rack(rack).keg_only?
rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
diff --git a/Library/Homebrew/cmd/log.rb b/Library/Homebrew/cmd/log.rb
index 22a3ee11d..9323c762d 100644
--- a/Library/Homebrew/cmd/log.rb
+++ b/Library/Homebrew/cmd/log.rb
@@ -9,20 +9,32 @@ module Homebrew
def log
if ARGV.named.empty?
- cd HOMEBREW_REPOSITORY
- git_log
+ git_log HOMEBREW_REPOSITORY
else
path = Formulary.path(ARGV.named.first)
- cd path.dirname # supports taps
- git_log path
+ tap = Tap.from_path(path)
+ git_log path.dirname, path, tap
end
end
- def git_log(path = nil)
- if File.exist? "#{`git rev-parse --show-toplevel`.chomp}/.git/shallow"
+ 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 <<-EOS.undent
- The git repository is a shallow clone therefore the filtering may be incorrect.
- Use `git fetch --unshallow` to get the full repository.
+ #{name} is a shallow clone so only partial output will be shown.
+ To get a full clone run:
+ git -C "#{git_cd}" fetch --unshallow
EOS
end
args = ARGV.options_only
diff --git a/Library/Homebrew/cmd/migrate.rb b/Library/Homebrew/cmd/migrate.rb
index 2726b1480..951a2942e 100644
--- a/Library/Homebrew/cmd/migrate.rb
+++ b/Library/Homebrew/cmd/migrate.rb
@@ -2,7 +2,7 @@
#: Migrate renamed packages to new name, where <formulae> are old names of
#: packages.
#:
-#: If `--force` is passed, then treat installed <formulae> and passed <formulae>
+#: If `--force` (or `-f`) is passed, then treat installed <formulae> and passed <formulae>
#: like if they are from same taps and migrate them anyway.
require "migrator"
diff --git a/Library/Homebrew/cmd/outdated.rb b/Library/Homebrew/cmd/outdated.rb
index a18f4e399..f163212e1 100644
--- a/Library/Homebrew/cmd/outdated.rb
+++ b/Library/Homebrew/cmd/outdated.rb
@@ -7,7 +7,7 @@
#: If `--quiet` is passed, list only the names of outdated brews (takes
#: precedence over `--verbose`).
#:
-#: If `--verbose` is passed, display detailed version information.
+#: If `--verbose` (or `-v`) is passed, display detailed version information.
#:
#: If `--json=`<version> is passed, the output will be in JSON format. The only
#: valid version is `v1`.
@@ -64,7 +64,9 @@ module Homebrew
"#{full_name} (#{kegs.map(&:version).join(", ")})"
end.join(", ")
- puts "#{outdated_versions} < #{current_version}"
+ pinned_version = " [pinned at #{f.pinned_version}]" if f.pinned?
+
+ puts "#{outdated_versions} < #{current_version}#{pinned_version}"
else
puts f.full_installed_specified_name
end
@@ -86,7 +88,9 @@ module Homebrew
json << { name: f.full_name,
installed_versions: outdated_versions.collect(&:to_s),
- current_version: current_version }
+ current_version: current_version,
+ pinned: f.pinned?,
+ pinned_version: f.pinned_version }
end
puts JSON.generate(json)
diff --git a/Library/Homebrew/cmd/reinstall.rb b/Library/Homebrew/cmd/reinstall.rb
index 586405909..c625d2d97 100644
--- a/Library/Homebrew/cmd/reinstall.rb
+++ b/Library/Homebrew/cmd/reinstall.rb
@@ -15,6 +15,7 @@ module Homebrew
onoe "#{f.full_name} is pinned. You must unpin it to reinstall."
next
end
+ Migrator.migrate_if_needed(f)
reinstall_formula(f)
end
end
diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb
index e834a00b5..20221524a 100644
--- a/Library/Homebrew/cmd/search.rb
+++ b/Library/Homebrew/cmd/search.rb
@@ -14,7 +14,7 @@
#: Search for <text> in the given package manager's list.
require "formula"
-require "blacklist"
+require "missing_formula"
require "utils"
require "thread"
require "official_taps"
@@ -67,13 +67,12 @@ module Homebrew
if $stdout.tty?
count = local_results.length + tap_results.length
- if msg = blacklisted?(query)
+ if reason = Homebrew::MissingFormula.reason(query, silent: true)
if count > 0
puts
- puts "If you meant #{query.inspect} precisely:"
- puts
+ puts "If you meant #{query.inspect} specifically:"
end
- puts msg
+ puts reason
elsif count.zero?
puts "No formula found for #{query.inspect}."
begin
@@ -101,10 +100,8 @@ module Homebrew
raise SEARCH_ERROR_QUEUE.pop unless SEARCH_ERROR_QUEUE.empty?
end
- SEARCHABLE_TAPS = OFFICIAL_TAPS.map { |tap| ["Homebrew", tap] } + [
- %w[Caskroom cask],
- %w[Caskroom versions],
- ]
+ SEARCHABLE_TAPS = OFFICIAL_TAPS.map { |tap| ["Homebrew", tap] } +
+ OFFICIAL_CASK_TAPS.map { |tap| ["caskroom", tap] }
def query_regexp(query)
case query
@@ -127,7 +124,7 @@ module Homebrew
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"
+ user != "caskroom"
return []
end
diff --git a/Library/Homebrew/cmd/tap.rb b/Library/Homebrew/cmd/tap.rb
index 114c4a8b6..2a07c1b2f 100644
--- a/Library/Homebrew/cmd/tap.rb
+++ b/Library/Homebrew/cmd/tap.rb
@@ -63,17 +63,4 @@ module Homebrew
def full_clone?
ARGV.include?("--full") || ARGV.homebrew_developer?
end
-
- # @deprecated this method will be removed in the future, if no external commands use it.
- 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
end
diff --git a/Library/Homebrew/cmd/uninstall.rb b/Library/Homebrew/cmd/uninstall.rb
index 5d02ebd1e..9c51a0d1c 100644
--- a/Library/Homebrew/cmd/uninstall.rb
+++ b/Library/Homebrew/cmd/uninstall.rb
@@ -1,7 +1,7 @@
#: * `uninstall`, `rm`, `remove` [`--force`] [`--ignore-dependencies`] <formula>:
#: Uninstall <formula>.
#:
-#: If `--force` is passed, and there are multiple versions of <formula>
+#: If `--force` (or `-f`) is passed, and there are multiple versions of <formula>
#: installed, delete all installed versions.
#:
#: If `--ignore-dependencies` is passed, uninstalling won't fail, even if
diff --git a/Library/Homebrew/cmd/unpack.rb b/Library/Homebrew/cmd/unpack.rb
index 60d796d9f..89992e1f0 100644
--- a/Library/Homebrew/cmd/unpack.rb
+++ b/Library/Homebrew/cmd/unpack.rb
@@ -6,7 +6,7 @@
#: If `--patch` is passed, patches for <formulae> will be applied to the
#: unpacked source.
#:
-#: If `--git` is passed, a Git repository will be initialized in the unpacked
+#: If `--git` (or `-g`) is passed, a Git repository will be initialized in the unpacked
#: source. This is useful for creating patches for the software.
require "stringio"
diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb
index c13d82090..aa1fd244d 100644
--- a/Library/Homebrew/cmd/update-report.rb
+++ b/Library/Homebrew/cmd/update-report.rb
@@ -361,7 +361,10 @@ class Reporter
case status
when "A", "D"
- @report[status.to_sym] << tap.formula_file_to_name(src)
+ full_name = tap.formula_file_to_name(src)
+ name = full_name.split("/").last
+ new_tap = tap.tap_migrations[name]
+ @report[status.to_sym] << full_name unless new_tap
when "M"
begin
formula = Formulary.factory(tap.path/src)
@@ -499,9 +502,21 @@ class Reporter
end
def migrate_formula_rename
- report[:R].each do |old_full_name, new_full_name|
- old_name = old_full_name.split("/").last
- next unless (dir = HOMEBREW_CELLAR/old_name).directory? && !dir.subdirs.empty?
+ Formula.installed.each do |formula|
+ next unless Migrator.needs_migration?(formula)
+
+ oldname = formula.oldname
+ oldname_rack = HOMEBREW_CELLAR/oldname
+
+ if oldname_rack.subdirs.empty?
+ oldname_rack.rmdir_if_possible
+ next
+ end
+
+ new_name = tap.formula_renames[oldname]
+ next unless new_name
+
+ new_full_name = "#{tap}/#{new_name}"
begin
f = Formulary.factory(new_full_name)
@@ -510,13 +525,7 @@ class Reporter
next
end
- begin
- migrator = Migrator.new(f)
- migrator.migrate
- rescue Migrator::MigratorDifferentTapsError
- rescue Exception => e
- onoe e
- end
+ Migrator.migrate_if_needed(f)
end
end
@@ -573,14 +582,17 @@ class ReporterHub
def dump_formula_report(key, title)
formulae = select_formula(key).sort.map do |name, new_name|
# Format list items of renamed formulae
- if key == :R
+ case key
+ when :R
name = pretty_installed(name) if installed?(name)
new_name = pretty_installed(new_name) if installed?(new_name)
"#{name} -> #{new_name}"
+ when :A
+ name unless installed?(name)
else
installed?(name) ? pretty_installed(name) : name
end
- end
+ end.compact
return if formulae.empty?
# Dump formula list.
diff --git a/Library/Homebrew/cmd/update.sh b/Library/Homebrew/cmd/update.sh
index 5cfdb3f46..197a99f2e 100644
--- a/Library/Homebrew/cmd/update.sh
+++ b/Library/Homebrew/cmd/update.sh
@@ -5,7 +5,7 @@
#: If `--merge` is specified then `git merge` is used to include updates
#: (rather than `git rebase`).
#:
-#: If `--force` is specified then always do a slower, full update check even
+#: If `--force` (or `-f`) is specified then always do a slower, full update check even
#: if unnecessary.
# Hide shellcheck complaint:
diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb
index ed36b8f33..d007ff8c8 100644
--- a/Library/Homebrew/cmd/upgrade.rb
+++ b/Library/Homebrew/cmd/upgrade.rb
@@ -88,6 +88,7 @@ module Homebrew
end
formulae_to_install.each do |f|
+ Migrator.migrate_if_needed(f)
upgrade_formula(f)
next unless ARGV.include?("--cleanup")
next unless f.installed?
diff --git a/Library/Homebrew/cmd/uses.rb b/Library/Homebrew/cmd/uses.rb
index b1122c90a..bab174184 100644
--- a/Library/Homebrew/cmd/uses.rb
+++ b/Library/Homebrew/cmd/uses.rb
@@ -28,7 +28,16 @@ module Homebrew
def uses
raise FormulaUnspecifiedError if ARGV.named.empty?
- used_formulae = ARGV.formulae
+ used_formulae_missing = false
+ used_formulae = begin
+ ARGV.formulae
+ rescue FormulaUnavailableError => e
+ opoo e
+ used_formulae_missing = true
+ # If the formula doesn't exist: fake the needed formula object name.
+ ARGV.named.map { |name| OpenStruct.new name: name, full_name: name }
+ end
+
formulae = ARGV.include?("--installed") ? Formula.installed : Formula
recursive = ARGV.flag? "--recursive"
includes = []
@@ -115,5 +124,6 @@ module Homebrew
return if uses.empty?
puts Formatter.columns(uses.map(&:full_name))
+ odie "Missing formulae should not have dependents!" if used_formulae_missing
end
end
diff --git a/Library/Homebrew/compat.rb b/Library/Homebrew/compat.rb
index 92b687725..3c080f616 100644
--- a/Library/Homebrew/compat.rb
+++ b/Library/Homebrew/compat.rb
@@ -25,3 +25,4 @@ require "compat/tab"
require "compat/ENV/shared"
require "compat/ENV/std"
require "compat/ENV/super"
+require "compat/utils/shell"
diff --git a/Library/Homebrew/compat/ARGV.rb b/Library/Homebrew/compat/ARGV.rb
index 23d02ce1a..e5fa8188f 100644
--- a/Library/Homebrew/compat/ARGV.rb
+++ b/Library/Homebrew/compat/ARGV.rb
@@ -1,6 +1,6 @@
module HomebrewArgvExtension
def build_32_bit?
- # odeprecated "ARGV.build_32_bit?"
+ odeprecated "ARGV.build_32_bit?"
include? "--32-bit"
end
end
diff --git a/Library/Homebrew/compat/build_options.rb b/Library/Homebrew/compat/build_options.rb
index 52aa9b951..73722dadb 100644
--- a/Library/Homebrew/compat/build_options.rb
+++ b/Library/Homebrew/compat/build_options.rb
@@ -1,6 +1,11 @@
class BuildOptions
def build_32_bit?
- # odeprecated "build.build_32_bit?"
+ odeprecated "build.build_32_bit?"
include?("32-bit") && option_defined?("32-bit")
end
+
+ def build_bottle?
+ odeprecated "build.build_bottle?", "build.bottle?"
+ bottle?
+ end
end
diff --git a/Library/Homebrew/compat/dependency_collector.rb b/Library/Homebrew/compat/dependency_collector.rb
index bd72c55d4..fbcf1c2a0 100644
--- a/Library/Homebrew/compat/dependency_collector.rb
+++ b/Library/Homebrew/compat/dependency_collector.rb
@@ -14,7 +14,6 @@ class DependencyCollector
output_deprecation(spec, tags)
Dependency.new(spec.to_s, tags)
when :apr
- # TODO: reenable in future when we've fixed a few of the audits.
# output_deprecation(spec, tags, "apr-util")
Dependency.new("apr-util", tags)
when :libltdl
diff --git a/Library/Homebrew/compat/global.rb b/Library/Homebrew/compat/global.rb
index 797e9ffe5..82c452cc0 100644
--- a/Library/Homebrew/compat/global.rb
+++ b/Library/Homebrew/compat/global.rb
@@ -3,7 +3,7 @@ module Homebrew
def method_missing(method, *args, &block)
if instance_methods.include?(method)
- # odeprecated "#{self}##{method}", "'module_function' or 'def self.#{method}' to convert it to a class method"
+ odeprecated "#{self}##{method}", "'module_function' or 'def self.#{method}' to convert it to a class method"
return instance_method(method).bind(self).call(*args, &block)
end
super
diff --git a/Library/Homebrew/compat/software_spec.rb b/Library/Homebrew/compat/software_spec.rb
index 51b0f3a0b..5efd2aeb4 100644
--- a/Library/Homebrew/compat/software_spec.rb
+++ b/Library/Homebrew/compat/software_spec.rb
@@ -1,7 +1,5 @@
class BottleSpecification
def revision(*args)
- # Don't announce deprecation yet as this is quite a big change
- # to a public interface.
# odeprecated "BottleSpecification.revision", "BottleSpecification.rebuild"
rebuild(*args)
end
diff --git a/Library/Homebrew/compat/tab.rb b/Library/Homebrew/compat/tab.rb
index 58fdc4913..2cf71c923 100644
--- a/Library/Homebrew/compat/tab.rb
+++ b/Library/Homebrew/compat/tab.rb
@@ -1,6 +1,6 @@
class Tab < OpenStruct
def build_32_bit?
- # odeprecated "Tab.build_32_bit?"
+ odeprecated "Tab.build_32_bit?"
include?("32-bit")
end
end
diff --git a/Library/Homebrew/compat/tap.rb b/Library/Homebrew/compat/tap.rb
index d1cf7f1d5..37b1eeac1 100644
--- a/Library/Homebrew/compat/tap.rb
+++ b/Library/Homebrew/compat/tap.rb
@@ -6,5 +6,3 @@ class Tap
core_tap?
end
end
-
-CoreFormulaRepository = CoreTap
diff --git a/Library/Homebrew/compat/utils.rb b/Library/Homebrew/compat/utils.rb
index 56b0824ba..3842e8a83 100644
--- a/Library/Homebrew/compat/utils.rb
+++ b/Library/Homebrew/compat/utils.rb
@@ -1,18 +1,13 @@
-# return the shell profile file based on users' preference shell
def shell_profile
- opoo "shell_profile has been deprecated in favor of Utils::Shell.profile"
- case ENV["SHELL"]
- when %r{/(ba)?sh} then "~/.bash_profile"
- when %r{/zsh} then "~/.zshrc"
- when %r{/ksh} then "~/.kshrc"
- else "~/.bash_profile"
- end
+ # odeprecated "shell_profile", "Utils::Shell.profile"
+ Utils::Shell.profile
end
module Tty
module_function
def white
+ odeprecated "Tty.white", "Tty.reset.bold"
reset.bold
end
end
diff --git a/Library/Homebrew/compat/utils/shell.rb b/Library/Homebrew/compat/utils/shell.rb
new file mode 100644
index 000000000..161f10ebb
--- /dev/null
+++ b/Library/Homebrew/compat/utils/shell.rb
@@ -0,0 +1,8 @@
+module Utils
+ module Shell
+ def self.shell_profile
+ odeprecated "Utils::Shell.shell_profile", "Utils::Shell.profile"
+ Utils::Shell.profile
+ end
+ end
+end
diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb
index 677a52447..95d54caee 100644
--- a/Library/Homebrew/dev-cmd/audit.rb
+++ b/Library/Homebrew/dev-cmd/audit.rb
@@ -1,4 +1,4 @@
-#: * `audit` [`--strict`] [`--fix`] [`--online`] [`--new-formula`] [`--display-cop-names`] [`--display-filename`] [<formulae>]:
+#: * `audit` [`--strict`] [`--fix`] [`--online`] [`--new-formula`] [`--display-cop-names`] [`--display-filename`] [`--only=`<method>|`--except=`<method] [<formulae>]:
#: Check <formulae> for Homebrew coding style violations. This should be
#: run before submitting a new formula.
#:
@@ -23,6 +23,10 @@
#: If `--display-filename` is passed, every line of output is prefixed with the
#: name of the file or formula being audited, to make the output easy to grep.
#:
+#: If `--only` is passed, only the methods named `audit_<method>` will be run.
+#:
+#: If `--except` is passed, the methods named `audit_<method>` will not be run.
+#:
#: `audit` exits with a non-zero status if any errors are found. This is useful,
#: for instance, for implementing pre-commit hooks.
@@ -38,7 +42,7 @@ require "official_taps"
require "cmd/search"
require "cmd/style"
require "date"
-require "blacklist"
+require "missing_formula"
require "digest"
module Homebrew
@@ -331,25 +335,44 @@ class FormulaAuditor
problem "File should end with a newline" unless text.trailing_newline?
- versioned_formulae = Dir[formula.path.to_s.gsub(/\.rb$/, "@*.rb")]
- needs_versioned_alias = !versioned_formulae.empty? &&
- formula.tap &&
- formula.aliases.grep(/.@\d/).empty?
- if needs_versioned_alias
- _, last_alias_version = File.basename(versioned_formulae.sort.reverse.first)
- .gsub(/\.rb$/, "")
- .split("@")
- major, minor, = formula.version.to_s.split(".")
- alias_name = if last_alias_version.split(".").length == 1
- "#{formula.name}@#{major}"
- else
- "#{formula.name}@#{major}.#{minor}"
+ if formula.versioned_formula?
+ unversioned_formula = begin
+ # build this ourselves as we want e.g. homebrew/core to be present
+ full_name = if formula.tap
+ "#{formula.tap}/#{formula.name}"
+ else
+ formula.name
+ end
+ Formulary.factory(full_name.gsub(/@.*$/, "")).path
+ rescue FormulaUnavailableError, TapFormulaAmbiguityError,
+ TapFormulaWithOldnameAmbiguityError
+ Pathname.new formula.path.to_s.gsub(/@.*\.rb$/, ".rb")
+ end
+ unless unversioned_formula.exist?
+ unversioned_name = unversioned_formula.basename(".rb")
+ problem "#{formula} is versioned but no #{unversioned_name} formula exists"
+ end
+ elsif ARGV.build_stable?
+ versioned_formulae = Dir[formula.path.to_s.gsub(/\.rb$/, "@*.rb")]
+ needs_versioned_alias = !versioned_formulae.empty? &&
+ formula.tap &&
+ formula.aliases.grep(/.@\d/).empty?
+ if needs_versioned_alias
+ _, last_alias_version = File.basename(versioned_formulae.sort.reverse.first)
+ .gsub(/\.rb$/, "")
+ .split("@")
+ major, minor, = formula.version.to_s.split(".")
+ alias_name = if last_alias_version.split(".").length == 1
+ "#{formula.name}@#{major}"
+ else
+ "#{formula.name}@#{major}.#{minor}"
+ end
+ problem <<-EOS.undent
+ Formula has other versions so create an alias:
+ cd #{formula.tap.alias_dir}
+ ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name}
+ EOS
end
- problem <<-EOS.undent
- Formula has other versions so create an alias:
- cd #{formula.tap.alias_dir}
- ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name}
- EOS
end
return unless @strict
@@ -399,7 +422,7 @@ class FormulaAuditor
name = formula.name
full_name = formula.full_name
- if blacklisted?(name)
+ if Homebrew::MissingFormula.blacklisted_reason(name)
problem "'#{name}' is blacklisted."
end
@@ -468,10 +491,16 @@ class FormulaAuditor
end
if @@aliases.include?(dep.name) &&
- (core_formula? || !dep_f.versioned_formula?)
+ (dep_f.core_formula? || !dep_f.versioned_formula?)
problem "Dependency '#{dep.name}' is an alias; use the canonical name '#{dep.to_formula.full_name}'."
end
+ if @new_formula && dep_f.keg_only_reason &&
+ !["openssl", "apr", "apr-util"].include?(dep.name) &&
+ [:provided_by_macos, :provided_by_osx].include?(dep_f.keg_only_reason.reason)
+ problem "Dependency '#{dep.name}' may be unnecessary as it is provided by macOS; try to build this formula without it."
+ end
+
dep.options.reject do |opt|
next true if dep_f.option_defined?(opt)
dep_f.requirements.detect do |r|
@@ -572,39 +601,6 @@ class FormulaAuditor
problem "New formulae should not use `deprecated_option`."
end
- def audit_desc
- # For now, only check the description when using `--strict`
- return unless @strict
-
- desc = formula.desc
-
- unless desc && !desc.empty?
- problem "Formula should have a desc (Description)."
- return
- end
-
- # Make sure the formula name plus description is no longer than 80 characters
- # Note full_name includes the name of the tap, while name does not
- linelength = "#{formula.name}: #{desc}".length
- if linelength > 80
- problem <<-EOS.undent
- Description is too long. \"name: desc\" should be less than 80 characters.
- Length is calculated as #{formula.name} + desc. (currently #{linelength})
- EOS
- end
-
- if desc =~ /([Cc]ommand ?line)/
- problem "Description should use \"command-line\" instead of \"#{$1}\""
- end
-
- if desc =~ /^([Aa]n?)\s/
- problem "Description shouldn't start with an indefinite article (#{$1})"
- end
-
- return unless desc.downcase.start_with? "#{formula.name} "
- problem "Description shouldn't include the formula name"
- end
-
def audit_homepage
homepage = formula.homepage
@@ -747,7 +743,10 @@ class FormulaAuditor
}
end
- spec.patches.each { |p| audit_patch(p) if p.external? }
+ next if spec.patches.empty?
+ spec.patches.each { |p| patch_problems(p) if p.external? }
+ next unless @new_formula
+ problem "New formulae should not require patches to build. Patches should be submitted and accepted upstream first."
end
%w[Stable Devel].each do |name|
@@ -775,7 +774,7 @@ class FormulaAuditor
automysqlbackup 3.0-rc6
aview 1.3.0rc1
distcc 3.2rc1
- elm-format 0.5.2-alpha
+ elm-format 0.6.0-alpha
ftgl 2.1.3-rc5
hidapi 0.8.0-rc1
libcaca 0.99b19
@@ -883,10 +882,10 @@ class FormulaAuditor
return if legacy_patches.empty?
problem "Use the patch DSL instead of defining a 'patches' method"
- legacy_patches.each { |p| audit_patch(p) }
+ legacy_patches.each { |p| patch_problems(p) }
end
- def audit_patch(patch)
+ def patch_problems(patch)
case patch.url
when /raw\.github\.com/, %r{gist\.github\.com/raw}, %r{gist\.github\.com/.+/raw},
%r{gist\.githubusercontent\.com/.+/raw}
@@ -958,7 +957,13 @@ class FormulaAuditor
problem "require \"language/go\" is unnecessary unless using `go_resource`s"
end
- def audit_line(line, _lineno)
+ def audit_lines
+ text.without_patch.split("\n").each_with_index do |line, lineno|
+ line_problems(line, lineno+1)
+ end
+ end
+
+ def line_problems(line, _lineno)
if line =~ /<(Formula|AmazonWebServicesFormula|ScriptFileFormula|GithubGistFormula)/
problem "Use a space in class inheritance: class Foo < #{$1}"
end
@@ -1036,6 +1041,18 @@ class FormulaAuditor
problem ":apr is deprecated. Usage should be \"apr-util\""
end
+ if line =~ /depends_on :tex/
+ problem ":tex is deprecated"
+ end
+
+ if line =~ /depends_on\s+['"](.+)['"]\s+=>\s+:(lua|perl|python|ruby)(\d*)/
+ problem "#{$2} modules should be vendored rather than use deprecated `depends_on \"#{$1}\" => :#{$2}#{$3}`"
+ end
+
+ if line =~ /depends_on\s+['"](.+)['"]\s+=>\s+.*['"](.+)['"]/
+ problem "Dependency #{$1} should not use option #{$2}"
+ end
+
# Commented-out depends_on
problem "Commented-out dep #{$1}" if line =~ /#\s*depends_on\s+(.+)\s*$/
@@ -1064,6 +1081,14 @@ class FormulaAuditor
problem "Use ENV instead of invoking '#{$1}' to modify the environment"
end
+ if formula.name != "wine" && line =~ /ENV\.universal_binary/
+ problem "macOS has been 64-bit only since 10.6 so ENV.universal_binary is deprecated."
+ end
+
+ if line =~ /build\.universal\?/
+ problem "macOS has been 64-bit only so build.universal? is deprecated."
+ end
+
if line =~ /version == ['"]HEAD['"]/
problem "Use 'build.head?' instead of inspecting 'version'"
end
@@ -1093,11 +1118,11 @@ class FormulaAuditor
end
if line =~ /(not\s|!)\s*build\.with?\?/
- problem "Don't negate 'build.without?': use 'build.with?'"
+ problem "Don't negate 'build.with?': use 'build.without?'"
end
if line =~ /(not\s|!)\s*build\.without?\?/
- problem "Don't negate 'build.with?': use 'build.without?'"
+ problem "Don't negate 'build.without?': use 'build.with?'"
end
if line =~ /ARGV\.(?!(debug\?|verbose\?|value[\(\s]))/
@@ -1145,11 +1170,11 @@ class FormulaAuditor
end
if line =~ /depends_on :(.+) (if.+|unless.+)$/
- audit_conditional_dep($1.to_sym, $2, $&)
+ conditional_dep_problems($1.to_sym, $2, $&)
end
if line =~ /depends_on ['"](.+)['"] (if.+|unless.+)$/
- audit_conditional_dep($1, $2, $&)
+ conditional_dep_problems($1, $2, $&)
end
if line =~ /(Dir\[("[^\*{},]+")\])/
@@ -1166,7 +1191,8 @@ class FormulaAuditor
problem "Use `assert_match` instead of `assert ...include?`"
end
- if line.include?('system "npm", "install"') && !line.include?("Language::Node") && formula.name !~ /^kibana(\d{2})?$/
+ if line.include?('system "npm", "install"') && !line.include?("Language::Node") &&
+ formula.name !~ /^kibana(\@\d+(\.\d+)?)?$/
problem "Use Language::Node for npm install args"
end
@@ -1174,6 +1200,10 @@ class FormulaAuditor
problem "'fails_with :llvm' is now a no-op so should be removed"
end
+ if line =~ /system\s+['"](otool|install_name_tool|lipo)/ && formula.name != "cctools"
+ problem "Use ruby-macho instead of calling #{$1}"
+ end
+
if formula.tap.to_s == "homebrew/core"
["OS.mac?", "OS.linux?"].each do |check|
next unless line.include?(check)
@@ -1232,7 +1262,7 @@ class FormulaAuditor
EOS
end
- def audit_conditional_dep(dep, condition, line)
+ def conditional_dep_problems(dep, condition, line)
quoted_dep = quote_dep(dep)
dep = Regexp.escape(dep.to_s)
@@ -1248,31 +1278,26 @@ class FormulaAuditor
dep.is_a?(Symbol) ? dep.inspect : "'#{dep}'"
end
- def audit_check_output(output)
+ def problem_if_output(output)
problem(output) if output
end
def audit
- audit_file
- audit_formula_name
- audit_class
- audit_specs
- audit_revision_and_version_scheme
- audit_desc
- audit_homepage
- audit_bottle_spec
- audit_github_repository
- audit_deps
- audit_conflicts
- audit_options
- audit_legacy_patches
- audit_text
- audit_caveats
- text.without_patch.split("\n").each_with_index { |line, lineno| audit_line(line, lineno+1) }
- audit_installed
- audit_prefix_has_contents
- audit_reverse_migration
- audit_style
+ only_audits = ARGV.value("only").to_s.split(",")
+ except_audits = ARGV.value("except").to_s.split(",")
+ if !only_audits.empty? && !except_audits.empty?
+ odie "--only and --except cannot be used simulataneously!"
+ end
+
+ methods.map(&:to_s).grep(/^audit_/).each do |audit_method_name|
+ name = audit_method_name.gsub(/^audit_/, "")
+ if !only_audits.empty?
+ next unless only_audits.include?(name)
+ elsif !except_audits.empty?
+ next if except_audits.include?(name)
+ end
+ send(audit_method_name)
+ end
end
private
@@ -1403,8 +1428,8 @@ class ResourceAuditor
def audit_urls
# Check GNU urls; doesn't apply to mirrors
- if url =~ %r{^(?:https?|ftp)://(?!alpha).+/gnu/}
- problem "Please use \"https://ftpmirror.gnu.org\" instead of #{url}."
+ if url =~ %r{^(?:https?|ftp)://ftpmirror.gnu.org/(.*)}
+ problem "Please use \"https://ftp.gnu.org/gnu/#{$1}\" instead of #{url}."
end
if mirrors.include?(url)
diff --git a/Library/Homebrew/dev-cmd/boneyard-formula-pr.rb b/Library/Homebrew/dev-cmd/boneyard-formula-pr.rb
deleted file mode 100644
index 7531ef9cf..000000000
--- a/Library/Homebrew/dev-cmd/boneyard-formula-pr.rb
+++ /dev/null
@@ -1,166 +0,0 @@
-#: @hide_from_man_page
-#: * `boneyard-formula-pr` [`--dry-run`] [`--local`] [`--reason=<reason>`] <formula> :
-#: Creates a pull request to boneyard a formula.
-#:
-#: If `--dry-run` is passed, print what would be done rather than doing it.
-#:
-#: If `--local` is passed, perform only local operations (i.e. don't push or create PR).
-#:
-#: If `--reason=<reason>` is passed, append this to the commit/PR message.
-
-require "formula"
-require "json"
-require "fileutils"
-
-begin
- require "json"
-rescue LoadError
- puts "Homebrew does not provide Ruby dependencies; install with:"
- puts " gem install json"
- odie "Dependency json is not installed."
-end
-
-module Homebrew
- module_function
-
- 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 <<-EOS.undent
- {
- }
- EOS
- 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 = <<-EOS.undent
- #{formula.name}: migrate to boneyard
-
- Created with `brew boneyard-formula-pr`#{reason}.
- EOS
- 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", <<-EOS.undent
- #{formula.name}: migrate from #{formula.tap.repo}
-
- Goes together with #{pr_url}.
-
- Created with `brew boneyard-formula-pr`#{reason}.
- EOS
- end
-
- safe_system "git", "checkout", "-"
- end
- end
-end
diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb
index b11da5607..8d3038a5a 100644
--- a/Library/Homebrew/dev-cmd/bottle.rb
+++ b/Library/Homebrew/dev-cmd/bottle.rb
@@ -6,7 +6,7 @@
#: generated DSL. Passing `--keep-old` will attempt to keep it at its
#: original value, while `--no-rebuild` will remove it.
#:
-#: If `--verbose` is passed, print the bottling commands and any warnings
+#: If `--verbose` (or `-v`) is passed, print the bottling commands and any warnings
#: encountered.
#:
#: If `--skip-relocation` is passed, do not check if the bottle can be marked
diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb
index 9c58dc71a..908f65f8f 100644
--- a/Library/Homebrew/dev-cmd/create.rb
+++ b/Library/Homebrew/dev-cmd/create.rb
@@ -10,7 +10,8 @@
#: If `--meson` is passed, create a basic template for a Meson-style build.
#:
#: If `--no-fetch` is passed, Homebrew will not download <URL> to the cache and
-#: will thus not add the SHA256 to the formula for you.
+#: will thus not add the SHA256 to the formula for you. It will also not check
+#: the GitHub API for GitHub projects (to fill out the description and homepage).
#:
#: The options `--set-name` and `--set-version` each take an argument and allow
#: you to explicitly set the name and version of the package you are creating.
@@ -19,7 +20,7 @@
#: the specified tap.
require "formula"
-require "blacklist"
+require "missing_formula"
require "digest"
require "erb"
@@ -28,15 +29,6 @@ module Homebrew
# Create a formula from a tarball URL
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
@@ -73,8 +65,8 @@ module Homebrew
# Don't allow blacklisted formula, or names that shadow aliases,
# unless --force is specified.
unless ARGV.force?
- if msg = blacklisted?(fc.name)
- raise "#{fc.name} is blacklisted for creation.\n#{msg}\nIf you really want to create this formula use --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
@@ -100,7 +92,7 @@ module Homebrew
end
class FormulaCreator
- attr_reader :url, :sha256
+ attr_reader :url, :sha256, :desc, :homepage
attr_accessor :name, :version, :tap, :path, :mode
def url=(url)
@@ -108,11 +100,15 @@ class FormulaCreator
path = Pathname.new(url)
if @name.nil?
case url
- when %r{github\.com/\S+/(\S+)\.git}
- @name = $1
+ when %r{github\.com/(\S+)/(\S+)\.git}
+ @user = $1
+ @name = $2
@head = true
- when %r{github\.com/\S+/(\S+)/archive/}
- @name = $1
+ @github = true
+ when %r{github\.com/(\S+)/(\S+)/(archive|releases)/}
+ @user = $1
+ @name = $2
+ @github = true
else
@name = path.basename.to_s[/(.*?)[-_.]?#{Regexp.escape(path.version.to_s)}/, 1]
end
@@ -131,7 +127,7 @@ class FormulaCreator
end
def fetch?
- !head? && !ARGV.include?("--no-fetch")
+ !ARGV.include?("--no-fetch")
end
def head?
@@ -145,11 +141,25 @@ class FormulaCreator
opoo "Version cannot be determined from URL."
puts "You'll need to add an explicit 'version' to the formula."
elsif fetch?
- r = Resource.new
- r.url(url)
- r.version(version)
- r.owner = self
- @sha256 = r.fetch.sha256 if r.download_strategy == CurlDownloadStrategy
+ unless head?
+ r = Resource.new
+ r.url(url)
+ r.version(version)
+ r.owner = self
+ @sha256 = r.fetch.sha256 if r.download_strategy == CurlDownloadStrategy
+ end
+
+ if @user && @name
+ begin
+ metadata = GitHub.repository(@user, @name)
+ @desc = metadata["description"]
+ @homepage = metadata["homepage"]
+ rescue GitHub::HTTPNotFoundError
+ # If there was no repository found assume the network connection is at
+ # fault rather than the input URL.
+ nil
+ end
+ end
end
path.write ERB.new(template, nil, ">").result(binding)
@@ -161,8 +171,8 @@ class FormulaCreator
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
class #{Formulary.class_s(name)} < Formula
- desc ""
- homepage ""
+ desc "#{desc}"
+ homepage "#{homepage}"
<% if head? %>
head "#{url}"
<% else %>
diff --git a/Library/Homebrew/dev-cmd/man.rb b/Library/Homebrew/dev-cmd/man.rb
index 581db38ca..4e5103910 100644
--- a/Library/Homebrew/dev-cmd/man.rb
+++ b/Library/Homebrew/dev-cmd/man.rb
@@ -27,7 +27,7 @@ module Homebrew
regenerate_man_pages
- if system "git", "-C", HOMEBREW_REPOSITORY, "diff", "--quiet", "docs/brew.1.html", "manpages"
+ 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
@@ -38,7 +38,7 @@ module Homebrew
Homebrew.install_gem_setup_path! "ronn"
markup = build_man_page
- convert_man_page(markup, TARGET_DOC_PATH/"brew.1.html")
+ 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
@@ -53,8 +53,7 @@ module Homebrew
.grep(/^#:/)
.map { |line| line.slice(2..-1) }
.join
- end
- .reject { |s| s.strip.empty? || s.include?("@hide_from_man_page") }
+ end.reject { |s| s.strip.empty? || s.include?("@hide_from_man_page") }
end
def build_man_page
@@ -107,13 +106,15 @@ module Homebrew
Utils.popen(["ronn", format_flag] + shared_args, "rb+") do |ronn|
ronn.write markup
ronn.close_write
- target.atomic_write ronn.read
+ ronn_output = ronn.read
+ ronn_output.gsub!(%r{</?var>}, "`") if format_flag == "--markdown"
+ target.atomic_write ronn_output
end
end
def target_path_to_format(target)
case target.basename
- when /\.html?$/ then ["--fragment", "HTML fragment"]
+ when /\.md$/ then ["--markdown", "markdown"]
when /\.\d$/ then ["--roff", "man page"]
else
odie "Failed to infer output format from '#{target.basename}'."
diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb
index ec89b14b8..36c9ac27c 100644
--- a/Library/Homebrew/dev-cmd/pull.rb
+++ b/Library/Homebrew/dev-cmd/pull.rb
@@ -1,4 +1,5 @@
-#: * `pull` [`--bottle`] [`--bump`] [`--clean`] [`--ignore-whitespace`] [`--resolve`] [`--branch-okay`] [`--no-pbcopy`] [`--no-publish`] <patch-source> [<patch-source>]:
+#: * `pull` [`--bottle`] [`--bump`] [`--clean`] [`--ignore-whitespace`] [`--resolve`] [`--branch-okay`] [`--no-pbcopy`] [`--no-publish`] [`--warn-on-publish-failure`] <patch-source> [<patch-source>]:
+#:
#: Gets a patch from a GitHub commit or pull request and applies it to Homebrew.
#: Optionally, installs the formulae changed by the patch.
#:
@@ -37,6 +38,9 @@
#: clipboard.
#:
#: If `--no-publish` is passed, do not publish bottles to Bintray.
+#:
+#: If `--warn-on-publish-failure` was passed, do not exit if there's a
+#: failure publishing bottles on Bintray.
require "net/http"
require "net/https"
@@ -264,7 +268,7 @@ module Homebrew
changed_formulae_names.each do |name|
f = Formula[name]
next if f.bottle_unneeded? || f.bottle_disabled?
- publish_bottle_file_on_bintray(f, bintray_creds)
+ next unless publish_bottle_file_on_bintray(f, bintray_creds)
published << f.full_name
end
else
@@ -425,7 +429,7 @@ module Homebrew
end
unless info.bottle_info_any
opoo "No bottle defined in formula #{package}"
- return
+ return false
end
version = info.pkg_version
ohai "Publishing on Bintray: #{package} #{version}"
@@ -434,6 +438,11 @@ module Homebrew
"-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
# Formula info drawn from an external "brew info --json" call
diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb
index 6e1977446..df295bf26 100644
--- a/Library/Homebrew/dev-cmd/tap-new.rb
+++ b/Library/Homebrew/dev-cmd/tap-new.rb
@@ -60,6 +60,7 @@ module Homebrew
- git -C "$HOMEBREW_REPOSITORY" reset --hard origin/master
- brew update || brew update
- HOMEBREW_TAP_DIR="$(brew --repo "$TRAVIS_REPO_SLUG")"
+ - mkdir -p "$HOMEBREW_TAP_DIR"
- rm -rf "$HOMEBREW_TAP_DIR"
- ln -s "$PWD" "$HOMEBREW_TAP_DIR"
- export HOMEBREW_DEVELOPER="1"
diff --git a/Library/Homebrew/dev-cmd/test.rb b/Library/Homebrew/dev-cmd/test.rb
index 4898629b0..288aa8a87 100644
--- a/Library/Homebrew/dev-cmd/test.rb
+++ b/Library/Homebrew/dev-cmd/test.rb
@@ -7,7 +7,7 @@
#: To test the development or head version of a formula, use `--devel` or
#: `--HEAD`.
#:
-#: If `--debug` is passed and the test fails, an interactive debugger will be
+#: If `--debug` (or `-d`) is passed and the test fails, an interactive debugger will be
#: launched with access to IRB or a shell inside the temporary test directory.
#:
#: If `--keep-tmp` is passed, the temporary files created for the test are
diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb
index 4f7f9e771..72d6143fc 100644
--- a/Library/Homebrew/dev-cmd/tests.rb
+++ b/Library/Homebrew/dev-cmd/tests.rb
@@ -3,7 +3,7 @@
#: `--only=`<test_script> runs only <test_script>_spec.rb, and `--seed`
#: randomizes tests with the provided value instead of a random seed.
#:
-#: If `--verbose` is passed, print the command that runs the tests.
+#: If `--verbose` (or `-v`) is passed, print the command that runs the tests.
#:
#: If `--coverage` is passed, also generate code coverage reports.
#:
@@ -28,11 +28,17 @@ module Homebrew
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.include? "--online"
+ ENV["HOMEBREW_TEST_ONLINE"] = "1"
+ else
+ ENV["HOMEBREW_NO_GITHUB_API"] = "1"
+ end
if ARGV.include? "--official-cmd-taps"
ENV["HOMEBREW_TEST_OFFICIAL_CMD_TAPS"] = "1"
@@ -96,6 +102,10 @@ module Homebrew
files = files.reject { |p| p =~ %r{^test/(os/mac|cask)(/.*|_spec\.rb)$} }
end
+ unless OS.linux?
+ files = files.reject { |p| p =~ %r{^test/os/linux(/.*|_spec\.rb)$} }
+ end
+
if parallel
system "bundle", "exec", "parallel_rspec", *opts, "--", *args, "--", *files
else
diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb
index 2ff168669..add05bc7c 100644
--- a/Library/Homebrew/dev-cmd/update-test.rb
+++ b/Library/Homebrew/dev-cmd/update-test.rb
@@ -33,12 +33,24 @@ module Homebrew
elsif date = ARGV.value("before")
Utils.popen_read("git", "rev-list", "-n1", "--before=#{date}", "origin/master").chomp
elsif ARGV.include?("--to-tag")
- Utils.popen_read("git", "tag", "--list", "--sort=-version:refname").lines[1].chomp
+ previous_tag =
+ Utils.popen_read("git", "tag", "--list", "--sort=-version:refname").lines[1]
+ unless previous_tag
+ safe_system "git", "fetch", "--tags", "--depth=1"
+ previous_tag =
+ Utils.popen_read("git", "tag", "--list", "--sort=-version:refname").lines[1]
+ end
+ previous_tag.to_s.chomp
else
Utils.popen_read("git", "rev-parse", "origin/master").chomp
end
+ odie "Could not find start commit!" if start_commit.empty?
+
start_commit = Utils.popen_read("git", "rev-parse", start_commit).chomp
+ odie "Could not find start commit!" if start_commit.empty?
+
end_commit = Utils.popen_read("git", "rev-parse", "HEAD").chomp
+ odie "Could not find end commit!" if end_commit.empty?
puts "Start commit: #{start_commit}"
puts "End commit: #{end_commit}"
diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb
index c8c4b83d2..3002a0a67 100644
--- a/Library/Homebrew/diagnostic.rb
+++ b/Library/Homebrew/diagnostic.rb
@@ -460,7 +460,7 @@ module Homebrew
Consider setting your PATH so that #{HOMEBREW_PREFIX}/bin
occurs before /usr/bin. Here is a one-liner:
- #{Utils::Shell.prepend_path_in_shell_profile("#{HOMEBREW_PREFIX}/bin")}
+ #{Utils::Shell.prepend_path_in_profile("#{HOMEBREW_PREFIX}/bin")}
EOS
end
end
@@ -480,7 +480,7 @@ module Homebrew
<<-EOS.undent
Homebrew's bin was not found in your PATH.
Consider setting the PATH for example like so
- #{Utils::Shell.prepend_path_in_shell_profile("#{HOMEBREW_PREFIX}/bin")}
+ #{Utils::Shell.prepend_path_in_profile("#{HOMEBREW_PREFIX}/bin")}
EOS
end
@@ -495,7 +495,7 @@ module Homebrew
Homebrew's sbin was not found in your PATH but you have installed
formulae that put executables in #{HOMEBREW_PREFIX}/sbin.
Consider setting the PATH for example like so
- #{Utils::Shell.prepend_path_in_shell_profile("#{HOMEBREW_PREFIX}/sbin")}
+ #{Utils::Shell.prepend_path_in_profile("#{HOMEBREW_PREFIX}/sbin")}
EOS
end
@@ -753,13 +753,14 @@ module Homebrew
def check_git_version
# https://help.github.com/articles/https-cloning-errors
return unless Utils.git_available?
- return unless Version.create(Utils.git_version) < Version.create("1.7.10")
+ return unless Version.create(Utils.git_version) < Version.create("1.8.5")
git = Formula["git"]
git_upgrade_cmd = git.any_version_installed? ? "upgrade" : "install"
<<-EOS.undent
An outdated version (#{Utils.git_version}) of Git was detected in your PATH.
- Git 1.7.10 or newer is required to perform checkouts over HTTPS from GitHub.
+ Git 1.8.5 or newer is required to perform checkouts over HTTPS from GitHub and
+ to support the 'git -C <path>' option.
Please upgrade:
brew #{git_upgrade_cmd} git
EOS
@@ -794,31 +795,59 @@ module Homebrew
EOS
end
- def check_git_origin
+ def check_brew_git_origin
return if !Utils.git_available? || !(HOMEBREW_REPOSITORY/".git").exist?
origin = HOMEBREW_REPOSITORY.git_origin
if origin.nil?
<<-EOS.undent
- Missing git origin remote.
+ Missing Homebrew/brew git origin remote.
Without a correctly configured origin, Homebrew won't update
properly. You can solve this by adding the Homebrew remote:
- cd #{HOMEBREW_REPOSITORY}
- git remote add origin #{Formatter.url("https://github.com/Homebrew/brew.git")}
+ git -C "#{HOMEBREW_REPOSITORY}" remote add origin #{Formatter.url("https://github.com/Homebrew/brew.git")}
EOS
- elsif origin !~ %r{Homebrew/brew(\.git)?$}
+ elsif origin !~ %r{Homebrew/brew(\.git|/)?$}
<<-EOS.undent
- Suspicious git origin remote found.
+ Suspicious Homebrew/brew git origin remote found.
With a non-standard origin, Homebrew won't pull updates from
the main repository. The current git origin is:
#{origin}
Unless you have compelling reasons, consider setting the
- origin remote to point at the main repository, located at:
- #{Formatter.url("https://github.com/Homebrew/brew.git")}
+ origin remote to point at the main repository by running:
+ git -C "#{HOMEBREW_REPOSITORY}" remote add origin #{Formatter.url("https://github.com/Homebrew/brew.git")}
+ EOS
+ end
+ end
+
+ def check_coretap_git_origin
+ coretap_path = CoreTap.instance.path
+ return if !Utils.git_available? || !(coretap_path/".git").exist?
+
+ origin = coretap_path.git_origin
+
+ if origin.nil?
+ <<-EOS.undent
+ Missing #{CoreTap.instance} git origin remote.
+
+ Without a correctly configured origin, Homebrew won't update
+ properly. You can solve this by adding the Homebrew remote:
+ git -C "#{coretap_path}" remote add origin #{Formatter.url("https://github.com/Homebrew/homebrew-core.git")}
+ EOS
+ elsif origin !~ %r{Homebrew/homebrew-core(\.git|/)?$}
+ <<-EOS.undent
+ Suspicious #{CoreTap.instance} git origin remote found.
+
+ With a non-standard origin, Homebrew won't pull updates from
+ the main repository. The current git origin is:
+ #{origin}
+
+ Unless you have compelling reasons, consider setting the
+ origin remote to point at the main repository by running:
+ git -C "#{coretap_path}" remote add origin #{Formatter.url("https://github.com/Homebrew/homebrew-core.git")}
EOS
end
end
diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb
index 77da4489e..6751b2224 100644
--- a/Library/Homebrew/exceptions.rb
+++ b/Library/Homebrew/exceptions.rb
@@ -77,35 +77,11 @@ class FormulaUnavailableError < RuntimeError
end
end
-class TapFormulaUnavailableError < FormulaUnavailableError
- attr_reader :tap, :user, :repo
-
- def initialize(tap, name)
- @tap = tap
- @user = tap.user
- @repo = tap.repo
- super "#{tap}/#{name}"
- end
-
- def to_s
- s = super
- s += "\nPlease tap it and then try again: brew tap #{tap}" unless tap.installed?
- s
- end
-end
-
-class FormulaClassUnavailableError < FormulaUnavailableError
+module FormulaClassUnavailableErrorModule
attr_reader :path
attr_reader :class_name
attr_reader :class_list
- def initialize(name, path, class_name, class_list)
- @path = path
- @class_name = class_name
- @class_list = class_list
- super name
- end
-
def to_s
s = super
s += "\nIn formula file: #{path}"
@@ -131,16 +107,70 @@ class FormulaClassUnavailableError < FormulaUnavailableError
end
end
-class FormulaUnreadableError < FormulaUnavailableError
+class FormulaClassUnavailableError < FormulaUnavailableError
+ include FormulaClassUnavailableErrorModule
+
+ def initialize(name, path, class_name, class_list)
+ @path = path
+ @class_name = class_name
+ @class_list = class_list
+ super name
+ end
+end
+
+module FormulaUnreadableErrorModule
attr_reader :formula_error
+ def to_s
+ "#{name}: " + formula_error.to_s
+ end
+end
+
+class FormulaUnreadableError < FormulaUnavailableError
+ include FormulaUnreadableErrorModule
+
def initialize(name, error)
super(name)
@formula_error = error
end
+end
+
+class TapFormulaUnavailableError < FormulaUnavailableError
+ attr_reader :tap, :user, :repo
+
+ def initialize(tap, name)
+ @tap = tap
+ @user = tap.user
+ @repo = tap.repo
+ super "#{tap}/#{name}"
+ end
def to_s
- "#{name}: " + formula_error.to_s
+ s = super
+ s += "\nPlease tap it and then try again: brew tap #{tap}" unless tap.installed?
+ s
+ end
+end
+
+class TapFormulaClassUnavailableError < TapFormulaUnavailableError
+ include FormulaClassUnavailableErrorModule
+
+ attr_reader :tap
+
+ def initialize(tap, name, path, class_name, class_list)
+ @path = path
+ @class_name = class_name
+ @class_list = class_list
+ super tap, name
+ end
+end
+
+class TapFormulaUnreadableError < TapFormulaUnavailableError
+ include FormulaUnreadableErrorModule
+
+ def initialize(tap, name, error)
+ super(tap, name)
+ @formula_error = error
end
end
@@ -363,14 +393,6 @@ class BuildError < RuntimeError
end
end
- if formula.tap && formula.tap.name == "homebrew/boneyard"
- onoe <<-EOS.undent
- #{formula} was moved to homebrew-boneyard because it has unfixable issues.
- Please do not file any issues about this. Sorry!
- EOS
- return
- end
-
if formula.tap && defined?(OS::ISSUES_URL)
if formula.tap.official?
puts Formatter.error(Formatter.url(OS::ISSUES_URL), label: "READ THIS")
diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb
index 0935647f5..4d6d96ad3 100644
--- a/Library/Homebrew/extend/ENV/super.rb
+++ b/Library/Homebrew/extend/ENV/super.rb
@@ -326,9 +326,7 @@ module Superenv
def set_x11_env_if_installed
end
- # This method does nothing in superenv since there's no custom CFLAGS API
- # @private
- def set_cpu_flags(*_args)
+ def set_cpu_flags(*)
end
end
diff --git a/Library/Homebrew/extend/io.rb b/Library/Homebrew/extend/io.rb
index 1357293cd..53bca196e 100644
--- a/Library/Homebrew/extend/io.rb
+++ b/Library/Homebrew/extend/io.rb
@@ -1,10 +1,17 @@
class IO
def readline_nonblock(sep = $INPUT_RECORD_SEPARATOR)
+ line = ""
buffer = ""
- buffer.concat(read_nonblock(1)) while buffer[-1] != sep
- buffer
+
+ loop do
+ break if buffer == sep
+ read_nonblock(1, buffer)
+ line.concat(buffer)
+ end
+
+ line
rescue IO::WaitReadable, EOFError => e
- raise e if buffer.empty?
- buffer
+ raise e if line.empty?
+ line
end
end
diff --git a/Library/Homebrew/extend/os/blacklist.rb b/Library/Homebrew/extend/os/blacklist.rb
deleted file mode 100644
index 932040f82..000000000
--- a/Library/Homebrew/extend/os/blacklist.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require "blacklist"
-require "extend/os/mac/blacklist" if OS.mac?
diff --git a/Library/Homebrew/extend/os/linux/hardware/cpu.rb b/Library/Homebrew/extend/os/linux/hardware/cpu.rb
index 4c8aa3f42..7c945b237 100644
--- a/Library/Homebrew/extend/os/linux/hardware/cpu.rb
+++ b/Library/Homebrew/extend/os/linux/hardware/cpu.rb
@@ -49,6 +49,8 @@ module Hardware
:haswell
when 0x3d, 0x47, 0x4f, 0x56
:broadwell
+ when 0x5e
+ :skylake
when 0x8e
:kabylake
else
diff --git a/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb b/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb
new file mode 100644
index 000000000..3fd847bc4
--- /dev/null
+++ b/Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb
@@ -0,0 +1,39 @@
+require "requirement"
+
+class OsxfuseRequirement < Requirement
+ download "https://github.com/libfuse/libfuse"
+
+ satisfy(build_env: false) do
+ next true if libfuse_formula_exists? && Formula["libfuse"].installed?
+ includedirs = %w[
+ /usr/include
+ /usr/local/include
+ ]
+ next true if (includedirs.map do |dir|
+ File.exist? "#{dir}/fuse.h"
+ end).any?
+ false
+ end
+
+ def message
+ msg = "libfuse is required to install this formula.\n"
+ if libfuse_formula_exists?
+ msg + <<-EOS.undent
+ Run "brew install libfuse" to install it.
+ EOS
+ else
+ msg + super
+ end
+ end
+
+ private
+
+ def libfuse_formula_exists?
+ begin
+ Formula["libfuse"]
+ rescue FormulaUnavailableError
+ return false
+ end
+ true
+ end
+end
diff --git a/Library/Homebrew/extend/os/mac/blacklist.rb b/Library/Homebrew/extend/os/mac/blacklist.rb
deleted file mode 100644
index edff4697e..000000000
--- a/Library/Homebrew/extend/os/mac/blacklist.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-def blacklisted?(name)
- case name.downcase
- when "xcode"
- if MacOS.version >= :lion
- <<-EOS.undent
- Xcode can be installed from the App Store.
- EOS
- else
- <<-EOS.undent
- Xcode can be installed from https://developer.apple.com/xcode/downloads/
- EOS
- end
- else
- generic_blacklisted?(name)
- end
-end
diff --git a/Library/Homebrew/extend/os/mac/development_tools.rb b/Library/Homebrew/extend/os/mac/development_tools.rb
index f54c6b8a3..caa85ffca 100644
--- a/Library/Homebrew/extend/os/mac/development_tools.rb
+++ b/Library/Homebrew/extend/os/mac/development_tools.rb
@@ -31,13 +31,13 @@ class DevelopmentTools
elsif MacOS.version == "10.8" || MacOS.version == "10.7"
<<-EOS.undent
Install the Command Line Tools from
- https://developer.apple.com/downloads/
+ https://developer.apple.com/download/more/
or via Xcode's preferences.
EOS
else
<<-EOS.undent
Install Xcode from
- https://developer.apple.com/xcode/downloads/
+ https://developer.apple.com/download/more/
EOS
end
end
diff --git a/Library/Homebrew/extend/os/mac/diagnostic.rb b/Library/Homebrew/extend/os/mac/diagnostic.rb
index c7dabde2b..ff936c75a 100644
--- a/Library/Homebrew/extend/os/mac/diagnostic.rb
+++ b/Library/Homebrew/extend/os/mac/diagnostic.rb
@@ -81,6 +81,12 @@ module Homebrew
return unless MacOS::CLT.installed?
return unless MacOS::CLT.outdated?
+ # Travis CI images are going to end up outdated so don't complain when
+ # `brew test-bot` runs `brew doctor` in the CI for the Homebrew/brew
+ # repository. This only needs to support whatever CI provider
+ # Homebrew/brew is currently using.
+ return if ENV["TRAVIS"]
+
<<-EOS.undent
A newer Command Line Tools release is available.
#{MacOS::CLT.update_instructions}
@@ -257,7 +263,7 @@ module Homebrew
SSL_CERT_DIR support was removed from Apple's curl.
If fetching formulae fails you should:
unset SSL_CERT_DIR
- and remove it from #{Utils::Shell.shell_profile} if present.
+ and remove it from #{Utils::Shell.profile} if present.
EOS
end
diff --git a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb
index 5b1c648bf..10379c981 100644
--- a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb
+++ b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb
@@ -67,7 +67,7 @@ module FormulaCellarChecks
checker = LinkageChecker.new(keg, formula)
return unless checker.broken_dylibs?
- audit_check_output <<-EOS.undent
+ problem_if_output <<-EOS.undent
The installation was broken.
Broken dylib links found:
#{checker.broken_dylibs.to_a * "\n "}
@@ -76,9 +76,9 @@ module FormulaCellarChecks
def audit_installed
generic_audit_installed
- audit_check_output(check_shadowed_headers)
- audit_check_output(check_openssl_links)
- audit_check_output(check_python_framework_links(formula.lib))
+ problem_if_output(check_shadowed_headers)
+ problem_if_output(check_openssl_links)
+ problem_if_output(check_python_framework_links(formula.lib))
check_linkage
end
end
diff --git a/Library/Homebrew/extend/os/mac/hardware/cpu.rb b/Library/Homebrew/extend/os/mac/hardware/cpu.rb
index f180995fb..22d118e1a 100644
--- a/Library/Homebrew/extend/os/mac/hardware/cpu.rb
+++ b/Library/Homebrew/extend/os/mac/hardware/cpu.rb
@@ -107,6 +107,20 @@ module Hardware
end
end
+ # Determines whether the current CPU and macOS combination
+ # can run an executable of the specified architecture.
+ # `arch` is a symbol in the same format returned by
+ # Hardware::CPU.family
+ def can_run?(arch)
+ if Hardware::CPU.intel?
+ intel_can_run? arch
+ elsif Hardware::CPU.ppc?
+ ppc_can_run? arch
+ else
+ false
+ end
+ end
+
def features
@features ||= sysctl_n(
"machdep.cpu.features",
@@ -162,6 +176,35 @@ module Hardware
@properties[keys] = Utils.popen_read("/usr/sbin/sysctl", "-n", *keys)
end
end
+
+ def intel_can_run?(arch)
+ case arch
+ when :ppc
+ # Rosetta is still available
+ MacOS.version < :lion
+ when :ppc64
+ # Rosetta never supported PPC64
+ false
+ when :x86_64
+ Hardware::CPU.is_64_bit?
+ when :i386
+ true
+ else # dunno
+ false
+ end
+ end
+
+ def ppc_can_run?(arch)
+ case arch
+ when :ppc
+ true
+ when :ppc64
+ Hardware::CPU.is_64_bit?
+ else
+ # Intel is never supported
+ false
+ end
+ end
end
end
end
diff --git a/Library/Homebrew/extend/os/mac/keg_relocate.rb b/Library/Homebrew/extend/os/mac/keg_relocate.rb
index 476e5da4a..0b2ecd1c9 100644
--- a/Library/Homebrew/extend/os/mac/keg_relocate.rb
+++ b/Library/Homebrew/extend/os/mac/keg_relocate.rb
@@ -78,19 +78,13 @@ class Keg
end
end
- def filename_contains_metavariable?(fn)
- fn =~ /^@(loader_|executable_|r)path/
- end
-
def each_install_name_for(file, &block)
dylibs = file.dynamically_linked_libraries
- dylibs.reject! { |fn| filename_contains_metavariable?(fn) }
+ dylibs.reject! { |fn| fn =~ /^@(loader_|executable_|r)path/ }
dylibs.each(&block)
end
def dylib_id_for(file)
- return file.dylib_id if filename_contains_metavariable?(file.dylib_id)
-
# The new dylib ID should have the same basename as the old dylib ID, not
# the basename of the file itself.
basename = File.basename(file.dylib_id)
@@ -131,6 +125,12 @@ class Keg
mach_o_files
end
+ def recursive_fgrep_args
+ # Don't recurse into symlinks; the man page says this is the default, but
+ # it's wrong. -O is a BSD-grep-only option.
+ "-lrO"
+ end
+
def self.file_linked_libraries(file, string)
# Check dynamic library linkage. Importantly, do not perform for static
# libraries, which will falsely report "linkage" to themselves.
diff --git a/Library/Homebrew/extend/os/mac/missing_formula.rb b/Library/Homebrew/extend/os/mac/missing_formula.rb
new file mode 100644
index 000000000..bcf0eb25d
--- /dev/null
+++ b/Library/Homebrew/extend/os/mac/missing_formula.rb
@@ -0,0 +1,22 @@
+module Homebrew
+ module MissingFormula
+ class << self
+ def blacklisted_reason(name)
+ case name.downcase
+ when "xcode"
+ if MacOS.version >= :lion
+ <<-EOS.undent
+ Xcode can be installed from the App Store.
+ EOS
+ else
+ <<-EOS.undent
+ Xcode can be installed from #{Formatter.url("https://developer.apple.com/download/more/")}.
+ EOS
+ end
+ else
+ generic_blacklisted_reason(name)
+ end
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb
new file mode 100644
index 000000000..8c898a272
--- /dev/null
+++ b/Library/Homebrew/extend/os/mac/requirements/osxfuse_requirement.rb
@@ -0,0 +1,34 @@
+require "requirement"
+
+class OsxfuseRequirement < Requirement
+ cask "osxfuse"
+ download "https://osxfuse.github.io/"
+
+ satisfy(build_env: false) { self.class.binary_osxfuse_installed? }
+
+ def self.binary_osxfuse_installed?
+ File.exist?("/usr/local/include/osxfuse/fuse.h") &&
+ !File.symlink?("/usr/local/include/osxfuse")
+ end
+
+ env do
+ ENV.append_path "PKG_CONFIG_PATH", HOMEBREW_LIBRARY/"Homebrew/os/mac/pkgconfig/fuse"
+
+ unless HOMEBREW_PREFIX.to_s == "/usr/local"
+ ENV.append_path "HOMEBREW_LIBRARY_PATHS", "/usr/local/lib"
+ ENV.append_path "HOMEBREW_INCLUDE_PATHS", "/usr/local/include/osxfuse"
+ end
+ end
+end
+
+class NonBinaryOsxfuseRequirement < Requirement
+ fatal true
+ satisfy(build_env: false) { HOMEBREW_PREFIX.to_s != "/usr/local" || !OsxfuseRequirement.binary_osxfuse_installed? }
+
+ def message
+ <<-EOS.undent
+ osxfuse is already installed from the binary distribution and
+ conflicts with this formula.
+ EOS
+ end
+end
diff --git a/Library/Homebrew/extend/os/missing_formula.rb b/Library/Homebrew/extend/os/missing_formula.rb
new file mode 100644
index 000000000..02c59f4e4
--- /dev/null
+++ b/Library/Homebrew/extend/os/missing_formula.rb
@@ -0,0 +1,2 @@
+require "missing_formula"
+require "extend/os/mac/missing_formula" if OS.mac?
diff --git a/Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb b/Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb
new file mode 100644
index 000000000..5f56d48c4
--- /dev/null
+++ b/Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb
@@ -0,0 +1,7 @@
+require "requirements/osxfuse_requirement"
+
+if OS.mac?
+ require "extend/os/mac/requirements/osxfuse_requirement"
+elsif OS.linux?
+ require "extend/os/linux/requirements/osxfuse_requirement"
+end
diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb
index eb254c624..690979e4e 100644
--- a/Library/Homebrew/extend/pathname.rb
+++ b/Library/Homebrew/extend/pathname.rb
@@ -365,9 +365,8 @@ class Pathname
unless method_defined?(:/)
def /(other)
- unless other.respond_to?(:to_str) || other.respond_to?(:to_path)
- opoo "Pathname#/ called on #{inspect} with #{other.inspect} as an argument"
- puts "This behavior is deprecated, please pass either a String or a Pathname"
+ if !other.respond_to?(:to_str) && !other.respond_to?(:to_path)
+ odeprecated "Pathname#/ with #{other.class}", "a String or a Pathname"
end
self + other.to_s
end
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index 443619206..aec004b0b 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -252,12 +252,14 @@ class Formula
public
- # The alias path that was used to install this formula, if present.
+ # The alias path that was used to install this formula, if it exists.
# Can differ from alias_path, which is the alias used to find the formula,
# and is specified to this instance.
def installed_alias_path
path = build.source["path"] if build.is_a?(Tab)
- path if path =~ %r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}
+ return unless path =~ %r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases}
+ return unless File.symlink?(path)
+ path
end
def installed_alias_name
@@ -1555,6 +1557,8 @@ class Formula
hide.include?(d.name) || d.installed_prefixes.empty?
end
missing_dependencies
+ rescue FormulaUnavailableError
+ []
end
# @private
@@ -2392,7 +2396,6 @@ class Formula
# version '4.8.1'
# end</pre>
def fails_with(compiler, &block)
- # TODO: deprecate this in future.
# odeprecated "fails_with :llvm" if compiler == :llvm
specs.each { |spec| spec.fails_with(compiler, &block) }
end
diff --git a/Library/Homebrew/formula_cellar_checks.rb b/Library/Homebrew/formula_cellar_checks.rb
index 7db5e748b..7f7d77569 100644
--- a/Library/Homebrew/formula_cellar_checks.rb
+++ b/Library/Homebrew/formula_cellar_checks.rb
@@ -14,7 +14,7 @@ module FormulaCellarChecks
<<-EOS.undent
#{prefix_bin} is not in your PATH
- You can amend this by altering your #{Utils::Shell.shell_profile} file
+ You can amend this by altering your #{Utils::Shell.profile} file
EOS
end
@@ -154,17 +154,17 @@ module FormulaCellarChecks
end
def audit_installed
- audit_check_output(check_manpages)
- audit_check_output(check_infopages)
- audit_check_output(check_jars)
- audit_check_output(check_non_libraries)
- audit_check_output(check_non_executables(formula.bin))
- audit_check_output(check_generic_executables(formula.bin))
- audit_check_output(check_non_executables(formula.sbin))
- audit_check_output(check_generic_executables(formula.sbin))
- audit_check_output(check_easy_install_pth(formula.lib))
- audit_check_output(check_elisp_dirname(formula.share, formula.name))
- audit_check_output(check_elisp_root(formula.share, formula.name))
+ problem_if_output(check_manpages)
+ problem_if_output(check_infopages)
+ problem_if_output(check_jars)
+ problem_if_output(check_non_libraries)
+ problem_if_output(check_non_executables(formula.bin))
+ problem_if_output(check_generic_executables(formula.bin))
+ problem_if_output(check_non_executables(formula.sbin))
+ problem_if_output(check_generic_executables(formula.sbin))
+ problem_if_output(check_easy_install_pth(formula.lib))
+ problem_if_output(check_elisp_dirname(formula.share, formula.name))
+ problem_if_output(check_elisp_root(formula.share, formula.name))
end
alias generic_audit_installed audit_installed
diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb
index 1f91ad5c4..7fed4b24e 100644
--- a/Library/Homebrew/formula_installer.rb
+++ b/Library/Homebrew/formula_installer.rb
@@ -173,34 +173,22 @@ class FormulaInstaller
EOS
end
- if ENV["HOMEBREW_CHECK_RECURSIVE_VERSION_DEPENDENCIES"]
- version_hash = {}
- version_conflicts = Set.new
- recursive_formulae.each do |f|
- name = f.name
- unversioned_name, = name.split("@")
- version_hash[unversioned_name] ||= Set.new
- version_hash[unversioned_name] << name
- next if version_hash[unversioned_name].length < 2
- version_conflicts += version_hash[unversioned_name]
- end
- unless version_conflicts.empty?
- raise CannotInstallFormulaError, <<-EOS.undent
- #{formula.full_name} contains conflicting version recursive dependencies:
- #{version_conflicts.to_a.join ", "}
- View these with `brew deps --tree #{formula.full_name}`.
- EOS
- end
- end
-
- unless ENV["HOMEBREW_NO_CHECK_UNLINKED_DEPENDENCIES"]
- unlinked_deps = recursive_formulae.select do |dep|
- dep.installed? && !dep.keg_only? && !dep.linked_keg.directory?
- end
-
- unless unlinked_deps.empty?
- raise CannotInstallFormulaError, "You must `brew link #{unlinked_deps*" "}` before #{formula.full_name} can be installed"
- end
+ version_hash = {}
+ version_conflicts = Set.new
+ recursive_formulae.each do |f|
+ name = f.name
+ unversioned_name, = name.split("@")
+ version_hash[unversioned_name] ||= Set.new
+ version_hash[unversioned_name] << name
+ next if version_hash[unversioned_name].length < 2
+ version_conflicts += version_hash[unversioned_name]
+ end
+ unless version_conflicts.empty?
+ raise CannotInstallFormulaError, <<-EOS.undent
+ #{formula.full_name} contains conflicting version recursive dependencies:
+ #{version_conflicts.to_a.join ", "}
+ View these with `brew deps --tree #{formula.full_name}`.
+ EOS
end
pinned_unsatisfied_deps = recursive_deps.select do |dep|
@@ -410,10 +398,13 @@ class FormulaInstaller
end
def install_requirement_formula?(req, dependent, build)
- return false unless req.to_dependency
+ req_dependency = req.to_dependency
+ return false unless req_dependency
return true unless req.satisfied?
return false if req.run?
- install_bottle_for?(dependent, build) || build_bottle?
+ return true if build_bottle?
+ return true if req.satisfied_by_formula?
+ install_bottle_for?(dependent, build)
end
def expand_requirements
@@ -855,15 +846,15 @@ class FormulaInstaller
tab.write
end
- def audit_check_output(output)
+ def problem_if_output(output)
return unless output
opoo output
@show_summary_heading = true
end
def audit_installed
- audit_check_output(check_env_path(formula.bin))
- audit_check_output(check_env_path(formula.sbin))
+ problem_if_output(check_env_path(formula.bin))
+ problem_if_output(check_env_path(formula.sbin))
super
end
diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb
index dcb995a6b..b8476f5cc 100644
--- a/Library/Homebrew/formula_support.rb
+++ b/Library/Homebrew/formula_support.rb
@@ -4,6 +4,8 @@ FormulaConflict = Struct.new(:name, :reason)
# Used to annotate formulae that duplicate macOS provided software
# or cause conflicts when linked in.
class KegOnlyReason
+ attr_reader :reason
+
def initialize(reason, explanation)
@reason = reason
@explanation = explanation
diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb
index 4a65f8704..f5e6a2eb9 100644
--- a/Library/Homebrew/formulary.rb
+++ b/Library/Homebrew/formulary.rb
@@ -210,6 +210,10 @@ module Formulary
def get_formula(spec, alias_path: nil)
super
+ rescue FormulaUnreadableError => e
+ raise TapFormulaUnreadableError.new(tap, name, e.formula_error), "", e.backtrace
+ rescue FormulaClassUnavailableError => e
+ raise TapFormulaClassUnavailableError.new(tap, name, e.path, e.class_name, e.class_list), "", e.backtrace
rescue FormulaUnavailableError => e
raise TapFormulaUnavailableError.new(tap, name), "", e.backtrace
end
@@ -402,7 +406,7 @@ module Formulary
end
def self.tap_paths(name, taps = Dir["#{HOMEBREW_LIBRARY}/Taps/*/*/"])
- name = name.downcase
+ name = name.to_s.downcase
taps.map do |tap|
Pathname.glob([
"#{tap}Formula/#{name}.rb",
diff --git a/Library/Homebrew/gpg.rb b/Library/Homebrew/gpg.rb
index 066f67864..cb9e367df 100644
--- a/Library/Homebrew/gpg.rb
+++ b/Library/Homebrew/gpg.rb
@@ -5,7 +5,10 @@ class Gpg
which_all(executable).detect do |gpg|
gpg_short_version = Utils.popen_read(gpg, "--version")[/\d\.\d/, 0]
next unless gpg_short_version
- Version.create(gpg_short_version.to_s) == Version.create("2.0")
+ gpg_version = Version.create(gpg_short_version.to_s)
+ @version = gpg_version
+ gpg_version == Version.create("2.0") ||
+ gpg_version == Version.create("2.1")
end
end
@@ -23,6 +26,10 @@ class Gpg
File.executable?(GPG_EXECUTABLE.to_s)
end
+ def self.version
+ @version if available?
+ end
+
def self.create_test_key(path)
odie "No GPG present to test against!" unless available?
diff --git a/Library/Homebrew/hardware.rb b/Library/Homebrew/hardware.rb
index fe07aee9d..997598def 100644
--- a/Library/Homebrew/hardware.rb
+++ b/Library/Homebrew/hardware.rb
@@ -80,6 +80,18 @@ module Hardware
def feature?(name)
features.include?(name)
end
+
+ def can_run?(arch)
+ if is_32_bit?
+ arch_32_bit == arch
+ elsif intel?
+ [:i386, :x86_64].include? arch
+ elsif ppc?
+ [:ppc, :ppc64].include? arch
+ else
+ false
+ end
+ end
end
end
diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb
index 86733860c..d4b9c5d77 100644
--- a/Library/Homebrew/keg.rb
+++ b/Library/Homebrew/keg.rb
@@ -240,8 +240,9 @@ class Keg
def remove_opt_record
opt_record.unlink
aliases.each do |a|
- next if !opt_record.symlink? && !opt_record.exist?
- (opt_record.parent/a).delete
+ alias_symlink = opt_record.parent/a
+ next if !alias_symlink.symlink? && !alias_symlink.exist?
+ alias_symlink.delete
end
opt_record.parent.rmdir_if_possible
end
@@ -302,23 +303,24 @@ class Keg
dir = case shell
when :bash then path.join("etc", "bash_completion.d")
when :zsh
- dir = path.join("share", "zsh", "site-functions")
- dir if dir && dir.directory? && dir.children.any? { |f| f.basename.to_s.start_with?("_") }
- when :fish then path.join("share", "fish", "vendor_completions.d")
+ dir = path/"share/zsh/site-functions"
+ dir if dir.directory? && dir.children.any? { |f| f.basename.to_s.start_with?("_") }
+ when :fish then path/"share/fish/vendor_completions.d"
end
dir && dir.directory? && !dir.children.empty?
end
- def zsh_functions_installed?
- # Check for non completion functions (i.e. files not started with an underscore),
- # since those can be checked separately
- dir = path.join("share", "zsh", "site-functions")
- dir && dir.directory? && dir.children.any? { |f| !f.basename.to_s.start_with?("_") }
- end
-
- def fish_functions_installed?
- dir = path.join("share", "fish", "vendor_functions.d")
- dir && dir.directory? && !dir.children.empty?
+ def functions_installed?(shell)
+ case shell
+ when :fish
+ dir = path/"share/fish/vendor_functions.d"
+ dir.directory? && !dir.children.empty?
+ when :zsh
+ # Check for non completion functions (i.e. files not started with an underscore),
+ # since those can be checked separately
+ dir = path/"share/zsh/site-functions"
+ dir.directory? && dir.children.any? { |f| !f.basename.to_s.start_with?("_") }
+ end
end
def plist_installed?
diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb
index 834cda768..6044426ee 100644
--- a/Library/Homebrew/keg_relocate.rb
+++ b/Library/Homebrew/keg_relocate.rb
@@ -16,9 +16,12 @@ class Keg
link = file.readlink
# Don't fix relative symlinks
next unless link.absolute?
- if link.to_s.start_with?(HOMEBREW_CELLAR.to_s) || link.to_s.start_with?(HOMEBREW_PREFIX.to_s)
- FileUtils.ln_sf(link.relative_path_from(file.parent), file)
- end
+ link_starts_cellar = link.to_s.start_with?(HOMEBREW_CELLAR.to_s)
+ link_starts_prefix = link.to_s.start_with?(HOMEBREW_PREFIX.to_s)
+ next if !link_starts_cellar && !link_starts_prefix
+ new_src = link.relative_path_from(file.parent)
+ file.unlink
+ FileUtils.ln_s(new_src, file)
end
end
alias generic_fix_dynamic_linkage fix_dynamic_linkage
@@ -96,8 +99,14 @@ class Keg
[]
end
+ def recursive_fgrep_args
+ # for GNU grep; overridden for BSD grep on OS X
+ "-lr"
+ end
+ alias generic_recursive_fgrep_args recursive_fgrep_args
+
def each_unique_file_matching(string)
- Utils.popen_read("/usr/bin/fgrep", "-lr", string, to_s) do |io|
+ Utils.popen_read("/usr/bin/fgrep", recursive_fgrep_args, string, to_s) do |io|
hardlinks = Set.new
until io.eof?
diff --git a/Library/Homebrew/language/python.rb b/Library/Homebrew/language/python.rb
index 23c5246ba..0f8e3a4e6 100644
--- a/Library/Homebrew/language/python.rb
+++ b/Library/Homebrew/language/python.rb
@@ -53,29 +53,6 @@ module Language
quiet_system python, "-c", script
end
- # deprecated; use system "python", *setup_install_args(prefix) instead
- def self.setup_install(python, prefix, *args)
- opoo <<-EOS.undent
- Language::Python.setup_install is deprecated.
- If you are a formula author, please use
- system "python", *Language::Python.setup_install_args(prefix)
- instead.
- EOS
-
- # force-import setuptools, which monkey-patches distutils, to make
- # sure that we always call a setuptools setup.py. trick borrowed from pip:
- # https://github.com/pypa/pip/blob/043af83/pip/req/req_install.py#L743-L780
- shim = <<-EOS.undent
- import setuptools, tokenize
- __file__ = 'setup.py'
- exec(compile(getattr(tokenize, 'open', open)(__file__).read()
- .replace('\\r\\n', '\\n'), __file__, 'exec'))
- EOS
- args += %w[--single-version-externally-managed --record=installed.txt]
- args << "--prefix=#{prefix}"
- system python, "-c", shim, "install", *args
- end
-
def self.setup_install_args(prefix)
shim = <<-EOS.undent
import setuptools, tokenize
diff --git a/Library/Homebrew/migrator.rb b/Library/Homebrew/migrator.rb
index a80cf0c59..3cb6c5178 100644
--- a/Library/Homebrew/migrator.rb
+++ b/Library/Homebrew/migrator.rb
@@ -77,13 +77,35 @@ class Migrator
# path to newname cellar according to new name
attr_reader :new_cellar
+ # true if new cellar existed at initialization time
+ attr_reader :new_cellar_existed
+
# path to newname pin
attr_reader :new_pin_record
# path to newname keg that will be linked if old_linked_keg isn't nil
attr_reader :new_linked_keg_record
- def initialize(formula)
+ def self.needs_migration?(formula)
+ oldname = formula.oldname
+ return false unless oldname
+ oldname_rack = HOMEBREW_CELLAR/oldname
+ return false if oldname_rack.symlink?
+ return false unless oldname_rack.directory?
+ true
+ end
+
+ def self.migrate_if_needed(formula)
+ return unless Migrator.needs_migration?(formula)
+ begin
+ migrator = Migrator.new(formula)
+ migrator.migrate
+ rescue Exception => e
+ onoe e
+ end
+ end
+
+ def initialize(formula, force: ARGV.force?)
@oldname = formula.oldname
@newname = formula.name
raise MigratorNoOldnameError, formula unless oldname
@@ -95,11 +117,12 @@ class Migrator
@old_tabs = old_cellar.subdirs.map { |d| Tab.for_keg(Keg.new(d)) }
@old_tap = old_tabs.first.tap
- if !ARGV.force? && !from_same_taps?
+ if !force && !from_same_tap_user?
raise MigratorDifferentTapsError.new(formula, old_tap)
end
@new_cellar = HOMEBREW_CELLAR/formula.name
+ @new_cellar_existed = @new_cellar.exist?
if @old_linked_keg = linked_old_linked_keg
@old_linked_keg_record = old_linked_keg.linked_keg_record if old_linked_keg.linked?
@@ -121,15 +144,26 @@ class Migrator
end
end
- def from_same_taps?
- if formula.tap == old_tap
+ def from_same_tap_user?
+ formula_tap_user = formula.tap.user if formula.tap
+ old_tap_user = nil
+
+ new_tap = if old_tap
+ old_tap_user, = old_tap.user
+ if migrate_tap = old_tap.tap_migrations[formula.oldname]
+ new_tap_user, new_tap_repo = migrate_tap.split("/")
+ "#{new_tap_user}/#{new_tap_repo}"
+ end
+ end
+
+ if formula_tap_user == old_tap_user
true
# Homebrew didn't use to update tabs while performing tap-migrations,
# so there can be INSTALL_RECEIPT's containing wrong information about tap,
# so we check if there is an entry about oldname migrated to tap and if
# newname's tap is the same as tap to which oldname migrated, then we
# can perform migrations and the taps for oldname and newname are the same.
- elsif formula.tap && old_tap && formula.tap == old_tap.tap_migrations[formula.oldname]
+ elsif formula.tap && old_tap && formula.tap == new_tap
fix_tabs
true
else
@@ -138,7 +172,10 @@ class Migrator
end
def linked_old_linked_keg
- kegs = old_cellar.subdirs.map { |d| Keg.new(d) }
+ keg_dirs = []
+ keg_dirs += new_cellar.subdirs if new_cellar.exist?
+ keg_dirs += old_cellar.subdirs
+ kegs = keg_dirs.map { |d| Keg.new(d) }
kegs.detect(&:linked?) || kegs.detect(&:optlinked?)
end
@@ -147,38 +184,55 @@ class Migrator
end
def migrate
- if new_cellar.exist?
- onoe "#{new_cellar} already exists; remove it manually and run brew migrate #{oldname}."
- return
- end
-
- begin
- oh1 "Migrating #{Formatter.identifier(oldname)} to #{Formatter.identifier(newname)}"
- lock
- unlink_oldname
- move_to_new_directory
- repin
- link_oldname_cellar
- link_oldname_opt
- link_newname unless old_linked_keg.nil?
- update_tabs
- rescue Interrupt
- ignore_interrupts { backup_oldname }
- rescue Exception => e
- onoe "Error occurred while migrating."
- puts e
- puts e.backtrace if ARGV.debug?
- puts "Backuping..."
- ignore_interrupts { backup_oldname }
- ensure
- unlock
- end
+ oh1 "Migrating #{Formatter.identifier(oldname)} to #{Formatter.identifier(newname)}"
+ lock
+ unlink_oldname
+ unlink_newname if new_cellar.exist?
+ repin
+ move_to_new_directory
+ link_oldname_cellar
+ link_oldname_opt
+ link_newname unless old_linked_keg.nil?
+ update_tabs
+ rescue Interrupt
+ ignore_interrupts { backup_oldname }
+ rescue Exception => e
+ onoe "Error occurred while migrating."
+ puts e
+ puts e.backtrace if ARGV.debug?
+ puts "Backing up..."
+ ignore_interrupts { backup_oldname }
+ ensure
+ unlock
end
# move everything from Cellar/oldname to Cellar/newname
def move_to_new_directory
- puts "Moving to: #{new_cellar}"
- FileUtils.mv(old_cellar, new_cellar)
+ return unless old_cellar.exist?
+
+ if new_cellar.exist?
+ conflicted = false
+ old_cellar.each_child do |c|
+ next unless (new_cellar/c.basename).exist?
+ begin
+ FileUtils.rm_rf c
+ rescue Errno::EACCES
+ conflicted = true
+ onoe "#{new_cellar/c.basename} already exists."
+ end
+ end
+
+ if conflicted
+ odie "Remove #{new_cellar} manually and run brew migrate #{oldname}."
+ end
+ end
+
+ oh1 "Moving #{Formatter.identifier(oldname)} children"
+ if new_cellar.exist?
+ FileUtils.mv(old_cellar.children, new_cellar)
+ else
+ FileUtils.mv(old_cellar, new_cellar)
+ end
end
def repin
@@ -207,6 +261,14 @@ class Migrator
end
end
+ def unlink_newname
+ oh1 "Unlinking #{Formatter.identifier(newname)}"
+ new_cellar.subdirs.each do |d|
+ keg = Keg.new(d)
+ keg.unlink
+ end
+ end
+
def link_newname
oh1 "Linking #{Formatter.identifier(newname)}"
new_keg = Keg.new(new_linked_keg_record)
@@ -310,7 +372,7 @@ class Migrator
new_cellar.subdirs.each do |d|
newname_keg = Keg.new(d)
newname_keg.unlink
- newname_keg.uninstall
+ newname_keg.uninstall if new_cellar_existed
end
end
diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb
new file mode 100644
index 000000000..eac3d7725
--- /dev/null
+++ b/Library/Homebrew/missing_formula.rb
@@ -0,0 +1,164 @@
+require "formulary"
+require "tap"
+require "utils"
+
+module Homebrew
+ module MissingFormula
+ class << self
+ def reason(name, silent: false)
+ blacklisted_reason(name) || tap_migration_reason(name) ||
+ deleted_reason(name, silent: silent)
+ end
+
+ def blacklisted_reason(name)
+ case name.downcase
+ when "gem", /^rubygems?$/ then <<-EOS.undent
+ Homebrew provides gem via: `brew install ruby`.
+ EOS
+ when "tex", "tex-live", "texlive", "latex" then <<-EOS.undent
+ Installing TeX from source is weird and gross, requires a lot of patches,
+ and only builds 32-bit (and thus can't use Homebrew dependencies)
+
+ We recommend using a MacTeX distribution: https://www.tug.org/mactex/
+
+ You can install it with Homebrew-Cask:
+ brew cask install mactex
+ EOS
+ when "pip" then <<-EOS.undent
+ Homebrew provides pip via: `brew install python`. However you will then
+ have two Pythons installed on your Mac, so alternatively you can install
+ pip via the instructions at:
+ #{Formatter.url("https://pip.readthedocs.io/en/stable/installing/")}
+ EOS
+ when "pil" then <<-EOS.undent
+ Instead of PIL, consider `pip install pillow` or `brew install Homebrew/science/pillow`.
+ EOS
+ when "macruby" then <<-EOS.undent
+ MacRuby is not packaged and is on an indefinite development hiatus.
+ You can read more about it at:
+ #{Formatter.url("https://github.com/MacRuby/MacRuby")}
+ EOS
+ when /(lib)?lzma/
+ "lzma is now part of the xz formula."
+ when "gtest", "googletest", "google-test" then <<-EOS.undent
+ Installing gtest system-wide is not recommended; it should be vendored
+ in your projects that use it.
+ EOS
+ when "gmock", "googlemock", "google-mock" then <<-EOS.undent
+ Installing gmock system-wide is not recommended; it should be vendored
+ in your projects that use it.
+ EOS
+ when "sshpass" then <<-EOS.undent
+ We won't add sshpass because it makes it too easy for novice SSH users to
+ ruin SSH's security.
+ EOS
+ when "gsutil" then <<-EOS.undent
+ Install gsutil with `pip install gsutil`
+ EOS
+ when "clojure" then <<-EOS.undent
+ Clojure isn't really a program but a library managed as part of a
+ project and Leiningen is the user interface to that library.
+
+ To install Clojure you should install Leiningen:
+ brew install leiningen
+ and then follow the tutorial:
+ #{Formatter.url("https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md")}
+ EOS
+ when "gfortran" then <<-EOS.undent
+ GNU Fortran is now provided as part of GCC, and can be installed with:
+ brew install gcc
+ EOS
+ when "play" then <<-EOS.undent
+ Play 2.3 replaces the play command with activator:
+ brew install typesafe-activator
+
+ You can read more about this change at:
+ #{Formatter.url("https://www.playframework.com/documentation/2.3.x/Migration23")}
+ #{Formatter.url("https://www.playframework.com/documentation/2.3.x/Highlights23")}
+ EOS
+ when "haskell-platform" then <<-EOS.undent
+ We no longer package haskell-platform. Consider installing ghc
+ and cabal-install instead:
+ brew install ghc cabal-install
+
+ You can install with Homebrew-Cask:
+ brew cask install haskell-platform
+ EOS
+ when "mysqldump-secure" then <<-EOS.undent
+ The creator of mysqldump-secure tried to game our popularity metrics.
+ EOS
+ when "ngrok" then <<-EOS.undent
+ Upstream sunsetted 1.x in March 2016 and 2.x is not open-source.
+
+ If you wish to use the 2.x release you can install with Homebrew-Cask:
+ brew cask install ngrok
+ EOS
+ end
+ end
+ alias generic_blacklisted_reason blacklisted_reason
+
+ def tap_migration_reason(name)
+ message = nil
+
+ Tap.each do |old_tap|
+ new_tap = old_tap.tap_migrations[name]
+ next unless new_tap
+
+ new_tap_user, new_tap_repo, = new_tap.split("/")
+ new_tap_name = "#{new_tap_user}/#{new_tap_repo}"
+
+ message = <<-EOS.undent
+ It was migrated from #{old_tap} to #{new_tap}.
+ You can access it again by running:
+ brew tap #{new_tap_name}
+ EOS
+ break
+ end
+
+ message
+ end
+
+ def deleted_reason(name, silent: false)
+ path = Formulary.path name
+ return if File.exist? path
+ tap = Tap.from_path(path)
+ return if tap.nil? || !File.exist?(tap.path)
+ relative_path = path.relative_path_from tap.path
+
+ tap.path.cd do
+ ohai "Searching for a previously deleted formula..." unless silent
+
+ # We know this may return incomplete results for shallow clones but
+ # we don't want to nag everyone with a shallow clone to unshallow it.
+ log_command = "git log --name-only --max-count=1 --format=%H\\\\n%h\\\\n%B -- #{relative_path}"
+ hash, short_hash, *commit_message, relative_path =
+ Utils.popen_read(log_command).gsub("\\n", "\n").lines.map(&:chomp)
+
+ if hash.to_s.empty? || short_hash.to_s.empty? ||
+ relative_path.to_s.empty?
+ ofail "No previously deleted formula found." unless silent
+ return
+ end
+
+ commit_message = commit_message.reject(&:empty?).join("\n ")
+
+ commit_message.sub!(/ \(#(\d+)\)$/, " (#{tap.issues_url}/\\1)")
+ commit_message.gsub!(/(Closes|Fixes) #(\d+)/, "\\1 #{tap.issues_url}/\\2")
+
+ <<-EOS.undent
+ #{name} was deleted from #{tap.name} in commit #{short_hash}:
+ #{commit_message}
+
+ To show the formula before removal run:
+ git -C "$(brew --repo #{tap})" show #{short_hash}^:#{relative_path}
+
+ If you still use this formula consider creating your own tap:
+ http://docs.brew.sh/How-to-Create-and-Maintain-a-Tap.html
+ EOS
+ end
+ end
+
+ require "extend/os/missing_formula"
+ end
+ end
+end
diff --git a/Library/Homebrew/official_taps.rb b/Library/Homebrew/official_taps.rb
index c7b96ae64..dcb65d9f8 100644
--- a/Library/Homebrew/official_taps.rb
+++ b/Library/Homebrew/official_taps.rb
@@ -1,11 +1,13 @@
OFFICIAL_TAPS = %w[
apache
- dupes
- fuse
nginx
php
science
- tex
+].freeze
+
+OFFICIAL_CASK_TAPS = %w[
+ cask
+ versions
].freeze
OFFICIAL_CMD_TAPS = {
@@ -13,3 +15,19 @@ OFFICIAL_CMD_TAPS = {
"homebrew/test-bot" => ["test-bot"],
"homebrew/services" => ["services"],
}.freeze
+
+DEPRECATED_OFFICIAL_TAPS = %w[
+ binary
+ completions
+ devel-only
+ dupes
+ emacs
+ fuse
+ games
+ gui
+ head-only
+ python
+ tex
+ versions
+ x11
+].freeze
diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb
index e09a9b3fd..dba2480ef 100644
--- a/Library/Homebrew/os/mac.rb
+++ b/Library/Homebrew/os/mac.rb
@@ -201,6 +201,12 @@ module OS
"7.3" => { clang: "7.3", clang_build: 703 },
"7.3.1" => { clang: "7.3", clang_build: 703 },
"8.0" => { clang: "8.0", clang_build: 800 },
+ "8.1" => { clang: "8.0", clang_build: 800 },
+ "8.2" => { clang: "8.0", clang_build: 800 },
+ "8.2.1" => { clang: "8.0", clang_build: 800 },
+ "8.3" => { clang: "8.1", clang_build: 802 },
+ "8.3.1" => { clang: "8.1", clang_build: 802 },
+ "8.3.2" => { clang: "8.1", clang_build: 802 },
}.freeze
def compilers_standard?
diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb
index aa4504a17..cac0dcc30 100644
--- a/Library/Homebrew/os/mac/xcode.rb
+++ b/Library/Homebrew/os/mac/xcode.rb
@@ -16,13 +16,13 @@ module OS
when "10.8" then "5.1.1"
when "10.9" then "6.2"
when "10.10" then "7.2.1"
- when "10.11" then "8.2"
- when "10.12" then "8.2"
+ when "10.11" then "8.2.1"
+ when "10.12" then "8.3.2"
else
raise "macOS '#{MacOS.version}' is invalid" unless OS::Mac.prerelease?
# Default to newest known version of Xcode for unreleased macOS versions.
- "8.2"
+ "8.3.2"
end
end
@@ -90,7 +90,7 @@ module OS
else
<<-EOS.undent
Xcode can be updated from
- https://developer.apple.com/xcode/downloads/
+ https://developer.apple.com/download/more/
EOS
end
end
@@ -128,11 +128,10 @@ module OS
end
end
- # The remaining logic provides a fake Xcode version for CLT-only
- # systems. This behavior only exists because Homebrew used to assume
- # Xcode.version would always be non-nil. This is deprecated, and will
- # be removed in a future version. To remain compatible, guard usage of
- # Xcode.version with an Xcode.installed? check.
+ # The remaining logic provides a fake Xcode version based on the
+ # installed CLT version. This is useful as they are packaged
+ # simultaneously so workarounds need to apply to both based on their
+ # comparable version.
case (DevelopmentTools.clang_version.to_f * 10).to_i
when 0 then "dunno"
when 1..14 then "3.2.2"
@@ -152,7 +151,8 @@ module OS
when 70 then "7.0"
when 73 then "7.3"
when 80 then "8.0"
- else "8.0"
+ when 81 then "8.3"
+ else "8.3"
end
end
@@ -202,7 +202,7 @@ module OS
elsif MacOS.version == "10.8" || MacOS.version == "10.7"
<<-EOS.undent
The standalone package can be obtained from
- https://developer.apple.com/downloads
+ https://developer.apple.com/download/more/
or it can be installed via Xcode's preferences.
EOS
end
@@ -213,8 +213,8 @@ module OS
# on the older supported platform for that Xcode release, i.e there's no
# CLT package for 10.11 that contains the Clang version from Xcode 8.
case MacOS.version
- when "10.12" then "800.0.42.1"
- when "10.11" then "703.0.31"
+ when "10.12" then "802.0.38"
+ when "10.11" then "800.0.42.1"
when "10.10" then "700.1.81"
when "10.9" then "600.0.57"
when "10.8" then "503.0.40"
diff --git a/Library/Homebrew/readall.rb b/Library/Homebrew/readall.rb
index 3dd7075ec..ddac58444 100644
--- a/Library/Homebrew/readall.rb
+++ b/Library/Homebrew/readall.rb
@@ -24,14 +24,21 @@ module Readall
!failed
end
- def valid_aliases?(alias_dirs)
+ def valid_aliases?(alias_dir, formula_dir)
+ return true unless alias_dir.directory?
+
failed = false
- alias_dirs.each do |alias_dir|
- next unless alias_dir.directory?
- alias_dir.children.each do |f|
- next unless f.symlink?
- next if f.file?
- onoe "Broken alias: #{f}"
+ alias_dir.each_child do |f|
+ if !f.symlink?
+ onoe "Non-symlink alias: #{f}"
+ failed = true
+ elsif !f.file?
+ onoe "Non-file alias: #{f}"
+ failed = true
+ end
+
+ if (formula_dir/"#{f.basename}.rb").exist?
+ onoe "Formula duplicating alias: #{f}"
failed = true
end
end
@@ -57,7 +64,7 @@ module Readall
def valid_tap?(tap, options = {})
failed = false
if options[:aliases]
- valid_aliases = valid_aliases?([tap.alias_dir])
+ valid_aliases = valid_aliases?(tap.alias_dir, tap.formula_dir)
failed = true unless valid_aliases
end
valid_formulae = valid_formulae?(tap.formula_files)
diff --git a/Library/Homebrew/requirement.rb b/Library/Homebrew/requirement.rb
index 49108ca75..a4bdabdd1 100644
--- a/Library/Homebrew/requirement.rb
+++ b/Library/Homebrew/requirement.rb
@@ -125,6 +125,10 @@ class Requirement
@formula || self.class.default_formula
end
+ def satisfied_by_formula?
+ !@formula.nil?
+ end
+
def to_dependency
if formula =~ HOMEBREW_TAP_FORMULA_REGEX
TapDependency.new(formula, tags, method(:modify_build_environment), name)
@@ -157,11 +161,9 @@ class Requirement
class << self
include BuildEnvironmentDSL
- attr_reader :env_proc
+ attr_reader :env_proc, :build
attr_rw :fatal, :default_formula
attr_rw :cask, :download
- # build is deprecated, use `depends_on <requirement> => :build` instead
- attr_rw :build
def satisfy(options = {}, &block)
@satisfied ||= Requirement::Satisfier.new(options, &block)
diff --git a/Library/Homebrew/requirements.rb b/Library/Homebrew/requirements.rb
index b09dc889a..553beb2a2 100644
--- a/Library/Homebrew/requirements.rb
+++ b/Library/Homebrew/requirements.rb
@@ -43,7 +43,7 @@ class XcodeRequirement < Requirement
EOS
else
message + <<-EOS.undent
- Xcode can be installed from #{Formatter.url("https://developer.apple.com/xcode/downloads/")}
+ Xcode can be installed from #{Formatter.url("https://developer.apple.com/download/more/")}.
EOS
end
end
diff --git a/Library/Homebrew/requirements/gpg2_requirement.rb b/Library/Homebrew/requirements/gpg2_requirement.rb
index 00bf4183a..97fabcca0 100644
--- a/Library/Homebrew/requirements/gpg2_requirement.rb
+++ b/Library/Homebrew/requirements/gpg2_requirement.rb
@@ -3,10 +3,10 @@ require "gpg"
class GPG2Requirement < Requirement
fatal true
- default_formula "gnupg2"
+ default_formula "gnupg"
# MacGPG2/GPGTools installs GnuPG 2.0.x as a vanilla `gpg` symlink
# pointing to `gpg2`, as do we. Ensure we're actually using a 2.0 `gpg`.
- # Temporarily, only support 2.0.x rather than the 2.1.x "modern" series.
+ # Support both the 2.0.x "stable" and 2.1.x "modern" series.
satisfy(build_env: false) { Gpg.gpg2 || Gpg.gpg }
end
diff --git a/Library/Homebrew/requirements/java_requirement.rb b/Library/Homebrew/requirements/java_requirement.rb
index 0887b69c7..653846edd 100644
--- a/Library/Homebrew/requirements/java_requirement.rb
+++ b/Library/Homebrew/requirements/java_requirement.rb
@@ -18,7 +18,7 @@ class JavaRequirement < Requirement
def message
version_string = " #{@version}" if @version
- s = "Java#{version_string} is required to install this formula."
+ s = "Java#{version_string} is required to install this formula.\n"
s += super
s
end
diff --git a/Library/Homebrew/requirements/osxfuse_requirement.rb b/Library/Homebrew/requirements/osxfuse_requirement.rb
index d5a341567..9a07209d4 100644
--- a/Library/Homebrew/requirements/osxfuse_requirement.rb
+++ b/Library/Homebrew/requirements/osxfuse_requirement.rb
@@ -2,34 +2,10 @@ require "requirement"
class OsxfuseRequirement < Requirement
fatal true
- cask "osxfuse"
- download "https://osxfuse.github.io/"
-
- satisfy(build_env: false) { self.class.binary_osxfuse_installed? }
-
- def self.binary_osxfuse_installed?
- File.exist?("/usr/local/include/osxfuse/fuse.h") &&
- !File.symlink?("/usr/local/include/osxfuse")
- end
-
- env do
- ENV.append_path "PKG_CONFIG_PATH", HOMEBREW_LIBRARY/"Homebrew/os/mac/pkgconfig/fuse"
-
- unless HOMEBREW_PREFIX.to_s == "/usr/local"
- ENV.append_path "HOMEBREW_LIBRARY_PATHS", "/usr/local/lib"
- ENV.append_path "HOMEBREW_INCLUDE_PATHS", "/usr/local/include/osxfuse"
- end
- end
end
class NonBinaryOsxfuseRequirement < Requirement
- fatal true
- satisfy(build_env: false) { HOMEBREW_PREFIX.to_s != "/usr/local" || !OsxfuseRequirement.binary_osxfuse_installed? }
-
- def message
- <<-EOS.undent
- osxfuse is already installed from the binary distribution and
- conflicts with this formula.
- EOS
- end
+ fatal false
end
+
+require "extend/os/requirements/osxfuse_requirement"
diff --git a/Library/Homebrew/requirements/ruby_requirement.rb b/Library/Homebrew/requirements/ruby_requirement.rb
index 327c13170..acc655924 100644
--- a/Library/Homebrew/requirements/ruby_requirement.rb
+++ b/Library/Homebrew/requirements/ruby_requirement.rb
@@ -11,7 +11,7 @@ class RubyRequirement < Requirement
satisfy(build_env: false) { new_enough_ruby }
env do
- ENV.prepend_path "PATH", new_enough_ruby
+ ENV.prepend_path "PATH", new_enough_ruby.dirname
end
def message
diff --git a/Library/Homebrew/rubocops.rb b/Library/Homebrew/rubocops.rb
index 1a28dd213..3625f2004 100644
--- a/Library/Homebrew/rubocops.rb
+++ b/Library/Homebrew/rubocops.rb
@@ -1 +1,2 @@
require_relative "./rubocops/bottle_block_cop"
+require_relative "./rubocops/formula_desc_cop"
diff --git a/Library/Homebrew/rubocops/bottle_block_cop.rb b/Library/Homebrew/rubocops/bottle_block_cop.rb
index 55eb55152..4d7a94461 100644
--- a/Library/Homebrew/rubocops/bottle_block_cop.rb
+++ b/Library/Homebrew/rubocops/bottle_block_cop.rb
@@ -1,16 +1,19 @@
+require_relative "./extend/formula_cop"
+
module RuboCop
module Cop
module Homebrew
- class CorrectBottleBlock < Cop
- MSG = "Use rebuild instead of revision in bottle block".freeze
+ # This cop audits `bottle` block in Formulae
+ #
+ # - `rebuild` should be used instead of `revision` in `bottle` block
- def on_block(node)
- return if block_length(node).zero?
- method, _args, body = *node
- _keyword, method_name = *method
+ class CorrectBottleBlock < FormulaCop
+ MSG = "Use rebuild instead of revision in bottle block".freeze
- return unless method_name == :bottle
- check_revision?(body)
+ def audit_formula(_node, _class_node, _parent_class_node, formula_class_body_node)
+ bottle = find_block(formula_class_body_node, :bottle)
+ return if bottle.nil? || block_size(bottle).zero?
+ problem "Use rebuild instead of revision in bottle block" if method_called?(bottle, :revision)
end
private
@@ -22,14 +25,6 @@ module RuboCop
corrector.remove(node.source_range)
end
end
-
- def check_revision?(body)
- body.children.each do |method_call_node|
- _receiver, method_name, _args = *method_call_node
- next unless method_name == :revision
- add_offense(method_call_node, :expression)
- end
- end
end
end
end
diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb
new file mode 100644
index 000000000..49108bd48
--- /dev/null
+++ b/Library/Homebrew/rubocops/extend/formula_cop.rb
@@ -0,0 +1,144 @@
+module RuboCop
+ module Cop
+ module Homebrew
+ class FormulaCop < Cop
+ @registry = Cop.registry
+
+ def on_class(node)
+ # This method is called by RuboCop and is the main entry point
+ file_path = processed_source.buffer.name
+ return unless file_path_allowed?(file_path)
+ class_node, parent_class_node, body = *node
+ return unless formula_class?(parent_class_node)
+ return unless respond_to?(:audit_formula)
+ @formula_name = class_name(class_node)
+ audit_formula(node, class_node, parent_class_node, body)
+ end
+
+ def regex_match_group(node, pattern)
+ # Checks for regex match of pattern in the node and
+ # Sets the appropriate instance variables to report the match
+ string_repr = string_content(node)
+ match_object = string_repr.match(pattern)
+ return unless match_object
+ node_begin_pos = start_column(node)
+ line_begin_pos = line_start_column(node)
+ @column = node_begin_pos + match_object.begin(0) - line_begin_pos + 1
+ @length = match_object.to_s.length
+ @line_no = line_number(node)
+ @source_buf = source_buffer(node)
+ @offense_source_range = source_range(@source_buf, @line_no, @column, @length)
+ @offensive_node = node
+ match_object
+ end
+
+ def find_node_method_by_name(node, method_name)
+ # Returns method_node matching method_name
+ return if node.nil?
+ node.each_child_node(:send) do |method_node|
+ next unless method_node.method_name == method_name
+ @offensive_node = method_node
+ @offense_source_range = method_node.source_range
+ return method_node
+ end
+ # If not found then, parent node becomes the offensive node
+ @offensive_node = node.parent
+ @offense_source_range = node.parent.source_range
+ nil
+ end
+
+ def find_block(node, block_name)
+ # Returns a block named block_name inside node
+ return if node.nil?
+ node.each_child_node(:block) do |block_node|
+ next if block_node.method_name != block_name
+ @offensive_node = block_node
+ @offense_source_range = block_node.source_range
+ return block_node
+ end
+ # If not found then, parent node becomes the offensive node
+ @offensive_node = node.parent
+ @offense_source_range = node.parent.source_range
+ nil
+ end
+
+ def method_called?(node, method_name)
+ # Check if a method is called inside a block
+ block_body = node.children[2]
+ block_body.each_child_node(:send) do |call_node|
+ next unless call_node.method_name == method_name
+ @offensive_node = call_node
+ @offense_source_range = call_node.source_range
+ return true
+ end
+ false
+ end
+
+ def parameters(method_node)
+ # Returns the array of arguments of the method_node
+ return unless method_node.send_type?
+ method_node.method_args
+ end
+
+ def line_start_column(node)
+ # Returns the begin position of the node's line in source code
+ node.source_range.source_buffer.line_range(node.loc.line).begin_pos
+ end
+
+ def start_column(node)
+ # Returns the begin position of the node in source code
+ node.source_range.begin_pos
+ end
+
+ def line_number(node)
+ # Returns the line number of the node
+ node.loc.line
+ end
+
+ def class_name(node)
+ # Returns the class node's name, nil if not a class node
+ @offensive_node = node
+ @offense_source_range = node.source_range
+ node.const_name
+ end
+
+ def size(node)
+ # Returns the node size in the source code
+ node.source_range.size
+ end
+
+ def block_size(block)
+ # Returns the block length of the block node
+ block_length(block)
+ end
+
+ def source_buffer(node)
+ # Source buffer is required as an argument to report style violations
+ node.source_range.source_buffer
+ end
+
+ def string_content(node)
+ # Returns the string representation if node is of type str
+ node.str_content if node.type == :str
+ end
+
+ def problem(msg)
+ add_offense(@offensive_node, @offense_source_range, msg)
+ end
+
+ private
+
+ def formula_class?(parent_class_node)
+ parent_class_node && parent_class_node.const_name == "Formula"
+ end
+
+ def file_path_allowed?(file_path)
+ paths_to_exclude = [%r{/Library/Homebrew/compat/},
+ %r{/Library/Homebrew/test/}]
+ return true if file_path.nil? # file_path is nil when source is directly passed to the cop eg., in specs
+ file_path !~ Regexp.union(paths_to_exclude)
+ end
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/rubocops/formula_desc_cop.rb b/Library/Homebrew/rubocops/formula_desc_cop.rb
new file mode 100644
index 000000000..7d69a48e7
--- /dev/null
+++ b/Library/Homebrew/rubocops/formula_desc_cop.rb
@@ -0,0 +1,48 @@
+require_relative "./extend/formula_cop"
+require_relative "../extend/string"
+
+module RuboCop
+ module Cop
+ module Homebrew
+ # This cop audits `desc` in Formulae
+ #
+ # - Checks for existence of `desc`
+ # - Checks if size of `desc` > 80
+ # - Checks if `desc` begins with an article
+ # - Checks for correct usage of `command-line` in `desc`
+ # - Checks if `desc` contains the formula name
+ class FormulaDesc < FormulaCop
+ def audit_formula(_node, _class_node, _parent_class_node, body)
+ desc_call = find_node_method_by_name(body, :desc)
+
+ if desc_call.nil?
+ problem "Formula should have a desc (Description)."
+ return
+ end
+
+ desc = parameters(desc_call).first
+ desc_length = "#{@formula_name}: #{string_content(desc)}".length
+ max_desc_length = 80
+ if desc_length > max_desc_length
+ problem <<-EOS.undent
+ Description is too long. "name: desc" should be less than #{max_desc_length} characters.
+ Length is calculated as #{@formula_name} + desc. (currently #{desc_length})
+ EOS
+ end
+
+ # Check if command-line is wrongly used in formula's desc
+ if match = regex_match_group(desc, /(command ?line)/i)
+ problem "Description should use \"command-line\" instead of \"#{match}\""
+ end
+
+ if match = regex_match_group(desc, /^(an?)\s/i)
+ problem "Description shouldn't start with an indefinite article (#{match})"
+ end
+
+ # Check if formula's name is used in formula's desc
+ problem "Description shouldn't include the formula name" if regex_match_group(desc, /^#{@formula_name}/i)
+ end
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb
index fb07f6c55..1d2e4bf64 100644
--- a/Library/Homebrew/software_spec.rb
+++ b/Library/Homebrew/software_spec.rb
@@ -117,8 +117,7 @@ class SoftwareSpec
def option(name, description = "")
opt = PREDEFINED_OPTIONS.fetch(name) do
if name.is_a?(Symbol)
- opoo "Passing arbitrary symbols to `option` is deprecated: #{name.inspect}"
- puts "Symbols are reserved for future use, please pass a string instead"
+ odeprecated "passing arbitrary symbols (i.e. #{name.inspect}) to `option`"
name = name.to_s
end
unless name.is_a?(String)
@@ -172,7 +171,6 @@ class SoftwareSpec
end
def fails_with(compiler, &block)
- # TODO: deprecate this in future.
# odeprecated "fails_with :llvm" if compiler == :llvm
compiler_failures << CompilerFailure.create(compiler, &block)
end
diff --git a/Library/Homebrew/tab.rb b/Library/Homebrew/tab.rb
index fd59539df..db4b1c585 100644
--- a/Library/Homebrew/tab.rb
+++ b/Library/Homebrew/tab.rb
@@ -100,11 +100,14 @@ class Tab < OpenStruct
def self.for_keg(keg)
path = keg.join(FILENAME)
- if path.exist?
+ tab = if path.exist?
from_file(path)
else
empty
end
+
+ tab["tabfile"] = path
+ tab
end
# Returns a tab for the named formula's installation,
diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb
index ba55e3cf6..c3af73c7e 100644
--- a/Library/Homebrew/tap.rb
+++ b/Library/Homebrew/tap.rb
@@ -41,6 +41,15 @@ class Tap
CACHE.fetch(cache_key) { |key| CACHE[key] = Tap.new(user, repo) }
end
+ def self.from_path(path)
+ path.to_s =~ HOMEBREW_TAP_PATH_REGEX
+ raise "Invalid tap path '#{path}'" unless $1
+ fetch($1, $2)
+ rescue
+ # No need to error as a nil tap is sufficient to show failure.
+ nil
+ end
+
extend Enumerable
# The user name of this {Tap}. Usually, it's the Github username of
@@ -192,6 +201,10 @@ class Tap
quiet = options.fetch(:quiet, false)
requested_remote = options[:clone_target] || default_remote
+ if official? && DEPRECATED_OFFICIAL_TAPS.include?(repo)
+ opoo "#{name} was deprecated. This tap is now empty as all its formulae were migrated."
+ end
+
if installed?
raise TapAlreadyTappedError, name unless full_clone
raise TapAlreadyUnshallowError, name unless shallow?
diff --git a/Library/Homebrew/test/.bundle/config b/Library/Homebrew/test/.bundle/config
index e451829e9..20549341c 100644
--- a/Library/Homebrew/test/.bundle/config
+++ b/Library/Homebrew/test/.bundle/config
@@ -1,3 +1,4 @@
---
BUNDLE_PATH: "../vendor/bundle"
BUNDLE_DISABLE_SHARED_GEMS: "true"
+BUNDLE_BIN: "../bin"
diff --git a/Library/Homebrew/test/Gemfile b/Library/Homebrew/test/Gemfile
index bc9bccfbc..f3c16c710 100644
--- a/Library/Homebrew/test/Gemfile
+++ b/Library/Homebrew/test/Gemfile
@@ -2,6 +2,7 @@ source "https://rubygems.org"
gem "parallel_tests"
gem "rspec"
+gem "rubocop"
gem "rspec-its", require: false
gem "rspec-wait", require: false
diff --git a/Library/Homebrew/test/Gemfile.lock b/Library/Homebrew/test/Gemfile.lock
index 64561be71..4d4eefd7d 100644
--- a/Library/Homebrew/test/Gemfile.lock
+++ b/Library/Homebrew/test/Gemfile.lock
@@ -1,6 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
+ ast (2.3.0)
codecov (0.1.9)
json
simplecov
@@ -11,6 +12,10 @@ GEM
parallel (1.10.0)
parallel_tests (2.13.0)
parallel
+ parser (2.4.0.0)
+ ast (~> 2.2)
+ powerpack (0.1.1)
+ rainbow (2.2.1)
rspec (3.5.0)
rspec-core (~> 3.5.0)
rspec-expectations (~> 3.5.0)
@@ -29,11 +34,19 @@ GEM
rspec-support (3.5.0)
rspec-wait (0.0.9)
rspec (>= 3, < 4)
+ rubocop (0.47.1)
+ parser (>= 2.3.3.1, < 3.0)
+ powerpack (~> 0.1)
+ rainbow (>= 1.99.1, < 3.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (~> 1.0, >= 1.0.1)
+ ruby-progressbar (1.8.1)
simplecov (0.13.0)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
+ unicode-display_width (1.1.3)
url (0.3.2)
PLATFORMS
@@ -45,6 +58,7 @@ DEPENDENCIES
rspec
rspec-its
rspec-wait
+ rubocop
simplecov
BUNDLED WITH
diff --git a/Library/Homebrew/test/blacklist_spec.rb b/Library/Homebrew/test/blacklist_spec.rb
deleted file mode 100644
index 01882167d..000000000
--- a/Library/Homebrew/test/blacklist_spec.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-require "blacklist"
-
-describe "Blacklist" do
- matcher(:be_blacklisted) { match(&method(:blacklisted?)) }
-
- context "rubygems" do
- %w[gem rubygem rubygems].each do |s|
- subject { s }
-
- it { is_expected.to be_blacklisted }
- end
- end
-
- context "latex" do
- %w[latex tex tex-live texlive TexLive].each do |s|
- subject { s }
-
- it { is_expected.to be_blacklisted }
- end
- end
-
- context "pip" do
- subject { "pip" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "pil" do
- subject { "pil" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "macruby" do
- subject { "MacRuby" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "lzma" do
- %w[lzma liblzma].each do |s|
- subject { s }
-
- it { is_expected.to be_blacklisted }
- end
- end
-
- context "gtest" do
- %w[gtest googletest google-test].each do |s|
- subject { s }
-
- it { is_expected.to be_blacklisted }
- end
- end
-
- context "gmock" do
- %w[gmock googlemock google-mock].each do |s|
- subject { s }
-
- it { is_expected.to be_blacklisted }
- end
- end
-
- context "sshpass" do
- subject { "sshpass" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "gsutil" do
- subject { "gsutil" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "clojure" do
- subject { "clojure" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "osmium" do
- %w[osmium Osmium].each do |s|
- subject { s }
-
- it { is_expected.to be_blacklisted }
- end
- end
-
- context "gfortran" do
- subject { "gfortran" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "play" do
- subject { "play" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "haskell-platform" do
- subject { "haskell-platform" }
-
- it { is_expected.to be_blacklisted }
- end
-
- context "xcode", :needs_macos do
- %w[xcode Xcode].each do |s|
- subject { s }
-
- it { is_expected.to be_blacklisted }
- end
- end
-end
diff --git a/Library/Homebrew/test/cask/artifact/binary_spec.rb b/Library/Homebrew/test/cask/artifact/binary_spec.rb
index 69bde3438..ee62e6439 100644
--- a/Library/Homebrew/test/cask/artifact/binary_spec.rb
+++ b/Library/Homebrew/test/cask/artifact/binary_spec.rb
@@ -6,9 +6,7 @@ describe Hbc::Artifact::Binary, :cask do
end
end
}
- let(:expected_path) {
- Hbc.binarydir.join("binary")
- }
+ let(:expected_path) { Hbc.binarydir.join("binary") }
before(:each) do
Hbc.binarydir.mkpath
@@ -26,15 +24,28 @@ describe Hbc::Artifact::Binary, :cask do
expect(expected_path.readlink).to exist
end
- it "makes the binary executable" do
- expect(FileUtils).to receive(:chmod).with("+x", cask.staged_path.join("binary"))
+ context "when the binary is not executable" do
+ let(:cask) {
+ Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-non-executable-binary.rb").tap do |cask|
+ shutup do
+ InstallHelper.install_without_artifacts(cask)
+ end
+ end
+ }
- shutup do
- Hbc::Artifact::Binary.new(cask).install_phase
- end
+ let(:expected_path) { Hbc.binarydir.join("naked_non_executable") }
- expect(expected_path).to be_a_symlink
- expect(expected_path.readlink).to be_executable
+ it "makes the binary executable" do
+ expect(FileUtils).to receive(:chmod)
+ .with("+x", cask.staged_path.join("naked_non_executable")).and_call_original
+
+ shutup do
+ Hbc::Artifact::Binary.new(cask).install_phase
+ end
+
+ expect(expected_path).to be_a_symlink
+ expect(expected_path.readlink).to be_executable
+ end
end
it "avoids clobbering an existing binary by linking over it" do
diff --git a/Library/Homebrew/test/cask/cask_spec.rb b/Library/Homebrew/test/cask/cask_spec.rb
index 2ab966f82..3736f3c01 100644
--- a/Library/Homebrew/test/cask/cask_spec.rb
+++ b/Library/Homebrew/test/cask/cask_spec.rb
@@ -85,8 +85,8 @@ describe Hbc::Cask, :cask do
it "proposes a versioned metadata directory name for each instance" do
cask_token = "local-caffeine"
c = Hbc::CaskLoader.load(cask_token)
- metadata_path = Hbc.caskroom.join(cask_token, ".metadata", c.version)
- expect(c.metadata_versioned_container_path.to_s).to eq(metadata_path.to_s)
+ metadata_timestamped_path = Hbc.caskroom.join(cask_token, ".metadata", c.version)
+ expect(c.metadata_versioned_path.to_s).to eq(metadata_timestamped_path.to_s)
end
end
diff --git a/Library/Homebrew/test/cask/cli/style_spec.rb b/Library/Homebrew/test/cask/cli/style_spec.rb
index ca17c5e46..d41636beb 100644
--- a/Library/Homebrew/test/cask/cli/style_spec.rb
+++ b/Library/Homebrew/test/cask/cli/style_spec.rb
@@ -81,7 +81,7 @@ describe Hbc::CLI::Style, :cask do
end
context "version" do
- it "matches `HOMEBREW_RUBOCOP_VERSION`" do
+ it "matches `HOMEBREW_RUBOCOP_VERSION`", :needs_network do
stdout, status = Open3.capture2("gem", "dependency", "rubocop-cask", "--version", HOMEBREW_RUBOCOP_CASK_VERSION, "--pipe", "--remote")
expect(status).to be_a_success
diff --git a/Library/Homebrew/test/cask/dsl_spec.rb b/Library/Homebrew/test/cask/dsl_spec.rb
index 7872b42a6..7eeabcf49 100644
--- a/Library/Homebrew/test/cask/dsl_spec.rb
+++ b/Library/Homebrew/test/cask/dsl_spec.rb
@@ -26,8 +26,6 @@ describe Hbc::DSL, :cask do
.*
Unexpected method 'future_feature' called on Cask unexpected-method-cask\\.
.*
- https://github.com/caskroom/homebrew-cask/blob/master/doc/reporting_bugs/pre_bug_report.md
- .*
https://github.com/caskroom/homebrew-cask#reporting-bugs
EOS
diff --git a/Library/Homebrew/test/cask/installer_spec.rb b/Library/Homebrew/test/cask/installer_spec.rb
index 7dd5b2bda..59d61bbdd 100644
--- a/Library/Homebrew/test/cask/installer_spec.rb
+++ b/Library/Homebrew/test/cask/installer_spec.rb
@@ -336,9 +336,8 @@ describe Hbc::Installer, :cask do
Hbc::Installer.new(caffeine).install
end
- m_path = caffeine.metadata_path(:now, true)
- expect(caffeine.metadata_path(:now, false)).to eq(m_path)
- expect(caffeine.metadata_path(:latest)).to eq(m_path)
+ m_path = caffeine.metadata_timestamped_path(timestamp: :now, create: true)
+ expect(caffeine.metadata_timestamped_path(timestamp: :latest)).to eq(m_path)
end
it "generates and finds a metadata subdirectory for an installed Cask" do
@@ -349,9 +348,8 @@ describe Hbc::Installer, :cask do
end
subdir_name = "Casks"
- m_subdir = caffeine.metadata_subdir(subdir_name, :now, true)
- expect(caffeine.metadata_subdir(subdir_name, :now, false)).to eq(m_subdir)
- expect(caffeine.metadata_subdir(subdir_name, :latest)).to eq(m_subdir)
+ m_subdir = caffeine.metadata_subdir(subdir_name, timestamp: :now, create: true)
+ expect(caffeine.metadata_subdir(subdir_name, timestamp: :latest)).to eq(m_subdir)
end
end
diff --git a/Library/Homebrew/test/cask/pkg_spec.rb b/Library/Homebrew/test/cask/pkg_spec.rb
index 9930cd00f..e507ceda0 100644
--- a/Library/Homebrew/test/cask/pkg_spec.rb
+++ b/Library/Homebrew/test/cask/pkg_spec.rb
@@ -36,7 +36,12 @@ describe Hbc::Pkg, :cask do
it "forgets the pkg" do
allow(fake_system_command).to receive(:run!).with(
"/usr/sbin/pkgutil",
- args: ["--export-plist", "my.fake.pkg"],
+ args: ["--pkg-info-plist", "my.fake.pkg"],
+ ).and_return(empty_response)
+
+ expect(fake_system_command).to receive(:run!).with(
+ "/usr/sbin/pkgutil",
+ args: ["--files", "my.fake.pkg"],
).and_return(empty_response)
expect(fake_system_command).to receive(:run!).with(
@@ -139,7 +144,7 @@ describe Hbc::Pkg, :cask do
expect(fake_system_command).to receive(:run!).with(
"/usr/sbin/pkgutil",
- args: ["--export-plist", pkg_id],
+ args: ["--pkg-info-plist", pkg_id],
).and_return(
Hbc::SystemCommand::Result.new(nil, pkg_info_plist, nil, 0),
)
diff --git a/Library/Homebrew/test/cleanup_spec.rb b/Library/Homebrew/test/cleanup_spec.rb
index b0e824767..2c3eddb8c 100644
--- a/Library/Homebrew/test/cleanup_spec.rb
+++ b/Library/Homebrew/test/cleanup_spec.rb
@@ -34,6 +34,39 @@ describe Homebrew::Cleanup do
expect(ds_store).to exist
end
+
+ context "when it can't remove a keg" do
+ let(:f1) { Class.new(Testball) { version "0.1" }.new }
+ let(:f2) { Class.new(Testball) { version "0.2" }.new }
+ let(:unremovable_kegs) { [] }
+
+ before(:each) do
+ described_class.instance_variable_set(:@unremovable_kegs, [])
+ shutup do
+ [f1, f2].each do |f|
+ f.brew do
+ f.install
+ end
+
+ Tab.create(f, DevelopmentTools.default_compiler, :libcxx).write
+ end
+ end
+
+ allow_any_instance_of(Keg)
+ .to receive(:uninstall)
+ .and_raise(Errno::EACCES)
+ end
+
+ it "doesn't remove any kegs" do
+ shutup { described_class.cleanup_formula f2 }
+ expect(f1.installed_kegs.size).to eq(2)
+ end
+
+ it "lists the unremovable kegs" do
+ shutup { described_class.cleanup_formula f2 }
+ expect(described_class.unremovable_kegs).to contain_exactly(f1.installed_kegs[0])
+ end
+ end
end
specify "::cleanup_formula" do
diff --git a/Library/Homebrew/test/cmd/bundle_spec.rb b/Library/Homebrew/test/cmd/bundle_spec.rb
index 13f13485c..286ddba97 100644
--- a/Library/Homebrew/test/cmd/bundle_spec.rb
+++ b/Library/Homebrew/test/cmd/bundle_spec.rb
@@ -1,6 +1,6 @@
describe "brew bundle", :integration_test, :needs_test_cmd_taps do
describe "check" do
- it "checks if a Brewfile's dependencies are satisfied" do
+ it "checks if a Brewfile's dependencies are satisfied", :needs_network do
setup_remote_tap "homebrew/bundle"
HOMEBREW_REPOSITORY.cd do
diff --git a/Library/Homebrew/test/cmd/link_spec.rb b/Library/Homebrew/test/cmd/link_spec.rb
index 7b85c96dc..59ab86cc4 100644
--- a/Library/Homebrew/test/cmd/link_spec.rb
+++ b/Library/Homebrew/test/cmd/link_spec.rb
@@ -48,9 +48,11 @@ describe "brew link", :integration_test do
expect { brew "install", "testball1" }.to be_a_success
end
- expect { brew "link", "testball1" }
+ expect { brew "link", "testball1", "SHELL" => "/bin/zsh" }
.to output(/testball1 is keg-only/).to_stderr
- .and output(/Note that doing so can interfere with building software\./).to_stdout
+ .and output(a_string_matching(/Note that doing so can interfere with building software\./)
+ .and(matching("If you need to have this software first in your PATH instead consider running:")
+ .and(including("echo 'export PATH=\"#{HOMEBREW_PREFIX}/opt/testball1/bin:$PATH\"' >> ~/.zshrc")))).to_stdout
.and be_a_success
end
end
diff --git a/Library/Homebrew/test/cmd/log_spec.rb b/Library/Homebrew/test/cmd/log_spec.rb
index bdbca8912..b9e3e8d3e 100644
--- a/Library/Homebrew/test/cmd/log_spec.rb
+++ b/Library/Homebrew/test/cmd/log_spec.rb
@@ -33,7 +33,7 @@ describe "brew log", :integration_test do
expect { brew "log", "#{shallow_tap}/testball" }
.to output(/This is a test commit for Testball/).to_stdout
- .and output(/Warning: The git repository is a shallow clone/).to_stderr
+ .and output(%r{Warning: homebrew/shallow is a shallow clone}).to_stderr
.and be_a_success
expect(shallow_tap.path/".git/shallow").to exist, "A shallow clone should have been created."
diff --git a/Library/Homebrew/test/cmd/outdated_spec.rb b/Library/Homebrew/test/cmd/outdated_spec.rb
index 2ce0825e8..65cce27c3 100644
--- a/Library/Homebrew/test/cmd/outdated_spec.rb
+++ b/Library/Homebrew/test/cmd/outdated_spec.rb
@@ -1,11 +1,87 @@
describe "brew outdated", :integration_test do
- it "prints outdated Formulae" do
- setup_test_formula "testball"
- (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath
-
- expect { brew "outdated" }
- .to output("testball\n").to_stdout
- .and not_to_output.to_stderr
- .and be_a_success
+ context "quiet output" do
+ it "prints outdated Formulae" do
+ setup_test_formula "testball"
+ (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath
+
+ expect { brew "outdated" }
+ .to output("testball\n").to_stdout
+ .and not_to_output.to_stderr
+ .and be_a_success
+ end
+ end
+
+ context "verbose output" do
+ it "prints out the installed and newer versions" do
+ setup_test_formula "testball"
+ (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath
+
+ expect { brew "outdated", "--verbose" }
+ .to output("testball (0.0.1) < 0.1\n").to_stdout
+ .and not_to_output.to_stderr
+ .and be_a_success
+ end
+ end
+
+ context "pinned formula, verbose output" do
+ it "prints out the pinned version" do
+ setup_test_formula "testball"
+ (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath
+
+ shutup do
+ expect { brew "pin", "testball" }.to be_a_success
+ end
+
+ expect { brew "outdated", "--verbose" }
+ .to output("testball (0.0.1) < 0.1 [pinned at 0.0.1]\n").to_stdout
+ .and not_to_output.to_stderr
+ .and be_a_success
+ end
+ end
+
+ context "json output" do
+ it "includes pinned version in the json output" do
+ setup_test_formula "testball"
+ (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath
+
+ shutup do
+ expect { brew "pin", "testball" }.to be_a_success
+ end
+
+ expected_json = [
+ {
+ name: "testball",
+ installed_versions: ["0.0.1"],
+ current_version: "0.1",
+ pinned: true,
+ pinned_version: "0.0.1",
+ },
+ ].to_json
+
+ expect { brew "outdated", "--json=v1" }
+ .to output(expected_json + "\n").to_stdout
+ .and not_to_output.to_stderr
+ .and be_a_success
+ end
+
+ it "has no pinned version when the formula isn't pinned" do
+ setup_test_formula "testball"
+ (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath
+
+ expected_json = [
+ {
+ name: "testball",
+ installed_versions: ["0.0.1"],
+ current_version: "0.1",
+ pinned: false,
+ pinned_version: nil,
+ },
+ ].to_json
+
+ expect { brew "outdated", "--json=v1" }
+ .to output(expected_json + "\n").to_stdout
+ .and not_to_output.to_stderr
+ .and be_a_success
+ end
end
end
diff --git a/Library/Homebrew/test/compiler_selector_spec.rb b/Library/Homebrew/test/compiler_selector_spec.rb
index 0f6f6b5f2..18efbfd42 100644
--- a/Library/Homebrew/test/compiler_selector_spec.rb
+++ b/Library/Homebrew/test/compiler_selector_spec.rb
@@ -3,7 +3,7 @@ require "software_spec"
describe CompilerSelector do
subject { described_class.new(software_spec, versions, compilers) }
- let(:compilers) { [:clang, :gcc, :llvm, :gnu] }
+ let(:compilers) { [:clang, :gcc, :gnu] }
let(:software_spec) { SoftwareSpec.new }
let(:cc) { :clang }
let(:versions) do
@@ -28,7 +28,6 @@ describe CompilerSelector do
describe "#compiler" do
it "raises an error if no matching compiler can be found" do
software_spec.fails_with(:clang)
- software_spec.fails_with(:llvm)
software_spec.fails_with(:gcc)
software_spec.fails_with(gcc: "4.8")
software_spec.fails_with(gcc: "4.7")
@@ -45,11 +44,6 @@ describe CompilerSelector do
expect(subject.compiler).to eq(:gcc)
end
- it "returns clang if it fails with llvm" do
- software_spec.fails_with(:llvm)
- expect(subject.compiler).to eq(:clang)
- end
-
it "returns clang if it fails with gcc" do
software_spec.fails_with(:gcc)
expect(subject.compiler).to eq(:clang)
@@ -68,13 +62,11 @@ describe CompilerSelector do
it "returns gcc if it fails with clang and llvm" do
software_spec.fails_with(:clang)
- software_spec.fails_with(:llvm)
expect(subject.compiler).to eq(:gcc)
end
it "returns clang if it fails with gcc and llvm" do
software_spec.fails_with(:gcc)
- software_spec.fails_with(:llvm)
expect(subject.compiler).to eq(:clang)
end
@@ -87,7 +79,6 @@ describe CompilerSelector do
example "returns a lower version of gcc if it fails with the highest version" do
software_spec.fails_with(:clang)
software_spec.fails_with(:gcc)
- software_spec.fails_with(:llvm)
software_spec.fails_with(gcc: "4.8")
expect(subject.compiler).to eq("gcc-4.7")
end
@@ -102,7 +93,6 @@ describe CompilerSelector do
allow(versions).to receive(:gcc_build_version).and_return(Version::NULL)
software_spec.fails_with(:clang)
- software_spec.fails_with(:llvm)
software_spec.fails_with(gcc: "4.8")
software_spec.fails_with(gcc: "4.7")
diff --git a/Library/Homebrew/test/dev-cmd/audit_spec.rb b/Library/Homebrew/test/dev-cmd/audit_spec.rb
index ec1a34fb4..8a8096849 100644
--- a/Library/Homebrew/test/dev-cmd/audit_spec.rb
+++ b/Library/Homebrew/test/dev-cmd/audit_spec.rb
@@ -303,7 +303,7 @@ describe FormulaAuditor do
end
end
- describe "#audit_line" do
+ describe "#line_problems" do
specify "pkgshare" do
fa = formula_auditor "foo", <<-EOS.undent, strict: true
class Foo < Formula
@@ -311,25 +311,25 @@ describe FormulaAuditor do
end
EOS
- fa.audit_line 'ohai "#{share}/foo"', 3
+ fa.line_problems 'ohai "#{share}/foo"', 3
expect(fa.problems.shift).to eq("Use \#{pkgshare} instead of \#{share}/foo")
- fa.audit_line 'ohai "#{share}/foo/bar"', 3
+ fa.line_problems 'ohai "#{share}/foo/bar"', 3
expect(fa.problems.shift).to eq("Use \#{pkgshare} instead of \#{share}/foo")
- fa.audit_line 'ohai share/"foo"', 3
+ fa.line_problems 'ohai share/"foo"', 3
expect(fa.problems.shift).to eq('Use pkgshare instead of (share/"foo")')
- fa.audit_line 'ohai share/"foo/bar"', 3
+ fa.line_problems 'ohai share/"foo/bar"', 3
expect(fa.problems.shift).to eq('Use pkgshare instead of (share/"foo")')
- fa.audit_line 'ohai "#{share}/foo-bar"', 3
+ fa.line_problems 'ohai "#{share}/foo-bar"', 3
expect(fa.problems).to eq([])
- fa.audit_line 'ohai share/"foo-bar"', 3
+ fa.line_problems 'ohai share/"foo-bar"', 3
expect(fa.problems).to eq([])
- fa.audit_line 'ohai share/"bar"', 3
+ fa.line_problems 'ohai share/"bar"', 3
expect(fa.problems).to eq([])
end
@@ -344,15 +344,11 @@ describe FormulaAuditor do
end
EOS
- fa.audit_desc
- expect(fa.problems.shift)
- .to eq("Description shouldn't include the formula name")
-
- fa.audit_line 'ohai "#{share}/foolibc++"', 3
+ fa.line_problems 'ohai "#{share}/foolibc++"', 3
expect(fa.problems.shift)
.to eq("Use \#{pkgshare} instead of \#{share}/foolibc++")
- fa.audit_line 'ohai share/"foolibc++"', 3
+ fa.line_problems 'ohai share/"foolibc++"', 3
expect(fa.problems.shift)
.to eq('Use pkgshare instead of (share/"foolibc++")')
end
@@ -364,7 +360,7 @@ describe FormulaAuditor do
end
EOS
- fa.audit_line "class Foo<Formula", 1
+ fa.line_problems "class Foo<Formula", 1
expect(fa.problems.shift)
.to eq("Use a space in class inheritance: class Foo < Formula")
end
@@ -372,10 +368,10 @@ describe FormulaAuditor do
specify "default template" do
fa = formula_auditor "foo", "class Foo < Formula; url '/foo-1.0.tgz'; end"
- fa.audit_line '# system "cmake", ".", *std_cmake_args', 3
+ fa.line_problems '# system "cmake", ".", *std_cmake_args', 3
expect(fa.problems.shift).to eq("Commented cmake call found")
- fa.audit_line "# PLEASE REMOVE", 3
+ fa.line_problems "# PLEASE REMOVE", 3
expect(fa.problems.shift).to eq("Please remove default template comments")
end
end
@@ -413,32 +409,6 @@ describe FormulaAuditor do
.to eq(["Don't recommend setuid in the caveats, suggest sudo instead."])
end
- specify "#audit_desc" do
- formula_descriptions = [
- { name: "foo", desc: nil,
- problem: "Formula should have a desc" },
- { name: "bar", desc: "bar" * 30,
- problem: "Description is too long" },
- { name: "baz", desc: "Baz commandline tool",
- problem: "Description should use \"command-line\"" },
- { name: "qux", desc: "A tool called Qux",
- problem: "Description shouldn't start with an indefinite article" },
- ]
-
- formula_descriptions.each do |formula|
- content = <<-EOS.undent
- class #{Formulary.class_s(formula[:name])} < Formula
- url "http://example.com/#{formula[:name]}-1.0.tgz"
- desc "#{formula[:desc]}"
- end
- EOS
-
- fa = formula_auditor formula[:name], content, strict: true
- fa.audit_desc
- expect(fa.problems.first).to match(formula[:problem])
- end
- end
-
describe "#audit_homepage" do
specify "homepage URLs" do
fa = formula_auditor "foo", <<-EOS.undent, online: true
diff --git a/Library/Homebrew/test/dev-cmd/pull_spec.rb b/Library/Homebrew/test/dev-cmd/pull_spec.rb
index 3c0108df2..2ebe144bb 100644
--- a/Library/Homebrew/test/dev-cmd/pull_spec.rb
+++ b/Library/Homebrew/test/dev-cmd/pull_spec.rb
@@ -6,9 +6,7 @@ describe "brew pull", :integration_test do
.and be_a_failure
end
- it "fetches a patch from a GitHub commit or pull request and applies it" do
- skip "Requires network connection." if ENV["HOMEBREW_NO_GITHUB_API"]
-
+ it "fetches a patch from a GitHub commit or pull request and applies it", :needs_network do
CoreTap.instance.path.cd do
shutup do
system "git", "init"
diff --git a/Library/Homebrew/test/diagnostic_spec.rb b/Library/Homebrew/test/diagnostic_spec.rb
index 59560127c..c2bcdb9c0 100644
--- a/Library/Homebrew/test/diagnostic_spec.rb
+++ b/Library/Homebrew/test/diagnostic_spec.rb
@@ -41,6 +41,18 @@ describe Homebrew::Diagnostic::Checks do
end
end
+ specify "#check_access_lock_dir" do
+ begin
+ mode = HOMEBREW_LOCK_DIR.stat.mode & 0777
+ HOMEBREW_LOCK_DIR.chmod 0555
+
+ expect(subject.check_access_lock_dir)
+ .to match("#{HOMEBREW_LOCK_DIR} isn't writable.")
+ ensure
+ HOMEBREW_LOCK_DIR.chmod mode
+ end
+ end
+
specify "#check_access_logs" do
begin
mode = HOMEBREW_LOGS.stat.mode & 0777
diff --git a/Library/Homebrew/test/formula_installer_spec.rb b/Library/Homebrew/test/formula_installer_spec.rb
index 600b4560f..efe2bf5a2 100644
--- a/Library/Homebrew/test/formula_installer_spec.rb
+++ b/Library/Homebrew/test/formula_installer_spec.rb
@@ -134,4 +134,50 @@ describe FormulaInstaller do
fi.check_install_sanity
}.to raise_error(CannotInstallFormulaError)
end
+
+ describe "#install_requirement_formula?" do
+ before do
+ @requirement = Python3Requirement.new
+ allow(@requirement).to receive(:satisfied?).and_return(satisfied?)
+ allow(@requirement).to receive(:satisfied_by_formula?).and_return(satisfied_by_formula?)
+ allow_any_instance_of(Dependency).to receive(:installed?).and_return(installed?)
+ @dependent = formula do
+ url "foo"
+ version "0.1"
+ depends_on :python3
+ end
+ @build = BuildOptions.new [], []
+ @fi = FormulaInstaller.new(@dependent)
+ end
+
+ subject { @fi.install_requirement_formula?(@requirement, @dependent, @build) }
+
+ context "it returns false when requirement is satisfied" do
+ let(:satisfied?) { true }
+ let(:satisfied_by_formula?) { false }
+ let(:installed?) { false }
+ it { is_expected.to be false }
+ end
+
+ context "it returns false when requirement is satisfied but default formula is installed" do
+ let(:satisfied?) { true }
+ let(:satisfied_by_formula?) { false }
+ let(:installed?) { true }
+ it { is_expected.to be false }
+ end
+
+ context "it returns true when requirement isn't satisfied" do
+ let(:satisfied?) { false }
+ let(:satisfied_by_formula?) { false }
+ let(:installed?) { false }
+ it { is_expected.to be true }
+ end
+
+ context "it returns true when requirement is satisfied by a formula" do
+ let(:satisfied?) { true }
+ let(:satisfied_by_formula?) { true }
+ let(:installed?) { false }
+ it { is_expected.to be true }
+ end
+ end
end
diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb
index 1e064912f..2309c36fb 100644
--- a/Library/Homebrew/test/formula_spec.rb
+++ b/Library/Homebrew/test/formula_spec.rb
@@ -129,6 +129,8 @@ describe Formula do
alias_name = "bar"
alias_path = "#{CoreTap.instance.alias_dir}/#{alias_name}"
+ CoreTap.instance.alias_dir.mkpath
+ FileUtils.ln_sf f.path, alias_path
f.build = Tab.new(source: { "path" => alias_path })
@@ -160,6 +162,8 @@ describe Formula do
alias_name = "bar"
full_alias_name = "#{tap.user}/#{tap.repo}/#{alias_name}"
alias_path = "#{tap.alias_dir}/#{alias_name}"
+ tap.alias_dir.mkpath
+ FileUtils.ln_sf f.path, alias_path
f.build = Tab.new(source: { "path" => alias_path })
@@ -168,6 +172,8 @@ describe Formula do
expect(f.full_installed_alias_name).to eq(full_alias_name)
expect(f.installed_specified_name).to eq(alias_name)
expect(f.full_installed_specified_name).to eq(full_alias_name)
+
+ FileUtils.rm_rf HOMEBREW_LIBRARY/"Taps/user"
end
specify "#prefix" do
@@ -402,6 +408,8 @@ describe Formula do
url "foo-1.0"
end
f.build = Tab.new(source: { "path" => source_path.to_s })
+ CoreTap.instance.alias_dir.mkpath
+ FileUtils.ln_sf f.path, source_path
expect(f.alias_path).to eq(alias_path)
expect(f.installed_alias_path).to eq(source_path.to_s)
@@ -443,6 +451,9 @@ describe Formula do
allow(described_class).to receive(:installed).and_return(formulae)
+ CoreTap.instance.alias_dir.mkpath
+ FileUtils.ln_sf formula_with_alias.path, alias_path
+
expect(described_class.installed_with_alias_path(alias_path))
.to eq([formula_with_alias])
end
@@ -940,6 +951,9 @@ describe Formula do
tab.source["path"] = alias_path
stub_formula_loader(f, alias_path)
+ CoreTap.instance.alias_dir.mkpath
+ FileUtils.ln_sf f.path, alias_path
+
expect(f.current_installed_alias_target).to eq(f)
expect(f.latest_formula).to eq(f)
expect(f).not_to have_changed_installed_alias_target
@@ -952,6 +966,9 @@ describe Formula do
tab.source["path"] = alias_path
stub_formula_loader(new_formula, alias_path)
+ CoreTap.instance.alias_dir.mkpath
+ FileUtils.ln_sf new_formula.path, alias_path
+
expect(f.current_installed_alias_target).to eq(new_formula)
expect(f.latest_formula).to eq(new_formula)
expect(f).to have_changed_installed_alias_target
@@ -964,6 +981,9 @@ describe Formula do
tab.source["path"] = alias_path
stub_formula_loader(new_formula, alias_path)
+ CoreTap.instance.alias_dir.mkpath
+ FileUtils.ln_sf new_formula.path, alias_path
+
expect(new_formula.current_installed_alias_target).to eq(new_formula)
expect(new_formula.latest_formula).to eq(new_formula)
expect(new_formula).not_to have_changed_installed_alias_target
@@ -1050,6 +1070,10 @@ describe Formula do
f.follow_installed_alias = true
f.build = setup_tab_for_prefix(same_prefix, path: alias_path)
stub_formula_loader(new_formula, alias_path)
+
+ CoreTap.instance.alias_dir.mkpath
+ FileUtils.ln_sf new_formula.path, alias_path
+
expect(f.outdated_kegs).not_to be_empty
end
@@ -1088,6 +1112,10 @@ describe Formula do
tab = setup_tab_for_prefix(old_alias_target_prefix, path: alias_path)
old_formula.build = tab
allow(described_class).to receive(:installed).and_return([old_formula])
+
+ CoreTap.instance.alias_dir.mkpath
+ FileUtils.ln_sf f.path, alias_path
+
expect(f.outdated_kegs).not_to be_empty
end
diff --git a/Library/Homebrew/test/gpg2_requirement_spec.rb b/Library/Homebrew/test/gpg2_requirement_spec.rb
index d7767abd3..a5501c84e 100644
--- a/Library/Homebrew/test/gpg2_requirement_spec.rb
+++ b/Library/Homebrew/test/gpg2_requirement_spec.rb
@@ -9,7 +9,7 @@ describe GPG2Requirement do
ENV["PATH"] = dir/"bin"
(dir/"bin/gpg").write <<-EOS.undent
#!/bin/bash
- echo 2.0.30
+ echo 2.1.20
EOS
FileUtils.chmod 0755, dir/"bin/gpg"
diff --git a/Library/Homebrew/test/gpg_spec.rb b/Library/Homebrew/test/gpg_spec.rb
index aa00d79f5..160e55379 100644
--- a/Library/Homebrew/test/gpg_spec.rb
+++ b/Library/Homebrew/test/gpg_spec.rb
@@ -13,7 +13,12 @@ describe Gpg do
shutup do
subject.create_test_key(dir)
end
- expect(dir/".gnupg/secring.gpg").to exist
+
+ if subject.version == Version.create("2.0")
+ expect(dir/".gnupg/secring.gpg").to be_a_file
+ else
+ expect(dir/".gnupg/pubring.kbx").to be_a_file
+ end
end
end
end
diff --git a/Library/Homebrew/test/hardware_spec.rb b/Library/Homebrew/test/hardware_spec.rb
index c5f8daf4e..de8d77e68 100644
--- a/Library/Homebrew/test/hardware_spec.rb
+++ b/Library/Homebrew/test/hardware_spec.rb
@@ -36,5 +36,52 @@ module Hardware
).to include(described_class.family)
end
end
+
+ describe "::can_run?" do
+ it "reports that Intel machines can run Intel executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :intel
+ allow(Hardware::CPU).to receive(:bits).and_return 64
+ expect(Hardware::CPU.can_run?(:i386)).to be true
+ expect(Hardware::CPU.can_run?(:x86_64)).to be true
+ end
+
+ it "reports that PowerPC machines can run PowerPC executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :ppc
+ allow(Hardware::CPU).to receive(:bits).and_return 64
+ expect(Hardware::CPU.can_run?(:ppc)).to be true
+ expect(Hardware::CPU.can_run?(:ppc64)).to be true
+ end
+
+ it "reports that 32-bit Intel machines can't run x86_64 executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :intel
+ allow(Hardware::CPU).to receive(:bits).and_return 32
+ expect(Hardware::CPU.can_run?(:x86_64)).to be false
+ end
+
+ it "reports that 32-bit PowerPC machines can't run ppc64 executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :ppc
+ allow(Hardware::CPU).to receive(:bits).and_return 32
+ expect(Hardware::CPU.can_run?(:ppc64)).to be false
+ end
+
+ it "identifies that Intel and PowerPC machines can't run each others' executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :ppc
+ expect(Hardware::CPU.can_run?(:i386)).to be false
+ expect(Hardware::CPU.can_run?(:x86_64)).to be false
+
+ allow(Hardware::CPU).to receive(:type).and_return :intel
+ expect(Hardware::CPU.can_run?(:ppc)).to be false
+ expect(Hardware::CPU.can_run?(:ppc64)).to be false
+ end
+
+ it "returns false for unknown CPU types" do
+ allow(Hardware::CPU).to receive(:type).and_return :dunno
+ expect(Hardware::CPU.can_run?(:i386)).to be false
+ end
+
+ it "returns false for unknown arches" do
+ expect(Hardware::CPU.can_run?(:blah)).to be false
+ end
+ end
end
end
diff --git a/Library/Homebrew/test/missing_formula_spec.rb b/Library/Homebrew/test/missing_formula_spec.rb
new file mode 100644
index 000000000..69bb3e70d
--- /dev/null
+++ b/Library/Homebrew/test/missing_formula_spec.rb
@@ -0,0 +1,171 @@
+require "missing_formula"
+
+describe Homebrew::MissingFormula do
+ context "::reason" do
+ subject { described_class.reason("gem") }
+
+ it { is_expected.to_not be_nil }
+ end
+
+ context "::blacklisted_reason" do
+ matcher(:be_blacklisted) do
+ match(&Homebrew::MissingFormula.method(:blacklisted_reason))
+ end
+
+ context "rubygems" do
+ %w[gem rubygem rubygems].each do |s|
+ subject { s }
+
+ it { is_expected.to be_blacklisted }
+ end
+ end
+
+ context "latex" do
+ %w[latex tex tex-live texlive TexLive].each do |s|
+ subject { s }
+
+ it { is_expected.to be_blacklisted }
+ end
+ end
+
+ context "pip" do
+ subject { "pip" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "pil" do
+ subject { "pil" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "macruby" do
+ subject { "MacRuby" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "lzma" do
+ %w[lzma liblzma].each do |s|
+ subject { s }
+
+ it { is_expected.to be_blacklisted }
+ end
+ end
+
+ context "gtest" do
+ %w[gtest googletest google-test].each do |s|
+ subject { s }
+
+ it { is_expected.to be_blacklisted }
+ end
+ end
+
+ context "gmock" do
+ %w[gmock googlemock google-mock].each do |s|
+ subject { s }
+
+ it { is_expected.to be_blacklisted }
+ end
+ end
+
+ context "sshpass" do
+ subject { "sshpass" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "gsutil" do
+ subject { "gsutil" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "clojure" do
+ subject { "clojure" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "gfortran" do
+ subject { "gfortran" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "play" do
+ subject { "play" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "haskell-platform" do
+ subject { "haskell-platform" }
+
+ it { is_expected.to be_blacklisted }
+ end
+
+ context "xcode", :needs_macos do
+ %w[xcode Xcode].each do |s|
+ subject { s }
+
+ it { is_expected.to be_blacklisted }
+ end
+ end
+ end
+
+ context "::tap_migration_reason" do
+ subject { described_class.tap_migration_reason(formula) }
+
+ before do
+ Tap.clear_cache
+ tap_path = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo"
+ tap_path.mkpath
+ (tap_path/"tap_migrations.json").write <<-EOS.undent
+ { "migrated-formula": "homebrew/bar" }
+ EOS
+ end
+
+ context "with a migrated formula" do
+ let(:formula) { "migrated-formula" }
+ it { is_expected.to_not be_nil }
+ end
+
+ context "with a missing formula" do
+ let(:formula) { "missing-formula" }
+ it { is_expected.to be_nil }
+ end
+ end
+
+ context "::deleted_reason" do
+ subject { described_class.deleted_reason(formula, silent: true) }
+
+ before do
+ Tap.clear_cache
+ tap_path = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo"
+ tap_path.mkpath
+ (tap_path/"deleted-formula.rb").write "placeholder"
+
+ tap_path.cd do
+ shutup do
+ system "git", "init"
+ system "git", "add", "--all"
+ system "git", "commit", "-m", "initial state"
+ system "git", "rm", "deleted-formula.rb"
+ system "git", "commit", "-m", "delete formula 'deleted-formula'"
+ end
+ end
+ end
+
+ context "with a deleted formula" do
+ let(:formula) { "homebrew/foo/deleted-formula" }
+ it { is_expected.to_not be_nil }
+ end
+
+ context "with a formula that never existed" do
+ let(:formula) { "homebrew/foo/missing-formula" }
+ it { is_expected.to be_nil }
+ end
+ end
+end
diff --git a/Library/Homebrew/test/os/linux/osxfuse_requirement_spec.rb b/Library/Homebrew/test/os/linux/osxfuse_requirement_spec.rb
new file mode 100644
index 000000000..c45af2fa7
--- /dev/null
+++ b/Library/Homebrew/test/os/linux/osxfuse_requirement_spec.rb
@@ -0,0 +1,9 @@
+require "requirements/osxfuse_requirement"
+
+describe OsxfuseRequirement do
+ subject { described_class.new([]) }
+
+ describe "#message" do
+ its(:message) { is_expected.to match("libfuse is required to install this formula") }
+ end
+end
diff --git a/Library/Homebrew/test/os/mac/hardware_spec.rb b/Library/Homebrew/test/os/mac/hardware_spec.rb
new file mode 100644
index 000000000..fa577ba7d
--- /dev/null
+++ b/Library/Homebrew/test/os/mac/hardware_spec.rb
@@ -0,0 +1,56 @@
+require "hardware"
+require "extend/os/mac/hardware/cpu"
+
+describe Hardware::CPU do
+ describe "::can_run?" do
+ it "reports that Intel Macs can run Intel executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :intel
+ allow(Hardware::CPU).to receive(:bits).and_return 64
+ expect(Hardware::CPU.can_run?(:i386)).to be true
+ expect(Hardware::CPU.can_run?(:x86_64)).to be true
+ end
+
+ it "reports that PowerPC Macs can run PowerPC executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :ppc
+ allow(Hardware::CPU).to receive(:bits).and_return 64
+ expect(Hardware::CPU.can_run?(:ppc)).to be true
+ expect(Hardware::CPU.can_run?(:ppc64)).to be true
+ end
+
+ it "reports that 32-bit Intel Macs can't run x86_64 executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :intel
+ allow(Hardware::CPU).to receive(:bits).and_return 32
+ expect(Hardware::CPU.can_run?(:x86_64)).to be false
+ end
+
+ it "reports that 32-bit PowerPC Macs can't run ppc64 executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :ppc
+ allow(Hardware::CPU).to receive(:bits).and_return 32
+ expect(Hardware::CPU.can_run?(:ppc64)).to be false
+ end
+
+ it "reports that Intel Macs can only run 32-bit PowerPC executables on 10.6 and older" do
+ allow(Hardware::CPU).to receive(:type).and_return :intel
+ allow(OS::Mac).to receive(:version).and_return OS::Mac::Version.new "10.6"
+ expect(Hardware::CPU.can_run?(:ppc)).to be true
+
+ allow(OS::Mac).to receive(:version).and_return OS::Mac::Version.new "10.7"
+ expect(Hardware::CPU.can_run?(:ppc)).to be false
+ end
+
+ it "reports that PowerPC Macs can't run Intel executables" do
+ allow(Hardware::CPU).to receive(:type).and_return :ppc
+ expect(Hardware::CPU.can_run?(:i386)).to be false
+ expect(Hardware::CPU.can_run?(:x86_64)).to be false
+ end
+
+ it "returns false for unknown CPU types" do
+ allow(Hardware::CPU).to receive(:type).and_return :dunno
+ expect(Hardware::CPU.can_run?(:i386)).to be false
+ end
+
+ it "returns false for unknown arches" do
+ expect(Hardware::CPU.can_run?(:blah)).to be false
+ end
+ end
+end
diff --git a/Library/Homebrew/test/os/mac/osxfuse_requirement_spec.rb b/Library/Homebrew/test/os/mac/osxfuse_requirement_spec.rb
new file mode 100644
index 000000000..06d3d885e
--- /dev/null
+++ b/Library/Homebrew/test/os/mac/osxfuse_requirement_spec.rb
@@ -0,0 +1,36 @@
+require "requirements/osxfuse_requirement"
+
+describe OsxfuseRequirement do
+ subject { described_class.new([]) }
+
+ describe "::binary_osxfuse_installed?" do
+ it "returns false if fuse.h does not exist" do
+ allow(File).to receive(:exist?).and_return(false)
+ expect(described_class).not_to be_binary_osxfuse_installed
+ end
+
+ it "returns false if osxfuse include directory is a symlink" do
+ allow(File).to receive(:exist?).and_return(true)
+ allow(File).to receive(:symlink?).and_return(true)
+ expect(described_class).not_to be_binary_osxfuse_installed
+ end
+ end
+
+ describe "environment" do
+ it "adds the fuse directories to the appropriate paths" do
+ expect(ENV).to receive(:append_path).with("PKG_CONFIG_PATH", any_args)
+ expect(ENV).to receive(:append_path).with("HOMEBREW_LIBRARY_PATHS", any_args)
+ expect(ENV).to receive(:append_path).with("HOMEBREW_INCLUDE_PATHS", any_args)
+ subject.modify_build_environment
+ end
+ end
+end
+
+describe NonBinaryOsxfuseRequirement do
+ subject { described_class.new([]) }
+
+ describe "#message" do
+ msg = /osxfuse is already installed from the binary distribution/
+ its(:message) { is_expected.to match(msg) }
+ end
+end
diff --git a/Library/Homebrew/test/requirement_spec.rb b/Library/Homebrew/test/requirement_spec.rb
index 110a7ac4f..959041cf4 100644
--- a/Library/Homebrew/test/requirement_spec.rb
+++ b/Library/Homebrew/test/requirement_spec.rb
@@ -146,17 +146,13 @@ describe Requirement do
end
describe "#build?" do
- context "#build true is specified" do
- let(:klass) do
- Class.new(described_class) do
- build true
- end
- end
+ context ":build tag is specified" do
+ subject { described_class.new([:build]) }
it { is_expected.to be_a_build_requirement }
end
- context "#build ommitted" do
+ context "#build omitted" do
it { is_expected.not_to be_a_build_requirement }
end
end
diff --git a/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb b/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb
new file mode 100644
index 000000000..5be2d6cf5
--- /dev/null
+++ b/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb
@@ -0,0 +1,67 @@
+require "rubocop"
+require "rubocop/rspec/support"
+require_relative "../../extend/string"
+require_relative "../../rubocops/bottle_block_cop"
+
+describe RuboCop::Cop::Homebrew::CorrectBottleBlock do
+ subject(:cop) { described_class.new }
+
+ context "When auditing Bottle Block" do
+ it "When there is revision in bottle block" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ bottle do
+ cellar :any
+ revision 2
+ end
+ end
+ EOS
+
+ expected_offenses = [{ message: "Use rebuild instead of revision in bottle block",
+ severity: :convention,
+ line: 5,
+ column: 4,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ def expect_offense(expected, actual)
+ expect(actual.message).to eq(expected[:message])
+ expect(actual.severity).to eq(expected[:severity])
+ expect(actual.line).to eq(expected[:line])
+ expect(actual.column).to eq(expected[:column])
+ end
+ end
+
+ context "When auditing Bottle Block with auto correct" do
+ it "When there is revision in bottle block" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ bottle do
+ cellar :any
+ revision 2
+ end
+ end
+ EOS
+ corrected_source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ bottle do
+ cellar :any
+ rebuild 2
+ end
+ end
+ EOS
+
+ new_source = autocorrect_source(cop, source)
+ expect(new_source).to eq(corrected_source)
+ end
+ end
+end
diff --git a/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb b/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb
new file mode 100644
index 000000000..04c4c27da
--- /dev/null
+++ b/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb
@@ -0,0 +1,121 @@
+require "rubocop"
+require "rubocop/rspec/support"
+require_relative "../../extend/string"
+require_relative "../../rubocops/formula_desc_cop"
+
+describe RuboCop::Cop::Homebrew::FormulaDesc do
+ subject(:cop) { described_class.new }
+
+ context "When auditing formula desc" do
+ it "When there is no desc" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ end
+ EOS
+
+ expected_offenses = [{ message: "Formula should have a desc (Description).",
+ severity: :convention,
+ line: 1,
+ column: 0,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ it "When desc is too long" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ desc '#{"bar"*30}'
+ end
+ EOS
+
+ msg = <<-EOS.undent
+ Description is too long. "name: desc" should be less than 80 characters.
+ Length is calculated as Foo + desc. (currently 95)
+ EOS
+ expected_offenses = [{ message: msg,
+ severity: :convention,
+ line: 3,
+ column: 2,
+ source: source }]
+
+ inspect_source(cop, source)
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ it "When wrong \"command-line\" usage in desc" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ desc 'command line'
+ end
+ EOS
+
+ expected_offenses = [{ message: "Description should use \"command-line\" instead of \"command line\"",
+ severity: :convention,
+ line: 3,
+ column: 8,
+ source: source }]
+
+ inspect_source(cop, source)
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ it "When an article is used in desc" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ desc 'An '
+ end
+ EOS
+
+ expected_offenses = [{ message: "Description shouldn't start with an indefinite article (An )",
+ severity: :convention,
+ line: 3,
+ column: 8,
+ source: source }]
+
+ inspect_source(cop, source)
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ it "When formula name is in desc" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ desc 'Foo'
+ end
+ EOS
+
+ expected_offenses = [{ message: "Description shouldn't include the formula name",
+ severity: :convention,
+ line: 3,
+ column: 8,
+ source: source }]
+
+ inspect_source(cop, source)
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ def expect_offense(expected, actual)
+ expect(actual.message).to eq(expected[:message])
+ expect(actual.severity).to eq(expected[:severity])
+ expect(actual.line).to eq(expected[:line])
+ expect(actual.column).to eq(expected[:column])
+ end
+ end
+end
diff --git a/Library/Homebrew/test/spec_helper.rb b/Library/Homebrew/test/spec_helper.rb
index 2f6274fd1..005c6d2fb 100644
--- a/Library/Homebrew/test/spec_helper.rb
+++ b/Library/Homebrew/test/spec_helper.rb
@@ -61,6 +61,10 @@ RSpec.configure do |config|
skip "Python not installed." unless which("python")
end
+ config.before(:each, :needs_network) do
+ skip "Requires network connection." unless ENV["HOMEBREW_TEST_ONLINE"]
+ end
+
config.around(:each) do |example|
begin
TEST_DIRECTORIES.each(&:mkpath)
diff --git a/Library/Homebrew/test/support/fixtures/cask/Casks/with-non-executable-binary.rb b/Library/Homebrew/test/support/fixtures/cask/Casks/with-non-executable-binary.rb
new file mode 100644
index 000000000..4bd2f0882
--- /dev/null
+++ b/Library/Homebrew/test/support/fixtures/cask/Casks/with-non-executable-binary.rb
@@ -0,0 +1,9 @@
+cask 'with-non-executable-binary' do
+ version '1.2.3'
+ sha256 'd5b2dfbef7ea28c25f7a77cd7fa14d013d82b626db1d82e00e25822464ba19e2'
+
+ url "file://#{TEST_FIXTURE_DIR}/cask/naked_non_executable"
+ homepage 'http://example.com/with-binary'
+
+ binary "naked_non_executable"
+end
diff --git a/Library/Homebrew/test/support/fixtures/cask/naked_non_executable b/Library/Homebrew/test/support/fixtures/cask/naked_non_executable
new file mode 100644
index 000000000..039e4d006
--- /dev/null
+++ b/Library/Homebrew/test/support/fixtures/cask/naked_non_executable
@@ -0,0 +1,2 @@
+#!/bin/sh
+exit 0
diff --git a/Library/Homebrew/test/tab_spec.rb b/Library/Homebrew/test/tab_spec.rb
index fec390c28..1b0836c93 100644
--- a/Library/Homebrew/test/tab_spec.rb
+++ b/Library/Homebrew/test/tab_spec.rb
@@ -258,7 +258,7 @@ describe Tab do
it "can create a Tab for a non-existant Keg" do
f.prefix.mkpath
- expect(subject.tabfile).to be nil
+ expect(subject.tabfile).to eq(f_tab_path)
end
end
diff --git a/Library/Homebrew/test/utils/shell_spec.rb b/Library/Homebrew/test/utils/shell_spec.rb
index c44bd8253..d32f9928f 100644
--- a/Library/Homebrew/test/utils/shell_spec.rb
+++ b/Library/Homebrew/test/utils/shell_spec.rb
@@ -1,92 +1,92 @@
require "utils/shell"
describe Utils::Shell do
- describe "::shell_profile" do
+ describe "::profile" do
it "returns ~/.bash_profile by default" do
ENV["SHELL"] = "/bin/another_shell"
- expect(subject.shell_profile).to eq("~/.bash_profile")
+ expect(subject.profile).to eq("~/.bash_profile")
end
it "returns ~/.bash_profile for Sh" do
ENV["SHELL"] = "/bin/another_shell"
- expect(subject.shell_profile).to eq("~/.bash_profile")
+ expect(subject.profile).to eq("~/.bash_profile")
end
it "returns ~/.bash_profile for Bash" do
ENV["SHELL"] = "/bin/bash"
- expect(subject.shell_profile).to eq("~/.bash_profile")
+ expect(subject.profile).to eq("~/.bash_profile")
end
it "returns ~/.zshrc for Zsh" do
ENV["SHELL"] = "/bin/zsh"
- expect(subject.shell_profile).to eq("~/.zshrc")
+ expect(subject.profile).to eq("~/.zshrc")
end
it "returns ~/.kshrc for Ksh" do
ENV["SHELL"] = "/bin/ksh"
- expect(subject.shell_profile).to eq("~/.kshrc")
+ expect(subject.profile).to eq("~/.kshrc")
end
end
- describe "::path_to_shell" do
+ describe "::from_path" do
it "supports a raw command name" do
- expect(subject.path_to_shell("bash")).to eq(:bash)
+ expect(subject.from_path("bash")).to eq(:bash)
end
it "supports full paths" do
- expect(subject.path_to_shell("/bin/bash")).to eq(:bash)
+ expect(subject.from_path("/bin/bash")).to eq(:bash)
end
it "supports versions" do
- expect(subject.path_to_shell("zsh-5.2")).to eq(:zsh)
+ expect(subject.from_path("zsh-5.2")).to eq(:zsh)
end
it "strips newlines" do
- expect(subject.path_to_shell("zsh-5.2\n")).to eq(:zsh)
+ expect(subject.from_path("zsh-5.2\n")).to eq(:zsh)
end
it "returns nil when input is invalid" do
- expect(subject.path_to_shell("")).to be nil
- expect(subject.path_to_shell("@@@@@@")).to be nil
- expect(subject.path_to_shell("invalid_shell-4.2")).to be nil
+ expect(subject.from_path("")).to be nil
+ expect(subject.from_path("@@@@@@")).to be nil
+ expect(subject.from_path("invalid_shell-4.2")).to be nil
end
end
specify "::sh_quote" do
- expect(subject.sh_quote("")).to eq("''")
- expect(subject.sh_quote("\\")).to eq("\\\\")
- expect(subject.sh_quote("\n")).to eq("'\n'")
- expect(subject.sh_quote("$")).to eq("\\$")
- expect(subject.sh_quote("word")).to eq("word")
+ expect(subject.send(:sh_quote, "")).to eq("''")
+ expect(subject.send(:sh_quote, "\\")).to eq("\\\\")
+ expect(subject.send(:sh_quote, "\n")).to eq("'\n'")
+ expect(subject.send(:sh_quote, "$")).to eq("\\$")
+ expect(subject.send(:sh_quote, "word")).to eq("word")
end
specify "::csh_quote" do
- expect(subject.csh_quote("")).to eq("''")
- expect(subject.csh_quote("\\")).to eq("\\\\")
+ expect(subject.send(:csh_quote, "")).to eq("''")
+ expect(subject.send(:csh_quote, "\\")).to eq("\\\\")
# note this test is different than for sh
- expect(subject.csh_quote("\n")).to eq("'\\\n'")
- expect(subject.csh_quote("$")).to eq("\\$")
- expect(subject.csh_quote("word")).to eq("word")
+ expect(subject.send(:csh_quote, "\n")).to eq("'\\\n'")
+ expect(subject.send(:csh_quote, "$")).to eq("\\$")
+ expect(subject.send(:csh_quote, "word")).to eq("word")
end
- describe "::prepend_path_in_shell_profile" do
+ describe "::prepend_path_in_profile" do
let(:path) { "/my/path" }
it "supports Tcsh" do
ENV["SHELL"] = "/bin/tcsh"
- expect(subject.prepend_path_in_shell_profile(path))
+ expect(subject.prepend_path_in_profile(path))
.to start_with("echo 'setenv PATH #{path}:$")
end
it "supports Bash" do
ENV["SHELL"] = "/bin/bash"
- expect(subject.prepend_path_in_shell_profile(path))
+ expect(subject.prepend_path_in_profile(path))
.to start_with("echo 'export PATH=\"#{path}:$")
end
it "supports Fish" do
ENV["SHELL"] = "/usr/local/bin/fish"
- expect(subject.prepend_path_in_shell_profile(path))
+ expect(subject.prepend_path_in_profile(path))
.to start_with("echo 'set -g fish_user_paths \"#{path}\" $fish_user_paths' >>")
end
end
diff --git a/Library/Homebrew/test/utils_spec.rb b/Library/Homebrew/test/utils_spec.rb
index 314c299a8..dd7ea20de 100644
--- a/Library/Homebrew/test/utils_spec.rb
+++ b/Library/Homebrew/test/utils_spec.rb
@@ -189,7 +189,13 @@ describe "globally-scoped helper methods" do
specify "#which_editor" do
ENV["HOMEBREW_EDITOR"] = "vemate"
- expect(which_editor).to eq("vemate")
+ ENV["HOMEBREW_PATH"] = dir
+
+ editor = dir/"vemate"
+ FileUtils.touch editor
+ FileUtils.chmod 0755, editor
+
+ expect(which_editor).to eql editor
end
specify "#gzip" do
diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb
index 46a8cc68e..f37b777ee 100644
--- a/Library/Homebrew/utils.rb
+++ b/Library/Homebrew/utils.rb
@@ -320,21 +320,21 @@ def which_all(cmd, path = ENV["PATH"])
end
def which_editor
- editor = ENV.values_at("HOMEBREW_EDITOR", "VISUAL", "EDITOR").compact.first
- return editor unless editor.nil?
+ editor = ENV.values_at("HOMEBREW_EDITOR", "VISUAL").compact.reject(&:empty?).first
+ return which(editor, ENV["HOMEBREW_PATH"]) unless editor.nil?
# Find Textmate
- editor = "mate" if which "mate"
+ editor = which("mate", ENV["HOMEBREW_PATH"])
# Find BBEdit / TextWrangler
- editor ||= "edit" if which "edit"
+ editor ||= which("edit", ENV["HOMEBREW_PATH"])
# Find vim
- editor ||= "vim" if which "vim"
+ editor ||= which("vim", ENV["HOMEBREW_PATH"])
# Default to standard vim
editor ||= "/usr/bin/vim"
opoo <<-EOS.undent
Using #{editor} because no editor was set in the environment.
- This may change in the future, so we recommend setting EDITOR, VISUAL,
+ This may change in the future, so we recommend setting EDITOR,
or HOMEBREW_EDITOR to your preferred text editor.
EOS
diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb
index 5f961974c..a5ed5394a 100644
--- a/Library/Homebrew/utils/github.rb
+++ b/Library/Homebrew/utils/github.rb
@@ -268,7 +268,6 @@ module GitHub
def print_pull_requests_matching(query)
return [] if ENV["HOMEBREW_NO_GITHUB_API"]
- ohai "Searching pull requests..."
open_or_closed_prs = issues_matching(query, type: "pr")
diff --git a/Library/Homebrew/utils/shell.rb b/Library/Homebrew/utils/shell.rb
index 302167d47..5327f6ecf 100644
--- a/Library/Homebrew/utils/shell.rb
+++ b/Library/Homebrew/utils/shell.rb
@@ -1,62 +1,24 @@
module Utils
- SHELL_PROFILE_MAP = {
- bash: "~/.bash_profile",
- csh: "~/.cshrc",
- fish: "~/.config/fish/config.fish",
- ksh: "~/.kshrc",
- sh: "~/.bash_profile",
- tcsh: "~/.tcshrc",
- zsh: "~/.zshrc",
- }.freeze
-
module Shell
- UNSAFE_SHELL_CHAR = %r{([^A-Za-z0-9_\-.,:/@\n])}
+ module_function
# take a path and heuristically convert it
# to a shell name, return nil if there's no match
- def path_to_shell(path)
+ def from_path(path)
# we only care about the basename
shell_name = File.basename(path)
# handle possible version suffix like `zsh-5.2`
shell_name.sub!(/-.*\z/m, "")
shell_name.to_sym if %w[bash csh fish ksh sh tcsh zsh].include?(shell_name)
end
- module_function :path_to_shell
-
- def preferred_shell
- path_to_shell(ENV.fetch("SHELL", ""))
- end
- module_function :preferred_shell
- def parent_shell
- path_to_shell(`ps -p #{Process.ppid} -o ucomm=`.strip)
+ def preferred
+ from_path(ENV.fetch("SHELL", ""))
end
- module_function :parent_shell
- def csh_quote(str)
- # ruby's implementation of shell_escape
- str = str.to_s
- return "''" if str.empty?
- str = str.dup
- # anything that isn't a known safe character is padded
- str.gsub!(UNSAFE_SHELL_CHAR, "\\\\" + "\\1")
- # newlines have to be specially quoted in csh
- str.gsub!(/\n/, "'\\\n'")
- str
+ def parent
+ from_path(`ps -p #{Process.ppid} -o ucomm=`.strip)
end
- module_function :csh_quote
-
- def sh_quote(str)
- # ruby's implementation of shell_escape
- str = str.to_s
- return "''" if str.empty?
- str = str.dup
- # anything that isn't a known safe character is padded
- str.gsub!(UNSAFE_SHELL_CHAR, "\\\\" + "\\1")
- str.gsub!(/\n/, "'\n'")
- str
- end
- module_function :sh_quote
# quote values. quoting keys is overkill
def export_value(shell, key, value)
@@ -72,24 +34,60 @@ module Utils
"setenv #{key} #{csh_quote(value)};"
end
end
- module_function :export_value
# return the shell profile file based on users' preferred shell
- def shell_profile
- SHELL_PROFILE_MAP.fetch(preferred_shell, "~/.bash_profile")
+ def profile
+ SHELL_PROFILE_MAP.fetch(preferred, "~/.bash_profile")
end
- module_function :shell_profile
- def prepend_path_in_shell_profile(path)
- case preferred_shell
+ def prepend_path_in_profile(path)
+ case preferred
when :bash, :ksh, :sh, :zsh, nil
- "echo 'export PATH=\"#{sh_quote(path)}:$PATH\"' >> #{shell_profile}"
+ "echo 'export PATH=\"#{sh_quote(path)}:$PATH\"' >> #{profile}"
when :csh, :tcsh
- "echo 'setenv PATH #{csh_quote(path)}:$PATH' >> #{shell_profile}"
+ "echo 'setenv PATH #{csh_quote(path)}:$PATH' >> #{profile}"
when :fish
- "echo 'set -g fish_user_paths \"#{sh_quote(path)}\" $fish_user_paths' >> #{shell_profile}"
+ "echo 'set -g fish_user_paths \"#{sh_quote(path)}\" $fish_user_paths' >> #{profile}"
end
end
- module_function :prepend_path_in_shell_profile
+
+ private
+
+ SHELL_PROFILE_MAP = {
+ bash: "~/.bash_profile",
+ csh: "~/.cshrc",
+ fish: "~/.config/fish/config.fish",
+ ksh: "~/.kshrc",
+ sh: "~/.bash_profile",
+ tcsh: "~/.tcshrc",
+ zsh: "~/.zshrc",
+ }.freeze
+
+ UNSAFE_SHELL_CHAR = %r{([^A-Za-z0-9_\-.,:/@\n])}
+
+ module_function
+
+ def csh_quote(str)
+ # ruby's implementation of shell_escape
+ str = str.to_s
+ return "''" if str.empty?
+ str = str.dup
+ # anything that isn't a known safe character is padded
+ str.gsub!(UNSAFE_SHELL_CHAR, "\\\\" + "\\1")
+ # newlines have to be specially quoted in csh
+ str.gsub!(/\n/, "'\\\n'")
+ str
+ end
+
+ def sh_quote(str)
+ # ruby's implementation of shell_escape
+ str = str.to_s
+ return "''" if str.empty?
+ str = str.dup
+ # anything that isn't a known safe character is padded
+ str.gsub!(UNSAFE_SHELL_CHAR, "\\\\" + "\\1")
+ str.gsub!(/\n/, "'\n'")
+ str
+ end
end
end
diff --git a/Library/Homebrew/vendor/README.md b/Library/Homebrew/vendor/README.md
index f998d26c5..906d42918 100644
--- a/Library/Homebrew/vendor/README.md
+++ b/Library/Homebrew/vendor/README.md
@@ -3,7 +3,7 @@ Vendored Dependencies
* [plist](https://github.com/bleything/plist), version 3.1.0
-* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 0.2.6
+* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 1.1.0
## Licenses:
@@ -33,7 +33,7 @@ Vendored Dependencies
### ruby-macho
> The MIT License
-> Copyright (c) 2015, 2016 William Woodruff <william @ tuffbizz.com>
+> Copyright (c) 2015, 2016, 2017 William Woodruff <william @ tuffbizz.com>
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
diff --git a/Library/Homebrew/vendor/macho/macho.rb b/Library/Homebrew/vendor/macho/macho.rb
index de1d4ff43..b7f20ea19 100644
--- a/Library/Homebrew/vendor/macho/macho.rb
+++ b/Library/Homebrew/vendor/macho/macho.rb
@@ -5,7 +5,6 @@ require "#{File.dirname(__FILE__)}/macho/load_commands"
require "#{File.dirname(__FILE__)}/macho/sections"
require "#{File.dirname(__FILE__)}/macho/macho_file"
require "#{File.dirname(__FILE__)}/macho/fat_file"
-require "#{File.dirname(__FILE__)}/macho/open"
require "#{File.dirname(__FILE__)}/macho/exceptions"
require "#{File.dirname(__FILE__)}/macho/utils"
require "#{File.dirname(__FILE__)}/macho/tools"
@@ -13,5 +12,29 @@ require "#{File.dirname(__FILE__)}/macho/tools"
# The primary namespace for ruby-macho.
module MachO
# release version
- VERSION = "0.2.6".freeze
+ VERSION = "1.1.0".freeze
+
+ # Opens the given filename as a MachOFile or FatFile, depending on its magic.
+ # @param filename [String] the file being opened
+ # @return [MachOFile] if the file is a Mach-O
+ # @return [FatFile] if the file is a Fat file
+ # @raise [ArgumentError] if the given file does not exist
+ # @raise [TruncatedFileError] if the file is too small to have a valid header
+ # @raise [MagicError] if the file's magic is not valid Mach-O magic
+ def self.open(filename)
+ raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
+ raise TruncatedFileError unless File.stat(filename).size >= 4
+
+ magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
+
+ if Utils.fat_magic?(magic)
+ file = FatFile.new(filename)
+ elsif Utils.magic?(magic)
+ file = MachOFile.new(filename)
+ else
+ raise MagicError, magic
+ end
+
+ file
+ end
end
diff --git a/Library/Homebrew/vendor/macho/macho/exceptions.rb b/Library/Homebrew/vendor/macho/macho/exceptions.rb
index 262c195a3..14c2c22ae 100644
--- a/Library/Homebrew/vendor/macho/macho/exceptions.rb
+++ b/Library/Homebrew/vendor/macho/macho/exceptions.rb
@@ -80,7 +80,8 @@ module MachO
# @param cputype [Fixnum] the CPU type of the unknown pair
# @param cpusubtype [Fixnum] the CPU sub-type of the unknown pair
def initialize(cputype, cpusubtype)
- super "Unrecognized CPU sub-type: 0x#{"%08x" % cpusubtype} (for CPU type: 0x#{"%08x" % cputype})"
+ super "Unrecognized CPU sub-type: 0x#{"%08x" % cpusubtype}" \
+ " (for CPU type: 0x#{"%08x" % cputype})"
end
end
@@ -108,13 +109,15 @@ module MachO
end
end
- # Raised when the number of arguments used to create a load command manually is wrong.
+ # Raised when the number of arguments used to create a load command manually
+ # is wrong.
class LoadCommandCreationArityError < MachOError
# @param cmd_sym [Symbol] the load command's symbol
# @param expected_arity [Fixnum] the number of arguments expected
# @param actual_arity [Fixnum] the number of arguments received
def initialize(cmd_sym, expected_arity, actual_arity)
- super "Expected #{expected_arity} arguments for #{cmd_sym} creation, got #{actual_arity}"
+ super "Expected #{expected_arity} arguments for #{cmd_sym} creation," \
+ " got #{actual_arity}"
end
end
@@ -130,7 +133,8 @@ module MachO
class LCStrMalformedError < MachOError
# @param lc [MachO::LoadCommand] the load command containing the string
def initialize(lc)
- super "Load command #{lc.type} at offset #{lc.view.offset} contains a malformed string"
+ super "Load command #{lc.type} at offset #{lc.view.offset} contains a" \
+ " malformed string"
end
end
diff --git a/Library/Homebrew/vendor/macho/macho/fat_file.rb b/Library/Homebrew/vendor/macho/macho/fat_file.rb
index 9f29922e6..351be5ac6 100644
--- a/Library/Homebrew/vendor/macho/macho/fat_file.rb
+++ b/Library/Homebrew/vendor/macho/macho/fat_file.rb
@@ -1,24 +1,50 @@
+require "forwardable"
+
module MachO
# Represents a "Fat" file, which contains a header, a listing of available
# architectures, and one or more Mach-O binaries.
# @see https://en.wikipedia.org/wiki/Mach-O#Multi-architecture_binaries
- # @see MachO::MachOFile
+ # @see MachOFile
class FatFile
+ extend Forwardable
+
# @return [String] the filename loaded from, or nil if loaded from a binary string
attr_accessor :filename
- # @return [MachO::FatHeader] the file's header
+ # @return [Headers::FatHeader] the file's header
attr_reader :header
- # @return [Array<MachO::FatArch>] an array of fat architectures
+ # @return [Array<Headers::FatArch>] an array of fat architectures
attr_reader :fat_archs
- # @return [Array<MachO::MachOFile>] an array of Mach-O binaries
+ # @return [Array<MachOFile>] an array of Mach-O binaries
attr_reader :machos
+ # Creates a new FatFile from the given (single-arch) Mach-Os
+ # @param machos [Array<MachOFile>] the machos to combine
+ # @return [FatFile] a new FatFile containing the give machos
+ def self.new_from_machos(*machos)
+ header = Headers::FatHeader.new(Headers::FAT_MAGIC, machos.size)
+ offset = Headers::FatHeader.bytesize + (machos.size * Headers::FatArch.bytesize)
+ fat_archs = []
+ machos.each do |macho|
+ fat_archs << Headers::FatArch.new(macho.header.cputype,
+ macho.header.cpusubtype,
+ offset, macho.serialize.bytesize,
+ macho.alignment)
+ offset += macho.serialize.bytesize
+ end
+
+ bin = header.serialize
+ bin << fat_archs.map(&:serialize).join
+ bin << machos.map(&:serialize).join
+
+ new_from_bin(bin)
+ end
+
# Creates a new FatFile instance from a binary string.
# @param bin [String] a binary string containing raw Mach-O data
- # @return [MachO::FatFile] a new FatFile
+ # @return [FatFile] a new FatFile
def self.new_from_bin(bin)
instance = allocate
instance.initialize_from_bin(bin)
@@ -38,7 +64,7 @@ module MachO
end
# Initializes a new FatFile instance from a binary string.
- # @see MachO::FatFile.new_from_bin
+ # @see new_from_bin
# @api private
def initialize_from_bin(bin)
@filename = nil
@@ -52,70 +78,41 @@ module MachO
@raw_data
end
- # @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
- def object?
- machos.first.object?
- end
-
- # @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise
- def executable?
- machos.first.executable?
- end
-
- # @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise
- def fvmlib?
- machos.first.fvmlib?
- end
-
- # @return [Boolean] true if the file is of type `MH_CORE`, false otherwise
- def core?
- machos.first.core?
- end
-
- # @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise
- def preload?
- machos.first.preload?
- end
-
- # @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise
- def dylib?
- machos.first.dylib?
- end
-
- # @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise
- def dylinker?
- machos.first.dylinker?
- end
-
- # @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise
- def bundle?
- machos.first.bundle?
- end
-
- # @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise
- def dsym?
- machos.first.dsym?
- end
-
- # @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise
- def kext?
- machos.first.kext?
- end
-
- # @return [Fixnum] the file's magic number
- def magic
- header.magic
- end
+ # @!method object?
+ # @return (see MachO::MachOFile#object?)
+ # @!method executable?
+ # @return (see MachO::MachOFile#executable?)
+ # @!method fvmlib?
+ # @return (see MachO::MachOFile#fvmlib?)
+ # @!method core?
+ # @return (see MachO::MachOFile#core?)
+ # @!method preload?
+ # @return (see MachO::MachOFile#preload?)
+ # @!method dylib?
+ # @return (see MachO::MachOFile#dylib?)
+ # @!method dylinker?
+ # @return (see MachO::MachOFile#dylinker?)
+ # @!method bundle?
+ # @return (see MachO::MachOFile#bundle?)
+ # @!method dsym?
+ # @return (see MachO::MachOFile#dsym?)
+ # @!method kext?
+ # @return (see MachO::MachOFile#kext?)
+ # @!method filetype
+ # @return (see MachO::MachOFile#filetype)
+ # @!method dylib_id
+ # @return (see MachO::MachOFile#dylib_id)
+ def_delegators :canonical_macho, :object?, :executable?, :fvmlib?,
+ :core?, :preload?, :dylib?, :dylinker?, :bundle?,
+ :dsym?, :kext?, :filetype, :dylib_id
+
+ # @!method magic
+ # @return (see MachO::Headers::FatHeader#magic)
+ def_delegators :header, :magic
# @return [String] a string representation of the file's magic number
def magic_string
- MH_MAGICS[magic]
- end
-
- # The file's type. Assumed to be the same for every Mach-O within.
- # @return [Symbol] the filetype
- def filetype
- machos.first.filetype
+ Headers::MH_MAGICS[magic]
end
# Populate the instance's fields with the raw Fat Mach-O data.
@@ -128,21 +125,13 @@ module MachO
end
# All load commands responsible for loading dylibs in the file's Mach-O's.
- # @return [Array<MachO::DylibCommand>] an array of DylibCommands
+ # @return [Array<LoadCommands::DylibCommand>] an array of DylibCommands
def dylib_load_commands
machos.map(&:dylib_load_commands).flatten
end
- # The file's dylib ID. If the file is not a dylib, returns `nil`.
- # @example
- # file.dylib_id # => 'libBar.dylib'
- # @return [String, nil] the file's dylib ID
- # @see MachO::MachOFile#linked_dylibs
- def dylib_id
- machos.first.dylib_id
- end
-
- # Changes the file's dylib ID to `new_id`. If the file is not a dylib, does nothing.
+ # Changes the file's dylib ID to `new_id`. If the file is not a dylib,
+ # does nothing.
# @example
# file.change_dylib_id('libFoo.dylib')
# @param new_id [String] the new dylib ID
@@ -151,7 +140,7 @@ module MachO
# if false, fail only if all slices fail.
# @return [void]
# @raise [ArgumentError] if `new_id` is not a String
- # @see MachO::MachOFile#linked_dylibs
+ # @see MachOFile#linked_dylibs
def change_dylib_id(new_id, options = {})
raise ArgumentError, "argument must be a String" unless new_id.is_a?(String)
return unless machos.all?(&:dylib?)
@@ -167,7 +156,7 @@ module MachO
# All shared libraries linked to the file's Mach-Os.
# @return [Array<String>] an array of all shared libraries
- # @see MachO::MachOFile#linked_dylibs
+ # @see MachOFile#linked_dylibs
def linked_dylibs
# Individual architectures in a fat binary can link to different subsets
# of libraries, but at this point we want to have the full picture, i.e.
@@ -175,8 +164,9 @@ module MachO
machos.map(&:linked_dylibs).flatten.uniq
end
- # Changes all dependent shared library install names from `old_name` to `new_name`.
- # In a fat file, this changes install names in all internal Mach-Os.
+ # Changes all dependent shared library install names from `old_name` to
+ # `new_name`. In a fat file, this changes install names in all internal
+ # Mach-Os.
# @example
# file.change_install_name('/usr/lib/libFoo.dylib', '/usr/lib/libBar.dylib')
# @param old_name [String] the shared library name being changed
@@ -185,7 +175,7 @@ module MachO
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
# if false, fail only if all slices fail.
# @return [void]
- # @see MachO::MachOFile#change_install_name
+ # @see MachOFile#change_install_name
def change_install_name(old_name, new_name, options = {})
each_macho(options) do |macho|
macho.change_install_name(old_name, new_name, options)
@@ -198,7 +188,7 @@ module MachO
# All runtime paths associated with the file's Mach-Os.
# @return [Array<String>] an array of all runtime paths
- # @see MachO::MachOFile#rpaths
+ # @see MachOFile#rpaths
def rpaths
# Can individual architectures have different runtime paths?
machos.map(&:rpaths).flatten.uniq
@@ -211,7 +201,7 @@ module MachO
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
# if false, fail only if all slices fail.
# @return [void]
- # @see MachO::MachOFile#change_rpath
+ # @see MachOFile#change_rpath
def change_rpath(old_path, new_path, options = {})
each_macho(options) do |macho|
macho.change_rpath(old_path, new_path, options)
@@ -226,7 +216,7 @@ module MachO
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
# if false, fail only if all slices fail.
# @return [void]
- # @see MachO::MachOFile#add_rpath
+ # @see MachOFile#add_rpath
def add_rpath(path, options = {})
each_macho(options) do |macho|
macho.add_rpath(path, options)
@@ -241,7 +231,7 @@ module MachO
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
# if false, fail only if all slices fail.
# @return void
- # @see MachO::MachOFile#delete_rpath
+ # @see MachOFile#delete_rpath
def delete_rpath(path, options = {})
each_macho(options) do |macho|
macho.delete_rpath(path, options)
@@ -254,20 +244,21 @@ module MachO
# @example
# file.extract(:i386) # => MachO::MachOFile
# @param cputype [Symbol] the CPU type of the Mach-O being extracted
- # @return [MachO::MachOFile, nil] the extracted Mach-O or nil if no Mach-O has the given CPU type
+ # @return [MachOFile, nil] the extracted Mach-O or nil if no Mach-O has the given CPU type
def extract(cputype)
machos.select { |macho| macho.cputype == cputype }.first
end
# Write all (fat) data to the given filename.
# @param filename [String] the file to write to
+ # @return [void]
def write(filename)
File.open(filename, "wb") { |f| f.write(@raw_data) }
end
# Write all (fat) data to the file used to initialize the instance.
# @return [void]
- # @raise [MachO::MachOError] if the instance was initialized without a file
+ # @raise [MachOError] if the instance was initialized without a file
# @note Overwrites all data in the file!
def write!
if filename.nil?
@@ -280,17 +271,18 @@ module MachO
private
# Obtain the fat header from raw file data.
- # @return [MachO::FatHeader] the fat header
- # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
- # @raise [MachO::MagicError] if the magic is not valid Mach-O magic
- # @raise [MachO::MachOBinaryError] if the magic is for a non-fat Mach-O file
- # @raise [MachO::JavaClassFileError] if the file is a Java classfile
+ # @return [Headers::FatHeader] the fat header
+ # @raise [TruncatedFileError] if the file is too small to have a
+ # valid header
+ # @raise [MagicError] if the magic is not valid Mach-O magic
+ # @raise [MachOBinaryError] if the magic is for a non-fat Mach-O file
+ # @raise [JavaClassFileError] if the file is a Java classfile
# @api private
def populate_fat_header
# the smallest fat Mach-O header is 8 bytes
raise TruncatedFileError if @raw_data.size < 8
- fh = FatHeader.new_from_bin(:big, @raw_data[0, FatHeader.bytesize])
+ fh = Headers::FatHeader.new_from_bin(:big, @raw_data[0, Headers::FatHeader.bytesize])
raise MagicError, fh.magic unless Utils.magic?(fh.magic)
raise MachOBinaryError unless Utils.fat_magic?(fh.magic)
@@ -308,22 +300,22 @@ module MachO
end
# Obtain an array of fat architectures from raw file data.
- # @return [Array<MachO::FatArch>] an array of fat architectures
+ # @return [Array<Headers::FatArch>] an array of fat architectures
# @api private
def populate_fat_archs
archs = []
- fa_off = FatHeader.bytesize
- fa_len = FatArch.bytesize
+ fa_off = Headers::FatHeader.bytesize
+ fa_len = Headers::FatArch.bytesize
header.nfat_arch.times do |i|
- archs << FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
+ archs << Headers::FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
end
archs
end
# Obtain an array of Mach-O blobs from raw file data.
- # @return [Array<MachO::MachOFile>] an array of Mach-Os
+ # @return [Array<MachOFile>] an array of Mach-Os
# @api private
def populate_machos
machos = []
@@ -351,7 +343,7 @@ module MachO
# @option options [Boolean] :strict (true) whether or not to fail loudly
# with an exception if at least one Mach-O raises an exception. If false,
# only raises an exception if *all* Mach-Os raise exceptions.
- # @raise [MachO::RecoverableModificationError] under the conditions of
+ # @raise [RecoverableModificationError] under the conditions of
# the `:strict` option above.
# @api private
def each_macho(options = {})
@@ -373,5 +365,13 @@ module MachO
# Non-strict mode: Raise first error if *all* Mach-O slices failed.
raise errors.first if errors.size == machos.size
end
+
+ # Return a single-arch Mach-O that represents this fat Mach-O for purposes
+ # of delegation.
+ # @return [MachOFile] the Mach-O file
+ # @api private
+ def canonical_macho
+ machos.first
+ end
end
end
diff --git a/Library/Homebrew/vendor/macho/macho/headers.rb b/Library/Homebrew/vendor/macho/macho/headers.rb
index 7272503af..08a4b80c4 100644
--- a/Library/Homebrew/vendor/macho/macho/headers.rb
+++ b/Library/Homebrew/vendor/macho/macho/headers.rb
@@ -1,587 +1,665 @@
module MachO
- # big-endian fat magic
- # @api private
- FAT_MAGIC = 0xcafebabe
-
- # little-endian fat magic
- # this is defined, but should never appear in ruby-macho code because
- # fat headers are always big-endian and therefore always unpacked as such.
- # @api private
- FAT_CIGAM = 0xbebafeca
-
- # 32-bit big-endian magic
- # @api private
- MH_MAGIC = 0xfeedface
-
- # 32-bit little-endian magic
- # @api private
- MH_CIGAM = 0xcefaedfe
-
- # 64-bit big-endian magic
- # @api private
- MH_MAGIC_64 = 0xfeedfacf
-
- # 64-bit little-endian magic
- # @api private
- MH_CIGAM_64 = 0xcffaedfe
-
- # association of magic numbers to string representations
- # @api private
- MH_MAGICS = {
- FAT_MAGIC => "FAT_MAGIC",
- MH_MAGIC => "MH_MAGIC",
- MH_CIGAM => "MH_CIGAM",
- MH_MAGIC_64 => "MH_MAGIC_64",
- MH_CIGAM_64 => "MH_CIGAM_64",
- }.freeze
-
- # mask for CPUs with 64-bit architectures (when running a 64-bit ABI?)
- # @api private
- CPU_ARCH_ABI64 = 0x01000000
-
- # any CPU (unused?)
- # @api private
- CPU_TYPE_ANY = -1
-
- # m68k compatible CPUs
- # @api private
- CPU_TYPE_MC680X0 = 0x06
-
- # i386 and later compatible CPUs
- # @api private
- CPU_TYPE_I386 = 0x07
-
- # x86_64 (AMD64) compatible CPUs
- # @api private
- CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64)
-
- # 32-bit ARM compatible CPUs
- # @api private
- CPU_TYPE_ARM = 0x0c
-
- # m88k compatible CPUs
- # @api private
- CPU_TYPE_MC88000 = 0xd
-
- # 64-bit ARM compatible CPUs
- # @api private
- CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
-
- # PowerPC compatible CPUs
- # @api private
- CPU_TYPE_POWERPC = 0x12
-
- # PowerPC64 compatible CPUs
- # @api private
- CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
-
- # association of cpu types to symbol representations
- # @api private
- CPU_TYPES = {
- CPU_TYPE_ANY => :any,
- CPU_TYPE_I386 => :i386,
- CPU_TYPE_X86_64 => :x86_64,
- CPU_TYPE_ARM => :arm,
- CPU_TYPE_ARM64 => :arm64,
- CPU_TYPE_POWERPC => :ppc,
- CPU_TYPE_POWERPC64 => :ppc64,
- }.freeze
-
- # mask for CPU subtype capabilities
- # @api private
- CPU_SUBTYPE_MASK = 0xff000000
-
- # 64-bit libraries (undocumented!)
- # @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html
- # @api private
- CPU_SUBTYPE_LIB64 = 0x80000000
-
- # the lowest common sub-type for `CPU_TYPE_I386`
- # @api private
- CPU_SUBTYPE_I386 = 3
-
- # the i486 sub-type for `CPU_TYPE_I386`
- # @api private
- CPU_SUBTYPE_486 = 4
-
- # the i486SX sub-type for `CPU_TYPE_I386`
- # @api private
- CPU_SUBTYPE_486SX = 132
-
- # the i586 (P5, Pentium) sub-type for `CPU_TYPE_I386`
- # @api private
- CPU_SUBTYPE_586 = 5
-
- # @see CPU_SUBTYPE_586
- # @api private
- CPU_SUBTYPE_PENT = CPU_SUBTYPE_586
-
- # the Pentium Pro (P6) sub-type for `CPU_TYPE_I386`
- # @api private
- CPU_SUBTYPE_PENTPRO = 22
-
- # the Pentium II (P6, M3?) sub-type for `CPU_TYPE_I386`
- # @api private
- CPU_SUBTYPE_PENTII_M3 = 54
-
- # the Pentium II (P6, M5?) sub-type for `CPU_TYPE_I386`
- # @api private
- CPU_SUBTYPE_PENTII_M5 = 86
-
- # the Pentium 4 (Netburst) sub-type for `CPU_TYPE_I386`
- # @api private
- CPU_SUBTYPE_PENTIUM_4 = 10
-
- # the lowest common sub-type for `CPU_TYPE_MC680X0`
- # @api private
- CPU_SUBTYPE_MC680X0_ALL = 1
-
- # @see CPU_SUBTYPE_MC680X0_ALL
- # @api private
- CPU_SUBTYPE_MC68030 = CPU_SUBTYPE_MC680X0_ALL
-
- # the 040 subtype for `CPU_TYPE_MC680X0`
- # @api private
- CPU_SUBTYPE_MC68040 = 2
-
- # the 030 subtype for `CPU_TYPE_MC680X0`
- # @api private
- CPU_SUBTYPE_MC68030_ONLY = 3
-
- # the lowest common sub-type for `CPU_TYPE_X86_64`
- # @api private
- CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386
-
- # the Haskell sub-type for `CPU_TYPE_X86_64`
- # @api private
- CPU_SUBTYPE_X86_64_H = 8
-
- # the lowest common sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_ALL = 0
-
- # the v4t sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V4T = 5
-
- # the v6 sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V6 = 6
-
- # the v5 sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V5TEJ = 7
-
- # the xscale (v5 family) sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_XSCALE = 8
-
- # the v7 sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V7 = 9
-
- # the v7f (Cortex A9) sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V7F = 10
+ # Classes and constants for parsing the headers of Mach-O binaries.
+ module Headers
+ # big-endian fat magic
+ # @api private
+ FAT_MAGIC = 0xcafebabe
- # the v7s ("Swift") sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V7S = 11
+ # little-endian fat magic
+ # this is defined, but should never appear in ruby-macho code because
+ # fat headers are always big-endian and therefore always unpacked as such.
+ # @api private
+ FAT_CIGAM = 0xbebafeca
- # the v7k ("Kirkwood40") sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V7K = 12
-
- # the v6m sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V6M = 14
-
- # the v7m sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V7M = 15
-
- # the v7em sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V7EM = 16
-
- # the v8 sub-type for `CPU_TYPE_ARM`
- # @api private
- CPU_SUBTYPE_ARM_V8 = 13
-
- # the lowest common sub-type for `CPU_TYPE_ARM64`
- # @api private
- CPU_SUBTYPE_ARM64_ALL = 0
-
- # the v8 sub-type for `CPU_TYPE_ARM64`
- # @api private
- CPU_SUBTYPE_ARM64_V8 = 1
-
- # the lowest common sub-type for `CPU_TYPE_MC88000`
- # @api private
- CPU_SUBTYPE_MC88000_ALL = 0
-
- # @see CPU_SUBTYPE_MC88000_ALL
- # @api private
- CPU_SUBTYPE_MMAX_JPC = CPU_SUBTYPE_MC88000_ALL
-
- # the 100 sub-type for `CPU_TYPE_MC88000`
- # @api private
- CPU_SUBTYPE_MC88100 = 1
-
- # the 110 sub-type for `CPU_TYPE_MC88000`
- # @api private
- CPU_SUBTYPE_MC88110 = 2
-
- # the lowest common sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_ALL = 0
-
- # the 601 sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_601 = 1
-
- # the 602 sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_602 = 2
-
- # the 603 sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_603 = 3
-
- # the 603e (G2) sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_603E = 4
-
- # the 603ev sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_603EV = 5
-
- # the 604 sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_604 = 6
-
- # the 604e sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_604E = 7
-
- # the 620 sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_620 = 8
-
- # the 750 (G3) sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_750 = 9
-
- # the 7400 (G4) sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_7400 = 10
-
- # the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_7450 = 11
-
- # the 970 (G5) sub-type for `CPU_TYPE_POWERPC`
- # @api private
- CPU_SUBTYPE_POWERPC_970 = 100
-
- # any CPU sub-type for CPU type `CPU_TYPE_POWERPC64`
- # @api private
- CPU_SUBTYPE_POWERPC64_ALL = CPU_SUBTYPE_POWERPC_ALL
-
- # association of CPU types/subtype pairs to symbol representations in
- # (very) roughly descending order of commonness
- # @see https://opensource.apple.com/source/cctools/cctools-877.8/libstuff/arch.c
- # @api private
- CPU_SUBTYPES = {
- CPU_TYPE_I386 => {
- CPU_SUBTYPE_I386 => :i386,
- CPU_SUBTYPE_486 => :i486,
- CPU_SUBTYPE_486SX => :i486SX,
- CPU_SUBTYPE_586 => :i586, # also "pentium" in arch(3)
- CPU_SUBTYPE_PENTPRO => :i686, # also "pentpro" in arch(3)
- CPU_SUBTYPE_PENTII_M3 => :pentIIm3,
- CPU_SUBTYPE_PENTII_M5 => :pentIIm5,
- CPU_SUBTYPE_PENTIUM_4 => :pentium4,
- }.freeze,
- CPU_TYPE_X86_64 => {
- CPU_SUBTYPE_X86_64_ALL => :x86_64,
- CPU_SUBTYPE_X86_64_H => :x86_64h,
- }.freeze,
- CPU_TYPE_ARM => {
- CPU_SUBTYPE_ARM_ALL => :arm,
- CPU_SUBTYPE_ARM_V4T => :armv4t,
- CPU_SUBTYPE_ARM_V6 => :armv6,
- CPU_SUBTYPE_ARM_V5TEJ => :armv5,
- CPU_SUBTYPE_ARM_XSCALE => :xscale,
- CPU_SUBTYPE_ARM_V7 => :armv7,
- CPU_SUBTYPE_ARM_V7F => :armv7f,
- CPU_SUBTYPE_ARM_V7S => :armv7s,
- CPU_SUBTYPE_ARM_V7K => :armv7k,
- CPU_SUBTYPE_ARM_V6M => :armv6m,
- CPU_SUBTYPE_ARM_V7M => :armv7m,
- CPU_SUBTYPE_ARM_V7EM => :armv7em,
- CPU_SUBTYPE_ARM_V8 => :armv8,
- }.freeze,
- CPU_TYPE_ARM64 => {
- CPU_SUBTYPE_ARM64_ALL => :arm64,
- CPU_SUBTYPE_ARM64_V8 => :arm64v8,
- }.freeze,
- CPU_TYPE_POWERPC => {
- CPU_SUBTYPE_POWERPC_ALL => :ppc,
- CPU_SUBTYPE_POWERPC_601 => :ppc601,
- CPU_SUBTYPE_POWERPC_603 => :ppc603,
- CPU_SUBTYPE_POWERPC_603E => :ppc603e,
- CPU_SUBTYPE_POWERPC_603EV => :ppc603ev,
- CPU_SUBTYPE_POWERPC_604 => :ppc604,
- CPU_SUBTYPE_POWERPC_604E => :ppc604e,
- CPU_SUBTYPE_POWERPC_750 => :ppc750,
- CPU_SUBTYPE_POWERPC_7400 => :ppc7400,
- CPU_SUBTYPE_POWERPC_7450 => :ppc7450,
- CPU_SUBTYPE_POWERPC_970 => :ppc970,
- }.freeze,
- CPU_TYPE_POWERPC64 => {
- CPU_SUBTYPE_POWERPC64_ALL => :ppc64,
- # apparently the only exception to the naming scheme
- CPU_SUBTYPE_POWERPC_970 => :ppc970_64,
- }.freeze,
- CPU_TYPE_MC680X0 => {
- CPU_SUBTYPE_MC680X0_ALL => :m68k,
- CPU_SUBTYPE_MC68030 => :mc68030,
- CPU_SUBTYPE_MC68040 => :mc68040,
- },
- CPU_TYPE_MC88000 => {
- CPU_SUBTYPE_MC88000_ALL => :m88k,
- },
- }.freeze
-
- # relocatable object file
- # @api private
- MH_OBJECT = 0x1
-
- # demand paged executable file
- # @api private
- MH_EXECUTE = 0x2
-
- # fixed VM shared library file
- # @api private
- MH_FVMLIB = 0x3
-
- # core dump file
- # @api private
- MH_CORE = 0x4
-
- # preloaded executable file
- # @api private
- MH_PRELOAD = 0x5
-
- # dynamically bound shared library
- # @api private
- MH_DYLIB = 0x6
-
- # dynamic link editor
- # @api private
- MH_DYLINKER = 0x7
-
- # dynamically bound bundle file
- # @api private
- MH_BUNDLE = 0x8
-
- # shared library stub for static linking only, no section contents
- # @api private
- MH_DYLIB_STUB = 0x9
-
- # companion file with only debug sections
- # @api private
- MH_DSYM = 0xa
-
- # x86_64 kexts
- # @api private
- MH_KEXT_BUNDLE = 0xb
-
- # association of filetypes to Symbol representations
- # @api private
- MH_FILETYPES = {
- MH_OBJECT => :object,
- MH_EXECUTE => :execute,
- MH_FVMLIB => :fvmlib,
- MH_CORE => :core,
- MH_PRELOAD => :preload,
- MH_DYLIB => :dylib,
- MH_DYLINKER => :dylinker,
- MH_BUNDLE => :bundle,
- MH_DYLIB_STUB => :dylib_stub,
- MH_DSYM => :dsym,
- MH_KEXT_BUNDLE => :kext_bundle,
- }.freeze
-
- # association of mach header flag symbols to values
- # @api private
- MH_FLAGS = {
- :MH_NOUNDEFS => 0x1,
- :MH_INCRLINK => 0x2,
- :MH_DYLDLINK => 0x4,
- :MH_BINDATLOAD => 0x8,
- :MH_PREBOUND => 0x10,
- :MH_SPLIT_SEGS => 0x20,
- :MH_LAZY_INIT => 0x40,
- :MH_TWOLEVEL => 0x80,
- :MH_FORCE_FLAT => 0x100,
- :MH_NOMULTIDEFS => 0x200,
- :MH_NOPREFIXBINDING => 0x400,
- :MH_PREBINDABLE => 0x800,
- :MH_ALLMODSBOUND => 0x1000,
- :MH_SUBSECTIONS_VIA_SYMBOLS => 0x2000,
- :MH_CANONICAL => 0x4000,
- :MH_WEAK_DEFINES => 0x8000,
- :MH_BINDS_TO_WEAK => 0x10000,
- :MH_ALLOW_STACK_EXECUTION => 0x20000,
- :MH_ROOT_SAFE => 0x40000,
- :MH_SETUID_SAFE => 0x80000,
- :MH_NO_REEXPORTED_DYLIBS => 0x100000,
- :MH_PIE => 0x200000,
- :MH_DEAD_STRIPPABLE_DYLIB => 0x400000,
- :MH_HAS_TLV_DESCRIPTORS => 0x800000,
- :MH_NO_HEAP_EXECUTION => 0x1000000,
- :MH_APP_EXTENSION_SAFE => 0x02000000,
- }.freeze
-
- # Fat binary header structure
- # @see MachO::FatArch
- class FatHeader < MachOStructure
- # @return [Fixnum] the magic number of the header (and file)
- attr_reader :magic
-
- # @return [Fixnum] the number of fat architecture structures following the header
- attr_reader :nfat_arch
-
- # always big-endian
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "N2".freeze
-
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 8
-
- # @api private
- def initialize(magic, nfat_arch)
- @magic = magic
- @nfat_arch = nfat_arch
- end
- end
+ # 32-bit big-endian magic
+ # @api private
+ MH_MAGIC = 0xfeedface
- # Fat binary header architecture structure. A Fat binary has one or more of
- # these, representing one or more internal Mach-O blobs.
- # @see MachO::FatHeader
- class FatArch < MachOStructure
- # @return [Fixnum] the CPU type of the Mach-O
- attr_reader :cputype
+ # 32-bit little-endian magic
+ # @api private
+ MH_CIGAM = 0xcefaedfe
- # @return [Fixnum] the CPU subtype of the Mach-O
- attr_reader :cpusubtype
+ # 64-bit big-endian magic
+ # @api private
+ MH_MAGIC_64 = 0xfeedfacf
- # @return [Fixnum] the file offset to the beginning of the Mach-O data
- attr_reader :offset
+ # 64-bit little-endian magic
+ # @api private
+ MH_CIGAM_64 = 0xcffaedfe
- # @return [Fixnum] the size, in bytes, of the Mach-O data
- attr_reader :size
+ # association of magic numbers to string representations
+ # @api private
+ MH_MAGICS = {
+ FAT_MAGIC => "FAT_MAGIC",
+ MH_MAGIC => "MH_MAGIC",
+ MH_CIGAM => "MH_CIGAM",
+ MH_MAGIC_64 => "MH_MAGIC_64",
+ MH_CIGAM_64 => "MH_CIGAM_64",
+ }.freeze
+
+ # mask for CPUs with 64-bit architectures (when running a 64-bit ABI?)
+ # @api private
+ CPU_ARCH_ABI64 = 0x01000000
- # @return [Fixnum] the alignment, as a power of 2
- attr_reader :align
+ # any CPU (unused?)
+ # @api private
+ CPU_TYPE_ANY = -1
- # always big-endian
- # @see MachOStructure::FORMAT
+ # m68k compatible CPUs
# @api private
- FORMAT = "N5".freeze
+ CPU_TYPE_MC680X0 = 0x06
- # @see MachOStructure::SIZEOF
+ # i386 and later compatible CPUs
# @api private
- SIZEOF = 20
+ CPU_TYPE_I386 = 0x07
+ # x86_64 (AMD64) compatible CPUs
# @api private
- def initialize(cputype, cpusubtype, offset, size, align)
- @cputype = cputype
- @cpusubtype = cpusubtype
- @offset = offset
- @size = size
- @align = align
- end
- end
+ CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64)
- # 32-bit Mach-O file header structure
- class MachHeader < MachOStructure
- # @return [Fixnum] the magic number
- attr_reader :magic
+ # 32-bit ARM compatible CPUs
+ # @api private
+ CPU_TYPE_ARM = 0x0c
- # @return [Fixnum] the CPU type of the Mach-O
- attr_reader :cputype
+ # m88k compatible CPUs
+ # @api private
+ CPU_TYPE_MC88000 = 0xd
- # @return [Fixnum] the CPU subtype of the Mach-O
- attr_reader :cpusubtype
+ # 64-bit ARM compatible CPUs
+ # @api private
+ CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
- # @return [Fixnum] the file type of the Mach-O
- attr_reader :filetype
+ # PowerPC compatible CPUs
+ # @api private
+ CPU_TYPE_POWERPC = 0x12
- # @return [Fixnum] the number of load commands in the Mach-O
- attr_reader :ncmds
+ # PowerPC64 compatible CPUs
+ # @api private
+ CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
- # @return [Fixnum] the size of all load commands, in bytes, in the Mach-O
- attr_reader :sizeofcmds
+ # association of cpu types to symbol representations
+ # @api private
+ CPU_TYPES = {
+ CPU_TYPE_ANY => :any,
+ CPU_TYPE_I386 => :i386,
+ CPU_TYPE_X86_64 => :x86_64,
+ CPU_TYPE_ARM => :arm,
+ CPU_TYPE_ARM64 => :arm64,
+ CPU_TYPE_POWERPC => :ppc,
+ CPU_TYPE_POWERPC64 => :ppc64,
+ }.freeze
+
+ # mask for CPU subtype capabilities
+ # @api private
+ CPU_SUBTYPE_MASK = 0xff000000
- # @return [Fixnum] the header flags associated with the Mach-O
- attr_reader :flags
+ # 64-bit libraries (undocumented!)
+ # @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html
+ # @api private
+ CPU_SUBTYPE_LIB64 = 0x80000000
- # @see MachOStructure::FORMAT
+ # the lowest common sub-type for `CPU_TYPE_I386`
# @api private
- FORMAT = "L=7".freeze
+ CPU_SUBTYPE_I386 = 3
- # @see MachOStructure::SIZEOF
+ # the i486 sub-type for `CPU_TYPE_I386`
# @api private
- SIZEOF = 28
+ CPU_SUBTYPE_486 = 4
+ # the i486SX sub-type for `CPU_TYPE_I386`
# @api private
- def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
- flags)
- @magic = magic
- @cputype = cputype
- # For now we're not interested in additional capability bits also to be
- # found in the `cpusubtype` field. We only care about the CPU sub-type.
- @cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK
- @filetype = filetype
- @ncmds = ncmds
- @sizeofcmds = sizeofcmds
- @flags = flags
- end
+ CPU_SUBTYPE_486SX = 132
- # @example
- # puts "this mach-o has position-independent execution" if header.flag?(:MH_PIE)
- # @param flag [Symbol] a mach header flag symbol
- # @return [Boolean] true if `flag` is present in the header's flag section
- def flag?(flag)
- flag = MH_FLAGS[flag]
- return false if flag.nil?
- flags & flag == flag
- end
- end
+ # the i586 (P5, Pentium) sub-type for `CPU_TYPE_I386`
+ # @api private
+ CPU_SUBTYPE_586 = 5
+
+ # @see CPU_SUBTYPE_586
+ # @api private
+ CPU_SUBTYPE_PENT = CPU_SUBTYPE_586
+
+ # the Pentium Pro (P6) sub-type for `CPU_TYPE_I386`
+ # @api private
+ CPU_SUBTYPE_PENTPRO = 22
+
+ # the Pentium II (P6, M3?) sub-type for `CPU_TYPE_I386`
+ # @api private
+ CPU_SUBTYPE_PENTII_M3 = 54
+
+ # the Pentium II (P6, M5?) sub-type for `CPU_TYPE_I386`
+ # @api private
+ CPU_SUBTYPE_PENTII_M5 = 86
+
+ # the Pentium 4 (Netburst) sub-type for `CPU_TYPE_I386`
+ # @api private
+ CPU_SUBTYPE_PENTIUM_4 = 10
+
+ # the lowest common sub-type for `CPU_TYPE_MC680X0`
+ # @api private
+ CPU_SUBTYPE_MC680X0_ALL = 1
+
+ # @see CPU_SUBTYPE_MC680X0_ALL
+ # @api private
+ CPU_SUBTYPE_MC68030 = CPU_SUBTYPE_MC680X0_ALL
+
+ # the 040 subtype for `CPU_TYPE_MC680X0`
+ # @api private
+ CPU_SUBTYPE_MC68040 = 2
+
+ # the 030 subtype for `CPU_TYPE_MC680X0`
+ # @api private
+ CPU_SUBTYPE_MC68030_ONLY = 3
+
+ # the lowest common sub-type for `CPU_TYPE_X86_64`
+ # @api private
+ CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386
+
+ # the Haskell sub-type for `CPU_TYPE_X86_64`
+ # @api private
+ CPU_SUBTYPE_X86_64_H = 8
+
+ # the lowest common sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_ALL = 0
+
+ # the v4t sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V4T = 5
+
+ # the v6 sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V6 = 6
+
+ # the v5 sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V5TEJ = 7
+
+ # the xscale (v5 family) sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_XSCALE = 8
+
+ # the v7 sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V7 = 9
+
+ # the v7f (Cortex A9) sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V7F = 10
+
+ # the v7s ("Swift") sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V7S = 11
+
+ # the v7k ("Kirkwood40") sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V7K = 12
+
+ # the v6m sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V6M = 14
+
+ # the v7m sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V7M = 15
- # 64-bit Mach-O file header structure
- class MachHeader64 < MachHeader
- # @return [void]
- attr_reader :reserved
+ # the v7em sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V7EM = 16
+
+ # the v8 sub-type for `CPU_TYPE_ARM`
+ # @api private
+ CPU_SUBTYPE_ARM_V8 = 13
+
+ # the lowest common sub-type for `CPU_TYPE_ARM64`
+ # @api private
+ CPU_SUBTYPE_ARM64_ALL = 0
+
+ # the v8 sub-type for `CPU_TYPE_ARM64`
+ # @api private
+ CPU_SUBTYPE_ARM64_V8 = 1
+
+ # the lowest common sub-type for `CPU_TYPE_MC88000`
+ # @api private
+ CPU_SUBTYPE_MC88000_ALL = 0
+
+ # @see CPU_SUBTYPE_MC88000_ALL
+ # @api private
+ CPU_SUBTYPE_MMAX_JPC = CPU_SUBTYPE_MC88000_ALL
+
+ # the 100 sub-type for `CPU_TYPE_MC88000`
+ # @api private
+ CPU_SUBTYPE_MC88100 = 1
+
+ # the 110 sub-type for `CPU_TYPE_MC88000`
+ # @api private
+ CPU_SUBTYPE_MC88110 = 2
+
+ # the lowest common sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_ALL = 0
+
+ # the 601 sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_601 = 1
+
+ # the 602 sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_602 = 2
+
+ # the 603 sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_603 = 3
+
+ # the 603e (G2) sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_603E = 4
+
+ # the 603ev sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_603EV = 5
+
+ # the 604 sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_604 = 6
+
+ # the 604e sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_604E = 7
+
+ # the 620 sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_620 = 8
+
+ # the 750 (G3) sub-type for `CPU_TYPE_POWERPC`
+ # @api private
+ CPU_SUBTYPE_POWERPC_750 = 9
- # @see MachOStructure::FORMAT
+ # the 7400 (G4) sub-type for `CPU_TYPE_POWERPC`
# @api private
- FORMAT = "L=8".freeze
+ CPU_SUBTYPE_POWERPC_7400 = 10
- # @see MachOStructure::SIZEOF
+ # the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC`
# @api private
- SIZEOF = 32
+ CPU_SUBTYPE_POWERPC_7450 = 11
+ # the 970 (G5) sub-type for `CPU_TYPE_POWERPC`
# @api private
- def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
- flags, reserved)
- super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
- @reserved = reserved
+ CPU_SUBTYPE_POWERPC_970 = 100
+
+ # any CPU sub-type for CPU type `CPU_TYPE_POWERPC64`
+ # @api private
+ CPU_SUBTYPE_POWERPC64_ALL = CPU_SUBTYPE_POWERPC_ALL
+
+ # association of CPU types/subtype pairs to symbol representations in
+ # (very) roughly descending order of commonness
+ # @see https://opensource.apple.com/source/cctools/cctools-877.8/libstuff/arch.c
+ # @api private
+ CPU_SUBTYPES = {
+ CPU_TYPE_I386 => {
+ CPU_SUBTYPE_I386 => :i386,
+ CPU_SUBTYPE_486 => :i486,
+ CPU_SUBTYPE_486SX => :i486SX,
+ CPU_SUBTYPE_586 => :i586, # also "pentium" in arch(3)
+ CPU_SUBTYPE_PENTPRO => :i686, # also "pentpro" in arch(3)
+ CPU_SUBTYPE_PENTII_M3 => :pentIIm3,
+ CPU_SUBTYPE_PENTII_M5 => :pentIIm5,
+ CPU_SUBTYPE_PENTIUM_4 => :pentium4,
+ }.freeze,
+ CPU_TYPE_X86_64 => {
+ CPU_SUBTYPE_X86_64_ALL => :x86_64,
+ CPU_SUBTYPE_X86_64_H => :x86_64h,
+ }.freeze,
+ CPU_TYPE_ARM => {
+ CPU_SUBTYPE_ARM_ALL => :arm,
+ CPU_SUBTYPE_ARM_V4T => :armv4t,
+ CPU_SUBTYPE_ARM_V6 => :armv6,
+ CPU_SUBTYPE_ARM_V5TEJ => :armv5,
+ CPU_SUBTYPE_ARM_XSCALE => :xscale,
+ CPU_SUBTYPE_ARM_V7 => :armv7,
+ CPU_SUBTYPE_ARM_V7F => :armv7f,
+ CPU_SUBTYPE_ARM_V7S => :armv7s,
+ CPU_SUBTYPE_ARM_V7K => :armv7k,
+ CPU_SUBTYPE_ARM_V6M => :armv6m,
+ CPU_SUBTYPE_ARM_V7M => :armv7m,
+ CPU_SUBTYPE_ARM_V7EM => :armv7em,
+ CPU_SUBTYPE_ARM_V8 => :armv8,
+ }.freeze,
+ CPU_TYPE_ARM64 => {
+ CPU_SUBTYPE_ARM64_ALL => :arm64,
+ CPU_SUBTYPE_ARM64_V8 => :arm64v8,
+ }.freeze,
+ CPU_TYPE_POWERPC => {
+ CPU_SUBTYPE_POWERPC_ALL => :ppc,
+ CPU_SUBTYPE_POWERPC_601 => :ppc601,
+ CPU_SUBTYPE_POWERPC_603 => :ppc603,
+ CPU_SUBTYPE_POWERPC_603E => :ppc603e,
+ CPU_SUBTYPE_POWERPC_603EV => :ppc603ev,
+ CPU_SUBTYPE_POWERPC_604 => :ppc604,
+ CPU_SUBTYPE_POWERPC_604E => :ppc604e,
+ CPU_SUBTYPE_POWERPC_750 => :ppc750,
+ CPU_SUBTYPE_POWERPC_7400 => :ppc7400,
+ CPU_SUBTYPE_POWERPC_7450 => :ppc7450,
+ CPU_SUBTYPE_POWERPC_970 => :ppc970,
+ }.freeze,
+ CPU_TYPE_POWERPC64 => {
+ CPU_SUBTYPE_POWERPC64_ALL => :ppc64,
+ # apparently the only exception to the naming scheme
+ CPU_SUBTYPE_POWERPC_970 => :ppc970_64,
+ }.freeze,
+ CPU_TYPE_MC680X0 => {
+ CPU_SUBTYPE_MC680X0_ALL => :m68k,
+ CPU_SUBTYPE_MC68030 => :mc68030,
+ CPU_SUBTYPE_MC68040 => :mc68040,
+ },
+ CPU_TYPE_MC88000 => {
+ CPU_SUBTYPE_MC88000_ALL => :m88k,
+ },
+ }.freeze
+
+ # relocatable object file
+ # @api private
+ MH_OBJECT = 0x1
+
+ # demand paged executable file
+ # @api private
+ MH_EXECUTE = 0x2
+
+ # fixed VM shared library file
+ # @api private
+ MH_FVMLIB = 0x3
+
+ # core dump file
+ # @api private
+ MH_CORE = 0x4
+
+ # preloaded executable file
+ # @api private
+ MH_PRELOAD = 0x5
+
+ # dynamically bound shared library
+ # @api private
+ MH_DYLIB = 0x6
+
+ # dynamic link editor
+ # @api private
+ MH_DYLINKER = 0x7
+
+ # dynamically bound bundle file
+ # @api private
+ MH_BUNDLE = 0x8
+
+ # shared library stub for static linking only, no section contents
+ # @api private
+ MH_DYLIB_STUB = 0x9
+
+ # companion file with only debug sections
+ # @api private
+ MH_DSYM = 0xa
+
+ # x86_64 kexts
+ # @api private
+ MH_KEXT_BUNDLE = 0xb
+
+ # association of filetypes to Symbol representations
+ # @api private
+ MH_FILETYPES = {
+ MH_OBJECT => :object,
+ MH_EXECUTE => :execute,
+ MH_FVMLIB => :fvmlib,
+ MH_CORE => :core,
+ MH_PRELOAD => :preload,
+ MH_DYLIB => :dylib,
+ MH_DYLINKER => :dylinker,
+ MH_BUNDLE => :bundle,
+ MH_DYLIB_STUB => :dylib_stub,
+ MH_DSYM => :dsym,
+ MH_KEXT_BUNDLE => :kext_bundle,
+ }.freeze
+
+ # association of mach header flag symbols to values
+ # @api private
+ MH_FLAGS = {
+ :MH_NOUNDEFS => 0x1,
+ :MH_INCRLINK => 0x2,
+ :MH_DYLDLINK => 0x4,
+ :MH_BINDATLOAD => 0x8,
+ :MH_PREBOUND => 0x10,
+ :MH_SPLIT_SEGS => 0x20,
+ :MH_LAZY_INIT => 0x40,
+ :MH_TWOLEVEL => 0x80,
+ :MH_FORCE_FLAT => 0x100,
+ :MH_NOMULTIDEFS => 0x200,
+ :MH_NOPREFIXBINDING => 0x400,
+ :MH_PREBINDABLE => 0x800,
+ :MH_ALLMODSBOUND => 0x1000,
+ :MH_SUBSECTIONS_VIA_SYMBOLS => 0x2000,
+ :MH_CANONICAL => 0x4000,
+ :MH_WEAK_DEFINES => 0x8000,
+ :MH_BINDS_TO_WEAK => 0x10000,
+ :MH_ALLOW_STACK_EXECUTION => 0x20000,
+ :MH_ROOT_SAFE => 0x40000,
+ :MH_SETUID_SAFE => 0x80000,
+ :MH_NO_REEXPORTED_DYLIBS => 0x100000,
+ :MH_PIE => 0x200000,
+ :MH_DEAD_STRIPPABLE_DYLIB => 0x400000,
+ :MH_HAS_TLV_DESCRIPTORS => 0x800000,
+ :MH_NO_HEAP_EXECUTION => 0x1000000,
+ :MH_APP_EXTENSION_SAFE => 0x02000000,
+ }.freeze
+
+ # Fat binary header structure
+ # @see MachO::FatArch
+ class FatHeader < MachOStructure
+ # @return [Fixnum] the magic number of the header (and file)
+ attr_reader :magic
+
+ # @return [Fixnum] the number of fat architecture structures following the header
+ attr_reader :nfat_arch
+
+ # always big-endian
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "N2".freeze
+
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 8
+
+ # @api private
+ def initialize(magic, nfat_arch)
+ @magic = magic
+ @nfat_arch = nfat_arch
+ end
+
+ # @return [String] the serialized fields of the fat header
+ def serialize
+ [magic, nfat_arch].pack(FORMAT)
+ end
+ end
+
+ # Fat binary header architecture structure. A Fat binary has one or more of
+ # these, representing one or more internal Mach-O blobs.
+ # @see MachO::Headers::FatHeader
+ class FatArch < MachOStructure
+ # @return [Fixnum] the CPU type of the Mach-O
+ attr_reader :cputype
+
+ # @return [Fixnum] the CPU subtype of the Mach-O
+ attr_reader :cpusubtype
+
+ # @return [Fixnum] the file offset to the beginning of the Mach-O data
+ attr_reader :offset
+
+ # @return [Fixnum] the size, in bytes, of the Mach-O data
+ attr_reader :size
+
+ # @return [Fixnum] the alignment, as a power of 2
+ attr_reader :align
+
+ # always big-endian
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "N5".freeze
+
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 20
+
+ # @api private
+ def initialize(cputype, cpusubtype, offset, size, align)
+ @cputype = cputype
+ @cpusubtype = cpusubtype
+ @offset = offset
+ @size = size
+ @align = align
+ end
+
+ # @return [String] the serialized fields of the fat arch
+ def serialize
+ [cputype, cpusubtype, offset, size, align].pack(FORMAT)
+ end
+ end
+
+ # 32-bit Mach-O file header structure
+ class MachHeader < MachOStructure
+ # @return [Fixnum] the magic number
+ attr_reader :magic
+
+ # @return [Fixnum] the CPU type of the Mach-O
+ attr_reader :cputype
+
+ # @return [Fixnum] the CPU subtype of the Mach-O
+ attr_reader :cpusubtype
+
+ # @return [Fixnum] the file type of the Mach-O
+ attr_reader :filetype
+
+ # @return [Fixnum] the number of load commands in the Mach-O
+ attr_reader :ncmds
+
+ # @return [Fixnum] the size of all load commands, in bytes, in the Mach-O
+ attr_reader :sizeofcmds
+
+ # @return [Fixnum] the header flags associated with the Mach-O
+ attr_reader :flags
+
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=7".freeze
+
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 28
+
+ # @api private
+ def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
+ flags)
+ @magic = magic
+ @cputype = cputype
+ # For now we're not interested in additional capability bits also to be
+ # found in the `cpusubtype` field. We only care about the CPU sub-type.
+ @cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK
+ @filetype = filetype
+ @ncmds = ncmds
+ @sizeofcmds = sizeofcmds
+ @flags = flags
+ end
+
+ # @example
+ # puts "this mach-o has position-independent execution" if header.flag?(:MH_PIE)
+ # @param flag [Symbol] a mach header flag symbol
+ # @return [Boolean] true if `flag` is present in the header's flag section
+ def flag?(flag)
+ flag = MH_FLAGS[flag]
+ return false if flag.nil?
+ flags & flag == flag
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_OBJECT`
+ def object?
+ filetype == Headers::MH_OBJECT
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_EXECUTE`
+ def executable?
+ filetype == Headers::MH_EXECUTE
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_FVMLIB`
+ def fvmlib?
+ filetype == Headers::MH_FVMLIB
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_CORE`
+ def core?
+ filetype == Headers::MH_CORE
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_PRELOAD`
+ def preload?
+ filetype == Headers::MH_PRELOAD
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_DYLIB`
+ def dylib?
+ filetype == Headers::MH_DYLIB
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_DYLINKER`
+ def dylinker?
+ filetype == Headers::MH_DYLINKER
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_BUNDLE`
+ def bundle?
+ filetype == Headers::MH_BUNDLE
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_DSYM`
+ def dsym?
+ filetype == Headers::MH_DSYM
+ end
+
+ # @return [Boolean] whether or not the file is of type `MH_KEXT_BUNDLE`
+ def kext?
+ filetype == Headers::MH_KEXT_BUNDLE
+ end
+
+ # @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
+ def magic32?
+ Utils.magic32?(magic)
+ end
+
+ # @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise
+ def magic64?
+ Utils.magic64?(magic)
+ end
+
+ # @return [Fixnum] the file's internal alignment
+ def alignment
+ magic32? ? 4 : 8
+ end
+ end
+
+ # 64-bit Mach-O file header structure
+ class MachHeader64 < MachHeader
+ # @return [void]
+ attr_reader :reserved
+
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=8".freeze
+
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 32
+
+ # @api private
+ def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
+ flags, reserved)
+ super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
+ @reserved = reserved
+ end
end
end
end
diff --git a/Library/Homebrew/vendor/macho/macho/load_commands.rb b/Library/Homebrew/vendor/macho/macho/load_commands.rb
index 205110801..be4319ee2 100644
--- a/Library/Homebrew/vendor/macho/macho/load_commands.rb
+++ b/Library/Homebrew/vendor/macho/macho/load_commands.rb
@@ -1,1314 +1,1350 @@
module MachO
- # load commands added after OS X 10.1 need to be bitwise ORed with
- # LC_REQ_DYLD to be recognized by the dynamic linder (dyld)
- # @api private
- LC_REQ_DYLD = 0x80000000
-
- # association of load commands to symbol representations
- # @api private
- LOAD_COMMANDS = {
- 0x1 => :LC_SEGMENT,
- 0x2 => :LC_SYMTAB,
- 0x3 => :LC_SYMSEG,
- 0x4 => :LC_THREAD,
- 0x5 => :LC_UNIXTHREAD,
- 0x6 => :LC_LOADFVMLIB,
- 0x7 => :LC_IDFVMLIB,
- 0x8 => :LC_IDENT,
- 0x9 => :LC_FVMFILE,
- 0xa => :LC_PREPAGE,
- 0xb => :LC_DYSYMTAB,
- 0xc => :LC_LOAD_DYLIB,
- 0xd => :LC_ID_DYLIB,
- 0xe => :LC_LOAD_DYLINKER,
- 0xf => :LC_ID_DYLINKER,
- 0x10 => :LC_PREBOUND_DYLIB,
- 0x11 => :LC_ROUTINES,
- 0x12 => :LC_SUB_FRAMEWORK,
- 0x13 => :LC_SUB_UMBRELLA,
- 0x14 => :LC_SUB_CLIENT,
- 0x15 => :LC_SUB_LIBRARY,
- 0x16 => :LC_TWOLEVEL_HINTS,
- 0x17 => :LC_PREBIND_CKSUM,
- (0x18 | LC_REQ_DYLD) => :LC_LOAD_WEAK_DYLIB,
- 0x19 => :LC_SEGMENT_64,
- 0x1a => :LC_ROUTINES_64,
- 0x1b => :LC_UUID,
- (0x1c | LC_REQ_DYLD) => :LC_RPATH,
- 0x1d => :LC_CODE_SIGNATURE,
- 0x1e => :LC_SEGMENT_SPLIT_INFO,
- (0x1f | LC_REQ_DYLD) => :LC_REEXPORT_DYLIB,
- 0x20 => :LC_LAZY_LOAD_DYLIB,
- 0x21 => :LC_ENCRYPTION_INFO,
- 0x22 => :LC_DYLD_INFO,
- (0x22 | LC_REQ_DYLD) => :LC_DYLD_INFO_ONLY,
- (0x23 | LC_REQ_DYLD) => :LC_LOAD_UPWARD_DYLIB,
- 0x24 => :LC_VERSION_MIN_MACOSX,
- 0x25 => :LC_VERSION_MIN_IPHONEOS,
- 0x26 => :LC_FUNCTION_STARTS,
- 0x27 => :LC_DYLD_ENVIRONMENT,
- (0x28 | LC_REQ_DYLD) => :LC_MAIN,
- 0x29 => :LC_DATA_IN_CODE,
- 0x2a => :LC_SOURCE_VERSION,
- 0x2b => :LC_DYLIB_CODE_SIGN_DRS,
- 0x2c => :LC_ENCRYPTION_INFO_64,
- 0x2d => :LC_LINKER_OPTION,
- 0x2e => :LC_LINKER_OPTIMIZATION_HINT,
- 0x2f => :LC_VERSION_MIN_TVOS,
- 0x30 => :LC_VERSION_MIN_WATCHOS,
- }.freeze
-
- # association of symbol representations to load command constants
- # @api private
- LOAD_COMMAND_CONSTANTS = LOAD_COMMANDS.invert.freeze
-
- # load commands responsible for loading dylibs
- # @api private
- DYLIB_LOAD_COMMANDS = [
- :LC_LOAD_DYLIB,
- :LC_LOAD_WEAK_DYLIB,
- :LC_REEXPORT_DYLIB,
- :LC_LAZY_LOAD_DYLIB,
- :LC_LOAD_UPWARD_DYLIB,
- ].freeze
-
- # load commands that can be created manually via {LoadCommand.create}
- # @api private
- CREATABLE_LOAD_COMMANDS = DYLIB_LOAD_COMMANDS + [
- :LC_ID_DYLIB,
- :LC_RPATH,
- :LC_LOAD_DYLINKER,
- ].freeze
-
- # association of load command symbols to string representations of classes
- # @api private
- LC_STRUCTURES = {
- :LC_SEGMENT => "SegmentCommand",
- :LC_SYMTAB => "SymtabCommand",
- :LC_SYMSEG => "SymsegCommand", # obsolete
- :LC_THREAD => "ThreadCommand", # seems obsolete, but not documented as such
- :LC_UNIXTHREAD => "ThreadCommand",
- :LC_LOADFVMLIB => "FvmlibCommand", # obsolete
- :LC_IDFVMLIB => "FvmlibCommand", # obsolete
- :LC_IDENT => "IdentCommand", # obsolete
- :LC_FVMFILE => "FvmfileCommand", # reserved for internal use only
- :LC_PREPAGE => "LoadCommand", # reserved for internal use only, no public struct
- :LC_DYSYMTAB => "DysymtabCommand",
- :LC_LOAD_DYLIB => "DylibCommand",
- :LC_ID_DYLIB => "DylibCommand",
- :LC_LOAD_DYLINKER => "DylinkerCommand",
- :LC_ID_DYLINKER => "DylinkerCommand",
- :LC_PREBOUND_DYLIB => "PreboundDylibCommand",
- :LC_ROUTINES => "RoutinesCommand",
- :LC_SUB_FRAMEWORK => "SubFrameworkCommand",
- :LC_SUB_UMBRELLA => "SubUmbrellaCommand",
- :LC_SUB_CLIENT => "SubClientCommand",
- :LC_SUB_LIBRARY => "SubLibraryCommand",
- :LC_TWOLEVEL_HINTS => "TwolevelHintsCommand",
- :LC_PREBIND_CKSUM => "PrebindCksumCommand",
- :LC_LOAD_WEAK_DYLIB => "DylibCommand",
- :LC_SEGMENT_64 => "SegmentCommand64",
- :LC_ROUTINES_64 => "RoutinesCommand64",
- :LC_UUID => "UUIDCommand",
- :LC_RPATH => "RpathCommand",
- :LC_CODE_SIGNATURE => "LinkeditDataCommand",
- :LC_SEGMENT_SPLIT_INFO => "LinkeditDataCommand",
- :LC_REEXPORT_DYLIB => "DylibCommand",
- :LC_LAZY_LOAD_DYLIB => "DylibCommand",
- :LC_ENCRYPTION_INFO => "EncryptionInfoCommand",
- :LC_DYLD_INFO => "DyldInfoCommand",
- :LC_DYLD_INFO_ONLY => "DyldInfoCommand",
- :LC_LOAD_UPWARD_DYLIB => "DylibCommand",
- :LC_VERSION_MIN_MACOSX => "VersionMinCommand",
- :LC_VERSION_MIN_IPHONEOS => "VersionMinCommand",
- :LC_FUNCTION_STARTS => "LinkeditDataCommand",
- :LC_DYLD_ENVIRONMENT => "DylinkerCommand",
- :LC_MAIN => "EntryPointCommand",
- :LC_DATA_IN_CODE => "LinkeditDataCommand",
- :LC_SOURCE_VERSION => "SourceVersionCommand",
- :LC_DYLIB_CODE_SIGN_DRS => "LinkeditDataCommand",
- :LC_ENCRYPTION_INFO_64 => "EncryptionInfoCommand64",
- :LC_LINKER_OPTION => "LinkerOptionCommand",
- :LC_LINKER_OPTIMIZATION_HINT => "LinkeditDataCommand",
- :LC_VERSION_MIN_TVOS => "VersionMinCommand",
- :LC_VERSION_MIN_WATCHOS => "VersionMinCommand",
- }.freeze
-
- # association of segment name symbols to names
- # @api private
- SEGMENT_NAMES = {
- :SEG_PAGEZERO => "__PAGEZERO",
- :SEG_TEXT => "__TEXT",
- :SEG_DATA => "__DATA",
- :SEG_OBJC => "__OBJC",
- :SEG_ICON => "__ICON",
- :SEG_LINKEDIT => "__LINKEDIT",
- :SEG_UNIXSTACK => "__UNIXSTACK",
- :SEG_IMPORT => "__IMPORT",
- }.freeze
-
- # association of segment flag symbols to values
- # @api private
- SEGMENT_FLAGS = {
- :SG_HIGHVM => 0x1,
- :SG_FVMLIB => 0x2,
- :SG_NORELOC => 0x4,
- :SG_PROTECTED_VERSION_1 => 0x8,
- }.freeze
-
- # Mach-O load command structure
- # This is the most generic load command - only cmd ID and size are
- # represented, and no actual data. Used when a more specific class
- # isn't available/implemented.
- class LoadCommand < MachOStructure
- # @return [MachO::MachOView] the raw view associated with the load command
- attr_reader :view
-
- # @return [Fixnum] the load command's identifying number
- attr_reader :cmd
-
- # @return [Fixnum] the size of the load command, in bytes
- attr_reader :cmdsize
-
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2".freeze
+ # Classes and constants for parsing load commands in Mach-O binaries.
+ module LoadCommands
+ # load commands added after OS X 10.1 need to be bitwise ORed with
+ # LC_REQ_DYLD to be recognized by the dynamic linker (dyld)
+ # @api private
+ LC_REQ_DYLD = 0x80000000
+
+ # association of load commands to symbol representations
+ # @api private
+ LOAD_COMMANDS = {
+ 0x1 => :LC_SEGMENT,
+ 0x2 => :LC_SYMTAB,
+ 0x3 => :LC_SYMSEG,
+ 0x4 => :LC_THREAD,
+ 0x5 => :LC_UNIXTHREAD,
+ 0x6 => :LC_LOADFVMLIB,
+ 0x7 => :LC_IDFVMLIB,
+ 0x8 => :LC_IDENT,
+ 0x9 => :LC_FVMFILE,
+ 0xa => :LC_PREPAGE,
+ 0xb => :LC_DYSYMTAB,
+ 0xc => :LC_LOAD_DYLIB,
+ 0xd => :LC_ID_DYLIB,
+ 0xe => :LC_LOAD_DYLINKER,
+ 0xf => :LC_ID_DYLINKER,
+ 0x10 => :LC_PREBOUND_DYLIB,
+ 0x11 => :LC_ROUTINES,
+ 0x12 => :LC_SUB_FRAMEWORK,
+ 0x13 => :LC_SUB_UMBRELLA,
+ 0x14 => :LC_SUB_CLIENT,
+ 0x15 => :LC_SUB_LIBRARY,
+ 0x16 => :LC_TWOLEVEL_HINTS,
+ 0x17 => :LC_PREBIND_CKSUM,
+ (0x18 | LC_REQ_DYLD) => :LC_LOAD_WEAK_DYLIB,
+ 0x19 => :LC_SEGMENT_64,
+ 0x1a => :LC_ROUTINES_64,
+ 0x1b => :LC_UUID,
+ (0x1c | LC_REQ_DYLD) => :LC_RPATH,
+ 0x1d => :LC_CODE_SIGNATURE,
+ 0x1e => :LC_SEGMENT_SPLIT_INFO,
+ (0x1f | LC_REQ_DYLD) => :LC_REEXPORT_DYLIB,
+ 0x20 => :LC_LAZY_LOAD_DYLIB,
+ 0x21 => :LC_ENCRYPTION_INFO,
+ 0x22 => :LC_DYLD_INFO,
+ (0x22 | LC_REQ_DYLD) => :LC_DYLD_INFO_ONLY,
+ (0x23 | LC_REQ_DYLD) => :LC_LOAD_UPWARD_DYLIB,
+ 0x24 => :LC_VERSION_MIN_MACOSX,
+ 0x25 => :LC_VERSION_MIN_IPHONEOS,
+ 0x26 => :LC_FUNCTION_STARTS,
+ 0x27 => :LC_DYLD_ENVIRONMENT,
+ (0x28 | LC_REQ_DYLD) => :LC_MAIN,
+ 0x29 => :LC_DATA_IN_CODE,
+ 0x2a => :LC_SOURCE_VERSION,
+ 0x2b => :LC_DYLIB_CODE_SIGN_DRS,
+ 0x2c => :LC_ENCRYPTION_INFO_64,
+ 0x2d => :LC_LINKER_OPTION,
+ 0x2e => :LC_LINKER_OPTIMIZATION_HINT,
+ 0x2f => :LC_VERSION_MIN_TVOS,
+ 0x30 => :LC_VERSION_MIN_WATCHOS,
+ }.freeze
+
+ # association of symbol representations to load command constants
+ # @api private
+ LOAD_COMMAND_CONSTANTS = LOAD_COMMANDS.invert.freeze
+
+ # load commands responsible for loading dylibs
+ # @api private
+ DYLIB_LOAD_COMMANDS = [
+ :LC_LOAD_DYLIB,
+ :LC_LOAD_WEAK_DYLIB,
+ :LC_REEXPORT_DYLIB,
+ :LC_LAZY_LOAD_DYLIB,
+ :LC_LOAD_UPWARD_DYLIB,
+ ].freeze
+
+ # load commands that can be created manually via {LoadCommand.create}
+ # @api private
+ CREATABLE_LOAD_COMMANDS = DYLIB_LOAD_COMMANDS + [
+ :LC_ID_DYLIB,
+ :LC_RPATH,
+ :LC_LOAD_DYLINKER,
+ ].freeze
+
+ # association of load command symbols to string representations of classes
+ # @api private
+ LC_STRUCTURES = {
+ :LC_SEGMENT => "SegmentCommand",
+ :LC_SYMTAB => "SymtabCommand",
+ # "obsolete"
+ :LC_SYMSEG => "SymsegCommand",
+ # seems obsolete, but not documented as such
+ :LC_THREAD => "ThreadCommand",
+ :LC_UNIXTHREAD => "ThreadCommand",
+ # "obsolete"
+ :LC_LOADFVMLIB => "FvmlibCommand",
+ # "obsolete"
+ :LC_IDFVMLIB => "FvmlibCommand",
+ # "obsolete"
+ :LC_IDENT => "IdentCommand",
+ # "reserved for internal use only"
+ :LC_FVMFILE => "FvmfileCommand",
+ # "reserved for internal use only", no public struct
+ :LC_PREPAGE => "LoadCommand",
+ :LC_DYSYMTAB => "DysymtabCommand",
+ :LC_LOAD_DYLIB => "DylibCommand",
+ :LC_ID_DYLIB => "DylibCommand",
+ :LC_LOAD_DYLINKER => "DylinkerCommand",
+ :LC_ID_DYLINKER => "DylinkerCommand",
+ :LC_PREBOUND_DYLIB => "PreboundDylibCommand",
+ :LC_ROUTINES => "RoutinesCommand",
+ :LC_SUB_FRAMEWORK => "SubFrameworkCommand",
+ :LC_SUB_UMBRELLA => "SubUmbrellaCommand",
+ :LC_SUB_CLIENT => "SubClientCommand",
+ :LC_SUB_LIBRARY => "SubLibraryCommand",
+ :LC_TWOLEVEL_HINTS => "TwolevelHintsCommand",
+ :LC_PREBIND_CKSUM => "PrebindCksumCommand",
+ :LC_LOAD_WEAK_DYLIB => "DylibCommand",
+ :LC_SEGMENT_64 => "SegmentCommand64",
+ :LC_ROUTINES_64 => "RoutinesCommand64",
+ :LC_UUID => "UUIDCommand",
+ :LC_RPATH => "RpathCommand",
+ :LC_CODE_SIGNATURE => "LinkeditDataCommand",
+ :LC_SEGMENT_SPLIT_INFO => "LinkeditDataCommand",
+ :LC_REEXPORT_DYLIB => "DylibCommand",
+ :LC_LAZY_LOAD_DYLIB => "DylibCommand",
+ :LC_ENCRYPTION_INFO => "EncryptionInfoCommand",
+ :LC_DYLD_INFO => "DyldInfoCommand",
+ :LC_DYLD_INFO_ONLY => "DyldInfoCommand",
+ :LC_LOAD_UPWARD_DYLIB => "DylibCommand",
+ :LC_VERSION_MIN_MACOSX => "VersionMinCommand",
+ :LC_VERSION_MIN_IPHONEOS => "VersionMinCommand",
+ :LC_FUNCTION_STARTS => "LinkeditDataCommand",
+ :LC_DYLD_ENVIRONMENT => "DylinkerCommand",
+ :LC_MAIN => "EntryPointCommand",
+ :LC_DATA_IN_CODE => "LinkeditDataCommand",
+ :LC_SOURCE_VERSION => "SourceVersionCommand",
+ :LC_DYLIB_CODE_SIGN_DRS => "LinkeditDataCommand",
+ :LC_ENCRYPTION_INFO_64 => "EncryptionInfoCommand64",
+ :LC_LINKER_OPTION => "LinkerOptionCommand",
+ :LC_LINKER_OPTIMIZATION_HINT => "LinkeditDataCommand",
+ :LC_VERSION_MIN_TVOS => "VersionMinCommand",
+ :LC_VERSION_MIN_WATCHOS => "VersionMinCommand",
+ }.freeze
+
+ # association of segment name symbols to names
+ # @api private
+ SEGMENT_NAMES = {
+ :SEG_PAGEZERO => "__PAGEZERO",
+ :SEG_TEXT => "__TEXT",
+ :SEG_DATA => "__DATA",
+ :SEG_OBJC => "__OBJC",
+ :SEG_ICON => "__ICON",
+ :SEG_LINKEDIT => "__LINKEDIT",
+ :SEG_UNIXSTACK => "__UNIXSTACK",
+ :SEG_IMPORT => "__IMPORT",
+ }.freeze
+
+ # association of segment flag symbols to values
+ # @api private
+ SEGMENT_FLAGS = {
+ :SG_HIGHVM => 0x1,
+ :SG_FVMLIB => 0x2,
+ :SG_NORELOC => 0x4,
+ :SG_PROTECTED_VERSION_1 => 0x8,
+ }.freeze
+
+ # Mach-O load command structure
+ # This is the most generic load command - only cmd ID and size are
+ # represented, and no actual data. Used when a more specific class
+ # isn't available/implemented.
+ class LoadCommand < MachOStructure
+ # @return [MachO::MachOView] the raw view associated with the load command
+ attr_reader :view
+
+ # @return [Fixnum] the load command's identifying number
+ attr_reader :cmd
+
+ # @return [Fixnum] the size of the load command, in bytes
+ attr_reader :cmdsize
+
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 8
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 8
- # Instantiates a new LoadCommand given a view into its origin Mach-O
- # @param view [MachO::MachOView] the load command's raw view
- # @return [MachO::LoadCommand] the new load command
- # @api private
- def self.new_from_bin(view)
- bin = view.raw_data.slice(view.offset, bytesize)
- format = Utils.specialize_format(self::FORMAT, view.endianness)
+ # Instantiates a new LoadCommand given a view into its origin Mach-O
+ # @param view [MachO::MachOView] the load command's raw view
+ # @return [LoadCommand] the new load command
+ # @api private
+ def self.new_from_bin(view)
+ bin = view.raw_data.slice(view.offset, bytesize)
+ format = Utils.specialize_format(self::FORMAT, view.endianness)
- new(view, *bin.unpack(format))
- end
+ new(view, *bin.unpack(format))
+ end
- # Creates a new (viewless) command corresponding to the symbol provided
- # @param cmd_sym [Symbol] the symbol of the load command being created
- # @param args [Array] the arguments for the load command being created
- def self.create(cmd_sym, *args)
- raise LoadCommandNotCreatableError, cmd_sym unless CREATABLE_LOAD_COMMANDS.include?(cmd_sym)
+ # Creates a new (viewless) command corresponding to the symbol provided
+ # @param cmd_sym [Symbol] the symbol of the load command being created
+ # @param args [Array] the arguments for the load command being created
+ def self.create(cmd_sym, *args)
+ raise LoadCommandNotCreatableError, cmd_sym unless CREATABLE_LOAD_COMMANDS.include?(cmd_sym)
- klass = MachO.const_get LC_STRUCTURES[cmd_sym]
- cmd = LOAD_COMMAND_CONSTANTS[cmd_sym]
+ klass = LoadCommands.const_get LC_STRUCTURES[cmd_sym]
+ cmd = LOAD_COMMAND_CONSTANTS[cmd_sym]
- # cmd will be filled in, view and cmdsize will be left unpopulated
- klass_arity = klass.instance_method(:initialize).arity - 3
+ # cmd will be filled in, view and cmdsize will be left unpopulated
+ klass_arity = klass.instance_method(:initialize).arity - 3
- raise LoadCommandCreationArityError.new(cmd_sym, klass_arity, args.size) if klass_arity != args.size
+ raise LoadCommandCreationArityError.new(cmd_sym, klass_arity, args.size) if klass_arity != args.size
- klass.new(nil, cmd, nil, *args)
- end
+ klass.new(nil, cmd, nil, *args)
+ end
- # @param view [MachO::MachOView] the load command's raw view
- # @param cmd [Fixnum] the load command's identifying number
- # @param cmdsize [Fixnum] the size of the load command in bytes
- # @api private
- def initialize(view, cmd, cmdsize)
- @view = view
- @cmd = cmd
- @cmdsize = cmdsize
- end
+ # @param view [MachO::MachOView] the load command's raw view
+ # @param cmd [Fixnum] the load command's identifying number
+ # @param cmdsize [Fixnum] the size of the load command in bytes
+ # @api private
+ def initialize(view, cmd, cmdsize)
+ @view = view
+ @cmd = cmd
+ @cmdsize = cmdsize
+ end
- # @return [Boolean] true if the load command can be serialized, false otherwise
- def serializable?
- CREATABLE_LOAD_COMMANDS.include?(LOAD_COMMANDS[cmd])
- end
+ # @return [Boolean] whether the load command can be serialized
+ def serializable?
+ CREATABLE_LOAD_COMMANDS.include?(LOAD_COMMANDS[cmd])
+ end
- # @param context [MachO::LoadCommand::SerializationContext] the context
- # to serialize into
- # @return [String, nil] the serialized fields of the load command, or nil
- # if the load command can't be serialized
- # @api private
- def serialize(context)
- raise LoadCommandNotSerializableError, LOAD_COMMANDS[cmd] unless serializable?
- format = Utils.specialize_format(FORMAT, context.endianness)
- [cmd, SIZEOF].pack(format)
- end
+ # @param context [SerializationContext] the context
+ # to serialize into
+ # @return [String, nil] the serialized fields of the load command, or nil
+ # if the load command can't be serialized
+ # @api private
+ def serialize(context)
+ raise LoadCommandNotSerializableError, LOAD_COMMANDS[cmd] unless serializable?
+ format = Utils.specialize_format(FORMAT, context.endianness)
+ [cmd, SIZEOF].pack(format)
+ end
- # @return [Fixnum] the load command's offset in the source file
- # @deprecated use {#view} instead
- def offset
- view.offset
- end
+ # @return [Fixnum] the load command's offset in the source file
+ # @deprecated use {#view} instead
+ def offset
+ view.offset
+ end
- # @return [Symbol] a symbol representation of the load command's identifying number
- def type
- LOAD_COMMANDS[cmd]
- end
+ # @return [Symbol] a symbol representation of the load command's
+ # identifying number
+ def type
+ LOAD_COMMANDS[cmd]
+ end
- alias to_sym type
+ alias to_sym type
- # @return [String] a string representation of the load command's identifying number
- def to_s
- type.to_s
- end
+ # @return [String] a string representation of the load command's
+ # identifying number
+ def to_s
+ type.to_s
+ end
- # Represents a Load Command string. A rough analogue to the lc_str
- # struct used internally by OS X. This class allows ruby-macho to
- # pretend that strings stored in LCs are immediately available without
- # explicit operations on the raw Mach-O data.
- class LCStr
- # @param lc [MachO::LoadCommand] the load command
- # @param lc_str [Fixnum, String] the offset to the beginning of the string,
- # or the string itself if not being initialized with a view.
- # @raise [MachO::LCStrMalformedError] if the string is malformed
- # @todo devise a solution such that the `lc_str` parameter is not
- # interpreted differently depending on `lc.view`. The current behavior
- # is a hack to allow viewless load command creation.
- # @api private
- def initialize(lc, lc_str)
- view = lc.view
-
- if view
- lc_str_abs = view.offset + lc_str
- lc_end = view.offset + lc.cmdsize - 1
- raw_string = view.raw_data.slice(lc_str_abs..lc_end)
- @string, null_byte, _padding = raw_string.partition("\x00")
- raise LCStrMalformedError, lc if null_byte.empty?
- @string_offset = lc_str
- else
- @string = lc_str
- @string_offset = 0
+ # Represents a Load Command string. A rough analogue to the lc_str
+ # struct used internally by OS X. This class allows ruby-macho to
+ # pretend that strings stored in LCs are immediately available without
+ # explicit operations on the raw Mach-O data.
+ class LCStr
+ # @param lc [LoadCommand] the load command
+ # @param lc_str [Fixnum, String] the offset to the beginning of the
+ # string, or the string itself if not being initialized with a view.
+ # @raise [MachO::LCStrMalformedError] if the string is malformed
+ # @todo devise a solution such that the `lc_str` parameter is not
+ # interpreted differently depending on `lc.view`. The current behavior
+ # is a hack to allow viewless load command creation.
+ # @api private
+ def initialize(lc, lc_str)
+ view = lc.view
+
+ if view
+ lc_str_abs = view.offset + lc_str
+ lc_end = view.offset + lc.cmdsize - 1
+ raw_string = view.raw_data.slice(lc_str_abs..lc_end)
+ @string, null_byte, _padding = raw_string.partition("\x00")
+ raise LCStrMalformedError, lc if null_byte.empty?
+ @string_offset = lc_str
+ else
+ @string = lc_str
+ @string_offset = 0
+ end
end
- end
- # @return [String] a string representation of the LCStr
- def to_s
- @string
+ # @return [String] a string representation of the LCStr
+ def to_s
+ @string
+ end
+
+ # @return [Fixnum] the offset to the beginning of the string in the
+ # load command
+ def to_i
+ @string_offset
+ end
end
- # @return [Fixnum] the offset to the beginning of the string in the load command
- def to_i
- @string_offset
+ # Represents the contextual information needed by a load command to
+ # serialize itself correctly into a binary string.
+ class SerializationContext
+ # @return [Symbol] the endianness of the serialized load command
+ attr_reader :endianness
+
+ # @return [Fixnum] the constant alignment value used to pad the
+ # serialized load command
+ attr_reader :alignment
+
+ # @param macho [MachO::MachOFile] the file to contextualize
+ # @return [SerializationContext] the
+ # resulting context
+ def self.context_for(macho)
+ new(macho.endianness, macho.alignment)
+ end
+
+ # @param endianness [Symbol] the endianness of the context
+ # @param alignment [Fixnum] the alignment of the context
+ # @api private
+ def initialize(endianness, alignment)
+ @endianness = endianness
+ @alignment = alignment
+ end
end
end
- # Represents the contextual information needed by a load command to
- # serialize itself correctly into a binary string.
- class SerializationContext
- # @return [Symbol] the endianness of the serialized load command
- attr_reader :endianness
+ # A load command containing a single 128-bit unique random number
+ # identifying an object produced by static link editor. Corresponds to
+ # LC_UUID.
+ class UUIDCommand < LoadCommand
+ # @return [Array<Fixnum>] the UUID
+ attr_reader :uuid
- # @return [Fixnum] the constant alignment value used to pad the serialized load command
- attr_reader :alignment
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2a16".freeze
- # @param macho [MachO::MachOFile] the file to contextualize
- # @return [MachO::LoadCommand::SerializationContext] the resulting context
- def self.context_for(macho)
- new(macho.endianness, macho.alignment)
- end
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 24
- # @param endianness [Symbol] the endianness of the context
- # @param alignment [Fixnum] the alignment of the context
# @api private
- def initialize(endianness, alignment)
- @endianness = endianness
- @alignment = alignment
+ def initialize(view, cmd, cmdsize, uuid)
+ super(view, cmd, cmdsize)
+ @uuid = uuid.unpack("C16") # re-unpack for the actual UUID array
end
- end
- end
-
- # A load command containing a single 128-bit unique random number identifying
- # an object produced by static link editor. Corresponds to LC_UUID.
- class UUIDCommand < LoadCommand
- # @return [Array<Fixnum>] the UUID
- attr_reader :uuid
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2a16".freeze
-
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 24
+ # @return [String] a string representation of the UUID
+ def uuid_string
+ hexes = uuid.map { |e| "%02x" % e }
+ segs = [
+ hexes[0..3].join, hexes[4..5].join, hexes[6..7].join,
+ hexes[8..9].join, hexes[10..15].join
+ ]
- # @api private
- def initialize(view, cmd, cmdsize, uuid)
- super(view, cmd, cmdsize)
- @uuid = uuid.unpack("C16") # re-unpack for the actual UUID array
+ segs.join("-")
+ end
end
- # @return [String] a string representation of the UUID
- def uuid_string
- hexes = uuid.map { |e| "%02x" % e }
- segs = [
- hexes[0..3].join, hexes[4..5].join, hexes[6..7].join,
- hexes[8..9].join, hexes[10..15].join
- ]
+ # A load command indicating that part of this file is to be mapped into
+ # the task's address space. Corresponds to LC_SEGMENT.
+ class SegmentCommand < LoadCommand
+ # @return [String] the name of the segment
+ attr_reader :segname
- segs.join("-")
- end
- end
+ # @return [Fixnum] the memory address of the segment
+ attr_reader :vmaddr
- # A load command indicating that part of this file is to be mapped into
- # the task's address space. Corresponds to LC_SEGMENT.
- class SegmentCommand < LoadCommand
- # @return [String] the name of the segment
- attr_reader :segname
+ # @return [Fixnum] the memory size of the segment
+ attr_reader :vmsize
- # @return [Fixnum] the memory address of the segment
- attr_reader :vmaddr
+ # @return [Fixnum] the file offset of the segment
+ attr_reader :fileoff
- # @return [Fixnum] the memory size of the segment
- attr_reader :vmsize
+ # @return [Fixnum] the amount to map from the file
+ attr_reader :filesize
- # @return [Fixnum] the file offset of the segment
- attr_reader :fileoff
+ # @return [Fixnum] the maximum VM protection
+ attr_reader :maxprot
- # @return [Fixnum] the amount to map from the file
- attr_reader :filesize
+ # @return [Fixnum] the initial VM protection
+ attr_reader :initprot
- # @return [Fixnum] the maximum VM protection
- attr_reader :maxprot
+ # @return [Fixnum] the number of sections in the segment
+ attr_reader :nsects
- # @return [Fixnum] the initial VM protection
- attr_reader :initprot
+ # @return [Fixnum] any flags associated with the segment
+ attr_reader :flags
- # @return [Fixnum] the number of sections in the segment
- attr_reader :nsects
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2a16L=4l=2L=2".freeze
- # @return [Fixnum] any flags associated with the segment
- attr_reader :flags
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 56
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2a16L=4l=2L=2".freeze
+ # @api private
+ def initialize(view, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
+ filesize, maxprot, initprot, nsects, flags)
+ super(view, cmd, cmdsize)
+ @segname = segname.delete("\x00")
+ @vmaddr = vmaddr
+ @vmsize = vmsize
+ @fileoff = fileoff
+ @filesize = filesize
+ @maxprot = maxprot
+ @initprot = initprot
+ @nsects = nsects
+ @flags = flags
+ end
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 56
+ # All sections referenced within this segment.
+ # @return [Array<MachO::Sections::Section>] if the Mach-O is 32-bit
+ # @return [Array<MachO::Sections::Section64>] if the Mach-O is 64-bit
+ def sections
+ klass = case self
+ when SegmentCommand64
+ MachO::Sections::Section64
+ when SegmentCommand
+ MachO::Sections::Section
+ end
- # @api private
- def initialize(view, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
- filesize, maxprot, initprot, nsects, flags)
- super(view, cmd, cmdsize)
- @segname = segname.delete("\x00")
- @vmaddr = vmaddr
- @vmsize = vmsize
- @fileoff = fileoff
- @filesize = filesize
- @maxprot = maxprot
- @initprot = initprot
- @nsects = nsects
- @flags = flags
- end
+ offset = view.offset + self.class.bytesize
+ length = nsects * klass.bytesize
- # All sections referenced within this segment.
- # @return [Array<MachO::Section>] if the Mach-O is 32-bit
- # @return [Array<MachO::Section64>] if the Mach-O is 64-bit
- def sections
- klass = case self
- when MachO::SegmentCommand64
- MachO::Section64
- when MachO::SegmentCommand
- MachO::Section
+ bins = view.raw_data[offset, length]
+ bins.unpack("a#{klass.bytesize}" * nsects).map do |bin|
+ klass.new_from_bin(view.endianness, bin)
+ end
end
- bins = view.raw_data[view.offset + self.class.bytesize, nsects * klass.bytesize]
- bins.unpack("a#{klass.bytesize}" * nsects).map do |bin|
- klass.new_from_bin(view.endianness, bin)
+ # @example
+ # puts "this segment relocated in/to it" if sect.flag?(:SG_NORELOC)
+ # @param flag [Symbol] a segment flag symbol
+ # @return [Boolean] true if `flag` is present in the segment's flag field
+ def flag?(flag)
+ flag = SEGMENT_FLAGS[flag]
+ return false if flag.nil?
+ flags & flag == flag
end
end
- # @example
- # puts "this segment relocated in/to it" if sect.flag?(:SG_NORELOC)
- # @param flag [Symbol] a segment flag symbol
- # @return [Boolean] true if `flag` is present in the segment's flag field
- def flag?(flag)
- flag = SEGMENT_FLAGS[flag]
- return false if flag.nil?
- flags & flag == flag
- end
- end
-
- # A load command indicating that part of this file is to be mapped into
- # the task's address space. Corresponds to LC_SEGMENT_64.
- class SegmentCommand64 < SegmentCommand
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2a16Q=4l=2L=2".freeze
+ # A load command indicating that part of this file is to be mapped into
+ # the task's address space. Corresponds to LC_SEGMENT_64.
+ class SegmentCommand64 < SegmentCommand
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2a16Q=4l=2L=2".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 72
- end
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 72
+ end
- # A load command representing some aspect of shared libraries, depending
- # on filetype. Corresponds to LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB,
- # and LC_REEXPORT_DYLIB.
- class DylibCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the library's path name as an LCStr
- attr_reader :name
+ # A load command representing some aspect of shared libraries, depending
+ # on filetype. Corresponds to LC_ID_DYLIB, LC_LOAD_DYLIB,
+ # LC_LOAD_WEAK_DYLIB, and LC_REEXPORT_DYLIB.
+ class DylibCommand < LoadCommand
+ # @return [LCStr] the library's path
+ # name as an LCStr
+ attr_reader :name
- # @return [Fixnum] the library's build time stamp
- attr_reader :timestamp
+ # @return [Fixnum] the library's build time stamp
+ attr_reader :timestamp
- # @return [Fixnum] the library's current version number
- attr_reader :current_version
+ # @return [Fixnum] the library's current version number
+ attr_reader :current_version
- # @return [Fixnum] the library's compatibility version number
- attr_reader :compatibility_version
+ # @return [Fixnum] the library's compatibility version number
+ attr_reader :compatibility_version
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=6".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=6".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 24
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 24
- # @api private
- def initialize(view, cmd, cmdsize, name, timestamp, current_version, compatibility_version)
- super(view, cmd, cmdsize)
- @name = LCStr.new(self, name)
- @timestamp = timestamp
- @current_version = current_version
- @compatibility_version = compatibility_version
- end
+ # @api private
+ def initialize(view, cmd, cmdsize, name, timestamp, current_version,
+ compatibility_version)
+ super(view, cmd, cmdsize)
+ @name = LCStr.new(self, name)
+ @timestamp = timestamp
+ @current_version = current_version
+ @compatibility_version = compatibility_version
+ end
- # @param context [MachO::LoadCcommand::SerializationContext] the context
- # @return [String] the serialized fields of the load command
- # @api private
- def serialize(context)
- format = Utils.specialize_format(FORMAT, context.endianness)
- string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :name => name.to_s)
- cmdsize = SIZEOF + string_payload.bytesize
- [cmd, cmdsize, string_offsets[:name], timestamp, current_version,
- compatibility_version].pack(format) + string_payload
+ # @param context [SerializationContext]
+ # the context
+ # @return [String] the serialized fields of the load command
+ # @api private
+ def serialize(context)
+ format = Utils.specialize_format(FORMAT, context.endianness)
+ string_payload, string_offsets = Utils.pack_strings(SIZEOF,
+ context.alignment,
+ :name => name.to_s)
+ cmdsize = SIZEOF + string_payload.bytesize
+ [cmd, cmdsize, string_offsets[:name], timestamp, current_version,
+ compatibility_version].pack(format) + string_payload
+ end
end
- end
- # A load command representing some aspect of the dynamic linker, depending
- # on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and
- # LC_DYLD_ENVIRONMENT.
- class DylinkerCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the dynamic linker's path name as an LCStr
- attr_reader :name
+ # A load command representing some aspect of the dynamic linker, depending
+ # on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and
+ # LC_DYLD_ENVIRONMENT.
+ class DylinkerCommand < LoadCommand
+ # @return [LCStr] the dynamic linker's
+ # path name as an LCStr
+ attr_reader :name
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=3".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=3".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 12
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 12
- # @api private
- def initialize(view, cmd, cmdsize, name)
- super(view, cmd, cmdsize)
- @name = LCStr.new(self, name)
- end
+ # @api private
+ def initialize(view, cmd, cmdsize, name)
+ super(view, cmd, cmdsize)
+ @name = LCStr.new(self, name)
+ end
- # @param context [MachO::LoadCcommand::SerializationContext] the context
- # @return [String] the serialized fields of the load command
- # @api private
- def serialize(context)
- format = Utils.specialize_format(FORMAT, context.endianness)
- string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :name => name.to_s)
- cmdsize = SIZEOF + string_payload.bytesize
- [cmd, cmdsize, string_offsets[:name]].pack(format) + string_payload
+ # @param context [SerializationContext]
+ # the context
+ # @return [String] the serialized fields of the load command
+ # @api private
+ def serialize(context)
+ format = Utils.specialize_format(FORMAT, context.endianness)
+ string_payload, string_offsets = Utils.pack_strings(SIZEOF,
+ context.alignment,
+ :name => name.to_s)
+ cmdsize = SIZEOF + string_payload.bytesize
+ [cmd, cmdsize, string_offsets[:name]].pack(format) + string_payload
+ end
end
- end
- # A load command used to indicate dynamic libraries used in prebinding.
- # Corresponds to LC_PREBOUND_DYLIB.
- class PreboundDylibCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the library's path name as an LCStr
- attr_reader :name
+ # A load command used to indicate dynamic libraries used in prebinding.
+ # Corresponds to LC_PREBOUND_DYLIB.
+ class PreboundDylibCommand < LoadCommand
+ # @return [LCStr] the library's path
+ # name as an LCStr
+ attr_reader :name
- # @return [Fixnum] the number of modules in the library
- attr_reader :nmodules
+ # @return [Fixnum] the number of modules in the library
+ attr_reader :nmodules
- # @return [Fixnum] a bit vector of linked modules
- attr_reader :linked_modules
+ # @return [Fixnum] a bit vector of linked modules
+ attr_reader :linked_modules
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=5".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=5".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 20
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 20
- # @api private
- def initialize(view, cmd, cmdsize, name, nmodules, linked_modules)
- super(view, cmd, cmdsize)
- @name = LCStr.new(self, name)
- @nmodules = nmodules
- @linked_modules = linked_modules
+ # @api private
+ def initialize(view, cmd, cmdsize, name, nmodules, linked_modules)
+ super(view, cmd, cmdsize)
+ @name = LCStr.new(self, name)
+ @nmodules = nmodules
+ @linked_modules = linked_modules
+ end
end
- end
- # A load command used to represent threads.
- # @note cctools-870 has all fields of thread_command commented out except common ones (cmd, cmdsize)
- class ThreadCommand < LoadCommand
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2".freeze
+ # A load command used to represent threads.
+ # @note cctools-870 and onwards have all fields of thread_command commented
+ # out except the common ones (cmd, cmdsize)
+ class ThreadCommand < LoadCommand
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 8
- end
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 8
+ end
- # A load command containing the address of the dynamic shared library
- # initialization routine and an index into the module table for the module
- # that defines the routine. Corresponds to LC_ROUTINES.
- class RoutinesCommand < LoadCommand
- # @return [Fixnum] the address of the initialization routine
- attr_reader :init_address
+ # A load command containing the address of the dynamic shared library
+ # initialization routine and an index into the module table for the module
+ # that defines the routine. Corresponds to LC_ROUTINES.
+ class RoutinesCommand < LoadCommand
+ # @return [Fixnum] the address of the initialization routine
+ attr_reader :init_address
- # @return [Fixnum] the index into the module table that the init routine is defined in
- attr_reader :init_module
+ # @return [Fixnum] the index into the module table that the init routine
+ # is defined in
+ attr_reader :init_module
- # @return [void]
- attr_reader :reserved1
+ # @return [void]
+ attr_reader :reserved1
- # @return [void]
- attr_reader :reserved2
+ # @return [void]
+ attr_reader :reserved2
- # @return [void]
- attr_reader :reserved3
+ # @return [void]
+ attr_reader :reserved3
- # @return [void]
- attr_reader :reserved4
+ # @return [void]
+ attr_reader :reserved4
- # @return [void]
- attr_reader :reserved5
+ # @return [void]
+ attr_reader :reserved5
- # @return [void]
- attr_reader :reserved6
+ # @return [void]
+ attr_reader :reserved6
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=10".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=10".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 40
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 40
- # @api private
- def initialize(view, cmd, cmdsize, init_address, init_module, reserved1,
- reserved2, reserved3, reserved4, reserved5, reserved6)
- super(view, cmd, cmdsize)
- @init_address = init_address
- @init_module = init_module
- @reserved1 = reserved1
- @reserved2 = reserved2
- @reserved3 = reserved3
- @reserved4 = reserved4
- @reserved5 = reserved5
- @reserved6 = reserved6
+ # @api private
+ def initialize(view, cmd, cmdsize, init_address, init_module, reserved1,
+ reserved2, reserved3, reserved4, reserved5, reserved6)
+ super(view, cmd, cmdsize)
+ @init_address = init_address
+ @init_module = init_module
+ @reserved1 = reserved1
+ @reserved2 = reserved2
+ @reserved3 = reserved3
+ @reserved4 = reserved4
+ @reserved5 = reserved5
+ @reserved6 = reserved6
+ end
end
- end
- # A load command containing the address of the dynamic shared library
- # initialization routine and an index into the module table for the module
- # that defines the routine. Corresponds to LC_ROUTINES_64.
- class RoutinesCommand64 < RoutinesCommand
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2Q=8".freeze
+ # A load command containing the address of the dynamic shared library
+ # initialization routine and an index into the module table for the module
+ # that defines the routine. Corresponds to LC_ROUTINES_64.
+ class RoutinesCommand64 < RoutinesCommand
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2Q=8".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 72
- end
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 72
+ end
- # A load command signifying membership of a subframework containing the name
- # of an umbrella framework. Corresponds to LC_SUB_FRAMEWORK.
- class SubFrameworkCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the umbrella framework name as an LCStr
- attr_reader :umbrella
+ # A load command signifying membership of a subframework containing the name
+ # of an umbrella framework. Corresponds to LC_SUB_FRAMEWORK.
+ class SubFrameworkCommand < LoadCommand
+ # @return [LCStr] the umbrella framework name as an LCStr
+ attr_reader :umbrella
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=3".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=3".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 12
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 12
- # @api private
- def initialize(view, cmd, cmdsize, umbrella)
- super(view, cmd, cmdsize)
- @umbrella = LCStr.new(self, umbrella)
+ # @api private
+ def initialize(view, cmd, cmdsize, umbrella)
+ super(view, cmd, cmdsize)
+ @umbrella = LCStr.new(self, umbrella)
+ end
end
- end
- # A load command signifying membership of a subumbrella containing the name
- # of an umbrella framework. Corresponds to LC_SUB_UMBRELLA.
- class SubUmbrellaCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the subumbrella framework name as an LCStr
- attr_reader :sub_umbrella
+ # A load command signifying membership of a subumbrella containing the name
+ # of an umbrella framework. Corresponds to LC_SUB_UMBRELLA.
+ class SubUmbrellaCommand < LoadCommand
+ # @return [LCStr] the subumbrella framework name as an LCStr
+ attr_reader :sub_umbrella
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=3".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=3".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 12
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 12
- # @api private
- def initialize(view, cmd, cmdsize, sub_umbrella)
- super(view, cmd, cmdsize)
- @sub_umbrella = LCStr.new(self, sub_umbrella)
+ # @api private
+ def initialize(view, cmd, cmdsize, sub_umbrella)
+ super(view, cmd, cmdsize)
+ @sub_umbrella = LCStr.new(self, sub_umbrella)
+ end
end
- end
- # A load command signifying a sublibrary of a shared library. Corresponds
- # to LC_SUB_LIBRARY.
- class SubLibraryCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the sublibrary name as an LCStr
- attr_reader :sub_library
+ # A load command signifying a sublibrary of a shared library. Corresponds
+ # to LC_SUB_LIBRARY.
+ class SubLibraryCommand < LoadCommand
+ # @return [LCStr] the sublibrary name as an LCStr
+ attr_reader :sub_library
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=3".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=3".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 12
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 12
- # @api private
- def initialize(view, cmd, cmdsize, sub_library)
- super(view, cmd, cmdsize)
- @sub_library = LCStr.new(self, sub_library)
+ # @api private
+ def initialize(view, cmd, cmdsize, sub_library)
+ super(view, cmd, cmdsize)
+ @sub_library = LCStr.new(self, sub_library)
+ end
end
- end
- # A load command signifying a shared library that is a subframework of
- # an umbrella framework. Corresponds to LC_SUB_CLIENT.
- class SubClientCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the subclient name as an LCStr
- attr_reader :sub_client
+ # A load command signifying a shared library that is a subframework of
+ # an umbrella framework. Corresponds to LC_SUB_CLIENT.
+ class SubClientCommand < LoadCommand
+ # @return [LCStr] the subclient name as an LCStr
+ attr_reader :sub_client
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=3".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=3".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 12
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 12
- # @api private
- def initialize(view, cmd, cmdsize, sub_client)
- super(view, cmd, cmdsize)
- @sub_client = LCStr.new(self, sub_client)
+ # @api private
+ def initialize(view, cmd, cmdsize, sub_client)
+ super(view, cmd, cmdsize)
+ @sub_client = LCStr.new(self, sub_client)
+ end
end
- end
- # A load command containing the offsets and sizes of the link-edit 4.3BSD
- # "stab" style symbol table information. Corresponds to LC_SYMTAB.
- class SymtabCommand < LoadCommand
- # @return [Fixnum] the symbol table's offset
- attr_reader :symoff
+ # A load command containing the offsets and sizes of the link-edit 4.3BSD
+ # "stab" style symbol table information. Corresponds to LC_SYMTAB.
+ class SymtabCommand < LoadCommand
+ # @return [Fixnum] the symbol table's offset
+ attr_reader :symoff
- # @return [Fixnum] the number of symbol table entries
- attr_reader :nsyms
+ # @return [Fixnum] the number of symbol table entries
+ attr_reader :nsyms
- # @return the string table's offset
- attr_reader :stroff
+ # @return the string table's offset
+ attr_reader :stroff
- # @return the string table size in bytes
- attr_reader :strsize
+ # @return the string table size in bytes
+ attr_reader :strsize
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=6".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=6".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 24
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 24
- # @api private
- def initialize(view, cmd, cmdsize, symoff, nsyms, stroff, strsize)
- super(view, cmd, cmdsize)
- @symoff = symoff
- @nsyms = nsyms
- @stroff = stroff
- @strsize = strsize
+ # @api private
+ def initialize(view, cmd, cmdsize, symoff, nsyms, stroff, strsize)
+ super(view, cmd, cmdsize)
+ @symoff = symoff
+ @nsyms = nsyms
+ @stroff = stroff
+ @strsize = strsize
+ end
end
- end
- # A load command containing symbolic information needed to support data
- # structures used by the dynamic link editor. Corresponds to LC_DYSYMTAB.
- class DysymtabCommand < LoadCommand
- # @return [Fixnum] the index to local symbols
- attr_reader :ilocalsym
+ # A load command containing symbolic information needed to support data
+ # structures used by the dynamic link editor. Corresponds to LC_DYSYMTAB.
+ class DysymtabCommand < LoadCommand
+ # @return [Fixnum] the index to local symbols
+ attr_reader :ilocalsym
- # @return [Fixnum] the number of local symbols
- attr_reader :nlocalsym
+ # @return [Fixnum] the number of local symbols
+ attr_reader :nlocalsym
- # @return [Fixnum] the index to externally defined symbols
- attr_reader :iextdefsym
+ # @return [Fixnum] the index to externally defined symbols
+ attr_reader :iextdefsym
- # @return [Fixnum] the number of externally defined symbols
- attr_reader :nextdefsym
+ # @return [Fixnum] the number of externally defined symbols
+ attr_reader :nextdefsym
- # @return [Fixnum] the index to undefined symbols
- attr_reader :iundefsym
+ # @return [Fixnum] the index to undefined symbols
+ attr_reader :iundefsym
- # @return [Fixnum] the number of undefined symbols
- attr_reader :nundefsym
+ # @return [Fixnum] the number of undefined symbols
+ attr_reader :nundefsym
- # @return [Fixnum] the file offset to the table of contents
- attr_reader :tocoff
+ # @return [Fixnum] the file offset to the table of contents
+ attr_reader :tocoff
- # @return [Fixnum] the number of entries in the table of contents
- attr_reader :ntoc
+ # @return [Fixnum] the number of entries in the table of contents
+ attr_reader :ntoc
- # @return [Fixnum] the file offset to the module table
- attr_reader :modtaboff
+ # @return [Fixnum] the file offset to the module table
+ attr_reader :modtaboff
- # @return [Fixnum] the number of entries in the module table
- attr_reader :nmodtab
+ # @return [Fixnum] the number of entries in the module table
+ attr_reader :nmodtab
- # @return [Fixnum] the file offset to the referenced symbol table
- attr_reader :extrefsymoff
+ # @return [Fixnum] the file offset to the referenced symbol table
+ attr_reader :extrefsymoff
- # @return [Fixnum] the number of entries in the referenced symbol table
- attr_reader :nextrefsyms
+ # @return [Fixnum] the number of entries in the referenced symbol table
+ attr_reader :nextrefsyms
- # @return [Fixnum] the file offset to the indirect symbol table
- attr_reader :indirectsymoff
+ # @return [Fixnum] the file offset to the indirect symbol table
+ attr_reader :indirectsymoff
- # @return [Fixnum] the number of entries in the indirect symbol table
- attr_reader :nindirectsyms
+ # @return [Fixnum] the number of entries in the indirect symbol table
+ attr_reader :nindirectsyms
- # @return [Fixnum] the file offset to the external relocation entries
- attr_reader :extreloff
+ # @return [Fixnum] the file offset to the external relocation entries
+ attr_reader :extreloff
- # @return [Fixnum] the number of external relocation entries
- attr_reader :nextrel
+ # @return [Fixnum] the number of external relocation entries
+ attr_reader :nextrel
- # @return [Fixnum] the file offset to the local relocation entries
- attr_reader :locreloff
+ # @return [Fixnum] the file offset to the local relocation entries
+ attr_reader :locreloff
- # @return [Fixnum] the number of local relocation entries
- attr_reader :nlocrel
+ # @return [Fixnum] the number of local relocation entries
+ attr_reader :nlocrel
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=20".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=20".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 80
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 80
- # ugh
- # @api private
- def initialize(view, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym,
- nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff,
- nmodtab, extrefsymoff, nextrefsyms, indirectsymoff,
- nindirectsyms, extreloff, nextrel, locreloff, nlocrel)
- super(view, cmd, cmdsize)
- @ilocalsym = ilocalsym
- @nlocalsym = nlocalsym
- @iextdefsym = iextdefsym
- @nextdefsym = nextdefsym
- @iundefsym = iundefsym
- @nundefsym = nundefsym
- @tocoff = tocoff
- @ntoc = ntoc
- @modtaboff = modtaboff
- @nmodtab = nmodtab
- @extrefsymoff = extrefsymoff
- @nextrefsyms = nextrefsyms
- @indirectsymoff = indirectsymoff
- @nindirectsyms = nindirectsyms
- @extreloff = extreloff
- @nextrel = nextrel
- @locreloff = locreloff
- @nlocrel = nlocrel
+ # ugh
+ # @api private
+ def initialize(view, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym,
+ nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff,
+ nmodtab, extrefsymoff, nextrefsyms, indirectsymoff,
+ nindirectsyms, extreloff, nextrel, locreloff, nlocrel)
+ super(view, cmd, cmdsize)
+ @ilocalsym = ilocalsym
+ @nlocalsym = nlocalsym
+ @iextdefsym = iextdefsym
+ @nextdefsym = nextdefsym
+ @iundefsym = iundefsym
+ @nundefsym = nundefsym
+ @tocoff = tocoff
+ @ntoc = ntoc
+ @modtaboff = modtaboff
+ @nmodtab = nmodtab
+ @extrefsymoff = extrefsymoff
+ @nextrefsyms = nextrefsyms
+ @indirectsymoff = indirectsymoff
+ @nindirectsyms = nindirectsyms
+ @extreloff = extreloff
+ @nextrel = nextrel
+ @locreloff = locreloff
+ @nlocrel = nlocrel
+ end
end
- end
- # A load command containing the offset and number of hints in the two-level
- # namespace lookup hints table. Corresponds to LC_TWOLEVEL_HINTS.
- class TwolevelHintsCommand < LoadCommand
- # @return [Fixnum] the offset to the hint table
- attr_reader :htoffset
+ # A load command containing the offset and number of hints in the two-level
+ # namespace lookup hints table. Corresponds to LC_TWOLEVEL_HINTS.
+ class TwolevelHintsCommand < LoadCommand
+ # @return [Fixnum] the offset to the hint table
+ attr_reader :htoffset
- # @return [Fixnum] the number of hints in the hint table
- attr_reader :nhints
+ # @return [Fixnum] the number of hints in the hint table
+ attr_reader :nhints
- # @return [MachO::TwolevelHintsCommand::TwolevelHintTable] the hint table
- attr_reader :table
+ # @return [TwolevelHintsTable]
+ # the hint table
+ attr_reader :table
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=4".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=4".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 16
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 16
- # @api private
- def initialize(view, cmd, cmdsize, htoffset, nhints)
- super(view, cmd, cmdsize)
- @htoffset = htoffset
- @nhints = nhints
- @table = TwolevelHintsTable.new(view, htoffset, nhints)
- end
+ # @api private
+ def initialize(view, cmd, cmdsize, htoffset, nhints)
+ super(view, cmd, cmdsize)
+ @htoffset = htoffset
+ @nhints = nhints
+ @table = TwolevelHintsTable.new(view, htoffset, nhints)
+ end
- # A representation of the two-level namespace lookup hints table exposed
- # by a {TwolevelHintsCommand} (`LC_TWOLEVEL_HINTS`).
- class TwolevelHintsTable
- # @return [Array<MachO::TwoLevelHintsTable::TwoLevelHint>] all hints in the table
- attr_reader :hints
+ # A representation of the two-level namespace lookup hints table exposed
+ # by a {TwolevelHintsCommand} (`LC_TWOLEVEL_HINTS`).
+ class TwolevelHintsTable
+ # @return [Array<TwolevelHint>] all hints in the table
+ attr_reader :hints
- # @param view [MachO::MachOView] the view into the current Mach-O
- # @param htoffset [Fixnum] the offset of the hints table
- # @param nhints [Fixnum] the number of two-level hints in the table
- # @api private
- def initialize(view, htoffset, nhints)
- format = Utils.specialize_format("L=#{nhints}", view.endianness)
- raw_table = view.raw_data[htoffset, nhints * 4]
- blobs = raw_table.unpack(format)
+ # @param view [MachO::MachOView] the view into the current Mach-O
+ # @param htoffset [Fixnum] the offset of the hints table
+ # @param nhints [Fixnum] the number of two-level hints in the table
+ # @api private
+ def initialize(view, htoffset, nhints)
+ format = Utils.specialize_format("L=#{nhints}", view.endianness)
+ raw_table = view.raw_data[htoffset, nhints * 4]
+ blobs = raw_table.unpack(format)
- @hints = blobs.map { |b| TwolevelHint.new(b) }
- end
+ @hints = blobs.map { |b| TwolevelHint.new(b) }
+ end
- # An individual two-level namespace lookup hint.
- class TwolevelHint
- # @return [Fixnum] the index into the sub-images
- attr_reader :isub_image
+ # An individual two-level namespace lookup hint.
+ class TwolevelHint
+ # @return [Fixnum] the index into the sub-images
+ attr_reader :isub_image
- # @return [Fixnum] the index into the table of contents
- attr_reader :itoc
+ # @return [Fixnum] the index into the table of contents
+ attr_reader :itoc
- # @param blob [Fixnum] the 32-bit number containing the lookup hint
- # @api private
- def initialize(blob)
- @isub_image = blob >> 24
- @itoc = blob & 0x00FFFFFF
+ # @param blob [Fixnum] the 32-bit number containing the lookup hint
+ # @api private
+ def initialize(blob)
+ @isub_image = blob >> 24
+ @itoc = blob & 0x00FFFFFF
+ end
end
end
end
- end
- # A load command containing the value of the original checksum for prebound
- # files, or zero. Corresponds to LC_PREBIND_CKSUM.
- class PrebindCksumCommand < LoadCommand
- # @return [Fixnum] the checksum or 0
- attr_reader :cksum
+ # A load command containing the value of the original checksum for prebound
+ # files, or zero. Corresponds to LC_PREBIND_CKSUM.
+ class PrebindCksumCommand < LoadCommand
+ # @return [Fixnum] the checksum or 0
+ attr_reader :cksum
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=3".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=3".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 12
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 12
- # @api private
- def initialize(view, cmd, cmdsize, cksum)
- super(view, cmd, cmdsize)
- @cksum = cksum
+ # @api private
+ def initialize(view, cmd, cmdsize, cksum)
+ super(view, cmd, cmdsize)
+ @cksum = cksum
+ end
end
- end
- # A load command representing an rpath, which specifies a path that should
- # be added to the current run path used to find @rpath prefixed dylibs.
- # Corresponds to LC_RPATH.
- class RpathCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the path to add to the run path as an LCStr
- attr_reader :path
+ # A load command representing an rpath, which specifies a path that should
+ # be added to the current run path used to find @rpath prefixed dylibs.
+ # Corresponds to LC_RPATH.
+ class RpathCommand < LoadCommand
+ # @return [LCStr] the path to add to the run path as an LCStr
+ attr_reader :path
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=3".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=3".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 12
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 12
- # @api private
- def initialize(view, cmd, cmdsize, path)
- super(view, cmd, cmdsize)
- @path = LCStr.new(self, path)
- end
+ # @api private
+ def initialize(view, cmd, cmdsize, path)
+ super(view, cmd, cmdsize)
+ @path = LCStr.new(self, path)
+ end
- # @param context [MachO::LoadCcommand::SerializationContext] the context
- # @return [String] the serialized fields of the load command
- # @api private
- def serialize(context)
- format = Utils.specialize_format(FORMAT, context.endianness)
- string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :path => path.to_s)
- cmdsize = SIZEOF + string_payload.bytesize
- [cmd, cmdsize, string_offsets[:path]].pack(format) + string_payload
+ # @param context [SerializationContext] the context
+ # @return [String] the serialized fields of the load command
+ # @api private
+ def serialize(context)
+ format = Utils.specialize_format(FORMAT, context.endianness)
+ string_payload, string_offsets = Utils.pack_strings(SIZEOF,
+ context.alignment,
+ :path => path.to_s)
+ cmdsize = SIZEOF + string_payload.bytesize
+ [cmd, cmdsize, string_offsets[:path]].pack(format) + string_payload
+ end
end
- end
- # A load command representing the offsets and sizes of a blob of data in
- # the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO,
- # LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS, and LC_LINKER_OPTIMIZATION_HINT.
- class LinkeditDataCommand < LoadCommand
- # @return [Fixnum] offset to the data in the __LINKEDIT segment
- attr_reader :dataoff
+ # A load command representing the offsets and sizes of a blob of data in
+ # the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE,
+ # LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
+ # LC_DYLIB_CODE_SIGN_DRS, and LC_LINKER_OPTIMIZATION_HINT.
+ class LinkeditDataCommand < LoadCommand
+ # @return [Fixnum] offset to the data in the __LINKEDIT segment
+ attr_reader :dataoff
- # @return [Fixnum] size of the data in the __LINKEDIT segment
- attr_reader :datasize
+ # @return [Fixnum] size of the data in the __LINKEDIT segment
+ attr_reader :datasize
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=4".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=4".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 16
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 16
- # @api private
- def initialize(view, cmd, cmdsize, dataoff, datasize)
- super(view, cmd, cmdsize)
- @dataoff = dataoff
- @datasize = datasize
+ # @api private
+ def initialize(view, cmd, cmdsize, dataoff, datasize)
+ super(view, cmd, cmdsize)
+ @dataoff = dataoff
+ @datasize = datasize
+ end
end
- end
- # A load command representing the offset to and size of an encrypted
- # segment. Corresponds to LC_ENCRYPTION_INFO.
- class EncryptionInfoCommand < LoadCommand
- # @return [Fixnum] the offset to the encrypted segment
- attr_reader :cryptoff
+ # A load command representing the offset to and size of an encrypted
+ # segment. Corresponds to LC_ENCRYPTION_INFO.
+ class EncryptionInfoCommand < LoadCommand
+ # @return [Fixnum] the offset to the encrypted segment
+ attr_reader :cryptoff
- # @return [Fixnum] the size of the encrypted segment
- attr_reader :cryptsize
+ # @return [Fixnum] the size of the encrypted segment
+ attr_reader :cryptsize
- # @return [Fixnum] the encryption system, or 0 if not encrypted yet
- attr_reader :cryptid
+ # @return [Fixnum] the encryption system, or 0 if not encrypted yet
+ attr_reader :cryptid
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=5".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=5".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 20
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 20
- # @api private
- def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid)
- super(view, cmd, cmdsize)
- @cryptoff = cryptoff
- @cryptsize = cryptsize
- @cryptid = cryptid
+ # @api private
+ def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid)
+ super(view, cmd, cmdsize)
+ @cryptoff = cryptoff
+ @cryptsize = cryptsize
+ @cryptid = cryptid
+ end
end
- end
- # A load command representing the offset to and size of an encrypted
- # segment. Corresponds to LC_ENCRYPTION_INFO_64.
- class EncryptionInfoCommand64 < LoadCommand
- # @return [Fixnum] the offset to the encrypted segment
- attr_reader :cryptoff
+ # A load command representing the offset to and size of an encrypted
+ # segment. Corresponds to LC_ENCRYPTION_INFO_64.
+ class EncryptionInfoCommand64 < LoadCommand
+ # @return [Fixnum] the offset to the encrypted segment
+ attr_reader :cryptoff
- # @return [Fixnum] the size of the encrypted segment
- attr_reader :cryptsize
+ # @return [Fixnum] the size of the encrypted segment
+ attr_reader :cryptsize
- # @return [Fixnum] the encryption system, or 0 if not encrypted yet
- attr_reader :cryptid
+ # @return [Fixnum] the encryption system, or 0 if not encrypted yet
+ attr_reader :cryptid
- # @return [Fixnum] 64-bit padding value
- attr_reader :pad
+ # @return [Fixnum] 64-bit padding value
+ attr_reader :pad
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=6".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=6".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 24
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 24
- # @api private
- def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid, pad)
- super(view, cmd, cmdsize)
- @cryptoff = cryptoff
- @cryptsize = cryptsize
- @cryptid = cryptid
- @pad = pad
+ # @api private
+ def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid, pad)
+ super(view, cmd, cmdsize)
+ @cryptoff = cryptoff
+ @cryptsize = cryptsize
+ @cryptid = cryptid
+ @pad = pad
+ end
end
- end
- # A load command containing the minimum OS version on which the binary
- # was built to run. Corresponds to LC_VERSION_MIN_MACOSX and LC_VERSION_MIN_IPHONEOS.
- class VersionMinCommand < LoadCommand
- # @return [Fixnum] the version X.Y.Z packed as x16.y8.z8
- attr_reader :version
+ # A load command containing the minimum OS version on which the binary
+ # was built to run. Corresponds to LC_VERSION_MIN_MACOSX and
+ # LC_VERSION_MIN_IPHONEOS.
+ class VersionMinCommand < LoadCommand
+ # @return [Fixnum] the version X.Y.Z packed as x16.y8.z8
+ attr_reader :version
- # @return [Fixnum] the SDK version X.Y.Z packed as x16.y8.z8
- attr_reader :sdk
+ # @return [Fixnum] the SDK version X.Y.Z packed as x16.y8.z8
+ attr_reader :sdk
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=4".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=4".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 16
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 16
- # @api private
- def initialize(view, cmd, cmdsize, version, sdk)
- super(view, cmd, cmdsize)
- @version = version
- @sdk = sdk
- end
+ # @api private
+ def initialize(view, cmd, cmdsize, version, sdk)
+ super(view, cmd, cmdsize)
+ @version = version
+ @sdk = sdk
+ end
- # A string representation of the binary's minimum OS version.
- # @return [String] a string representing the minimum OS version.
- def version_string
- binary = "%032b" % version
- segs = [
- binary[0..15], binary[16..23], binary[24..31]
- ].map { |s| s.to_i(2) }
+ # A string representation of the binary's minimum OS version.
+ # @return [String] a string representing the minimum OS version.
+ def version_string
+ binary = "%032b" % version
+ segs = [
+ binary[0..15], binary[16..23], binary[24..31]
+ ].map { |s| s.to_i(2) }
- segs.join(".")
- end
+ segs.join(".")
+ end
- # A string representation of the binary's SDK version.
- # @return [String] a string representing the SDK version.
- def sdk_string
- binary = "%032b" % sdk
- segs = [
- binary[0..15], binary[16..23], binary[24..31]
- ].map { |s| s.to_i(2) }
+ # A string representation of the binary's SDK version.
+ # @return [String] a string representing the SDK version.
+ def sdk_string
+ binary = "%032b" % sdk
+ segs = [
+ binary[0..15], binary[16..23], binary[24..31]
+ ].map { |s| s.to_i(2) }
- segs.join(".")
+ segs.join(".")
+ end
end
- end
- # A load command containing the file offsets and sizes of the new
- # compressed form of the information dyld needs to load the image.
- # Corresponds to LC_DYLD_INFO and LC_DYLD_INFO_ONLY.
- class DyldInfoCommand < LoadCommand
- # @return [Fixnum] the file offset to the rebase information
- attr_reader :rebase_off
+ # A load command containing the file offsets and sizes of the new
+ # compressed form of the information dyld needs to load the image.
+ # Corresponds to LC_DYLD_INFO and LC_DYLD_INFO_ONLY.
+ class DyldInfoCommand < LoadCommand
+ # @return [Fixnum] the file offset to the rebase information
+ attr_reader :rebase_off
- # @return [Fixnum] the size of the rebase information
- attr_reader :rebase_size
+ # @return [Fixnum] the size of the rebase information
+ attr_reader :rebase_size
- # @return [Fixnum] the file offset to the binding information
- attr_reader :bind_off
+ # @return [Fixnum] the file offset to the binding information
+ attr_reader :bind_off
- # @return [Fixnum] the size of the binding information
- attr_reader :bind_size
+ # @return [Fixnum] the size of the binding information
+ attr_reader :bind_size
- # @return [Fixnum] the file offset to the weak binding information
- attr_reader :weak_bind_off
+ # @return [Fixnum] the file offset to the weak binding information
+ attr_reader :weak_bind_off
- # @return [Fixnum] the size of the weak binding information
- attr_reader :weak_bind_size
+ # @return [Fixnum] the size of the weak binding information
+ attr_reader :weak_bind_size
- # @return [Fixnum] the file offset to the lazy binding information
- attr_reader :lazy_bind_off
+ # @return [Fixnum] the file offset to the lazy binding information
+ attr_reader :lazy_bind_off
- # @return [Fixnum] the size of the lazy binding information
- attr_reader :lazy_bind_size
+ # @return [Fixnum] the size of the lazy binding information
+ attr_reader :lazy_bind_size
- # @return [Fixnum] the file offset to the export information
- attr_reader :export_off
+ # @return [Fixnum] the file offset to the export information
+ attr_reader :export_off
- # @return [Fixnum] the size of the export information
- attr_reader :export_size
+ # @return [Fixnum] the size of the export information
+ attr_reader :export_size
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=12".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=12".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 48
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 48
- # @api private
- def initialize(view, cmd, cmdsize, rebase_off, rebase_size, bind_off,
- bind_size, weak_bind_off, weak_bind_size, lazy_bind_off,
- lazy_bind_size, export_off, export_size)
- super(view, cmd, cmdsize)
- @rebase_off = rebase_off
- @rebase_size = rebase_size
- @bind_off = bind_off
- @bind_size = bind_size
- @weak_bind_off = weak_bind_off
- @weak_bind_size = weak_bind_size
- @lazy_bind_off = lazy_bind_off
- @lazy_bind_size = lazy_bind_size
- @export_off = export_off
- @export_size = export_size
+ # @api private
+ def initialize(view, cmd, cmdsize, rebase_off, rebase_size, bind_off,
+ bind_size, weak_bind_off, weak_bind_size, lazy_bind_off,
+ lazy_bind_size, export_off, export_size)
+ super(view, cmd, cmdsize)
+ @rebase_off = rebase_off
+ @rebase_size = rebase_size
+ @bind_off = bind_off
+ @bind_size = bind_size
+ @weak_bind_off = weak_bind_off
+ @weak_bind_size = weak_bind_size
+ @lazy_bind_off = lazy_bind_off
+ @lazy_bind_size = lazy_bind_size
+ @export_off = export_off
+ @export_size = export_size
+ end
end
- end
- # A load command containing linker options embedded in object files.
- # Corresponds to LC_LINKER_OPTION.
- class LinkerOptionCommand < LoadCommand
- # @return [Fixnum] the number of strings
- attr_reader :count
+ # A load command containing linker options embedded in object files.
+ # Corresponds to LC_LINKER_OPTION.
+ class LinkerOptionCommand < LoadCommand
+ # @return [Fixnum] the number of strings
+ attr_reader :count
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=3".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=3".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 12
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 12
- # @api private
- def initialize(view, cmd, cmdsize, count)
- super(view, cmd, cmdsize)
- @count = count
+ # @api private
+ def initialize(view, cmd, cmdsize, count)
+ super(view, cmd, cmdsize)
+ @count = count
+ end
end
- end
- # A load command specifying the offset of main(). Corresponds to LC_MAIN.
- class EntryPointCommand < LoadCommand
- # @return [Fixnum] the file (__TEXT) offset of main()
- attr_reader :entryoff
+ # A load command specifying the offset of main(). Corresponds to LC_MAIN.
+ class EntryPointCommand < LoadCommand
+ # @return [Fixnum] the file (__TEXT) offset of main()
+ attr_reader :entryoff
- # @return [Fixnum] if not 0, the initial stack size.
- attr_reader :stacksize
+ # @return [Fixnum] if not 0, the initial stack size.
+ attr_reader :stacksize
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2Q=2".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2Q=2".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 24
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 24
- # @api private
- def initialize(view, cmd, cmdsize, entryoff, stacksize)
- super(view, cmd, cmdsize)
- @entryoff = entryoff
- @stacksize = stacksize
+ # @api private
+ def initialize(view, cmd, cmdsize, entryoff, stacksize)
+ super(view, cmd, cmdsize)
+ @entryoff = entryoff
+ @stacksize = stacksize
+ end
end
- end
- # A load command specifying the version of the sources used to build the
- # binary. Corresponds to LC_SOURCE_VERSION.
- class SourceVersionCommand < LoadCommand
- # @return [Fixnum] the version packed as a24.b10.c10.d10.e10
- attr_reader :version
+ # A load command specifying the version of the sources used to build the
+ # binary. Corresponds to LC_SOURCE_VERSION.
+ class SourceVersionCommand < LoadCommand
+ # @return [Fixnum] the version packed as a24.b10.c10.d10.e10
+ attr_reader :version
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2Q=1".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2Q=1".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 16
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 16
- # @api private
- def initialize(view, cmd, cmdsize, version)
- super(view, cmd, cmdsize)
- @version = version
- end
+ # @api private
+ def initialize(view, cmd, cmdsize, version)
+ super(view, cmd, cmdsize)
+ @version = version
+ end
- # A string representation of the sources used to build the binary.
- # @return [String] a string representation of the version
- def version_string
- binary = "%064b" % version
- segs = [
- binary[0..23], binary[24..33], binary[34..43], binary[44..53],
- binary[54..63]
- ].map { |s| s.to_i(2) }
+ # A string representation of the sources used to build the binary.
+ # @return [String] a string representation of the version
+ def version_string
+ binary = "%064b" % version
+ segs = [
+ binary[0..23], binary[24..33], binary[34..43], binary[44..53],
+ binary[54..63]
+ ].map { |s| s.to_i(2) }
- segs.join(".")
+ segs.join(".")
+ end
end
- end
- # An obsolete load command containing the offset and size of the (GNU style)
- # symbol table information. Corresponds to LC_SYMSEG.
- class SymsegCommand < LoadCommand
- # @return [Fixnum] the offset to the symbol segment
- attr_reader :offset
+ # An obsolete load command containing the offset and size of the (GNU style)
+ # symbol table information. Corresponds to LC_SYMSEG.
+ class SymsegCommand < LoadCommand
+ # @return [Fixnum] the offset to the symbol segment
+ attr_reader :offset
- # @return [Fixnum] the size of the symbol segment in bytes
- attr_reader :size
+ # @return [Fixnum] the size of the symbol segment in bytes
+ attr_reader :size
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=4".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=4".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 16
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 16
- # @api private
- def initialize(view, cmd, cmdsize, offset, size)
- super(view, cmd, cmdsize)
- @offset = offset
- @size = size
+ # @api private
+ def initialize(view, cmd, cmdsize, offset, size)
+ super(view, cmd, cmdsize)
+ @offset = offset
+ @size = size
+ end
end
- end
- # An obsolete load command containing a free format string table. Each string
- # is null-terminated and the command is zero-padded to a multiple of 4.
- # Corresponds to LC_IDENT.
- class IdentCommand < LoadCommand
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=2".freeze
+ # An obsolete load command containing a free format string table. Each
+ # string is null-terminated and the command is zero-padded to a multiple of
+ # 4. Corresponds to LC_IDENT.
+ class IdentCommand < LoadCommand
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=2".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 8
- end
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 8
+ end
- # An obsolete load command containing the path to a file to be loaded into
- # memory. Corresponds to LC_FVMFILE.
- class FvmfileCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the pathname of the file being loaded
- attr_reader :name
+ # An obsolete load command containing the path to a file to be loaded into
+ # memory. Corresponds to LC_FVMFILE.
+ class FvmfileCommand < LoadCommand
+ # @return [LCStr] the pathname of the file being loaded
+ attr_reader :name
- # @return [Fixnum] the virtual address being loaded at
- attr_reader :header_addr
+ # @return [Fixnum] the virtual address being loaded at
+ attr_reader :header_addr
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=4".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=4".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 16
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 16
- def initialize(view, cmd, cmdsize, name, header_addr)
- super(view, cmd, cmdsize)
- @name = LCStr.new(self, name)
- @header_addr = header_addr
+ def initialize(view, cmd, cmdsize, name, header_addr)
+ super(view, cmd, cmdsize)
+ @name = LCStr.new(self, name)
+ @header_addr = header_addr
+ end
end
- end
- # An obsolete load command containing the path to a library to be loaded into
- # memory. Corresponds to LC_LOADFVMLIB and LC_IDFVMLIB.
- class FvmlibCommand < LoadCommand
- # @return [MachO::LoadCommand::LCStr] the library's target pathname
- attr_reader :name
+ # An obsolete load command containing the path to a library to be loaded
+ # into memory. Corresponds to LC_LOADFVMLIB and LC_IDFVMLIB.
+ class FvmlibCommand < LoadCommand
+ # @return [LCStr] the library's target pathname
+ attr_reader :name
- # @return [Fixnum] the library's minor version number
- attr_reader :minor_version
+ # @return [Fixnum] the library's minor version number
+ attr_reader :minor_version
- # @return [Fixnum] the library's header address
- attr_reader :header_addr
+ # @return [Fixnum] the library's header address
+ attr_reader :header_addr
- # @see MachOStructure::FORMAT
- # @api private
- FORMAT = "L=5".freeze
+ # @see MachOStructure::FORMAT
+ # @api private
+ FORMAT = "L=5".freeze
- # @see MachOStructure::SIZEOF
- # @api private
- SIZEOF = 20
+ # @see MachOStructure::SIZEOF
+ # @api private
+ SIZEOF = 20
- def initialize(view, cmd, cmdsize, name, minor_version, header_addr)
- super(view, cmd, cmdsize)
- @name = LCStr.new(self, name)
- @minor_version = minor_version
- @header_addr = header_addr
+ def initialize(view, cmd, cmdsize, name, minor_version, header_addr)
+ super(view, cmd, cmdsize)
+ @name = LCStr.new(self, name)
+ @minor_version = minor_version
+ @header_addr = header_addr
+ end
end
end
end
diff --git a/Library/Homebrew/vendor/macho/macho/macho_file.rb b/Library/Homebrew/vendor/macho/macho/macho_file.rb
index 8ece62672..7693ab0dd 100644
--- a/Library/Homebrew/vendor/macho/macho/macho_file.rb
+++ b/Library/Homebrew/vendor/macho/macho/macho_file.rb
@@ -1,27 +1,33 @@
+require "forwardable"
+
module MachO
# Represents a Mach-O file, which contains a header and load commands
# as well as binary executable instructions. Mach-O binaries are
# architecture specific.
# @see https://en.wikipedia.org/wiki/Mach-O
- # @see MachO::FatFile
+ # @see FatFile
class MachOFile
- # @return [String] the filename loaded from, or nil if loaded from a binary string
+ extend Forwardable
+
+ # @return [String] the filename loaded from, or nil if loaded from a binary
+ # string
attr_accessor :filename
# @return [Symbol] the endianness of the file, :big or :little
attr_reader :endianness
- # @return [MachO::MachHeader] if the Mach-O is 32-bit
- # @return [MachO::MachHeader64] if the Mach-O is 64-bit
+ # @return [Headers::MachHeader] if the Mach-O is 32-bit
+ # @return [Headers::MachHeader64] if the Mach-O is 64-bit
attr_reader :header
- # @return [Array<MachO::LoadCommand>] an array of the file's load commands
+ # @return [Array<LoadCommands::LoadCommand>] an array of the file's load
+ # commands
# @note load commands are provided in order of ascending offset.
attr_reader :load_commands
# Creates a new MachOFile instance from a binary string.
# @param bin [String] a binary string containing raw Mach-O data
- # @return [MachO::MachOFile] a new MachOFile
+ # @return [MachOFile] a new MachOFile
def self.new_from_bin(bin)
instance = allocate
instance.initialize_from_bin(bin)
@@ -55,109 +61,63 @@ module MachO
@raw_data
end
- # @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
- def magic32?
- Utils.magic32?(header.magic)
- end
-
- # @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise
- def magic64?
- Utils.magic64?(header.magic)
- end
-
- # @return [Fixnum] the file's internal alignment
- def alignment
- magic32? ? 4 : 8
- end
-
- # @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
- def object?
- header.filetype == MH_OBJECT
- end
-
- # @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise
- def executable?
- header.filetype == MH_EXECUTE
- end
-
- # @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise
- def fvmlib?
- header.filetype == MH_FVMLIB
- end
-
- # @return [Boolean] true if the file is of type `MH_CORE`, false otherwise
- def core?
- header.filetype == MH_CORE
- end
-
- # @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise
- def preload?
- header.filetype == MH_PRELOAD
- end
-
- # @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise
- def dylib?
- header.filetype == MH_DYLIB
- end
-
- # @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise
- def dylinker?
- header.filetype == MH_DYLINKER
- end
-
- # @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise
- def bundle?
- header.filetype == MH_BUNDLE
- end
-
- # @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise
- def dsym?
- header.filetype == MH_DSYM
- end
-
- # @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise
- def kext?
- header.filetype == MH_KEXT_BUNDLE
- end
-
- # @return [Fixnum] the file's magic number
- def magic
- header.magic
- end
+ # @!method magic
+ # @return (see MachO::Headers::MachHeader#magic)
+ # @!method ncmds
+ # @return (see MachO::Headers::MachHeader#ncmds)
+ # @!method sizeofcmds
+ # @return (see MachO::Headers::MachHeader#sizeofcmds)
+ # @!method flags
+ # @return (see MachO::Headers::MachHeader#flags)
+ # @!method object?
+ # @return (see MachO::Headers::MachHeader#object?)
+ # @!method executable?
+ # @return (see MachO::Headers::MachHeader#executable?)
+ # @!method fvmlib?
+ # @return (see MachO::Headers::MachHeader#fvmlib?)
+ # @!method core?
+ # @return (see MachO::Headers::MachHeader#core?)
+ # @!method preload?
+ # @return (see MachO::Headers::MachHeader#preload?)
+ # @!method dylib?
+ # @return (see MachO::Headers::MachHeader#dylib?)
+ # @!method dylinker?
+ # @return (see MachO::Headers::MachHeader#dylinker?)
+ # @!method bundle?
+ # @return (see MachO::Headers::MachHeader#bundle?)
+ # @!method dsym?
+ # @return (see MachO::Headers::MachHeader#dsym?)
+ # @!method kext?
+ # @return (see MachO::Headers::MachHeader#kext?)
+ # @!method magic32?
+ # @return (see MachO::Headers::MachHeader#magic32?)
+ # @!method magic64?
+ # @return (see MachO::Headers::MachHeader#magic64?)
+ # @!method alignment
+ # @return (see MachO::Headers::MachHeader#alignment)
+ def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
+ :executable?, :fvmlib?, :core?, :preload?, :dylib?,
+ :dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
+ :alignment
# @return [String] a string representation of the file's magic number
def magic_string
- MH_MAGICS[magic]
+ Headers::MH_MAGICS[magic]
end
# @return [Symbol] a string representation of the Mach-O's filetype
def filetype
- MH_FILETYPES[header.filetype]
+ Headers::MH_FILETYPES[header.filetype]
end
# @return [Symbol] a symbol representation of the Mach-O's CPU type
def cputype
- CPU_TYPES[header.cputype]
+ Headers::CPU_TYPES[header.cputype]
end
# @return [Symbol] a symbol representation of the Mach-O's CPU subtype
def cpusubtype
- CPU_SUBTYPES[header.cputype][header.cpusubtype]
- end
-
- # @return [Fixnum] the number of load commands in the Mach-O's header
- def ncmds
- header.ncmds
- end
-
- # @return [Fixnum] the size of all load commands, in bytes
- def sizeofcmds
- header.sizeofcmds
- end
-
- # @return [Fixnum] execution flags set by the linker
- def flags
- header.flags
+ Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype]
end
# All load commands of a given name.
@@ -165,7 +125,8 @@ module MachO
# file.command("LC_LOAD_DYLIB")
# file[:LC_LOAD_DYLIB]
# @param [String, Symbol] name the load command ID
- # @return [Array<MachO::LoadCommand>] an array of LoadCommands corresponding to `name`
+ # @return [Array<LoadCommands::LoadCommand>] an array of load commands
+ # corresponding to `name`
def command(name)
load_commands.select { |lc| lc.type == name.to_sym }
end
@@ -174,16 +135,16 @@ module MachO
# Inserts a load command at the given offset.
# @param offset [Fixnum] the offset to insert at
- # @param lc [MachO::LoadCommand] the load command to insert
+ # @param lc [LoadCommands::LoadCommand] the load command to insert
# @param options [Hash]
# @option options [Boolean] :repopulate (true) whether or not to repopulate
# the instance fields
- # @raise [MachO::OffsetInsertionError] if the offset is not in the load command region
- # @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
+ # @raise [OffsetInsertionError] if the offset is not in the load command region
+ # @raise [HeaderPadError] if the new command exceeds the header pad buffer
# @note Calling this method with an arbitrary offset in the load command
# region **will leave the object in an inconsistent state**.
def insert_command(offset, lc, options = {})
- context = LoadCommand::SerializationContext.context_for(self)
+ context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
cmd_raw = lc.serialize(context)
if offset < header.class.bytesize || offset + cmd_raw.bytesize > low_fileoff
@@ -207,14 +168,14 @@ module MachO
end
# Replace a load command with another command in the Mach-O, preserving location.
- # @param old_lc [MachO::LoadCommand] the load command being replaced
- # @param new_lc [MachO::LoadCommand] the load command being added
+ # @param old_lc [LoadCommands::LoadCommand] the load command being replaced
+ # @param new_lc [LoadCommands::LoadCommand] the load command being added
# @return [void]
- # @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
- # @see {#insert_command}
+ # @raise [HeaderPadError] if the new command exceeds the header pad buffer
+ # @see #insert_command
# @note This is public, but methods like {#dylib_id=} should be preferred.
def replace_command(old_lc, new_lc)
- context = LoadCommand::SerializationContext.context_for(self)
+ context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
cmd_raw = new_lc.serialize(context)
new_sizeofcmds = sizeofcmds + cmd_raw.bytesize - old_lc.cmdsize
if header.class.bytesize + new_sizeofcmds > low_fileoff
@@ -226,12 +187,12 @@ module MachO
end
# Appends a new load command to the Mach-O.
- # @param lc [MachO::LoadCommand] the load command being added
+ # @param lc [LoadCommands::LoadCommand] the load command being added
# @param options [Hash]
# @option options [Boolean] :repopulate (true) whether or not to repopulate
# the instance fields
# @return [void]
- # @see {#insert_command}
+ # @see #insert_command
# @note This is public, but methods like {#add_rpath} should be preferred.
# Setting `repopulate` to false **will leave the instance in an
# inconsistent state** unless {#populate_fields} is called **immediately**
@@ -241,7 +202,7 @@ module MachO
end
# Delete a load command from the Mach-O.
- # @param lc [MachO::LoadCommand] the load command being deleted
+ # @param lc [LoadCommands::LoadCommand] the load command being deleted
# @param options [Hash]
# @option options [Boolean] :repopulate (true) whether or not to repopulate
# the instance fields
@@ -275,14 +236,14 @@ module MachO
end
# All load commands responsible for loading dylibs.
- # @return [Array<MachO::DylibCommand>] an array of DylibCommands
+ # @return [Array<LoadCommands::DylibCommand>] an array of DylibCommands
def dylib_load_commands
- load_commands.select { |lc| DYLIB_LOAD_COMMANDS.include?(lc.type) }
+ load_commands.select { |lc| LoadCommands::DYLIB_LOAD_COMMANDS.include?(lc.type) }
end
# All segment load commands in the Mach-O.
- # @return [Array<MachO::SegmentCommand>] if the Mach-O is 32-bit
- # @return [Array<MachO::SegmentCommand64>] if the Mach-O is 64-bit
+ # @return [Array<LoadCommands::SegmentCommand>] if the Mach-O is 32-bit
+ # @return [Array<LoadCommands::SegmentCommand64>] if the Mach-O is 64-bit
def segments
if magic32?
command(:LC_SEGMENT)
@@ -319,10 +280,10 @@ module MachO
old_lc = command(:LC_ID_DYLIB).first
raise DylibIdMissingError unless old_lc
- new_lc = LoadCommand.create(:LC_ID_DYLIB, new_id,
- old_lc.timestamp,
- old_lc.current_version,
- old_lc.compatibility_version)
+ new_lc = LoadCommands::LoadCommand.create(:LC_ID_DYLIB, new_id,
+ old_lc.timestamp,
+ old_lc.current_version,
+ old_lc.compatibility_version)
replace_command(old_lc, new_lc)
end
@@ -341,22 +302,22 @@ module MachO
# Changes the shared library `old_name` to `new_name`
# @example
- # file.change_install_name("/usr/lib/libWhatever.dylib", "/usr/local/lib/libWhatever2.dylib")
+ # file.change_install_name("abc.dylib", "def.dylib")
# @param old_name [String] the shared library's old name
# @param new_name [String] the shared library's new name
# @param _options [Hash]
# @return [void]
- # @raise [MachO::DylibUnknownError] if no shared library has the old name
+ # @raise [DylibUnknownError] if no shared library has the old name
# @note `_options` is currently unused and is provided for signature
# compatibility with {MachO::FatFile#change_install_name}
def change_install_name(old_name, new_name, _options = {})
old_lc = dylib_load_commands.find { |d| d.name.to_s == old_name }
raise DylibUnknownError, old_name if old_lc.nil?
- new_lc = LoadCommand.create(old_lc.type, new_name,
- old_lc.timestamp,
- old_lc.current_version,
- old_lc.compatibility_version)
+ new_lc = LoadCommands::LoadCommand.create(old_lc.type, new_name,
+ old_lc.timestamp,
+ old_lc.current_version,
+ old_lc.compatibility_version)
replace_command(old_lc, new_lc)
end
@@ -376,8 +337,8 @@ module MachO
# @param new_path [String] the new runtime path
# @param _options [Hash]
# @return [void]
- # @raise [MachO::RpathUnknownError] if no such old runtime path exists
- # @raise [MachO::RpathExistsError] if the new runtime path already exists
+ # @raise [RpathUnknownError] if no such old runtime path exists
+ # @raise [RpathExistsError] if the new runtime path already exists
# @note `_options` is currently unused and is provided for signature
# compatibility with {MachO::FatFile#change_rpath}
def change_rpath(old_path, new_path, _options = {})
@@ -385,7 +346,7 @@ module MachO
raise RpathUnknownError, old_path if old_lc.nil?
raise RpathExistsError, new_path if rpaths.include?(new_path)
- new_lc = LoadCommand.create(:LC_RPATH, new_path)
+ new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path)
delete_rpath(old_path)
insert_command(old_lc.view.offset, new_lc)
@@ -399,13 +360,13 @@ module MachO
# @param path [String] the new runtime path
# @param _options [Hash]
# @return [void]
- # @raise [MachO::RpathExistsError] if the runtime path already exists
+ # @raise [RpathExistsError] if the runtime path already exists
# @note `_options` is currently unused and is provided for signature
# compatibility with {MachO::FatFile#add_rpath}
def add_rpath(path, _options = {})
raise RpathExistsError, path if rpaths.include?(path)
- rpath_cmd = LoadCommand.create(:LC_RPATH, path)
+ rpath_cmd = LoadCommands::LoadCommand.create(:LC_RPATH, path)
add_command(rpath_cmd)
end
@@ -417,7 +378,7 @@ module MachO
# @param path [String] the runtime path to delete
# @param _options [Hash]
# @return void
- # @raise [MachO::RpathUnknownError] if no such runtime path exists
+ # @raise [RpathUnknownError] if no such runtime path exists
# @note `_options` is currently unused and is provided for signature
# compatibility with {MachO::FatFile#delete_rpath}
def delete_rpath(path, _options = {})
@@ -431,15 +392,6 @@ module MachO
populate_fields
end
- # All sections of the segment `segment`.
- # @param segment [MachO::SegmentCommand, MachO::SegmentCommand64] the segment being inspected
- # @return [Array<MachO::Section>] if the Mach-O is 32-bit
- # @return [Array<MachO::Section64>] if the Mach-O is 64-bit
- # @deprecated use {MachO::SegmentCommand#sections} instead
- def sections(segment)
- segment.sections
- end
-
# Write all Mach-O data to the given filename.
# @param filename [String] the file to write to
# @return [void]
@@ -449,7 +401,7 @@ module MachO
# Write all Mach-O data to the file used to initialize the instance.
# @return [void]
- # @raise [MachO::MachOError] if the instance was initialized without a file
+ # @raise [MachOError] if the instance was initialized without a file
# @note Overwrites all data in the file!
def write!
if @filename.nil?
@@ -462,16 +414,16 @@ module MachO
private
# The file's Mach-O header structure.
- # @return [MachO::MachHeader] if the Mach-O is 32-bit
- # @return [MachO::MachHeader64] if the Mach-O is 64-bit
- # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
+ # @return [Headers::MachHeader] if the Mach-O is 32-bit
+ # @return [Headers::MachHeader64] if the Mach-O is 64-bit
+ # @raise [TruncatedFileError] if the file is too small to have a valid header
# @api private
def populate_mach_header
# the smallest Mach-O header is 28 bytes
raise TruncatedFileError if @raw_data.size < 28
magic = populate_and_check_magic
- mh_klass = Utils.magic32?(magic) ? MachHeader : MachHeader64
+ mh_klass = Utils.magic32?(magic) ? Headers::MachHeader : Headers::MachHeader64
mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize])
check_cputype(mh.cputype)
@@ -483,8 +435,8 @@ module MachO
# Read just the file's magic number and check its validity.
# @return [Fixnum] the magic
- # @raise [MachO::MagicError] if the magic is not valid Mach-O magic
- # @raise [MachO::FatBinaryError] if the magic is for a Fat file
+ # @raise [MagicError] if the magic is not valid Mach-O magic
+ # @raise [FatBinaryError] if the magic is for a Fat file
# @api private
def populate_and_check_magic
magic = @raw_data[0..3].unpack("N").first
@@ -499,32 +451,32 @@ module MachO
# Check the file's CPU type.
# @param cputype [Fixnum] the CPU type
- # @raise [MachO::CPUTypeError] if the CPU type is unknown
+ # @raise [CPUTypeError] if the CPU type is unknown
# @api private
def check_cputype(cputype)
- raise CPUTypeError, cputype unless CPU_TYPES.key?(cputype)
+ raise CPUTypeError, cputype unless Headers::CPU_TYPES.key?(cputype)
end
# Check the file's CPU type/subtype pair.
# @param cpusubtype [Fixnum] the CPU subtype
- # @raise [MachO::CPUSubtypeError] if the CPU sub-type is unknown
+ # @raise [CPUSubtypeError] if the CPU sub-type is unknown
# @api private
def check_cpusubtype(cputype, cpusubtype)
# Only check sub-type w/o capability bits (see `populate_mach_header`).
- raise CPUSubtypeError.new(cputype, cpusubtype) unless CPU_SUBTYPES[cputype].key?(cpusubtype)
+ raise CPUSubtypeError.new(cputype, cpusubtype) unless Headers::CPU_SUBTYPES[cputype].key?(cpusubtype)
end
# Check the file's type.
# @param filetype [Fixnum] the file type
- # @raise [MachO::FiletypeError] if the file type is unknown
+ # @raise [FiletypeError] if the file type is unknown
# @api private
def check_filetype(filetype)
- raise FiletypeError, filetype unless MH_FILETYPES.key?(filetype)
+ raise FiletypeError, filetype unless Headers::MH_FILETYPES.key?(filetype)
end
# All load commands in the file.
- # @return [Array<MachO::LoadCommand>] an array of load commands
- # @raise [MachO::LoadCommandError] if an unknown load command is encountered
+ # @return [Array<LoadCommands::LoadCommand>] an array of load commands
+ # @raise [LoadCommandError] if an unknown load command is encountered
# @api private
def populate_load_commands
offset = header.class.bytesize
@@ -533,13 +485,13 @@ module MachO
header.ncmds.times do
fmt = Utils.specialize_format("L=", endianness)
cmd = @raw_data.slice(offset, 4).unpack(fmt).first
- cmd_sym = LOAD_COMMANDS[cmd]
+ cmd_sym = LoadCommands::LOAD_COMMANDS[cmd]
raise LoadCommandError, cmd if cmd_sym.nil?
# why do I do this? i don't like declaring constants below
# classes, and i need them to resolve...
- klass = MachO.const_get LC_STRUCTURES[cmd_sym]
+ klass = LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym]
view = MachOView.new(@raw_data, endianness, offset)
command = klass.new_from_bin(view)
diff --git a/Library/Homebrew/vendor/macho/macho/open.rb b/Library/Homebrew/vendor/macho/macho/open.rb
deleted file mode 100644
index 103f61741..000000000
--- a/Library/Homebrew/vendor/macho/macho/open.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-module MachO
- # Opens the given filename as a MachOFile or FatFile, depending on its magic.
- # @param filename [String] the file being opened
- # @return [MachO::MachOFile] if the file is a Mach-O
- # @return [MachO::FatFile] if the file is a Fat file
- # @raise [ArgumentError] if the given file does not exist
- # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
- # @raise [MachO::MagicError] if the file's magic is not valid Mach-O magic
- def self.open(filename)
- raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
- raise TruncatedFileError unless File.stat(filename).size >= 4
-
- magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
-
- if Utils.fat_magic?(magic)
- file = FatFile.new(filename)
- elsif Utils.magic?(magic)
- file = MachOFile.new(filename)
- else
- raise MagicError, magic
- end
-
- file
- end
-end
diff --git a/Library/Homebrew/vendor/macho/macho/sections.rb b/Library/Homebrew/vendor/macho/macho/sections.rb
index bd6218bb5..1e69e0b61 100644
--- a/Library/Homebrew/vendor/macho/macho/sections.rb
+++ b/Library/Homebrew/vendor/macho/macho/sections.rb
@@ -1,170 +1,176 @@
module MachO
- # type mask
- SECTION_TYPE = 0x000000ff
-
- # attributes mask
- SECTION_ATTRIBUTES = 0xffffff00
-
- # user settable attributes mask
- SECTION_ATTRIBUTES_USR = 0xff000000
-
- # system settable attributes mask
- SECTION_ATTRIBUTES_SYS = 0x00ffff00
-
- # association of section flag symbols to values
- # @api private
- SECTION_FLAGS = {
- :S_REGULAR => 0x0,
- :S_ZEROFILL => 0x1,
- :S_CSTRING_LITERALS => 0x2,
- :S_4BYTE_LITERALS => 0x3,
- :S_8BYTE_LITERALS => 0x4,
- :S_LITERAL_POINTERS => 0x5,
- :S_NON_LAZY_SYMBOL_POINTERS => 0x6,
- :S_LAZY_SYMBOL_POINTERS => 0x7,
- :S_SYMBOL_STUBS => 0x8,
- :S_MOD_INIT_FUNC_POINTERS => 0x9,
- :S_MOD_TERM_FUNC_POINTERS => 0xa,
- :S_COALESCED => 0xb,
- :S_GB_ZEROFILE => 0xc,
- :S_INTERPOSING => 0xd,
- :S_16BYTE_LITERALS => 0xe,
- :S_DTRACE_DOF => 0xf,
- :S_LAZY_DYLIB_SYMBOL_POINTERS => 0x10,
- :S_THREAD_LOCAL_REGULAR => 0x11,
- :S_THREAD_LOCAL_ZEROFILL => 0x12,
- :S_THREAD_LOCAL_VARIABLES => 0x13,
- :S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
- :S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
- :S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
- :S_ATTR_NO_TOC => 0x40000000,
- :S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
- :S_ATTR_NO_DEAD_STRIP => 0x10000000,
- :S_ATTR_LIVE_SUPPORT => 0x08000000,
- :S_ATTR_SELF_MODIFYING_CODE => 0x04000000,
- :S_ATTR_DEBUG => 0x02000000,
- :S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
- :S_ATTR_EXT_RELOC => 0x00000200,
- :S_ATTR_LOC_RELOC => 0x00000100,
- }.freeze
-
- # association of section name symbols to names
- # @api private
- SECTION_NAMES = {
- :SECT_TEXT => "__text",
- :SECT_FVMLIB_INIT0 => "__fvmlib_init0",
- :SECT_FVMLIB_INIT1 => "__fvmlib_init1",
- :SECT_DATA => "__data",
- :SECT_BSS => "__bss",
- :SECT_COMMON => "__common",
- :SECT_OBJC_SYMBOLS => "__symbol_table",
- :SECT_OBJC_MODULES => "__module_info",
- :SECT_OBJC_STRINGS => "__selector_strs",
- :SECT_OBJC_REFS => "__selector_refs",
- :SECT_ICON_HEADER => "__header",
- :SECT_ICON_TIFF => "__tiff",
- }.freeze
-
- # Represents a section of a segment for 32-bit architectures.
- class Section < MachOStructure
- # @return [String] the name of the section, including null pad bytes
- attr_reader :sectname
-
- # @return [String] the name of the segment's section, including null pad bytes
- attr_reader :segname
-
- # @return [Fixnum] the memory address of the section
- attr_reader :addr
-
- # @return [Fixnum] the size, in bytes, of the section
- attr_reader :size
-
- # @return [Fixnum] the file offset of the section
- attr_reader :offset
-
- # @return [Fixnum] the section alignment (power of 2) of the section
- attr_reader :align
-
- # @return [Fixnum] the file offset of the section's relocation entries
- attr_reader :reloff
-
- # @return [Fixnum] the number of relocation entries
- attr_reader :nreloc
-
- # @return [Fixnum] flags for type and attributes of the section
- attr_reader :flags
-
- # @return [void] reserved (for offset or index)
- attr_reader :reserved1
-
- # @return [void] reserved (for count or sizeof)
- attr_reader :reserved2
-
- # @see MachOStructure::FORMAT
- FORMAT = "a16a16L=9".freeze
-
- # @see MachOStructure::SIZEOF
- SIZEOF = 68
+ # Classes and constants for parsing sections in Mach-O binaries.
+ module Sections
+ # type mask
+ SECTION_TYPE = 0x000000ff
- # @api private
- def initialize(sectname, segname, addr, size, offset, align, reloff,
- nreloc, flags, reserved1, reserved2)
- @sectname = sectname
- @segname = segname
- @addr = addr
- @size = size
- @offset = offset
- @align = align
- @reloff = reloff
- @nreloc = nreloc
- @flags = flags
- @reserved1 = reserved1
- @reserved2 = reserved2
- end
+ # attributes mask
+ SECTION_ATTRIBUTES = 0xffffff00
- # @return [String] the section's name, with any trailing NULL characters removed
- def section_name
- sectname.delete("\x00")
- end
-
- # @return [String] the parent segment's name, with any trailing NULL characters removed
- def segment_name
- segname.delete("\x00")
- end
+ # user settable attributes mask
+ SECTION_ATTRIBUTES_USR = 0xff000000
- # @return [Boolean] true if the section has no contents (i.e, `size` is 0)
- def empty?
- size.zero?
- end
+ # system settable attributes mask
+ SECTION_ATTRIBUTES_SYS = 0x00ffff00
- # @example
- # puts "this section is regular" if sect.flag?(:S_REGULAR)
- # @param flag [Symbol] a section flag symbol
- # @return [Boolean] true if `flag` is present in the section's flag field
- def flag?(flag)
- flag = SECTION_FLAGS[flag]
- return false if flag.nil?
- flags & flag == flag
+ # association of section flag symbols to values
+ # @api private
+ SECTION_FLAGS = {
+ :S_REGULAR => 0x0,
+ :S_ZEROFILL => 0x1,
+ :S_CSTRING_LITERALS => 0x2,
+ :S_4BYTE_LITERALS => 0x3,
+ :S_8BYTE_LITERALS => 0x4,
+ :S_LITERAL_POINTERS => 0x5,
+ :S_NON_LAZY_SYMBOL_POINTERS => 0x6,
+ :S_LAZY_SYMBOL_POINTERS => 0x7,
+ :S_SYMBOL_STUBS => 0x8,
+ :S_MOD_INIT_FUNC_POINTERS => 0x9,
+ :S_MOD_TERM_FUNC_POINTERS => 0xa,
+ :S_COALESCED => 0xb,
+ :S_GB_ZEROFILE => 0xc,
+ :S_INTERPOSING => 0xd,
+ :S_16BYTE_LITERALS => 0xe,
+ :S_DTRACE_DOF => 0xf,
+ :S_LAZY_DYLIB_SYMBOL_POINTERS => 0x10,
+ :S_THREAD_LOCAL_REGULAR => 0x11,
+ :S_THREAD_LOCAL_ZEROFILL => 0x12,
+ :S_THREAD_LOCAL_VARIABLES => 0x13,
+ :S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
+ :S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
+ :S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
+ :S_ATTR_NO_TOC => 0x40000000,
+ :S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
+ :S_ATTR_NO_DEAD_STRIP => 0x10000000,
+ :S_ATTR_LIVE_SUPPORT => 0x08000000,
+ :S_ATTR_SELF_MODIFYING_CODE => 0x04000000,
+ :S_ATTR_DEBUG => 0x02000000,
+ :S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
+ :S_ATTR_EXT_RELOC => 0x00000200,
+ :S_ATTR_LOC_RELOC => 0x00000100,
+ }.freeze
+
+ # association of section name symbols to names
+ # @api private
+ SECTION_NAMES = {
+ :SECT_TEXT => "__text",
+ :SECT_FVMLIB_INIT0 => "__fvmlib_init0",
+ :SECT_FVMLIB_INIT1 => "__fvmlib_init1",
+ :SECT_DATA => "__data",
+ :SECT_BSS => "__bss",
+ :SECT_COMMON => "__common",
+ :SECT_OBJC_SYMBOLS => "__symbol_table",
+ :SECT_OBJC_MODULES => "__module_info",
+ :SECT_OBJC_STRINGS => "__selector_strs",
+ :SECT_OBJC_REFS => "__selector_refs",
+ :SECT_ICON_HEADER => "__header",
+ :SECT_ICON_TIFF => "__tiff",
+ }.freeze
+
+ # Represents a section of a segment for 32-bit architectures.
+ class Section < MachOStructure
+ # @return [String] the name of the section, including null pad bytes
+ attr_reader :sectname
+
+ # @return [String] the name of the segment's section, including null
+ # pad bytes
+ attr_reader :segname
+
+ # @return [Fixnum] the memory address of the section
+ attr_reader :addr
+
+ # @return [Fixnum] the size, in bytes, of the section
+ attr_reader :size
+
+ # @return [Fixnum] the file offset of the section
+ attr_reader :offset
+
+ # @return [Fixnum] the section alignment (power of 2) of the section
+ attr_reader :align
+
+ # @return [Fixnum] the file offset of the section's relocation entries
+ attr_reader :reloff
+
+ # @return [Fixnum] the number of relocation entries
+ attr_reader :nreloc
+
+ # @return [Fixnum] flags for type and attributes of the section
+ attr_reader :flags
+
+ # @return [void] reserved (for offset or index)
+ attr_reader :reserved1
+
+ # @return [void] reserved (for count or sizeof)
+ attr_reader :reserved2
+
+ # @see MachOStructure::FORMAT
+ FORMAT = "a16a16L=9".freeze
+
+ # @see MachOStructure::SIZEOF
+ SIZEOF = 68
+
+ # @api private
+ def initialize(sectname, segname, addr, size, offset, align, reloff,
+ nreloc, flags, reserved1, reserved2)
+ @sectname = sectname
+ @segname = segname
+ @addr = addr
+ @size = size
+ @offset = offset
+ @align = align
+ @reloff = reloff
+ @nreloc = nreloc
+ @flags = flags
+ @reserved1 = reserved1
+ @reserved2 = reserved2
+ end
+
+ # @return [String] the section's name, with any trailing NULL characters
+ # removed
+ def section_name
+ sectname.delete("\x00")
+ end
+
+ # @return [String] the parent segment's name, with any trailing NULL
+ # characters removed
+ def segment_name
+ segname.delete("\x00")
+ end
+
+ # @return [Boolean] whether the section is empty (i.e, {size} is 0)
+ def empty?
+ size.zero?
+ end
+
+ # @example
+ # puts "this section is regular" if sect.flag?(:S_REGULAR)
+ # @param flag [Symbol] a section flag symbol
+ # @return [Boolean] whether the flag is present in the section's {flags}
+ def flag?(flag)
+ flag = SECTION_FLAGS[flag]
+ return false if flag.nil?
+ flags & flag == flag
+ end
end
- end
- # Represents a section of a segment for 64-bit architectures.
- class Section64 < Section
- # @return [void] reserved
- attr_reader :reserved3
+ # Represents a section of a segment for 64-bit architectures.
+ class Section64 < Section
+ # @return [void] reserved
+ attr_reader :reserved3
- # @see MachOStructure::FORMAT
- FORMAT = "a16a16Q=2L=8".freeze
+ # @see MachOStructure::FORMAT
+ FORMAT = "a16a16Q=2L=8".freeze
- # @see MachOStructure::SIZEOF
- SIZEOF = 80
+ # @see MachOStructure::SIZEOF
+ SIZEOF = 80
- # @api private
- def initialize(sectname, segname, addr, size, offset, align, reloff,
- nreloc, flags, reserved1, reserved2, reserved3)
- super(sectname, segname, addr, size, offset, align, reloff,
- nreloc, flags, reserved1, reserved2)
- @reserved3 = reserved3
+ # @api private
+ def initialize(sectname, segname, addr, size, offset, align, reloff,
+ nreloc, flags, reserved1, reserved2, reserved3)
+ super(sectname, segname, addr, size, offset, align, reloff,
+ nreloc, flags, reserved1, reserved2)
+ @reserved3 = reserved3
+ end
end
end
end
diff --git a/Library/Homebrew/vendor/macho/macho/structure.rb b/Library/Homebrew/vendor/macho/macho/structure.rb
index 43f7bc84e..bac5342d4 100644
--- a/Library/Homebrew/vendor/macho/macho/structure.rb
+++ b/Library/Homebrew/vendor/macho/macho/structure.rb
@@ -19,7 +19,7 @@ module MachO
# @param endianness [Symbol] either `:big` or `:little`
# @param bin [String] the string to be unpacked into the new structure
- # @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
+ # @return [MachO::MachOStructure] the resulting structure
# @api private
def self.new_from_bin(endianness, bin)
format = Utils.specialize_format(self::FORMAT, endianness)
diff --git a/Library/Homebrew/vendor/macho/macho/tools.rb b/Library/Homebrew/vendor/macho/macho/tools.rb
index f34d75dc1..b49626d9d 100644
--- a/Library/Homebrew/vendor/macho/macho/tools.rb
+++ b/Library/Homebrew/vendor/macho/macho/tools.rb
@@ -1,5 +1,6 @@
module MachO
- # A collection of convenient methods for common operations on Mach-O and Fat binaries.
+ # A collection of convenient methods for common operations on Mach-O and Fat
+ # binaries.
module Tools
# @param filename [String] the Mach-O or Fat binary being read
# @return [Array<String>] an array of all dylibs linked to the binary
@@ -9,7 +10,8 @@ module MachO
file.linked_dylibs
end
- # Changes the dylib ID of a Mach-O or Fat binary, overwriting the source file.
+ # Changes the dylib ID of a Mach-O or Fat binary, overwriting the source
+ # file.
# @param filename [String] the Mach-O or Fat binary being modified
# @param new_id [String] the new dylib ID for the binary
# @param options [Hash]
@@ -23,7 +25,8 @@ module MachO
file.write!
end
- # Changes a shared library install name in a Mach-O or Fat binary, overwriting the source file.
+ # Changes a shared library install name in a Mach-O or Fat binary,
+ # overwriting the source file.
# @param filename [String] the Mach-O or Fat binary being modified
# @param old_name [String] the old shared library name
# @param new_name [String] the new shared library name
@@ -38,7 +41,8 @@ module MachO
file.write!
end
- # Changes a runtime path in a Mach-O or Fat binary, overwriting the source file.
+ # Changes a runtime path in a Mach-O or Fat binary, overwriting the source
+ # file.
# @param filename [String] the Mach-O or Fat binary being modified
# @param old_path [String] the old runtime path
# @param new_path [String] the new runtime path
@@ -67,7 +71,8 @@ module MachO
file.write!
end
- # Delete a runtime path from a Mach-O or Fat binary, overwriting the source file.
+ # Delete a runtime path from a Mach-O or Fat binary, overwriting the source
+ # file.
# @param filename [String] the Mach-O or Fat binary being modified
# @param old_path [String] the old runtime path
# @param options [Hash]
@@ -80,5 +85,24 @@ module MachO
file.delete_rpath(old_path, options)
file.write!
end
+
+ # Merge multiple Mach-Os into one universal (Fat) binary.
+ # @param filename [String] the fat binary to create
+ # @param files [Array<MachO::MachOFile, MachO::FatFile>] the files to merge
+ # @return [void]
+ def self.merge_machos(filename, *files)
+ machos = files.map do |file|
+ macho = MachO.open(file)
+ case macho
+ when MachO::MachOFile
+ macho
+ else
+ macho.machos
+ end
+ end.flatten
+
+ fat_macho = MachO::FatFile.new_from_machos(*machos)
+ fat_macho.write(filename)
+ end
end
end
diff --git a/Library/Homebrew/vendor/macho/macho/utils.rb b/Library/Homebrew/vendor/macho/macho/utils.rb
index cedd0bc1c..ecfc8390b 100644
--- a/Library/Homebrew/vendor/macho/macho/utils.rb
+++ b/Library/Homebrew/vendor/macho/macho/utils.rb
@@ -5,7 +5,7 @@ module MachO
# @param value [Fixnum] the number being rounded
# @param round [Fixnum] the number being rounded with
# @return [Fixnum] the rounded value
- # @see https://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
+ # @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
def self.round(value, round)
round -= 1
value += round
@@ -13,7 +13,8 @@ module MachO
value
end
- # Returns the number of bytes needed to pad the given size to the given alignment.
+ # Returns the number of bytes needed to pad the given size to the given
+ # alignment.
# @param size [Fixnum] the unpadded size
# @param alignment [Fixnum] the number to alignment the size with
# @return [Fixnum] the number of pad bytes required
@@ -21,7 +22,8 @@ module MachO
round(size, alignment) - size
end
- # Converts an abstract (native-endian) String#unpack format to big or little.
+ # Converts an abstract (native-endian) String#unpack format to big or
+ # little.
# @param format [String] the format string being converted
# @param endianness [Symbol] either `:big` or `:little`
# @return [String] the converted string
@@ -31,7 +33,8 @@ module MachO
end
# Packs tagged strings into an aligned payload.
- # @param fixed_offset [Fixnum] the baseline offset for the first packed string
+ # @param fixed_offset [Fixnum] the baseline offset for the first packed
+ # string
# @param alignment [Fixnum] the alignment value to use for packing
# @param strings [Hash] the labeled strings to pack
# @return [Array<String, Hash>] the packed string and labeled offsets
@@ -53,44 +56,44 @@ module MachO
# Compares the given number to valid Mach-O magic numbers.
# @param num [Fixnum] the number being checked
- # @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
+ # @return [Boolean] whether `num` is a valid Mach-O magic number
def self.magic?(num)
- MH_MAGICS.key?(num)
+ Headers::MH_MAGICS.key?(num)
end
# Compares the given number to valid Fat magic numbers.
# @param num [Fixnum] the number being checked
- # @return [Boolean] true if `num` is a valid Fat magic number, false otherwise
+ # @return [Boolean] whether `num` is a valid Fat magic number
def self.fat_magic?(num)
- num == FAT_MAGIC
+ num == Headers::FAT_MAGIC
end
# Compares the given number to valid 32-bit Mach-O magic numbers.
# @param num [Fixnum] the number being checked
- # @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise
+ # @return [Boolean] whether `num` is a valid 32-bit magic number
def self.magic32?(num)
- num == MH_MAGIC || num == MH_CIGAM
+ num == Headers::MH_MAGIC || num == Headers::MH_CIGAM
end
# Compares the given number to valid 64-bit Mach-O magic numbers.
# @param num [Fixnum] the number being checked
- # @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise
+ # @return [Boolean] whether `num` is a valid 64-bit magic number
def self.magic64?(num)
- num == MH_MAGIC_64 || num == MH_CIGAM_64
+ num == Headers::MH_MAGIC_64 || num == Headers::MH_CIGAM_64
end
# Compares the given number to valid little-endian magic numbers.
# @param num [Fixnum] the number being checked
- # @return [Boolean] true if `num` is a valid little-endian magic number, false otherwise
+ # @return [Boolean] whether `num` is a valid little-endian magic number
def self.little_magic?(num)
- num == MH_CIGAM || num == MH_CIGAM_64
+ num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64
end
# Compares the given number to valid big-endian magic numbers.
# @param num [Fixnum] the number being checked
- # @return [Boolean] true if `num` is a valid big-endian magic number, false otherwise
+ # @return [Boolean] whether `num` is a valid big-endian magic number
def self.big_magic?(num)
- num == MH_CIGAM || num == MH_CIGAM_64
+ num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64
end
end
end
diff --git a/Library/Homebrew/vendor/plist/plist/parser.rb b/Library/Homebrew/vendor/plist/plist/parser.rb
index de441fcc5..7d8bfab07 100644..100755
--- a/Library/Homebrew/vendor/plist/plist/parser.rb
+++ b/Library/Homebrew/vendor/plist/plist/parser.rb
@@ -69,6 +69,11 @@ module Plist
@xml = plist_data_or_file
end
+ # TODO: Update vendored `plist` parser when
+ # https://github.com/patsplat/plist/pull/38
+ # is merged.
+ @xml.force_encoding("UTF-8")
+
@listener = listener
end