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