| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											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| | 
					
						
							| 
									
										
										
										
											2013-07-23 10:51:07 -07:00
										 |  |  |         # TODO -- fix for :recommended, should still allow --with-xyz | 
					
						
							| 
									
										
										
										
											2013-01-23 00:26:31 -06:00
										 |  |  |         dep_f.build.has_option?(opt.name) | 
					
						
							|  |  |  |       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-07-16 15:49:11 -05:00
										 |  |  |         next if dep.build? | 
					
						
							|  |  |  |         next if dep.name == 'autoconf' && f.name =~ /automake/ | 
					
						
							|  |  |  |         next if dep.name == 'libtool' && %w{imagemagick libgphoto2 libp11}.any? { |n| f.name == n } | 
					
						
							|  |  |  |         next if dep.name =~ /autoconf|pkg-config/ && f.name == 'ruby-build' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |       when 'python', 'python2', 'python3' | 
					
						
							|  |  |  |         problem <<-EOS.undent
 | 
					
						
							|  |  |  |           Don't use #{dep} as a dependency (string). | 
					
						
							|  |  |  |              We have special `depends_on :python` (or :python2 or :python3 ) | 
					
						
							|  |  |  |              that works with brewed and system Python and allows us to support | 
					
						
							|  |  |  |              bindings for 2.x and 3.x in parallel and much more. | 
					
						
							|  |  |  |           EOS | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       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 | 
					
						
							| 
									
										
										
										
											2013-06-09 13:44:59 -05:00
										 |  |  |         Formula.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? | 
					
						
							|  |  |  |       next unless p =~ %r[^https?://.*\bsourceforge\.] | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2012-03-17 19:49:49 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-09-09 14:16:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2013-07-23 11:21:37 -05:00
										 |  |  |     urls.select { |u| u =~ %r[https://.*/(?: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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-03 14:54:18 -06:00
										 |  |  |     if urls.any? { |u| u =~ /\.xz/ } && !f.deps.any? { |d| d.name == "xz" } | 
					
						
							|  |  |  |       problem "Missing a build-time dependency on 'xz'" | 
					
						
							|  |  |  |     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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |     [:stable, :devel].each do |spec| | 
					
						
							|  |  |  |       s = f.send(spec) | 
					
						
							|  |  |  |       next if s.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if s.version.to_s.empty? | 
					
						
							|  |  |  |         problem "Invalid or missing #{spec} version" | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											2012-07-10 16:10:16 -05:00
										 |  |  |         version_text = s.version unless s.version.detected_from_url? | 
					
						
							| 
									
										
										
										
											2013-06-28 21:17:12 -05:00
										 |  |  |         version_url = Version.detect(s.url, s.specs) | 
					
						
							| 
									
										
										
										
											2013-05-14 20:13:49 -05:00
										 |  |  |         if version_url.to_s == version_text.to_s && s.version.instance_of?(Version) | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |           problem "#{spec} version #{version_text} is redundant with version scanned from URL" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2010-09-29 10:21:44 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-04 08:48:49 -07:00
										 |  |  |       if s.version.to_s =~ /^v/ | 
					
						
							|  |  |  |         problem "#{spec} version #{s.version} should not have a leading 'v'" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       cksum = s.checksum | 
					
						
							|  |  |  |       next if cksum.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-29 15:36:14 -05:00
										 |  |  |       case cksum.hash_type | 
					
						
							|  |  |  |       when :md5 | 
					
						
							|  |  |  |         problem "md5 checksums are deprecated, please use sha1 or sha256" | 
					
						
							|  |  |  |         next | 
					
						
							|  |  |  |       when :sha1   then len = 40
 | 
					
						
							|  |  |  |       when :sha256 then len = 64
 | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if cksum.empty? | 
					
						
							|  |  |  |         problem "#{cksum.hash_type} is empty" | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         problem "#{cksum.hash_type} should be #{len} characters" unless cksum.hexdigest.length == len | 
					
						
							|  |  |  |         problem "#{cksum.hash_type} contains invalid characters" unless cksum.hexdigest =~ /^[a-fA-F0-9]+$/ | 
					
						
							|  |  |  |         problem "#{cksum.hash_type} should be lowercase" unless cksum.hexdigest == cksum.hexdigest.downcase | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2011-11-30 13:14:24 -06:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-05-27 22:24:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Check for :using that is already detected from the url | 
					
						
							|  |  |  |     @specs.each do |s| | 
					
						
							|  |  |  |       next if s.using.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       url_strategy = DownloadStrategyDetector.detect(s.url) | 
					
						
							|  |  |  |       using_strategy = DownloadStrategyDetector.detect('', s.using) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       problem "redundant :using specification in url or head" if url_strategy == using_strategy | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-11-30 13:14:24 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def audit_patches | 
					
						
							| 
									
										
										
										
											2013-05-07 18:39:45 -05:00
										 |  |  |     Patches.new(f.patches).select(&:external?).each do |p| | 
					
						
							|  |  |  |       case p.url | 
					
						
							|  |  |  |       when %r[raw\.github\.com], %r[gist\.github\.com/raw] | 
					
						
							|  |  |  |         unless p.url =~ /[a-fA-F0-9]{40}/ | 
					
						
							|  |  |  |           problem "GitHub/Gist patches should specify a revision:\n#{p.url}" | 
					
						
							| 
									
										
										
										
											2012-09-06 20:47:05 -05:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2013-05-07 18:39:45 -05:00
										 |  |  |       when %r[macports/trunk] | 
					
						
							|  |  |  |         problem "MacPorts patches should specify a revision instead of trunk:\n#{p.url}" | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2013-07-23 11:21:37 -05:00
										 |  |  |     if text =~ /system\s+['"]xcodebuild/ && text !~ /SYMROOT=/ | 
					
						
							| 
									
										
										
										
											2013-07-16 23:15:22 -05:00
										 |  |  |       problem "xcodebuild should be passed an explicit \"SYMROOT\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   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-07-16 21:25:02 -05:00
										 |  |  |     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+ | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r{\(\s*(prefix\s*\+\s*(['"])(bin|include|libexec|lib|sbin|share)[/'"])} | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"(#{$1}...#{$2})\" should be \"(#{$3}+...)\"" | 
					
						
							|  |  |  |     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 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r[(\#\{prefix\}/(bin|include|libexec|lib|sbin|share))] | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "\"#{$1}\" should be \"\#{#{$2}}\"" | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ %r{(system|ENV\[.+\]\s?=)\s?['"](/usr/bin/)?(gcc|llvm-gcc|clang)['" ]} | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |       problem "Use \"\#{ENV.cc}\" instead of hard-coding \"#{$3}\"" | 
					
						
							|  |  |  |     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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /system\s+['"](env|export)/ | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05: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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /build\.with\?\s+['"]-?-?with-(.*)['"]/ | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |       problem "No double 'with': Use `build.with? '#{$1}'` to check for \"--with-#{$1}\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 21:25:02 -05:00
										 |  |  |     if line =~ /build\.without\?\s+['"]-?-?without-(.*)['"]/ | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |       problem "No double 'without': Use `build.without? '#{$1}'` to check for \"--without-#{$1}\"" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-07 11:56:11 -07:00
										 |  |  |     unless f.name == 'mongodb' # Mongo writes out a Ruby script that uses ARGV | 
					
						
							|  |  |  |       if line =~ /ARGV\.(?!(debug\?|verbose\?|value[\(\s]))/ | 
					
						
							|  |  |  |         problem "Use build instead of ARGV to check options" | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											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/ | 
					
						
							| 
									
										
										
										
											2012-09-13 07:14:45 -07:00
										 |  |  |       problem "`skip_clean :all` is deprecated; brew no longer strips symbols" | 
					
						
							|  |  |  |     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 | 
					
						
							|  |  |  |   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-01-21 10:33:56 +01:00
										 |  |  |   def audit_python | 
					
						
							|  |  |  |     if text =~ /(def\s*)?which_python/ | 
					
						
							| 
									
										
										
										
											2013-07-16 11:10:14 +02:00
										 |  |  |       problem "Replace `which_python` by `python.xy`, which returns e.g. 'python2.7'" | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if text =~ /which\(?["']python/ | 
					
						
							|  |  |  |       problem "Don't locate python with `which 'python'`, use `python.binary` instead" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-16 11:10:14 +02:00
										 |  |  |     if text =~ /LanguageModuleDependency.new\s?\(\s?:python/ | 
					
						
							|  |  |  |       problem <<-EOS.undent
 | 
					
						
							|  |  |  |         Python: Replace `LanguageModuleDependency.new(:python,'PyPi-name','module')` | 
					
						
							|  |  |  |            by the new `depends_on :python => ['module' => 'PyPi-name']` | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 16:41:14 +02:00
										 |  |  |     # Checks that apply only to code in def install | 
					
						
							|  |  |  |     if text =~ /(\s*)def\s+install((.*\n)*?)(\1end)/ | 
					
						
							|  |  |  |       install_body = $2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if install_body =~ /system\(?\s*['"]python/ | 
					
						
							| 
									
										
										
										
											2013-07-16 11:10:14 +02:00
										 |  |  |         problem "Instead of `system 'python', ...`, call `system python, ...`" | 
					
						
							| 
									
										
										
										
											2013-06-06 16:41:14 +02:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if text =~ /system\(?\s*python\.binary/ | 
					
						
							| 
									
										
										
										
											2013-07-16 11:10:14 +02:00
										 |  |  |         problem "Instead of `system python.binary, ...`, call `system python, ...`" | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 16:41:14 +02:00
										 |  |  |     # Checks that apply only to code in def caveats | 
					
						
							| 
									
										
										
										
											2013-07-22 22:53:11 -05:00
										 |  |  |     if text =~ /(\s*)def\s+caveats((.*\n)*?)(\1end)/ || text =~ /(\s*)def\s+caveats;(.*?)end/ | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |       caveats_body = $2 | 
					
						
							| 
									
										
										
										
											2013-07-22 22:53:22 -05:00
										 |  |  |       if caveats_body =~ /[ \{=](python[23]?)\.(.*\w)/ | 
					
						
							|  |  |  |         # So if in the body of caveats there is a `python.whatever` called, | 
					
						
							|  |  |  |         # check that there is a guard like `if python` or similiar: | 
					
						
							|  |  |  |         python = $1 | 
					
						
							|  |  |  |         method = $2 | 
					
						
							|  |  |  |         unless caveats_body =~ /(if python[23]?)|(if build\.with\?\s?\(?['"]python)|(unless build.without\?\s?\(?['"]python)/ | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |           problem "Please guard `#{python}.#{method}` like so `#{python}.#{method} if #{python}`" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-03 10:46:06 +02:00
										 |  |  |     unless f.requirements.any?{ |r| r.kind_of?(PythonInstalled) } | 
					
						
							| 
									
										
										
										
											2013-06-06 16:41:14 +02:00
										 |  |  |       # So if there is no PythonInstalled requirement, we can check if the | 
					
						
							|  |  |  |       # formula still uses python and should add a `depends_on :python` | 
					
						
							|  |  |  |       unless f.name.to_s =~ /(pypy[0-9]*)|(python[0-9]*)/ | 
					
						
							|  |  |  |         if text =~ /system.["' ]?python([0-9"'])?/ | 
					
						
							|  |  |  |           problem "If the formula uses Python, it should declare so by `depends_on :python#{$1}`" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         if text =~ /setup\.py/ | 
					
						
							|  |  |  |           problem <<-EOS.undent
 | 
					
						
							|  |  |  |             If the formula installs Python bindings you should declare `depends_on :python[3]`"
 | 
					
						
							|  |  |  |           EOS | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |     # Todo: | 
					
						
							|  |  |  |     # The python do ... end block is possibly executed twice. Once for | 
					
						
							|  |  |  |     # python 2.x and once for 3.x. So if a `system 'make'` is called, a | 
					
						
							|  |  |  |     # `system 'make clean'` should also be called at the end of the block. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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)) | 
					
						
							|  |  |  |     audit_check_output(check_non_executables(f.sbin)) | 
					
						
							|  |  |  |   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-01-21 10:33:56 +01:00
										 |  |  |     audit_python | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 01:37:46 -05:00
										 |  |  |   def problem p | 
					
						
							|  |  |  |     @problems << p | 
					
						
							| 
									
										
										
										
											2010-06-23 11:20:47 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | end |