PageRenderTime 158ms CodeModel.GetById 28ms RepoModel.GetById 2ms app.codeStats 0ms

/Library/Homebrew/brew.h.rb

https://github.com/alkesh/homebrew
Ruby | 549 lines | 402 code | 79 blank | 68 comment | 49 complexity | 148194938679ff74e4648fd7e2ec2e08 MD5 | raw file
  1. # Copyright 2009 Max Howell and other contributors.
  2. #
  3. # Redistribution and use in source and binary forms, with or without
  4. # modification, are permitted provided that the following conditions
  5. # are met:
  6. #
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # 2. Redistributions in binary form must reproduce the above copyright
  10. # notice, this list of conditions and the following disclaimer in the
  11. # documentation and/or other materials provided with the distribution.
  12. #
  13. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  14. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15. # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  16. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  17. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  18. # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  19. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  20. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  22. # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. #
  24. FORMULA_META_FILES = %w[README README.md ChangeLog COPYING LICENSE LICENCE COPYRIGHT AUTHORS]
  25. PLEASE_REPORT_BUG = "#{Tty.white}Please report this bug at #{Tty.em}http://github.com/mxcl/homebrew/issues#{Tty.reset}"
  26. def check_for_blacklisted_formula names
  27. return if ARGV.force?
  28. names.each do |name|
  29. case name
  30. # bazaar don't maintain their PyPi entry properly yet
  31. # when they do we'll remove our formula and use that
  32. # when 'bazaar', 'bzr' then abort <<-EOS
  33. #Bazaar can be installed thusly:
  34. #
  35. # brew install pip && pip install bzr==2.0.1
  36. #
  37. # EOS
  38. when 'mercurial', 'hg' then abort <<-EOS
  39. Mercurial can be install thusly:
  40. brew install pip && pip install mercurial
  41. EOS
  42. end
  43. end
  44. end
  45. def __make url, name
  46. require 'formula'
  47. path = Formula.path name
  48. raise "#{path} already exists" if path.exist?
  49. # Check if a formula aliased to this name exists.
  50. already_aka = Formulary.find_alias name
  51. if already_aka != nil
  52. opoo "Formula #{already_aka} is aliased to #{name}."
  53. puts "Please check if you are creating a duplicate."
  54. end
  55. template=<<-EOS
  56. require 'formula'
  57. class #{Formula.class_s name} <Formula
  58. url '#{url}'
  59. homepage ''
  60. md5 ''
  61. cmake depends_on 'cmake'
  62. def install
  63. autotools system "./configure", "--prefix=\#{prefix}", "--disable-debug", "--disable-dependency-tracking"
  64. cmake system "cmake . \#{std_cmake_parameters}"
  65. system "make install"
  66. end
  67. end
  68. EOS
  69. mode=nil
  70. if ARGV.include? '--cmake'
  71. mode= :cmake
  72. elsif ARGV.include? '--autotools'
  73. mode= :autotools
  74. end
  75. f=File.new path, 'w'
  76. template.each_line do |s|
  77. if s.strip.empty?
  78. f.puts
  79. next
  80. end
  81. cmd=s[0..11].strip
  82. if cmd.empty?
  83. cmd=nil
  84. else
  85. cmd=cmd.to_sym
  86. end
  87. out=s[12..-1] || ''
  88. if mode.nil?
  89. # we show both but comment out cmake as it is less common
  90. # the implication being the pacakger should remove whichever is not needed
  91. if cmd == :cmake and not out.empty?
  92. f.print '#'
  93. out = out[1..-1]
  94. end
  95. elsif cmd != mode and not cmd.nil?
  96. next
  97. end
  98. f.puts out
  99. end
  100. f.close
  101. return path
  102. end
  103. def make url
  104. path = Pathname.new url
  105. /(.*?)[-_.]?#{path.version}/.match path.basename
  106. unless $1.to_s.empty?
  107. name = $1
  108. else
  109. print "Formula name [#{path.stem}]: "
  110. gots = $stdin.gets.chomp
  111. if gots.empty?
  112. name = path.stem
  113. else
  114. name = gots
  115. end
  116. end
  117. force_text = "If you really want to make this formula use --force."
  118. case name.downcase
  119. when /libxml/, /libxlst/, /freetype/, /libpng/, /wxwidgets/
  120. raise <<-EOS
  121. #{name} is blacklisted for creation
  122. Apple distributes this library with OS X, you can find it in /usr/X11/lib.
  123. However not all build scripts look here, so you may need to call ENV.x11 or
  124. ENV.libxml2 in your formula's install function.
  125. #{force_text}
  126. EOS
  127. when /rubygem/
  128. raise "Sorry RubyGems comes with OS X so we don't package it.\n\n#{force_text}"
  129. when /wxwidgets/
  130. raise <<-EOS
  131. #{name} is blacklisted for creation
  132. An older version of wxWidgets is provided by Apple with OS X, but
  133. a formula for wxWidgets 2.8.10 is provided:
  134. brew install wxmac
  135. #{force_text}
  136. EOS
  137. end unless ARGV.force?
  138. __make url, name
  139. end
  140. def github_info name
  141. formula_name = Formula.path(name).basename
  142. user = ''
  143. branch = ''
  144. if system "/usr/bin/which -s git"
  145. user=`git config --global github.user`.chomp
  146. all_branches = `git branch 2>/dev/null`
  147. /^\*\s*(.*)/.match all_branches
  148. branch = ($1 || '').chomp
  149. end
  150. user = 'mxcl' if user.empty?
  151. branch = 'master' if user.empty?
  152. return "http://github.com/#{user}/homebrew/commits/#{branch}/Library/Formula/#{formula_name}"
  153. end
  154. def info name
  155. require 'formula'
  156. exec 'open', github_info(name) if ARGV.flag? '--github'
  157. f=Formula.factory name
  158. puts "#{f.name} #{f.version}"
  159. puts f.homepage
  160. puts "Depends on: #{f.deps.join(', ')}" unless f.deps.empty?
  161. if f.prefix.parent.directory?
  162. kids=f.prefix.parent.children
  163. kids.each do |keg|
  164. print "#{keg} (#{keg.abv})"
  165. print " *" if f.prefix == keg and kids.length > 1
  166. puts
  167. end
  168. else
  169. puts "Not installed"
  170. end
  171. if f.caveats
  172. puts
  173. puts f.caveats
  174. puts
  175. end
  176. history = github_info(name)
  177. puts history if history
  178. rescue FormulaUnavailableError
  179. # check for DIY installation
  180. d=HOMEBREW_PREFIX+name
  181. if d.directory?
  182. ohai "DIY Installation"
  183. d.children.each {|keg| puts "#{keg} (#{keg.abv})"}
  184. else
  185. raise "No such formula or keg"
  186. end
  187. end
  188. def issues_for_formula name
  189. # bit basic as depends on the issue at github having the exact name of the
  190. # formula in it. Which for stuff like objective-caml is unlikely. So we
  191. # really should search for aliases too.
  192. name = f.name if Formula === name
  193. require 'open-uri'
  194. require 'yaml'
  195. issues = []
  196. open("http://github.com/api/v2/yaml/issues/search/mxcl/homebrew/open/"+name) do |f|
  197. YAML::load(f.read)['issues'].each do |issue|
  198. issues << 'http://github.com/mxcl/homebrew/issues/#issue/%s' % issue['number']
  199. end
  200. end
  201. issues
  202. rescue
  203. []
  204. end
  205. def cleanup name
  206. require 'formula'
  207. f = Formula.factory name
  208. # we can't tell which one to keep in this circumstance
  209. raise "The most recent version of #{name} is not installed" unless f.installed?
  210. if f.prefix.parent.directory?
  211. kids = f.prefix.parent.children
  212. kids.each do |keg|
  213. next if f.prefix == keg
  214. print "Uninstalling #{keg}..."
  215. FileUtils.rm_rf keg
  216. puts
  217. end
  218. end
  219. prune # seems like a good time to do some additional cleanup
  220. end
  221. def clean f
  222. Cleaner.new f
  223. # Hunt for empty folders and nuke them unless they are
  224. # protected by f.skip_clean?
  225. # We want post-order traversal, so put the dirs in a stack
  226. # and then pop them off later.
  227. paths = []
  228. f.prefix.find do |path|
  229. paths << path if path.directory?
  230. end
  231. until paths.empty? do
  232. d = paths.pop
  233. if d.children.empty? and not f.skip_clean? d
  234. puts "rmdir: #{d} (empty)" if ARGV.verbose?
  235. d.rmdir
  236. end
  237. end
  238. end
  239. def prune
  240. $n=0
  241. $d=0
  242. dirs=Array.new
  243. paths=%w[bin sbin etc lib include share].collect {|d| HOMEBREW_PREFIX+d}
  244. paths.each do |path|
  245. path.find do |path|
  246. path.extend ObserverPathnameExtension
  247. if path.symlink?
  248. path.unlink unless path.resolved_path_exists?
  249. elsif path.directory?
  250. dirs<<path
  251. end
  252. end
  253. end
  254. dirs.sort.reverse_each {|d| d.rmdir_if_possible}
  255. if $n == 0 and $d == 0
  256. puts "Nothing pruned" if ARGV.verbose?
  257. else
  258. # always showing symlinks text is deliberate
  259. print "Pruned #{$n} symbolic links "
  260. print "and #{$d} directories " if $d > 0
  261. puts "from #{HOMEBREW_PREFIX}"
  262. end
  263. end
  264. def diy
  265. path=Pathname.getwd
  266. if ARGV.include? '--set-version'
  267. version=ARGV.next
  268. else
  269. version=path.version
  270. raise "Couldn't determine version, try --set-version" if version.nil? or version.empty?
  271. end
  272. if ARGV.include? '--set-name'
  273. name=ARGV.next
  274. else
  275. path.basename.to_s =~ /(.*?)-?#{version}/
  276. if $1.nil? or $1.empty?
  277. name=path.basename
  278. else
  279. name=$1
  280. end
  281. end
  282. prefix=HOMEBREW_CELLAR+name+version
  283. if File.file? 'CMakeLists.txt'
  284. "-DCMAKE_INSTALL_PREFIX=#{prefix}"
  285. elsif File.file? 'Makefile.am'
  286. "--prefix=#{prefix}"
  287. end
  288. end
  289. def macports_or_fink_installed?
  290. # See these issues for some history:
  291. # http://github.com/mxcl/homebrew/issues/#issue/13
  292. # http://github.com/mxcl/homebrew/issues/#issue/41
  293. # http://github.com/mxcl/homebrew/issues/#issue/48
  294. %w[port fink].each do |ponk|
  295. path = `/usr/bin/which -s #{ponk}`
  296. return ponk unless path.empty?
  297. end
  298. # we do the above check because macports can be relocated and fink may be
  299. # able to be relocated in the future. This following check is because if
  300. # fink and macports are not in the PATH but are still installed it can
  301. # *still* break the build -- because some build scripts hardcode these paths:
  302. %w[/sw/bin/fink /opt/local/bin/port].each do |ponk|
  303. return ponk if File.exist? ponk
  304. end
  305. # finally, sometimes people make their MacPorts or Fink read-only so they
  306. # can quickly test Homebrew out, but still in theory obey the README's
  307. # advise to rename the root directory. This doesn't work, many build scripts
  308. # error out when they try to read from these now unreadable directories.
  309. %w[/sw /opt/local].each do |path|
  310. path = Pathname.new(path)
  311. return path if path.exist? and not path.readable?
  312. end
  313. false
  314. end
  315. def versions_of(keg_name)
  316. `/bin/ls #{HOMEBREW_CELLAR}/#{keg_name}`.collect { |version| version.strip }.reverse
  317. end
  318. ########################################################## class PrettyListing
  319. class PrettyListing
  320. def initialize path
  321. Pathname.new(path).children.sort{ |a,b| a.to_s.downcase <=> b.to_s.downcase }.each do |pn|
  322. case pn.basename.to_s
  323. when 'bin', 'sbin'
  324. pn.find { |pnn| puts pnn unless pnn.directory? }
  325. when 'lib'
  326. print_dir pn do |pnn|
  327. # dylibs have multiple symlinks and we don't care about them
  328. (pnn.extname == '.dylib' or pnn.extname == '.pc') and not pnn.symlink?
  329. end
  330. else
  331. if pn.directory?
  332. print_dir pn
  333. elsif not FORMULA_META_FILES.include? pn.basename.to_s
  334. puts pn
  335. end
  336. end
  337. end
  338. end
  339. private
  340. def print_dir root
  341. dirs = []
  342. remaining_root_files = []
  343. other = ''
  344. root.children.sort.each do |pn|
  345. if pn.directory?
  346. dirs << pn
  347. elsif block_given? and yield pn
  348. puts pn
  349. other = 'other '
  350. else
  351. remaining_root_files << pn
  352. end
  353. end
  354. dirs.each do |d|
  355. files = []
  356. d.find { |pn| files << pn unless pn.directory? }
  357. print_remaining_files files, d
  358. end
  359. print_remaining_files remaining_root_files, root, other
  360. end
  361. def print_remaining_files files, root, other = ''
  362. case files.length
  363. when 0
  364. # noop
  365. when 1
  366. puts *files
  367. else
  368. puts "#{root}/ (#{files.length} #{other}files)"
  369. end
  370. end
  371. end
  372. ################################################################ class Cleaner
  373. class Cleaner
  374. def initialize f
  375. @f=f
  376. # correct common issues
  377. share=f.prefix+'share'
  378. (f.prefix+'man').mv share rescue nil
  379. [f.bin, f.sbin, f.lib].each {|d| clean_dir d}
  380. # you can read all of this stuff online nowadays, save the space
  381. # info pages are pants, everyone agrees apart from Richard Stallman
  382. # feel free to ask for build options though! http://bit.ly/Homebrew
  383. unlink = Proc.new{ |path| path.unlink unless f.skip_clean? path rescue nil }
  384. %w[doc docs info].each do |fn|
  385. unlink.call(f.share+fn)
  386. unlink.call(f.prefix+fn)
  387. end
  388. end
  389. private
  390. def strip path, args=''
  391. return if @f.skip_clean? path
  392. puts "strip #{path}" if ARGV.verbose?
  393. path.chmod 0644 # so we can strip
  394. unless path.stat.nlink > 1
  395. system "strip", *(args+path)
  396. else
  397. path = path.to_s.gsub ' ', '\\ '
  398. # strip unlinks the file and recreates it, thus breaking hard links!
  399. # is this expected behaviour? patch does it too still, this fixes it
  400. tmp = `/usr/bin/mktemp -t homebrew_strip`.chomp
  401. begin
  402. `/usr/bin/strip #{args} -o #{tmp} #{path}`
  403. `/bin/cat #{tmp} > #{path}`
  404. ensure
  405. FileUtils.rm tmp
  406. end
  407. end
  408. end
  409. def clean_file path
  410. perms=0444
  411. case `file -h '#{path}'`
  412. when /Mach-O dynamically linked shared library/
  413. # Stripping libraries is causing no end of trouble
  414. # Lets just give up, and try to do it manually in instances where it
  415. # makes sense
  416. #strip path, '-SxX'
  417. when /Mach-O [^ ]* ?executable/
  418. strip path
  419. perms=0555
  420. when /script text executable/
  421. perms=0555
  422. end
  423. path.chmod perms
  424. end
  425. def clean_dir d
  426. d.find do |path|
  427. if path.directory?
  428. Find.prune if @f.skip_clean? path
  429. elsif not path.file?
  430. next
  431. elsif path.extname == '.la' and not @f.skip_clean? path
  432. # *.la files are stupid
  433. path.unlink
  434. elsif not path.symlink?
  435. clean_file path
  436. end
  437. end
  438. end
  439. end
  440. def gcc_build
  441. `/usr/bin/gcc-4.2 -v 2>&1` =~ /build (\d{4,})/
  442. if $1
  443. $1.to_i
  444. elsif system "/usr/bin/which gcc"
  445. # Xcode 3.0 didn't come with gcc-4.2
  446. # We can't change the above regex to use gcc because the version numbers
  447. # are different and thus, not useful.
  448. # FIXME I bet you 20 quid this causes a side effect magic values tend to
  449. 401
  450. else
  451. nil
  452. end
  453. end
  454. def llvm_build
  455. if MACOS_VERSION >= 10.6
  456. `/Developer/usr/bin/llvm-gcc-4.2 -v 2>&1` =~ /LLVM build (\d{4,})/
  457. $1.to_i
  458. end
  459. end
  460. def x11_installed?
  461. Pathname.new('/usr/X11/lib/libpng.dylib').exist?
  462. end