2018-02-01 16:06:17 -05:00
#: * `audit` [`--strict`] [`--fix`] [`--online`] [`--new-formula`] [`--display-cop-names`] [`--display-filename`] [`--only=`<method>|`--except=`<method>] [`--only-cops=`<cops>|`--except-cops=`<cops>] [<formulae>]:
2016-04-08 16:28:43 +02:00
#: Check <formulae> for Homebrew coding style violations. This should be
#: run before submitting a new formula.
#:
#: If no <formulae> are provided, all of them are checked.
#:
2016-04-18 17:39:21 -04:00
#: If `--strict` is passed, additional checks are run, including RuboCop
2016-08-02 10:59:39 +01:00
#: style checks.
2016-04-08 16:28:43 +02:00
#:
2017-01-18 22:37:11 +05:30
#: If `--fix` is passed, style violations will be
2018-02-01 16:06:17 -05:00
#: automatically fixed using RuboCop's auto-correct feature.
2016-04-08 16:28:43 +02:00
#:
#: If `--online` is passed, additional slower checks that require a network
2016-08-02 10:59:39 +01:00
#: connection are run.
2016-08-17 01:19:40 +02:00
#:
2016-08-02 10:59:39 +01:00
#: If `--new-formula` is passed, various additional checks are run that check
2016-11-03 02:51:22 +00:00
#: if a new formula is eligible for Homebrew. This should be used when creating
2016-08-02 10:59:39 +01:00
#: new formulae and implies `--strict` and `--online`.
2016-08-17 01:19:40 +02:00
#:
2016-04-18 17:39:21 -04:00
#: If `--display-cop-names` is passed, the RuboCop cop name for each violation
#: is included in the output.
#:
2016-05-11 09:19:45 -07:00
#: 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.
#:
2018-02-01 16:06:17 -05:00
#: Passing `--only=`<method> will run only the methods named `audit_<method>`,
#: while `--except=`<method> will skip the methods named `audit_<method>`.
#: For either option <method> should be a comma-separated list.
2017-04-18 08:17:24 +01:00
#:
2018-02-01 16:06:17 -05:00
#: Passing `--only-cops=`<cops> will check for violations of only the listed
#: RuboCop <cops>, while `--except-cops=`<cops> will skip checking the listed
#: <cops>. For either option <cops> should be a comma-separated list of cop names.
2017-04-23 04:09:13 +05:30
#:
2016-04-08 16:28:43 +02:00
#: `audit` exits with a non-zero status if any errors are found. This is useful,
#: for instance, for implementing pre-commit hooks.
2016-04-18 17:39:21 -04:00
# Undocumented options:
2018-02-01 16:06:17 -05:00
# `-D` activates debugging and profiling of the audit methods (not the same as `--debug`)
2016-04-18 17:39:21 -04:00
2015-05-24 16:14:44 +01:00
require " formula "
2016-01-14 13:33:56 +08:00
require " formula_versions "
2017-12-03 14:02:55 +01:00
require " utils/curl "
2015-05-24 16:14:44 +01:00
require " extend/ENV "
require " formula_cellar_checks "
2015-05-31 18:40:28 +08:00
require " cmd/search "
2016-04-18 17:39:21 -04:00
require " cmd/style "
2015-07-09 15:28:27 +01:00
require " date "
2017-03-18 17:02:08 +02:00
require " missing_formula "
2017-02-02 21:25:29 +00:00
require " digest "
2018-02-04 22:09:35 +05:30
require " cli_parser "
2012-03-17 19:49:49 -07:00
2014-06-18 22:41:47 -05:00
module Homebrew
2016-09-26 01:44:51 +02:00
module_function
2012-08-07 01:37:46 -05:00
def audit
2018-03-25 17:48:22 +05:30
args = Homebrew :: CLI :: Parser . parse do
2018-02-04 22:09:35 +05:30
switch " --strict "
switch " --online "
switch " --new-formula "
switch " --fix "
switch " --display-cop-names "
switch " --display-filename "
switch " -D " , " --audit-debug " , description : " Activates debugging and profiling "
2018-03-29 03:20:14 +05:30
switch :verbose
switch :debug
2018-02-04 22:09:35 +05:30
comma_array " --only "
comma_array " --except "
comma_array " --only-cops "
comma_array " --except-cops "
2018-03-25 17:48:22 +05:30
end
2018-02-04 22:09:35 +05:30
2017-09-02 12:38:18 +05:30
Homebrew . auditing = true
2018-02-04 22:09:35 +05:30
inject_dump_stats! ( FormulaAuditor , / ^audit_ / ) if args . audit_debug?
2016-04-18 17:39:21 -04:00
2012-08-07 01:37:46 -05:00
formula_count = 0
problem_count = 0
2018-02-04 22:09:35 +05:30
new_formula = args . new_formula?
strict = new_formula || args . strict?
online = new_formula || args . online?
2015-07-09 12:31:17 +01:00
2013-08-19 13:03:41 -05:00
ENV . activate_extensions!
2013-05-07 18:39:45 -05:00
ENV . setup_build_environment
2016-04-18 17:39:21 -04:00
if ARGV . named . empty?
ff = Formula
files = Tap . map ( & :formula_dir )
2012-08-07 01:37:46 -05:00
else
2016-04-18 17:39:21 -04:00
ff = ARGV . resolved_formulae
files = ARGV . resolved_formulae . map ( & :path )
end
2016-08-16 17:00:31 +01:00
2018-02-04 22:09:35 +05:30
only_cops = args . only_cops
except_cops = args . except_cops
2017-06-30 10:58:24 +05:30
2018-02-04 22:09:35 +05:30
if only_cops && except_cops
2017-05-03 11:33:00 +05:30
odie " --only-cops and --except-cops cannot be used simultaneously! "
2018-02-04 22:09:35 +05:30
elsif ( only_cops || except_cops ) && ( strict || args . only )
2017-06-30 10:58:24 +05:30
odie " --only-cops/--except-cops and --strict/--only cannot be used simultaneously "
2017-04-23 04:09:13 +05:30
end
2018-02-04 22:09:35 +05:30
options = { fix : args . fix? , realpath : true }
2017-05-03 11:33:00 +05:30
2018-02-04 22:09:35 +05:30
if only_cops
2017-05-03 11:33:00 +05:30
options [ :only_cops ] = only_cops
2018-02-04 22:09:35 +05:30
args . only = [ " style " ]
elsif args . new_formula?
2017-07-28 05:01:01 +05:30
nil
2017-07-15 13:34:16 +05:30
elsif strict
2017-07-28 05:01:01 +05:30
options [ :except_cops ] = [ :NewFormulaAudit ]
2018-02-04 22:09:35 +05:30
elsif except_cops
2017-05-03 11:33:00 +05:30
options [ :except_cops ] = except_cops
elsif ! strict
2017-07-30 22:01:07 +05:30
options [ :only_cops ] = [ :FormulaAudit ]
2012-08-07 01:37:46 -05:00
end
2014-12-27 12:38:04 +00:00
2018-02-04 22:09:35 +05:30
options [ :display_cop_names ] = args . display_cop_names?
2017-04-23 04:09:13 +05:30
# Check style in a single batch run up front for performance
style_results = check_style_json ( files , options )
2017-03-29 02:07:53 +05:30
2018-01-07 13:36:16 +10:00
ff . sort . each do | f |
2018-02-04 22:09:35 +05:30
options = { new_formula : new_formula , strict : strict , online : online , only : args . only , except : args . except }
2017-03-29 02:07:53 +05:30
options [ :style_offenses ] = style_results . file_offenses ( f . path )
2016-04-18 17:39:21 -04:00
fa = FormulaAuditor . new ( f , options )
2012-08-07 01:37:46 -05:00
fa . audit
2016-04-18 17:39:21 -04:00
next if fa . problems . empty?
2016-08-25 07:00:39 -07:00
fa . problems
2016-04-18 17:39:21 -04:00
formula_count += 1
problem_count += fa . problems . size
2016-05-11 09:19:45 -07:00
problem_lines = fa . problems . map { | p | " * #{ p . chomp . gsub ( " \n " , " \n " ) } " }
2018-02-04 22:09:35 +05:30
if args . display_filename?
2016-05-16 18:46:47 +01:00
puts problem_lines . map { | s | " #{ f . path } : #{ s } " }
2016-05-11 09:19:45 -07:00
else
2016-05-16 18:46:47 +01:00
puts " #{ f . full_name } : " , problem_lines . map { | s | " #{ s } " }
2016-05-11 09:19:45 -07:00
end
2012-08-07 01:37:46 -05:00
end
2016-09-22 20:12:28 +02:00
return if problem_count . zero?
2017-03-11 11:33:12 +01:00
ofail " #{ Formatter . pluralize ( problem_count , " problem " ) } in #{ Formatter . pluralize ( formula_count , " formula " ) } "
2012-08-07 01:37:46 -05:00
end
end
2012-03-17 19:49:49 -07:00
2012-08-07 01:37:46 -05:00
class FormulaText
2015-08-03 13:09:07 +01:00
def initialize ( path )
2014-06-04 15:37:36 -05:00
@text = path . open ( " rb " , & :read )
2015-06-09 21:34:44 +08:00
@lines = @text . lines . to_a
2010-07-23 21:31:32 -07:00
end
2012-08-07 01:37:46 -05:00
def without_patch
2014-11-12 21:41:14 -06:00
@text . split ( " \n __END__ " ) . first
2011-11-29 19:37:39 -06:00
end
2016-09-11 17:41:51 +01:00
def data?
2014-09-23 15:47:34 -04:00
/ ^[^ # ]* \ bDATA \ b / =~ @text
2010-08-15 15:19:19 -07:00
end
2016-09-11 17:41:51 +01:00
def end?
2012-08-07 01:37:46 -05:00
/ ^__END__$ / =~ @text
2010-09-08 09:07:59 -07:00
end
2016-09-11 17:41:51 +01:00
def trailing_newline?
2013-02-21 09:56:30 +01:00
/ \ Z \ n / =~ @text
2010-09-07 14:34:39 -07:00
end
2015-02-24 15:54:31 +08:00
2016-09-11 17:41:51 +01:00
def =~ ( other )
other =~ @text
2015-02-24 15:54:31 +08:00
end
2015-06-08 18:57:17 +08:00
2016-07-13 18:28:40 +08:00
def include? ( s )
@text . include? s
end
2016-08-25 07:00:39 -07:00
def line_number ( regex , skip = 0 )
index = @lines . drop ( skip ) . index { | line | line =~ regex }
2015-06-08 18:57:17 +08:00
index ? index + 1 : nil
end
2016-08-25 07:00:39 -07:00
def reverse_line_number ( regex )
index = @lines . reverse . index { | line | line =~ regex }
index ? @lines . count - index : nil
end
2012-08-07 01:37:46 -05:00
end
2010-09-07 14:34:39 -07:00
2012-08-07 01:37:46 -05:00
class FormulaAuditor
2013-07-15 19:29:08 -07:00
include FormulaCellarChecks
2014-10-29 22:38:49 -05:00
attr_reader :formula , :text , :problems
2012-08-07 01:37:46 -05:00
2015-08-03 13:09:07 +01:00
def initialize ( formula , options = { } )
2014-10-29 22:38:49 -05:00
@formula = formula
2016-09-11 17:41:51 +01:00
@new_formula = options [ :new_formula ]
@strict = options [ :strict ]
@online = options [ :online ]
2018-02-04 22:09:35 +05:30
@display_cop_names = options [ :display_cop_names ]
@only = options [ :only ]
@except = options [ :except ]
2016-04-18 17:39:21 -04:00
# Accept precomputed style offense results, for efficiency
@style_offenses = options [ :style_offenses ]
2018-02-04 21:54:49 -05:00
# Allow the actual official-ness of a formula to be overridden, for testing purposes
@official_tap = formula . tap & . official? || options [ :official_tap ]
2012-08-07 01:37:46 -05:00
@problems = [ ]
2014-11-12 21:41:14 -06:00
@text = FormulaText . new ( formula . path )
2015-08-03 13:09:07 +01:00
@specs = %w[ stable devel head ] . map { | s | formula . send ( s ) } . compact
2012-08-07 01:37:46 -05:00
end
2016-04-18 17:39:21 -04:00
def audit_style
return unless @style_offenses
@style_offenses . each do | offense |
2018-02-04 22:09:35 +05:30
problem offense . to_s ( display_cop_name : @display_cop_names )
2016-04-18 17:39:21 -04:00
end
end
2016-08-25 07:00:39 -07:00
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
# corresponding bits. (The also included 0100000 flag means regular file.)
wanted_mode = 0100644 & ~ File . umask
actual_mode = formula . path . stat . mode
unless actual_mode == wanted_mode
problem format ( " Incorrect file permissions (%03o): chmod %03o %s " ,
actual_mode & 0777 , wanted_mode & 0777 , formula . path )
end
2016-09-25 01:51:37 +02:00
problem " 'DATA' was found, but no '__END__' " if text . data? && ! text . end?
2016-08-25 07:00:39 -07:00
2016-09-11 17:41:51 +01:00
if text . end? && ! text . data?
2016-08-25 07:00:39 -07:00
problem " '__END__' was found, but 'DATA' is not used "
end
if text =~ / inreplace [^ \ n]* do [^ \ n]* \ n[^ \ n]* \ .gsub![^ \ n]* \ n \ *end /m
problem " 'inreplace ... do' was used for a single substitution (use the non-block form instead). "
end
2016-09-25 01:51:37 +02:00
problem " File should end with a newline " unless text . trailing_newline?
2016-08-25 07:00:39 -07:00
2017-03-26 20:36:37 +01:00
if formula . versioned_formula?
2017-04-22 13:00:36 +01:00
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
2017-03-26 20:36:37 +01:00
unless unversioned_formula . exist?
unversioned_name = unversioned_formula . basename ( " .rb " )
problem " #{ formula } is versioned but no #{ unversioned_name } formula exists "
end
2017-07-07 09:30:18 +01:00
elsif ARGV . build_stable? && formula . stable? &&
2017-05-09 15:10:29 +01:00
! ( 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
valid_alias_names = [ alias_name_major , alias_name_major_minor ]
2017-09-24 20:12:58 +01:00
unless formula . tap & . core_tap?
2017-08-08 16:51:46 -04:00
versioned_aliases . map! { | a | " #{ formula . tap } / #{ a } " }
2017-05-17 15:18:59 -04:00
valid_alias_names . map! { | a | " #{ formula . tap } / #{ a } " }
end
2017-05-09 15:10:29 +01:00
valid_versioned_aliases = versioned_aliases & valid_alias_names
invalid_versioned_aliases = versioned_aliases - valid_alias_names
if valid_versioned_aliases . empty?
if formula . tap
2017-10-15 02:28:32 +02:00
problem << ~ EOS
2017-05-09 15:10:29 +01:00
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
2017-03-26 20:36:37 +01:00
else
2017-05-09 15:10:29 +01:00
problem " Formula has other versions so create an alias named #{ alias_name } . "
2017-03-26 20:36:37 +01:00
end
2017-05-09 15:10:29 +01:00
end
unless invalid_versioned_aliases . empty?
2017-10-15 02:28:32 +02:00
problem << ~ EOS
2017-05-09 15:10:29 +01:00
Formula has invalid versioned aliases :
#{invalid_versioned_aliases.join("\n ")}
2017-03-26 20:36:37 +01:00
EOS
2017-02-23 09:14:54 +00:00
end
end
2014-12-27 20:46:01 +00:00
end
2014-12-27 15:58:29 +00:00
2017-10-07 00:31:28 +02:00
def self . aliases
# core aliases + tap alias names + tap alias full name
@aliases || = Formula . aliases + Formula . tap_aliases
2010-08-08 10:17:53 -07:00
end
2015-05-31 18:40:28 +08:00
def audit_formula_name
return unless @strict
# skip for non-official taps
2018-02-04 21:54:49 -05:00
return unless @official_tap
2015-05-31 18:40:28 +08:00
name = formula . name
2018-04-14 01:39:00 +02:00
if MissingFormula . blacklisted_reason ( name )
2016-11-20 00:40:54 -05:00
problem " ' #{ name } ' is blacklisted. "
end
2015-09-13 17:33:35 +08:00
if Formula . aliases . include? name
2015-06-07 11:49:41 -07:00
problem " Formula name conflicts with existing aliases. "
2015-05-31 18:40:28 +08:00
return
end
2016-03-07 18:04:25 +08:00
if oldname = CoreTap . instance . formula_renames [ name ]
2015-12-09 12:09:55 +08:00
problem " ' #{ name } ' is reserved as the old name of #{ oldname } "
2015-08-09 14:48:12 +03:00
return
end
2017-09-29 16:23:02 +01:00
return if formula . core_formula?
return unless Formula . core_names . include? ( name )
2015-09-07 18:54:44 +08:00
2017-09-29 16:23:02 +01:00
problem " Formula name conflicts with existing core formula. "
2015-05-31 18:40:28 +08:00
end
2014-10-17 00:11:46 -05:00
def audit_deps
2014-10-17 00:07:35 -05:00
@specs . each do | spec |
# Check for things we don't like to depend on.
# We allow non-Homebrew installs whenever possible.
spec . deps . each do | dep |
begin
dep_f = dep . to_formula
rescue TapFormulaUnavailableError
# Don't complain about missing cross-tap dependencies
next
rescue FormulaUnavailableError
problem " Can't find dependency #{ dep . name . inspect } . "
next
2015-05-17 19:59:18 +08:00
rescue TapFormulaAmbiguityError
problem " Ambiguous dependency #{ dep . name . inspect } . "
next
2015-10-07 17:34:29 +08:00
rescue TapFormulaWithOldnameAmbiguityError
problem " Ambiguous oldname dependency #{ dep . name . inspect } . "
next
2014-10-17 00:07:35 -05:00
end
2014-10-17 00:11:46 -05:00
2015-10-07 17:34:29 +08:00
if dep_f . oldname && dep . name . split ( " / " ) . last == dep_f . oldname
2016-01-06 17:58:16 +01:00
problem " Dependency ' #{ dep . name } ' was renamed; use new name ' #{ dep_f . name } '. "
2015-08-09 14:48:12 +03:00
end
2017-10-07 00:31:28 +02:00
if self . class . aliases . include? ( dep . name ) &&
2017-04-04 18:38:18 +01:00
( dep_f . core_formula? || ! dep_f . versioned_formula? )
2015-05-27 20:42:20 +08:00
problem " Dependency ' #{ dep . name } ' is an alias; use the canonical name ' #{ dep . to_formula . full_name } '. "
2014-10-17 00:11:46 -05:00
end
2014-10-17 00:07:35 -05:00
2017-03-19 20:45:21 +02:00
if @new_formula && dep_f . keg_only_reason &&
! [ " openssl " , " apr " , " apr-util " ] . include? ( dep . name ) &&
[ :provided_by_macos , :provided_by_osx ] . include? ( dep_f . keg_only_reason . reason )
problem " Dependency ' #{ dep . name } ' may be unnecessary as it is provided by macOS; try to build this formula without it. "
end
2017-10-07 00:31:28 +02:00
dep . options . each do | opt |
next if dep_f . option_defined? ( opt )
next if dep_f . requirements . detect do | r |
2014-10-17 00:07:35 -05:00
if r . recommended?
opt . name == " with- #{ r . name } "
elsif r . optional?
opt . name == " without- #{ r . name } "
end
2014-02-16 22:35:14 +00:00
end
2017-10-07 00:31:28 +02:00
2014-10-17 00:07:35 -05:00
problem " Dependency #{ dep } does not define option #{ opt . name . inspect } "
2014-02-16 22:35:14 +00:00
end
2013-01-23 00:26:31 -06:00
2018-03-19 10:11:08 +00:00
if dep . name == " git "
2017-12-30 18:58:30 +00:00
problem " Don't use git as a dependency (it's always available) "
2018-03-19 10:11:08 +00:00
end
if dep . tags . include? ( :run )
problem " Dependency ' #{ dep . name } ' is marked as :run. Remove :run; it is a no-op. "
2014-10-17 00:07:35 -05:00
end
2012-08-07 01:37:46 -05:00
end
end
2010-09-13 15:16:09 -07:00
end
2013-01-03 11:22:31 -08:00
def audit_conflicts
2014-10-29 22:38:49 -05:00
formula . conflicts . each do | c |
2013-01-03 11:22:31 -08:00
begin
2014-02-24 20:23:21 -08:00
Formulary . factory ( c . name )
2015-05-05 23:26:11 +08:00
rescue TapFormulaUnavailableError
# Don't complain about missing cross-tap conflicts.
next
2013-02-17 22:54:27 -06:00
rescue FormulaUnavailableError
2013-06-09 13:44:59 -05:00
problem " Can't find conflicting formula #{ c . name . inspect } . "
2015-10-07 17:34:29 +08:00
rescue TapFormulaAmbiguityError , TapFormulaWithOldnameAmbiguityError
2015-05-17 19:59:18 +08:00
problem " Ambiguous conflicting formula #{ c . name . inspect } . "
2013-01-03 11:22:31 -08:00
end
end
end
2010-08-07 15:23:13 -07:00
2017-04-28 04:53:52 +01:00
def audit_keg_only_style
return unless @strict
return unless formula . keg_only?
whitelist = %w[
Apple
macOS
OS
Homebrew
Xcode
GPG
GNOME
BSD
2017-05-02 19:05:56 +01:00
Firefox
2017-04-28 04:53:52 +01:00
] . 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 ]
2017-05-02 19:30:41 +01:00
if reason =~ / \ A[A-Z] / && ! reason . start_with? ( * whitelist )
2017-10-15 02:28:32 +02:00
problem << ~ EOS
2017-04-28 04:53:52 +01:00
'#{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
2015-05-07 23:18:01 -04:00
def audit_homepage
2014-10-29 22:38:49 -05:00
homepage = formula . homepage
2014-09-14 15:43:20 -05:00
2017-05-29 18:24:52 +01:00
return if homepage . nil? || homepage . empty?
2017-02-26 16:49:09 +11:00
2015-07-11 23:36:03 +02:00
return unless @online
2016-12-23 20:29:56 +00:00
2017-09-16 12:41:08 +01:00
return unless DevelopmentTools . curl_handles_most_https_certificates?
2017-12-03 14:02:55 +01:00
if http_content_problem = curl_check_http_content ( homepage ,
user_agents : [ :browser , :default ] ,
check_content : true ,
strict : @strict )
2017-02-23 10:15:06 +00:00
problem http_content_problem
end
2011-03-15 21:40:09 -07:00
end
2015-10-23 10:41:39 +02:00
def audit_bottle_spec
2016-09-23 22:02:23 +02:00
return unless formula . bottle_disabled?
return if formula . bottle_disable_reason . valid?
problem " Unrecognized bottle modifier "
2015-10-23 10:41:39 +02:00
end
2015-07-08 14:22:44 +01:00
def audit_github_repository
2015-07-09 12:31:17 +01:00
return unless @online
2016-08-02 10:59:39 +01:00
return unless @new_formula
2015-07-08 14:22:44 +01:00
2016-07-13 16:19:51 +08:00
regex = %r{ https?://github \ .com/([^/]+)/([^/]+)/?.* }
2015-07-08 16:22:42 +01:00
_ , user , repo = * regex . match ( formula . stable . url ) if formula . stable
2015-07-08 14:22:44 +01:00
_ , user , repo = * regex . match ( formula . homepage ) unless user
return if ! user || ! repo
2015-07-08 15:19:36 +01:00
repo . gsub! ( / .git$ / , " " )
begin
metadata = GitHub . repository ( user , repo )
2015-07-08 15:29:55 +01:00
rescue GitHub :: HTTPNotFoundError
2015-07-08 15:19:36 +01:00
return
end
2016-03-13 01:40:00 +01:00
return if metadata . nil?
2015-07-08 14:22:44 +01:00
problem " GitHub fork (not canonical repository) " if metadata [ " fork " ]
2017-10-06 11:39:43 -07:00
if formula & . tap & . core_tap? &&
( metadata [ " forks_count " ] < 20 ) && ( metadata [ " subscribers_count " ] < 20 ) &&
2016-02-11 20:31:48 +00:00
( metadata [ " stargazers_count " ] < 50 )
problem " GitHub repository not notable enough (<20 forks, <20 watchers and <50 stars) "
2015-07-08 14:22:44 +01:00
end
2016-09-23 22:02:23 +02:00
return if Date . parse ( metadata [ " created_at " ] ) < = ( Date . today - 30 )
problem " GitHub repository too new (<30 days old) "
2015-07-08 14:22:44 +01:00
end
2012-08-07 01:37:46 -05:00
def audit_specs
2016-05-16 18:40:22 +01:00
if head_only? ( formula ) && formula . tap . to_s . downcase !~ %r{ [-/]head-only$ }
2014-11-12 21:30:09 -06:00
problem " Head-only (no stable download) "
end
2012-01-25 22:41:53 -06:00
2016-05-16 18:40:22 +01:00
if devel_only? ( formula ) && formula . tap . to_s . downcase !~ %r{ [-/]devel-only$ }
2015-01-24 23:36:33 +00:00
problem " Devel-only (no stable download) "
end
2013-09-18 18:50:23 -05:00
%w[ Stable Devel HEAD ] . each do | name |
2017-09-14 19:58:37 +01:00
spec_name = name . downcase . to_sym
next unless spec = formula . send ( spec_name )
2013-09-18 18:50:23 -05:00
2017-09-14 19:58:37 +01:00
ra = ResourceAuditor . new ( spec , spec_name , online : @online , strict : @strict ) . audit
2013-09-18 18:50:23 -05:00
problems . concat ra . problems . map { | problem | " #{ name } : #{ problem } " }
2013-09-18 18:22:00 -05:00
spec . resources . each_value do | resource |
2017-09-14 19:58:37 +01:00
ra = ResourceAuditor . new ( resource , spec_name , online : @online , strict : @strict ) . audit
2013-09-18 18:50:23 -05:00
problems . concat ra . problems . map { | problem |
" #{ name } resource #{ resource . name . inspect } : #{ problem } "
}
2013-09-18 18:22:00 -05:00
end
2014-03-13 19:51:23 -05:00
2017-04-21 13:15:27 +01:00
next if spec . patches . empty?
next unless @new_formula
problem " New formulae should not require patches to build. Patches should be submitted and accepted upstream first. "
2013-05-27 22:24:22 -07:00
end
2014-09-23 13:04:55 -05:00
2015-05-24 03:05:00 +08:00
%w[ Stable Devel ] . each do | name |
next unless spec = formula . send ( name . downcase )
version = spec . version
if version . to_s !~ / \ d /
problem " #{ name } : version ( #{ version } ) is set to a string without a digit "
end
2017-03-02 21:21:52 -08:00
if version . to_s . start_with? ( " HEAD " )
problem " #{ name } : non-HEAD version name ( #{ version } ) should not begin with HEAD "
end
2015-05-24 03:05:00 +08:00
end
2014-10-29 22:38:49 -05:00
if formula . stable && formula . devel
if formula . devel . version < formula . stable . version
problem " devel version #{ formula . devel . version } is older than stable version #{ formula . stable . version } "
elsif formula . devel . version == formula . stable . version
2014-09-23 13:04:55 -05:00
problem " stable and devel versions are identical "
end
end
2015-01-22 16:58:54 -05:00
2018-04-14 19:24:07 +10:00
if @new_formula && formula . head
problem " New formulae should not have a HEAD spec "
end
2017-01-13 16:26:59 -08:00
unstable_whitelist = %w[
aalib 1 . 4 rc5
2017-02-25 03:03:37 -08:00
angolmois 2 . 0 . 0 alpha2
2017-01-13 16:26:59 -08:00
automysqlbackup 3 . 0 - rc6
aview 1 . 3 . 0 rc1
distcc 3 . 2 rc1
2017-03-26 22:43:08 -07:00
elm - format 0 . 6 . 0 - alpha
2017-01-13 16:26:59 -08:00
ftgl 2 . 1 . 3 - rc5
hidapi 0 . 8 . 0 - rc1
libcaca 0 . 99 b19
2017-02-25 03:03:37 -08:00
nethack4 4 . 3 . 0 - beta2
opensyobon 1 . 0 rc2
2017-01-13 16:26:59 -08:00
premake 4 . 4 - beta5
pwnat 0 . 3 - beta
pxz 4 . 999 . 9
recode 3 . 7 - beta2
speexdsp 1 . 2 rc3
sqoop 1 . 4 . 6
tcptraceroute 1 . 5 beta7
testssl 2 . 8 rc3
tiny - fugue 5 . 0 b8
vbindiff 3 . 0 _beta4
] . each_slice ( 2 ) . to_a . map do | formula , version |
[ formula , version . sub ( / \ d+$ / , " " ) ]
end
gnome_devel_whitelist = %w[
gtk - doc 1 . 25
libart 2 . 3 . 21
pygtkglext 1 . 1 . 0
2018-03-25 11:35:16 +01:00
libepoxy 1 . 5 . 0
2017-01-13 16:26:59 -08:00
] . each_slice ( 2 ) . to_a . map do | formula , version |
[ formula , version . split ( " . " ) [ 0 .. 1 ] . join ( " . " ) ]
end
2015-01-22 16:58:54 -05:00
stable = formula . stable
2017-09-24 19:24:46 +01:00
case stable & . url
2016-10-24 14:54:28 +01:00
when / [ \ d \ ._-](alpha|beta|rc \ d) /
2017-06-10 20:23:20 +03:00
matched = Regexp . last_match ( 1 )
2017-01-13 16:26:59 -08:00
version_prefix = stable . version . to_s . sub ( / \ d+$ / , " " )
return if unstable_whitelist . include? ( [ formula . name , version_prefix ] )
problem " Stable version URLs should not contain #{ matched } "
2015-05-14 00:01:00 -04:00
when %r{ download \ .gnome \ .org/sources } , %r{ ftp \ .gnome \ .org/pub/GNOME/sources }i
2017-01-13 16:26:59 -08:00
version_prefix = stable . version . to_s . split ( " . " ) [ 0 .. 1 ] . join ( " . " )
return if gnome_devel_whitelist . include? ( [ formula . name , version_prefix ] )
2015-11-01 09:25:06 -08:00
version = Version . parse ( stable . url )
2016-07-11 16:09:35 +03:00
if version > = Version . create ( " 1.0 " )
2015-11-01 09:25:06 -08:00
minor_version = version . to_s . split ( " . " , 3 ) [ 1 ] . to_i
if minor_version . odd?
problem " #{ stable . version } is a development release "
end
2015-01-22 16:58:54 -05:00
end
end
2011-11-30 13:14:24 -06:00
end
2016-08-18 12:55:46 +01:00
def audit_revision_and_version_scheme
2016-01-14 13:33:56 +08:00
return unless formula . tap # skip formula not from core or any taps
return unless formula . tap . git? # git log is required
2016-10-30 10:38:37 +01:00
return if @new_formula
2016-01-14 13:33:56 +08:00
2017-04-23 18:56:22 +01:00
fv = FormulaVersions . new ( formula )
2017-05-10 20:45:34 +02:00
previous_version_and_checksum = fv . previous_version_and_checksum ( " origin/master " )
[ :stable , :devel ] . each do | spec_sym |
next unless spec = formula . send ( spec_sym )
next unless previous_version_and_checksum [ spec_sym ] [ :version ] == spec . version
next if previous_version_and_checksum [ spec_sym ] [ :checksum ] == spec . checksum
2017-05-22 02:04:02 +02:00
problem " #{ spec_sym } : sha256 changed without the version also changing; please create an issue upstream to rule out malicious circumstances and to find out why the file changed. "
2017-05-10 20:45:34 +02:00
end
2016-11-13 13:35:25 +00:00
attributes = [ :revision , :version_scheme ]
2016-08-18 12:55:19 +01:00
attributes_map = fv . version_attributes_map ( attributes , " origin/master " )
2017-04-23 18:56:22 +01:00
current_version_scheme = formula . version_scheme
2016-11-17 17:13:52 +00:00
[ :stable , :devel ] . each do | spec |
2016-11-13 13:35:25 +00:00
spec_version_scheme_map = attributes_map [ :version_scheme ] [ spec ]
2017-04-26 11:33:13 +01:00
next if spec_version_scheme_map . empty?
2016-11-13 13:35:25 +00:00
2017-04-23 18:56:22 +01:00
version_schemes = spec_version_scheme_map . values . flatten
max_version_scheme = version_schemes . max
2016-11-13 13:35:25 +00:00
max_version = spec_version_scheme_map . select do | _ , version_scheme |
version_scheme . first == max_version_scheme
end . keys . max
2017-04-23 18:56:22 +01:00
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
2016-11-15 09:02:50 +00:00
2017-04-23 18:56:22 +01:00
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 "
2016-11-13 13:35:25 +00:00
end
2017-04-23 18:56:22 +01:00
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 } ) "
2016-10-30 13:49:55 -04:00
end
2016-09-22 20:12:28 +02:00
2017-04-23 18:56:22 +01:00
current_revision = formula . revision
2017-04-26 11:33:13 +01:00
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
2017-04-23 18:56:22 +01:00
2017-04-26 11:33:13 +01:00
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 "
2016-01-15 16:17:14 +08:00
end
2017-04-23 18:56:22 +01:00
elsif ! current_revision . zero? # head/devel-only formula
problem " 'revision #{ current_revision } ' should be removed "
2016-01-14 13:33:56 +08:00
end
end
2013-07-16 23:15:22 -05:00
def audit_text
2016-10-24 15:07:49 +01:00
bin_names = Set . new
bin_names << formula . name
bin_names += formula . aliases
[ formula . bin , formula . sbin ] . each do | dir |
next unless dir . exist?
bin_names += dir . children . map ( & :basename ) . map ( & :to_s )
end
bin_names . each do | name |
2016-11-02 13:23:38 -04:00
[ " system " , " shell_output " , " pipe_output " ] . each do | cmd |
2017-04-27 20:17:06 +02:00
if text =~ %r{ (def test|test do).*( #{ Regexp . escape ( HOMEBREW_PREFIX ) } /bin/)? #{ cmd } [ \ ( \ s]+['"] #{ Regexp . escape ( name ) } [ \ s'"] }m
2016-10-24 18:57:57 +02:00
problem %Q( fully scope test #{ cmd } calls e.g. #{ cmd } " \# {bin}/ #{ name } " )
2016-11-02 13:23:38 -04:00
end
2016-10-24 15:07:49 +01:00
end
end
2013-07-16 23:15:22 -05:00
end
2017-04-18 08:17:24 +01:00
def audit_lines
text . without_patch . split ( " \n " ) . each_with_index do | line , lineno |
2017-06-01 16:06:51 +02:00
line_problems ( line , lineno + 1 )
2017-04-18 08:17:24 +01:00
end
end
def line_problems ( line , _lineno )
2012-08-07 01:37:46 -05:00
# Check for string interpolation of single values.
2013-07-16 21:25:02 -05:00
if line =~ / (system|inreplace|gsub!|change_make_var!).*[ ,]" # \ {([ \ w.]+) \ }" /
2017-06-10 20:23:20 +03:00
problem " Don't need to interpolate \" #{ Regexp . last_match ( 2 ) } \" with #{ Regexp . last_match ( 1 ) } "
2012-08-07 01:37:46 -05:00
end
2012-01-25 22:41:53 -06:00
2012-08-07 01:37:46 -05:00
# Check for string concatenation; prefer interpolation
2013-07-16 21:25:02 -05:00
if line =~ / ( # \ { \ w+ \ s* \ + \ s*['"][^}]+ \ }) /
2017-06-10 20:23:20 +03:00
problem " Try not to concatenate paths in string interpolation: \n #{ Regexp . last_match ( 1 ) } "
2012-04-05 21:12:02 -05:00
end
2012-01-25 22:41:53 -06:00
2012-08-07 01:37:46 -05:00
# Prefer formula path shortcuts in Pathname+
2014-03-21 20:07:56 -05:00
if line =~ %r{ \ ( \ s*(prefix \ s* \ + \ s*(['"])(bin|include|libexec|lib|sbin|share|Frameworks)[/'"]) }
2017-06-10 20:23:20 +03:00
problem " \" ( #{ Regexp . last_match ( 1 ) } ... #{ Regexp . last_match ( 2 ) } ) \" should be \" ( #{ Regexp . last_match ( 3 ) . downcase } +...) \" "
2012-08-07 01:37:46 -05:00
end
2012-06-18 19:58:35 -05:00
2016-09-25 01:51:37 +02:00
problem " Use separate make calls " if line . include? ( " make && make " )
2012-03-17 19:49:49 -07:00
2015-06-15 09:56:04 +01:00
if line =~ / JAVA_HOME /i && ! formula . requirements . map ( & :class ) . include? ( JavaRequirement )
2015-05-24 16:27:54 +08:00
problem " Use `depends_on :java` to set JAVA_HOME "
end
2016-09-22 20:12:28 +02:00
return unless @strict
2014-12-27 14:01:43 +00:00
2018-02-04 21:54:49 -05:00
if @official_tap && line . include? ( " env :std " )
2018-01-09 15:26:54 +00:00
problem " `env :std` in official tap formulae is deprecated "
end
if line . include? ( " env :userpaths " )
problem " `env :userpaths` in formulae is deprecated "
end
2017-01-03 22:12:21 +00:00
2016-09-22 20:12:28 +02:00
if line =~ / system ((["'])[^"' ]*(?: \ s[^"' ]*)+ \ 2) /
2017-06-10 20:23:20 +03:00
bad_system = Regexp . last_match ( 1 )
2016-09-22 20:12:28 +02:00
unless %w[ | < > & ; * ] . any? { | c | bad_system . include? c }
good_system = bad_system . gsub ( " " , " \" , \" " )
problem " Use `system #{ good_system } ` instead of `system #{ bad_system } ` "
2014-12-27 15:59:16 +00:00
end
2016-09-22 20:12:28 +02:00
end
2016-01-09 16:32:23 +00:00
2017-06-10 20:23:20 +03:00
problem " ` #{ Regexp . last_match ( 1 ) } ` is now unnecessary " if line =~ / (require ["']formula["']) /
2016-01-09 16:32:23 +00:00
2016-09-22 20:12:28 +02:00
if line =~ %r{ # \{ share \} / #{ Regexp . escape ( formula . name ) } [/'"] }
problem " Use \# {pkgshare} instead of \# {share}/ #{ formula . name } "
end
2018-04-07 20:41:25 +01:00
if line =~ / depends_on .+ if build \ .with(out)? \ ? \ (?["'] \ w+["'] \ )? /
problem " `Use :optional` or `:recommended` instead of ` #{ Regexp . last_match ( 0 ) } ` "
end
2016-09-23 22:02:23 +02:00
return unless line =~ %r{ share( \ s*[/+] \ s*)(['"]) #{ Regexp . escape ( formula . name ) } (?: \ 2|/) }
2017-06-10 20:23:20 +03:00
problem " Use pkgshare instead of (share #{ Regexp . last_match ( 1 ) } \" #{ formula . name } \" ) "
2013-07-16 20:38:50 -05:00
end
2015-06-17 04:58:32 +01:00
def audit_reverse_migration
2016-02-26 15:33:27 +08:00
# Only enforce for new formula being re-added to core and official taps
2015-06-17 04:58:32 +01:00
return unless @strict
2018-02-04 21:54:49 -05:00
return unless @official_tap
2016-09-22 20:12:28 +02:00
return unless formula . tap . tap_migrations . key? ( formula . name )
2015-06-17 04:58:32 +01:00
2017-10-15 02:28:32 +02:00
problem << ~ EOS
2016-09-22 20:12:28 +02:00
#{formula.name} seems to be listed in tap_migrations.json!
Please remove #{formula.name} from present tap & tap_migrations.json
before submitting it to Homebrew / homebrew - #{formula.tap.repo}.
EOS
2015-06-17 04:58:32 +01:00
end
2015-02-02 22:53:52 +08:00
def audit_prefix_has_contents
return unless formula . prefix . directory?
2016-09-22 20:12:28 +02:00
return unless Keg . new ( formula . prefix ) . empty_installation?
2015-02-02 22:53:52 +08:00
2017-10-15 02:28:32 +02:00
problem << ~ EOS
2016-09-22 20:12:28 +02:00
The installation seems to be empty . Please ensure the prefix
is set correctly and expected files are installed .
The prefix configure / make argument may be case - sensitive .
EOS
2015-02-02 22:53:52 +08:00
end
2018-02-04 21:54:49 -05:00
def audit_url_is_not_binary
return unless @official_tap
urls = @specs . map ( & :url )
urls . each do | url |
if url =~ / darwin /i && ( url =~ / x86_64 /i || url =~ / amd64 /i )
problem " #{ url } looks like a binary package, not a source archive. Official taps are source-only. "
end
end
end
2013-07-16 20:38:50 -05:00
def quote_dep ( dep )
2016-09-11 17:41:51 +01:00
dep . is_a? ( Symbol ) ? dep . inspect : " ' #{ dep } ' "
2012-08-07 01:37:46 -05:00
end
2010-08-09 11:59:16 -07:00
2017-04-18 08:17:24 +01:00
def problem_if_output ( output )
2014-10-13 23:13:00 -05:00
problem ( output ) if output
2013-07-15 19:29:08 -07:00
end
2012-08-07 01:37:46 -05:00
def audit
2018-02-04 22:09:35 +05:30
only_audits = @only
except_audits = @except
if only_audits && except_audits
2017-05-03 11:33:00 +05:30
odie " --only and --except cannot be used simultaneously! "
2017-04-18 08:17:24 +01:00
end
methods . map ( & :to_s ) . grep ( / ^audit_ / ) . each do | audit_method_name |
name = audit_method_name . gsub ( / ^audit_ / , " " )
2018-02-04 22:09:35 +05:30
if only_audits
2017-04-18 08:17:24 +01:00
next unless only_audits . include? ( name )
2018-02-04 22:09:35 +05:30
elsif except_audits
2017-04-18 08:17:24 +01:00
next if except_audits . include? ( name )
end
send ( audit_method_name )
end
2012-08-07 01:37:46 -05:00
end
2010-11-09 13:00:33 +00:00
2012-08-07 01:37:46 -05:00
private
2011-05-31 13:23:42 -07:00
2015-08-03 13:09:07 +01:00
def problem ( p )
2012-08-07 01:37:46 -05:00
@problems << p
2010-06-23 11:20:47 -07:00
end
2014-11-12 21:30:09 -06:00
def head_only? ( formula )
2015-01-24 23:36:33 +00:00
formula . head && formula . devel . nil? && formula . stable . nil?
end
def devel_only? ( formula )
formula . devel && formula . stable . nil?
2014-11-12 21:30:09 -06:00
end
2010-06-23 11:20:47 -07:00
end
2013-09-18 18:08:50 -05:00
class ResourceAuditor
2017-09-14 19:58:37 +01:00
attr_reader :name , :version , :checksum , :url , :mirrors , :using , :specs , :owner
attr_reader :spec_name , :problems
2013-09-18 18:08:50 -05:00
2017-09-14 19:58:37 +01:00
def initialize ( resource , spec_name , options = { } )
2014-12-22 00:43:02 -05:00
@name = resource . name
2013-09-18 18:08:50 -05:00
@version = resource . version
@checksum = resource . checksum
@url = resource . url
2015-05-07 22:44:01 -04:00
@mirrors = resource . mirrors
2013-09-18 18:08:50 -05:00
@using = resource . using
@specs = resource . specs
2017-09-14 19:58:37 +01:00
@owner = resource . owner
@spec_name = spec_name
@online = options [ :online ]
@strict = options [ :strict ]
@problems = [ ]
2013-09-18 18:08:50 -05:00
end
def audit
audit_version
audit_download_strategy
2015-05-07 22:44:01 -04:00
audit_urls
2013-09-18 18:08:50 -05:00
self
end
def audit_version
2013-11-26 20:35:07 -06:00
if version . nil?
problem " missing version "
elsif version . to_s . empty?
problem " version is set to an empty string "
2015-08-03 13:09:07 +01:00
elsif ! version . detected_from_url?
2013-09-18 18:08:50 -05:00
version_text = version
version_url = Version . detect ( url , specs )
if version_url . to_s == version_text . to_s && version . instance_of? ( Version )
problem " version #{ version_text } is redundant with version scanned from URL "
end
end
2016-07-13 18:28:40 +08:00
if version . to_s . start_with? ( " v " )
2013-09-18 18:08:50 -05:00
problem " version #{ version } should not have a leading 'v' "
end
2015-04-19 14:31:19 +08:00
2016-09-23 22:02:23 +02:00
return unless version . to_s =~ / _ \ d+$ /
problem " version #{ version } should not end with an underline and a number "
2013-09-18 18:08:50 -05:00
end
def audit_download_strategy
2015-08-03 13:09:07 +01:00
if url =~ %r{ ^(cvs|bzr|hg|fossil):// } || url =~ %r{ ^(svn) \ +http:// }
2017-06-10 20:23:20 +03:00
problem " Use of the #{ $& } scheme is deprecated, pass `:using => : #{ Regexp . last_match ( 1 ) } ` instead "
2014-12-18 18:04:22 -05:00
end
2015-03-07 15:02:25 +00:00
url_strategy = DownloadStrategyDetector . detect ( url )
if using == :git || url_strategy == GitDownloadStrategy
if specs [ :tag ] && ! specs [ :revision ]
problem " Git should specify :revision when a :tag is specified. "
end
end
2013-09-18 18:08:50 -05:00
return unless using
2015-07-22 16:41:10 +08:00
if using == :ssl3 || \
2015-08-03 13:09:07 +01:00
( Object . const_defined? ( " CurlSSL3DownloadStrategy " ) && using == CurlSSL3DownloadStrategy )
2014-10-18 17:39:53 -05:00
problem " The SSL3 download strategy is deprecated, please choose a different URL "
2015-07-22 16:41:10 +08:00
elsif ( Object . const_defined? ( " CurlUnsafeDownloadStrategy " ) && using == CurlUnsafeDownloadStrategy ) || \
2015-08-03 13:09:07 +01:00
( Object . const_defined? ( " UnsafeSubversionDownloadStrategy " ) && using == UnsafeSubversionDownloadStrategy )
2014-10-18 17:39:53 -05:00
problem " #{ using . name } is deprecated, please choose a different URL "
end
2014-12-22 00:43:02 -05:00
if using == :cvs
mod = specs [ :module ]
2016-09-25 01:51:37 +02:00
problem " Redundant :module value in URL " if mod == name
2014-12-22 00:43:02 -05:00
2015-08-03 13:09:07 +01:00
if url =~ %r{ :[^/]+$ }
2014-12-22 00:43:02 -05:00
mod = url . split ( " : " ) . last
if mod == name
problem " Redundant CVS module appended to URL "
else
problem " Specify CVS module as `:module => \" #{ mod } \" ` instead of appending it to the URL "
end
end
end
2016-09-23 22:02:23 +02:00
return unless url_strategy == DownloadStrategyDetector . detect ( " " , using )
problem " Redundant :using value in URL "
2013-09-18 18:08:50 -05:00
end
2017-09-16 12:41:08 +01:00
def self . curl_openssl_and_deps
@curl_openssl_and_deps || = begin
formulae_names = [ " curl " , " openssl " ]
2017-09-14 19:58:37 +01:00
formulae_names += formulae_names . flat_map do | f |
Formula [ f ] . recursive_dependencies . map ( & :name )
end
formulae_names . uniq
rescue FormulaUnavailableError
[ ]
end
end
2015-05-07 22:44:01 -04:00
def audit_urls
urls = [ url ] + mirrors
2016-12-23 11:29:31 +00:00
2017-09-16 12:41:08 +01:00
curl_openssl_or_deps = ResourceAuditor . curl_openssl_and_deps . include? ( owner . name )
2017-09-14 19:58:37 +01:00
2017-09-16 12:41:08 +01:00
if spec_name == :stable && curl_openssl_or_deps
problem " should not use xz tarballs " if url . end_with? ( " .xz " )
unless urls . find { | u | u . start_with? ( " http:// " ) }
problem " should always include at least one HTTP mirror "
end
2017-06-07 16:52:05 +01:00
end
2016-12-23 11:29:31 +00:00
return unless @online
urls . each do | url |
2017-02-24 08:45:39 +00:00
next if ! @strict && mirrors . include? ( url )
strategy = DownloadStrategyDetector . detect ( url , using )
2017-01-30 18:30:57 +00:00
if strategy < = CurlDownloadStrategy && ! url . start_with? ( " file " )
2017-03-04 10:06:47 -05:00
# A `brew mirror`'ed URL is usually not yet reachable at the time of
# pull request.
next if url =~ %r{ ^https://dl.bintray.com/homebrew/mirror/ }
2017-12-03 14:02:55 +01:00
if http_content_problem = curl_check_http_content ( url , require_http : curl_openssl_or_deps )
2017-02-23 10:15:06 +00:00
problem http_content_problem
end
2017-01-24 23:11:50 +00:00
elsif strategy < = GitDownloadStrategy
2018-03-14 16:30:45 -05:00
unless Utils . git_remote_exists? url
2017-01-24 23:11:50 +00:00
problem " The URL #{ url } is not a valid git URL "
end
elsif strategy < = SubversionDownloadStrategy
2017-03-05 11:42:59 +01:00
next unless DevelopmentTools . subversion_handles_most_https_certificates?
2017-08-29 16:14:00 +05:30
next unless Utils . svn_available?
2018-03-14 16:55:45 -05:00
unless Utils . svn_remote_exists? url
2016-12-11 21:36:58 +00:00
problem " The URL #{ url } is not a valid svn URL "
2016-12-10 14:20:47 +00:00
end
2016-12-08 21:41:24 +00:00
end
2017-02-02 21:25:29 +00:00
end
end
2015-08-03 13:09:07 +01:00
def problem ( text )
2013-09-18 18:08:50 -05:00
@problems << text
end
end