2017-05-03 11:33:00 +05:30
#: * `audit` [`--strict`] [`--fix`] [`--online`] [`--new-formula`] [`--display-cop-names`] [`--display-filename`] [`--only=`<method>|`--except=`<method>] [`--only-cops=`[COP1,COP2..]|`--except-cops=`[COP1,COP2..]] [<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
2017-01-18 15:55:32 +05:30
#: 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.
#:
2017-04-18 08:17:24 +01:00
#: 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.
#:
2017-05-03 11:33:00 +05:30
#: If `--only-cops` is passed, only the given Rubocop cop(s)' violations would be checked.
2017-04-23 04:09:13 +05:30
#:
2017-05-03 11:33:00 +05:30
#: If `--except-cops` is passed, the given Rubocop cop(s)' checks would be skipped.
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:
# -D activates debugging and profiling of the audit methods (not the same as --debug)
2015-05-24 16:14:44 +01:00
require " formula "
2016-01-14 13:33:56 +08:00
require " formula_versions "
2015-05-24 16:14:44 +01:00
require " utils "
require " extend/ENV "
require " formula_cellar_checks "
2015-05-31 18:40:28 +08:00
require " official_taps "
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 "
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
2016-09-25 01:51:37 +02:00
Homebrew . inject_dump_stats! ( FormulaAuditor , / ^audit_ / ) if ARGV . switch? " D "
2016-04-18 17:39:21 -04:00
2012-08-07 01:37:46 -05:00
formula_count = 0
problem_count = 0
2016-08-02 10:59:39 +01:00
new_formula = ARGV . include? " --new-formula "
strict = new_formula || ARGV . include? ( " --strict " )
online = new_formula || ARGV . include? ( " --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
2017-04-23 04:09:13 +05:30
only_cops = ARGV . value ( " only-cops " ) . to_s . split ( " , " )
except_cops = ARGV . value ( " except-cops " ) . to_s . split ( " , " )
2017-06-30 10:58:24 +05:30
2017-04-23 04:09:13 +05:30
if ! only_cops . empty? && ! except_cops . empty?
2017-05-03 11:33:00 +05:30
odie " --only-cops and --except-cops cannot be used simultaneously! "
2017-06-30 10:58:24 +05:30
elsif ( ! only_cops . empty? || ! except_cops . empty? ) && ( strict || ARGV . value ( " only " ) )
odie " --only-cops/--except-cops and --strict/--only cannot be used simultaneously "
2017-04-23 04:09:13 +05:30
end
2017-05-03 11:33:00 +05:30
options = { fix : ARGV . flag? ( " --fix " ) , realpath : true }
if ! only_cops . empty?
options [ :only_cops ] = only_cops
2017-06-30 10:58:24 +05:30
ARGV . push ( " --only=style " )
2017-07-15 13:34:16 +05:30
elsif 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 ]
2017-05-03 11:33:00 +05:30
elsif ! except_cops . empty?
options [ :except_cops ] = except_cops
elsif ! strict
2017-07-15 13:34:16 +05:30
options [ :except_cops ] = [ :FormulaAuditStrict , :NewFormulaAudit ]
2012-08-07 01:37:46 -05:00
end
2014-12-27 12:38:04 +00:00
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
2012-08-07 01:37:46 -05:00
ff . each do | f |
2016-09-17 15:32:44 +01:00
options = { new_formula : new_formula , strict : strict , online : online }
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 " ) } " }
if ARGV . include? " --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
2016-10-22 13:32:46 +01:00
BUILD_TIME_DEPS = %w[
2012-08-07 01:37:46 -05:00
autoconf
automake
boost - build
bsdmake
cmake
2015-11-16 18:48:01 +08:00
godep
2012-08-07 01:37:46 -05:00
imake
2013-02-03 14:41:00 -06:00
intltool
2012-08-07 01:37:46 -05:00
libtool
pkg - config
scons
smake
2015-11-16 18:48:01 +08:00
sphinx - doc
2012-09-05 21:12:08 -07:00
swig
2016-09-11 17:41:51 +01:00
] . freeze
2012-08-07 01:37:46 -05:00
2016-07-13 15:58:04 +08:00
FILEUTILS_METHODS = FileUtils . singleton_methods ( false ) . map { | m | Regexp . escape ( m ) } . join " | "
2014-12-27 14:00:51 +00: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 ]
2016-04-18 17:39:21 -04:00
# Accept precomputed style offense results, for efficiency
@style_offenses = options [ :style_offenses ]
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
2017-06-07 16:52:05 +01:00
def self . check_http_content ( url , name , user_agents : [ :default ] )
2017-02-24 08:51:15 +00:00
return unless url . start_with? " http "
2017-02-23 10:15:06 +00:00
details = nil
user_agent = nil
2017-06-07 16:52:05 +01:00
hash_needed = url . start_with? ( " http: " ) && name != " curl "
2017-02-23 10:15:06 +00:00
user_agents . each do | ua |
2017-03-13 18:11:33 -04:00
details = http_content_headers_and_checksum ( url , hash_needed : hash_needed , user_agent : ua )
2017-02-23 10:15:06 +00:00
user_agent = ua
break if details [ :status ] . to_s . start_with? ( " 2 " )
end
2016-12-30 20:17:34 +00:00
2017-02-23 10:15:06 +00:00
return " The URL #{ url } is not reachable " unless details [ :status ]
unless details [ :status ] . start_with? " 2 "
return " The URL #{ url } is not reachable (HTTP status code #{ details [ :status ] } ) "
end
2017-03-13 18:11:33 -04:00
return unless hash_needed
2017-02-23 10:15:06 +00:00
secure_url = url . sub " http " , " https "
secure_details =
2017-03-13 18:11:33 -04:00
http_content_headers_and_checksum ( secure_url , hash_needed : true , user_agent : user_agent )
2017-02-23 10:15:06 +00:00
if ! details [ :status ] . to_s . start_with? ( " 2 " ) ||
! secure_details [ :status ] . to_s . start_with? ( " 2 " )
return
end
etag_match = details [ :etag ] &&
details [ :etag ] == secure_details [ :etag ]
content_length_match =
details [ :content_length ] &&
details [ :content_length ] == secure_details [ :content_length ]
file_match = details [ :file_hash ] == secure_details [ :file_hash ]
return if ! etag_match && ! content_length_match && ! file_match
" The URL #{ url } could use HTTPS rather than HTTP "
end
2017-03-13 18:11:33 -04:00
def self . http_content_headers_and_checksum ( url , hash_needed : false , user_agent : :default )
max_time = hash_needed ? " 600 " : " 25 "
2017-02-23 10:15:06 +00:00
args = curl_args (
2017-03-13 18:11:33 -04:00
extra_args : [ " --connect-timeout " , " 15 " , " --include " , " --max-time " , max_time , url ] ,
2017-02-23 10:15:06 +00:00
show_output : true ,
user_agent : user_agent ,
)
output = Open3 . popen3 ( * args ) { | _ , stdout , _ , _ | stdout . read }
status_code = :unknown
while status_code == :unknown || status_code . to_s . start_with? ( " 3 " )
headers , _ , output = output . partition ( " \r \n \r \n " )
status_code = headers [ %r{ HTTP \ /.* ( \ d+) } , 1 ]
end
2017-03-13 18:11:33 -04:00
output_hash = Digest :: SHA256 . digest ( output ) if hash_needed
2017-02-23 10:15:06 +00:00
{
status : status_code ,
etag : headers [ %r{ ETag: ([wW] \ /)?"(([^"]| \\ ")*)" } , 2 ] ,
content_length : headers [ / Content-Length: ( \ d+) / , 1 ] ,
2017-03-13 18:11:33 -04:00
file_hash : output_hash ,
2017-02-23 10:15:06 +00:00
}
2016-12-30 20:17:34 +00:00
end
2016-04-18 17:39:21 -04:00
def audit_style
return unless @style_offenses
display_cop_names = ARGV . include? ( " --display-cop-names " )
@style_offenses . each do | offense |
2016-09-17 15:32:44 +01:00
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-05-21 01:48:58 -04:00
if formula . tap && ! formula . tap . core_tap?
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
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
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-03-26 20:36:37 +01:00
problem <<-EOS.undent
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
2014-12-27 20:46:01 +00:00
def audit_class
2014-12-27 15:58:29 +00:00
if @strict
2014-12-27 20:46:01 +00:00
unless formula . test_defined?
2014-12-27 15:58:29 +00:00
problem " A `test do` test block should be added "
end
end
2015-01-22 20:34:51 -05:00
2016-01-21 00:12:16 +01:00
classes = %w[ GithubGistFormula ScriptFileFormula AmazonWebServicesFormula ]
klass = classes . find do | c |
Object . const_defined? ( c ) && formula . class < Object . const_get ( c )
2015-01-22 20:34:51 -05:00
end
2015-03-03 19:33:47 +08:00
2016-01-21 00:12:16 +01:00
problem " #{ klass } is deprecated, use Formula instead " if klass
2010-08-08 10:17:53 -07:00
end
2015-09-13 17:33:35 +08:00
# core aliases + tap alias names + tap alias full name
@@aliases || = Formula . aliases + Formula . tap_aliases
2010-09-08 09:22:48 -07:00
2015-05-31 18:40:28 +08:00
def audit_formula_name
return unless @strict
# skip for non-official taps
2015-12-15 15:33:27 +01:00
return if formula . tap . nil? || ! formula . tap . official?
2015-05-31 18:40:28 +08:00
name = formula . name
full_name = formula . full_name
2017-03-18 17:02:08 +02:00
if Homebrew :: 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
2015-05-31 18:40:28 +08:00
if ! formula . core_formula? && Formula . core_names . include? ( name )
2015-06-07 11:49:41 -07:00
problem " Formula name conflicts with existing core formula. "
2015-05-31 18:40:28 +08:00
return
end
2016-09-11 17:41:51 +01:00
@@local_official_taps_name_map || = Tap . select ( & :official? ) . flat_map ( & :formula_names )
. each_with_object ( { } ) do | tap_formula_full_name , name_map |
tap_formula_name = tap_formula_full_name . split ( " / " ) . last
name_map [ tap_formula_name ] || = [ ]
name_map [ tap_formula_name ] << tap_formula_full_name
name_map
end
2015-09-07 18:54:44 +08:00
same_name_tap_formulae = @@local_official_taps_name_map [ name ] || [ ]
2015-07-09 22:06:53 +08:00
if @online
2017-04-25 12:08:50 +01:00
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
2015-07-09 22:06:53 +08:00
end
2015-05-31 18:40:28 +08:00
same_name_tap_formulae . delete ( full_name )
2016-09-23 22:02:23 +02:00
return if same_name_tap_formulae . empty?
problem " Formula name conflicts with #{ same_name_tap_formulae . join " , " } "
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-02-23 09:14:54 +00:00
if @@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
2014-10-17 00:07:35 -05:00
dep . options . reject do | opt |
next true if dep_f . option_defined? ( opt )
dep_f . requirements . detect do | r |
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
2014-10-17 00:07:35 -05:00
end . each do | opt |
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
2014-10-17 00:07:35 -05:00
case dep . name
2015-02-19 18:27:50 +08:00
when " git "
2015-03-15 20:12:43 +08:00
problem " Don't use git as a dependency "
2015-02-19 18:27:50 +08:00
when " mercurial "
problem " Use `depends_on :hg` instead of `depends_on 'mercurial'` "
2015-05-24 16:14:44 +01:00
when " gfortran "
2014-10-17 00:07:35 -05:00
problem " Use `depends_on :fortran` instead of `depends_on 'gfortran'` "
2016-07-12 02:54:15 +01:00
when " ruby "
problem <<-EOS.undent
Don ' t use " ruby " as a dependency . If this formula requires a
minimum Ruby version not provided by the system you should
use the RubyRequirement :
depends_on :ruby = > " 1.8 "
where " 1.8 " is the minimum version of Ruby required .
EOS
2016-10-14 23:05:34 +02:00
when " open-mpi " , " mpich "
2014-10-17 00:07:35 -05:00
problem <<-EOS.undent
2015-06-15 09:56:04 +01:00
There are multiple conflicting ways to install MPI . Use an MPIRequirement :
2014-10-17 00:07:35 -05:00
depends_on :mpi = > [ < lang list > ]
Where < lang list > is a comma delimited list that can include :
:cc , :cxx , :f77 , :f90
EOS
2016-10-15 18:31:06 +02:00
when * BUILD_TIME_DEPS
next if dep . build? || dep . run?
2016-11-02 16:49:37 -07:00
problem <<-EOS.undent
#{dep} dependency should be
depends_on " #{ dep } " = > :build
Or if it is indeed a runtime dependency
depends_on " #{ dep } " = > :run
EOS
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-04-28 04:53:52 +01:00
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
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-02-23 10:15:06 +00:00
return unless DevelopmentTools . curl_handles_most_https_homepages?
if http_content_problem = FormulaAuditor . check_http_content ( homepage ,
2017-06-07 16:52:05 +01:00
formula . name ,
user_agents : [ :browser , :default ] )
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 " ]
2016-02-11 20:31:48 +00:00
if ( metadata [ " forks_count " ] < 20 ) && ( metadata [ " subscribers_count " ] < 20 ) &&
( 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 |
2014-10-29 22:38:49 -05:00
next unless spec = formula . send ( name . downcase )
2013-09-18 18:50:23 -05:00
2017-02-23 10:15:06 +00:00
ra = ResourceAuditor . new ( spec , 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-02-23 10:15:06 +00:00
ra = ResourceAuditor . new ( resource , 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?
2017-04-18 08:17:24 +01:00
spec . patches . each { | p | patch_problems ( p ) if p . external? }
2017-04-21 13:15:27 +01:00
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
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
] . 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
2015-05-14 00:01:00 -04:00
case stable && 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
2017-04-18 08:17:24 +01:00
def patch_problems ( patch )
2014-03-13 19:51:23 -05:00
case patch . url
2017-06-28 20:49:37 -07:00
when %r{ https?://github \ .com/.+/.+/(?:commit|pull)/[a-fA-F0-9]*.(?:patch|diff) }
unless patch . url =~ / \ ?full_index= \ w+$ /
problem <<-EOS.undent
GitHub patches should use the full_index parameter :
#{patch.url}?full_index=1
EOS
end
2015-08-03 13:09:07 +01:00
when / raw \ .github \ .com / , %r{ gist \ .github \ .com/raw } , %r{ gist \ .github \ .com/.+/raw } ,
%r{ gist \ .githubusercontent \ .com/.+/raw }
2014-03-13 19:51:23 -05:00
unless patch . url =~ / [a-fA-F0-9]{40} /
problem " GitHub/Gist patches should specify a revision: \n #{ patch . url } "
2012-08-07 01:37:46 -05:00
end
2016-05-19 07:56:11 +01:00
when %r{ https?://patch-diff \ .githubusercontent \ .com/raw/(.+)/(.+)/pull/(.+) \ .(?:diff|patch) }
problem <<-EOS.undent
use GitHub pull request URLs :
2017-06-28 20:49:37 -07:00
https : / / github . com / #{Regexp.last_match(1)}/#{Regexp.last_match(2)}/pull/#{Regexp.last_match(3)}.patch?full_index=1
2016-05-19 07:56:11 +01:00
Rather than patch - diff :
#{patch.url}
EOS
2015-08-03 13:09:07 +01:00
when %r{ macports/trunk }
2014-03-13 19:51:23 -05:00
problem " MacPorts patches should specify a revision instead of trunk: \n #{ patch . url } "
2015-08-03 13:09:07 +01:00
when %r{ ^http://trac \ .macports \ .org }
2015-01-04 23:43:15 +00:00
problem " Patches from MacPorts Trac should be https://, not http: \n #{ patch . url } "
2015-08-03 13:09:07 +01:00
when %r{ ^http://bugs \ .debian \ .org }
2015-01-04 23:43:15 +00:00
problem " Patches from Debian should be https://, not http: \n #{ patch . url } "
2010-09-09 14:16:05 -07:00
end
2012-08-07 01:37:46 -05:00
end
2010-09-09 14:16:05 -07:00
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 )
2013-07-16 21:25:02 -05:00
if line =~ / <(Formula|AmazonWebServicesFormula|ScriptFileFormula|GithubGistFormula) /
2017-06-10 20:23:20 +03:00
problem " Use a space in class inheritance: class Foo < #{ Regexp . last_match ( 1 ) } "
2010-09-09 14:16:05 -07:00
end
2012-08-07 01:37:46 -05:00
# Commented-out cmake support from default template
2016-09-25 01:51:37 +02:00
problem " Commented cmake call found " if line . include? ( '# system "cmake' )
2010-09-09 14:16:05 -07:00
2013-07-03 09:20:41 -07:00
# Comments from default template
2015-10-23 10:33:34 +02:00
[
" # PLEASE REMOVE " ,
" # Documentation: " ,
" # if this fails, try separate make/make install steps " ,
" # The URL of the archive " ,
" # # Naming -- " ,
" # if your formula requires any X11/XQuartz components " ,
" # if your formula fails when building in parallel " ,
" # Remove unrecognized options if warned by configure " ,
] . each do | comment |
2016-09-25 01:51:37 +02:00
next unless line . include? ( comment )
problem " Please remove default template comments "
2013-07-03 09:20:41 -07:00
end
2012-08-07 01:37:46 -05:00
# FileUtils is included in Formula
2013-12-04 20:07:27 -08:00
# encfs modifies a file with this name, so check for some leading characters
2016-09-11 17:41:51 +01:00
if line =~ %r{ [^'"/]FileUtils \ .( \ w+) }
2017-06-10 20:23:20 +03:00
problem " Don't need 'FileUtils.' before #{ Regexp . last_match ( 1 ) } . "
2012-08-07 01:37:46 -05:00
end
2010-09-09 14:16:05 -07:00
2012-08-07 01:37:46 -05:00
# Check for long inreplace block vars
2013-07-16 21:25:02 -05:00
if line =~ / inreplace .* do \ |(.{2,}) \ | /
2017-06-10 20:23:20 +03:00
problem " \" inreplace <filenames> do |s| \" is preferred over \" | #{ 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 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
2015-08-03 13:09:07 +01:00
if line =~ / ((man) \ s* \ + \ s*(['"])(man[1-8])(['"])) /
2017-06-10 20:23:20 +03:00
problem " \" #{ Regexp . last_match ( 1 ) } \" should be \" #{ Regexp . last_match ( 4 ) } \" "
2012-08-07 01:37:46 -05:00
end
2012-04-05 21:12:02 -05:00
2012-08-07 01:37:46 -05:00
# Prefer formula path shortcuts in strings
2014-03-21 20:07:56 -05:00
if line =~ %r[ ( \ # \ {prefix \ }/(bin|include|libexec|lib|sbin|share|Frameworks)) ]
2017-06-10 20:23:20 +03:00
problem " \" #{ Regexp . last_match ( 1 ) } \" should be \" \# { #{ Regexp . last_match ( 2 ) . downcase } } \" "
2012-04-05 21:12:02 -05:00
end
2012-01-25 22:41:53 -06:00
2013-07-16 21:25:02 -05:00
if line =~ %r[ (( \ # \ {prefix \ }/share/man/| \ # \ {man \ }/)(man [ 1-8 ] )) ]
2017-06-10 20:23:20 +03:00
problem " \" #{ Regexp . last_match ( 1 ) } \" should be \" \# { #{ Regexp . last_match ( 3 ) } } \" "
2012-08-07 01:37:46 -05:00
end
2012-01-25 22:41:53 -06:00
2013-07-16 21:25:02 -05:00
if line =~ %r[ (( \ # \ {share \ }/(man))) [ /'" ] ]
2017-06-10 20:23:20 +03:00
problem " \" #{ Regexp . last_match ( 1 ) } \" should be \" \# { #{ Regexp . last_match ( 3 ) } } \" "
2012-08-07 01:37:46 -05:00
end
2010-08-21 11:55:57 -07:00
2013-07-16 21:25:02 -05:00
if line =~ %r[ ( \ # \ {prefix \ }/share/(info|man)) ]
2017-06-10 20:23:20 +03:00
problem " \" #{ Regexp . last_match ( 1 ) } \" should be \" \# { #{ Regexp . last_match ( 2 ) } } \" "
2012-08-07 01:37:46 -05:00
end
2010-08-21 11:55:57 -07:00
2015-08-03 13:09:07 +01:00
if line =~ / depends_on :(automake|autoconf|libtool) /
2017-06-10 20:23:20 +03:00
problem " : #{ Regexp . last_match ( 1 ) } is deprecated. Usage should be \" #{ Regexp . last_match ( 1 ) } \" "
2015-05-03 18:52:46 +01:00
end
2016-10-12 15:37:33 +01:00
if line =~ / depends_on :apr /
problem " :apr is deprecated. Usage should be \" apr-util \" "
end
2017-05-29 18:24:52 +01:00
problem " :tex is deprecated " if line =~ / depends_on :tex /
2017-03-19 20:46:31 +02:00
2017-04-21 13:06:29 +01:00
if line =~ / depends_on \ s+['"](.+)['"] \ s+=> \ s+:(lua|perl|python|ruby)( \ d*) /
2017-06-10 20:23:20 +03:00
problem " #{ Regexp . last_match ( 2 ) } modules should be vendored rather than use deprecated `depends_on \" #{ Regexp . last_match ( 1 ) } \" => : #{ Regexp . last_match ( 2 ) } #{ Regexp . last_match ( 3 ) } ` "
2017-04-21 13:06:29 +01:00
end
2017-05-13 13:00:00 +01:00
if line =~ / depends_on \ s+['"](.+)['"] \ s+=> \ s+(.*) /
2017-06-10 20:23:20 +03:00
dep = Regexp . last_match ( 1 )
Regexp . last_match ( 2 ) . split ( " " ) . map do | o |
2017-06-02 22:26:37 +01:00
break if [ " if " , " unless " ] . include? ( o )
2017-05-13 13:00:00 +01:00
next unless o =~ / ^ \ [?['"](.*)['"] /
2017-06-10 20:23:20 +03:00
problem " Dependency #{ dep } should not use option #{ Regexp . last_match ( 1 ) } "
2017-05-13 13:00:00 +01:00
end
2017-04-10 22:42:57 +01:00
end
2012-08-07 01:37:46 -05:00
# Commented-out depends_on
2017-06-10 20:23:20 +03:00
problem " Commented-out dep #{ Regexp . last_match ( 1 ) } " if line =~ / # \ s*depends_on \ s+(.+) \ s*$ /
2010-09-07 09:23:29 -07:00
2013-07-16 21:25:02 -05:00
if line =~ / if \ s+ARGV \ .include \ ? \ s+'--(HEAD|devel)' /
2017-06-10 20:23:20 +03:00
problem " Use \" if build. #{ Regexp . last_match ( 1 ) . downcase } ? \" instead "
2012-08-07 01:37:46 -05:00
end
2012-03-17 19:49:49 -07: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
2016-09-25 01:51:37 +02:00
problem " Use spaces instead of tabs for indentation " if line =~ / ^[ ]* \ t /
2011-05-31 13:23:42 -07:00
2016-07-13 18:28:40 +08:00
if line . include? ( " ENV.x11 " )
2012-09-03 19:18:58 -07:00
problem " Use \" depends_on :x11 \" instead of \" ENV.x11 \" "
end
2012-08-07 01:37:46 -05:00
# Avoid hard-coding compilers
2014-03-06 21:15:05 +00:00
if line =~ %r{ (system|ENV \ [.+ \ ] \ s?=) \ s?['"](/usr/bin/)?(gcc|llvm-gcc|clang)['" ] }
2017-06-10 20:23:20 +03:00
problem " Use \" \# {ENV.cc} \" instead of hard-coding \" #{ Regexp . last_match ( 3 ) } \" "
2012-08-07 01:37:46 -05:00
end
2010-08-10 11:52:03 -07:00
2013-07-16 21:25:02 -05:00
if line =~ %r{ (system|ENV \ [.+ \ ] \ s?=) \ s?['"](/usr/bin/)?((g|llvm-g|clang) \ + \ +)['" ] }
2017-06-10 20:23:20 +03:00
problem " Use \" \# {ENV.cxx} \" instead of hard-coding \" #{ Regexp . last_match ( 3 ) } \" "
2012-08-07 01:37:46 -05:00
end
2011-02-20 15:03:15 -08:00
2014-03-05 07:53:53 -08:00
if line =~ / system \ s+['"](env|export)( \ s+|['"]) /
2017-06-10 20:23:20 +03:00
problem " Use ENV instead of invoking ' #{ Regexp . last_match ( 1 ) } ' to modify the environment "
2012-08-07 01:37:46 -05:00
end
2012-01-22 22:32:15 -06:00
2017-04-10 22:36:39 +01:00
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
2013-07-16 21:25:02 -05:00
if line =~ / version == ['"]HEAD['"] /
2012-08-22 20:59:43 -07:00
problem " Use 'build.head?' instead of inspecting 'version' "
end
2014-03-06 20:40:15 +00:00
if line =~ / build \ .include \ ?[ \ s \ (]+['"] \ - \ -(.*)['"] /
2017-06-10 20:23:20 +03:00
problem " Reference ' #{ Regexp . last_match ( 1 ) } ' without dashes "
2012-08-25 09:36:01 -07:00
end
2014-03-06 20:40:15 +00:00
if line =~ / build \ .include \ ?[ \ s \ (]+['"]with(out)?-(.*)['"] /
2017-06-10 20:23:20 +03:00
problem " Use build.with #{ Regexp . last_match ( 1 ) } ? \" #{ Regexp . last_match ( 2 ) } \" instead of build.include? 'with #{ Regexp . last_match ( 1 ) } - #{ Regexp . last_match ( 2 ) } ' "
2013-01-21 10:33:56 +01:00
end
2014-03-06 20:40:15 +00:00
if line =~ / build \ .with \ ?[ \ s \ (]+['"]-?-?with-(.*)['"] /
2017-06-10 20:23:20 +03:00
problem " Don't duplicate 'with': Use `build.with? \" #{ Regexp . last_match ( 1 ) } \" ` to check for \" --with- #{ Regexp . last_match ( 1 ) } \" "
2014-03-06 20:40:15 +00:00
end
if line =~ / build \ .without \ ?[ \ s \ (]+['"]-?-?without-(.*)['"] /
2017-06-10 20:23:20 +03:00
problem " Don't duplicate 'without': Use `build.without? \" #{ Regexp . last_match ( 1 ) } \" ` to check for \" --without- #{ Regexp . last_match ( 1 ) } \" "
2014-03-06 20:40:15 +00:00
end
2014-03-21 06:08:18 -04:00
if line =~ / unless build \ .with \ ?(.*) /
2017-06-10 20:23:20 +03:00
problem " Use if build.without? #{ Regexp . last_match ( 1 ) } instead of unless build.with? #{ Regexp . last_match ( 1 ) } "
2014-03-21 06:08:18 -04:00
end
if line =~ / unless build \ .without \ ?(.*) /
2017-06-10 20:23:20 +03:00
problem " Use if build.with? #{ Regexp . last_match ( 1 ) } instead of unless build.without? #{ Regexp . last_match ( 1 ) } "
2014-03-06 20:40:15 +00:00
end
if line =~ / (not \ s|!) \ s*build \ .with? \ ? /
2017-04-19 10:59:11 -07:00
problem " Don't negate 'build.with?': use 'build.without?' "
2014-03-06 20:40:15 +00:00
end
if line =~ / (not \ s|!) \ s*build \ .without? \ ? /
2017-04-19 10:59:11 -07:00
problem " Don't negate 'build.without?': use 'build.with?' "
2013-01-21 10:33:56 +01:00
end
2014-03-06 21:15:05 +00:00
if line =~ / ARGV \ .(?!(debug \ ?|verbose \ ?|value[ \ ( \ s])) /
2014-10-13 23:13:00 -05:00
problem " Use build instead of ARGV to check options "
2012-08-22 20:59:43 -07:00
end
2016-09-25 01:51:37 +02:00
problem " Use new-style option definitions " if line . include? ( " def options " )
2012-09-04 18:18:14 -05:00
2016-07-13 18:28:40 +08:00
if line . end_with? ( " def test " )
2014-07-27 12:27:53 -07:00
problem " Use new-style test definitions (test do) "
end
2016-07-13 18:28:40 +08:00
if line . include? ( " MACOS_VERSION " )
2012-09-04 18:18:14 -05:00
problem " Use MacOS.version instead of MACOS_VERSION "
end
2012-09-10 16:40:13 -05:00
2016-07-13 18:28:40 +08:00
if line . include? ( " MACOS_FULL_VERSION " )
2016-04-03 23:19:38 +08:00
problem " Use MacOS.full_version instead of MACOS_FULL_VERSION "
end
2015-10-16 16:41:14 +08:00
2015-08-03 13:09:07 +01:00
cats = %w[ leopard snow_leopard lion mountain_lion ] . join ( " | " )
2013-07-16 21:25:02 -05:00
if line =~ / MacOS \ .(?: #{ cats } ) \ ? /
2013-04-06 22:11:26 -05:00
problem " \" #{ $& } \" is deprecated, use a comparison to MacOS.version instead "
2012-09-10 16:40:13 -05:00
end
2012-09-13 07:14:45 -07:00
2013-07-16 21:25:02 -05:00
if line =~ / skip_clean \ s+:all /
2015-08-03 13:09:07 +01:00
problem " `skip_clean :all` is deprecated; brew no longer strips symbols \n " \
2014-02-23 12:09:28 -08:00
" \t Pass explicit paths to prevent Homebrew from removing empty folders. "
2012-09-13 07:14:45 -07:00
end
2013-01-27 14:27:32 -08:00
2013-07-16 21:25:02 -05:00
if line =~ / depends_on [A-Z][ \ w:]+ \ .new$ /
2013-04-06 22:11:26 -05:00
problem " `depends_on` can take requirement classes instead of instances "
2013-01-27 14:27:32 -08:00
end
2013-04-22 15:06:42 -05:00
2013-07-16 21:25:02 -05:00
if line =~ / ^def ( \ w+).*$ /
2017-06-10 20:23:20 +03:00
problem " Define method #{ Regexp . last_match ( 1 ) . inspect } in the class body, not at the top-level "
2013-04-22 15:06:42 -05:00
end
2013-06-23 20:40:00 -07:00
2016-07-13 18:28:40 +08:00
if line . include? ( " ENV.fortran " ) && ! formula . requirements . map ( & :class ) . include? ( FortranRequirement )
2013-06-23 20:40:00 -07:00
problem " Use `depends_on :fortran` instead of `ENV.fortran` "
end
2013-07-16 20:38:50 -05: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
2013-07-16 21:25:02 -05:00
if line =~ / depends_on :(.+) (if.+|unless.+)$ /
2017-06-10 20:23:20 +03:00
conditional_dep_problems ( Regexp . last_match ( 1 ) . to_sym , Regexp . last_match ( 2 ) , $& )
2013-07-16 20:38:50 -05:00
end
2013-07-16 21:25:02 -05:00
if line =~ / depends_on ['"](.+)['"] (if.+|unless.+)$ /
2017-06-10 20:23:20 +03:00
conditional_dep_problems ( Regexp . last_match ( 1 ) , Regexp . last_match ( 2 ) , $& )
2013-07-16 20:38:50 -05:00
end
2014-03-29 09:16:27 -05:00
if line =~ / (Dir \ [("[^ \ *{},]+") \ ]) /
2017-06-10 20:23:20 +03:00
problem " #{ Regexp . last_match ( 1 ) } is unnecessary; just use #{ Regexp . last_match ( 2 ) } "
2014-03-29 09:16:27 -05:00
end
2014-12-27 14:00:51 +00:00
2014-12-27 20:35:26 +00:00
if line =~ / system (["']( #{ FILEUTILS_METHODS } )["' ]) /o
2017-06-10 20:23:20 +03:00
system = Regexp . last_match ( 1 )
method = Regexp . last_match ( 2 )
2014-12-27 14:00:51 +00:00
problem " Use the ` #{ method } ` Ruby method instead of `system #{ system } ` "
end
2014-12-27 14:01:31 +00:00
2015-08-09 09:32:40 +01:00
if line =~ / assert [^!]+ \ .include? /
2015-07-12 18:08:14 +01:00
problem " Use `assert_match` instead of `assert ...include?` "
end
2017-03-26 12:54:25 -04:00
if line . include? ( 'system "npm", "install"' ) && ! line . include? ( " Language::Node " ) &&
2017-03-26 14:29:38 -04:00
formula . name !~ / ^kibana( \ @ \ d+( \ . \ d+)?)?$ /
2016-04-27 18:08:44 +02:00
problem " Use Language::Node for npm install args "
end
2016-12-13 02:10:11 +00:00
if line . include? ( " fails_with :llvm " )
problem " 'fails_with :llvm' is now a no-op so should be removed "
end
2017-03-29 09:49:48 -04:00
if line =~ / system \ s+['"](otool|install_name_tool|lipo) / && formula . name != " cctools "
2017-06-10 20:23:20 +03:00
problem " Use ruby-macho instead of calling #{ Regexp . last_match ( 1 ) } "
2017-01-11 23:07:26 -05:00
end
2016-12-13 02:32:38 +00:00
if formula . tap . to_s == " homebrew/core "
[ " OS.mac? " , " OS.linux? " ] . each do | check |
next unless line . include? ( check )
problem " Don't use #{ check } ; Homebrew/core only supports macOS "
end
end
2017-04-23 18:56:22 +01:00
if line =~ / ((revision|version_scheme) \ s+0) /
2017-06-10 20:23:20 +03:00
problem " ' #{ Regexp . last_match ( 1 ) } ' should be removed "
2017-04-23 18:56:22 +01:00
end
2016-09-22 20:12:28 +02:00
return unless @strict
2014-12-27 14:01:43 +00:00
2017-06-10 20:23:20 +03:00
problem " ` #{ Regexp . last_match ( 1 ) } ` in formulae is deprecated " if line =~ / (env :(std|userpaths)) /
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
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
2016-02-26 15:33:27 +08:00
return unless formula . tap && formula . tap . official?
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
2016-09-22 20:12:28 +02:00
problem <<-EOS.undent
#{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
2016-09-22 20:12:28 +02:00
problem <<-EOS.undent
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
2017-04-18 08:17:24 +01:00
def conditional_dep_problems ( dep , condition , line )
2013-07-23 11:21:37 -05:00
quoted_dep = quote_dep ( dep )
dep = Regexp . escape ( dep . to_s )
2013-07-16 20:38:50 -05:00
case condition
when / if build \ .include \ ? ['"]with- #{ dep } ['"]$ / , / if build \ .with \ ? ['"] #{ dep } ['"]$ /
2016-10-24 17:27:20 +02:00
problem %Q( Replace #{ line . inspect } with "depends_on #{ quoted_dep } => :optional" )
2013-07-16 20:38:50 -05:00
when / unless build \ .include \ ? ['"]without- #{ dep } ['"]$ / , / unless build \ .without \ ? ['"] #{ dep } ['"]$ /
2016-10-24 17:27:20 +02:00
problem %Q( Replace #{ line . inspect } with "depends_on #{ quoted_dep } => :recommended" )
2013-07-16 20:38:50 -05:00
end
end
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
2017-04-18 08:17:24 +01:00
only_audits = ARGV . value ( " only " ) . to_s . split ( " , " )
except_audits = ARGV . value ( " except " ) . to_s . split ( " , " )
if ! only_audits . empty? && ! except_audits . empty?
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_ / , " " )
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
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
attr_reader :problems
2015-05-07 22:44:01 -04:00
attr_reader :version , :checksum , :using , :specs , :url , :mirrors , :name
2013-09-18 18:08:50 -05:00
2016-12-23 11:29:31 +00:00
def initialize ( resource , 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
2016-12-23 11:29:31 +00:00
@online = options [ :online ]
2017-02-23 10:15:06 +00:00
@strict = options [ :strict ]
2013-09-18 18:08:50 -05:00
@problems = [ ]
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
2015-05-07 22:44:01 -04:00
def audit_urls
urls = [ url ] + mirrors
2016-12-23 11:29:31 +00:00
2017-06-07 16:52:05 +01:00
if name == " curl " && ! urls . find { | u | u . start_with? ( " http:// " ) }
problem " should always include at least one HTTP url "
end
2017-06-02 22:28:03 +01:00
# Check pypi urls
if @strict
urls . each do | p |
next unless p =~ %r{ ^https?://pypi.python.org/(.*) }
2017-06-10 20:23:20 +03:00
problem " #{ p } should be `https://files.pythonhosted.org/ #{ Regexp . last_match ( 1 ) } ` "
2017-06-02 22:28:03 +01:00
end
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-06-07 16:52:05 +01:00
if http_content_problem = FormulaAuditor . check_http_content ( url , name )
2017-02-23 10:15:06 +00:00
problem http_content_problem
end
2017-01-24 23:11:50 +00:00
elsif strategy < = GitDownloadStrategy
unless Utils . git_remote_exists url
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?
2016-12-10 14:20:47 +00: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