| 
									
										
										
										
											2010-06-23 11:20:47 -07:00
										 |  |  | require 'formula' | 
					
						
							|  |  |  | require 'utils' | 
					
						
							| 
									
										
										
										
											2013-08-19 12:32:57 -05:00
										 |  |  | require 'extend/ENV' | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  | require 'formula_cellar_checks' | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | module Homebrew extend self | 
					
						
							|  |  |  |   def audit | 
					
						
							|  |  |  |     formula_count = 0
 | 
					
						
							|  |  |  |     problem_count = 0
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-19 13:03:41 -05:00
										 |  |  |     ENV.activate_extensions! | 
					
						
							| 
									
										
										
										
											2013-05-07 18:39:45 -05:00
										 |  |  |     ENV.setup_build_environment | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     ff = if ARGV.named.empty? | 
					
						
							| 
									
										
										
										
											2012-08-21 11:39:45 -04:00
										 |  |  |       Formula | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     else | 
					
						
							|  |  |  |       ARGV.formulae | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ff.each do |f| | 
					
						
							|  |  |  |       fa = FormulaAuditor.new f | 
					
						
							|  |  |  |       fa.audit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       unless fa.problems.empty? | 
					
						
							|  |  |  |         puts "#{f.name}:" | 
					
						
							|  |  |  |         fa.problems.each { |p| puts " * #{p}" } | 
					
						
							|  |  |  |         puts | 
					
						
							|  |  |  |         formula_count += 1
 | 
					
						
							|  |  |  |         problem_count += fa.problems.size | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unless problem_count.zero? | 
					
						
							|  |  |  |       ofail "#{problem_count} problems in #{formula_count} formulae" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Module | 
					
						
							|  |  |  |   def redefine_const(name, value) | 
					
						
							|  |  |  |     __send__(:remove_const, name) if const_defined?(name) | 
					
						
							|  |  |  |     const_set(name, value) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							| 
									
										
										
										
											2010-06-23 11:20:47 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | # Formula extensions for auditing | 
					
						
							|  |  |  | class Formula | 
					
						
							|  |  |  |   def head_only? | 
					
						
							|  |  |  |     @head and @stable.nil? | 
					
						
							| 
									
										
										
										
											2011-06-06 07:25:00 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-03-21 12:57:35 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def text | 
					
						
							|  |  |  |     @text ||= FormulaText.new(@path) | 
					
						
							| 
									
										
										
										
											2010-07-12 10:34:12 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2010-07-12 10:34:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | class FormulaText | 
					
						
							|  |  |  |   def initialize path | 
					
						
							|  |  |  |     @text = path.open('r') { |f| f.read } | 
					
						
							| 
									
										
										
										
											2010-07-23 21:31:32 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def without_patch | 
					
						
							|  |  |  |     @text.split("__END__")[0].strip() | 
					
						
							| 
									
										
										
										
											2011-11-29 19:37:39 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def has_DATA? | 
					
						
							|  |  |  |     /\bDATA\b/ =~ @text | 
					
						
							| 
									
										
										
										
											2010-08-15 15:19:19 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def has_END? | 
					
						
							|  |  |  |     /^__END__$/ =~ @text | 
					
						
							| 
									
										
										
										
											2010-09-08 09:07:59 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def has_trailing_newline? | 
					
						
							| 
									
										
										
										
											2013-02-21 09:56:30 +01:00
										 |  |  |     /\Z\n/ =~ @text | 
					
						
							| 
									
										
										
										
											2010-09-07 14:34:39 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2010-09-07 14:34:39 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | class FormulaAuditor | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  |   include FormulaCellarChecks | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-17 22:52:39 -06:00
										 |  |  |   attr_reader :f, :text, :problems | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   BUILD_TIME_DEPS = %W[
 | 
					
						
							|  |  |  |     autoconf | 
					
						
							|  |  |  |     automake | 
					
						
							|  |  |  |     boost-build | 
					
						
							|  |  |  |     bsdmake | 
					
						
							|  |  |  |     cmake | 
					
						
							|  |  |  |     imake | 
					
						
							| 
									
										
										
										
											2013-02-03 14:41:00 -06:00
										 |  |  |     intltool | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     libtool | 
					
						
							|  |  |  |     pkg-config | 
					
						
							|  |  |  |     scons | 
					
						
							|  |  |  |     smake | 
					
						
							| 
									
										
										
										
											2012-09-05 21:12:08 -07:00
										 |  |  |     swig | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def initialize f | 
					
						
							|  |  |  |     @f = f | 
					
						
							|  |  |  |     @problems = [] | 
					
						
							|  |  |  |     @text = f.text.without_patch | 
					
						
							| 
									
										
										
										
											2013-04-06 22:10:33 -05:00
										 |  |  |     @specs = %w{stable devel head}.map { |s| f.send(s) }.compact | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # We need to do this in case the formula defines a patch that uses DATA. | 
					
						
							|  |  |  |     f.class.redefine_const :DATA, "" | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_file | 
					
						
							|  |  |  |     unless f.path.stat.mode.to_s(8) == "100644" | 
					
						
							|  |  |  |       problem "Incorrect file permissions: chmod 644 #{f.path}" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-06-23 11:20:47 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     if f.text.has_DATA? and not f.text.has_END? | 
					
						
							|  |  |  |       problem "'DATA' was found, but no '__END__'" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-08 10:17:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     if f.text.has_END? and not f.text.has_DATA? | 
					
						
							|  |  |  |       problem "'__END__' was found, but 'DATA' is not used" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-15 11:32:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-21 09:56:30 +01:00
										 |  |  |     unless f.text.has_trailing_newline? | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "File should end with a newline" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-08 10:17:53 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit_deps | 
					
						
							|  |  |  |     # Don't depend_on aliases; use full name | 
					
						
							| 
									
										
										
										
											2013-05-07 18:40:14 -05:00
										 |  |  |     @@aliases ||= Formula.aliases | 
					
						
							|  |  |  |     f.deps.select { |d| @@aliases.include? d.name }.each do |d| | 
					
						
							| 
									
										
										
										
											2013-08-14 21:30:23 -07:00
										 |  |  |       real_name = d.to_formula.name | 
					
						
							|  |  |  |       problem "Dependency '#{d}' is an alias; use the canonical name '#{real_name}'." | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-09-08 09:22:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Check for things we don't like to depend on. | 
					
						
							|  |  |  |     # We allow non-Homebrew installs whenever possible. | 
					
						
							| 
									
										
										
										
											2013-01-23 00:26:31 -06:00
										 |  |  |     f.deps.each do |dep| | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       begin | 
					
						
							| 
									
										
										
										
											2013-01-23 00:26:31 -06:00
										 |  |  |         dep_f = dep.to_formula | 
					
						
							| 
									
										
										
										
											2014-02-28 23:04:37 -06:00
										 |  |  |       rescue TapFormulaUnavailableError | 
					
						
							|  |  |  |         # Don't complain about missing cross-tap dependencies | 
					
						
							|  |  |  |         next | 
					
						
							| 
									
										
										
										
											2013-04-06 22:10:43 -05:00
										 |  |  |       rescue FormulaUnavailableError | 
					
						
							| 
									
										
										
										
											2013-02-02 00:54:32 -06:00
										 |  |  |         problem "Can't find dependency #{dep.name.inspect}." | 
					
						
							| 
									
										
										
										
											2013-06-26 18:08:54 -05:00
										 |  |  |         next | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2010-08-08 10:17:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-23 00:26:31 -06:00
										 |  |  |       dep.options.reject do |opt| | 
					
						
							| 
									
										
										
										
											2014-02-16 22:35:14 +00:00
										 |  |  |         next true if dep_f.build.has_option?(opt.name) | 
					
						
							|  |  |  |         dep_f.requirements.detect do |r| | 
					
						
							|  |  |  |           if r.tags.include? :recommended | 
					
						
							|  |  |  |             opt.name == "with-#{r.name}" | 
					
						
							|  |  |  |           elsif r.tags.include? :optional | 
					
						
							|  |  |  |             opt.name == "without-#{r.name}" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2013-01-23 00:26:31 -06:00
										 |  |  |       end.each do |opt| | 
					
						
							|  |  |  |         problem "Dependency #{dep} does not define option #{opt.name.inspect}" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case dep.name | 
					
						
							| 
									
										
										
										
											2013-04-06 22:11:02 -05:00
										 |  |  |       when *BUILD_TIME_DEPS | 
					
						
							| 
									
										
										
										
											2013-11-04 12:00:06 -06:00
										 |  |  |         next if dep.build? or dep.run? | 
					
						
							| 
									
										
										
										
											2013-06-27 21:11:16 -05:00
										 |  |  |         problem %{#{dep} dependency should be "depends_on '#{dep}' => :build"} | 
					
						
							| 
									
										
										
										
											2013-06-04 11:15:30 -05:00
										 |  |  |       when "git", "ruby", "emacs", "mercurial" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |         problem <<-EOS.undent
 | 
					
						
							| 
									
										
										
										
											2013-01-23 00:26:31 -06:00
										 |  |  |           Don't use #{dep} as a dependency. We allow non-Homebrew | 
					
						
							|  |  |  |           #{dep} installations. | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |           EOS | 
					
						
							|  |  |  |       when 'gfortran' | 
					
						
							| 
									
										
										
										
											2013-06-23 20:40:00 -07:00
										 |  |  |         problem "Use `depends_on :fortran` instead of `depends_on 'gfortran'`" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       when 'open-mpi', 'mpich2' | 
					
						
							|  |  |  |         problem <<-EOS.undent
 | 
					
						
							|  |  |  |           There are multiple conflicting ways to install MPI. Use an MPIDependency: | 
					
						
							| 
									
										
										
										
											2013-06-26 22:08:54 -05:00
										 |  |  |             depends_on :mpi => [<lang list>] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |           Where <lang list> is a comma delimited list that can include: | 
					
						
							| 
									
										
										
										
											2013-06-26 22:08:54 -05:00
										 |  |  |             :cc, :cxx, :f77, :f90 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |           EOS | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-09-13 15:16:09 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-03 11:22:31 -08:00
										 |  |  |   def audit_conflicts | 
					
						
							| 
									
										
										
										
											2013-06-09 13:44:59 -05:00
										 |  |  |     f.conflicts.each do |c| | 
					
						
							| 
									
										
										
										
											2013-01-03 11:22:31 -08:00
										 |  |  |       begin | 
					
						
							| 
									
										
										
										
											2014-02-24 20:23:21 -08:00
										 |  |  |         Formulary.factory(c.name) | 
					
						
							| 
									
										
										
										
											2013-02-17 22:54:27 -06:00
										 |  |  |       rescue FormulaUnavailableError | 
					
						
							| 
									
										
										
										
											2013-06-09 13:44:59 -05:00
										 |  |  |         problem "Can't find conflicting formula #{c.name.inspect}." | 
					
						
							| 
									
										
										
										
											2013-01-03 11:22:31 -08:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-08-07 15:23:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit_urls | 
					
						
							|  |  |  |     unless f.homepage =~ %r[^https?://] | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |       problem "The homepage should start with http or https (url is #{f.homepage})." | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check for http:// GitHub homepage urls, https:// is preferred. | 
					
						
							|  |  |  |     # Note: only check homepages that are repo pages, not *.github.com hosts | 
					
						
							|  |  |  |     if f.homepage =~ %r[^http://github\.com/] | 
					
						
							|  |  |  |       problem "Use https:// URLs for homepages on GitHub (url is #{f.homepage})." | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-10-08 20:11:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Google Code homepages should end in a slash | 
					
						
							|  |  |  |     if f.homepage =~ %r[^https?://code\.google\.com/p/[^/]+[^/]$] | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |       problem "Google Code homepage should end with a slash (url is #{f.homepage})." | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-10-30 08:26:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-06 22:10:33 -05:00
										 |  |  |     urls = @specs.map(&:url) | 
					
						
							| 
									
										
										
										
											2010-10-21 07:51:47 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Check GNU urls; doesn't apply to mirrors | 
					
						
							| 
									
										
										
										
											2013-05-27 18:31:18 -05:00
										 |  |  |     urls.grep(%r[^(?:https?|ftp)://(?!alpha).+/gnu/]) do |u| | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |       problem "\"ftpmirror.gnu.org\" is preferred for GNU software (url is #{u})." | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-03-21 12:54:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # the rest of the checks apply to mirrors as well | 
					
						
							| 
									
										
										
										
											2013-04-06 22:10:33 -05:00
										 |  |  |     urls.concat(@specs.map(&:mirrors).flatten) | 
					
						
							| 
									
										
										
										
											2011-11-18 15:22:04 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Check SourceForge urls | 
					
						
							|  |  |  |     urls.each do |p| | 
					
						
							| 
									
										
										
										
											2013-07-12 23:00:08 -07:00
										 |  |  |       # Skip if the URL looks like a SVN repo | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       next if p =~ %r[/svnroot/] | 
					
						
							|  |  |  |       next if p =~ %r[svn\.sourceforge] | 
					
						
							| 
									
										
										
										
											2011-12-08 22:16:19 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       # Is it a sourceforge http(s) URL? | 
					
						
							| 
									
										
										
										
											2014-02-26 21:51:46 +01:00
										 |  |  |       next unless p =~ %r[^https?://.*\b(sourceforge|sf)\.(com|net)] | 
					
						
							| 
									
										
										
										
											2011-12-08 22:16:19 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       if p =~ /(\?|&)use_mirror=/ | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |         problem "Don't use #{$1}use_mirror in SourceForge urls (url is #{p})." | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-06-17 17:59:30 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       if p =~ /\/download$/ | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |         problem "Don't use /download in SourceForge urls (url is #{p})." | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-06-17 18:01:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-30 12:07:18 -07:00
										 |  |  |       if p =~ %r[^https?://sourceforge\.] | 
					
						
							|  |  |  |         problem "Use http://downloads.sourceforge.net to get geolocation (url is #{p})." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if p =~ %r[^https?://prdownloads\.] | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |         problem "Don't use prdownloads in SourceForge urls (url is #{p}).\n" + | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |                 "\tSee: http://librelist.com/browser/homebrew/2011/1/12/prdownloads-is-bad/" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2010-08-09 11:59:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       if p =~ %r[^http://\w+\.dl\.] | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |         problem "Don't use specific dl mirrors in SourceForge urls (url is #{p})." | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-02-26 21:51:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if p.start_with? "http://downloads" | 
					
						
							|  |  |  |         problem "Use https:// URLs for downloads from SourceForge (url is #{p})." | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-09-09 14:16:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-05 02:13:00 -05:00
										 |  |  |     # Check for Google Code download urls, https:// is preferred | 
					
						
							|  |  |  |     urls.grep(%r[^http://.*\.googlecode\.com/files.*]) do |u| | 
					
						
							|  |  |  |       problem "Use https:// URLs for downloads from Google Code (url is #{u})." | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |     # Check for git:// GitHub repo urls, https:// is preferred. | 
					
						
							| 
									
										
										
										
											2013-05-27 18:31:18 -05:00
										 |  |  |     urls.grep(%r[^git://[^/]*github\.com/]) do |u| | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |       problem "Use https:// URLs for accessing GitHub repositories (url is #{u})." | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-02-03 14:54:18 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |     # Check for http:// GitHub repo urls, https:// is preferred. | 
					
						
							| 
									
										
										
										
											2013-05-27 18:31:18 -05:00
										 |  |  |     urls.grep(%r[^http://github\.com/.*\.git$]) do |u| | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  |       problem "Use https:// URLs for accessing GitHub repositories (url is #{u})." | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-03-10 10:46:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-15 15:18:22 -07:00
										 |  |  |     # Use new-style archive downloads | 
					
						
							| 
									
										
										
										
											2014-03-25 16:14:03 +00:00
										 |  |  |     urls.select { |u| u =~ %r[https://.*github.*/(?:tar|zip)ball/] && u !~ %r[\.git$] }.each do |u| | 
					
						
							| 
									
										
										
										
											2013-03-15 15:18:22 -07:00
										 |  |  |       problem "Use /archive/ URLs for GitHub tarballs (url is #{u})." | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-03-06 21:15:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Don't use GitHub .zip files | 
					
						
							|  |  |  |     urls.select { |u| u =~ %r[https://.*github.*/(archive|releases)/.*\.zip$] && u !~ %r[releases/download] }.each do |u| | 
					
						
							|  |  |  |       problem "Use GitHub tarballs rather than zipballs (url is #{u})." | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-03-15 21:40:09 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit_specs | 
					
						
							|  |  |  |     problem "Head-only (no stable download)" if f.head_only? | 
					
						
							| 
									
										
										
										
											2012-01-25 22:41:53 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-18 18:50:23 -05:00
										 |  |  |     %w[Stable Devel HEAD].each do |name| | 
					
						
							|  |  |  |       next unless spec = f.send(name.downcase) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  |       ra = ResourceAuditor.new(spec).audit | 
					
						
							| 
									
										
										
										
											2013-09-18 18:50:23 -05:00
										 |  |  |       problems.concat ra.problems.map { |problem| "#{name}: #{problem}" } | 
					
						
							| 
									
										
										
										
											2013-09-18 18:22:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       spec.resources.each_value do |resource| | 
					
						
							| 
									
										
										
										
											2013-09-18 18:50:23 -05:00
										 |  |  |         ra = ResourceAuditor.new(resource).audit | 
					
						
							|  |  |  |         problems.concat ra.problems.map { |problem| | 
					
						
							|  |  |  |           "#{name} resource #{resource.name.inspect}: #{problem}" | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-09-18 18:22:00 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-03-13 19:51:23 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       spec.patches.select(&:external?).each { |p| audit_patch(p) } | 
					
						
							| 
									
										
										
										
											2013-05-27 22:24:22 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-11-30 13:14:24 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit_patches | 
					
						
							| 
									
										
										
										
											2014-03-13 19:51:23 -05:00
										 |  |  |     patches = Patch.normalize_legacy_patches(f.patches) | 
					
						
							|  |  |  |     patches.grep(LegacyPatch).each { |p| audit_patch(p) } | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_patch(patch) | 
					
						
							|  |  |  |     case patch.url | 
					
						
							| 
									
										
										
										
											2014-03-19 18:21:14 -05:00
										 |  |  |     when %r[raw\.github\.com], %r[gist\.github\.com/raw], %r[gist\.github\.com/.+/raw], | 
					
						
							|  |  |  |       %r[gist\.githubusercontent\.com/.+/raw] | 
					
						
							| 
									
										
										
										
											2014-03-13 19:51:23 -05:00
										 |  |  |       unless patch.url =~ /[a-fA-F0-9]{40}/ | 
					
						
							|  |  |  |         problem "GitHub/Gist patches should specify a revision:\n#{patch.url}" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-03-13 19:51:23 -05:00
										 |  |  |     when %r[macports/trunk] | 
					
						
							|  |  |  |       problem "MacPorts patches should specify a revision instead of trunk:\n#{patch.url}" | 
					
						
							| 
									
										
										
										
											2010-09-09 14:16:05 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-09-09 14:16:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 23:15:22 -05:00
										 |  |  |   def audit_text | 
					
						
							| 
									
										
										
										
											2014-02-25 07:36:47 -08:00
										 |  |  |     if text =~ /system\s+['"]scons/ | 
					
						
							| 
									
										
										
										
											2014-02-25 20:51:16 -08:00
										 |  |  |       problem "use \"scons *args\" instead of \"system 'scons', *args\"" | 
					
						
							| 
									
										
										
										
											2014-02-25 07:36:47 -08:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-27 21:47:38 -06:00
										 |  |  |     if text =~ /system\s+['"]xcodebuild/ | 
					
						
							|  |  |  |       problem %{use "xcodebuild *args" instead of "system 'xcodebuild', *args"} | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if text =~ /xcodebuild[ (]["'*]/ && text !~ /SYMROOT=/ | 
					
						
							|  |  |  |       problem %{xcodebuild should be passed an explicit "SYMROOT"} | 
					
						
							| 
									
										
										
										
											2013-07-16 23:15:22 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-02-24 20:23:21 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if text =~ /Formula\.factory\(/ | 
					
						
							|  |  |  |       problem "\"Formula.factory(name)\" is deprecated in favor of \"Formula[name]\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-07-16 23:15:22 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_line(line) | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /<(Formula|AmazonWebServicesFormula|ScriptFileFormula|GithubGistFormula)/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use a space in class inheritance: class Foo < #{$1}" | 
					
						
							| 
									
										
										
										
											2010-09-09 14:16:05 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Commented-out cmake support from default template | 
					
						
							| 
									
										
										
										
											2013-07-16 21:39:46 -05:00
										 |  |  |     if line =~ /# system "cmake/ | 
					
						
							| 
									
										
										
										
											2013-01-04 09:30:57 -08:00
										 |  |  |       problem "Commented cmake call found" | 
					
						
							| 
									
										
										
										
											2010-09-09 14:16:05 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-03 09:20:41 -07:00
										 |  |  |     # Comments from default template | 
					
						
							| 
									
										
										
										
											2013-07-16 21:39:46 -05:00
										 |  |  |     if line =~ /# PLEASE REMOVE/ | 
					
						
							| 
									
										
										
										
											2013-07-05 12:05:29 -07:00
										 |  |  |       problem "Please remove default template comments" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-07-16 21:39:46 -05:00
										 |  |  |     if line =~ /# if this fails, try separate make\/make install steps/ | 
					
						
							| 
									
										
										
										
											2013-07-03 09:20:41 -07:00
										 |  |  |       problem "Please remove default template comments" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-07-16 21:39:46 -05:00
										 |  |  |     if line =~ /# if your formula requires any X11\/XQuartz components/ | 
					
						
							| 
									
										
										
										
											2013-07-05 12:05:29 -07:00
										 |  |  |       problem "Please remove default template comments" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-07-16 21:39:46 -05:00
										 |  |  |     if line =~ /# if your formula's build system can't parallelize/ | 
					
						
							| 
									
										
										
										
											2013-07-03 09:20:41 -07:00
										 |  |  |       problem "Please remove default template comments" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # FileUtils is included in Formula | 
					
						
							| 
									
										
										
										
											2013-12-04 20:07:27 -08:00
										 |  |  |     # encfs modifies a file with this name, so check for some leading characters | 
					
						
							|  |  |  |     if line =~ /[^'"\/]FileUtils\.(\w+)/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Don't need 'FileUtils.' before #{$1}." | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-09-09 14:16:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Check for long inreplace block vars | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /inreplace .* do \|(.{2,})\|/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"inreplace <filenames> do |s|\" is preferred over \"|#{$1}|\"." | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-01-25 22:41:53 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Check for string interpolation of single values. | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /(system|inreplace|gsub!|change_make_var!).*[ ,]"#\{([\w.]+)\}"/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Don't need to interpolate \"#{$2}\" with #{$1}" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-01-25 22:41:53 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Check for string concatenation; prefer interpolation | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /(#\{\w+\s*\+\s*['"][^}]+\})/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Try not to concatenate paths in string interpolation:\n   #{$1}" | 
					
						
							| 
									
										
										
										
											2012-04-05 21:12:02 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-01-25 22:41:53 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Prefer formula path shortcuts in Pathname+ | 
					
						
							| 
									
										
										
										
											2014-03-21 20:07:56 -05:00
										 |  |  |     if line =~ %r{\(\s*(prefix\s*\+\s*(['"])(bin|include|libexec|lib|sbin|share|Frameworks)[/'"])} | 
					
						
							|  |  |  |       problem "\"(#{$1}...#{$2})\" should be \"(#{$3.downcase}+...)\"" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-06-18 19:58:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r[((man)\s*\+\s*(['"])(man[1-8])(['"]))] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"#{$4}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-04-05 21:12:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Prefer formula path shortcuts in strings | 
					
						
							| 
									
										
										
										
											2014-03-21 20:07:56 -05:00
										 |  |  |     if line =~ %r[(\#\{prefix\}/(bin|include|libexec|lib|sbin|share|Frameworks))] | 
					
						
							|  |  |  |       problem "\"#{$1}\" should be \"\#{#{$2.downcase}}\"" | 
					
						
							| 
									
										
										
										
											2012-04-05 21:12:02 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-01-25 22:41:53 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r[((\#\{prefix\}/share/man/|\#\{man\}/)(man[1-8]))] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"\#{#{$3}}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-01-25 22:41:53 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r[((\#\{share\}/(man)))[/'"]] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"\#{#{$3}}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-21 11:55:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r[(\#\{prefix\}/share/(info|man))] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"\#{#{$2}}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-21 11:55:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Commented-out depends_on | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /#\s*depends_on\s+(.+)\s*$/ | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Commented-out dep #{$1}" | 
					
						
							| 
									
										
										
										
											2010-09-07 09:23:29 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # No trailing whitespace, please | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /[\t ]+$/ | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Trailing whitespace was found" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-21 11:55:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /if\s+ARGV\.include\?\s+'--(HEAD|devel)'/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use \"if ARGV.build_#{$1.downcase}?\" instead" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /make && make/ | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Use separate make calls" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /^[ ]*\t/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use spaces instead of tabs for indentation" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-05-31 13:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /ENV\.x11/ | 
					
						
							| 
									
										
										
										
											2012-09-03 19:18:58 -07:00
										 |  |  |       problem "Use \"depends_on :x11\" instead of \"ENV.x11\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     # Avoid hard-coding compilers | 
					
						
							| 
									
										
										
										
											2014-03-06 21:15:05 +00:00
										 |  |  |     if line =~ %r{(system|ENV\[.+\]\s?=)\s?['"](/usr/bin/)?(gcc|llvm-gcc|clang)['" ]} | 
					
						
							|  |  |  |       problem "Use \"\#{ENV.cc}\" instead of hard-coding \"#{$3}\"" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-08-10 11:52:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r{(system|ENV\[.+\]\s?=)\s?['"](/usr/bin/)?((g|llvm-g|clang)\+\+)['" ]} | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use \"\#{ENV.cxx}\" instead of hard-coding \"#{$3}\"" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-02-20 15:03:15 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-05 07:53:53 -08:00
										 |  |  |     if line =~ /system\s+['"](env|export)(\s+|['"])/ | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use ENV instead of invoking '#{$1}' to modify the environment" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-01-22 22:32:15 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /version == ['"]HEAD['"]/ | 
					
						
							| 
									
										
										
										
											2012-08-22 20:59:43 -07:00
										 |  |  |       problem "Use 'build.head?' instead of inspecting 'version'" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-06 20:40:15 +00:00
										 |  |  |     if line =~ /build\.include\?[\s\(]+['"]\-\-(.*)['"]/ | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Reference '#{$1}' without dashes" | 
					
						
							| 
									
										
										
										
											2012-08-25 09:36:01 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-06 20:40:15 +00:00
										 |  |  |     if line =~ /build\.include\?[\s\(]+['"]with(out)?-(.*)['"]/ | 
					
						
							|  |  |  |       problem "Use build.with#{$1}? \"#{$2}\" instead of build.include? 'with#{$1}-#{$2}'" | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-06 20:40:15 +00:00
										 |  |  |     if line =~ /build\.with\?[\s\(]+['"]-?-?with-(.*)['"]/ | 
					
						
							|  |  |  |       problem "Don't duplicate 'with': Use `build.with? \"#{$1}\"` to check for \"--with-#{$1}\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /build\.without\?[\s\(]+['"]-?-?without-(.*)['"]/ | 
					
						
							|  |  |  |       problem "Don't duplicate 'without': Use `build.without? \"#{$1}\"` to check for \"--without-#{$1}\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-21 06:08:18 -04:00
										 |  |  |     if line =~ /unless build\.with\?(.*)/ | 
					
						
							|  |  |  |       problem "Use if build.without?#{$1} instead of unless build.with?#{$1}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /unless build\.without\?(.*)/ | 
					
						
							|  |  |  |       problem "Use if build.with?#{$1} instead of unless build.without?#{$1}" | 
					
						
							| 
									
										
										
										
											2014-03-06 20:40:15 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /(not\s|!)\s*build\.with?\?/ | 
					
						
							|  |  |  |       problem "Don't negate 'build.without?': use 'build.with?'" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /(not\s|!)\s*build\.without?\?/ | 
					
						
							|  |  |  |       problem "Don't negate 'build.with?': use 'build.without?'" | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-06 21:15:05 +00:00
										 |  |  |     if line =~ /ARGV\.(?!(debug\?|verbose\?|value[\(\s]))/ | 
					
						
							|  |  |  |       # Python formulae need ARGV for Requirements | 
					
						
							|  |  |  |       problem "Use build instead of ARGV to check options", | 
					
						
							|  |  |  |               :whitelist => %w{pygobject3 qscintilla2} | 
					
						
							| 
									
										
										
										
											2012-08-22 20:59:43 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /def options/ | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "Use new-style option definitions" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-09-04 18:18:14 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /MACOS_VERSION/ | 
					
						
							| 
									
										
										
										
											2012-09-04 18:18:14 -05:00
										 |  |  |       problem "Use MacOS.version instead of MACOS_VERSION" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-09-10 16:40:13 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-06 22:11:26 -05:00
										 |  |  |     cats = %w{leopard snow_leopard lion mountain_lion}.join("|") | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /MacOS\.(?:#{cats})\?/ | 
					
						
							| 
									
										
										
										
											2013-04-06 22:11:26 -05:00
										 |  |  |       problem "\"#{$&}\" is deprecated, use a comparison to MacOS.version instead" | 
					
						
							| 
									
										
										
										
											2012-09-10 16:40:13 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /skip_clean\s+:all/ | 
					
						
							| 
									
										
										
										
											2014-02-23 12:09:28 -08:00
										 |  |  |       problem "`skip_clean :all` is deprecated; brew no longer strips symbols\n" + | 
					
						
							|  |  |  |               "\tPass explicit paths to prevent Homebrew from removing empty folders." | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-01-27 14:27:32 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /depends_on [A-Z][\w:]+\.new$/ | 
					
						
							| 
									
										
										
										
											2013-04-06 22:11:26 -05:00
										 |  |  |       problem "`depends_on` can take requirement classes instead of instances" | 
					
						
							| 
									
										
										
										
											2013-01-27 14:27:32 -08:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-04-22 15:06:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /^def (\w+).*$/ | 
					
						
							| 
									
										
										
										
											2013-04-22 15:06:42 -05:00
										 |  |  |       problem "Define method #{$1.inspect} in the class body, not at the top-level" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-23 20:40:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /ENV.fortran/ | 
					
						
							| 
									
										
										
										
											2013-06-23 20:40:00 -07:00
										 |  |  |       problem "Use `depends_on :fortran` instead of `ENV.fortran`" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /depends_on :(.+) (if.+|unless.+)$/ | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |       audit_conditional_dep($1.to_sym, $2, $&) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /depends_on ['"](.+)['"] (if.+|unless.+)$/ | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |       audit_conditional_dep($1, $2, $&) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-03-29 09:16:27 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if line =~ /(Dir\[("[^\*{},]+")\])/ | 
					
						
							|  |  |  |       problem "#{$1} is unnecessary; just use #{$2}" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_conditional_dep(dep, condition, line) | 
					
						
							| 
									
										
										
										
											2013-07-23 11:21:37 -05:00
										 |  |  |     quoted_dep = quote_dep(dep) | 
					
						
							|  |  |  |     dep = Regexp.escape(dep.to_s) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |     case condition | 
					
						
							|  |  |  |     when /if build\.include\? ['"]with-#{dep}['"]$/, /if build\.with\? ['"]#{dep}['"]$/ | 
					
						
							| 
									
										
										
										
											2013-07-23 11:21:37 -05:00
										 |  |  |       problem %{Replace #{line.inspect} with "depends_on #{quoted_dep} => :optional"} | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |     when /unless build\.include\? ['"]without-#{dep}['"]$/, /unless build\.without\? ['"]#{dep}['"]$/ | 
					
						
							| 
									
										
										
										
											2013-07-23 11:21:37 -05:00
										 |  |  |       problem %{Replace #{line.inspect} with "depends_on #{quoted_dep} => :recommended"} | 
					
						
							| 
									
										
										
										
											2013-07-16 20:38:50 -05:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def quote_dep(dep) | 
					
						
							|  |  |  |     Symbol === dep ? dep.inspect : "'#{dep}'" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-08-09 11:59:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  |   def audit_check_output warning_and_description | 
					
						
							|  |  |  |     return unless warning_and_description | 
					
						
							| 
									
										
										
										
											2013-09-07 17:38:15 +01:00
										 |  |  |     warning, description = *warning_and_description | 
					
						
							|  |  |  |     problem "#{warning}\n#{description}" | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_installed | 
					
						
							|  |  |  |     audit_check_output(check_manpages) | 
					
						
							|  |  |  |     audit_check_output(check_infopages) | 
					
						
							|  |  |  |     audit_check_output(check_jars) | 
					
						
							|  |  |  |     audit_check_output(check_non_libraries) | 
					
						
							|  |  |  |     audit_check_output(check_non_executables(f.bin)) | 
					
						
							| 
									
										
										
										
											2013-11-10 12:51:24 -08:00
										 |  |  |     audit_check_output(check_generic_executables(f.bin)) | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  |     audit_check_output(check_non_executables(f.sbin)) | 
					
						
							| 
									
										
										
										
											2013-11-10 12:51:24 -08:00
										 |  |  |     audit_check_output(check_generic_executables(f.sbin)) | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit | 
					
						
							|  |  |  |     audit_file | 
					
						
							|  |  |  |     audit_specs | 
					
						
							|  |  |  |     audit_urls | 
					
						
							|  |  |  |     audit_deps | 
					
						
							| 
									
										
										
										
											2013-01-03 11:22:31 -08:00
										 |  |  |     audit_conflicts | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     audit_patches | 
					
						
							| 
									
										
										
										
											2013-07-16 23:15:22 -05:00
										 |  |  |     audit_text | 
					
						
							|  |  |  |     text.each_line { |line| audit_line(line) } | 
					
						
							| 
									
										
										
										
											2013-07-15 19:29:08 -07:00
										 |  |  |     audit_installed | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-11-09 13:00:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   private | 
					
						
							| 
									
										
										
										
											2011-05-31 13:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-06 21:15:05 +00:00
										 |  |  |   def problem p, options={} | 
					
						
							|  |  |  |     return if options[:whitelist].to_a.include? f.name | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     @problems << p | 
					
						
							| 
									
										
										
										
											2010-06-23 11:20:47 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ResourceAuditor | 
					
						
							|  |  |  |   attr_reader :problems | 
					
						
							|  |  |  |   attr_reader :version, :checksum, :using, :specs, :url | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def initialize(resource) | 
					
						
							|  |  |  |     @version  = resource.version | 
					
						
							|  |  |  |     @checksum = resource.checksum | 
					
						
							|  |  |  |     @url      = resource.url | 
					
						
							|  |  |  |     @using    = resource.using | 
					
						
							|  |  |  |     @specs    = resource.specs | 
					
						
							|  |  |  |     @problems = [] | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit | 
					
						
							|  |  |  |     audit_version | 
					
						
							|  |  |  |     audit_checksum | 
					
						
							|  |  |  |     audit_download_strategy | 
					
						
							|  |  |  |     self | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_version | 
					
						
							| 
									
										
										
										
											2013-11-26 20:35:07 -06:00
										 |  |  |     if version.nil? | 
					
						
							|  |  |  |       problem "missing version" | 
					
						
							|  |  |  |     elsif version.to_s.empty? | 
					
						
							|  |  |  |       problem "version is set to an empty string" | 
					
						
							| 
									
										
										
										
											2013-09-18 18:08:50 -05:00
										 |  |  |     elsif not 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 =~ /^v/ | 
					
						
							|  |  |  |       problem "version #{version} should not have a leading 'v'" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_checksum | 
					
						
							|  |  |  |     return unless checksum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case checksum.hash_type | 
					
						
							|  |  |  |     when :md5 | 
					
						
							|  |  |  |       problem "MD5 checksums are deprecated, please use SHA1 or SHA256" | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     when :sha1   then len = 40
 | 
					
						
							|  |  |  |     when :sha256 then len = 64
 | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if checksum.empty? | 
					
						
							|  |  |  |       problem "#{checksum.hash_type} is empty" | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       problem "#{checksum.hash_type} should be #{len} characters" unless checksum.hexdigest.length == len | 
					
						
							|  |  |  |       problem "#{checksum.hash_type} contains invalid characters" unless checksum.hexdigest =~ /^[a-fA-F0-9]+$/ | 
					
						
							|  |  |  |       problem "#{checksum.hash_type} should be lowercase" unless checksum.hexdigest == checksum.hexdigest.downcase | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def audit_download_strategy | 
					
						
							|  |  |  |     return unless using | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     url_strategy   = DownloadStrategyDetector.detect(url) | 
					
						
							|  |  |  |     using_strategy = DownloadStrategyDetector.detect('', using) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if url_strategy == using_strategy | 
					
						
							|  |  |  |       problem "redundant :using specification in URL" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def problem text | 
					
						
							|  |  |  |     @problems << text | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |