diff options
| author | Mike McQuaid | 2015-08-29 10:56:24 +0100 |
|---|---|---|
| committer | Mike McQuaid | 2015-08-29 15:43:16 +0100 |
| commit | 2c959a7d5847094d316278188e816a7dadc1a090 (patch) | |
| tree | 1788b7791102363b7eab595f1346e3199b4de80a /Library/Homebrew | |
| parent | 77536e39de0368a0ba3ca2b46f0417abdf75aadf (diff) | |
| download | brew-2c959a7d5847094d316278188e816a7dadc1a090.tar.bz2 | |
More API documentation.
And remove the documented stuff from the `example-formula.rb`.
Closes Homebrew/homebrew#43241.
Signed-off-by: Mike McQuaid <mike@mikemcquaid.com>
Diffstat (limited to 'Library/Homebrew')
| -rw-r--r-- | Library/Homebrew/README.md | 10 | ||||
| -rw-r--r-- | Library/Homebrew/build_options.rb | 39 | ||||
| -rw-r--r-- | Library/Homebrew/cmd/create.rb | 2 | ||||
| -rw-r--r-- | Library/Homebrew/cmd/man.rb | 8 | ||||
| -rw-r--r-- | Library/Homebrew/compilers.rb | 1 | ||||
| -rw-r--r-- | Library/Homebrew/extend/ENV/shared.rb | 32 | ||||
| -rw-r--r-- | Library/Homebrew/extend/ENV/std.rb | 11 | ||||
| -rw-r--r-- | Library/Homebrew/extend/ENV/super.rb | 29 | ||||
| -rw-r--r-- | Library/Homebrew/extend/fileutils.rb | 22 | ||||
| -rw-r--r-- | Library/Homebrew/extend/pathname.rb | 36 | ||||
| -rw-r--r-- | Library/Homebrew/formula.rb | 479 | ||||
| -rw-r--r-- | Library/Homebrew/mach.rb | 16 | ||||
| -rw-r--r-- | Library/Homebrew/manpages/brew.1.md | 2 | ||||
| -rw-r--r-- | Library/Homebrew/utils.rb | 1 | ||||
| -rw-r--r-- | Library/Homebrew/utils/inreplace.rb | 7 |
15 files changed, 633 insertions, 62 deletions
diff --git a/Library/Homebrew/README.md b/Library/Homebrew/README.md index f154675e2..00036f131 100644 --- a/Library/Homebrew/README.md +++ b/Library/Homebrew/README.md @@ -1,4 +1,8 @@ -# Homebrew Public API -We're (finally) working on a documented public API for Homebrew. It's currently a work in progress; a bunch of public stuff is documented and a bunch of private stuff is undocumented. Sorry about that! +# Homebrew's Formula API +This is the (partially) documented public API for Homebrew. It's currently a work in progress. Sorry about that! -The main class you should look at is {Formula}. Assume everything else is private for now. +The main class you should look at is the {Formula} class (and classes linked from there). That's the class that's used to create Homebrew formulae (i.e. package descriptions). Assume anything else you stumble upon is private. + +You may also find the [Formula Cookbook](Formula-Cookbook.md) and [Ruby Style Guide](https://github.com/styleguide/ruby) helpful in creating formulae. + +Good luck! diff --git a/Library/Homebrew/build_options.rb b/Library/Homebrew/build_options.rb index 05f8507de..2e8f741d4 100644 --- a/Library/Homebrew/build_options.rb +++ b/Library/Homebrew/build_options.rb @@ -1,13 +1,28 @@ class BuildOptions + # @private def initialize(args, options) @args = args @options = options end + # True if a {Formula} is being built with a specific option + # (which isn't named `with-*` or `without-*`). + # @deprecated def include?(name) @args.include?("--#{name}") end + # True if a {Formula} is being built with a specific option. + # <pre>args << "--i-want-spam" if build.with? "spam" + # + # args << "--qt-gui" if build.with? "qt" # "--with-qt" ==> build.with? "qt" + # + # # If a formula presents a user with a choice, but the choice must be fulfilled: + # if build.with? "example2" + # args << "--with-example2" + # else + # args << "--with-example1" + # end</pre> def with?(val) name = val.respond_to?(:option_name) ? val.option_name : val @@ -20,47 +35,65 @@ class BuildOptions end end + # True if a {Formula} is being built without a specific option. + # <pre>args << "--no-spam-plz" if build.without? "spam" def without?(name) !with? name end + # True if a {Formula} is being built as a bottle (i.e. binary package). def bottle? include? "build-bottle" end + # True if a {Formula} is being built with {Formula.head} instead of {Formula.stable}. + # <pre>args << "--some-new-stuff" if build.head?</pre> + # <pre># If there are multiple conditional arguments use a block instead of lines. + # if build.head? + # args << "--i-want-pizza" + # args << "--and-a-cold-beer" if build.with? "cold-beer" + # end</pre> def head? include? "HEAD" end + # True if a {Formula} is being built with {Formula.devel} instead of {Formula.stable}. + # <pre>args << "--some-beta" if build.devel?</pre> def devel? include? "devel" end + # True if a {Formula} is being built with {Formula.stable} instead of {Formula.devel} or {Formula.head}. This is the default. + # <pre>args << "--some-beta" if build.devel?</pre> def stable? !(head? || devel?) end - # True if the user requested a universal build. + # True if a {Formula} is being built universally. + # e.g. on newer Intel Macs this means a combined x86_64/x86 binary/library. + # <pre>args << "--universal-binary" if build.universal?</pre> def universal? include?("universal") && option_defined?("universal") end - # True if the user requested to enable C++11 mode. + # True if a {Formula} is being built in C++11 mode. def cxx11? include?("c++11") && option_defined?("c++11") end - # Request a 32-bit only build. + # True if a {Formula} is being built in 32-bit/x86 mode. # This is needed for some use-cases though we prefer to build Universal # when a 32-bit version is needed. def build_32_bit? include?("32-bit") && option_defined?("32-bit") end + # @private def used_options @options & @args end + # @private def unused_options @options - @args end diff --git a/Library/Homebrew/cmd/create.rb b/Library/Homebrew/cmd/create.rb index 88b8c0df3..e83c9facd 100644 --- a/Library/Homebrew/cmd/create.rb +++ b/Library/Homebrew/cmd/create.rb @@ -118,7 +118,7 @@ class FormulaCreator def template; <<-EOS.undent # Documentation: https://github.com/Homebrew/homebrew/blob/master/share/doc/homebrew/Formula-Cookbook.md - # #{HOMEBREW_CONTRIB}/example-formula.rb + # http://www.rubydoc.info/github/Homebrew/homebrew/master/frames # PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST! class #{Formulary.class_s(name)} < Formula diff --git a/Library/Homebrew/cmd/man.rb b/Library/Homebrew/cmd/man.rb index 5c4abbe39..208c07d47 100644 --- a/Library/Homebrew/cmd/man.rb +++ b/Library/Homebrew/cmd/man.rb @@ -3,6 +3,7 @@ require "formula" module Homebrew SOURCE_PATH=HOMEBREW_REPOSITORY/"Library/Homebrew/manpages" TARGET_PATH=HOMEBREW_REPOSITORY/"share/man/man1" + DOC_PATH=HOMEBREW_REPOSITORY/"share/doc/homebrew" LINKED_PATH=HOMEBREW_PREFIX/"share/man/man1" def man @@ -21,12 +22,15 @@ module Homebrew else Homebrew.install_gem_setup_path! "ronn" + puts "Writing HTML fragments to #{DOC_PATH}" puts "Writing manpages to #{TARGET_PATH}" target_file = nil Dir["#{SOURCE_PATH}/*.md"].each do |source_file| - target_file = TARGET_PATH/File.basename(source_file, ".md") - safe_system "ronn --roff --pipe --organization='Homebrew' --manual='brew' #{source_file} > #{target_file}" + target_html = DOC_PATH/"#{File.basename(source_file, ".md")}.html" + safe_system "ronn --fragment --pipe --organization='Homebrew' --manual='brew' #{source_file} > #{target_html}" + target_man = TARGET_PATH/File.basename(source_file, ".md") + safe_system "ronn --roff --pipe --organization='Homebrew' --manual='brew' #{source_file} > #{target_man}" end system "man", target_file if ARGV.flag? "--verbose" diff --git a/Library/Homebrew/compilers.rb b/Library/Homebrew/compilers.rb index 4ed8c7f00..ab710a6d0 100644 --- a/Library/Homebrew/compilers.rb +++ b/Library/Homebrew/compilers.rb @@ -1,3 +1,4 @@ +# @private module CompilerConstants GNU_GCC_VERSIONS = %w[4.3 4.4 4.5 4.6 4.7 4.8 4.9 5] GNU_GCC_REGEXP = /^gcc-(4\.[3-9]|5)$/ diff --git a/Library/Homebrew/extend/ENV/shared.rb b/Library/Homebrew/extend/ENV/shared.rb index a85eff305..7553540c9 100644 --- a/Library/Homebrew/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/ENV/shared.rb @@ -1,12 +1,20 @@ require "formula" require "compilers" +# Homebrew extends Ruby's `ENV` to make our code more readable. +# Implemented in {SharedEnvExtension} and either {Superenv} or +# {Stdenv} (depending on the build mode). +# @see Superenv +# @see Stdenv +# @see http://www.rubydoc.info/stdlib/Env Ruby's ENV API module SharedEnvExtension include CompilerConstants + # @private CC_FLAG_VARS = %w[CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS] + # @private FC_FLAG_VARS = %w[FCFLAGS FFLAGS] - + # @private SANITIZED_VARS = %w[ CDPATH GREP_OPTIONS CLICOLOR_FORCE CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH @@ -18,11 +26,13 @@ module SharedEnvExtension LIBRARY_PATH ] + # @private def setup_build_environment(formula = nil) @formula = formula reset end + # @private def reset SANITIZED_VARS.each { |k| delete(k) } end @@ -72,6 +82,10 @@ module SharedEnvExtension append key, path, File::PATH_SEPARATOR if File.directory? path end + # Prepends a directory to `PATH`. + # Is the formula struggling to find the pkgconfig file? Point it to it. + # This is done automatically for `keg_only` formulae. + # <pre>ENV.prepend_path "PKG_CONFIG_PATH", "#{Formula["glib"].opt_lib}/pkgconfig"</pre> def prepend_path(key, path) prepend key, path, File::PATH_SEPARATOR if File.directory? path end @@ -126,6 +140,13 @@ module SharedEnvExtension self["FCFLAGS"] end + # Outputs the current compiler. + # @return [Symbol] + # <pre># Do something only for clang + # if ENV.compiler == :clang + # # modify CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS in one go: + # ENV.append_to_cflags "-I ./missing/includes" + # end</pre> def compiler @compiler ||= if (cc = ARGV.cc) warn_about_non_apple_gcc($&) if cc =~ GNU_GCC_REGEXP @@ -147,6 +168,7 @@ module SharedEnvExtension end end + # @private def determine_cc COMPILER_SYMBOL_MAP.invert.fetch(compiler, compiler) end @@ -159,13 +181,14 @@ module SharedEnvExtension end end - # Snow Leopard defines an NCURSES value the opposite of most distros + # Snow Leopard defines an NCURSES value the opposite of most distros. # See: https://bugs.python.org/issue6848 - # Currently only used by aalib in core + # Currently only used by aalib in core. def ncurses_define append "CPPFLAGS", "-DNCURSES_OPAQUE=0" end + # @private def userpaths! paths = ORIGINAL_PATHS.map { |p| p.realpath.to_s rescue nil } - %w[/usr/X11/bin /opt/X11/bin] self["PATH"] = paths.unshift(*self["PATH"].split(File::PATH_SEPARATOR)).uniq.join(File::PATH_SEPARATOR) @@ -212,12 +235,14 @@ module SharedEnvExtension end # ld64 is a newer linker provided for Xcode 2.5 + # @private def ld64 ld64 = Formulary.factory("ld64") self["LD"] = ld64.bin/"ld" append "LDFLAGS", "-B#{ld64.bin}/" end + # @private def gcc_version_formula(name) version = name[GNU_GCC_REGEXP, 1] gcc_version_name = "gcc#{version.delete(".")}" @@ -230,6 +255,7 @@ module SharedEnvExtension end end + # @private def warn_about_non_apple_gcc(name) begin gcc_formula = gcc_version_formula(name) diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb index d05ccf1a3..fef991540 100644 --- a/Library/Homebrew/extend/ENV/std.rb +++ b/Library/Homebrew/extend/ENV/std.rb @@ -2,9 +2,11 @@ require "hardware" require "os/mac" require "extend/ENV/shared" +# @deprecated module Stdenv include SharedEnvExtension + # @private SAFE_CFLAGS_FLAGS = "-w -pipe" DEFAULT_FLAGS = "-march=core2 -msse4" @@ -14,6 +16,7 @@ module Stdenv end end + # @private def setup_build_environment(formula = nil) super @@ -69,6 +72,7 @@ module Stdenv end end + # @private def determine_pkg_config_libdir paths = [] paths << "#{HOMEBREW_PREFIX}/lib/pkgconfig" @@ -106,11 +110,13 @@ module Stdenv end end + # @private def determine_cc s = super MacOS.locate(s) || Pathname.new(s) end + # @private def determine_cxx dir, base = determine_cc.split dir / base.to_s.sub("gcc", "g++").sub("clang", "clang++") @@ -295,6 +301,7 @@ module Stdenv end end + # @private def replace_in_cflags(before, after) CC_FLAG_VARS.each do |key| self[key] = self[key].sub(before, after) if key?(key) @@ -308,6 +315,7 @@ module Stdenv # Sets architecture-specific flags for every environment variable # given in the list `flags`. + # @private def set_cpu_flags(flags, default = DEFAULT_FLAGS, map = Hardware::CPU.optimization_flags) cflags =~ /(-Xarch_#{Hardware::CPU.arch_32_bit} )-march=/ xarch = $1.to_s @@ -319,6 +327,7 @@ module Stdenv append flags, map.fetch(effective_arch, default) end + # @private def effective_arch if ARGV.build_bottle? ARGV.bottle_arch || Hardware.oldest_cpu @@ -332,6 +341,7 @@ module Stdenv end end + # @private def set_cpu_cflags(default = DEFAULT_FLAGS, map = Hardware::CPU.optimization_flags) set_cpu_flags CC_FLAG_VARS, default, map end @@ -346,5 +356,6 @@ module Stdenv end # This method does nothing in stdenv since there's no arg refurbishment + # @private def refurbish_args; end end diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb index 95a8773cd..5216b579c 100644 --- a/Library/Homebrew/extend/ENV/super.rb +++ b/Library/Homebrew/extend/ENV/super.rb @@ -1,20 +1,23 @@ require "os/mac" require "extend/ENV/shared" -### Why `superenv`? -# 1) Only specify the environment we need (NO LDFLAGS for cmake) -# 2) Only apply compiler specific options when we are calling that compiler -# 3) Force all incpaths and libpaths into the cc instantiation (less bugs) -# 4) Cater toolchain usage to specific Xcode versions -# 5) Remove flags that we don't want or that will break builds -# 6) Simpler code -# 7) Simpler formula that *just work* -# 8) Build-system agnostic configuration of the tool-chain - +# ### Why `superenv`? +# +# 1. Only specify the environment we need (NO LDFLAGS for cmake) +# 2. Only apply compiler specific options when we are calling that compiler +# 3. Force all incpaths and libpaths into the cc instantiation (less bugs) +# 4. Cater toolchain usage to specific Xcode versions +# 5. Remove flags that we don't want or that will break builds +# 6. Simpler code +# 7. Simpler formula that *just work* +# 8. Build-system agnostic configuration of the tool-chain module Superenv include SharedEnvExtension - attr_accessor :keg_only_deps, :deps, :x11 + # @private + attr_accessor :keg_only_deps, :deps + + attr_accessor :x11 alias_method :x11?, :x11 def self.extended(base) @@ -22,6 +25,7 @@ module Superenv base.deps = [] end + # @private def self.bin return unless MacOS.has_apple_developer_tools? @@ -36,6 +40,7 @@ module Superenv delete("as_nl") end + # @private def setup_build_environment(formula = nil) super send(compiler) @@ -302,6 +307,7 @@ module Superenv append "HOMEBREW_CCCFG", "h", "" if compiler == :clang end + # @private def refurbish_args append "HOMEBREW_CCCFG", "O", "" end @@ -312,6 +318,7 @@ module Superenv end end + # @private def noop(*_args); end noops = [] diff --git a/Library/Homebrew/extend/fileutils.rb b/Library/Homebrew/extend/fileutils.rb index 741fca57f..a6321931c 100644 --- a/Library/Homebrew/extend/fileutils.rb +++ b/Library/Homebrew/extend/fileutils.rb @@ -1,7 +1,8 @@ require "fileutils" require "tmpdir" -# We enhance FileUtils to make our Formula code more readable. +# Homebrew extends Ruby's `FileUtils` to make our code more readable. +# @see http://ruby-doc.org/stdlib-1.8.7/libdoc/fileutils/rdoc/FileUtils.html Ruby's FileUtils API module FileUtils # Create a temporary directory then yield. When the block returns, # recursively delete the temporary directory. @@ -23,8 +24,10 @@ module FileUtils end module_function :mktemp - # A version of mkdir that also changes to that folder in a block. + # @private alias_method :old_mkdir, :mkdir + + # A version of mkdir that also changes to that folder in a block. def mkdir(name, &_block) old_mkdir(name) if block_given? @@ -42,6 +45,7 @@ module FileUtils # never backported into the 1.9.3 branch. Fixed in 2.0.0. # The monkey-patched method here is copied directly from upstream fix. if RUBY_VERSION < "2.0.0" + # @private class Entry_ alias_method :old_copy_metadata, :copy_metadata def copy_metadata(path) @@ -82,23 +86,27 @@ module FileUtils end end - private - - # Run scons using a Homebrew-installed version, instead of whatever - # is in the user's PATH + # Run `scons` using a Homebrew-installed version rather than whatever is in the `PATH`. def scons(*args) system Formulary.factory("scons").opt_bin/"scons", *args end + # Run the `rake` from the `ruby` Homebrew is using rather than whatever is in the `PATH`. def rake(*args) system RUBY_BIN/"rake", *args end - alias_method :old_ruby, :ruby if method_defined?(:ruby) + if method_defined?(:ruby) + # @private + alias_method :old_ruby, :ruby + end + + # Run the `ruby` Homebrew is using rather than whatever is in the `PATH`. def ruby(*args) system RUBY_PATH, *args end + # Run `xcodebuild` without Homebrew's compiler environment variables set. def xcodebuild(*args) removed = ENV.remove_cc_etc system "xcodebuild", *args diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index c71a636e9..ed831f2cb 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -3,12 +3,15 @@ require "mach" require "resource" require "metafiles" -# we enhance pathname to make our code more readable +# Homebrew extends Ruby's `Pathname` to make our code more readable. +# @see http://ruby-doc.org/stdlib-1.8.7/libdoc/pathname/rdoc/Pathname.html Ruby's Pathname API class Pathname include MachO + # @private BOTTLE_EXTNAME_RX = /(\.[a-z0-9_]+\.bottle\.(\d+\.)?tar\.gz)$/ + # Moves a file from the original location to the {Pathname}'s. def install(*sources) sources.each do |src| case src @@ -77,8 +80,12 @@ class Pathname end private :install_symlink_p + if method_defined?(:write) + # @private + alias_method :old_write, :write + end + # we assume this pathname object is a file obviously - alias_method :old_write, :write if method_defined?(:write) def write(content, *open_args) raise "Will not overwrite #{self}" if exist? dirname.mkpath @@ -131,6 +138,7 @@ class Pathname end private :default_stat + # @private def cp(dst) opoo "Pathname#cp is deprecated, use FileUtils.cp" if file? @@ -141,6 +149,7 @@ class Pathname dst end + # @private def cp_path_sub(pattern, replacement) raise "#{self} does not exist" unless self.exist? @@ -157,8 +166,10 @@ class Pathname end end - # extended to support common double extensions + # @private alias_method :extname_old, :extname + + # extended to support common double extensions def extname(path = to_s) BOTTLE_EXTNAME_RX.match(path) return $1 if $1 @@ -175,6 +186,7 @@ class Pathname # I don't trust the children.length == 0 check particularly, not to mention # it is slow to enumerate the whole directory just to see if it is empty, # instead rely on good ol' libc and the filesystem + # @private def rmdir_if_possible rmdir true @@ -189,17 +201,20 @@ class Pathname false end + # @private def chmod_R(perms) opoo "Pathname#chmod_R is deprecated, use FileUtils.chmod_R" require "fileutils" FileUtils.chmod_R perms, to_s end + # @private def version require "version" Version.parse(self) end + # @private def compression_type case extname when ".jar", ".war" @@ -240,10 +255,12 @@ class Pathname end end + # @private def text_executable? /^#!\s*\S+/ === open("r") { |f| f.read(1024) } end + # @private def incremental_hash(klass) digest = klass.new if digest.respond_to?(:file) @@ -255,6 +272,7 @@ class Pathname digest.hexdigest end + # @private def sha1 require "digest/sha1" incremental_hash(Digest::SHA1) @@ -282,10 +300,12 @@ class Pathname children.select(&:directory?) end + # @private def resolved_path self.symlink? ? dirname+readlink : self end + # @private def resolved_path_exists? link = readlink rescue ArgumentError @@ -295,6 +315,7 @@ class Pathname (dirname+link).exist? end + # @private def make_relative_symlink(src) dirname.mkpath File.symlink(src.relative_path_from(dirname), self) @@ -308,6 +329,7 @@ class Pathname self + other.to_s end unless method_defined?(:/) + # @private def ensure_writable saved_perms = nil unless writable_real? @@ -319,10 +341,12 @@ class Pathname chmod saved_perms if saved_perms end + # @private def install_info quiet_system "/usr/bin/install-info", "--quiet", to_s, "#{dirname}/dir" end + # @private def uninstall_info quiet_system "/usr/bin/install-info", "--delete", "--quiet", to_s, "#{dirname}/dir" end @@ -389,6 +413,7 @@ class Pathname end end + # @private def abv out = "" n = Utils.popen_read("find", expand_path.to_s, "-type", "f", "!", "-name", ".DS_Store").split("\n").size @@ -403,7 +428,9 @@ class Pathname # the Regexp literals, which forces string interpolation to happen only # once instead of each time the method is called. This is fixed in 1.9+. if RUBY_VERSION <= "1.8.7" + # @private alias_method :old_chop_basename, :chop_basename + def chop_basename(path) base = File.basename(path) if /\A#{Pathname::SEPARATOR_PAT}?\z/o =~ base @@ -414,7 +441,9 @@ class Pathname end private :chop_basename + # @private alias_method :old_prepend_prefix, :prepend_prefix + def prepend_prefix(prefix, relpath) if relpath.empty? File.dirname(prefix) @@ -437,6 +466,7 @@ class Pathname end end +# @private module ObserverPathnameExtension class << self attr_accessor :n, :d diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 7ec035dd7..7a9bb0f69 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -22,11 +22,38 @@ require "keg" # correspond. # Make sure you check with `brew search` that the name is free! # @abstract +# @see SharedEnvExtension +# @see FileUtils +# @see Pathname +# @see http://www.rubydoc.info/github/Homebrew/homebrew/file/share/doc/homebrew/Formula-Cookbook.md Formula Cookbook +# @see https://github.com/styleguide/ruby Ruby Style Guide +# +# <pre>class Wget < Formula +# homepage "https://www.gnu.org/software/wget/" +# url "https://ftp.gnu.org/gnu/wget/wget-1.15.tar.gz" +# sha256 "52126be8cf1bddd7536886e74c053ad7d0ed2aa89b4b630f76785bac21695fcd" +# +# def install +# system "./configure", "--prefix=#{prefix}" +# system "make", "install" +# end +# end</pre> class Formula include FileUtils include Utils::Inreplace extend Enumerable + # @!method inreplace(paths, before = nil, after = nil) + # Actually implemented in {Utils::Inreplace.inreplace}. + # Sometimes we have to change a bit before we install. Mostly we + # prefer a patch but if you need the `prefix` of this formula in the + # patch you have to resort to `inreplace`, because in the patch + # you don't have access to any var defined by the formula. Only + # HOMEBREW_PREFIX is available in the embedded patch. + # inreplace supports regular expressions. + # <pre>inreplace "somefile.cfg", /look[for]what?/, "replace by #{bin}/tool"</pre> + # @see Utils::Inreplace.inreplace + # The name of this {Formula}. # e.g. `this-formula` attr_reader :name @@ -43,12 +70,15 @@ class Formula # The stable (and default) {SoftwareSpec} for this {Formula} # This contains all the attributes (e.g. URL, checksum) that apply to the # stable version of this formula. + # @private + attr_reader :stable # The development {SoftwareSpec} for this {Formula}. # Installed when using `brew install --devel` # `nil` if there is no development version. # @see #stable + # @private attr_reader :devel # The HEAD {SoftwareSpec} for this {Formula}. @@ -57,6 +87,7 @@ class Formula # commit in the version control system. # `nil` if there is no HEAD version. # @see #stable + # @private attr_reader :head # The currently active {SoftwareSpec}. @@ -67,6 +98,7 @@ class Formula # A symbol to indicate currently active {SoftwareSpec}. # It's either :stable, :devel or :head # @see #active_spec + # @private attr_reader :active_spec_sym # Used for creating new Homebrew versions of software without new upstream @@ -84,12 +116,14 @@ class Formula # When installing a bottle (binary package) from a local path this will be # set to the full path to the bottle tarball. If not, it will be `nil`. + # @private attr_accessor :local_bottle_path # The {BuildOptions} for this {Formula}. Lists the arguments passed and any # {#options} in the {Formula}. Note that these may differ at different times # during the installation of a {Formula}. This is annoying but the result of # state that we're trying to eliminate. + # @return [BuildOptions] attr_accessor :build # @private @@ -165,16 +199,19 @@ class Formula public # Is the currently active {SoftwareSpec} a {#stable} build? + # @private def stable? active_spec == stable end # Is the currently active {SoftwareSpec} a {#devel} build? + # @private def devel? active_spec == devel end # Is the currently active {SoftwareSpec} a {#head} build? + # @private def head? active_spec == head end @@ -221,6 +258,9 @@ class Formula end # A named Resource for the currently active {SoftwareSpec}. + # Additional downloads can be defined as {#resource}s. + # {Resource#stage} will create a temporary directory and yield to a block. + # <pre>resource("additional_files").stage { bin.install "my/extra/tool" }</pre> def resource(name) active_spec.resource(name) end @@ -246,40 +286,49 @@ class Formula end # The {Dependency}s for the currently active {SoftwareSpec}. + # @private def deps active_spec.deps end # The {Requirement}s for the currently active {SoftwareSpec}. + # @private def requirements active_spec.requirements end # The cached download for the currently active {SoftwareSpec}. + # @private def cached_download active_spec.cached_download end # Deletes the download for the currently active {SoftwareSpec}. + # @private def clear_cache active_spec.clear_cache end # The list of patches for the currently active {SoftwareSpec}. + # @private def patchlist active_spec.patches end # The options for the currently active {SoftwareSpec}. + # @private def options active_spec.options end # The deprecated options for the currently active {SoftwareSpec}. + # @private def deprecated_options active_spec.deprecated_options end + # The deprecated option flags for the currently active {SoftwareSpec}. + # @private def deprecated_flags active_spec.deprecated_flags end @@ -290,6 +339,7 @@ class Formula end # All the {.fails_with} for the currently active {SoftwareSpec}. + # @private def compiler_failures active_spec.compiler_failures end @@ -297,11 +347,13 @@ class Formula # If this {Formula} is installed. # This is actually just a check for if the {#installed_prefix} directory # exists and is not empty. + # @private def installed? (dir = installed_prefix).directory? && dir.children.length > 0 end # If at least one version of {Formula} is installed. + # @private def any_version_installed? require "tab" rack.directory? && rack.subdirs.any? { |keg| (keg/Tab::FILENAME).file? } @@ -316,6 +368,7 @@ class Formula # The latest prefix for this formula. Checks for {#head}, then {#devel} # and then {#stable}'s {#prefix} + # @private def installed_prefix if head && (head_prefix = prefix(PkgVersion.new(head.version, revision))).directory? head_prefix @@ -330,6 +383,7 @@ class Formula # The currently installed version for this formula. Will raise an exception # if the formula is not installed. + # @private def installed_version Keg.new(installed_prefix).version end @@ -342,6 +396,7 @@ class Formula # The parent of the prefix; the named directory in the cellar containing all # installed versions of this software + # @private def rack prefix.parent end @@ -349,6 +404,12 @@ class Formula # The directory where the formula's binaries should be installed. # This is symlinked into `HOMEBREW_PREFIX` after installation or with # `brew link` for formulae that are not keg-only. + # + # Need to install into the {.bin} but the makefile doesn't mkdir -p prefix/bin? + # <pre>bin.mkpath</pre> + # + # No `make install` available? + # <pre>bin.install "binary1"</pre> def bin prefix+"bin" end @@ -363,6 +424,9 @@ class Formula # The directory where the formula's headers should be installed. # This is symlinked into `HOMEBREW_PREFIX` after installation or with # `brew link` for formulae that are not keg-only. + # + # No `make install` available? + # <pre>include.install "example.h"</pre> def include prefix+"include" end @@ -377,6 +441,9 @@ class Formula # The directory where the formula's libraries should be installed. # This is symlinked into `HOMEBREW_PREFIX` after installation or with # `brew link` for formulae that are not keg-only. + # + # No `make install` available? + # <pre>lib.install "example.dylib"</pre> def lib prefix+"lib" end @@ -402,6 +469,9 @@ class Formula # The directory where the formula's man1 pages should be installed. # This is symlinked into `HOMEBREW_PREFIX` after installation or with # `brew link` for formulae that are not keg-only. + # + # No `make install` available? + # <pre>man1.install "example.1"</pre> def man1 man+"man1" end @@ -416,6 +486,9 @@ class Formula # The directory where the formula's man3 pages should be installed. # This is symlinked into `HOMEBREW_PREFIX` after installation or with # `brew link` for formulae that are not keg-only. + # + # No `make install` available? + # <pre>man3.install "man.3"</pre> def man3 man+"man3" end @@ -466,6 +539,18 @@ class Formula # The directory where the formula's shared files should be installed. # This is symlinked into `HOMEBREW_PREFIX` after installation or with # `brew link` for formulae that are not keg-only. + # + # Need a custom directory? + # <pre>(share/"concept").mkpath</pre> + # + # Installing something into another custom directory? + # <pre>(share/"concept2").install "ducks.txt"</pre> + # + # Install `./example_code/simple/ones` to share/demos + # <pre>(share/"demos").install "example_code/simple/ones"</pre> + # + # Install `./example_code/simple/ones` to share/demos/examples + # <pre>(share/"demos").install "example_code/simple/ones" => "examples"</pre> def share prefix+"share" end @@ -474,6 +559,9 @@ class Formula # with the name of the formula appended to avoid linking conflicts. # This is symlinked into `HOMEBREW_PREFIX` after installation or with # `brew link` for formulae that are not keg-only. + # + # No `make install` available? + # <pre>pkgshare.install "examples"</pre> def pkgshare prefix+"share"+name end @@ -537,20 +625,49 @@ class Formula # The directory used for as the prefix for {#etc} and {#var} files on # installation so, despite not being in `HOMEBREW_CELLAR`, they are installed # there after pouring a bottle. + # @private def bottle_prefix prefix+".bottle" end + # The directory where the formula's installation logs will be written. + # @private def logs HOMEBREW_LOGS+name end - # override this to provide a plist + # This method can be overridden to provide a plist. + # For more examples read Apple's handy manpage: + # https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/plist.5.html + # <pre>def plist; <<-EOS.undent + # <?xml version="1.0" encoding="UTF-8"?> + # <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> + # <plist version="1.0"> + # <dict> + # <key>Label</key> + # <string>#{plist_name}</string> + # <key>ProgramArguments</key> + # <array> + # <string>#{opt_bin}/example</string> + # <string>--do-this</string> + # </array> + # <key>RunAtLoad</key> + # <true/> + # <key>KeepAlive</key> + # <true/> + # <key>StandardErrorPath</key> + # <string>/dev/null</string> + # <key>StandardOutPath</key> + # <string>/dev/null</string> + # </plist> + # EOS + #end</pre> def plist nil end alias_method :startup_plist, :plist - # plist name, i.e. the name of the launchd service + + # The {.plist} name (the name of the launchd service). def plist_name "homebrew.mxcl."+name end @@ -559,10 +676,12 @@ class Formula prefix+(plist_name+".plist") end + # @private def plist_manual self.class.plist_manual end + # @private def plist_startup self.class.plist_startup end @@ -573,6 +692,7 @@ class Formula # # This is the prefered way to refer a formula in plists or from another # formula, as the path is stable even when the software is updated. + # <pre>args << "--with-readline=#{Formula["readline"].opt_prefix}" if build.with? "readline"</pre> def opt_prefix Pathname.new("#{HOMEBREW_PREFIX}/opt/#{name}") end @@ -619,6 +739,7 @@ class Formula # Can be overridden to run commands on both source and bottle installation. def post_install; end + # @private def post_install_defined? method(:post_install).owner == self.class end @@ -631,7 +752,23 @@ class Formula self.build = build end - # tell the user about any caveats regarding this package, return a string + # Tell the user about any caveats regarding this package. + # @return [String] + # <pre>def caveats + # <<-EOS.undent + # Are optional. Something the user should know? + # EOS + # end</pre> + # + # <pre>def caveats + # s = <<-EOS.undent + # Print some important notice to the user when `brew info <formula>` is + # called or when brewing a formula. + # This is optional. You can use all the vars like #{version} here. + # EOS + # s += "Some issue only on older systems" if MacOS.version < :mountain_lion + # s + # end</pre> def caveats nil end @@ -642,6 +779,7 @@ class Formula keg_only_reason && keg_only_reason.valid? end + # @private def keg_only_reason self.class.keg_only_reason end @@ -651,6 +789,7 @@ class Formula # skip_clean "bin/foo", "lib/bar" # keep .la files with: # skip_clean :la + # @private def skip_clean?(path) return true if path.extname == ".la" && self.class.skip_clean_paths.include?(:la) to_check = path.relative_path_from(prefix).to_s @@ -662,6 +801,7 @@ class Formula # allow overwriting certain files. e.g. # link_overwrite "bin/foo", "lib/bar" # link_overwrite "share/man/man1/baz-*" + # @private def link_overwrite?(path) # Don't overwrite files not created by Homebrew. return false unless path.stat.uid == File.stat(HOMEBREW_BREW_FILE).uid @@ -685,10 +825,12 @@ class Formula false end + # @private def require_universal_deps? false end + # @private def patch unless patchlist.empty? ohai "Patching" @@ -710,6 +852,7 @@ class Formula end end + # @private def lock @lock = FormulaLock.new(name) @lock.lock @@ -719,27 +862,33 @@ class Formula end end + # @private def unlock @lock.unlock unless @lock.nil? @oldname_lock.unlock unless @oldname_lock.nil? end + # @private def pinnable? @pin.pinnable? end + # @private def pinned? @pin.pinned? end + # @private def pin @pin.pin end + # @private def unpin @pin.unpin end + # @private def ==(other) instance_of?(other.class) && name == other.name && @@ -747,10 +896,12 @@ class Formula end alias_method :eql?, :== + # @private def hash name.hash end + # @private def <=>(other) return unless Formula === other name <=> other.name @@ -760,10 +911,12 @@ class Formula name end + # @private def inspect "#<Formula #{name} (#{active_spec_sym}) #{path}>" end + # @private def file_modified? git = which("git") @@ -798,40 +951,48 @@ class Formula end # an array of all core {Formula} names + # @private def self.core_names @core_names ||= Dir["#{HOMEBREW_LIBRARY}/Formula/*.rb"].map { |f| File.basename f, ".rb" }.sort end # an array of all core {Formula} files + # @private def self.core_files @core_files ||= Pathname.glob("#{HOMEBREW_LIBRARY}/Formula/*.rb") end # an array of all tap {Formula} names + # @private def self.tap_names @tap_names ||= Tap.flat_map(&:formula_names).sort end # an array of all tap {Formula} files + # @private def self.tap_files @tap_files ||= Tap.flat_map(&:formula_files) end # an array of all {Formula} names + # @private def self.names @names ||= (core_names + tap_names.map { |name| name.split("/")[-1] }).sort.uniq end # an array of all {Formula} files + # @private def self.files @files ||= core_files + tap_files end # an array of all {Formula} names, which the tap formulae have the fully-qualified name + # @private def self.full_names @full_names ||= core_names + tap_names end + # @private def self.each files.each do |file| begin @@ -846,6 +1007,7 @@ class Formula end # An array of all racks currently installed. + # @private def self.racks @racks ||= if HOMEBREW_CELLAR.directory? HOMEBREW_CELLAR.subdirs.reject(&:symlink?) @@ -855,6 +1017,7 @@ class Formula end # An array of all installed {Formula} + # @private def self.installed @installed ||= racks.map do |rack| begin @@ -864,6 +1027,7 @@ class Formula end.compact end + # @private def self.aliases Dir["#{HOMEBREW_LIBRARY}/Aliases/*"].map { |f| File.basename f }.sort end @@ -872,10 +1036,12 @@ class Formula Formulary.factory(name) end + # @private def tap? HOMEBREW_TAP_DIR_REGEX === path end + # @private def tap if path.to_s =~ HOMEBREW_TAP_DIR_REGEX "#{$1}/#{$2}" @@ -884,6 +1050,7 @@ class Formula end end + # @private def print_tap_action(options = {}) if tap? verb = options[:verb] || "Installing" @@ -892,29 +1059,35 @@ class Formula end # True if this formula is provided by Homebrew itself + # @private def core_formula? path == Formulary.core_path(name) end + # @private def env self.class.env end + # @private def conflicts self.class.conflicts end # Returns a list of Dependency objects in an installable order, which # means if a depends on b then b will be ordered before a in this list + # @private def recursive_dependencies(&block) Dependency.expand(self, &block) end # The full set of Requirements for this formula's dependency tree. + # @private def recursive_requirements(&block) Requirement.expand(self, &block) end + # @private def to_hash hsh = { "name" => name, @@ -969,14 +1142,17 @@ class Formula hsh end + # @private def fetch active_spec.fetch end + # @private def verify_download_integrity(fn) active_spec.verify_download_integrity(fn) end + # @private def run_test old_home = ENV["HOME"] build, self.build = self.build, Tab.for_formula(self) @@ -992,17 +1168,28 @@ class Formula ENV["HOME"] = old_home end + # @private def test_defined? false end + # @private def test end + # @private def test_fixtures(file) HOMEBREW_LIBRARY.join("Homebrew", "test", "fixtures", file) end + # This method is overriden in {Formula} subclasses to provide the installation instructions. + # The sources (from {.url}) are downloaded, hash-checked and + # Homebrew changes into a temporary directory where the + # archive was unpacked or repository cloned. + # <pre>def install + # system "./configure", "--prefix=#{prefix}" + # system "make", "install" + # end</pre> def install end @@ -1018,8 +1205,29 @@ class Formula EOS end - # Pretty titles the command and buffers stdout/stderr - # Throws if there's an error + public + + # To call out to the system, we use the `system` method and we prefer + # you give the args separately as in the line below, otherwise a subshell + # has to be opened first. + # <pre>system "./bootstrap.sh", "--arg1", "--prefix=#{prefix}"</pre> + # + # For CMake we have some necessary defaults in {#std_cmake_args}: + # <pre>system "cmake", ".", *std_cmake_args</pre> + # + # If the arguments given to configure (or make or cmake) are depending + # on options defined above, we usually make a list first and then + # use the `args << if <condition>` to append to: + # <pre>args = ["--with-option1", "--with-option2"] + # + # # Most software still uses `configure` and `make`. + # # Check with `./configure --help` what our options are. + # system "./configure", "--disable-debug", "--disable-dependency-tracking", + # "--disable-silent-rules", "--prefix=#{prefix}", + # *args # our custom arg list (needs `*` to unpack) + # + # # If there is a "make", "install" available, please use it! + # system "make", "install"</pre> def system(cmd, *args) verbose = ARGV.verbose? # remove "boring" arguments so that the important ones are more likely to @@ -1178,13 +1386,17 @@ class Formula # A one-line description of the software. Used by users to get an overview # of the software and Homebrew maintainers. # Shows when running `brew info`. + # + # <pre>desc "Example formula"</pre> attr_rw :desc - # @!attribute [w] + # @!attribute [w] homepage # The homepage for the software. Used by users to get more information # about the software and Homebrew maintainers as a point of contact for # e.g. submitting patches. # Can be opened with running `brew home`. + # + # <pre>homepage "https://www.example.com"</pre> attr_rw :homepage # The `:startup` attribute set by {.plist_options}. @@ -1195,12 +1407,14 @@ class Formula # @private attr_reader :plist_manual - # @!attribute [w] + # @!attribute [w] revision # Used for creating new Homebrew versions of software without new upstream # versions. For example, if we bump the major version of a library this # {Formula} {.depends_on} then we may need to update the `revision` of this # {Formula} to install a new version linked against the new library version. # `0` if unset. + # + # <pre>revision 1</pre> attr_rw :revision # A list of the {.stable}, {.devel} and {.head} {SoftwareSpec}s. @@ -1212,6 +1426,15 @@ class Formula # @!attribute [w] url # The URL used to download the source for the {#stable} version of the formula. # We prefer `https` for security and proxy reasons. + # Optionally specify the download strategy with `:using => ...` + # `:git`, `:hg`, `:svn`, `:bzr`, `:cvs`, + # `:curl` (normal file download. Will also extract.) + # `:nounzip` (without extracting) + # `:post` (download via an HTTP POST) + # `S3DownloadStrategy` (download from S3 using signed request) + # + # <pre>url "https://packed.sources.and.we.prefer.https.example.com/archive-1.2.3.tar.bz2"</pre> + # <pre>url "https://some.dont.provide.archives.example.com", :using => :git, :tag => "1.2.3"</pre> def url(val, specs = {}) stable.url(val, specs) end @@ -1220,6 +1443,8 @@ class Formula # The version string for the {#stable} version of the formula. # The version is autodetected from the URL and/or tag so only needs to be # declared if it cannot be autodetected correctly. + # + # <pre>version "1.2-final"</pre> def version(val = nil) stable.version(val) end @@ -1230,45 +1455,100 @@ class Formula # there can be more than one. Generally we add them when the main {.url} # is unreliable. If {.url} is really unreliable then we may swap the # {.mirror} and {.url}. + # + # <pre>mirror "https://in.case.the.host.is.down.example.com" + # mirror "https://in.case.the.mirror.is.down.example.com</pre> def mirror(val) stable.mirror(val) end - # @!attribute [w] sha1 + # @!attribute [w] sha256 # @scope class # To verify the {#cached_download}'s integrity and security we verify the - # SHA-1 hash matches what we've declared in the {Formula}. To quickly fill + # SHA-256 hash matches what we've declared in the {Formula}. To quickly fill # this value you can leave it blank and run `brew fetch --force` and it'll # tell you the currently valid value. - - # @!attribute [w] sha256 - # @scope class - # Similar to {.sha1} but using a SHA-256 hash instead. - + # + # <pre>sha256 "2a2ba417eebaadcb4418ee7b12fe2998f26d6e6f7fda7983412ff66a741ab6f7"</pre> Checksum::TYPES.each do |type| define_method(type) { |val| stable.send(type, val) } end + # @!attribute [w] bottle + # Adds a {.bottle} {SoftwareSpec}. + # This provides a pre-built binary package built by the Homebrew maintainers for you. + # It will be installed automatically if there is a binary package for your platform and you haven't passed or previously used any options on this formula. + # If you maintain your own repository, you can add your own bottle links. + # https://github.com/Homebrew/homebrew/blob/master/share/doc/homebrew/Bottles.md + # You can ignore this block entirely if submitting to Homebrew/Homebrew, It'll be + # handled for you by the Brew Test Bot. + # + # <pre>bottle do + # root_url "http://mikemcquaid.com" # Optional root to calculate bottle URLs + # prefix "/opt/homebrew" # Optional HOMEBREW_PREFIX in which the bottles were built. + # cellar "/opt/homebrew/Cellar" # Optional HOMEBREW_CELLAR in which the bottles were built. + # revision 1 # Making the old bottle outdated without bumping the version/revision of the formula. + # sha256 "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865" => :yosemite + # sha256 "53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3" => :mavericks + # sha256 "1121cfccd5913f0a63fec40a6ffd44ea64f9dc135c66634ba001d10bcf4302a2" => :mountain_lion + # end</pre> def bottle(*, &block) stable.bottle(&block) end + # @private def build stable.build end + # @!attribute [w] stable + # Allows adding {.depends_on} and {#patch}es just to the {.stable} {SoftwareSpec}. + # This is required instead of using a conditional. + # It is preferrable to also pull the {url} and {.sha256} into the block if one is added. + # + # <pre>stable do + # url "https://example.com/foo-1.0.tar.gz" + # sha256 "2a2ba417eebaadcb4418ee7b12fe2998f26d6e6f7fda7983412ff66a741ab6f7" + # + # depends_on "libxml2" + # depends_on "libffi" + # end</pre> def stable(&block) @stable ||= SoftwareSpec.new return @stable unless block_given? @stable.instance_eval(&block) end + # @!attribute [w] devel + # Adds a {.devel} {SoftwareSpec}. + # This can be installed by passing the `--devel` option to allow + # installing non-stable (e.g. beta) versions of software. + # + # <pre>devel do + # url "https://example.com/archive-2.0-beta.tar.gz" + # sha256 "2a2ba417eebaadcb4418ee7b12fe2998f26d6e6f7fda7983412ff66a741ab6f7" + # + # depends_on "cairo" + # depends_on "pixman" + # end</pre> def devel(&block) @devel ||= SoftwareSpec.new return @devel unless block_given? @devel.instance_eval(&block) end + # @!attribute [w] head + # Adds a {.head} {SoftwareSpec}. + # This can be installed by passing the `--HEAD` option to allow + # installing software directly from a branch of a version-control repository. + # If called as a method this provides just the {url} for the {SoftwareSpec}. + # If a block is provided you can also add {.depends_on} and {#patch}es just to the {.head} {SoftwareSpec}. + # The download strategies (e.g. `:using =>`) are the same as for {url}. + # `master` is the default branch and doesn't need stating with a `:branch` parameter. + # <pre>head "https://we.prefer.https.over.git.example.com/.git"</pre> + # <pre>head "https://example.com/.git", :branch => "name_of_branch", :revision => "abc123"</pre> + # or (if autodetect fails): + # <pre>head "https://hg.is.awesome.but.git.has.won.example.com/", :using => :hg</pre> def head(val = nil, specs = {}, &block) @head ||= HeadSoftwareSpec.new if block_given? @@ -1280,7 +1560,13 @@ class Formula end end - # Define a named resource using a {SoftwareSpec} style block + # Additional downloads can be defined as resources and accessed in the + # install method. Resources can also be defined inside a stable, devel, or + # head block. This mechanism replaces ad-hoc "subformula" classes. + # <pre>resource "additional_files" do + # url "https://example.com/additional-stuff.tar.gz" + # sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2" + # end</pre> def resource(name, klass = Resource, &block) specs.each do |spec| spec.resource(name, klass, &block) unless spec.resource_defined?(name) @@ -1291,10 +1577,71 @@ class Formula specs.each { |spec| spec.go_resource(name, &block) } end + # The dependencies for this formula. Use strings for the names of other + # formulae. Homebrew provides some :special dependencies for stuff that + # requires certain extra handling (often changing some ENV vars or + # deciding if to use the system provided version or not.) + # <pre># `:build` means this dep is only needed during build. + # depends_on "cmake" => :build</pre> + # <pre>depends_on "homebrew/dupes/tcl-tk" => :optional</pre> + # <pre># `:recommended` dependencies are built by default. + # # But a `--without-...` option is generated to opt-out. + # depends_on "readline" => :recommended</pre> + # <pre># `:optional` dependencies are NOT built by default. + # # But a `--with-...` options is generated. + # depends_on "glib" => :optional</pre> + # <pre># If you need to specify that another formula has to be built with/out + # # certain options (note, no `--` needed before the option): + # depends_on "zeromq" => "with-pgm" + # depends_on "qt" => ["with-qtdbus", "developer"] # Multiple options.</pre> + # <pre># Optional and enforce that boost is built with `--with-c++11`. + # depends_on "boost" => [:optional, "with-c++11"]</pre> + # <pre># If a dependency is only needed in certain cases: + # depends_on "sqlite" if MacOS.version == :leopard + # depends_on :xcode # If the formula really needs full Xcode. + # depends_on :tex # Homebrew does not provide a Tex Distribution. + # depends_on :fortran # Checks that `gfortran` is available or `FC` is set. + # depends_on :mpi => :cc # Needs MPI with `cc` + # depends_on :mpi => [:cc, :cxx, :optional] # Is optional. MPI with `cc` and `cxx`. + # depends_on :macos => :lion # Needs at least Mac OS X "Lion" aka. 10.7. + # depends_on :apr # If a formula requires the CLT-provided apr library to exist. + # depends_on :arch => :intel # If this formula only builds on Intel architecture. + # depends_on :arch => :x86_64 # If this formula only builds on Intel x86 64-bit. + # depends_on :arch => :ppc # Only builds on PowerPC? + # depends_on :ld64 # Sometimes ld fails on `MacOS.version < :leopard`. Then use this. + # depends_on :x11 # X11/XQuartz components. Non-optional X11 deps should go in Homebrew/Homebrew-x11 + # depends_on :osxfuse # Permits the use of the upstream signed binary or our source package. + # depends_on :tuntap # Does the same thing as above. This is vital for Yosemite and above. + # depends_on :mysql => :recommended</pre> + # <pre># It is possible to only depend on something if + # # `build.with?` or `build.without? "another_formula"`: + # depends_on :mysql # allows brewed or external mysql to be used + # depends_on :postgresql if build.without? "sqlite" + # depends_on :hg # Mercurial (external or brewed) is needed</pre> + # + # <pre># If any Python >= 2.7 < 3.x is okay (either from OS X or brewed): + # depends_on :python</pre> + # <pre># to depend on Python >= 2.7 but use system Python where possible + # depends_on :python if MacOS.version <= :snow_leopard</pre> + # <pre># Python 3.x if the `--with-python3` is given to `brew install example` + # depends_on :python3 => :optional</pre> def depends_on(dep) specs.each { |spec| spec.depends_on(dep) } end + # @!attribute [w] option + # Options can be used as arguments to `brew install`. + # To switch features on/off: `"with-something"` or `"with-otherthing"`. + # To use other software: `"with-other-software"` or `"without-foo"` + # Note, that for {.depends_on} that are `:optional` or `:recommended`, options + # are generated automatically. + # + # There are also some special options: + # - `:universal`: build a universal binary/library (e.g. on newer Intel Macs + # this means a combined x86_64/x86 binary/library). + # <pre>option "with-spam", "The description goes here without a dot at the end"</pre> + # <pre>option "with-qt", "Text here overwrites the autogenerated one from 'depends_on "qt" => :optional'"</pre> + # <pre>option :universal</pre> def option(name, description = "") specs.each { |spec| spec.option(name, description) } end @@ -1303,19 +1650,62 @@ class Formula specs.each { |spec| spec.deprecated_option(hash) } end + # External patches can be declared using resource-style blocks. + # <pre>patch do + # url "https://example.com/example_patch.diff" + # sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2" + # end</pre> + # + # A strip level of `-p1` is assumed. It can be overridden using a symbol + # argument: + # <pre>patch :p0 do + # url "https://example.com/example_patch.diff" + # sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2" + # end</pre> + # + # Patches can be declared in stable, devel, and head blocks. This form is + # preferred over using conditionals. + # <pre>stable do + # patch do + # url "https://example.com/example_patch.diff" + # sha256 "c6bc3f48ce8e797854c4b865f6a8ff969867bbcaebd648ae6fd825683e59fef2" + # end + # end</pre> + # + # Embedded (`__END__`) patches are declared like so: + # <pre>patch :DATA + # patch :p0, :DATA</pre> + # + # Patches can also be embedded by passing a string. This makes it possible + # to provide multiple embedded patches while making only some of them + # conditional. + # <pre>patch :p0, "..."</pre> def patch(strip = :p1, src = nil, &block) specs.each { |spec| spec.patch(strip, src, &block) } end + # Defines launchd plist handling. + # + # Does your plist need to be loaded at startup? + # <pre>plist_options :startup => true</pre> + # + # Or only when necessary or desired by the user? + # <pre>plist_options :manual => "foo"</pre> + # + # Or perhaps you'd like to give the user a choice? Ooh fancy. + # <pre>plist_options :startup => "true", :manual => "foo start"</pre> def plist_options(options) @plist_startup = options[:startup] @plist_manual = options[:manual] end + # @private def conflicts @conflicts ||= [] end + # If this formula conflicts with another one. + # <pre>conflicts_with "imagemagick", :because => "because this is just a stupid example"</pre> def conflicts_with(*names) opts = Hash === names.last ? names.pop : {} names.each { |name| conflicts << FormulaConflict.new(name, opts[:because]) } @@ -1327,10 +1717,19 @@ class Formula skip_clean_paths.merge(paths) end + # @private def skip_clean_paths @skip_clean_paths ||= Set.new end + # Software that will not be sym-linked into the `brew --prefix` will only + # live in its Cellar. Other formulae can depend on it and then brew will + # add the necessary includes and libs (etc.) during the brewing of that + # other formula. But generally, keg_only formulae are not in your PATH + # and not seen by compilers if you build your own software outside of + # Homebrew. This way, we don't shadow software provided by OS X. + # <pre>keg_only :provided_by_osx</pre> + # <pre>keg_only "because I want it so"</pre> def keg_only(reason, explanation = "") @keg_only_reason = KegOnlyReason.new(reason, explanation) end @@ -1340,22 +1739,21 @@ class Formula define_method(:skip_cxxstdlib_check?) { true } if check_type == :skip end + # Marks the {Formula} as failing with a particular compiler so it will fall back to others. # For Apple compilers, this should be in the format: - # fails_with compiler do - # cause "An explanation for why the build doesn't work." - # build "The Apple build number for the newest incompatible release." + # <pre>fails_with :llvm do # :llvm is really llvm-gcc + # build 2334 + # cause "Segmentation fault during linking." # end # + # fails_with :clang do + # build 600 + # cause "multiple configure and compile errors" + # end</pre> + # # The block may be omitted, and if present the build may be omitted; # if so, then the compiler will be blacklisted for *all* versions. # - # For GNU GCC compilers, this should be in the format: - # fails_with compiler => major_version do - # cause - # version "The official release number for the latest incompatible - # version, for instance 4.8.1" - # end - # # `major_version` should be the major release number only, for instance # '4.8' for the GCC 4.8 series (4.8.0, 4.8.1, etc.). # If `version` or the block is omitted, then the compiler will be @@ -1364,9 +1762,9 @@ class Formula # For example, if a bug is only triggered on GCC 4.8.1 but is not # encountered on 4.8.2: # - # fails_with :gcc => '4.8' do + # <pre>fails_with :gcc => '4.8' do # version '4.8.1' - # end + # end</pre> def fails_with(compiler, &block) specs.each { |spec| spec.fails_with(compiler, &block) } end @@ -1375,15 +1773,42 @@ class Formula specs.each { |spec| spec.needs(*standards) } end + # Test (is required for new formula and makes us happy). + # @return [Boolean] + # + # The block will create, run in and delete a temporary directory. + # + # We are fine if the executable does not error out, so we know linking + # and building the software was ok. + # <pre>system bin/"foobar", "--version"</pre> + # + # <pre>(testpath/"test.file").write <<-EOS.undent + # writing some test file, if you need to + # EOS + # assert_equal "OK", shell_output("test_command test.file").strip</pre> + # + # Need complete control over stdin, stdout? + # <pre>require "open3" + # Open3.popen3("#{bin}/example", "argument") do |stdin, stdout, _| + # stdin.write("some text") + # stdin.close + # assert_equal "result", stdout.read + # end</pre> + # + # The test will fail if it returns false, or if an exception is raised. + # Failed assertions and failed `system` commands will raise exceptions. + def test(&block) define_method(:test, &block) end + # @private def link_overwrite(*paths) paths.flatten! link_overwrite_paths.merge(paths) end + # @private def link_overwrite_paths @link_overwrite_paths ||= Set.new end diff --git a/Library/Homebrew/mach.rb b/Library/Homebrew/mach.rb index f7ca428e6..49382291c 100644 --- a/Library/Homebrew/mach.rb +++ b/Library/Homebrew/mach.rb @@ -1,21 +1,26 @@ module ArchitectureListExtension + # @private def fat? length > 1 end + # @private def intel_universal? intersects_all?(Hardware::CPU::INTEL_32BIT_ARCHS, Hardware::CPU::INTEL_64BIT_ARCHS) end + # @private def ppc_universal? intersects_all?(Hardware::CPU::PPC_32BIT_ARCHS, Hardware::CPU::PPC_64BIT_ARCHS) end # Old-style 32-bit PPC/Intel universal, e.g. ppc7400 and i386 + # @private def cross_universal? intersects_all?(Hardware::CPU::PPC_32BIT_ARCHS, Hardware::CPU::INTEL_32BIT_ARCHS) end + # @private def universal? intel_universal? || ppc_universal? || cross_universal? end @@ -24,6 +29,7 @@ module ArchitectureListExtension (Hardware::CPU::PPC_32BIT_ARCHS+Hardware::CPU::PPC_64BIT_ARCHS).any? { |a| self.include? a } end + # @private def remove_ppc! (Hardware::CPU::PPC_32BIT_ARCHS+Hardware::CPU::PPC_64BIT_ARCHS).each { |a| delete a } end @@ -46,12 +52,13 @@ module ArchitectureListExtension end module MachO + # @private OTOOL_RX = /\t(.*) \(compatibility version (?:\d+\.)*\d+, current version (?:\d+\.)*\d+\)/ # Mach-O binary methods, see: # /usr/include/mach-o/loader.h # /usr/include/mach-o/fat.h - + # @private def mach_data @mach_data ||= begin offsets = [] @@ -132,18 +139,22 @@ module MachO arch == :ppc64 end + # @private def dylib? mach_data.any? { |m| m.fetch(:type) == :dylib } end + # @private def mach_o_executable? mach_data.any? { |m| m.fetch(:type) == :executable } end + # @private def mach_o_bundle? mach_data.any? { |m| m.fetch(:type) == :bundle } end + # @private class Metadata attr_reader :path, :dylib_id, :dylibs @@ -171,6 +182,7 @@ module MachO end end + # @private def mach_metadata @mach_metadata ||= Metadata.new(self) end @@ -180,10 +192,12 @@ module MachO # to be absolute paths. # Returns an empty array both for software that links against no libraries, # and for non-mach objects. + # @private def dynamically_linked_libraries mach_metadata.dylibs end + # @private def dylib_id mach_metadata.dylib_id end diff --git a/Library/Homebrew/manpages/brew.1.md b/Library/Homebrew/manpages/brew.1.md index 2ef86a169..71b5dc3df 100644 --- a/Library/Homebrew/manpages/brew.1.md +++ b/Library/Homebrew/manpages/brew.1.md @@ -92,7 +92,7 @@ Note that these flags should only appear after a command. and version, but if it fails, you'll have to make your own template. The wget formula serves as a simple example. For a complete cheat-sheet, have a look at - `$(brew --repository)/Library/Contributions/example-formula.rb` + <http://www.rubydoc.info/github/Homebrew/homebrew/master/frames> If `--autotools` is passed, create a basic template for an Autotools-style build. If `--cmake` is passed, create a basic template for a CMake-style build. diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index 63cdaadfa..84e2363ca 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -80,6 +80,7 @@ def oh1(title) puts "#{Tty.green}==>#{Tty.white} #{title}#{Tty.reset}" end +# Print a warning (do this rarely) def opoo(warning) $stderr.puts "#{Tty.yellow}Warning#{Tty.reset}: #{warning}" end diff --git a/Library/Homebrew/utils/inreplace.rb b/Library/Homebrew/utils/inreplace.rb index 8ed32bc5b..ee47da457 100644 --- a/Library/Homebrew/utils/inreplace.rb +++ b/Library/Homebrew/utils/inreplace.rb @@ -8,6 +8,13 @@ module Utils end module Inreplace + # Sometimes we have to change a bit before we install. Mostly we + # prefer a patch but if you need the `prefix` of this formula in the + # patch you have to resort to `inreplace`, because in the patch + # you don't have access to any var defined by the formula. Only + # HOMEBREW_PREFIX is available in the embedded patch. + # inreplace supports regular expressions. + # <pre>inreplace "somefile.cfg", /look[for]what?/, "replace by #{bin}/tool"</pre> def inreplace(paths, before = nil, after = nil) errors = {} |
