aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
Diffstat (limited to 'Library')
-rw-r--r--Library/.rubocop.yml18
-rw-r--r--Library/Homebrew/PATH.rb74
-rw-r--r--Library/Homebrew/brew.rb17
-rw-r--r--Library/Homebrew/brew.sh7
-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/cask.rb52
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/doctor.rb2
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/reinstall.rb28
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/search.rb36
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/uninstall.rb10
-rw-r--r--Library/Homebrew/cask/lib/hbc/container.rb2
-rw-r--r--Library/Homebrew/cask/lib/hbc/dsl/container.rb9
-rw-r--r--Library/Homebrew/cask/lib/hbc/installer.rb41
-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/utils.rb13
-rw-r--r--Library/Homebrew/caveats.rb10
-rw-r--r--Library/Homebrew/cmd/--env.rb4
-rw-r--r--Library/Homebrew/cmd/install.rb5
-rw-r--r--Library/Homebrew/cmd/link.rb4
-rw-r--r--Library/Homebrew/cmd/postinstall.rb5
-rw-r--r--Library/Homebrew/cmd/search.rb95
-rw-r--r--Library/Homebrew/cmd/sh.rb2
-rw-r--r--Library/Homebrew/cmd/style.rb42
-rw-r--r--Library/Homebrew/cmd/tap.rb13
-rw-r--r--Library/Homebrew/cmd/update.sh2
-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/dependable.rb2
-rw-r--r--Library/Homebrew/dev-cmd/audit.rb460
-rw-r--r--Library/Homebrew/dev-cmd/create.rb56
-rw-r--r--Library/Homebrew/dev-cmd/mirror.rb6
-rw-r--r--Library/Homebrew/dev-cmd/pull.rb6
-rw-r--r--Library/Homebrew/dev-cmd/tap-new.rb6
-rw-r--r--Library/Homebrew/dev-cmd/tests.rb39
-rw-r--r--Library/Homebrew/diagnostic.rb13
-rw-r--r--Library/Homebrew/download_strategy.rb3
-rw-r--r--Library/Homebrew/exceptions.rb84
-rw-r--r--Library/Homebrew/extend/ENV.rb7
-rw-r--r--Library/Homebrew/extend/ENV/shared.rb40
-rw-r--r--Library/Homebrew/extend/ENV/std.rb13
-rw-r--r--Library/Homebrew/extend/ENV/super.rb88
-rw-r--r--Library/Homebrew/extend/io.rb15
-rw-r--r--Library/Homebrew/extend/os/linux/requirements/osxfuse_requirement.rb39
-rw-r--r--Library/Homebrew/extend/os/mac/diagnostic.rb2
-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/requirements/osxfuse_requirement.rb34
-rw-r--r--Library/Homebrew/extend/os/requirements/osxfuse_requirement.rb7
-rw-r--r--Library/Homebrew/extend/pathname.rb6
-rw-r--r--Library/Homebrew/formula.rb47
-rw-r--r--Library/Homebrew/formula_cellar_checks.rb24
-rw-r--r--Library/Homebrew/formula_installer.rb93
-rw-r--r--Library/Homebrew/formula_support.rb16
-rw-r--r--Library/Homebrew/formula_versions.rb45
-rw-r--r--Library/Homebrew/formulary.rb23
-rw-r--r--Library/Homebrew/global.rb6
-rw-r--r--Library/Homebrew/gpg.rb5
-rw-r--r--Library/Homebrew/hardware.rb12
-rw-r--r--Library/Homebrew/keg.rb5
-rw-r--r--Library/Homebrew/language/python.rb23
-rw-r--r--Library/Homebrew/manpages/brew.1.md.erb39
-rw-r--r--Library/Homebrew/missing_formula.rb2
-rw-r--r--Library/Homebrew/official_taps.rb21
-rw-r--r--Library/Homebrew/os/mac.rb2
-rw-r--r--Library/Homebrew/os/mac/xcode.rb15
-rw-r--r--Library/Homebrew/os/mac/xquartz.rb1
-rw-r--r--Library/Homebrew/readall.rb23
-rw-r--r--Library/Homebrew/requirement.rb10
-rw-r--r--Library/Homebrew/requirements/osxfuse_requirement.rb30
-rw-r--r--Library/Homebrew/rubocops.rb3
-rw-r--r--Library/Homebrew/rubocops/bottle_block_cop.rb6
-rw-r--r--Library/Homebrew/rubocops/components_order_cop.rb114
-rw-r--r--Library/Homebrew/rubocops/components_redundancy_cop.rb33
-rw-r--r--Library/Homebrew/rubocops/extend/formula_cop.rb303
-rw-r--r--Library/Homebrew/rubocops/formula_desc_cop.rb4
-rw-r--r--Library/Homebrew/rubocops/homepage_cop.rb82
-rw-r--r--Library/Homebrew/sandbox.rb4
-rwxr-xr-xLibrary/Homebrew/shims/scm/git1
-rw-r--r--Library/Homebrew/software_spec.rb9
-rw-r--r--Library/Homebrew/tap.rb16
-rw-r--r--Library/Homebrew/test/.bundle/config1
-rw-r--r--Library/Homebrew/test/Gemfile.lock42
-rw-r--r--Library/Homebrew/test/PATH_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/install_spec.rb14
-rw-r--r--Library/Homebrew/test/cask/cli/reinstall_spec.rb23
-rw-r--r--Library/Homebrew/test/cask/cli/search_spec.rb6
-rw-r--r--Library/Homebrew/test/cask/cli/style_spec.rb2
-rw-r--r--Library/Homebrew/test/cask/cli/uninstall_spec.rb21
-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/cmd/bundle_spec.rb2
-rw-r--r--Library/Homebrew/test/cmd/install_spec.rb12
-rw-r--r--Library/Homebrew/test/cmd/search_remote_tap_spec.rb14
-rw-r--r--Library/Homebrew/test/compiler_selector_spec.rb12
-rw-r--r--Library/Homebrew/test/dev-cmd/audit_spec.rb426
-rw-r--r--Library/Homebrew/test/dev-cmd/pull_spec.rb4
-rw-r--r--Library/Homebrew/test/diagnostic_spec.rb25
-rw-r--r--Library/Homebrew/test/formula_spec.rb18
-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.rb2
-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.rb2
-rw-r--r--Library/Homebrew/test/rubocops/components_order_cop_spec.rb163
-rw-r--r--Library/Homebrew/test/rubocops/components_redundancy_cop_spec.rb87
-rw-r--r--Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb27
-rw-r--r--Library/Homebrew/test/rubocops/homepage_cop_spec.rb124
-rw-r--r--Library/Homebrew/test/spec_helper.rb5
-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/support/helper/spec/shared_context/integration_test.rb1
-rw-r--r--Library/Homebrew/test/utils/github_spec.rb13
-rw-r--r--Library/Homebrew/test/utils/shell_spec.rb56
-rw-r--r--Library/Homebrew/test/utils_spec.rb8
-rw-r--r--Library/Homebrew/test/version_spec.rb5
-rw-r--r--Library/Homebrew/utils.rb41
-rw-r--r--Library/Homebrew/utils/analytics.sh2
-rw-r--r--Library/Homebrew/utils/github.rb14
-rw-r--r--Library/Homebrew/utils/shell.rb106
-rw-r--r--Library/Homebrew/vendor/README.md2
-rwxr-xr-xLibrary/Homebrew/vendor/plist/plist.rb6
-rwxr-xr-x[-rw-r--r--]Library/Homebrew/vendor/plist/plist/generator.rb10
-rwxr-xr-x[-rw-r--r--]Library/Homebrew/vendor/plist/plist/parser.rb37
-rwxr-xr-xLibrary/Homebrew/vendor/plist/plist/version.rb5
-rw-r--r--Library/Homebrew/version.rb5
143 files changed, 2925 insertions, 1391 deletions
diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml
index a782c1117..12886a508 100644
--- a/Library/.rubocop.yml
+++ b/Library/.rubocop.yml
@@ -8,10 +8,19 @@ AllCops:
require: ./Homebrew/rubocops.rb
-Homebrew/CorrectBottleBlock:
+FormulaAuditStrict/BottleBlock:
Enabled: true
-Homebrew/FormulaDesc:
+FormulaAuditStrict/Desc:
+ Enabled: true
+
+FormulaAuditStrict/ComponentsOrder:
+ Enabled: true
+
+FormulaAuditStrict/ComponentsRedundancy:
+ Enabled: true
+
+FormulaAudit/Homepage:
Enabled: true
Metrics/AbcSize:
@@ -34,6 +43,11 @@ Metrics/MethodLength:
Metrics/ModuleLength:
CountComments: false
+ Exclude:
+ - '**/bin/**/*'
+ - '**/cmd/**/*'
+ - '**/lib/**/*'
+ - '**/spec/**/*'
Metrics/PerceivedComplexity:
Enabled: false
diff --git a/Library/Homebrew/PATH.rb b/Library/Homebrew/PATH.rb
new file mode 100644
index 000000000..de7167eb4
--- /dev/null
+++ b/Library/Homebrew/PATH.rb
@@ -0,0 +1,74 @@
+class PATH
+ include Enumerable
+ extend Forwardable
+
+ def_delegator :@paths, :each
+
+ def initialize(*paths)
+ @paths = parse(*paths)
+ end
+
+ def prepend(*paths)
+ @paths = parse(*paths, *@paths)
+ self
+ end
+
+ def append(*paths)
+ @paths = parse(*@paths, *paths)
+ self
+ end
+
+ def insert(index, *paths)
+ @paths = parse(*@paths.insert(index, *paths))
+ self
+ end
+
+ def select(&block)
+ self.class.new(@paths.select(&block))
+ end
+
+ def reject(&block)
+ self.class.new(@paths.reject(&block))
+ end
+
+ def to_ary
+ @paths
+ end
+ alias to_a to_ary
+
+ def to_str
+ @paths.join(File::PATH_SEPARATOR)
+ end
+ alias to_s to_str
+
+ def ==(other)
+ if other.respond_to?(:to_ary)
+ return true if to_ary == other.to_ary
+ end
+
+ if other.respond_to?(:to_str)
+ return true if to_str == other.to_str
+ end
+
+ false
+ end
+
+ def empty?
+ @paths.empty?
+ end
+
+ def existing
+ existing_path = select(&File.method(:directory?))
+ # return nil instead of empty PATH, to unset environment variables
+ existing_path unless existing_path.empty?
+ end
+
+ private
+
+ def parse(*paths)
+ paths.flatten
+ .compact
+ .flat_map { |p| Pathname.new(p).to_path.split(File::PATH_SEPARATOR) }
+ .uniq
+ end
+end
diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb
index aa38b54f4..e07599ac6 100644
--- a/Library/Homebrew/brew.rb
+++ b/Library/Homebrew/brew.rb
@@ -12,9 +12,9 @@ require "pathname"
HOMEBREW_LIBRARY_PATH = Pathname.new(__FILE__).realpath.parent
$:.unshift(HOMEBREW_LIBRARY_PATH.to_s)
require "global"
+require "tap"
if ARGV == %w[--version] || ARGV == %w[-v]
- require "tap"
puts "Homebrew #{HOMEBREW_VERSION}"
puts "Homebrew/homebrew-core #{CoreTap.instance.version_string}"
exit 0
@@ -23,8 +23,7 @@ end
def require?(path)
require path
rescue LoadError => e
- # HACK: ( because we should raise on syntax errors but
- # not if the file doesn't exist. TODO make robust!
+ # we should raise on syntax errors but not if the file doesn't exist.
raise unless e.to_s.include? path
end
@@ -48,13 +47,15 @@ begin
end
end
+ path = PATH.new(ENV["PATH"])
+
# Add contributed commands to PATH before checking.
- Dir["#{HOMEBREW_LIBRARY}/Taps/*/*/cmd"].each do |tap_cmd_dir|
- ENV["PATH"] += "#{File::PATH_SEPARATOR}#{tap_cmd_dir}"
- end
+ path.append(Pathname.glob(Tap::TAP_DIRECTORY/"*/*/cmd"))
# Add SCM wrappers.
- ENV["PATH"] += "#{File::PATH_SEPARATOR}#{HOMEBREW_SHIMS_PATH}/scm"
+ path.append(HOMEBREW_SHIMS_PATH/"scm")
+
+ ENV["PATH"] = path
if cmd
internal_cmd = require? HOMEBREW_LIBRARY_PATH.join("cmd", cmd)
@@ -122,7 +123,7 @@ rescue SystemExit => e
onoe "Kernel.exit" if ARGV.verbose? && !e.success?
$stderr.puts e.backtrace if ARGV.debug?
raise
-rescue Interrupt => e
+rescue Interrupt
$stderr.puts # seemingly a newline is typical
exit 130
rescue BuildError => e
diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh
index 11c1a6c59..02ce5e1c1 100644
--- a/Library/Homebrew/brew.sh
+++ b/Library/Homebrew/brew.sh
@@ -2,7 +2,7 @@ HOMEBREW_VERSION="$(git -C "$HOMEBREW_REPOSITORY" describe --tags --dirty 2>/dev
HOMEBREW_USER_AGENT_VERSION="$HOMEBREW_VERSION"
if [[ -z "$HOMEBREW_VERSION" ]]
then
- HOMEBREW_VERSION=">1.1.0 (no git repository)"
+ HOMEBREW_VERSION=">1.2.0 (no git repository)"
HOMEBREW_USER_AGENT_VERSION="1.X.Y"
fi
@@ -101,6 +101,8 @@ then
[[ "$HOMEBREW_PROCESSOR" = "i386" ]] && HOMEBREW_PROCESSOR="Intel"
HOMEBREW_MACOS_VERSION="$(/usr/bin/sw_vers -productVersion)"
HOMEBREW_OS_VERSION="macOS $HOMEBREW_MACOS_VERSION"
+ # Don't change this from Mac OS X to match what macOS itself does in Safari on 10.12
+ HOMEBREW_OS_USER_AGENT_VERSION="Mac OS X $HOMEBREW_MACOS_VERSION"
printf -v HOMEBREW_MACOS_VERSION_NUMERIC "%02d%02d%02d" ${HOMEBREW_MACOS_VERSION//./ }
if [[ "$HOMEBREW_MACOS_VERSION_NUMERIC" -lt "100900" &&
@@ -113,8 +115,9 @@ else
HOMEBREW_PRODUCT="${HOMEBREW_SYSTEM}brew"
[[ -n "$HOMEBREW_LINUX" ]] && HOMEBREW_OS_VERSION="$(lsb_release -sd 2>/dev/null)"
: "${HOMEBREW_OS_VERSION:=$(uname -r)}"
+ HOMEBREW_OS_USER_AGENT_VERSION="$HOMEBREW_OS_VERSION"
fi
-HOMEBREW_USER_AGENT="$HOMEBREW_PRODUCT/$HOMEBREW_USER_AGENT_VERSION ($HOMEBREW_SYSTEM; $HOMEBREW_PROCESSOR $HOMEBREW_OS_VERSION)"
+HOMEBREW_USER_AGENT="$HOMEBREW_PRODUCT/$HOMEBREW_USER_AGENT_VERSION ($HOMEBREW_SYSTEM; $HOMEBREW_PROCESSOR $HOMEBREW_OS_USER_AGENT_VERSION)"
HOMEBREW_CURL_VERSION="$("$HOMEBREW_CURL" --version 2>/dev/null | head -n1 | /usr/bin/awk '{print $1"/"$2}')"
HOMEBREW_USER_AGENT_CURL="$HOMEBREW_USER_AGENT $HOMEBREW_CURL_VERSION"
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/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/reinstall.rb b/Library/Homebrew/cask/lib/hbc/cli/reinstall.rb
index b52c43328..c2ed8f462 100644
--- a/Library/Homebrew/cask/lib/hbc/cli/reinstall.rb
+++ b/Library/Homebrew/cask/lib/hbc/cli/reinstall.rb
@@ -7,30 +7,10 @@ module Hbc
begin
cask = CaskLoader.load(cask_token)
- installer = Installer.new(cask,
- force: force,
- skip_cask_deps: skip_cask_deps,
- require_sha: require_sha)
- installer.print_caveats
- installer.fetch
-
- if cask.installed?
- # use copy of cask for uninstallation to avoid 'No such file or directory' bug
- installed_cask = cask
-
- # use the same cask file that was used for installation, if possible
- if (installed_caskfile = installed_cask.installed_caskfile).exist?
- installed_cask = CaskLoader.load_from_file(installed_caskfile)
- end
-
- # Always force uninstallation, ignore method parameter
- Installer.new(installed_cask, force: true).uninstall
- end
-
- installer.stage
- installer.install_artifacts
- installer.enable_accessibility_access
- puts installer.summary
+ Installer.new(cask,
+ force: force,
+ skip_cask_deps: skip_cask_deps,
+ require_sha: require_sha).reinstall
count += 1
rescue CaskUnavailableError => e
diff --git a/Library/Homebrew/cask/lib/hbc/cli/search.rb b/Library/Homebrew/cask/lib/hbc/cli/search.rb
index 992aca583..7abd744e4 100644
--- a/Library/Homebrew/cask/lib/hbc/cli/search.rb
+++ b/Library/Homebrew/cask/lib/hbc/cli/search.rb
@@ -13,6 +13,15 @@ module Hbc
end
end
+ def self.search_remote(query)
+ matches = GitHub.search_code("user:caskroom", "path:Casks", "filename:#{query}", "extension:rb")
+ [*matches].map do |match|
+ tap = Tap.fetch(match["repository"]["full_name"])
+ next if tap.installed?
+ "#{tap.name}/#{File.basename(match["path"], ".rb")}"
+ end.compact
+ end
+
def self.search(*arguments)
exact_match = nil
partial_matches = []
@@ -29,27 +38,34 @@ module Hbc
partial_matches = simplified_tokens.grep(/#{simplified_search_term}/i) { |t| all_tokens[simplified_tokens.index(t)] }
partial_matches.delete(exact_match)
end
- [exact_match, partial_matches, search_term]
+
+ remote_matches = search_remote(search_term)
+
+ [exact_match, partial_matches, remote_matches, search_term]
end
- def self.render_results(exact_match, partial_matches, search_term)
+ def self.render_results(exact_match, partial_matches, remote_matches, search_term)
if !exact_match && partial_matches.empty?
puts "No Cask found for \"#{search_term}\"."
return
end
if exact_match
- ohai "Exact match"
+ ohai "Exact Match"
puts highlight_installed exact_match
end
- return if partial_matches.empty?
-
- if extract_regexp search_term
- ohai "Regexp matches"
- else
- ohai "Partial matches"
+ unless partial_matches.empty?
+ if extract_regexp search_term
+ ohai "Regexp Matches"
+ else
+ ohai "Partial Matches"
+ end
+ puts Formatter.columns(partial_matches.map(&method(:highlight_installed)))
end
- puts Formatter.columns(partial_matches.map(&method(:highlight_installed)))
+
+ return if remote_matches.empty?
+ ohai "Remote Matches"
+ puts Formatter.columns(remote_matches.map(&method(:highlight_installed)))
end
def self.highlight_installed(token)
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 c6b2c3c37..961e31968 100644
--- a/Library/Homebrew/cask/lib/hbc/container.rb
+++ b/Library/Homebrew/cask/lib/hbc/container.rb
@@ -61,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/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 824c1b1be..f02f07806 100644
--- a/Library/Homebrew/cask/lib/hbc/installer.rb
+++ b/Library/Homebrew/cask/lib/hbc/installer.rb
@@ -24,6 +24,7 @@ module Hbc
@force = force
@skip_cask_deps = skip_cask_deps
@require_sha = require_sha
+ @reinstall = false
end
def self.print_caveats(cask)
@@ -76,13 +77,16 @@ module Hbc
def install
odebug "Hbc::Installer#install"
- if @cask.installed? && !force
+ if @cask.installed? && !force && !@reinstall
raise CaskAlreadyInstalledAutoUpdatesError, @cask if @cask.auto_updates
raise CaskAlreadyInstalledError, @cask
end
print_caveats
fetch
+ uninstall_existing_cask if @reinstall
+
+ oh1 "Installing Cask #{@cask}"
stage
install_artifacts
enable_accessibility_access
@@ -90,6 +94,23 @@ module Hbc
puts summary
end
+ def reinstall
+ odebug "Hbc::Installer#reinstall"
+ @reinstall = true
+ install
+ end
+
+ def uninstall_existing_cask
+ return unless @cask.installed?
+
+ # use the same cask file that was used for installation, if possible
+ installed_caskfile = @cask.installed_caskfile
+ installed_cask = installed_caskfile.exist? ? CaskLoader.load_from_file(installed_caskfile) : @cask
+
+ # Always force uninstallation, ignore method parameter
+ Installer.new(installed_cask, force: true).uninstall
+ end
+
def summary
s = ""
s << "#{Emoji.install_badge} " if Emoji.enabled?
@@ -295,19 +316,17 @@ 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
- odebug "Hbc::Installer#uninstall"
+ oh1 "Uninstalling Cask #{@cask}"
disable_accessibility_access
uninstall_artifacts
purge_versioned_files
@@ -355,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/utils.rb b/Library/Homebrew/cask/lib/hbc/utils.rb
index ecb565e8e..b2b65a08e 100644
--- a/Library/Homebrew/cask/lib/hbc/utils.rb
+++ b/Library/Homebrew/cask/lib/hbc/utils.rb
@@ -43,7 +43,7 @@ module Hbc
p.rmtree
else
command.run("/bin/rm",
- args: command_args + ["-r", "-f", "--", p],
+ args: ["-r", "-f", "--", p],
sudo: true)
end
end
@@ -115,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 61b703469..ee09063fd 100644
--- a/Library/Homebrew/caveats.rb
+++ b/Library/Homebrew/caveats.rb
@@ -44,15 +44,17 @@ class Caveats
def keg_only_text
return unless f.keg_only?
- s = "This formula is keg-only, which means it was not symlinked into #{HOMEBREW_PREFIX}."
- s << "\n\n#{f.keg_only_reason}\n"
+ s = <<-EOS.undent
+ This formula is keg-only, which means it was not symlinked into #{HOMEBREW_PREFIX},
+ because #{f.keg_only_reason.to_s.chomp}.
+ EOS
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
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/install.rb b/Library/Homebrew/cmd/install.rb
index 1808c4d9c..394b31db0 100644
--- a/Library/Homebrew/cmd/install.rb
+++ b/Library/Homebrew/cmd/install.rb
@@ -206,7 +206,8 @@ module Homebrew
Migrator.migrate_if_needed(f)
install_formula(f)
end
- rescue FormulaClassUnavailableError => e
+ 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).
@@ -240,6 +241,8 @@ module Homebrew
puts "To install one of them, run (for example):\n brew install #{formulae_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
diff --git a/Library/Homebrew/cmd/link.rb b/Library/Homebrew/cmd/link.rb
index 5ce6bea48..b8bd135e0 100644
--- a/Library/Homebrew/cmd/link.rb
+++ b/Library/Homebrew/cmd/link.rb
@@ -86,8 +86,8 @@ module Homebrew
opt = HOMEBREW_PREFIX/"opt/#{keg.name}"
puts "\nIf you need to have this software first in your PATH instead consider running:"
- puts " #{Utils::Shell.prepend_path_in_shell_profile(opt/"bin")}" if bin.directory?
- puts " #{Utils::Shell.prepend_path_in_shell_profile(opt/"sbin")}" if sbin.directory?
+ 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)
diff --git a/Library/Homebrew/cmd/postinstall.rb b/Library/Homebrew/cmd/postinstall.rb
index 8808a2602..f5d091227 100644
--- a/Library/Homebrew/cmd/postinstall.rb
+++ b/Library/Homebrew/cmd/postinstall.rb
@@ -7,7 +7,10 @@ module Homebrew
module_function
def postinstall
- ARGV.resolved_formulae.each { |f| run_post_install(f) if f.post_install_defined? }
+ ARGV.resolved_formulae.each do |f|
+ ohai "Postinstalling #{f}"
+ run_post_install(f)
+ end
end
def run_post_install(formula)
diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb
index 443739f8c..f71a14ba1 100644
--- a/Library/Homebrew/cmd/search.rb
+++ b/Library/Homebrew/cmd/search.rb
@@ -16,15 +16,12 @@
require "formula"
require "missing_formula"
require "utils"
-require "thread"
require "official_taps"
require "descriptions"
module Homebrew
module_function
- SEARCH_ERROR_QUEUE = Queue.new
-
def search
if ARGV.empty?
puts Formatter.columns(Formula.full_names)
@@ -61,7 +58,7 @@ module Homebrew
regex = query_regexp(query)
local_results = search_formulae(regex)
puts Formatter.columns(local_results) unless local_results.empty?
- tap_results = search_taps(regex)
+ tap_results = search_taps(query)
puts Formatter.columns(tap_results) unless tap_results.empty?
if $stdout.tty?
@@ -75,36 +72,25 @@ module Homebrew
puts reason
elsif count.zero?
puts "No formula found for #{query.inspect}."
- begin
- GitHub.print_pull_requests_matching(query)
- rescue GitHub::Error => e
- SEARCH_ERROR_QUEUE << e
- end
+ GitHub.print_pull_requests_matching(query)
end
end
end
- if $stdout.tty?
- metacharacters = %w[\\ | ( ) [ ] { } ^ $ * + ?]
- bad_regex = metacharacters.any? do |char|
- ARGV.any? do |arg|
- arg.include?(char) && !arg.start_with?("/")
- end
- end
- if !ARGV.empty? && bad_regex
- ohai "Did you mean to perform a regular expression search?"
- ohai "Surround your query with /slashes/ to search by regex."
+ return unless $stdout.tty?
+ return if ARGV.empty?
+ metacharacters = %w[\\ | ( ) [ ] { } ^ $ * + ?].freeze
+ return unless metacharacters.any? do |char|
+ ARGV.any? do |arg|
+ arg.include?(char) && !arg.start_with?("/")
end
end
-
- raise SEARCH_ERROR_QUEUE.pop unless SEARCH_ERROR_QUEUE.empty?
+ ohai <<-EOS.undent
+ Did you mean to perform a regular expression search?
+ Surround your query with /slashes/ to search locally by regex.
+ EOS
end
- SEARCHABLE_TAPS = OFFICIAL_TAPS.map { |tap| ["Homebrew", tap] } + [
- %w[Caskroom cask],
- %w[Caskroom versions],
- ]
-
def query_regexp(query)
case query
when %r{^/(.*)/$} then Regexp.new($1)
@@ -114,53 +100,16 @@ module Homebrew
odie "#{query} is not a valid regex"
end
- def search_taps(regex_or_string)
- SEARCHABLE_TAPS.map do |user, repo|
- Thread.new { search_tap(user, repo, regex_or_string) }
- end.inject([]) do |results, t|
- results.concat(t.value)
- end
- end
-
- def search_tap(user, repo, regex_or_string)
- regex = regex_or_string.is_a?(String) ? /^#{Regexp.escape(regex_or_string)}$/ : regex_or_string
-
- if (HOMEBREW_LIBRARY/"Taps/#{user.downcase}/homebrew-#{repo.downcase}").directory? && \
- user != "Caskroom"
- return []
- end
-
- remote_tap_formulae = Hash.new do |cache, key|
- user, repo = key.split("/", 2)
- tree = {}
-
- GitHub.open "https://api.github.com/repos/#{user}/homebrew-#{repo}/git/trees/HEAD?recursive=1" do |json|
- json["tree"].each do |object|
- next unless object["type"] == "blob"
-
- subtree, file = File.split(object["path"])
-
- if File.extname(file) == ".rb"
- tree[subtree] ||= []
- tree[subtree] << file
- end
- end
- end
-
- paths = tree["Formula"] || tree["HomebrewFormula"] || tree["."] || []
- paths += tree["Casks"] || []
- cache[key] = paths.map { |path| File.basename(path, ".rb") }
- end
-
- names = remote_tap_formulae["#{user}/#{repo}"]
- user = user.downcase if user == "Homebrew" # special handling for the Homebrew organization
- names.select { |name| name =~ regex }.map { |name| "#{user}/#{repo}/#{name}" }
- rescue GitHub::HTTPNotFoundError
- opoo "Failed to search tap: #{user}/#{repo}. Please run `brew update`"
- []
- rescue GitHub::Error => e
- SEARCH_ERROR_QUEUE << e
- []
+ def search_taps(query)
+ valid_dirnames = ["Formula", "HomebrewFormula", "Casks", "."].freeze
+ matches = GitHub.search_code("user:Homebrew", "user:caskroom", "filename:#{query}", "extension:rb")
+ [*matches].map do |match|
+ dirname, filename = File.split(match["path"])
+ next unless valid_dirnames.include?(dirname)
+ tap = Tap.fetch(match["repository"]["full_name"])
+ next if tap.installed?
+ "#{tap.name}/#{File.basename(filename, ".rb")}"
+ end.compact
end
def search_formulae(regex)
diff --git a/Library/Homebrew/cmd/sh.rb b/Library/Homebrew/cmd/sh.rb
index 249753355..69f329cb3 100644
--- a/Library/Homebrew/cmd/sh.rb
+++ b/Library/Homebrew/cmd/sh.rb
@@ -23,7 +23,7 @@ module Homebrew
ENV.setup_build_environment
if superenv?
# superenv stopped adding brew's bin but generally users will want it
- ENV["PATH"] = ENV["PATH"].split(File::PATH_SEPARATOR).insert(1, "#{HOMEBREW_PREFIX}/bin").join(File::PATH_SEPARATOR)
+ ENV["PATH"] = PATH.new(ENV["PATH"]).insert(1, HOMEBREW_PREFIX/"bin")
end
ENV["PS1"] = 'brew \[\033[1;32m\]\w\[\033[0m\]$ '
ENV["VERBOSE"] = "1"
diff --git a/Library/Homebrew/cmd/style.rb b/Library/Homebrew/cmd/style.rb
index 2a7f37031..cf41d91ee 100644
--- a/Library/Homebrew/cmd/style.rb
+++ b/Library/Homebrew/cmd/style.rb
@@ -1,4 +1,4 @@
-#: * `style` [`--fix`] [`--display-cop-names`] [<files>|<taps>|<formulae>]:
+#: * `style` [`--fix`] [`--display-cop-names`] [`--only-cops=`[COP1,COP2..]|`--except-cops=`[COP1,COP2..]] [<files>|<taps>|<formulae>]:
#: Check formulae or files for conformance to Homebrew style guidelines.
#:
#: <formulae> and <files> may not be combined. If both are omitted, style will run
@@ -11,6 +11,10 @@
#: If `--display-cop-names` is passed, the RuboCop cop name for each violation
#: is included in the output.
#:
+#: If `--only-cops` is passed, only the given Rubocop cop(s)' violations would be checked.
+#:
+#: If `--except-cops` is passed, the given Rubocop cop(s)' checks would be skipped.
+#:
#: Exits with a non-zero status if any style violations are found.
require "utils"
@@ -30,7 +34,20 @@ module Homebrew
ARGV.formulae.map(&:path)
end
- Homebrew.failed = check_style_and_print(target, fix: ARGV.flag?("--fix"))
+ only_cops = ARGV.value("only-cops").to_s.split(",")
+ except_cops = ARGV.value("except-cops").to_s.split(",")
+ if !only_cops.empty? && !except_cops.empty?
+ odie "--only-cops and --except-cops cannot be used simultaneously!"
+ end
+
+ options = { fix: ARGV.flag?("--fix") }
+ if !only_cops.empty?
+ options[:only_cops] = only_cops
+ elsif !except_cops.empty?
+ options[:except_cops] = except_cops
+ end
+
+ Homebrew.failed = check_style_and_print(target, options)
end
# Checks style for a list of files, printing simple RuboCop output.
@@ -47,13 +64,34 @@ module Homebrew
def check_style_impl(files, output_type, options = {})
fix = options[:fix]
+
Homebrew.install_gem_setup_path! "rubocop", HOMEBREW_RUBOCOP_VERSION
+ require "rubocop"
+ require_relative "../rubocops"
args = %w[
--force-exclusion
]
args << "--auto-correct" if fix
+ if options[:except_cops]
+ options[:except_cops].map! { |cop| RuboCop::Cop::Cop.registry.qualified_cop_name(cop.to_s, "") }
+ cops_to_exclude = options[:except_cops].select do |cop|
+ RuboCop::Cop::Cop.registry.names.include?(cop) ||
+ RuboCop::Cop::Cop.registry.departments.include?(cop.to_sym)
+ end
+
+ args << "--except" << cops_to_exclude.join(",") unless cops_to_exclude.empty?
+ elsif options[:only_cops]
+ options[:only_cops].map! { |cop| RuboCop::Cop::Cop.registry.qualified_cop_name(cop.to_s, "") }
+ cops_to_include = options[:only_cops].select do |cop|
+ RuboCop::Cop::Cop.registry.names.include?(cop) ||
+ RuboCop::Cop::Cop.registry.departments.include?(cop.to_sym)
+ end
+
+ args << "--only" << cops_to_include.join(",") unless cops_to_include.empty?
+ end
+
if files.nil?
args << "--config" << HOMEBREW_LIBRARY_PATH/".rubocop.yml"
args += [HOMEBREW_LIBRARY_PATH]
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/update.sh b/Library/Homebrew/cmd/update.sh
index 197a99f2e..77a5c1cd2 100644
--- a/Library/Homebrew/cmd/update.sh
+++ b/Library/Homebrew/cmd/update.sh
@@ -23,7 +23,7 @@ git() {
}
git_init_if_necessary() {
- if [[ -n "$HOMEBREW_MACOS" ]]
+ if [[ -n "$HOMEBREW_MACOS" ]] || [[ -n "$HOMEBREW_FORCE_HOMEBREW_ORG" ]]
then
BREW_OFFICIAL_REMOTE="https://github.com/Homebrew/brew"
CORE_OFFICIAL_REMOTE="https://github.com/Homebrew/homebrew-core"
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/dependable.rb b/Library/Homebrew/dependable.rb
index 0834b08ec..785eb94d8 100644
--- a/Library/Homebrew/dependable.rb
+++ b/Library/Homebrew/dependable.rb
@@ -20,8 +20,6 @@ module Dependable
end
def required?
- # FIXME: Should `required?` really imply `!build?`? And if so, why doesn't
- # any of `optional?` and `recommended?` equally imply `!build?`?
!build? && !optional? && !recommended?
end
diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb
index ba6c3f333..cbe26b422 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>] [`--only-cops=`[COP1,COP2..]|`--except-cops=`[COP1,COP2..]] [<formulae>]:
#: Check <formulae> for Homebrew coding style violations. This should be
#: run before submitting a new formula.
#:
@@ -23,6 +23,14 @@
#: 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.
+#:
+#: If `--only-cops` is passed, only the given Rubocop cop(s)' violations would be checked.
+#:
+#: If `--except-cops` is passed, the given Rubocop cop(s)' checks would be skipped.
+#:
#: `audit` exits with a non-zero status if any errors are found. This is useful,
#: for instance, for implementing pre-commit hooks.
@@ -65,15 +73,30 @@ module Homebrew
files = ARGV.resolved_formulae.map(&:path)
end
- if strict
- options = { fix: ARGV.flag?("--fix"), realpath: true }
- # Check style in a single batch run up front for performance
- style_results = check_style_json(files, options)
+ only_cops = ARGV.value("only-cops").to_s.split(",")
+ except_cops = ARGV.value("except-cops").to_s.split(",")
+ if !only_cops.empty? && !except_cops.empty?
+ odie "--only-cops and --except-cops cannot be used simultaneously!"
+ elsif (!only_cops.empty? || !except_cops.empty?) && strict
+ odie "--only-cops/--except-cops and --strict cannot be used simultaneously"
+ end
+
+ options = { fix: ARGV.flag?("--fix"), realpath: true }
+
+ if !only_cops.empty?
+ options[:only_cops] = only_cops
+ elsif !except_cops.empty?
+ options[:except_cops] = except_cops
+ elsif !strict
+ options[:except_cops] = [:FormulaAuditStrict]
end
+ # Check style in a single batch run up front for performance
+ style_results = check_style_json(files, options)
+
ff.each do |f|
options = { new_formula: new_formula, strict: strict, online: online }
- options[:style_offenses] = style_results.file_offenses(f.path) if strict
+ options[:style_offenses] = style_results.file_offenses(f.path)
fa = FormulaAuditor.new(f, options)
fa.audit
@@ -244,70 +267,6 @@ class FormulaAuditor
end
end
- def component_problem(before, after, offset = 0)
- problem "`#{before[1]}` (line #{before[0] + offset}) should be put before `#{after[1]}` (line #{after[0] + offset})"
- end
-
- # scan in the reverse direction for remaining problems but report problems
- # in the forward direction so that contributors don't reverse the order of
- # lines in the file simply by following instructions
- def audit_components(reverse = true, previous_pair = nil)
- component_list = [
- [/^ include Language::/, "include directive"],
- [/^ desc ["'][\S\ ]+["']/, "desc"],
- [/^ homepage ["'][\S\ ]+["']/, "homepage"],
- [/^ url ["'][\S\ ]+["']/, "url"],
- [/^ mirror ["'][\S\ ]+["']/, "mirror"],
- [/^ version ["'][\S\ ]+["']/, "version"],
- [/^ (sha1|sha256) ["'][\S\ ]+["']/, "checksum"],
- [/^ revision/, "revision"],
- [/^ version_scheme/, "version_scheme"],
- [/^ head ["'][\S\ ]+["']/, "head"],
- [/^ stable do/, "stable block"],
- [/^ bottle do/, "bottle block"],
- [/^ devel do/, "devel block"],
- [/^ head do/, "head block"],
- [/^ bottle (:unneeded|:disable)/, "bottle modifier"],
- [/^ keg_only/, "keg_only"],
- [/^ option/, "option"],
- [/^ depends_on/, "depends_on"],
- [/^ conflicts_with/, "conflicts_with"],
- [/^ (go_)?resource/, "resource"],
- [/^ def install/, "install method"],
- [/^ def caveats/, "caveats method"],
- [/^ (plist_options|def plist)/, "plist block"],
- [/^ test do/, "test block"],
- ]
- if previous_pair
- previous_before = previous_pair[0]
- previous_after = previous_pair[1]
- end
- offset = previous_after && previous_after[0] && previous_after[0] >= 1 ? previous_after[0] - 1 : 0
- present = component_list.map do |regex, name|
- lineno = if reverse
- text.reverse_line_number regex
- else
- text.line_number regex, offset
- end
- next unless lineno
- [lineno, name]
- end.compact
- no_problem = true
- present.each_cons(2) do |c1, c2|
- if reverse
- # scan in the forward direction from the offset
- audit_components(false, [c1, c2]) if c1[0] > c2[0] # at least one more offense
- elsif c1[0] > c2[0] && (offset.zero? || previous_pair.nil? || (c1[0] + offset) != previous_before[0] || (c2[0] + offset) != previous_after[0])
- component_problem c1, c2, offset
- no_problem = false
- end
- end
- if no_problem && previous_pair
- component_problem previous_before, previous_after
- end
- present
- end
-
def audit_file
# Under normal circumstances (umask 0022), we expect a file mode of 644. If
# the user's umask is more restrictive, respect that by masking out the
@@ -332,53 +291,60 @@ class FormulaAuditor
problem "File should end with a newline" unless text.trailing_newline?
if formula.versioned_formula?
- unversioned_formula = Pathname.new formula.path.to_s.gsub(/@.*\.rb$/, ".rb")
+ 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
- else
- 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
+ elsif ARGV.build_stable? &&
+ !(versioned_formulae = Dir[formula.path.to_s.gsub(/\.rb$/, "@*.rb")]).empty?
+ versioned_aliases = formula.aliases.grep(/.@\d/)
+ _, last_alias_version =
+ File.basename(versioned_formulae.sort.reverse.first)
+ .gsub(/\.rb$/, "").split("@")
+ major, minor, = formula.version.to_s.split(".")
+ alias_name_major = "#{formula.name}@#{major}"
+ alias_name_major_minor = "#{alias_name_major}.#{minor}"
+ alias_name = if last_alias_version.split(".").length == 1
+ alias_name_major
+ else
+ alias_name_major_minor
end
- end
-
- return unless @strict
+ valid_alias_names = [alias_name_major, alias_name_major_minor]
- present = audit_components
+ valid_versioned_aliases = versioned_aliases & valid_alias_names
+ invalid_versioned_aliases = versioned_aliases - valid_alias_names
- present.map!(&:last)
- if present.include?("stable block")
- %w[url checksum mirror].each do |component|
- if present.include?(component)
- problem "`#{component}` should be put inside `stable block`"
+ if valid_versioned_aliases.empty?
+ if formula.tap
+ problem <<-EOS.undent
+ Formula has other versions so create a versioned alias:
+ cd #{formula.tap.alias_dir}
+ ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name}
+ EOS
+ else
+ problem "Formula has other versions so create an alias named #{alias_name}."
end
end
- end
- if present.include?("head") && present.include?("head block")
- problem "Should not have both `head` and `head do`"
+ unless invalid_versioned_aliases.empty?
+ problem <<-EOS.undent
+ Formula has invalid versioned aliases:
+ #{invalid_versioned_aliases.join("\n ")}
+ EOS
+ end
end
-
- return unless present.include?("bottle modifier") && present.include?("bottle block")
- problem "Should not have `bottle :unneeded/:disable` and `bottle do`"
end
def audit_class
@@ -437,11 +403,11 @@ class FormulaAuditor
same_name_tap_formulae = @@local_official_taps_name_map[name] || []
if @online
- @@remote_official_taps ||= OFFICIAL_TAPS - Tap.select(&:official?).map(&:repo)
-
- same_name_tap_formulae += @@remote_official_taps.map do |tap|
- Thread.new { Homebrew.search_tap "homebrew", tap, name }
- end.flat_map(&:value)
+ Homebrew.search_taps(name).each do |tap_formula_full_name|
+ tap_formula_name = tap_formula_full_name.split("/").last
+ next if tap_formula_name != name
+ same_name_tap_formulae << tap_formula_full_name
+ end
end
same_name_tap_formulae.delete(full_name)
@@ -558,6 +524,38 @@ class FormulaAuditor
EOS
end
+ def audit_keg_only_style
+ return unless @strict
+ return unless formula.keg_only?
+
+ whitelist = %w[
+ Apple
+ macOS
+ OS
+ Homebrew
+ Xcode
+ GPG
+ GNOME
+ BSD
+ Firefox
+ ].freeze
+
+ reason = formula.keg_only_reason.to_s
+ # Formulae names can legitimately be uppercase/lowercase/both.
+ name = Regexp.new(formula.name, Regexp::IGNORECASE)
+ reason.sub!(name, "")
+ first_word = reason.split[0]
+
+ if reason =~ /\A[A-Z]/ && !reason.start_with?(*whitelist)
+ problem <<-EOS.undent
+ '#{first_word}' from the keg_only reason should be '#{first_word.downcase}'.
+ EOS
+ end
+
+ return unless reason.end_with?(".")
+ problem "keg_only reason should not end with a period."
+ end
+
def audit_options
formula.options.each do |o|
if o.name == "32-bit"
@@ -590,78 +588,9 @@ class FormulaAuditor
homepage = formula.homepage
if homepage.nil? || homepage.empty?
- problem "Formula should have a homepage."
return
end
- unless homepage =~ %r{^https?://}
- problem "The homepage should start with http or https (URL is #{homepage})."
- end
-
- # Check for http:// GitHub homepage urls, https:// is preferred.
- # Note: only check homepages that are repo pages, not *.github.com hosts
- if homepage.start_with? "http://github.com/"
- problem "Please use https:// for #{homepage}"
- end
-
- # Savannah has full SSL/TLS support but no auto-redirect.
- # Doesn't apply to the download URLs, only the homepage.
- if homepage.start_with? "http://savannah.nongnu.org/"
- problem "Please use https:// for #{homepage}"
- end
-
- # Freedesktop is complicated to handle - It has SSL/TLS, but only on certain subdomains.
- # To enable https Freedesktop change the URL from http://project.freedesktop.org/wiki to
- # https://wiki.freedesktop.org/project_name.
- # "Software" is redirected to https://wiki.freedesktop.org/www/Software/project_name
- if homepage =~ %r{^http://((?:www|nice|libopenraw|liboil|telepathy|xorg)\.)?freedesktop\.org/(?:wiki/)?}
- if homepage =~ /Software/
- problem "#{homepage} should be styled `https://wiki.freedesktop.org/www/Software/project_name`"
- else
- problem "#{homepage} should be styled `https://wiki.freedesktop.org/project_name`"
- end
- end
-
- # Google Code homepages should end in a slash
- if homepage =~ %r{^https?://code\.google\.com/p/[^/]+[^/]$}
- problem "#{homepage} should end with a slash"
- end
-
- # People will run into mixed content sometimes, but we should enforce and then add
- # exemptions as they are discovered. Treat mixed content on homepages as a bug.
- # Justify each exemptions with a code comment so we can keep track here.
- case homepage
- when %r{^http://[^/]*\.github\.io/},
- %r{^http://[^/]*\.sourceforge\.io/}
- problem "Please use https:// for #{homepage}"
- end
-
- if homepage =~ %r{^http://([^/]*)\.(sf|sourceforge)\.net(/|$)}
- problem "#{homepage} should be `https://#{$1}.sourceforge.io/`"
- end
-
- # There's an auto-redirect here, but this mistake is incredibly common too.
- # Only applies to the homepage and subdomains for now, not the FTP URLs.
- if homepage =~ %r{^http://((?:build|cloud|developer|download|extensions|git|glade|help|library|live|nagios|news|people|projects|rt|static|wiki|www)\.)?gnome\.org}
- problem "Please use https:// for #{homepage}"
- end
-
- # Compact the above into this list as we're able to remove detailed notations, etc over time.
- case homepage
- when %r{^http://[^/]*\.apache\.org},
- %r{^http://packages\.debian\.org},
- %r{^http://wiki\.freedesktop\.org/},
- %r{^http://((?:www)\.)?gnupg\.org/},
- %r{^http://ietf\.org},
- %r{^http://[^/.]+\.ietf\.org},
- %r{^http://[^/.]+\.tools\.ietf\.org},
- %r{^http://www\.gnu\.org/},
- %r{^http://code\.google\.com/},
- %r{^http://bitbucket\.org/},
- %r{^http://(?:[^/]*\.)?archive\.org}
- problem "Please use https:// for #{homepage}"
- end
-
return unless @online
return unless DevelopmentTools.curl_handles_most_https_homepages?
@@ -728,7 +657,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|
@@ -809,51 +741,67 @@ class FormulaAuditor
return unless formula.tap.git? # git log is required
return if @new_formula
- fv = FormulaVersions.new(formula, max_depth: 1)
+ fv = FormulaVersions.new(formula)
attributes = [:revision, :version_scheme]
-
attributes_map = fv.version_attributes_map(attributes, "origin/master")
- attributes.each do |attribute|
- stable_attribute_map = attributes_map[attribute][:stable]
- next if stable_attribute_map.nil? || stable_attribute_map.empty?
-
- attributes_for_version = stable_attribute_map[formula.version]
- next if attributes_for_version.nil? || attributes_for_version.empty?
-
- old_attribute = formula.send(attribute)
- max_attribute = attributes_for_version.max
- if max_attribute && old_attribute < max_attribute
- problem "#{attribute} should not decrease (from #{max_attribute} to #{old_attribute})"
- end
- end
-
+ current_version_scheme = formula.version_scheme
[:stable, :devel].each do |spec|
spec_version_scheme_map = attributes_map[:version_scheme][spec]
- next if spec_version_scheme_map.nil? || spec_version_scheme_map.empty?
+ next if spec_version_scheme_map.empty?
- max_version_scheme = spec_version_scheme_map.values.flatten.max
+ version_schemes = spec_version_scheme_map.values.flatten
+ max_version_scheme = version_schemes.max
max_version = spec_version_scheme_map.select do |_, version_scheme|
version_scheme.first == max_version_scheme
end.keys.max
- formula_spec = formula.send(spec)
- next if formula_spec.nil?
+ if max_version_scheme && current_version_scheme < max_version_scheme
+ problem "version_scheme should not decrease (from #{max_version_scheme} to #{current_version_scheme})"
+ end
- if max_version && formula_spec.version < max_version
- problem "#{spec} version should not decrease (from #{max_version} to #{formula_spec.version})"
+ if max_version_scheme && current_version_scheme >= max_version_scheme &&
+ current_version_scheme > 1 &&
+ !version_schemes.include?(current_version_scheme - 1)
+ problem "version_schemes should only increment by 1"
end
+
+ formula_spec = formula.send(spec)
+ next unless formula_spec
+
+ spec_version = formula_spec.version
+ next unless max_version
+ next if spec_version >= max_version
+
+ above_max_version_scheme = current_version_scheme > max_version_scheme
+ map_includes_version = spec_version_scheme_map.keys.include?(spec_version)
+ next if !current_version_scheme.zero? &&
+ (above_max_version_scheme || map_includes_version)
+ problem "#{spec} version should not decrease (from #{max_version} to #{spec_version})"
end
- return if formula.revision.zero?
- if formula.stable
- revision_map = attributes_map[:revision][:stable]
- stable_revisions = revision_map[formula.stable.version] if revision_map
- if !stable_revisions || stable_revisions.empty?
+ current_revision = formula.revision
+ revision_map = attributes_map[:revision][:stable]
+ if formula.stable && !revision_map.empty?
+ stable_revisions = revision_map[formula.stable.version]
+ stable_revisions ||= []
+ max_revision = stable_revisions.max || 0
+
+ if current_revision < max_revision
+ problem "revision should not decrease (from #{max_revision} to #{current_revision})"
+ end
+
+ stable_revisions -= [formula.revision]
+ if !current_revision.zero? && stable_revisions.empty? &&
+ revision_map.keys.length > 1
problem "'revision #{formula.revision}' should be removed"
+ elsif current_revision > 1 &&
+ current_revision != max_revision &&
+ !stable_revisions.include?(current_revision - 1)
+ problem "revisions should only increment by 1"
end
- else # head/devel-only formula
- problem "'revision #{formula.revision}' should be removed"
+ elsif !current_revision.zero? # head/devel-only formula
+ problem "'revision #{current_revision}' should be removed"
end
end
@@ -864,10 +812,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}
@@ -935,11 +883,21 @@ class FormulaAuditor
problem "Formulae using virtualenvs do not need a `setuptools` resource."
end
+ if text =~ /system\s+['"]go['"],\s+['"]get['"]/
+ problem "Formulae should not use `go get`. If non-vendored resources are required use `go_resource`s."
+ end
+
return unless text.include?('require "language/go"') && !text.include?("go_resource")
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
@@ -1018,7 +976,19 @@ class FormulaAuditor
end
if line =~ /depends_on :tex/
- problem ":tex is deprecated."
+ 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+(.*)/
+ dep = $1
+ $2.split(" ").map do |o|
+ next unless o =~ /^\[?['"](.*)['"]/
+ problem "Dependency #{dep} should not use option #{$1}"
+ end
end
# Commented-out depends_on
@@ -1049,6 +1019,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
@@ -1078,11 +1056,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]))/
@@ -1130,11 +1108,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\[("[^\*{},]+")\])/
@@ -1171,6 +1149,10 @@ class FormulaAuditor
end
end
+ if line =~ /((revision|version_scheme)\s+0)/
+ problem "'#{$1}' should be removed"
+ end
+
return unless @strict
problem "`#{$1}` in formulae is deprecated" if line =~ /(env :(std|userpaths))/
@@ -1222,7 +1204,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)
@@ -1238,30 +1220,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_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 simultaneously!"
+ 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
@@ -1392,8 +1370,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/create.rb b/Library/Homebrew/dev-cmd/create.rb
index 6855d6f37..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.
@@ -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
@@ -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/mirror.rb b/Library/Homebrew/dev-cmd/mirror.rb
index 10811493c..e2492203d 100644
--- a/Library/Homebrew/dev-cmd/mirror.rb
+++ b/Library/Homebrew/dev-cmd/mirror.rb
@@ -8,10 +8,10 @@ module Homebrew
def mirror
odie "This command requires at least formula argument!" if ARGV.named.empty?
- bintray_user = ENV["BINTRAY_USER"]
- bintray_key = ENV["BINTRAY_KEY"]
+ bintray_user = ENV["HOMEBREW_BINTRAY_USER"]
+ bintray_key = ENV["HOMEBREW_BINTRAY_KEY"]
if !bintray_user || !bintray_key
- raise "Missing BINTRAY_USER or BINTRAY_KEY variables!"
+ raise "Missing HOMEBREW_BINTRAY_USER or HOMEBREW_BINTRAY_KEY variables!"
end
ARGV.formulae.each do |f|
diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb
index 36c9ac27c..9d08da95b 100644
--- a/Library/Homebrew/dev-cmd/pull.rb
+++ b/Library/Homebrew/dev-cmd/pull.rb
@@ -263,7 +263,7 @@ module Homebrew
end
published = []
- bintray_creds = { user: ENV["BINTRAY_USER"], key: ENV["BINTRAY_KEY"] }
+ bintray_creds = { user: ENV["HOMEBREW_BINTRAY_USER"], key: ENV["HOMEBREW_BINTRAY_KEY"] }
if bintray_creds[:user] && bintray_creds[:key]
changed_formulae_names.each do |name|
f = Formula[name]
@@ -272,7 +272,7 @@ module Homebrew
published << f.full_name
end
else
- opoo "You must set BINTRAY_USER and BINTRAY_KEY to add or update bottles on Bintray!"
+ opoo "You must set HOMEBREW_BINTRAY_USER and HOMEBREW_BINTRAY_KEY to add or update bottles on Bintray!"
end
published
end
@@ -608,7 +608,7 @@ module Homebrew
def check_bintray_mirror(name, url)
headers = curl_output("--connect-timeout", "15", "--head", url)[0]
status_code = headers.scan(%r{^HTTP\/.* (\d+)}).last.first
- return if status_code.start_with?("3")
+ return if status_code.start_with?("2")
opoo "The Bintray mirror #{url} is not reachable (HTTP status code #{status_code})."
opoo "Do you need to upload it with `brew mirror #{name}`?"
end
diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb
index df295bf26..dcb41265c 100644
--- a/Library/Homebrew/dev-cmd/tap-new.rb
+++ b/Library/Homebrew/dev-cmd/tap-new.rb
@@ -47,8 +47,12 @@ module Homebrew
language: ruby
os: osx
env: OSX=10.12
- osx_image: xcode8.1
+ osx_image: xcode8.3
rvm: system
+ cache:
+ directories:
+ - $HOME/.gem/ruby
+ - Library/Homebrew/vendor/bundle
before_install:
- export TRAVIS_COMMIT="$(git rev-parse --verify -q HEAD)"
diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb
index 91c7d880b..d90326768 100644
--- a/Library/Homebrew/dev-cmd/tests.rb
+++ b/Library/Homebrew/dev-cmd/tests.rb
@@ -33,7 +33,12 @@ module Homebrew
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"
@@ -74,20 +79,24 @@ module Homebrew
Dir.glob("test/**/*_spec.rb").reject { |p| p =~ %r{^test/vendor/bundle/} }
end
- opts = []
-
- if ENV["CI"]
- opts << "--combine-stderr"
- opts << "--serialize-stdout"
+ opts = if ENV["CI"]
+ %w[
+ --combine-stderr
+ --serialize-stdout
+ ]
+ else
+ %w[
+ --nice
+ ]
end
- args = [
- "--color",
- "-I", HOMEBREW_LIBRARY_PATH/"test",
- "--require", "spec_helper",
- "--format", "progress",
- "--format", "ParallelTests::RSpec::RuntimeLogger",
- "--out", "tmp/parallel_runtime_rspec.log"
+ args = ["-I", HOMEBREW_LIBRARY_PATH/"test"]
+ args += %w[
+ --color
+ --require spec_helper
+ --format progress
+ --format ParallelTests::RSpec::RuntimeLogger
+ --out tmp/parallel_runtime_rspec.log
]
args << "--seed" << ARGV.next if ARGV.include? "--seed"
@@ -97,6 +106,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/diagnostic.rb b/Library/Homebrew/diagnostic.rb
index 61cdf2f1a..6bb5c8b8e 100644
--- a/Library/Homebrew/diagnostic.rb
+++ b/Library/Homebrew/diagnostic.rb
@@ -100,8 +100,7 @@ module Homebrew
# See https://github.com/Homebrew/legacy-homebrew/pull/9986
def check_path_for_trailing_slashes
- all_paths = ENV["PATH"].split(File::PATH_SEPARATOR)
- bad_paths = all_paths.select { |p| p[-1..-1] == "/" }
+ bad_paths = PATH.new(ENV["HOMEBREW_PATH"]).select { |p| p.end_with?("/") }
return if bad_paths.empty?
inject_file_list bad_paths, <<-EOS.undent
@@ -439,7 +438,7 @@ module Homebrew
message = ""
- paths.each do |p|
+ paths(ENV["HOMEBREW_PATH"]).each do |p|
case p
when "/usr/bin"
unless $seen_prefix_bin
@@ -460,7 +459,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 +479,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 +494,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
@@ -609,7 +608,7 @@ module Homebrew
/Applications/Server.app/Contents/ServerRoot/usr/sbin
].map(&:downcase)
- paths.each do |p|
+ paths(ENV["HOMEBREW_PATH"]).each do |p|
next if whitelist.include?(p.downcase) || !File.directory?(p)
realpath = Pathname.new(p).realpath.to_s
diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb
index a0025cef3..d74efe0bb 100644
--- a/Library/Homebrew/download_strategy.rb
+++ b/Library/Homebrew/download_strategy.rb
@@ -520,6 +520,9 @@ class S3DownloadStrategy < CurlDownloadStrategy
bucket = $1
key = $2
+ ENV["AWS_ACCESS_KEY_ID"] = ENV["HOMEBREW_AWS_ACCESS_KEY_ID"]
+ ENV["AWS_SECRET_ACCESS_KEY"] = ENV["HOMEBREW_AWS_SECRET_ACCESS_KEY"]
+
obj = AWS::S3.new.buckets[bucket].objects[key]
begin
s3url = obj.url_for(:get)
diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb
index cfdf5e12d..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
diff --git a/Library/Homebrew/extend/ENV.rb b/Library/Homebrew/extend/ENV.rb
index 729598e28..283e90b69 100644
--- a/Library/Homebrew/extend/ENV.rb
+++ b/Library/Homebrew/extend/ENV.rb
@@ -26,6 +26,13 @@ module EnvActivation
ensure
replace(old_env)
end
+
+ def clear_sensitive_environment!
+ ENV.keys.each do |key|
+ next unless /(cookie|key|token)/i =~ key
+ ENV.delete key
+ end
+ end
end
ENV.extend(EnvActivation)
diff --git a/Library/Homebrew/extend/ENV/shared.rb b/Library/Homebrew/extend/ENV/shared.rb
index 2cdc2f83a..b51ade48b 100644
--- a/Library/Homebrew/extend/ENV/shared.rb
+++ b/Library/Homebrew/extend/ENV/shared.rb
@@ -1,6 +1,7 @@
require "formula"
require "compilers"
require "development_tools"
+require "PATH"
# Homebrew extends Ruby's `ENV` to make our code more readable.
# Implemented in {SharedEnvExtension} and either {Superenv} or
@@ -80,7 +81,7 @@ module SharedEnvExtension
end
def append_path(key, path)
- append key, path, File::PATH_SEPARATOR if File.directory? path
+ self[key] = PATH.new(self[key]).append(path)
end
# Prepends a directory to `PATH`.
@@ -92,7 +93,7 @@ module SharedEnvExtension
# (e.g. <pre>ENV.prepend_path "PATH", which("emacs").dirname</pre>)
def prepend_path(key, path)
return if %w[/usr/bin /bin /usr/sbin /sbin].include? path.to_s
- prepend key, path, File::PATH_SEPARATOR if File.directory? path
+ self[key] = PATH.new(self[key]).prepend(path)
end
def prepend_create_path(key, path)
@@ -196,22 +197,23 @@ module SharedEnvExtension
# @private
def userpaths!
- paths = self["PATH"].split(File::PATH_SEPARATOR)
- # put Superenv.bin and opt path at the first
- new_paths = paths.select { |p| p.start_with?("#{HOMEBREW_REPOSITORY}/Library/ENV", "#{HOMEBREW_PREFIX}/opt") }
- # XXX hot fix to prefer brewed stuff (e.g. python) over /usr/bin.
- new_paths << "#{HOMEBREW_PREFIX}/bin"
- # reset of self["PATH"]
- new_paths += paths
- # user paths
- new_paths += ORIGINAL_PATHS.map do |p|
- begin
- p.realpath.to_s
- rescue
- nil
- end
- end - %w[/usr/X11/bin /opt/X11/bin]
- self["PATH"] = new_paths.uniq.join(File::PATH_SEPARATOR)
+ path = PATH.new(self["PATH"]).select do |p|
+ # put Superenv.bin and opt path at the first
+ p.start_with?("#{HOMEBREW_REPOSITORY}/Library/ENV", "#{HOMEBREW_PREFIX}/opt")
+ end
+ path.append(HOMEBREW_PREFIX/"bin") # XXX hot fix to prefer brewed stuff (e.g. python) over /usr/bin.
+ path.append(self["PATH"]) # reset of self["PATH"]
+ path.append(
+ # user paths
+ ORIGINAL_PATHS.map do |p|
+ begin
+ p.realpath.to_s
+ rescue
+ nil
+ end
+ end - %w[/usr/X11/bin /opt/X11/bin],
+ )
+ self["PATH"] = path
end
def fortran
@@ -244,7 +246,7 @@ module SharedEnvExtension
else
if (gfortran = which("gfortran", (HOMEBREW_PREFIX/"bin").to_s))
ohai "Using Homebrew-provided fortran compiler."
- elsif (gfortran = which("gfortran", ORIGINAL_PATHS.join(File::PATH_SEPARATOR)))
+ elsif (gfortran = which("gfortran", PATH.new(ORIGINAL_PATHS)))
ohai "Using a fortran compiler found at #{gfortran}."
end
if gfortran
diff --git a/Library/Homebrew/extend/ENV/std.rb b/Library/Homebrew/extend/ENV/std.rb
index 403ea1978..c4cc0985f 100644
--- a/Library/Homebrew/extend/ENV/std.rb
+++ b/Library/Homebrew/extend/ENV/std.rb
@@ -1,7 +1,6 @@
require "hardware"
require "extend/ENV/shared"
-# TODO: deprecate compiling related codes after it's only used by brew test.
# @private
module Stdenv
include SharedEnvExtension
@@ -58,12 +57,12 @@ module Stdenv
end
def determine_pkg_config_libdir
- paths = []
- paths << "#{HOMEBREW_PREFIX}/lib/pkgconfig"
- paths << "#{HOMEBREW_PREFIX}/share/pkgconfig"
- paths += homebrew_extra_pkg_config_paths
- paths << "/usr/lib/pkgconfig"
- paths.select { |d| File.directory? d }.join(File::PATH_SEPARATOR)
+ PATH.new(
+ HOMEBREW_PREFIX/"lib/pkgconfig",
+ HOMEBREW_PREFIX/"share/pkgconfig",
+ homebrew_extra_pkg_config_paths,
+ "/usr/lib/pkgconfig",
+ ).existing
end
# Removes the MAKEFLAGS environment variable, causing make to use a single job.
diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb
index 0935647f5..ef41161af 100644
--- a/Library/Homebrew/extend/ENV/super.rb
+++ b/Library/Homebrew/extend/ENV/super.rb
@@ -101,29 +101,28 @@ module Superenv
end
def determine_path
- paths = [Superenv.bin]
+ path = PATH.new(Superenv.bin)
# Formula dependencies can override standard tools.
- paths += deps.map { |d| d.opt_bin.to_s }
-
- paths += homebrew_extra_paths
- paths += %w[/usr/bin /bin /usr/sbin /sbin]
+ path.append(deps.map(&:opt_bin))
+ path.append(homebrew_extra_paths)
+ path.append("/usr/bin", "/bin", "/usr/sbin", "/sbin")
# Homebrew's apple-gcc42 will be outside the PATH in superenv,
# so xcrun may not be able to find it
begin
case homebrew_cc
when "gcc-4.2"
- paths << Formulary.factory("apple-gcc42").opt_bin
+ path.append(Formulary.factory("apple-gcc42").opt_bin)
when GNU_GCC_REGEXP
- paths << gcc_version_formula($&).opt_bin
+ path.append(gcc_version_formula($&).opt_bin)
end
rescue FormulaUnavailableError
# Don't fail and don't add these formulae to the path if they don't exist.
nil
end
- paths.to_path_s
+ path.existing
end
def homebrew_extra_pkg_config_paths
@@ -131,15 +130,17 @@ module Superenv
end
def determine_pkg_config_path
- paths = deps.map { |d| "#{d.opt_lib}/pkgconfig" }
- paths += deps.map { |d| "#{d.opt_share}/pkgconfig" }
- paths.to_path_s
+ PATH.new(
+ deps.map { |d| d.opt_lib/"pkgconfig" },
+ deps.map { |d| d.opt_share/"pkgconfig" },
+ ).existing
end
def determine_pkg_config_libdir
- paths = %w[/usr/lib/pkgconfig]
- paths += homebrew_extra_pkg_config_paths
- paths.to_path_s
+ PATH.new(
+ "/usr/lib/pkgconfig",
+ homebrew_extra_pkg_config_paths,
+ ).existing
end
def homebrew_extra_aclocal_paths
@@ -147,10 +148,11 @@ module Superenv
end
def determine_aclocal_path
- paths = keg_only_deps.map { |d| "#{d.opt_share}/aclocal" }
- paths << "#{HOMEBREW_PREFIX}/share/aclocal"
- paths += homebrew_extra_aclocal_paths
- paths.to_path_s
+ PATH.new(
+ keg_only_deps.map { |d| d.opt_share/"aclocal" },
+ HOMEBREW_PREFIX/"share/aclocal",
+ homebrew_extra_aclocal_paths,
+ ).existing
end
def homebrew_extra_isystem_paths
@@ -158,13 +160,14 @@ module Superenv
end
def determine_isystem_paths
- paths = ["#{HOMEBREW_PREFIX}/include"]
- paths += homebrew_extra_isystem_paths
- paths.to_path_s
+ PATH.new(
+ HOMEBREW_PREFIX/"include",
+ homebrew_extra_isystem_paths,
+ ).existing
end
def determine_include_paths
- keg_only_deps.map { |d| d.opt_include.to_s }.to_path_s
+ PATH.new(keg_only_deps.map(&:opt_include)).existing
end
def homebrew_extra_library_paths
@@ -172,10 +175,11 @@ module Superenv
end
def determine_library_paths
- paths = keg_only_deps.map { |d| d.opt_lib.to_s }
- paths << "#{HOMEBREW_PREFIX}/lib"
- paths += homebrew_extra_library_paths
- paths.to_path_s
+ PATH.new(
+ keg_only_deps.map(&:opt_lib),
+ HOMEBREW_PREFIX/"lib",
+ homebrew_extra_library_paths,
+ ).existing
end
def determine_dependencies
@@ -183,9 +187,10 @@ module Superenv
end
def determine_cmake_prefix_path
- paths = keg_only_deps.map { |d| d.opt_prefix.to_s }
- paths << HOMEBREW_PREFIX.to_s
- paths.to_path_s
+ PATH.new(
+ keg_only_deps.map(&:opt_prefix),
+ HOMEBREW_PREFIX.to_s,
+ ).existing
end
def homebrew_extra_cmake_include_paths
@@ -193,9 +198,7 @@ module Superenv
end
def determine_cmake_include_path
- paths = []
- paths += homebrew_extra_cmake_include_paths
- paths.to_path_s
+ PATH.new(homebrew_extra_cmake_include_paths).existing
end
def homebrew_extra_cmake_library_paths
@@ -203,9 +206,7 @@ module Superenv
end
def determine_cmake_library_path
- paths = []
- paths += homebrew_extra_cmake_library_paths
- paths.to_path_s
+ PATH.new(homebrew_extra_cmake_library_paths).existing
end
def homebrew_extra_cmake_frameworks_paths
@@ -213,9 +214,10 @@ module Superenv
end
def determine_cmake_frameworks_path
- paths = deps.map { |d| d.opt_frameworks.to_s }
- paths += homebrew_extra_cmake_frameworks_paths
- paths.to_path_s
+ PATH.new(
+ deps.map(&:opt_frameworks),
+ homebrew_extra_cmake_frameworks_paths,
+ ).existing
end
def determine_make_jobs
@@ -326,15 +328,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)
- end
-end
-
-class Array
- def to_path_s
- map(&:to_s).uniq.select { |s| File.directory? s }.join(File::PATH_SEPARATOR).chuzzle
+ 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/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/diagnostic.rb b/Library/Homebrew/extend/os/mac/diagnostic.rb
index fb6b30836..ff936c75a 100644
--- a/Library/Homebrew/extend/os/mac/diagnostic.rb
+++ b/Library/Homebrew/extend/os/mac/diagnostic.rb
@@ -263,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/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/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..c413e9e94 100644
--- a/Library/Homebrew/extend/pathname.rb
+++ b/Library/Homebrew/extend/pathname.rb
@@ -331,7 +331,6 @@ class Pathname
raise ChecksumMismatchError.new(self, expected, actual) unless expected == actual
end
- # FIXME: eliminate the places where we rely on this method
alias to_str to_s unless method_defined?(:to_str)
def cd
@@ -365,9 +364,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 d544bd668..1230199bf 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -13,6 +13,7 @@ require "pkg_version"
require "tap"
require "keg"
require "migrator"
+require "extend/ENV"
# A formula provides instructions and metadata for Homebrew to install a piece
# of software. Every Homebrew formula is a {Formula}.
@@ -1004,19 +1005,26 @@ class Formula
def post_install; end
# @private
- def post_install_defined?
- method(:post_install).owner == self.class
- end
-
- # @private
def run_post_install
@prefix_returns_versioned_prefix = true
build = self.build
self.build = Tab.for_formula(self)
+
old_tmpdir = ENV["TMPDIR"]
old_temp = ENV["TEMP"]
old_tmp = ENV["TMP"]
+ old_path = ENV["HOMEBREW_PATH"]
+
ENV["TMPDIR"] = ENV["TEMP"] = ENV["TMP"] = HOMEBREW_TEMP
+ ENV["HOMEBREW_PATH"] = nil
+
+ ENV.clear_sensitive_environment!
+
+ Pathname.glob("#{bottle_prefix}/{etc,var}/**/*") do |path|
+ path.extend(InstallRenamed)
+ path.cp_path_sub(bottle_prefix, HOMEBREW_PREFIX)
+ end
+
with_logging("post_install") do
post_install
end
@@ -1025,6 +1033,7 @@ class Formula
ENV["TMPDIR"] = old_tmpdir
ENV["TEMP"] = old_temp
ENV["TMP"] = old_tmp
+ ENV["HOMEBREW_PATH"] = old_path
@prefix_returns_versioned_prefix = false
end
@@ -1664,9 +1673,15 @@ class Formula
old_temp = ENV["TEMP"]
old_tmp = ENV["TMP"]
old_term = ENV["TERM"]
+ old_path = ENV["HOMEBREW_PATH"]
+
ENV["CURL_HOME"] = old_curl_home || old_home
ENV["TMPDIR"] = ENV["TEMP"] = ENV["TMP"] = HOMEBREW_TEMP
ENV["TERM"] = "dumb"
+ ENV["HOMEBREW_PATH"] = nil
+
+ ENV.clear_sensitive_environment!
+
mktemp("#{name}-test") do |staging|
staging.retain! if ARGV.keep_tmp?
@testpath = staging.tmpdir
@@ -1689,6 +1704,7 @@ class Formula
ENV["TEMP"] = old_temp
ENV["TMP"] = old_tmp
ENV["TERM"] = old_term
+ ENV["HOMEBREW_PATH"] = old_path
@prefix_returns_versioned_prefix = false
end
@@ -1892,7 +1908,6 @@ class Formula
def exec_cmd(cmd, args, out, logfn)
ENV["HOMEBREW_CC_LOG_PATH"] = logfn
- # TODO: system "xcodebuild" is deprecated, this should be removed soon.
ENV.remove_cc_etc if cmd.to_s.start_with? "xcodebuild"
# Turn on argument filtering in the superenv compiler wrapper.
@@ -1925,17 +1940,28 @@ class Formula
mkdir_p env_home
old_home = ENV["HOME"]
- ENV["HOME"] = env_home
old_curl_home = ENV["CURL_HOME"]
- ENV["CURL_HOME"] = old_curl_home || old_home
+ old_path = ENV["HOMEBREW_PATH"]
+
+ unless ARGV.interactive?
+ ENV["HOME"] = env_home
+ ENV["CURL_HOME"] = old_curl_home || old_home
+ end
+ ENV["HOMEBREW_PATH"] = nil
+
setup_home env_home
+ ENV.clear_sensitive_environment!
+
begin
yield staging
ensure
@buildpath = nil
- ENV["HOME"] = old_home
- ENV["CURL_HOME"] = old_curl_home
+ unless ARGV.interactive?
+ ENV["HOME"] = old_home
+ ENV["CURL_HOME"] = old_curl_home
+ end
+ ENV["HOMEBREW_PATH"] = old_path
end
end
end
@@ -2396,7 +2422,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 017be51dc..f50d9ed9e 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|
@@ -229,11 +217,20 @@ class FormulaInstaller
# function but after instantiating this class so that it can avoid having to
# relink the active keg if possible (because it is slow).
if formula.linked_keg.directory?
- # some other version is already installed *and* linked
- raise CannotInstallFormulaError, <<-EOS.undent
- #{formula.name}-#{formula.linked_keg.resolved_path.basename} already installed
- To install this version, first `brew unlink #{formula.name}`
+ message = <<-EOS.undent
+ #{formula.name} #{formula.linked_keg.resolved_path.basename} is already installed
EOS
+ message += if formula.outdated? && !formula.head?
+ <<-EOS.undent
+ To upgrade to #{formula.version}, run `brew upgrade #{formula.name}`
+ EOS
+ else
+ # some other version is already installed *and* linked
+ <<-EOS.undent
+ To install #{formula.version}, first run `brew unlink #{formula.name}`
+ EOS
+ end
+ raise CannotInstallFormulaError, message
end
check_conflicts
@@ -567,13 +564,11 @@ class FormulaInstaller
fix_dynamic_linkage(keg)
end
- if formula.post_install_defined?
- if build_bottle?
- ohai "Not running post_install as we're building a bottle"
- puts "You can run it manually using `brew postinstall #{formula.full_name}`"
- else
- post_install
- end
+ if build_bottle?
+ ohai "Not running post_install as we're building a bottle"
+ puts "You can run it manually using `brew postinstall #{formula.full_name}`"
+ else
+ post_install
end
caveats
@@ -661,13 +656,15 @@ class FormulaInstaller
Sandbox.print_sandbox_message if Sandbox.formula?(formula)
Utils.safe_fork do
- # Invalidate the current sudo timestamp in case a build script calls sudo
- system "/usr/bin/sudo", "-k"
+ # Invalidate the current sudo timestamp in case a build script calls sudo.
+ # Travis CI's Linux sudoless workers have a weird sudo that fails here.
+ system "/usr/bin/sudo", "-k" unless ENV["TRAVIS_SUDO"] == "false"
if Sandbox.formula?(formula)
sandbox = Sandbox.new
formula.logs.mkpath
sandbox.record_log(formula.logs/"build.sandbox.log")
+ sandbox.allow_write_path(ENV["HOME"]) if ARGV.interactive?
sandbox.allow_write_temp_and_cache
sandbox.allow_write_log(formula)
sandbox.allow_write_xcode
@@ -835,12 +832,6 @@ class FormulaInstaller
skip_linkage = formula.bottle_specification.skip_relocation?
keg.replace_placeholders_with_locations tab.changed_files, skip_linkage: skip_linkage
- Pathname.glob("#{formula.bottle_prefix}/{etc,var}/**/*") do |path|
- path.extend(InstallRenamed)
- path.cp_path_sub(formula.bottle_prefix, HOMEBREW_PREFIX)
- end
- FileUtils.rm_rf formula.bottle_prefix
-
tab = Tab.for_keg(keg)
CxxStdlib.check_compatibility(
@@ -858,15 +849,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
@@ -899,6 +890,6 @@ class FormulaInstaller
def puts_requirement_messages
return unless @requirement_messages
return if @requirement_messages.empty?
- puts @requirement_messages
+ $stderr.puts @requirement_messages
end
end
diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb
index b8476f5cc..4d963a55e 100644
--- a/Library/Homebrew/formula_support.rb
+++ b/Library/Homebrew/formula_support.rb
@@ -32,30 +32,30 @@ class KegOnlyReason
return @explanation unless @explanation.empty?
case @reason
when :versioned_formula then <<-EOS.undent
- This is an alternate version of another formula.
+ this is an alternate version of another formula
EOS
when :provided_by_macos, :provided_by_osx then <<-EOS.undent
macOS already provides this software and installing another version in
- parallel can cause all kinds of trouble.
+ parallel can cause all kinds of trouble
EOS
when :shadowed_by_macos, :shadowed_by_osx then <<-EOS.undent
macOS provides similar software and installing this software in
- parallel can cause all kinds of trouble.
+ parallel can cause all kinds of trouble
EOS
when :provided_pre_mountain_lion then <<-EOS.undent
- macOS already provides this software in versions before Mountain Lion.
+ macOS already provides this software in versions before Mountain Lion
EOS
when :provided_pre_mavericks then <<-EOS.undent
- macOS already provides this software in versions before Mavericks.
+ macOS already provides this software in versions before Mavericks
EOS
when :provided_pre_el_capitan then <<-EOS.undent
- macOS already provides this software in versions before El Capitan.
+ macOS already provides this software in versions before El Capitan
EOS
when :provided_until_xcode43 then <<-EOS.undent
- Xcode provides this software prior to version 4.3.
+ Xcode provides this software prior to version 4.3
EOS
when :provided_until_xcode5 then <<-EOS.undent
- Xcode provides this software prior to version 5.
+ Xcode provides this software prior to version 5
EOS
else
@reason
diff --git a/Library/Homebrew/formula_versions.rb b/Library/Homebrew/formula_versions.rb
index 28c2a3be8..70706a2f0 100644
--- a/Library/Homebrew/formula_versions.rb
+++ b/Library/Homebrew/formula_versions.rb
@@ -7,21 +7,22 @@ class FormulaVersions
ErrorDuringExecution, LoadError, MethodDeprecatedError
].freeze
+ MAX_VERSIONS_DEPTH = 2
+
attr_reader :name, :path, :repository, :entry_name
- def initialize(formula, options = {})
+ def initialize(formula)
@name = formula.name
@path = formula.path
@repository = formula.tap.path
@entry_name = @path.relative_path_from(repository).to_s
- @max_depth = options[:max_depth]
+ @current_formula = formula
end
def rev_list(branch)
repository.cd do
- depth = 0
Utils.popen_read("git", "rev-list", "--abbrev-commit", "--remove-empty", branch, "--", entry_name) do |io|
- yield io.readline.chomp until io.eof? || (@max_depth && (depth += 1) > @max_depth)
+ yield io.readline.chomp until io.eof?
end
end
end
@@ -49,11 +50,15 @@ class FormulaVersions
def bottle_version_map(branch)
map = Hash.new { |h, k| h[k] = [] }
+
+ versions_seen = 0
rev_list(branch) do |rev|
formula_at_revision(rev) do |f|
bottle = f.bottle_specification
map[f.pkg_version] << bottle.rebuild unless bottle.checksums.empty?
+ versions_seen = (map.keys + [f.pkg_version]).uniq.length
end
+ return map if versions_seen > MAX_VERSIONS_DEPTH
end
map
end
@@ -63,26 +68,38 @@ class FormulaVersions
return attributes_map if attributes.empty?
attributes.each do |attribute|
- attributes_map[attribute] ||= {}
+ attributes_map[attribute] ||= {
+ stable: {},
+ devel: {},
+ }
end
+ stable_versions_seen = 0
rev_list(branch) do |rev|
formula_at_revision(rev) do |f|
attributes.each do |attribute|
map = attributes_map[attribute]
- if f.stable
- map[:stable] ||= {}
- map[:stable][f.stable.version] ||= []
- map[:stable][f.stable.version] << f.send(attribute)
- end
- next unless f.devel
- map[:devel] ||= {}
- map[:devel][f.devel.version] ||= []
- map[:devel][f.devel.version] << f.send(attribute)
+ set_attribute_map(map, f, attribute)
+
+ stable_keys_length = (map[:stable].keys + [f.version]).uniq.length
+ stable_versions_seen = [stable_versions_seen, stable_keys_length].max
end
end
+ break if stable_versions_seen > MAX_VERSIONS_DEPTH
end
attributes_map
end
+
+ private
+
+ def set_attribute_map(map, f, attribute)
+ if f.stable
+ map[:stable][f.stable.version] ||= []
+ map[:stable][f.stable.version] << f.send(attribute)
+ end
+ return unless f.devel
+ map[:devel][f.devel.version] ||= []
+ map[:devel][f.devel.version] << f.send(attribute)
+ end
end
diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb
index 4a65f8704..446d5dc10 100644
--- a/Library/Homebrew/formulary.rb
+++ b/Library/Homebrew/formulary.rb
@@ -105,7 +105,18 @@ module Formulary
# Loads formulae from bottles.
class BottleLoader < FormulaLoader
def initialize(bottle_name)
- @bottle_filename = Pathname(bottle_name).realpath
+ case bottle_name
+ when %r{(https?|ftp|file)://}
+ # The name of the formula is found between the last slash and the last hyphen.
+ resource = Resource.new bottle_name[%r{([^/]+)-}, 1] { url bottle_name }
+ downloader = CurlBottleDownloadStrategy.new resource.name, resource
+ @bottle_filename = downloader.cached_location
+ cached = @bottle_filename.exist?
+ downloader.fetch
+ ohai "Pouring the cached bottle" if cached
+ else
+ @bottle_filename = Pathname(bottle_name).realpath
+ end
name, full_name = Utils::Bottles.resolve_formula_names @bottle_filename
super name, Formulary.path(full_name)
end
@@ -210,6 +221,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
@@ -331,10 +346,10 @@ module Formulary
def self.loader_for(ref, from: nil)
case ref
- when %r{(https?|ftp|file)://}
- return FromUrlLoader.new(ref)
when Pathname::BOTTLE_EXTNAME_RX
return BottleLoader.new(ref)
+ when %r{(https?|ftp|file)://}
+ return FromUrlLoader.new(ref)
when HOMEBREW_TAP_FORMULA_REGEX
return TapLoader.new(ref, from: from)
end
@@ -402,7 +417,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/global.rb b/Library/Homebrew/global.rb
index 391f5b012..877253072 100644
--- a/Library/Homebrew/global.rb
+++ b/Library/Homebrew/global.rb
@@ -3,6 +3,7 @@ require "extend/fileutils"
require "extend/pathname"
require "extend/git_repository"
require "extend/ARGV"
+require "PATH"
require "extend/string"
require "os"
require "utils"
@@ -10,6 +11,7 @@ require "exceptions"
require "set"
require "rbconfig"
require "official_taps"
+require "pp"
ARGV.extend(HomebrewArgvExtension)
@@ -53,7 +55,8 @@ HOMEBREW_PULL_OR_COMMIT_URL_REGEX = %r[https://github\.com/([\w-]+)/([\w-]+)?/(?
require "compat" unless ARGV.include?("--no-compat") || ENV["HOMEBREW_NO_COMPAT"]
-ORIGINAL_PATHS = ENV["PATH"].split(File::PATH_SEPARATOR).map do |p|
+ENV["HOMEBREW_PATH"] ||= ENV["PATH"]
+ORIGINAL_PATHS = PATH.new(ENV["HOMEBREW_PATH"]).map do |p|
begin
Pathname.new(p).expand_path
rescue
@@ -61,7 +64,6 @@ ORIGINAL_PATHS = ENV["PATH"].split(File::PATH_SEPARATOR).map do |p|
end
end.compact.freeze
-# TODO: remove this as soon as it's removed from commands.rb.
HOMEBREW_INTERNAL_COMMAND_ALIASES = {
"ls" => "list",
"homepage" => "home",
diff --git a/Library/Homebrew/gpg.rb b/Library/Homebrew/gpg.rb
index 777542055..cb9e367df 100644
--- a/Library/Homebrew/gpg.rb
+++ b/Library/Homebrew/gpg.rb
@@ -6,6 +6,7 @@ class Gpg
gpg_short_version = Utils.popen_read(gpg, "--version")[/\d\.\d/, 0]
next unless gpg_short_version
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
@@ -25,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 d4b9c5d77..8733def27 100644
--- a/Library/Homebrew/keg.rb
+++ b/Library/Homebrew/keg.rb
@@ -468,7 +468,10 @@ class Keg
end
def aliases
- Formulary.from_rack(rack).aliases
+ formula = Formulary.from_rack(rack)
+ aliases = formula.aliases
+ return aliases if formula.stable?
+ aliases.reject { |a| a.include?("@") }
rescue FormulaUnavailableError
[]
end
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/manpages/brew.1.md.erb b/Library/Homebrew/manpages/brew.1.md.erb
index 5b0228e3f..29f8d0bec 100644
--- a/Library/Homebrew/manpages/brew.1.md.erb
+++ b/Library/Homebrew/manpages/brew.1.md.erb
@@ -98,8 +98,15 @@ can take several different forms:
The formula file will be cached for later use.
## ENVIRONMENT
+ * `HOMEBREW_ARTIFACT_DOMAIN`:
+ If set, instructs Homebrew to use the given URL as a download mirror for bottles and binaries.
+
+ * `HOMEBREW_AUTO_UPDATE_SECS`:
+ If set, Homebrew will only check for autoupdates once per this seconds interval.
+
+ *Default:* `60`.
- * `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`:
+ * `HOMEBREW_AWS_ACCESS_KEY_ID`, `HOMEBREW_AWS_SECRET_ACCESS_KEY`:
When using the `S3` download strategy, Homebrew will look in
these variables for access credentials (see
<https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-environment>
@@ -107,30 +114,9 @@ can take several different forms:
the `S3` download strategy will download with a public
(unsigned) URL.
- * `BROWSER`:
- If set, and `HOMEBREW_BROWSER` is not, use `BROWSER` as the web browser
- when opening project homepages.
-
- * `EDITOR`:
- If set, and `HOMEBREW_EDITOR` and `VISUAL` are not, use `EDITOR` as the text editor.
-
- * `GIT`:
- When using Git, Homebrew will use `GIT` if set,
- a Homebrew-built Git if installed, or the system-provided binary.
-
- Set this to force Homebrew to use a particular git binary.
-
* `HOMEBREW_BOTTLE_DOMAIN`:
If set, instructs Homebrew to use the given URL as a download mirror for bottles.
- * `HOMEBREW_ARTIFACT_DOMAIN`:
- If set, instructs Homebrew to use the given URL as a download mirror for bottles and binaries.
-
- * `HOMEBREW_AUTO_UPDATE_SECS`:
- If set, Homebrew will only check for autoupdates once per this seconds interval.
-
- *Default:* `60`.
-
* `HOMEBREW_BROWSER`:
If set, uses this setting as the browser when opening project homepages,
instead of the OS default browser.
@@ -178,6 +164,12 @@ can take several different forms:
If set, Homebrew will always use its vendored, relocatable Ruby 2.0 version
even if the system version of Ruby is >=2.0.
+ * `HOMEBREW_GIT`:
+ When using Git, Homebrew will use `GIT` if set,
+ a Homebrew-built Git if installed, or the system-provided binary.
+
+ Set this to force Homebrew to use a particular git binary.
+
* `HOMEBREW_GITHUB_API_TOKEN`:
A personal access token for the GitHub API, which you can create at
<https://github.com/settings/tokens>. If set, GitHub will allow you a
@@ -243,9 +235,6 @@ can take several different forms:
* `HOMEBREW_VERBOSE`:
If set, Homebrew always assumes `--verbose` when running commands.
- * `VISUAL`:
- If set, and `HOMEBREW_EDITOR` is not, use `VISUAL` as the text editor.
-
## USING HOMEBREW BEHIND A PROXY
Homebrew uses several commands for downloading files (e.g. `curl`, `git`, `svn`).
diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb
index 5b903b899..eac3d7725 100644
--- a/Library/Homebrew/missing_formula.rb
+++ b/Library/Homebrew/missing_formula.rb
@@ -122,7 +122,7 @@ module Homebrew
path = Formulary.path name
return if File.exist? path
tap = Tap.from_path(path)
- return unless File.exist? tap.path
+ return if tap.nil? || !File.exist?(tap.path)
relative_path = path.relative_path_from tap.path
tap.path.cd do
diff --git a/Library/Homebrew/official_taps.rb b/Library/Homebrew/official_taps.rb
index a7bc4a1d6..dcb65d9f8 100644
--- a/Library/Homebrew/official_taps.rb
+++ b/Library/Homebrew/official_taps.rb
@@ -5,8 +5,29 @@ OFFICIAL_TAPS = %w[
science
].freeze
+OFFICIAL_CASK_TAPS = %w[
+ cask
+ versions
+].freeze
+
OFFICIAL_CMD_TAPS = {
"homebrew/bundle" => ["bundle"],
"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 518936647..dba2480ef 100644
--- a/Library/Homebrew/os/mac.rb
+++ b/Library/Homebrew/os/mac.rb
@@ -205,6 +205,8 @@ module OS
"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 70fe3c14d..9ed95d3f2 100644
--- a/Library/Homebrew/os/mac/xcode.rb
+++ b/Library/Homebrew/os/mac/xcode.rb
@@ -17,12 +17,12 @@ module OS
when "10.9" then "6.2"
when "10.10" then "7.2.1"
when "10.11" then "8.2.1"
- when "10.12" then "8.3"
+ 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.3"
+ "8.3.2"
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"
@@ -214,7 +213,7 @@ 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 "802.0.38"
+ when "10.12" then "802.0.42"
when "10.11" then "800.0.42.1"
when "10.10" then "700.1.81"
when "10.9" then "600.0.57"
diff --git a/Library/Homebrew/os/mac/xquartz.rb b/Library/Homebrew/os/mac/xquartz.rb
index b82772faf..2fdf0abea 100644
--- a/Library/Homebrew/os/mac/xquartz.rb
+++ b/Library/Homebrew/os/mac/xquartz.rb
@@ -5,7 +5,6 @@ module OS
module XQuartz
module_function
- # TODO: confirm this path when you have internet
DEFAULT_BUNDLE_PATH = Pathname.new("Applications/Utilities/XQuartz.app").freeze
FORGE_BUNDLE_ID = "org.macosforge.xquartz.X11".freeze
APPLE_BUNDLE_ID = "org.x.X11".freeze
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 bd8cf20c8..6c20e7917 100644
--- a/Library/Homebrew/requirement.rb
+++ b/Library/Homebrew/requirement.rb
@@ -96,7 +96,7 @@ class Requirement
# PATH.
parent = satisfied_result_parent
return unless parent
- return if ENV["PATH"].split(File::PATH_SEPARATOR).include?(parent.to_s)
+ return if PATH.new(ENV["PATH"]).include?(parent.to_s)
ENV.append_path("PATH", parent)
end
@@ -151,21 +151,19 @@ class Requirement
end
def which(cmd)
- super(cmd, ORIGINAL_PATHS.join(File::PATH_SEPARATOR))
+ super(cmd, PATH.new(ORIGINAL_PATHS))
end
def which_all(cmd)
- super(cmd, ORIGINAL_PATHS.join(File::PATH_SEPARATOR))
+ super(cmd, PATH.new(ORIGINAL_PATHS))
end
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/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/rubocops.rb b/Library/Homebrew/rubocops.rb
index 3625f2004..587bf4b20 100644
--- a/Library/Homebrew/rubocops.rb
+++ b/Library/Homebrew/rubocops.rb
@@ -1,2 +1,5 @@
require_relative "./rubocops/bottle_block_cop"
require_relative "./rubocops/formula_desc_cop"
+require_relative "./rubocops/components_order_cop"
+require_relative "./rubocops/components_redundancy_cop"
+require_relative "./rubocops/homepage_cop"
diff --git a/Library/Homebrew/rubocops/bottle_block_cop.rb b/Library/Homebrew/rubocops/bottle_block_cop.rb
index 4d7a94461..f0c7d59bb 100644
--- a/Library/Homebrew/rubocops/bottle_block_cop.rb
+++ b/Library/Homebrew/rubocops/bottle_block_cop.rb
@@ -2,18 +2,18 @@ require_relative "./extend/formula_cop"
module RuboCop
module Cop
- module Homebrew
+ module FormulaAuditStrict
# This cop audits `bottle` block in Formulae
#
# - `rebuild` should be used instead of `revision` in `bottle` block
- class CorrectBottleBlock < FormulaCop
+ class BottleBlock < FormulaCop
MSG = "Use rebuild instead of revision in bottle block".freeze
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)
+ problem "Use rebuild instead of revision in bottle block" if method_called_in_block?(bottle, :revision)
end
private
diff --git a/Library/Homebrew/rubocops/components_order_cop.rb b/Library/Homebrew/rubocops/components_order_cop.rb
new file mode 100644
index 000000000..dfddbe145
--- /dev/null
+++ b/Library/Homebrew/rubocops/components_order_cop.rb
@@ -0,0 +1,114 @@
+require_relative "./extend/formula_cop"
+
+module RuboCop
+ module Cop
+ module FormulaAuditStrict
+ # This cop checks for correct order of components in a Formula
+ #
+ # - component_precedence_list has component hierarchy in a nested list
+ # where each sub array contains components' details which are at same precedence level
+ class ComponentsOrder < FormulaCop
+ def audit_formula(_node, _class_node, _parent_class_node, formula_class_body_node)
+ component_precedence_list = [
+ [{ name: :include, type: :method_call }],
+ [{ name: :desc, type: :method_call }],
+ [{ name: :homepage, type: :method_call }],
+ [{ name: :url, type: :method_call }],
+ [{ name: :mirror, type: :method_call }],
+ [{ name: :version, type: :method_call }],
+ [{ name: :sha256, type: :method_call }],
+ [{ name: :revision, type: :method_call }],
+ [{ name: :version_scheme, type: :method_call }],
+ [{ name: :head, type: :method_call }],
+ [{ name: :stable, type: :block_call }],
+ [{ name: :bottle, type: :block_call }],
+ [{ name: :devel, type: :block_call }],
+ [{ name: :head, type: :block_call }],
+ [{ name: :bottle, type: :method_call }],
+ [{ name: :keg_only, type: :method_call }],
+ [{ name: :option, type: :method_call }],
+ [{ name: :depends_on, type: :method_call }],
+ [{ name: :conflicts_with, type: :method_call }],
+ [{ name: :go_resource, type: :block_call }, { name: :resource, type: :block_call }],
+ [{ name: :install, type: :method_definition }],
+ [{ name: :caveats, type: :method_definition }],
+ [{ name: :plist_options, type: :method_call }, { name: :plist, type: :method_definition }],
+ [{ name: :test, type: :block_call }],
+ ]
+
+ @present_components = component_precedence_list.map do |components|
+ relevant_components = []
+ components.each do |component|
+ case component[:type]
+ when :method_call
+ relevant_components += find_method_calls_by_name(formula_class_body_node, component[:name]).to_a
+ when :block_call
+ relevant_components += find_blocks(formula_class_body_node, component[:name]).to_a
+ when :method_definition
+ relevant_components << find_method_def(formula_class_body_node, component[:name])
+ end
+ end
+ relevant_components.delete_if(&:nil?)
+ end
+
+ # Check if each present_components is above rest of the present_components
+ @present_components.take(@present_components.size-1).each_with_index do |preceding_component, p_idx|
+ next if preceding_component.empty?
+ @present_components.drop(p_idx+1).each do |succeeding_component|
+ next if succeeding_component.empty?
+ @offensive_nodes = check_precedence(preceding_component, succeeding_component)
+ component_problem @offensive_nodes[0], @offensive_nodes[1] if @offensive_nodes
+ end
+ end
+ end
+
+ private
+
+ # Method to format message for reporting component precedence violations
+ def component_problem(c1, c2)
+ problem "`#{format_component(c1)}` (line #{line_number(c1)}) should be put before `#{format_component(c2)}` (line #{line_number(c2)})"
+ end
+
+ # autocorrect method gets called just after component_problem method call
+ def autocorrect(_node)
+ succeeding_node = @offensive_nodes[0]
+ preceding_node = @offensive_nodes[1]
+ lambda do |corrector|
+ reorder_components(corrector, succeeding_node, preceding_node)
+ end
+ end
+
+ # Reorder two nodes in the source, using the corrector instance in autocorrect method
+ # Components of same type are grouped together when rewriting the source
+ # Linebreaks are introduced if components are of two different methods/blocks/multilines
+ def reorder_components(corrector, node1, node2)
+ # order_idx : node1's index in component_precedence_list
+ # curr_p_idx: node1's index in preceding_comp_arr
+ # preceding_comp_arr: array containing components of same type
+ order_idx, curr_p_idx, preceding_comp_arr = get_state(node1)
+
+ # curr_p_idx > 0 means node1 needs to be grouped with its own kind
+ if curr_p_idx>0
+ node2 = preceding_comp_arr[curr_p_idx-1]
+ indentation = " " * (start_column(node2) - line_start_column(node2))
+ line_breaks = node2.multiline? ? "\n\n" : "\n"
+ corrector.insert_after(node2.source_range, line_breaks+indentation+node1.source)
+ else
+ indentation = " " * (start_column(node2) - line_start_column(node2))
+ # No line breaks upto version_scheme, order_idx == 8
+ line_breaks = order_idx>8 ? "\n\n" : "\n"
+ corrector.insert_before(node2.source_range, node1.source+line_breaks+indentation)
+ end
+ corrector.remove(range_with_surrounding_space(node1.source_range, :left))
+ end
+
+ # Returns precedence index and component's index to properly reorder and group during autocorrect
+ def get_state(node1)
+ @present_components.each_with_index do |comp, idx|
+ return [idx, comp.index(node1), comp] if comp.member?(node1)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/rubocops/components_redundancy_cop.rb b/Library/Homebrew/rubocops/components_redundancy_cop.rb
new file mode 100644
index 000000000..52dba4718
--- /dev/null
+++ b/Library/Homebrew/rubocops/components_redundancy_cop.rb
@@ -0,0 +1,33 @@
+require_relative "./extend/formula_cop"
+
+module RuboCop
+ module Cop
+ module FormulaAuditStrict
+ # This cop checks if redundant components are present and other component errors
+ #
+ # - `url|checksum|mirror` should be inside `stable` block
+ # - `head` and `head do` should not be simultaneously present
+ # - `bottle :unneeded/:disable` and `bottle do` should not be simultaneously present
+
+ class ComponentsRedundancy < FormulaCop
+ HEAD_MSG = "`head` and `head do` should not be simultaneously present".freeze
+ BOTTLE_MSG = "`bottle :modifier` and `bottle do` should not be simultaneously present".freeze
+
+ def audit_formula(_node, _class_node, _parent_class_node, formula_class_body_node)
+ stable_block = find_block(formula_class_body_node, :stable)
+ if stable_block
+ [:url, :sha256, :mirror].each do |method_name|
+ problem "`#{method_name}` should be put inside `stable` block" if method_called?(formula_class_body_node, method_name)
+ end
+ end
+
+ problem HEAD_MSG if method_called?(formula_class_body_node, :head) &&
+ find_block(formula_class_body_node, :head)
+
+ problem BOTTLE_MSG if method_called?(formula_class_body_node, :bottle) &&
+ find_block(formula_class_body_node, :bottle)
+ end
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb
index 49108bd48..3f70086b3 100644
--- a/Library/Homebrew/rubocops/extend/formula_cop.rb
+++ b/Library/Homebrew/rubocops/extend/formula_cop.rb
@@ -1,143 +1,212 @@
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
+ class FormulaCop < Cop
+ @registry = Cop.registry
+
+ # This method is called by RuboCop and is the main entry point
+ def on_class(node)
+ 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
+ # Checks for regex match of pattern in the node and
+ # Sets the appropriate instance variables to report the match
+ def regex_match_group(node, pattern)
+ 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
+ # Returns method_node matching method_name
+ def find_node_method_by_name(node, 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
+
+ # Returns an array of method call nodes matching method_name inside node
+ def find_method_calls_by_name(node, method_name)
+ return if node.nil?
+ node.each_child_node(:send).select { |method_node| method_name == method_node.method_name }
+ end
+
+ # Returns a block named block_name inside node
+ def find_block(node, block_name)
+ 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
+
+ # Returns an array of block nodes named block_name inside node
+ def find_blocks(node, block_name)
+ return if node.nil?
+ node.each_child_node(:block).select { |block_node| block_name == block_node.method_name }
+ end
+
+ # Returns a method definition node with method_name
+ def find_method_def(node, method_name)
+ return if node.nil?
+ node.each_child_node(:def) do |def_node|
+ def_method_name = method_name(def_node)
+ next unless method_name == def_method_name
+ @offensive_node = def_node
+ @offense_source_range = def_node.source_range
+ return def_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
+
+ # Check if a method is called inside a block
+ def method_called_in_block?(node, method_name)
+ 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 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
+ # Check if method_name is called among the direct children nodes in the given node
+ def method_called?(node, method_name)
+ node.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 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
+ # Checks for precedence, returns the first pair of precedence violating nodes
+ def check_precedence(first_nodes, next_nodes)
+ next_nodes.each do |each_next_node|
+ first_nodes.each do |each_first_node|
+ if component_precedes?(each_first_node, each_next_node)
+ return [each_first_node, each_next_node]
+ end
end
- false
end
+ nil
+ 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
+ # If first node does not precede next_node, sets appropriate instance variables for reporting
+ def component_precedes?(first_node, next_node)
+ return false if line_number(first_node) < line_number(next_node)
+ @offense_source_range = first_node.source_range
+ @offensive_node = first_node
+ true
+ 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
+ # Returns the array of arguments of the method_node
+ def parameters(method_node)
+ return unless method_node.send_type?
+ method_node.method_args
+ end
- def start_column(node)
- # Returns the begin position of the node in source code
- node.source_range.begin_pos
- end
+ # Returns the begin position of the node's line in source code
+ def line_start_column(node)
+ node.source_range.source_buffer.line_range(node.loc.line).begin_pos
+ end
- def line_number(node)
- # Returns the line number of the node
- node.loc.line
- end
+ # Returns the begin position of the node in source code
+ def start_column(node)
+ node.source_range.begin_pos
+ 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
+ # Returns the line number of the node
+ def line_number(node)
+ node.loc.line
+ end
- def size(node)
- # Returns the node size in the source code
- node.source_range.size
- end
+ # Returns the class node's name, nil if not a class node
+ def class_name(node)
+ @offensive_node = node
+ @offense_source_range = node.source_range
+ node.const_name
+ end
- def block_size(block)
- # Returns the block length of the block node
- block_length(block)
- end
+ # Returns the method name for a def node
+ def method_name(node)
+ node.children[0] if node.def_type?
+ end
- def source_buffer(node)
- # Source buffer is required as an argument to report style violations
- node.source_range.source_buffer
- end
+ # Returns the node size in the source code
+ def size(node)
+ node.source_range.size
+ end
- def string_content(node)
- # Returns the string representation if node is of type str
- node.str_content if node.type == :str
- end
+ # Returns the block length of the block node
+ def block_size(block)
+ block_length(block)
+ end
- def problem(msg)
- add_offense(@offensive_node, @offense_source_range, msg)
- end
+ # Source buffer is required as an argument to report style violations
+ def source_buffer(node)
+ node.source_range.source_buffer
+ end
- private
+ # Returns the string representation if node is of type str(plain) or dstr(interpolated)
+ def string_content(node)
+ return node.str_content if node.type == :str
+ node.each_child_node(:str).map(&:str_content).join("") if node.type == :dstr
+ end
- def formula_class?(parent_class_node)
- parent_class_node && parent_class_node.const_name == "Formula"
- end
+ # Returns printable component name
+ def format_component(component_node)
+ return component_node.method_name if component_node.send_type? || component_node.block_type?
+ method_name(component_node) if component_node.def_type?
+ 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
+ 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
diff --git a/Library/Homebrew/rubocops/formula_desc_cop.rb b/Library/Homebrew/rubocops/formula_desc_cop.rb
index 7d69a48e7..1fbf1ddbf 100644
--- a/Library/Homebrew/rubocops/formula_desc_cop.rb
+++ b/Library/Homebrew/rubocops/formula_desc_cop.rb
@@ -3,7 +3,7 @@ require_relative "../extend/string"
module RuboCop
module Cop
- module Homebrew
+ module FormulaAuditStrict
# This cop audits `desc` in Formulae
#
# - Checks for existence of `desc`
@@ -11,7 +11,7 @@ module RuboCop
# - 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
+ class Desc < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body)
desc_call = find_node_method_by_name(body, :desc)
diff --git a/Library/Homebrew/rubocops/homepage_cop.rb b/Library/Homebrew/rubocops/homepage_cop.rb
new file mode 100644
index 000000000..a40c7b049
--- /dev/null
+++ b/Library/Homebrew/rubocops/homepage_cop.rb
@@ -0,0 +1,82 @@
+require_relative "./extend/formula_cop"
+
+module RuboCop
+ module Cop
+ module FormulaAudit
+ # This cop audits `homepage` url in Formulae
+ class Homepage < FormulaCop
+ def audit_formula(_node, _class_node, _parent_class_node, formula_class_body_node)
+ homepage_node = find_node_method_by_name(formula_class_body_node, :homepage)
+ homepage = if homepage_node
+ string_content(parameters(homepage_node).first)
+ else
+ ""
+ end
+
+ problem "Formula should have a homepage." if homepage_node.nil? || homepage.empty?
+
+ unless homepage =~ %r{^https?://}
+ problem "The homepage should start with http or https (URL is #{homepage})."
+ end
+
+ case homepage
+ # Check for http:// GitHub homepage urls, https:// is preferred.
+ # Note: only check homepages that are repo pages, not *.github.com hosts
+ when %r{^http://github.com/}
+ problem "Please use https:// for #{homepage}"
+
+ # Savannah has full SSL/TLS support but no auto-redirect.
+ # Doesn't apply to the download URLs, only the homepage.
+ when %r{^http://savannah.nongnu.org/}
+ problem "Please use https:// for #{homepage}"
+
+ # Freedesktop is complicated to handle - It has SSL/TLS, but only on certain subdomains.
+ # To enable https Freedesktop change the URL from http://project.freedesktop.org/wiki to
+ # https://wiki.freedesktop.org/project_name.
+ # "Software" is redirected to https://wiki.freedesktop.org/www/Software/project_name
+ when %r{^http://((?:www|nice|libopenraw|liboil|telepathy|xorg)\.)?freedesktop\.org/(?:wiki/)?}
+ if homepage =~ /Software/
+ problem "#{homepage} should be styled `https://wiki.freedesktop.org/www/Software/project_name`"
+ else
+ problem "#{homepage} should be styled `https://wiki.freedesktop.org/project_name`"
+ end
+
+ # Google Code homepages should end in a slash
+ when %r{^https?://code\.google\.com/p/[^/]+[^/]$}
+ problem "#{homepage} should end with a slash"
+
+ # People will run into mixed content sometimes, but we should enforce and then add
+ # exemptions as they are discovered. Treat mixed content on homepages as a bug.
+ # Justify each exemptions with a code comment so we can keep track here.
+
+ when %r{^http://[^/]*\.github\.io/},
+ %r{^http://[^/]*\.sourceforge\.io/}
+ problem "Please use https:// for #{homepage}"
+
+ when %r{^http://([^/]*)\.(sf|sourceforge)\.net(/|$)}
+ problem "#{homepage} should be `https://#{$1}.sourceforge.io/`"
+
+ # There's an auto-redirect here, but this mistake is incredibly common too.
+ # Only applies to the homepage and subdomains for now, not the FTP URLs.
+ when %r{^http://((?:build|cloud|developer|download|extensions|git|glade|help|library|live|nagios|news|people|projects|rt|static|wiki|www)\.)?gnome\.org}
+ problem "Please use https:// for #{homepage}"
+
+ # Compact the above into this list as we're able to remove detailed notations, etc over time.
+ when %r{^http://[^/]*\.apache\.org},
+ %r{^http://packages\.debian\.org},
+ %r{^http://wiki\.freedesktop\.org/},
+ %r{^http://((?:www)\.)?gnupg\.org/},
+ %r{^http://ietf\.org},
+ %r{^http://[^/.]+\.ietf\.org},
+ %r{^http://[^/.]+\.tools\.ietf\.org},
+ %r{^http://www\.gnu\.org/},
+ %r{^http://code\.google\.com/},
+ %r{^http://bitbucket\.org/},
+ %r{^http://(?:[^/]*\.)?archive\.org}
+ problem "Please use https:// for #{homepage}"
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/sandbox.rb b/Library/Homebrew/sandbox.rb
index 9597dafa8..b16bbde1a 100644
--- a/Library/Homebrew/sandbox.rb
+++ b/Library/Homebrew/sandbox.rb
@@ -5,10 +5,6 @@ class Sandbox
SANDBOX_EXEC = "/usr/bin/sandbox-exec".freeze
SANDBOXED_TAPS = %w[
homebrew/core
- homebrew/dupes
- homebrew/fuse
- homebrew/devel-only
- homebrew/tex
].freeze
def self.available?
diff --git a/Library/Homebrew/shims/scm/git b/Library/Homebrew/shims/scm/git
index 82bb47c25..bfb779c25 100755
--- a/Library/Homebrew/shims/scm/git
+++ b/Library/Homebrew/shims/scm/git
@@ -86,7 +86,6 @@ fi
case "$(lowercase "$SCM_FILE")" in
git)
[[ -n "$HOMEBREW_GIT" ]] && safe_exec "$(which "$HOMEBREW_GIT")" "$@"
- [[ -n "$GIT" ]] && safe_exec "$(which "$GIT")" "$@"
;;
svn)
[[ -n "$HOMEBREW_SVN" ]] && safe_exec "$(which "$HOMEBREW_SVN")" "$@"
diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb
index fb07f6c55..be851ca16 100644
--- a/Library/Homebrew/software_spec.rb
+++ b/Library/Homebrew/software_spec.rb
@@ -8,6 +8,7 @@ require "dependency_collector"
require "utils/bottles"
require "patch"
require "compilers"
+require "os/mac/version"
class SoftwareSpec
extend Forwardable
@@ -117,8 +118,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 +172,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
@@ -340,8 +339,8 @@ class BottleSpecification
tags = collector.keys.sort_by do |tag|
# Sort non-MacOS tags below MacOS tags.
begin
- MacOS::Version.from_symbol tag
- rescue
+ OS::Mac::Version.from_symbol tag
+ rescue ArgumentError
"0.#{tag}"
end
end
diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb
index 99138330b..66aa10158 100644
--- a/Library/Homebrew/tap.rb
+++ b/Library/Homebrew/tap.rb
@@ -201,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?
@@ -522,13 +526,11 @@ end
# A specialized {Tap} class for the core formulae
class CoreTap < Tap
- if OS.mac?
- def default_remote
- "https://github.com/Homebrew/homebrew-core"
- end
- else
- def default_remote
- "https://github.com/Linuxbrew/homebrew-core"
+ def default_remote
+ if OS.mac? || ENV["HOMEBREW_FORCE_HOMEBREW_ORG"]
+ "https://github.com/Homebrew/homebrew-core".freeze
+ else
+ "https://github.com/Linuxbrew/homebrew-core".freeze
end
end
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.lock b/Library/Homebrew/test/Gemfile.lock
index 4d4eefd7d..1f6adae93 100644
--- a/Library/Homebrew/test/Gemfile.lock
+++ b/Library/Homebrew/test/Gemfile.lock
@@ -2,51 +2,53 @@ GEM
remote: https://rubygems.org/
specs:
ast (2.3.0)
- codecov (0.1.9)
+ codecov (0.1.10)
json
simplecov
url
diff-lcs (1.3)
docile (1.1.5)
- json (2.0.3)
- parallel (1.10.0)
- parallel_tests (2.13.0)
+ json (2.1.0)
+ parallel (1.11.2)
+ parallel_tests (2.14.1)
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)
- rspec-mocks (~> 3.5.0)
- rspec-core (3.5.4)
- rspec-support (~> 3.5.0)
- rspec-expectations (3.5.0)
+ rainbow (2.2.2)
+ rake
+ rake (12.0.0)
+ rspec (3.6.0)
+ rspec-core (~> 3.6.0)
+ rspec-expectations (~> 3.6.0)
+ rspec-mocks (~> 3.6.0)
+ rspec-core (3.6.0)
+ rspec-support (~> 3.6.0)
+ rspec-expectations (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.5.0)
+ rspec-support (~> 3.6.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
- rspec-mocks (3.5.0)
+ rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.5.0)
- rspec-support (3.5.0)
+ rspec-support (~> 3.6.0)
+ rspec-support (3.6.0)
rspec-wait (0.0.9)
rspec (>= 3, < 4)
- rubocop (0.47.1)
+ rubocop (0.48.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)
+ simplecov (0.14.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
- unicode-display_width (1.1.3)
+ unicode-display_width (1.2.1)
url (0.3.2)
PLATFORMS
@@ -62,4 +64,4 @@ DEPENDENCIES
simplecov
BUNDLED WITH
- 1.14.5
+ 1.14.6
diff --git a/Library/Homebrew/test/PATH_spec.rb b/Library/Homebrew/test/PATH_spec.rb
new file mode 100644
index 000000000..68233c23c
--- /dev/null
+++ b/Library/Homebrew/test/PATH_spec.rb
@@ -0,0 +1,115 @@
+require "PATH"
+
+describe PATH do
+ describe "#initialize" do
+ it "can take multiple arguments" do
+ expect(described_class.new("/path1", "/path2")).to eq("/path1:/path2")
+ end
+
+ it "can parse a mix of arrays and arguments" do
+ expect(described_class.new(["/path1", "/path2"], "/path3")).to eq("/path1:/path2:/path3")
+ end
+
+ it "splits an existing PATH" do
+ expect(described_class.new("/path1:/path2")).to eq(["/path1", "/path2"])
+ end
+
+ it "removes duplicates" do
+ expect(described_class.new("/path1", "/path1")).to eq("/path1")
+ end
+ end
+
+ describe "#to_ary" do
+ it "returns a PATH array" do
+ expect(described_class.new("/path1", "/path2").to_ary).to eq(["/path1", "/path2"])
+ end
+ end
+
+ describe "#to_str" do
+ it "returns a PATH string" do
+ expect(described_class.new("/path1", "/path2").to_str).to eq("/path1:/path2")
+ end
+ end
+
+ describe "#prepend" do
+ it "prepends a path to a PATH" do
+ expect(described_class.new("/path1").prepend("/path2").to_str).to eq("/path2:/path1")
+ end
+
+ it "removes duplicates" do
+ expect(described_class.new("/path1").prepend("/path1").to_str).to eq("/path1")
+ end
+ end
+
+ describe "#append" do
+ it "prepends a path to a PATH" do
+ expect(described_class.new("/path1").append("/path2").to_str).to eq("/path1:/path2")
+ end
+
+ it "removes duplicates" do
+ expect(described_class.new("/path1").append("/path1").to_str).to eq("/path1")
+ end
+ end
+
+ describe "#insert" do
+ it "inserts a path at a given index" do
+ expect(described_class.new("/path1").insert(0, "/path2").to_str).to eq("/path2:/path1")
+ end
+
+ it "can insert multiple paths" do
+ expect(described_class.new("/path1").insert(0, "/path2", "/path3")).to eq("/path2:/path3:/path1")
+ end
+ end
+
+ describe "#include?" do
+ it "returns true if a path is included" do
+ path = described_class.new("/path1", "/path2")
+ expect(path).to include("/path1")
+ expect(path).to include("/path2")
+ end
+
+ it "returns false if a path is not included" do
+ expect(described_class.new("/path1")).not_to include("/path2")
+ end
+
+ it "returns false if the given string contains a separator" do
+ expect(described_class.new("/path1", "/path2")).not_to include("/path1:")
+ end
+ end
+
+ describe "#each" do
+ it "loops through each path" do
+ enum = described_class.new("/path1", "/path2").each
+
+ expect(enum.next).to eq("/path1")
+ expect(enum.next).to eq("/path2")
+ end
+ end
+
+ describe "#select" do
+ it "returns an object of the same class instead of an Array" do
+ expect(described_class.new.select { true }).to be_a(described_class)
+ end
+ end
+
+ describe "#reject" do
+ it "returns an object of the same class instead of an Array" do
+ expect(described_class.new.reject { true }).to be_a(described_class)
+ end
+ end
+
+ describe "#existing" do
+ it "returns a new PATH without non-existent paths" do
+ allow(File).to receive(:directory?).with("/path1").and_return(true)
+ allow(File).to receive(:directory?).with("/path2").and_return(false)
+
+ path = described_class.new("/path1", "/path2")
+ expect(path.existing.to_ary).to eq(["/path1"])
+ expect(path.to_ary).to eq(["/path1", "/path2"])
+ end
+
+ it "returns nil instead of an empty #{described_class}" do
+ expect(described_class.new.existing).to be nil
+ 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/install_spec.rb b/Library/Homebrew/test/cask/cli/install_spec.rb
index 5a40017e8..219b9522e 100644
--- a/Library/Homebrew/test/cask/cli/install_spec.rb
+++ b/Library/Homebrew/test/cask/cli/install_spec.rb
@@ -1,4 +1,18 @@
describe Hbc::CLI::Install, :cask do
+ it "displays the installation progress" do
+ output = Regexp.new <<-EOS.undent
+ ==> Downloading file:.*caffeine.zip
+ ==> Verifying checksum for Cask local-caffeine
+ ==> Installing Cask local-caffeine
+ ==> Moving App 'Caffeine.app' to '.*Caffeine.app'.
+ .*local-caffeine was successfully installed!
+ EOS
+
+ expect {
+ Hbc::CLI::Install.run("local-caffeine")
+ }.to output(output).to_stdout
+ end
+
it "allows staging and activation of multiple Casks at once" do
shutup do
Hbc::CLI::Install.run("local-transmission", "local-caffeine")
diff --git a/Library/Homebrew/test/cask/cli/reinstall_spec.rb b/Library/Homebrew/test/cask/cli/reinstall_spec.rb
index e573a3470..8885fa199 100644
--- a/Library/Homebrew/test/cask/cli/reinstall_spec.rb
+++ b/Library/Homebrew/test/cask/cli/reinstall_spec.rb
@@ -1,4 +1,27 @@
describe Hbc::CLI::Reinstall, :cask do
+ it "displays the reinstallation progress" do
+ caffeine = Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/local-caffeine.rb")
+
+ shutup do
+ Hbc::Installer.new(caffeine).install
+ end
+
+ output = Regexp.new <<-EOS.undent
+ ==> Downloading file:.*caffeine.zip
+ Already downloaded: .*local-caffeine--1.2.3.zip
+ ==> Verifying checksum for Cask local-caffeine
+ ==> Uninstalling Cask local-caffeine
+ ==> Removing App '.*Caffeine.app'.
+ ==> Installing Cask local-caffeine
+ ==> Moving App 'Caffeine.app' to '.*Caffeine.app'.
+ .*local-caffeine was successfully installed!
+ EOS
+
+ expect {
+ Hbc::CLI::Reinstall.run("local-caffeine")
+ }.to output(output).to_stdout
+ end
+
it "allows reinstalling a Cask" do
shutup do
Hbc::CLI::Install.run("local-transmission")
diff --git a/Library/Homebrew/test/cask/cli/search_spec.rb b/Library/Homebrew/test/cask/cli/search_spec.rb
index 9843a6de6..00fcf7382 100644
--- a/Library/Homebrew/test/cask/cli/search_spec.rb
+++ b/Library/Homebrew/test/cask/cli/search_spec.rb
@@ -3,7 +3,7 @@ describe Hbc::CLI::Search, :cask do
expect {
Hbc::CLI::Search.run("local")
}.to output(<<-EOS.undent).to_stdout
- ==> Partial matches
+ ==> Partial Matches
local-caffeine
local-transmission
EOS
@@ -42,13 +42,13 @@ describe Hbc::CLI::Search, :cask do
it "accepts a regexp argument" do
expect {
Hbc::CLI::Search.run("/^local-c[a-z]ffeine$/")
- }.to output("==> Regexp matches\nlocal-caffeine\n").to_stdout
+ }.to output("==> Regexp Matches\nlocal-caffeine\n").to_stdout
end
it "Returns both exact and partial matches" do
expect {
Hbc::CLI::Search.run("test-opera")
- }.to output(/^==> Exact match\ntest-opera\n==> Partial matches\ntest-opera-mail/).to_stdout
+ }.to output(/^==> Exact Match\ntest-opera\n==> Partial Matches\ntest-opera-mail/).to_stdout
end
it "does not search the Tap name" do
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/cli/uninstall_spec.rb b/Library/Homebrew/test/cask/cli/uninstall_spec.rb
index fb196ee72..4089c47b4 100644
--- a/Library/Homebrew/test/cask/cli/uninstall_spec.rb
+++ b/Library/Homebrew/test/cask/cli/uninstall_spec.rb
@@ -1,4 +1,21 @@
describe Hbc::CLI::Uninstall, :cask do
+ it "displays the uninstallation progress" do
+ caffeine = Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/local-caffeine.rb")
+
+ shutup do
+ Hbc::Installer.new(caffeine).install
+ end
+
+ output = Regexp.new <<-EOS.undent
+ ==> Uninstalling Cask local-caffeine
+ ==> Removing App '.*Caffeine.app'.
+ EOS
+
+ expect {
+ Hbc::CLI::Uninstall.run("local-caffeine")
+ }.to output(output).to_stdout
+ end
+
it "shows an error when a bad Cask is provided" do
expect {
Hbc::CLI::Uninstall.run("notacask")
@@ -13,7 +30,9 @@ describe Hbc::CLI::Uninstall, :cask do
it "tries anyway on a non-present Cask when --force is given" do
expect {
- Hbc::CLI::Uninstall.run("local-caffeine", "--force")
+ shutup do
+ Hbc::CLI::Uninstall.run("local-caffeine", "--force")
+ end
}.not_to raise_error
end
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/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/install_spec.rb b/Library/Homebrew/test/cmd/install_spec.rb
index c1240a30e..b819c17be 100644
--- a/Library/Homebrew/test/cmd/install_spec.rb
+++ b/Library/Homebrew/test/cmd/install_spec.rb
@@ -77,7 +77,7 @@ describe "brew install", :integration_test do
EOS
expect { brew "install", "testball1" }
- .to output(/first `brew unlink testball1`/).to_stderr
+ .to output(/`brew upgrade testball1`/).to_stderr
.and not_to_output.to_stdout
.and be_a_failure
@@ -217,10 +217,9 @@ describe "brew install", :integration_test do
depends_on NonFatalRequirement
EOS
- # FIXME: This should output to STDERR.
expect { brew "install", "testball1" }
- .to output(/NonFatalRequirement unsatisfied!/).to_stdout
- .and not_to_output.to_stderr
+ .to output(/NonFatalRequirement unsatisfied!/).to_stderr
+ .and output(/built in/).to_stdout
.and be_a_success
end
@@ -234,10 +233,9 @@ describe "brew install", :integration_test do
depends_on FatalRequirement
EOS
- # FIXME: This should output to STDERR.
expect { brew "install", "testball1" }
- .to output(/FatalRequirement unsatisfied!/).to_stdout
- .and output(/An unsatisfied requirement failed this build./).to_stderr
+ .to output(/FatalRequirement unsatisfied!/).to_stderr
+ .and not_to_output.to_stdout
.and be_a_failure
end
end
diff --git a/Library/Homebrew/test/cmd/search_remote_tap_spec.rb b/Library/Homebrew/test/cmd/search_remote_tap_spec.rb
index 99c2cc20b..b0beb122c 100644
--- a/Library/Homebrew/test/cmd/search_remote_tap_spec.rb
+++ b/Library/Homebrew/test/cmd/search_remote_tap_spec.rb
@@ -1,19 +1,21 @@
require "cmd/search"
describe Homebrew do
- specify "#search_tap" do
+ specify "#search_taps" do
json_response = {
- "tree" => [
+ "items" => [
{
- "path" => "Formula/not-a-formula.rb",
- "type" => "blob",
+ "path" => "Formula/some-formula.rb",
+ "repository" => {
+ "full_name" => "Homebrew/homebrew-foo",
+ },
},
],
}
allow(GitHub).to receive(:open).and_yield(json_response)
- expect(described_class.search_tap("homebrew", "not-a-tap", "not-a-formula"))
- .to eq(["homebrew/not-a-tap/not-a-formula"])
+ expect(described_class.search_taps("some-formula"))
+ .to match(["homebrew/foo/some-formula"])
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 a6bb22837..b07ffaadc 100644
--- a/Library/Homebrew/test/dev-cmd/audit_spec.rb
+++ b/Library/Homebrew/test/dev-cmd/audit_spec.rb
@@ -5,6 +5,13 @@ RSpec::Matchers.alias_matcher :have_data, :be_data
RSpec::Matchers.alias_matcher :have_end, :be_end
RSpec::Matchers.alias_matcher :have_trailing_newline, :be_trailing_newline
+module Count
+ def self.increment
+ @count ||= 0
+ @count += 1
+ end
+end
+
describe FormulaText do
let(:dir) { mktmpdir }
@@ -141,100 +148,6 @@ describe FormulaAuditor do
fa.audit_file
expect(fa.problems).to eq([])
end
-
- specify "strict: ordering issue" do
- fa = formula_auditor "foo", <<-EOS.undent, strict: true
- class Foo < Formula
- url "http://example.com/foo-1.0.tgz"
- homepage "http://example.com"
- end
- EOS
-
- fa.audit_file
- expect(fa.problems)
- .to eq(["`homepage` (line 3) should be put before `url` (line 2)"])
- end
-
- specify "strict: resource placement" do
- fa = formula_auditor "foo", <<-EOS.undent, strict: true
- class Foo < Formula
- url "https://example.com/foo-1.0.tgz"
-
- resource "foo2" do
- url "https://example.com/foo-2.0.tgz"
- end
-
- depends_on "openssl"
- end
- EOS
-
- fa.audit_file
- expect(fa.problems)
- .to eq(["`depends_on` (line 8) should be put before `resource` (line 4)"])
- end
-
- specify "strict: plist placement" do
- fa = formula_auditor "foo", <<-EOS.undent, strict: true
- class Foo < Formula
- url "https://example.com/foo-1.0.tgz"
-
- test do
- expect(shell_output("./dogs")).to match("Dogs are terrific")
- end
-
- def plist
- end
- end
- EOS
-
- fa.audit_file
- expect(fa.problems)
- .to eq(["`plist block` (line 8) should be put before `test block` (line 4)"])
- end
-
- specify "strict: url outside of stable block" do
- fa = formula_auditor "foo", <<-EOS.undent, strict: true
- class Foo < Formula
- url "http://example.com/foo-1.0.tgz"
- stable do
- # stuff
- end
- end
- EOS
-
- fa.audit_file
- expect(fa.problems).to eq(["`url` should be put inside `stable block`"])
- end
-
- specify "strict: head and head do" do
- fa = formula_auditor "foo", <<-EOS.undent, strict: true
- class Foo < Formula
- head "http://example.com/foo.git"
- head do
- # stuff
- end
- end
- EOS
-
- fa.audit_file
- expect(fa.problems).to eq(["Should not have both `head` and `head do`"])
- end
-
- specify "strict: bottle and bottle do" do
- fa = formula_auditor "foo", <<-EOS.undent, strict: true
- class Foo < Formula
- url "http://example.com/foo-1.0.tgz"
- bottle do
- # bottles go here
- end
- bottle :unneeded
- end
- EOS
-
- fa.audit_file
- expect(fa.problems)
- .to eq(["Should not have `bottle :unneeded/:disable` and `bottle do`"])
- end
end
describe "#audit_class" do
@@ -303,7 +216,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 +224,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,11 +257,11 @@ describe FormulaAuditor do
end
EOS
- 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
@@ -360,7 +273,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
@@ -368,10 +281,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
@@ -409,77 +322,66 @@ describe FormulaAuditor do
.to eq(["Don't recommend setuid in the caveats, suggest sudo instead."])
end
- describe "#audit_homepage" do
- specify "homepage URLs" do
- fa = formula_auditor "foo", <<-EOS.undent, online: true
+ describe "#audit_keg_only_style" do
+ specify "keg_only_needs_downcasing" do
+ fa = formula_auditor "foo", <<-EOS.undent, strict: true
class Foo < Formula
- homepage "ftp://example.com/foo"
url "http://example.com/foo-1.0.tgz"
+
+ keg_only "Because why not"
end
EOS
- fa.audit_homepage
+ fa.audit_keg_only_style
expect(fa.problems)
- .to eq(["The homepage should start with http or https (URL is #{fa.formula.homepage})."])
-
- formula_homepages = {
- "bar" => "http://www.freedesktop.org/wiki/bar",
- "baz" => "http://www.freedesktop.org/wiki/Software/baz",
- "qux" => "https://code.google.com/p/qux",
- "quux" => "http://github.com/quux",
- "corge" => "http://savannah.nongnu.org/corge",
- "grault" => "http://grault.github.io/",
- "garply" => "http://www.gnome.org/garply",
- "sf1" => "http://foo.sourceforge.net/",
- "sf2" => "http://foo.sourceforge.net",
- "sf3" => "http://foo.sf.net/",
- "sf4" => "http://foo.sourceforge.io/",
- "waldo" => "http://www.gnu.org/waldo",
- }
-
- formula_homepages.each do |name, homepage|
- fa = formula_auditor name, <<-EOS.undent
- class #{Formulary.class_s(name)} < Formula
- homepage "#{homepage}"
- url "http://example.com/#{name}-1.0.tgz"
- end
- EOS
+ .to eq(["'Because' from the keg_only reason should be 'because'.\n"])
+ end
- fa.audit_homepage
- if homepage =~ %r{http:\/\/www\.freedesktop\.org}
- if homepage =~ /Software/
- expect(fa.problems.first).to match(
- "#{homepage} should be styled " \
- "`https://wiki.freedesktop.org/www/Software/project_name`",
- )
- else
- expect(fa.problems.first).to match(
- "#{homepage} should be styled " \
- "`https://wiki.freedesktop.org/project_name`",
- )
- end
- elsif homepage =~ %r{https:\/\/code\.google\.com}
- expect(fa.problems.first)
- .to match("#{homepage} should end with a slash")
- elsif homepage =~ /foo\.(sf|sourceforge)\.net/
- expect(fa.problems.first)
- .to match("#{homepage} should be `https://foo.sourceforge.io/`")
- else
- expect(fa.problems.first)
- .to match("Please use https:// for #{homepage}")
+ specify "keg_only_redundant_period" do
+ fa = formula_auditor "foo", <<-EOS.undent, strict: true
+ class Foo < Formula
+ url "http://example.com/foo-1.0.tgz"
+
+ keg_only "because this line ends in a period."
end
- end
+ EOS
+
+ fa.audit_keg_only_style
+ expect(fa.problems)
+ .to eq(["keg_only reason should not end with a period."])
+ end
+
+ specify "keg_only_handles_block_correctly" do
+ fa = formula_auditor "foo", <<-EOS.undent, strict: true
+ class Foo < Formula
+ url "http://example.com/foo-1.0.tgz"
+
+ keg_only <<-EOF.undent
+ this line starts with a lowercase word.
+
+ This line does not but that shouldn't be a
+ problem
+ EOF
+ end
+ EOS
+
+ fa.audit_keg_only_style
+ expect(fa.problems)
+ .to eq([])
end
- specify "missing homepage" do
- fa = formula_auditor "foo", <<-EOS.undent, online: true
+ specify "keg_only_handles_whitelist_correctly" do
+ fa = formula_auditor "foo", <<-EOS.undent, strict: true
class Foo < Formula
url "http://example.com/foo-1.0.tgz"
+
+ keg_only "Apple ships foo in the CLT package"
end
EOS
- fa.audit_homepage
- expect(fa.problems.first).to match("Formula should have a homepage.")
+ fa.audit_keg_only_style
+ expect(fa.problems)
+ .to eq([])
end
end
@@ -517,5 +419,203 @@ describe FormulaAuditor do
expect(fa.problems.first)
.to match('xcodebuild should be passed an explicit "SYMROOT"')
end
+
+ specify "disallow go get usage" do
+ fa = formula_auditor "foo", <<-EOS.undent
+ class Foo <Formula
+ url "http://example.com/foo-1.0.tgz"
+
+ def install
+ system "go", "get", "bar"
+ end
+ end
+ EOS
+ fa.audit_text
+ expect(fa.problems.first)
+ .to match("Formulae should not use `go get`. If non-vendored resources are required use `go_resource`s.")
+ end
+ end
+
+ describe "#audit_revision_and_version_scheme" do
+ let(:origin_tap_path) { Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" }
+ let(:formula_subpath) { "Formula/foo#{@foo_version}.rb" }
+ let(:origin_formula_path) { origin_tap_path/formula_subpath }
+ let(:tap_path) { Tap::TAP_DIRECTORY/"homebrew/homebrew-bar" }
+ let(:formula_path) { tap_path/formula_subpath }
+
+ before(:each) do
+ @foo_version = Count.increment
+
+ origin_formula_path.write <<-EOS.undent
+ class Foo#{@foo_version} < Formula
+ url "https://example.com/foo-1.0.tar.gz"
+ revision 2
+ version_scheme 1
+ end
+ EOS
+
+ origin_tap_path.mkpath
+ origin_tap_path.cd do
+ shutup do
+ system "git", "init"
+ system "git", "add", "--all"
+ system "git", "commit", "-m", "init"
+ end
+ end
+
+ tap_path.mkpath
+ tap_path.cd do
+ shutup do
+ system "git", "clone", origin_tap_path, "."
+ end
+ end
+ end
+
+ subject do
+ fa = described_class.new(Formulary.factory(formula_path))
+ fa.audit_revision_and_version_scheme
+ fa.problems.first
+ end
+
+ def formula_gsub(before, after = "")
+ text = formula_path.read
+ text.gsub! before, after
+ formula_path.unlink
+ formula_path.write text
+ end
+
+ def formula_gsub_commit(before, after = "")
+ text = origin_formula_path.read
+ text.gsub!(before, after)
+ origin_formula_path.unlink
+ origin_formula_path.write text
+
+ origin_tap_path.cd do
+ shutup do
+ system "git", "commit", "-am", "commit"
+ end
+ end
+
+ tap_path.cd do
+ shutup do
+ system "git", "fetch"
+ system "git", "reset", "--hard", "origin/master"
+ end
+ end
+ end
+
+ context "revisions" do
+ context "should not be removed when first committed above 0" do
+ it { is_expected.to be_nil }
+ end
+
+ context "should not decrease with the same version" do
+ before { formula_gsub_commit "revision 2", "revision 1" }
+
+ it { is_expected.to match("revision should not decrease (from 2 to 1)") }
+ end
+
+ context "should not be removed with the same version" do
+ before { formula_gsub_commit "revision 2" }
+
+ it { is_expected.to match("revision should not decrease (from 2 to 0)") }
+ end
+
+ context "should not decrease with the same, uncommitted version" do
+ before { formula_gsub "revision 2", "revision 1" }
+
+ it { is_expected.to match("revision should not decrease (from 2 to 1)") }
+ end
+
+ context "should be removed with a newer version" do
+ before { formula_gsub_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz" }
+
+ it { is_expected.to match("'revision 2' should be removed") }
+ end
+
+ context "should not warn on an newer version revision removal" do
+ before do
+ formula_gsub_commit "revision 2", ""
+ formula_gsub_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz"
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context "should only increment by 1 with an uncommitted version" do
+ before do
+ formula_gsub "foo-1.0.tar.gz", "foo-1.1.tar.gz"
+ formula_gsub "revision 2", "revision 4"
+ end
+
+ it { is_expected.to match("revisions should only increment by 1") }
+ end
+
+ context "should not warn on past increment by more than 1" do
+ before do
+ formula_gsub_commit "revision 2", "# no revision"
+ formula_gsub_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz"
+ formula_gsub_commit "# no revision", "revision 3"
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ context "version_schemes" do
+ context "should not decrease with the same version" do
+ before { formula_gsub_commit "version_scheme 1" }
+
+ it { is_expected.to match("version_scheme should not decrease (from 1 to 0)") }
+ end
+
+ context "should not decrease with a new version" do
+ before do
+ formula_gsub_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz"
+ formula_gsub_commit "version_scheme 1", ""
+ formula_gsub_commit "revision 2", ""
+ end
+
+ it { is_expected.to match("version_scheme should not decrease (from 1 to 0)") }
+ end
+
+ context "should only increment by 1" do
+ before do
+ formula_gsub_commit "version_scheme 1", "# no version_scheme"
+ formula_gsub_commit "foo-1.0.tar.gz", "foo-1.1.tar.gz"
+ formula_gsub_commit "revision 2", ""
+ formula_gsub_commit "# no version_scheme", "version_scheme 3"
+ end
+
+ it { is_expected.to match("version_schemes should only increment by 1") }
+ end
+ end
+
+ context "versions" do
+ context "uncommitted should not decrease" do
+ before { formula_gsub "foo-1.0.tar.gz", "foo-0.9.tar.gz" }
+
+ it { is_expected.to match("stable version should not decrease (from 1.0 to 0.9)") }
+ end
+
+ context "committed can decrease" do
+ before do
+ formula_gsub_commit "revision 2"
+ formula_gsub_commit "foo-1.0.tar.gz", "foo-0.9.tar.gz"
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context "can decrease with version_scheme increased" do
+ before do
+ formula_gsub "revision 2"
+ formula_gsub "foo-1.0.tar.gz", "foo-0.9.tar.gz"
+ formula_gsub "version_scheme 1", "version_scheme 2"
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
end
end
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..c4373671e 100644
--- a/Library/Homebrew/test/diagnostic_spec.rb
+++ b/Library/Homebrew/test/diagnostic_spec.rb
@@ -7,7 +7,7 @@ describe Homebrew::Diagnostic::Checks do
end
specify "#check_path_for_trailing_slashes" do
- ENV["PATH"] += File::PATH_SEPARATOR + "/foo/bar/"
+ ENV["HOMEBREW_PATH"] += File::PATH_SEPARATOR + "/foo/bar/"
expect(subject.check_path_for_trailing_slashes)
.to match("Some directories in your path end in a slash")
end
@@ -41,6 +41,20 @@ describe Homebrew::Diagnostic::Checks do
end
end
+ specify "#check_access_lock_dir" do
+ begin
+ prev_mode = HOMEBREW_LOCK_DIR.stat.mode
+ mode = HOMEBREW_LOCK_DIR.stat.mode & 0777
+ HOMEBREW_LOCK_DIR.chmod 0555
+ expect(HOMEBREW_LOCK_DIR.stat.mode).not_to eq(prev_mode)
+
+ 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
@@ -110,8 +124,9 @@ describe Homebrew::Diagnostic::Checks do
specify "#check_user_path_3" do
begin
sbin = HOMEBREW_PREFIX/"sbin"
- ENV["PATH"] = "#{HOMEBREW_PREFIX}/bin#{File::PATH_SEPARATOR}" +
- ENV["PATH"].gsub(/(?:^|#{Regexp.escape(File::PATH_SEPARATOR)})#{Regexp.escape(sbin)}/, "")
+ ENV["HOMEBREW_PATH"] =
+ "#{HOMEBREW_PREFIX}/bin#{File::PATH_SEPARATOR}" +
+ ENV["HOMEBREW_PATH"].gsub(/(?:^|#{Regexp.escape(File::PATH_SEPARATOR)})#{Regexp.escape(sbin)}/, "")
(sbin/"something").mkpath
expect(subject.check_user_path_1).to be nil
@@ -137,7 +152,9 @@ describe Homebrew::Diagnostic::Checks do
file = "#{path}/foo-config"
FileUtils.touch file
FileUtils.chmod 0755, file
- ENV["PATH"] = "#{path}#{File::PATH_SEPARATOR}#{ENV["PATH"]}"
+ ENV["HOMEBREW_PATH"] =
+ ENV["PATH"] =
+ "#{path}#{File::PATH_SEPARATOR}#{ENV["PATH"]}"
expect(subject.check_for_config_scripts)
.to match('"config" scripts exist')
diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb
index 2309c36fb..1f98ca525 100644
--- a/Library/Homebrew/test/formula_spec.rb
+++ b/Library/Homebrew/test/formula_spec.rb
@@ -10,7 +10,6 @@ RSpec::Matchers.alias_matcher :supersede_an_installed_formula, :be_supersedes_an
RSpec::Matchers.alias_matcher :have_changed_alias, :be_alias_changed
RSpec::Matchers.alias_matcher :have_option_defined, :be_option_defined
-RSpec::Matchers.alias_matcher :have_post_install_defined, :be_post_install_defined
RSpec::Matchers.alias_matcher :have_test_defined, :be_test_defined
RSpec::Matchers.alias_matcher :pour_bottle, :be_pour_bottle
@@ -624,23 +623,6 @@ describe Formula do
expect(f.desc).to eq("a formula")
end
- specify "#post_install_defined?" do
- f1 = formula do
- url "foo-1.0"
-
- def post_install
- # do nothing
- end
- end
-
- f2 = formula do
- url "foo-1.0"
- end
-
- expect(f1).to have_post_install_defined
- expect(f2).not_to have_post_install_defined
- end
-
specify "#test_defined?" do
f1 = formula do
url "foo-1.0"
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
index 215cf17f7..69bb3e70d 100644
--- a/Library/Homebrew/test/missing_formula_spec.rb
+++ b/Library/Homebrew/test/missing_formula_spec.rb
@@ -139,7 +139,7 @@ describe Homebrew::MissingFormula do
end
context "::deleted_reason" do
- subject { described_class.deleted_reason(formula) }
+ subject { described_class.deleted_reason(formula, silent: true) }
before do
Tap.clear_cache
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
index 5be2d6cf5..a775b0b17 100644
--- a/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb
+++ b/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb
@@ -3,7 +3,7 @@ require "rubocop/rspec/support"
require_relative "../../extend/string"
require_relative "../../rubocops/bottle_block_cop"
-describe RuboCop::Cop::Homebrew::CorrectBottleBlock do
+describe RuboCop::Cop::FormulaAuditStrict::BottleBlock do
subject(:cop) { described_class.new }
context "When auditing Bottle Block" do
diff --git a/Library/Homebrew/test/rubocops/components_order_cop_spec.rb b/Library/Homebrew/test/rubocops/components_order_cop_spec.rb
new file mode 100644
index 000000000..25467c635
--- /dev/null
+++ b/Library/Homebrew/test/rubocops/components_order_cop_spec.rb
@@ -0,0 +1,163 @@
+require "rubocop"
+require "rubocop/rspec/support"
+require_relative "../../extend/string"
+require_relative "../../rubocops/components_order_cop"
+
+describe RuboCop::Cop::FormulaAuditStrict::ComponentsOrder do
+ subject(:cop) { described_class.new }
+
+ context "When auditing formula components order" do
+ it "When url precedes homepage" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "http://example.com/foo-1.0.tgz"
+ homepage "http://example.com"
+ end
+ EOS
+
+ expected_offenses = [{ message: "`homepage` (line 3) should be put before `url` (line 2)",
+ 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 `resource` precedes `depends_on`" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "https://example.com/foo-1.0.tgz"
+
+ resource "foo2" do
+ url "https://example.com/foo-2.0.tgz"
+ end
+
+ depends_on "openssl"
+ end
+ EOS
+
+ expected_offenses = [{ message: "`depends_on` (line 8) should be put before `resource` (line 4)",
+ severity: :convention,
+ line: 8,
+ 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 `test` precedes `plist`" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "https://example.com/foo-1.0.tgz"
+
+ test do
+ expect(shell_output("./dogs")).to match("Dogs are terrific")
+ end
+
+ def plist
+ end
+ end
+ EOS
+
+ expected_offenses = [{ message: "`plist` (line 8) should be put before `test` (line 4)",
+ severity: :convention,
+ line: 8,
+ 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 only one of many `depends_on` precedes `conflicts_with`" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ depends_on "autoconf" => :build
+ conflicts_with "visionmedia-watch"
+ depends_on "automake" => :build
+ depends_on "libtool" => :build
+ depends_on "pkg-config" => :build
+ depends_on "gettext"
+ end
+ EOS
+
+ expected_offenses = [{ message: "`depends_on` (line 4) should be put before `conflicts_with` (line 3)",
+ severity: :convention,
+ line: 4,
+ column: 2,
+ 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 formula components order with autocorrect" do
+ it "When url precedes homepage" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "http://example.com/foo-1.0.tgz"
+ homepage "http://example.com"
+ end
+ EOS
+ correct_source = <<-EOS.undent
+ class Foo < Formula
+ homepage "http://example.com"
+ url "http://example.com/foo-1.0.tgz"
+ end
+ EOS
+
+ corrected_source = autocorrect_source(cop, source)
+ expect(corrected_source).to eq(correct_source)
+ end
+
+ it "When `resource` precedes `depends_on`" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "https://example.com/foo-1.0.tgz"
+
+ resource "foo2" do
+ url "https://example.com/foo-2.0.tgz"
+ end
+
+ depends_on "openssl"
+ end
+ EOS
+ correct_source = <<-EOS.undent
+ class Foo < Formula
+ url "https://example.com/foo-1.0.tgz"
+
+ depends_on "openssl"
+
+ resource "foo2" do
+ url "https://example.com/foo-2.0.tgz"
+ end
+ end
+ EOS
+ corrected_source = autocorrect_source(cop, source)
+ expect(corrected_source).to eq(correct_source)
+ end
+ end
+end
diff --git a/Library/Homebrew/test/rubocops/components_redundancy_cop_spec.rb b/Library/Homebrew/test/rubocops/components_redundancy_cop_spec.rb
new file mode 100644
index 000000000..fd635a126
--- /dev/null
+++ b/Library/Homebrew/test/rubocops/components_redundancy_cop_spec.rb
@@ -0,0 +1,87 @@
+require "rubocop"
+require "rubocop/rspec/support"
+require_relative "../../extend/string"
+require_relative "../../rubocops/components_redundancy_cop"
+
+describe RuboCop::Cop::FormulaAuditStrict::ComponentsRedundancy do
+ subject(:cop) { described_class.new }
+
+ context "When auditing formula components common errors" do
+ it "When url outside stable block" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "http://example.com/foo-1.0.tgz"
+ stable do
+ # stuff
+ end
+ end
+ EOS
+
+ expected_offenses = [{ message: "`url` should be put inside `stable` block",
+ severity: :convention,
+ line: 2,
+ 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 both `head` and `head do` are present" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ head "http://example.com/foo.git"
+ head do
+ # stuff
+ end
+ end
+ EOS
+
+ expected_offenses = [{ message: "`head` and `head do` should not be simultaneously present",
+ 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 both `bottle :modifier` and `bottle do` are present" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "http://example.com/foo-1.0.tgz"
+ bottle do
+ # bottles go here
+ end
+ bottle :unneeded
+ end
+ EOS
+
+ expected_offenses = [{ message: "`bottle :modifier` and `bottle do` should not be simultaneously present",
+ 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
+
+ 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/rubocops/formula_desc_cop_spec.rb b/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb
index 04c4c27da..432b15e3c 100644
--- a/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb
+++ b/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb
@@ -3,7 +3,7 @@ require "rubocop/rspec/support"
require_relative "../../extend/string"
require_relative "../../rubocops/formula_desc_cop"
-describe RuboCop::Cop::Homebrew::FormulaDesc do
+describe RuboCop::Cop::FormulaAuditStrict::Desc do
subject(:cop) { described_class.new }
context "When auditing formula desc" do
@@ -51,6 +51,31 @@ describe RuboCop::Cop::Homebrew::FormulaDesc do
end
end
+ it "When desc is multiline string" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ desc '#{"bar"*10}'\
+ '#{"foo"*21}'
+ end
+ EOS
+
+ msg = <<-EOS.undent
+ Description is too long. "name: desc" should be less than 80 characters.
+ Length is calculated as Foo + desc. (currently 98)
+ 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
diff --git a/Library/Homebrew/test/rubocops/homepage_cop_spec.rb b/Library/Homebrew/test/rubocops/homepage_cop_spec.rb
new file mode 100644
index 000000000..c03efd825
--- /dev/null
+++ b/Library/Homebrew/test/rubocops/homepage_cop_spec.rb
@@ -0,0 +1,124 @@
+require "rubocop"
+require "rubocop/rspec/support"
+require_relative "../../extend/string"
+require_relative "../../rubocops/homepage_cop"
+
+describe RuboCop::Cop::FormulaAudit::Homepage do
+ subject(:cop) { described_class.new }
+
+ context "When auditing homepage" do
+ it "When there is no homepage" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url 'http://example.com/foo-1.0.tgz'
+ end
+ EOS
+
+ expected_offenses = [{ message: "Formula should have a homepage.",
+ 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 "Homepage with ftp" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ homepage "ftp://example.com/foo"
+ url "http://example.com/foo-1.0.tgz"
+ end
+ EOS
+
+ expected_offenses = [{ message: "The homepage should start with http or https (URL is ftp://example.com/foo).",
+ severity: :convention,
+ line: 2,
+ column: 2,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ it "Homepage URLs" do
+ formula_homepages = {
+ "bar" => "http://www.freedesktop.org/wiki/bar",
+ "baz" => "http://www.freedesktop.org/wiki/Software/baz",
+ "qux" => "https://code.google.com/p/qux",
+ "quux" => "http://github.com/quux",
+ "corge" => "http://savannah.nongnu.org/corge",
+ "grault" => "http://grault.github.io/",
+ "garply" => "http://www.gnome.org/garply",
+ "sf1" => "http://foo.sourceforge.net/",
+ "sf2" => "http://foo.sourceforge.net",
+ "sf3" => "http://foo.sf.net/",
+ "sf4" => "http://foo.sourceforge.io/",
+ "waldo" => "http://www.gnu.org/waldo",
+ }
+
+ formula_homepages.each do |name, homepage|
+ source = <<-EOS.undent
+ class #{name.capitalize} < Formula
+ homepage "#{homepage}"
+ url "http://example.com/#{name}-1.0.tgz"
+ end
+ EOS
+
+ inspect_source(cop, source)
+ if homepage =~ %r{http:\/\/www\.freedesktop\.org}
+ if homepage =~ /Software/
+ expected_offenses = [{ message: "#{homepage} should be styled " \
+ "`https://wiki.freedesktop.org/www/Software/project_name`",
+ severity: :convention,
+ line: 2,
+ column: 2,
+ source: source }]
+ else
+ expected_offenses = [{ message: "#{homepage} should be styled " \
+ "`https://wiki.freedesktop.org/project_name`",
+ severity: :convention,
+ line: 2,
+ column: 2,
+ source: source }]
+ end
+ elsif homepage =~ %r{https:\/\/code\.google\.com}
+ expected_offenses = [{ message: "#{homepage} should end with a slash",
+ severity: :convention,
+ line: 2,
+ column: 2,
+ source: source }]
+ elsif homepage =~ /foo\.(sf|sourceforge)\.net/
+ expected_offenses = [{ message: "#{homepage} should be `https://foo.sourceforge.io/`",
+ severity: :convention,
+ line: 2,
+ column: 2,
+ source: source }]
+ else
+ expected_offenses = [{ message: "Please use https:// for #{homepage}",
+ severity: :convention,
+ line: 2,
+ column: 2,
+ source: source }]
+ end
+ expected_offenses.zip([cop.offenses.last]).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ 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..e193b91a0 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)
@@ -89,6 +93,7 @@ RSpec.configure do |config|
HOMEBREW_PREFIX/"opt",
HOMEBREW_PREFIX/"Caskroom",
HOMEBREW_LIBRARY/"Taps/caskroom",
+ HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-bar",
HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-bundle",
HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-foo",
HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-services",
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/support/helper/spec/shared_context/integration_test.rb b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb
index b037068d2..ae1854f58 100644
--- a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb
+++ b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb
@@ -72,6 +72,7 @@ RSpec.shared_context "integration test" do
env.merge!(
"PATH" => path,
+ "HOMEBREW_PATH" => path,
"HOMEBREW_BREW_FILE" => HOMEBREW_PREFIX/"bin/brew",
"HOMEBREW_INTEGRATION_TEST" => command_id_from_args(args),
"HOMEBREW_TEST_TMPDIR" => TEST_TMPDIR,
diff --git a/Library/Homebrew/test/utils/github_spec.rb b/Library/Homebrew/test/utils/github_spec.rb
new file mode 100644
index 000000000..9b539262f
--- /dev/null
+++ b/Library/Homebrew/test/utils/github_spec.rb
@@ -0,0 +1,13 @@
+require "utils/github"
+
+describe GitHub do
+ describe "::search_code", :needs_network do
+ it "searches code" do
+ results = subject.search_code("repo:Homebrew/brew", "path:/", "filename:readme", "language:markdown")
+
+ expect(results.count).to eq(1)
+ expect(results.first["name"]).to eq("README.md")
+ expect(results.first["path"]).to eq("README.md")
+ end
+ 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..be224990a 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/test/version_spec.rb b/Library/Homebrew/test/version_spec.rb
index d3d63a25c..41e05019c 100644
--- a/Library/Homebrew/test/version_spec.rb
+++ b/Library/Homebrew/test/version_spec.rb
@@ -433,6 +433,11 @@ describe Version do
.to be_detected_from("https://homebrew.bintray.com/bottles/imagemagick-6.7.5-7.lion.bottle.1.tar.gz")
end
+ specify "date-based version style" do
+ expect(Version.create("2017-04-17"))
+ .to be_detected_from("https://example.com/dada-v2017-04-17.tar.gz")
+ end
+
specify "dash version style" do
expect(Version.create("3.4"))
.to be_detected_from("http://www.antlr.org/download/antlr-3.4-complete.jar")
diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb
index 46a8cc68e..28d7fc283 100644
--- a/Library/Homebrew/utils.rb
+++ b/Library/Homebrew/utils.rb
@@ -190,10 +190,10 @@ module Homebrew
Gem::Specification.reset
# Add Gem binary directory and (if missing) Ruby binary directory to PATH.
- path = ENV["PATH"].split(File::PATH_SEPARATOR)
- path.unshift(RUBY_BIN) if which("ruby") != RUBY_PATH
- path.unshift(Gem.bindir)
- ENV["PATH"] = path.join(File::PATH_SEPARATOR)
+ path = PATH.new(ENV["PATH"])
+ path.prepend(RUBY_BIN) if which("ruby") != RUBY_PATH
+ path.prepend(Gem.bindir)
+ ENV["PATH"] = path
if Gem::Specification.find_all_by_name(name, version).empty?
ohai "Installing or updating '#{name}' gem"
@@ -293,7 +293,7 @@ def quiet_system(cmd, *args)
end
def which(cmd, path = ENV["PATH"])
- path.split(File::PATH_SEPARATOR).each do |p|
+ PATH.new(path).each do |p|
begin
pcmd = File.expand_path(cmd, p)
rescue ArgumentError
@@ -307,7 +307,7 @@ def which(cmd, path = ENV["PATH"])
end
def which_all(cmd, path = ENV["PATH"])
- path.to_s.split(File::PATH_SEPARATOR).map do |p|
+ PATH.new(path).map do |p|
begin
pcmd = File.expand_path(cmd, p)
rescue ArgumentError
@@ -320,25 +320,34 @@ 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", "HOMEBREW_VISUAL").compact.reject(&:empty?).first
+ if editor
+ editor_name, _, editor_args = editor.partition " "
+ editor_path = which(editor_name, ENV["HOMEBREW_PATH"])
+ editor = if editor_args.to_s.empty?
+ editor_path.to_s
+ else
+ "#{editor_path} #{editor_args}"
+ end
+ return editor
+ end
# 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
- editor
+ editor.to_s
end
def exec_editor(*args)
@@ -347,7 +356,7 @@ def exec_editor(*args)
end
def exec_browser(*args)
- browser = ENV["HOMEBREW_BROWSER"] || ENV["BROWSER"]
+ browser = ENV["HOMEBREW_BROWSER"]
browser ||= OS::PATH_OPEN if defined?(OS::PATH_OPEN)
return unless browser
safe_exec(browser, *args)
@@ -406,8 +415,8 @@ def nostdout
end
end
-def paths
- @paths ||= ENV["PATH"].split(File::PATH_SEPARATOR).collect do |p|
+def paths(env_path = ENV["PATH"])
+ @paths ||= PATH.new(env_path).collect do |p|
begin
File.expand_path(p).chomp("/")
rescue ArgumentError
diff --git a/Library/Homebrew/utils/analytics.sh b/Library/Homebrew/utils/analytics.sh
index 35f91eabc..8d5cf2ff7 100644
--- a/Library/Homebrew/utils/analytics.sh
+++ b/Library/Homebrew/utils/analytics.sh
@@ -85,8 +85,6 @@ report-analytics-screenview-command() {
fi
# Don't report commands used mostly by our scripts and not users.
- # TODO: list more e.g. shell completion things here perhaps using a single
- # script as a shell-completion entry point.
case "$HOMEBREW_COMMAND" in
--prefix|analytics|command|commands)
return
diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb
index a5ed5394a..88c5199c2 100644
--- a/Library/Homebrew/utils/github.rb
+++ b/Library/Homebrew/utils/github.rb
@@ -4,7 +4,7 @@ require "tempfile"
module GitHub
module_function
- ISSUES_URI = URI.parse("https://api.github.com/search/issues")
+ API_URL = "https://api.github.com".freeze
CREATE_GIST_SCOPES = ["gist"].freeze
CREATE_ISSUE_SCOPES = ["public_repo"].freeze
@@ -228,13 +228,19 @@ module GitHub
end
def issues_matching(query, qualifiers = {})
- uri = ISSUES_URI.dup
+ uri = URI.parse("#{API_URL}/search/issues")
uri.query = build_query_string(query, qualifiers)
open(uri) { |json| json["items"] }
end
def repository(user, repo)
- open(URI.parse("https://api.github.com/repos/#{user}/#{repo}")) { |j| j }
+ open(URI.parse("#{API_URL}/repos/#{user}/#{repo}"))
+ end
+
+ def search_code(*params)
+ uri = URI.parse("#{API_URL}/search/code")
+ uri.query = "q=#{uri_escape(params.join(" "))}"
+ open(uri) { |json| json["items"] }
end
def build_query_string(query, qualifiers)
@@ -286,7 +292,7 @@ module GitHub
end
def private_repo?(user, repo)
- uri = URI.parse("https://api.github.com/repos/#{user}/#{repo}")
+ uri = URI.parse("#{API_URL}/repos/#{user}/#{repo}")
open(uri) { |json| json["private"] }
end
end
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 906d42918..b408631c7 100644
--- a/Library/Homebrew/vendor/README.md
+++ b/Library/Homebrew/vendor/README.md
@@ -1,7 +1,7 @@
Vendored Dependencies
=====================
-* [plist](https://github.com/bleything/plist), version 3.1.0
+* [plist](https://github.com/patsplat/plist), version 3.3.0
* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 1.1.0
diff --git a/Library/Homebrew/vendor/plist/plist.rb b/Library/Homebrew/vendor/plist/plist.rb
index 0b828afc6..82ecb27d2 100755
--- a/Library/Homebrew/vendor/plist/plist.rb
+++ b/Library/Homebrew/vendor/plist/plist.rb
@@ -1,5 +1,5 @@
-#!/usr/bin/env ruby
-#
+# encoding: utf-8
+
# = plist
#
# This is the main file for plist. Everything interesting happens in
@@ -15,7 +15,7 @@ require 'stringio'
require_relative 'plist/generator'
require_relative 'plist/parser'
+require_relative 'plist/version'
module Plist
- VERSION = '3.1.0'
end
diff --git a/Library/Homebrew/vendor/plist/plist/generator.rb b/Library/Homebrew/vendor/plist/plist/generator.rb
index 3b84c301f..84bef3aaf 100644..100755
--- a/Library/Homebrew/vendor/plist/plist/generator.rb
+++ b/Library/Homebrew/vendor/plist/plist/generator.rb
@@ -1,12 +1,12 @@
-#!/usr/bin/env ruby
-#
+# encoding: utf-8
+
# = plist
#
# Copyright 2006-2010 Ben Bleything and Patrick May
# Distributed under the MIT License
#
-module Plist ; end
+module Plist; end
# === Create a plist
# You can dump an object to a plist in one of two ways:
@@ -94,7 +94,7 @@ module Plist::Emit
output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
when Date # also catches DateTime
output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'))
- when String, Symbol, Fixnum, Bignum, Integer, Float
+ when String, Symbol, Integer, Float
output << tag(element_type(element), CGI::escapeHTML(element.to_s))
when IO, StringIO
element.rewind
@@ -159,7 +159,7 @@ module Plist::Emit
when String, Symbol
'string'
- when Fixnum, Bignum, Integer
+ when Integer
'integer'
when Float
diff --git a/Library/Homebrew/vendor/plist/plist/parser.rb b/Library/Homebrew/vendor/plist/plist/parser.rb
index de441fcc5..4de13f881 100644..100755
--- a/Library/Homebrew/vendor/plist/plist/parser.rb
+++ b/Library/Homebrew/vendor/plist/plist/parser.rb
@@ -1,5 +1,5 @@
-#!/usr/bin/env ruby
-#
+# encoding: utf-8
+
# = plist
#
# Copyright 2006-2010 Ben Bleything and Patrick May
@@ -73,10 +73,10 @@ module Plist
end
TEXT = /([^<]+)/
- XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/um
- DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
- COMMENT_START = /\A<!--/u
- COMMENT_END = /.*?-->/um
+ XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/m
+ DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/m
+ COMMENT_START = /\A<!--/
+ COMMENT_END = /.*?-->/m
def parse
@@ -91,7 +91,14 @@ module Plist
if @scanner.scan(COMMENT_START)
@scanner.scan(COMMENT_END)
elsif @scanner.scan(XMLDECL_PATTERN)
+ encoding = parse_encoding_from_xml_declaration(@scanner[1])
+ next if encoding.nil?
+
+ # use the specified encoding for the rest of the file
+ next unless String.method_defined?(:force_encoding)
+ @scanner.string = @scanner.rest.force_encoding(encoding)
elsif @scanner.scan(DOCTYPE_PATTERN)
+ next
elsif @scanner.scan(start_tag)
@listener.tag_start(@scanner[1], nil)
if (@scanner[2] =~ /\/$/)
@@ -106,6 +113,22 @@ module Plist
end
end
end
+
+ private
+
+ def parse_encoding_from_xml_declaration(xml_declaration)
+ return unless defined?(Encoding)
+
+ xml_encoding = xml_declaration.match(/(?:\A|\s)encoding=(?:"(.*?)"|'(.*?)')(?:\s|\Z)/)
+
+ return if xml_encoding.nil?
+
+ begin
+ Encoding.find(xml_encoding[1])
+ rescue ArgumentError
+ nil
+ end
+ end
end
class PTag
@@ -213,7 +236,7 @@ module Plist
data = Base64.decode64(text.gsub(/\s+/, '')) unless text.nil?
begin
return Marshal.load(data)
- rescue Exception => e
+ rescue Exception
io = StringIO.new
io.write data
io.rewind
diff --git a/Library/Homebrew/vendor/plist/plist/version.rb b/Library/Homebrew/vendor/plist/plist/version.rb
new file mode 100755
index 000000000..80b1f73dd
--- /dev/null
+++ b/Library/Homebrew/vendor/plist/plist/version.rb
@@ -0,0 +1,5 @@
+# encoding: utf-8
+
+module Plist
+ VERSION = '3.3.0'.freeze
+end
diff --git a/Library/Homebrew/version.rb b/Library/Homebrew/version.rb
index b9f512a50..da239f788 100644
--- a/Library/Homebrew/version.rb
+++ b/Library/Homebrew/version.rb
@@ -316,6 +316,11 @@ class Version
spec.stem
end
+ # date-based versioning
+ # e.g. ltopers-v2017-04-14.tar.gz
+ m = /-v?(\d{4}-\d{2}-\d{2})/.match(stem)
+ return m.captures.first unless m.nil?
+
# GitHub tarballs
# e.g. https://github.com/foo/bar/tarball/v1.2.3
# e.g. https://github.com/sam-github/libnet/tarball/libnet-1.1.4