| 
									
										
										
										
											2016-08-02 10:59:39 +01:00
										 |  |  | #:  * `audit` [`--strict`] [`--online`] [`--new-formula`] [`--display-cop-names`] [`--display-filename`] [<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
										 |  |  | #: | 
					
						
							|  |  |  | #:    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 | 
					
						
							|  |  |  | #:    if a new formula is eligable for Homebrew. This should be used when creating | 
					
						
							|  |  |  | #:    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. | 
					
						
							|  |  |  | #: | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 22:41:47 -05:00
										 |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit | 
					
						
							| 
									
										
										
										
											2016-04-18 17:39:21 -04:00
										 |  |  |     if ARGV.switch? "D" | 
					
						
							|  |  |  |       Homebrew.inject_dump_stats!(FormulaAuditor, /^audit_/) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  |     if strict | 
					
						
							| 
									
										
										
										
											2016-04-18 17:39:21 -04:00
										 |  |  |       # Check style in a single batch run up front for performance | 
					
						
							|  |  |  |       style_results = check_style_json(files, :realpath => true) | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-12-27 12:38:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     ff.each do |f| | 
					
						
							| 
									
										
										
										
											2016-08-02 10:59:39 +01:00
										 |  |  |       options = { :new_formula => new_formula, :strict => strict, :online => online } | 
					
						
							| 
									
										
										
										
											2016-08-16 17:00:31 +01:00
										 |  |  |       options[:style_offenses] = style_results.file_offenses(f.path) if strict | 
					
						
							| 
									
										
										
										
											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? | 
					
						
							| 
									
										
										
										
											2015-01-04 10:48:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unless problem_count.zero? | 
					
						
							| 
									
										
										
										
											2015-06-05 02:34:28 +02:00
										 |  |  |       problems = "problem" + plural(problem_count) | 
					
						
							|  |  |  |       formulae = "formula" + plural(formula_count, "e") | 
					
						
							|  |  |  |       ofail "#{problem_count} #{problems} in #{formula_count} #{formulae}" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							|  |  |  |   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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def has_DATA? | 
					
						
							| 
									
										
										
										
											2014-09-23 15:47:34 -04:00
										 |  |  |     /^[^#]*\bDATA\b/ =~ @text | 
					
						
							| 
									
										
										
										
											2010-08-15 15:19:19 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def has_END? | 
					
						
							|  |  |  |     /^__END__$/ =~ @text | 
					
						
							| 
									
										
										
										
											2010-09-08 09:07:59 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def has_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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |   def =~(regex) | 
					
						
							| 
									
										
										
										
											2015-02-24 15:54:31 +08:00
										 |  |  |     regex =~ @text | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-06-08 18:57:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |   def include?(s) | 
					
						
							|  |  |  |     @text.include? s | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |   def line_number(regex) | 
					
						
							| 
									
										
										
										
											2015-06-08 18:57:17 +08:00
										 |  |  |     index = @lines.index { |line| line =~ regex } | 
					
						
							|  |  |  |     index ? index + 1 : 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
										 |  |  | 
 | 
					
						
							|  |  |  |   BUILD_TIME_DEPS = %W[
 | 
					
						
							|  |  |  |     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 | 
					
						
							| 
									
										
										
										
											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-08-02 10:59:39 +01:00
										 |  |  |     @new_formula = !!options[:new_formula] | 
					
						
							| 
									
										
										
										
											2014-12-27 12:38:04 +00:00
										 |  |  |     @strict = !!options[:strict] | 
					
						
							| 
									
										
										
										
											2015-07-09 12:31:17 +01:00
										 |  |  |     @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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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| | 
					
						
							|  |  |  |       problem offense.to_s(:display_cop_name => display_cop_names) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit_file | 
					
						
							| 
									
										
										
										
											2015-11-11 13:11:17 +01:00
										 |  |  |     # 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) | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-06-23 11:20:47 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if text.has_DATA? && !text.has_END? | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "'DATA' was found, but no '__END__'" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-08 10:17:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if text.has_END? && !text.has_DATA? | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "'__END__' was found, but 'DATA' is not used" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-15 11:32:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-19 20:38:46 +01:00
										 |  |  |     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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-12 21:41:14 -06:00
										 |  |  |     unless text.has_trailing_newline? | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "File should end with a newline" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-06-08 18:57:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return unless @strict | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     component_list = [ | 
					
						
							| 
									
										
										
										
											2016-08-06 03:26:38 +01:00
										 |  |  |       [/^  include Language::/,            "include directive"], | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       [/^  desc ["'][\S\ ]+["']/,          "desc"], | 
					
						
							|  |  |  |       [/^  homepage ["'][\S\ ]+["']/,      "homepage"], | 
					
						
							|  |  |  |       [/^  url ["'][\S\ ]+["']/,           "url"], | 
					
						
							|  |  |  |       [/^  mirror ["'][\S\ ]+["']/,        "mirror"], | 
					
						
							|  |  |  |       [/^  version ["'][\S\ ]+["']/,       "version"], | 
					
						
							|  |  |  |       [/^  (sha1|sha256) ["'][\S\ ]+["']/, "checksum"], | 
					
						
							| 
									
										
										
										
											2015-11-18 08:07:49 +01:00
										 |  |  |       [/^  revision/,                      "revision"], | 
					
						
							| 
									
										
										
										
											2016-08-18 12:53:07 +01:00
										 |  |  |       [/^  version_scheme/,                "version_scheme"], | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       [/^  head ["'][\S\ ]+["']/,          "head"], | 
					
						
							|  |  |  |       [/^  stable do/,                     "stable block"], | 
					
						
							|  |  |  |       [/^  bottle do/,                     "bottle block"], | 
					
						
							|  |  |  |       [/^  devel do/,                      "devel block"], | 
					
						
							|  |  |  |       [/^  head do/,                       "head block"], | 
					
						
							| 
									
										
										
										
											2015-10-19 17:23:06 +01:00
										 |  |  |       [/^  bottle (:unneeded|:disable)/,   "bottle modifier"], | 
					
						
							| 
									
										
										
										
											2015-11-18 08:07:49 +01:00
										 |  |  |       [/^  keg_only/,                      "keg_only"], | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       [/^  option/,                        "option"], | 
					
						
							|  |  |  |       [/^  depends_on/,                    "depends_on"], | 
					
						
							| 
									
										
										
										
											2016-08-06 03:22:02 +01:00
										 |  |  |       [/^  conflicts_with/,                "conflicts_with"], | 
					
						
							| 
									
										
										
										
											2016-01-28 13:37:45 +00:00
										 |  |  |       [/^  (go_)?resource/,                "resource"], | 
					
						
							| 
									
										
										
										
											2015-06-08 18:57:17 +08:00
										 |  |  |       [/^  def install/,                   "install method"], | 
					
						
							|  |  |  |       [/^  def caveats/,                   "caveats method"], | 
					
						
							| 
									
										
										
										
											2016-04-04 17:16:06 +01:00
										 |  |  |       [/^  (plist_options|def plist)/,     "plist block"], | 
					
						
							| 
									
										
										
										
											2015-10-19 17:23:06 +01:00
										 |  |  |       [/^  test do/,                       "test block"], | 
					
						
							| 
									
										
										
										
											2015-06-08 18:57:17 +08:00
										 |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-05 05:38:50 -04:00
										 |  |  |     present = component_list.map do |regex, name| | 
					
						
							| 
									
										
										
										
											2015-06-08 18:57:17 +08:00
										 |  |  |       lineno = text.line_number regex | 
					
						
							|  |  |  |       next unless lineno | 
					
						
							|  |  |  |       [lineno, name] | 
					
						
							| 
									
										
										
										
											2015-10-05 05:38:50 -04:00
										 |  |  |     end.compact | 
					
						
							|  |  |  |     present.each_cons(2) do |c1, c2| | 
					
						
							| 
									
										
										
										
											2015-06-08 18:57:17 +08:00
										 |  |  |       unless c1[0] < c2[0] | 
					
						
							| 
									
										
										
										
											2015-07-16 20:33:15 +02:00
										 |  |  |         problem "`#{c1[1]}` (line #{c1[0]}) should be put before `#{c2[1]}` (line #{c2[0]})" | 
					
						
							| 
									
										
										
										
											2015-06-08 18:57:17 +08:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-10-05 05:38:50 -04:00
										 |  |  |     present.map!(&:last) | 
					
						
							| 
									
										
										
										
											2016-01-13 23:25:57 +08:00
										 |  |  |     if present.include?("stable block") | 
					
						
							|  |  |  |       %w[url checksum mirror].each do |component| | 
					
						
							|  |  |  |         if present.include?(component) | 
					
						
							|  |  |  |           problem "`#{component}` should be put inside `stable block`" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-10-05 05:38:50 -04:00
										 |  |  |     if present.include?("head") && present.include?("head block") | 
					
						
							|  |  |  |       problem "Should not have both `head` and `head do`" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-10-19 17:23:06 +01:00
										 |  |  |     if present.include?("bottle modifier") && present.include?("bottle block") | 
					
						
							|  |  |  |       problem "Should not have `bottle :unneeded/:disable` and `bottle do`" | 
					
						
							|  |  |  |     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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 18:54:44 +08:00
										 |  |  |     @@local_official_taps_name_map ||= Tap.select(&:official?).flat_map(&:formula_names). | 
					
						
							|  |  |  |       reduce(Hash.new) do |name_map, tap_formula_full_name| | 
					
						
							|  |  |  |         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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     same_name_tap_formulae = @@local_official_taps_name_map[name] || [] | 
					
						
							| 
									
										
										
										
											2015-07-09 22:06:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if @online | 
					
						
							| 
									
										
										
										
											2015-09-07 18:32:38 +08:00
										 |  |  |       @@remote_official_taps ||= OFFICIAL_TAPS - Tap.select(&:official?).map(&:repo) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-09 22:06:53 +08:00
										 |  |  |       same_name_tap_formulae += @@remote_official_taps.map do |tap| | 
					
						
							|  |  |  |         Thread.new { Homebrew.search_tap "homebrew", tap, name } | 
					
						
							| 
									
										
										
										
											2015-08-06 17:12:35 +08:00
										 |  |  |       end.flat_map(&:value) | 
					
						
							| 
									
										
										
										
											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-05-30 20:41:17 +01:00
										 |  |  |     unless same_name_tap_formulae.empty? | 
					
						
							| 
									
										
										
										
											2015-06-07 11:49:41 -07:00
										 |  |  |       problem "Formula name conflicts with #{same_name_tap_formulae.join ", "}" | 
					
						
							| 
									
										
										
										
											2015-05-31 18:40:28 +08:00
										 |  |  |     end | 
					
						
							|  |  |  |   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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 00:11:46 -05:00
										 |  |  |         if @@aliases.include?(dep.name) | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  |         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 | 
					
						
							|  |  |  |         when *BUILD_TIME_DEPS | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |           next if dep.build? || dep.run? | 
					
						
							| 
									
										
										
										
											2015-02-17 17:56:44 +08:00
										 |  |  |           problem <<-EOS.undent
 | 
					
						
							|  |  |  |             #{dep} dependency should be | 
					
						
							|  |  |  |               depends_on "#{dep}" => :build | 
					
						
							| 
									
										
										
										
											2015-08-25 11:02:34 -04:00
										 |  |  |             Or if it is indeed a runtime dependency | 
					
						
							| 
									
										
										
										
											2015-02-17 17:56:44 +08:00
										 |  |  |               depends_on "#{dep}" => :run | 
					
						
							|  |  |  |           EOS | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2015-09-13 20:57:43 +08: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 | 
					
						
							|  |  |  |         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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-27 12:38:58 +00:00
										 |  |  |   def audit_options | 
					
						
							|  |  |  |     formula.options.each do |o| | 
					
						
							|  |  |  |       next unless @strict | 
					
						
							| 
									
										
										
										
											2014-12-27 15:57:11 +00:00
										 |  |  |       if o.name !~ /with(out)?-/ && o.name != "c++11" && o.name != "universal" && o.name != "32-bit" | 
					
						
							| 
									
										
										
										
											2014-12-27 12:38:58 +00:00
										 |  |  |         problem "Options should begin with with/without. Migrate '--#{o.name}' with `deprecated_option`." | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-12-08 13:25:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if o.name =~ /^with(out)?-(?:checks?|tests)$/ | 
					
						
							| 
									
										
										
										
											2016-05-03 08:16:20 -04:00
										 |  |  |         unless formula.deps.any? { |d| d.name == "check" && (d.optional? || d.recommended?) } | 
					
						
							|  |  |  |           problem "Use '--with#{$1}-test' instead of '--#{o.name}'. Migrate '--#{o.name}' with `deprecated_option`." | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2015-12-08 13:25:19 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-12-27 12:38:58 +00:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 13:05:22 -04:00
										 |  |  |   def audit_desc | 
					
						
							|  |  |  |     # For now, only check the description when using `--strict` | 
					
						
							|  |  |  |     return unless @strict | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     desc = formula.desc | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:41:17 +01:00
										 |  |  |     unless desc && !desc.empty? | 
					
						
							| 
									
										
										
										
											2015-05-19 13:05:22 -04:00
										 |  |  |       problem "Formula should have a desc (Description)." | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Make sure the formula name plus description is no longer than 80 characters | 
					
						
							| 
									
										
										
										
											2015-12-23 09:31:17 -05:00
										 |  |  |     # Note full_name includes the name of the tap, while name does not | 
					
						
							|  |  |  |     linelength = formula.name.length + ": ".length + desc.length | 
					
						
							| 
									
										
										
										
											2015-05-19 13:05:22 -04:00
										 |  |  |     if linelength > 80
 | 
					
						
							| 
									
										
										
										
											2015-07-14 17:15:51 +01:00
										 |  |  |       problem <<-EOS.undent
 | 
					
						
							|  |  |  |         Description is too long. \"name: desc\" should be less than 80 characters.
 | 
					
						
							| 
									
										
										
										
											2015-12-23 09:31:17 -05:00
										 |  |  |         Length is calculated as #{formula.name} + desc. (currently #{linelength}) | 
					
						
							| 
									
										
										
										
											2015-07-14 17:15:51 +01:00
										 |  |  |       EOS | 
					
						
							| 
									
										
										
										
											2015-05-19 13:05:22 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-06 15:45:52 +08:00
										 |  |  |     if desc =~ /([Cc]ommand ?line)/ | 
					
						
							| 
									
										
										
										
											2015-08-03 11:51:59 +02:00
										 |  |  |       problem "Description should use \"command-line\" instead of \"#{$1}\"" | 
					
						
							| 
									
										
										
										
											2015-05-19 13:05:22 -04:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-08-03 11:53:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-22 13:15:33 +08:00
										 |  |  |     if desc =~ /^([Aa]n?)\s/ | 
					
						
							| 
									
										
										
										
											2015-10-30 00:47:47 +01:00
										 |  |  |       problem "Description shouldn't start with an indefinite article (#{$1})" | 
					
						
							| 
									
										
										
										
											2015-08-03 11:53:30 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-10-30 00:59:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 14:42:45 +01:00
										 |  |  |     if desc.downcase.start_with? "#{formula.name} " | 
					
						
							| 
									
										
										
										
											2015-10-30 00:59:30 +01:00
										 |  |  |       problem "Description shouldn't include the formula name" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-05-19 13:05:22 -04:00
										 |  |  |   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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     unless homepage =~ %r{^https?://} | 
					
						
							| 
									
										
										
										
											2014-09-14 15:43:20 -05:00
										 |  |  |       problem "The homepage should start with http or https (URL is #{homepage})." | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check for http:// GitHub homepage urls, https:// is preferred. | 
					
						
							|  |  |  |     # Note: only check homepages that are repo pages, not *.github.com hosts | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if homepage.start_with? "http://github.com/" | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{homepage}" | 
					
						
							| 
									
										
										
										
											2015-01-04 23:43:15 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Savannah has full SSL/TLS support but no auto-redirect. | 
					
						
							| 
									
										
										
										
											2015-05-14 00:15:41 -04:00
										 |  |  |     # Doesn't apply to the download URLs, only the homepage. | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if homepage.start_with? "http://savannah.nongnu.org/" | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{homepage}" | 
					
						
							| 
									
										
										
										
											2015-02-11 00:53:54 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Freedesktop is complicated to handle - It has SSL/TLS, but only on certain subdomains. | 
					
						
							| 
									
										
										
										
											2015-06-07 11:49:41 -07:00
										 |  |  |     # To enable https Freedesktop change the URL from http://project.freedesktop.org/wiki to | 
					
						
							| 
									
										
										
										
											2015-02-11 00:53:54 +00:00
										 |  |  |     # https://wiki.freedesktop.org/project_name. | 
					
						
							|  |  |  |     # "Software" is redirected to https://wiki.freedesktop.org/www/Software/project_name | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if homepage =~ %r{^http://((?:www|nice|libopenraw|liboil|telepathy|xorg)\.)?freedesktop\.org/(?:wiki/)?} | 
					
						
							| 
									
										
										
										
											2015-02-11 00:53:54 +00:00
										 |  |  |       if homepage =~ /Software/ | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |         problem "#{homepage} should be styled `https://wiki.freedesktop.org/www/Software/project_name`" | 
					
						
							| 
									
										
										
										
											2015-02-11 00:53:54 +00:00
										 |  |  |       else | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |         problem "#{homepage} should be styled `https://wiki.freedesktop.org/project_name`" | 
					
						
							| 
									
										
										
										
											2015-02-11 00:53:54 +00:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |     # Google Code homepages should end in a slash | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if homepage =~ %r{^https?://code\.google\.com/p/[^/]+[^/]$} | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "#{homepage} should end with a slash" | 
					
						
							| 
									
										
										
										
											2015-01-04 23:43:15 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-11 00:53:54 +00:00
										 |  |  |     # People will run into mixed content sometimes, but we should enforce and then add | 
					
						
							|  |  |  |     # exemptions as they are discovered. Treat mixed content on homepages as a bug. | 
					
						
							|  |  |  |     # Justify each exemptions with a code comment so we can keep track here. | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if homepage =~ %r{^http://[^/]*github\.io/} | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{homepage}" | 
					
						
							| 
									
										
										
										
											2015-03-16 23:55:11 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-04 23:43:15 +00:00
										 |  |  |     # There's an auto-redirect here, but this mistake is incredibly common too. | 
					
						
							| 
									
										
										
										
											2015-05-14 00:15:41 -04:00
										 |  |  |     # Only applies to the homepage and subdomains for now, not the FTP URLs. | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if homepage =~ %r{^http://((?:build|cloud|developer|download|extensions|git|glade|help|library|live|nagios|news|people|projects|rt|static|wiki|www)\.)?gnome\.org} | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{homepage}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Compact the above into this list as we're able to remove detailed notations, etc over time. | 
					
						
							|  |  |  |     case homepage | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     when %r{^http://[^/]*\.apache\.org}, | 
					
						
							|  |  |  |          %r{^http://packages\.debian\.org}, | 
					
						
							|  |  |  |          %r{^http://wiki\.freedesktop\.org/}, | 
					
						
							| 
									
										
										
										
											2016-07-13 16:19:51 +08:00
										 |  |  |          %r{^http://((?:www)\.)?gnupg\.org/}, | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |          %r{^http://ietf\.org}, | 
					
						
							|  |  |  |          %r{^http://[^/.]+\.ietf\.org}, | 
					
						
							|  |  |  |          %r{^http://[^/.]+\.tools\.ietf\.org}, | 
					
						
							|  |  |  |          %r{^http://www\.gnu\.org/}, | 
					
						
							| 
									
										
										
										
											2015-08-10 19:11:58 +01:00
										 |  |  |          %r{^http://code\.google\.com/}, | 
					
						
							| 
									
										
										
										
											2015-08-10 22:40:08 +02:00
										 |  |  |          %r{^http://bitbucket\.org/}, | 
					
						
							|  |  |  |          %r{^http://(?:[^/]*\.)?archive\.org} | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{homepage}" | 
					
						
							| 
									
										
										
										
											2015-01-04 23:43:15 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-07-11 23:36:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return unless @online | 
					
						
							|  |  |  |     begin | 
					
						
							| 
									
										
										
										
											2015-08-02 10:50:39 +02:00
										 |  |  |       nostdout { curl "--connect-timeout", "15", "-o", "/dev/null", homepage } | 
					
						
							| 
									
										
										
										
											2015-07-11 23:36:03 +02:00
										 |  |  |     rescue ErrorDuringExecution | 
					
						
							|  |  |  |       problem "The homepage is not reachable (curl exit code #{$?.exitstatus})" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-03-15 21:40:09 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-23 10:41:39 +02:00
										 |  |  |   def audit_bottle_spec | 
					
						
							|  |  |  |     if formula.bottle_disabled? && !formula.bottle_disable_reason.valid? | 
					
						
							|  |  |  |       problem "Unrecognized bottle modifier" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if Date.parse(metadata["created_at"]) > (Date.today - 30) | 
					
						
							| 
									
										
										
										
											2015-07-08 14:22:44 +01:00
										 |  |  |       problem "GitHub repository too new (<30 days old)" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  |       ra = ResourceAuditor.new(spec).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| | 
					
						
							| 
									
										
										
										
											2013-09-18 18:50:23 -05:00
										 |  |  |         ra = ResourceAuditor.new(resource).audit | 
					
						
							|  |  |  |         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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-17 17:08:23 +02:00
										 |  |  |       spec.patches.each { |p| audit_patch(p) if p.external? } | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |     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
										 |  |  | 
 | 
					
						
							|  |  |  |     stable = formula.stable | 
					
						
							| 
									
										
										
										
											2015-05-14 00:01:00 -04:00
										 |  |  |     case stable && stable.url | 
					
						
							|  |  |  |     when %r{download\.gnome\.org/sources}, %r{ftp\.gnome\.org/pub/GNOME/sources}i | 
					
						
							| 
									
										
										
										
											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-01-16 23:19:36 +08:00
										 |  |  |     fv = FormulaVersions.new(formula, :max_depth => 10) | 
					
						
							| 
									
										
										
										
											2016-08-18 12:55:46 +01:00
										 |  |  |     attributes = [:revision, :version_scheme] | 
					
						
							| 
									
										
										
										
											2016-08-18 12:55:19 +01:00
										 |  |  |     attributes_map = fv.version_attributes_map(attributes, "origin/master") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     attributes.each do |attribute| | 
					
						
							|  |  |  |       attributes_for_version = attributes_map[attribute][formula.version] | 
					
						
							|  |  |  |       if !attributes_for_version.empty? | 
					
						
							|  |  |  |         if formula.send(attribute) < attributes_for_version.max | 
					
						
							|  |  |  |           problem "#{attribute} should not decrease" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     revision_map = attributes_map[:revision] | 
					
						
							|  |  |  |     if formula.revision != 0
 | 
					
						
							| 
									
										
										
										
											2016-01-15 16:17:14 +08:00
										 |  |  |       if formula.stable | 
					
						
							|  |  |  |         if revision_map[formula.stable.version].empty? # check stable spec | 
					
						
							| 
									
										
										
										
											2016-08-18 14:49:26 +01:00
										 |  |  |           problem "'revision #{formula.revision}' should be removed" | 
					
						
							| 
									
										
										
										
											2016-01-15 16:17:14 +08:00
										 |  |  |         end | 
					
						
							|  |  |  |       else # head/devel-only formula | 
					
						
							| 
									
										
										
										
											2016-08-18 14:49:26 +01:00
										 |  |  |         problem "'revision #{formula.revision}' should be removed" | 
					
						
							| 
									
										
										
										
											2016-01-15 16:17:14 +08:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-01-14 13:33:56 +08:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-22 16:34:08 +08:00
										 |  |  |   def audit_legacy_patches | 
					
						
							| 
									
										
										
										
											2015-07-22 15:27:58 +08:00
										 |  |  |     return unless formula.respond_to?(:patches) | 
					
						
							| 
									
										
										
										
											2014-10-29 22:38:49 -05:00
										 |  |  |     legacy_patches = Patch.normalize_legacy_patches(formula.patches).grep(LegacyPatch) | 
					
						
							| 
									
										
										
										
											2016-08-05 22:01:32 +08:00
										 |  |  |     unless legacy_patches.empty? | 
					
						
							| 
									
										
										
										
											2014-07-11 12:46:14 -05:00
										 |  |  |       problem "Use the patch DSL instead of defining a 'patches' method" | 
					
						
							|  |  |  |       legacy_patches.each { |p| audit_patch(p) } | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-03-13 19:51:23 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_patch(patch) | 
					
						
							|  |  |  |     case patch.url | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2016-08-18 14:47:34 -07:00
										 |  |  |           https://github.com/#{$1}/#{$2}/pull/#{$3}.patch | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2014-02-25 07:36:47 -08:00
										 |  |  |     if text =~ /system\s+['"]scons/ | 
					
						
							| 
									
										
										
										
											2014-02-25 20:51:16 -08:00
										 |  |  |       problem "use \"scons *args\" instead of \"system 'scons', *args\"" | 
					
						
							| 
									
										
										
										
											2014-02-25 07:36:47 -08:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-27 21:47:38 -06:00
										 |  |  |     if text =~ /system\s+['"]xcodebuild/ | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       problem %(use "xcodebuild *args" instead of "system 'xcodebuild', *args") | 
					
						
							| 
									
										
										
										
											2014-02-27 21:47:38 -06:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if text =~ /xcodebuild[ (]["'*]/ && !text.include?("SYMROOT=") | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       problem %(xcodebuild should be passed an explicit "SYMROOT") | 
					
						
							| 
									
										
										
										
											2013-07-16 23:15:22 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-02-24 20:23:21 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if text.include? "Formula.factory(" | 
					
						
							| 
									
										
										
										
											2014-02-24 20:23:21 -08:00
										 |  |  |       problem "\"Formula.factory(name)\" is deprecated in favor of \"Formula[name]\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-06-09 15:52:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if text.include?("def plist") && !text.include?("plist_options") | 
					
						
							| 
									
										
										
										
											2016-04-04 17:41:39 +01:00
										 |  |  |       problem "Please set plist_options when using a formula-defined plist." | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-07-10 14:01:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if text.include?('require "language/go"') && !text.include?("go_resource") | 
					
						
							| 
									
										
										
										
											2016-07-10 14:01:34 +01:00
										 |  |  |       problem "require \"language/go\" is unnecessary unless using `go_resource`s" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-07-16 23:15:22 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-20 00:00:36 +08:00
										 |  |  |   def audit_line(line, lineno) | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /<(Formula|AmazonWebServicesFormula|ScriptFileFormula|GithubGistFormula)/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use a space in class inheritance: class Foo < #{$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-07-13 18:28:40 +08:00
										 |  |  |     if line.include?('# system "cmake') | 
					
						
							| 
									
										
										
										
											2013-01-04 09:30:57 -08:00
										 |  |  |       problem "Commented cmake call found" | 
					
						
							| 
									
										
										
										
											2010-09-09 14:16:05 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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| | 
					
						
							|  |  |  |       if line.include? comment | 
					
						
							|  |  |  |         problem "Please remove default template comments" | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |     if line =~ /[^'"\/]FileUtils\.(\w+)/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Don't need 'FileUtils.' before #{$1}." | 
					
						
							|  |  |  |     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,})\|/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"inreplace <filenames> do |s|\" is preferred over \"|#{$1}|\"." | 
					
						
							|  |  |  |     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.]+)\}"/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Don't need to interpolate \"#{$2}\" with #{$1}" | 
					
						
							|  |  |  |     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*['"][^}]+\})/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Try not to concatenate paths in string interpolation:\n   #{$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)[/'"])} | 
					
						
							|  |  |  |       problem "\"(#{$1}...#{$2})\" should be \"(#{$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])(['"]))/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"#{$4}\"" | 
					
						
							|  |  |  |     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))] | 
					
						
							|  |  |  |       problem "\"#{$1}\" should be \"\#{#{$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]))] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"\#{#{$3}}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-01-25 22:41:53 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r[((\#\{share\}/(man)))[/'"]] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"\#{#{$3}}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-21 11:55:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r[(\#\{prefix\}/share/(info|man))] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"\#{#{$2}}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-21 11:55:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if line =~ /depends_on :(automake|autoconf|libtool)/ | 
					
						
							| 
									
										
										
										
											2015-05-03 18:52:46 +01:00
										 |  |  |       problem ":#{$1} is deprecated. Usage should be \"#{$1}\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Commented-out depends_on | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /#\s*depends_on\s+(.+)\s*$/ | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Commented-out dep #{$1}" | 
					
						
							| 
									
										
										
										
											2010-09-07 09:23:29 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # No trailing whitespace, please | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /[\t ]+$/ | 
					
						
							| 
									
										
										
										
											2013-11-20 00:00:36 +08:00
										 |  |  |       problem "#{lineno}: Trailing whitespace was found" | 
					
						
							| 
									
										
										
										
											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 =~ /if\s+ARGV\.include\?\s+'--(HEAD|devel)'/ | 
					
						
							| 
									
										
										
										
											2014-06-15 23:26:07 -05:00
										 |  |  |       problem "Use \"if build.#{$1.downcase}?\" instead" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if line.include?("make && make") | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Use separate make calls" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /^[ ]*\t/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use spaces instead of tabs for indentation" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											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)['" ]} | 
					
						
							|  |  |  |       problem "Use \"\#{ENV.cc}\" instead of hard-coding \"#{$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)\+\+)['" ]} | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use \"\#{ENV.cxx}\" instead of hard-coding \"#{$3}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-02-20 15:03:15 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-05 07:53:53 -08:00
										 |  |  |     if line =~ /system\s+['"](env|export)(\s+|['"])/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use ENV instead of invoking '#{$1}' to modify the environment" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-01-22 22:32:15 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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\(]+['"]\-\-(.*)['"]/ | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Reference '#{$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)?-(.*)['"]/ | 
					
						
							|  |  |  |       problem "Use build.with#{$1}? \"#{$2}\" instead of build.include? 'with#{$1}-#{$2}'" | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-06 20:40:15 +00:00
										 |  |  |     if line =~ /build\.with\?[\s\(]+['"]-?-?with-(.*)['"]/ | 
					
						
							|  |  |  |       problem "Don't duplicate 'with': Use `build.with? \"#{$1}\"` to check for \"--with-#{$1}\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /build\.without\?[\s\(]+['"]-?-?without-(.*)['"]/ | 
					
						
							|  |  |  |       problem "Don't duplicate 'without': Use `build.without? \"#{$1}\"` to check for \"--without-#{$1}\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-21 06:08:18 -04:00
										 |  |  |     if line =~ /unless build\.with\?(.*)/ | 
					
						
							|  |  |  |       problem "Use if build.without?#{$1} instead of unless build.with?#{$1}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /unless build\.without\?(.*)/ | 
					
						
							|  |  |  |       problem "Use if build.with?#{$1} instead of unless build.without?#{$1}" | 
					
						
							| 
									
										
										
										
											2014-03-06 20:40:15 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /(not\s|!)\s*build\.with?\?/ | 
					
						
							|  |  |  |       problem "Don't negate 'build.without?': use 'build.with?'" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /(not\s|!)\s*build\.without?\?/ | 
					
						
							|  |  |  |       problem "Don't negate 'build.with?': use 'build.without?'" | 
					
						
							| 
									
										
										
										
											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-07-13 18:28:40 +08:00
										 |  |  |     if line.include?("def options") | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Use new-style option definitions" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											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
										 |  |  |               "\tPass 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+).*$/ | 
					
						
							| 
									
										
										
										
											2013-04-22 15:06:42 -05:00
										 |  |  |       problem "Define method #{$1.inspect} in the class body, not at the top-level" | 
					
						
							|  |  |  |     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.+)$/ | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |       audit_conditional_dep($1.to_sym, $2, $&) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /depends_on ['"](.+)['"] (if.+|unless.+)$/ | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |       audit_conditional_dep($1, $2, $&) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-03-29 09:16:27 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /(Dir\[("[^\*{},]+")\])/ | 
					
						
							|  |  |  |       problem "#{$1} is unnecessary; just use #{$2}" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-12-27 14:00:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-27 20:35:26 +00:00
										 |  |  |     if line =~ /system (["'](#{FILEUTILS_METHODS})["' ])/o | 
					
						
							| 
									
										
										
										
											2014-12-27 14:00:51 +00:00
										 |  |  |       system = $1 | 
					
						
							|  |  |  |       method = $2 | 
					
						
							|  |  |  |       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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if line.include?('system "npm", "install"') && !line.include?("Language::Node") && formula.name !~ /^kibana(\d{2})?$/ | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |       problem "Use Language::Node for npm install args" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-27 14:01:31 +00:00
										 |  |  |     if @strict | 
					
						
							| 
									
										
										
										
											2016-05-29 22:52:26 +01:00
										 |  |  |       if line =~ /system ((["'])[^"' ]*(?:\s[^"' ]*)+\2)/ | 
					
						
							| 
									
										
										
										
											2014-12-27 14:01:31 +00:00
										 |  |  |         bad_system = $1 | 
					
						
							| 
									
										
										
										
											2015-04-11 10:22:49 +02:00
										 |  |  |         unless %w[| < > & ; *].any? { |c| bad_system.include? c } | 
					
						
							| 
									
										
										
										
											2015-03-09 15:03:19 +08:00
										 |  |  |           good_system = bad_system.gsub(" ", "\", \"") | 
					
						
							|  |  |  |           problem "Use `system #{good_system}` instead of `system #{bad_system}` " | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2014-12-27 14:01:31 +00:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-12-27 14:01:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-27 15:59:16 +00:00
										 |  |  |       if line =~ /(require ["']formula["'])/ | 
					
						
							|  |  |  |         problem "`#{$1}` is now unnecessary" | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-01-09 16:32:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 10:13:04 -08:00
										 |  |  |       if line =~ %r{#\{share\}/#{Regexp.escape(formula.name)}[/'"]} | 
					
						
							| 
									
										
										
										
											2016-01-09 16:32:23 +00:00
										 |  |  |         problem "Use \#{pkgshare} instead of \#{share}/#{formula.name}" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 17:46:40 +02:00
										 |  |  |       if line =~ %r{share(\s*[/+]\s*)(['"])#{Regexp.escape(formula.name)}(?:\2|/)} | 
					
						
							|  |  |  |         problem "Use pkgshare instead of (share#{$1}\"#{formula.name}\")" | 
					
						
							| 
									
										
										
										
											2016-01-09 16:32:23 +00:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-12-27 14:01:31 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 09:29:17 +00:00
										 |  |  |   def audit_caveats | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     caveats = formula.caveats.to_s | 
					
						
							| 
									
										
										
										
											2015-02-19 09:29:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |     if caveats.include?("setuid") | 
					
						
							| 
									
										
										
										
											2015-02-19 09:29:17 +00:00
										 |  |  |       problem "Don't recommend setuid in the caveats, suggest sudo instead." | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   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? | 
					
						
							| 
									
										
										
										
											2015-06-17 04:58:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-26 15:33:27 +08:00
										 |  |  |     if formula.tap.tap_migrations.key?(formula.name) | 
					
						
							| 
									
										
										
										
											2015-06-17 04:58:32 +01:00
										 |  |  |       problem <<-EOS.undent
 | 
					
						
							| 
									
										
										
										
											2016-05-01 14:59:39 +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}. | 
					
						
							| 
									
										
										
										
											2015-06-17 04:58:32 +01:00
										 |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-02 22:53:52 +08:00
										 |  |  |   def audit_prefix_has_contents | 
					
						
							|  |  |  |     return unless formula.prefix.directory? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 18:59:34 +08:00
										 |  |  |     if Keg.new(formula.prefix).empty_installation? | 
					
						
							|  |  |  |       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 | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |   def audit_conditional_dep(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}['"]$/ | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       problem %(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}['"]$/ | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       problem %(Replace #{line.inspect} with "depends_on #{quoted_dep} => :recommended") | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def quote_dep(dep) | 
					
						
							|  |  |  |     Symbol === dep ? dep.inspect : "'#{dep}'" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-08-09 11:59:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-13 23:13:00 -05:00
										 |  |  |   def audit_check_output(output) | 
					
						
							|  |  |  |     problem(output) if output | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit | 
					
						
							|  |  |  |     audit_file | 
					
						
							| 
									
										
										
										
											2015-05-31 18:40:28 +08:00
										 |  |  |     audit_formula_name | 
					
						
							| 
									
										
										
										
											2014-12-27 20:46:01 +00:00
										 |  |  |     audit_class | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     audit_specs | 
					
						
							| 
									
										
										
										
											2016-08-18 12:55:46 +01:00
										 |  |  |     audit_revision_and_version_scheme | 
					
						
							| 
									
										
										
										
											2015-05-19 13:05:22 -04:00
										 |  |  |     audit_desc | 
					
						
							| 
									
										
										
										
											2015-05-07 23:18:01 -04:00
										 |  |  |     audit_homepage | 
					
						
							| 
									
										
										
										
											2015-10-23 10:41:39 +02:00
										 |  |  |     audit_bottle_spec | 
					
						
							| 
									
										
										
										
											2015-07-08 14:22:44 +01:00
										 |  |  |     audit_github_repository | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     audit_deps | 
					
						
							| 
									
										
										
										
											2013-01-03 11:22:31 -08:00
										 |  |  |     audit_conflicts | 
					
						
							| 
									
										
										
										
											2014-12-27 12:38:58 +00:00
										 |  |  |     audit_options | 
					
						
							| 
									
										
										
										
											2015-07-22 16:34:08 +08:00
										 |  |  |     audit_legacy_patches | 
					
						
							| 
									
										
										
										
											2013-07-16 23:15:22 -05:00
										 |  |  |     audit_text | 
					
						
							| 
									
										
										
										
											2015-02-19 09:29:17 +00:00
										 |  |  |     audit_caveats | 
					
						
							| 
									
										
										
										
											2014-11-12 21:41:14 -06:00
										 |  |  |     text.without_patch.split("\n").each_with_index { |line, lineno| audit_line(line, lineno+1) } | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  |     audit_installed | 
					
						
							| 
									
										
										
										
											2015-02-02 22:53:52 +08:00
										 |  |  |     audit_prefix_has_contents | 
					
						
							| 
									
										
										
										
											2015-06-17 04:58:32 +01:00
										 |  |  |     audit_reverse_migration | 
					
						
							| 
									
										
										
										
											2016-04-18 17:39:21 -04:00
										 |  |  |     audit_style | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  |   def initialize(resource) | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |     @problems = [] | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit | 
					
						
							|  |  |  |     audit_version | 
					
						
							|  |  |  |     audit_checksum | 
					
						
							|  |  |  |     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
										 |  |  | 
 | 
					
						
							|  |  |  |     if version.to_s =~ /_\d+$/ | 
					
						
							| 
									
										
										
										
											2015-06-07 11:49:41 -07:00
										 |  |  |       problem "version #{version} should not end with an underline and a number" | 
					
						
							| 
									
										
										
										
											2015-04-19 14:31:19 +08:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_checksum | 
					
						
							|  |  |  |     return unless checksum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case checksum.hash_type | 
					
						
							|  |  |  |     when :md5 | 
					
						
							| 
									
										
										
										
											2015-02-24 23:25:57 +00:00
										 |  |  |       problem "MD5 checksums are deprecated, please use SHA256" | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  |       return | 
					
						
							| 
									
										
										
										
											2015-02-24 23:25:57 +00:00
										 |  |  |     when :sha1 | 
					
						
							| 
									
										
										
										
											2015-07-09 13:44:41 +01:00
										 |  |  |       problem "SHA1 checksums are deprecated, please use SHA256" | 
					
						
							|  |  |  |       return | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  |     when :sha256 then len = 64
 | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if checksum.empty? | 
					
						
							|  |  |  |       problem "#{checksum.hash_type} is empty" | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       problem "#{checksum.hash_type} should be #{len} characters" unless checksum.hexdigest.length == len | 
					
						
							|  |  |  |       problem "#{checksum.hash_type} contains invalid characters" unless checksum.hexdigest =~ /^[a-fA-F0-9]+$/ | 
					
						
							|  |  |  |       problem "#{checksum.hash_type} should be lowercase" unless checksum.hexdigest == checksum.hexdigest.downcase | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_download_strategy | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if url =~ %r{^(cvs|bzr|hg|fossil)://} || url =~ %r{^(svn)\+http://} | 
					
						
							| 
									
										
										
										
											2014-12-18 18:04:22 -05:00
										 |  |  |       problem "Use of the #{$&} scheme is deprecated, pass `:using => :#{$1}` instead" | 
					
						
							|  |  |  |     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] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if mod == name | 
					
						
							|  |  |  |         problem "Redundant :module value in URL" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     using_strategy = DownloadStrategyDetector.detect("", using) | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if url_strategy == using_strategy | 
					
						
							| 
									
										
										
										
											2014-12-22 00:43:02 -05:00
										 |  |  |       problem "Redundant :using value in URL" | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |   def audit_urls | 
					
						
							|  |  |  |     # Check GNU urls; doesn't apply to mirrors | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     if url =~ %r{^(?:https?|ftp)://(?!alpha).+/gnu/} | 
					
						
							| 
									
										
										
										
											2016-06-22 19:56:10 +02:00
										 |  |  |       problem "Please use \"https://ftpmirror.gnu.org\" instead of #{url}." | 
					
						
							| 
									
										
										
										
											2015-06-14 20:17:08 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |     if mirrors.include?(url) | 
					
						
							|  |  |  |       problem "URL should not be duplicated as a mirror: #{url}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     urls = [url] + mirrors | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-14 00:15:41 -04:00
										 |  |  |     # Check a variety of SSL/TLS URLs that don't consistently auto-redirect | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |     # or are overly common errors that need to be reduced & fixed over time. | 
					
						
							|  |  |  |     urls.each do |p| | 
					
						
							|  |  |  |       case p | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       when %r{^http://ftp\.gnu\.org/}, | 
					
						
							| 
									
										
										
										
											2016-06-22 19:56:10 +02:00
										 |  |  |            %r{^http://ftpmirror\.gnu\.org/}, | 
					
						
							| 
									
										
										
										
											2016-07-10 02:43:27 +02:00
										 |  |  |            %r{^http://download\.savannah\.gnu\.org/}, | 
					
						
							|  |  |  |            %r{^http://download-mirror\.savannah\.gnu\.org/}, | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |            %r{^http://[^/]*\.apache\.org/}, | 
					
						
							|  |  |  |            %r{^http://code\.google\.com/}, | 
					
						
							|  |  |  |            %r{^http://fossies\.org/}, | 
					
						
							|  |  |  |            %r{^http://mirrors\.kernel\.org/}, | 
					
						
							| 
									
										
										
										
											2015-08-10 22:40:08 +02:00
										 |  |  |            %r{^http://(?:[^/]*\.)?bintray\.com/}, | 
					
						
							| 
									
										
										
										
											2015-08-05 19:45:24 +01:00
										 |  |  |            %r{^http://tools\.ietf\.org/}, | 
					
						
							| 
									
										
										
										
											2015-08-10 19:11:58 +01:00
										 |  |  |            %r{^http://launchpad\.net/}, | 
					
						
							| 
									
										
										
										
											2015-08-10 22:40:08 +02:00
										 |  |  |            %r{^http://bitbucket\.org/}, | 
					
						
							| 
									
										
										
										
											2016-05-30 19:14:09 +01:00
										 |  |  |            %r{^http://cpan\.metacpan\.org/}, | 
					
						
							| 
									
										
										
										
											2016-02-04 14:57:55 +00:00
										 |  |  |            %r{^http://hackage\.haskell\.org/}, | 
					
						
							| 
									
										
										
										
											2016-05-20 10:54:29 +01:00
										 |  |  |            %r{^http://(?:[^/]*\.)?archive\.org}, | 
					
						
							| 
									
										
										
										
											2016-05-30 20:15:51 +01:00
										 |  |  |            %r{^http://(?:[^/]*\.)?freedesktop\.org}, | 
					
						
							|  |  |  |            %r{^http://(?:[^/]*\.)?mirrorservice\.org/} | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |         problem "Please use https:// for #{p}" | 
					
						
							| 
									
										
										
										
											2016-05-30 17:15:11 +01:00
										 |  |  |       when %r{^http://search\.mcpan\.org/CPAN/(.*)}i | 
					
						
							| 
									
										
										
										
											2016-05-30 17:13:43 +01:00
										 |  |  |         problem "#{p} should be `https://cpan.metacpan.org/#{$1}`" | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       when %r{^(http|ftp)://ftp\.gnome\.org/pub/gnome/(.*)}i | 
					
						
							| 
									
										
										
										
											2015-05-29 02:39:24 +02:00
										 |  |  |         problem "#{p} should be `https://download.gnome.org/#{$2}`" | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:29:33 +01:00
										 |  |  |     # Prefer HTTP/S when possible over FTP protocol due to possible firewalls. | 
					
						
							|  |  |  |     urls.each do |p| | 
					
						
							|  |  |  |       case p | 
					
						
							|  |  |  |       when %r{^ftp://ftp\.mirrorservice\.org} | 
					
						
							|  |  |  |         problem "Please use https:// for #{p}" | 
					
						
							|  |  |  |       when %r{^ftp://ftp\.cpan\.org/pub/CPAN(.*)}i | 
					
						
							|  |  |  |         problem "#{p} should be `http://search.cpan.org/CPAN#{$1}`" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |     # Check SourceForge urls | 
					
						
							|  |  |  |     urls.each do |p| | 
					
						
							|  |  |  |       # Skip if the URL looks like a SVN repo | 
					
						
							| 
									
										
										
										
											2016-07-13 18:28:40 +08:00
										 |  |  |       next if p.include? "/svnroot/" | 
					
						
							|  |  |  |       next if p.include? "svn.sourceforge" | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # Is it a sourceforge http(s) URL? | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       next unless p =~ %r{^https?://.*\b(sourceforge|sf)\.(com|net)} | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if p =~ /(\?|&)use_mirror=/ | 
					
						
							|  |  |  |         problem "Don't use #{$1}use_mirror in SourceForge urls (url is #{p})." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 20:41:17 +01:00
										 |  |  |       if p.end_with?("/download") | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |         problem "Don't use /download in SourceForge urls (url is #{p})." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       if p =~ %r{^https?://sourceforge\.} | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |         problem "Use https://downloads.sourceforge.net to get geolocation (url is #{p})." | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       if p =~ %r{^https?://prdownloads\.} | 
					
						
							|  |  |  |         problem "Don't use prdownloads in SourceForge urls (url is #{p}).\n" \ | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |                 "\tSee: http://librelist.com/browser/homebrew/2011/1/12/prdownloads-is-bad/" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |       if p =~ %r{^http://\w+\.dl\.} | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |         problem "Don't use specific dl mirrors in SourceForge urls (url is #{p})." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if p.start_with? "http://downloads" | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |         problem "Please use https:// for #{p}" | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check for Google Code download urls, https:// is preferred | 
					
						
							|  |  |  |     # Intentionally not extending this to SVN repositories due to certificate | 
					
						
							|  |  |  |     # issues. | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     urls.grep(%r{^http://.*\.googlecode\.com/files.*}) do |u| | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{u}" | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check for new-url Google Code download urls, https:// is preferred | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     urls.grep(%r{^http://code\.google\.com/}) do |u| | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{u}" | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check for git:// GitHub repo urls, https:// is preferred. | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     urls.grep(%r{^git://[^/]*github\.com/}) do |u| | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{u}" | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check for git:// Gitorious repo urls, https:// is preferred. | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     urls.grep(%r{^git://[^/]*gitorious\.org/}) do |u| | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{u}" | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check for http:// GitHub repo urls, https:// is preferred. | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     urls.grep(%r{^http://github\.com/.*\.git$}) do |u| | 
					
						
							| 
									
										
										
										
											2015-05-24 16:14:44 +01:00
										 |  |  |       problem "Please use https:// for #{u}" | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Use new-style archive downloads | 
					
						
							| 
									
										
										
										
											2015-08-17 17:08:23 +02:00
										 |  |  |     urls.each do |u| | 
					
						
							|  |  |  |       next unless u =~ %r{https://.*github.*/(?:tar|zip)ball/} && u !~ /\.git$/ | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |       problem "Use /archive/ URLs for GitHub tarballs (url is #{u})." | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Don't use GitHub .zip files | 
					
						
							| 
									
										
										
										
											2015-08-17 17:08:23 +02:00
										 |  |  |     urls.each do |u| | 
					
						
							|  |  |  |       next unless u =~ %r{https://.*github.*/(archive|releases)/.*\.zip$} && u !~ %r{releases/download} | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |       problem "Use GitHub tarballs rather than zipballs (url is #{u})." | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-05-19 07:56:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Don't use GitHub codeload URLs | 
					
						
							|  |  |  |     urls.each do |u| | 
					
						
							|  |  |  |       next unless u =~ %r{https?://codeload\.github\.com/(.+)/(.+)/(?:tar\.gz|zip)/(.+)} | 
					
						
							|  |  |  |       problem <<-EOS.undent
 | 
					
						
							|  |  |  |         use GitHub archive URLs: | 
					
						
							|  |  |  |           https://github.com/#{$1}/#{$2}/archive/#{$3}.tar.gz | 
					
						
							|  |  |  |         Rather than codeload: | 
					
						
							|  |  |  |           #{u} | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-06-02 09:36:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Check for Maven Central urls, prefer HTTPS redirector over specific host | 
					
						
							|  |  |  |     urls.each do |u| | 
					
						
							|  |  |  |       next unless u =~ %r{https?://(?:central|repo\d+)\.maven\.org/maven2/(.+)$} | 
					
						
							|  |  |  |       problem "#{u} should be `https://search.maven.org/remotecontent?filepath=#{$1}`" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-05-07 22:44:01 -04:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |   def problem(text) | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  |     @problems << text | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |