diff options
| author | Max Howell | 2010-09-11 20:22:54 +0100 |
|---|---|---|
| committer | Adam Vandenberg | 2011-03-12 11:55:02 -0800 |
| commit | 9afc85ad338f9e053fe36127937d308ad62593bc (patch) | |
| tree | 610d3c0ae869d9e58e283f065c914566316ddd8c /bin | |
| parent | f57463eee6333f8dbeb42a122290677d6c755871 (diff) | |
| download | homebrew-9afc85ad338f9e053fe36127937d308ad62593bc.tar.bz2 | |
Refactor the brew command into one file per command
The code was sucking. To the extent that maintenance was hard. It's a lot
easier to work with code that is sensibly split at sensible boundaries. So
now it is more like that.
But the refactor is minimal. Because we don't want you to have more merge
hell than absolutely necessary.
If you merge you will need to pay attention to brew.h.rb (as it is deleted)
and bin/brew (as command logic is gone). It will be painful, but you will just
have to help git out by moving any changes around manually.
Note compatibility.rb. It ensures that any function renames or removals don't
break anything. We're pretty serious about backwards compatibility. And that's
because we encourage you to hack around with the innards. And we couldn't do
that if we would then just make stuff disappear behind your back.
Diffstat (limited to 'bin')
| -rwxr-xr-x | bin/brew | 345 |
1 files changed, 42 insertions, 303 deletions
@@ -38,313 +38,48 @@ if MACOS_VERSION < 10.5 abort "Homebrew requires Leopard or higher. For Tiger support, see:\nhttp://github.com/sceaga/homebrew/tree/tiger" end -def dump_config - require 'hardware' - sha = `cd #{HOMEBREW_REPOSITORY} && git rev-parse --verify HEAD 2> /dev/null`.chomp - sha = "(none)" if sha.empty? - bits = Hardware.bits - cores = Hardware.cores_as_words - kernel_arch = `uname -m`.chomp - system_ruby = Pathname.new("/usr/bin/ruby") - - llvm, llvm_msg = _compiler_recommendation llvm_build, RECOMMENDED_LLVM - gcc_42, gcc_42_msg = _compiler_recommendation gcc_42_build, RECOMMENDED_GCC_42 - gcc_40, gcc_40_msg = _compiler_recommendation gcc_40_build, RECOMMENDED_GCC_40 - xcode = xcode_version || "?" - - puts <<-EOS -HOMEBREW_VERSION: #{HOMEBREW_VERSION} -HEAD: #{sha} -HOMEBREW_PREFIX: #{HOMEBREW_PREFIX} -HOMEBREW_CELLAR: #{HOMEBREW_CELLAR} -HOMEBREW_REPOSITORY: #{HOMEBREW_REPOSITORY} -HOMEBREW_LIBRARY_PATH: #{HOMEBREW_LIBRARY_PATH} -Hardware: #{cores}-core #{bits}-bit #{Hardware.intel_family} -OS X: #{MACOS_FULL_VERSION} -Kernel Architecture: #{kernel_arch} -Ruby: #{RUBY_VERSION}-#{RUBY_PATCHLEVEL} -/usr/bin/ruby => #{system_ruby.realpath} -Xcode: #{xcode} -GCC-4.0: #{gcc_40 ? "build #{gcc_40}" : "N/A"} #{gcc_42_msg} -GCC-4.2: #{gcc_42 ? "build #{gcc_42}" : "N/A"} #{gcc_40_msg} -LLVM: #{llvm ? "build #{llvm}" : "N/A" } #{llvm_msg} -MacPorts or Fink? #{macports_or_fink_installed?} -X11 installed? #{x11_installed?} -EOS +def require? path + require path.to_s.chomp +rescue LoadError => e + # HACK :( because we should raise on syntax errors but + # not if the file doesn't exist. TODO make robust! + raise unless e.to_s.include? path end begin - require 'brew.h' - - case arg = ARGV.shift - when '--cache' - if ARGV.named.empty? - puts HOMEBREW_CACHE - else - puts ARGV.formulae.collect {|f| f.cached_download} - end - when '--prefix' - if ARGV.named.empty? - puts HOMEBREW_PREFIX - else - puts ARGV.formulae.collect {|f| f.prefix} - end - when '--repository' - puts HOMEBREW_REPOSITORY - when '--cellar' - if ARGV.named.empty? - puts HOMEBREW_CELLAR - else - puts ARGV.formulae.collect {|f| HOMEBREW_CELLAR+f.name} - end - when '--config' - dump_config - when '--env' - require 'hardware' - require 'extend/ENV' - ENV.extend(HomebrewEnvExtension) - ENV.setup_build_environment - dump_build_env ENV - - when 'home', 'homepage' - if ARGV.named.empty? - exec "open", HOMEBREW_WWW - else - exec "open", *ARGV.formulae.collect {|f| f.homepage} - end - - when 'ls', 'list' - if ARGV.flag? '--unbrewed' - dirs = HOMEBREW_PREFIX.children.select { |pn| pn.directory? }.collect { |pn| pn.basename.to_s } - dirs -= ['Library', 'Cellar', '.git'] - Dir.chdir HOMEBREW_PREFIX - exec 'find', *dirs + %w[-type f ( ! -iname .ds_store ! -iname brew )] - elsif ARGV.flag? '--versions' - if ARGV.named.empty? - to_list = HOMEBREW_CELLAR.children.select { |pn| pn.directory? } - else - to_list = ARGV.named.collect { |n| HOMEBREW_CELLAR+n }.select { |pn| pn.exist? } - end - to_list.each do |d| - versions = d.children.select { |pn| pn.directory? }.collect { |pn| pn.basename.to_s } - puts "#{d.basename} #{versions *' '}" - end - elsif ARGV.named.empty? - ENV['CLICOLOR']=nil - exec 'ls', *ARGV.options_only<<HOMEBREW_CELLAR if HOMEBREW_CELLAR.exist? - elsif ARGV.verbose? or not $stdout.tty? - exec "find", *ARGV.kegs+%w[-not -type d -print] - else - ARGV.kegs.each { |keg| PrettyListing.new keg } - end - - when 'search', '-S' - if ARGV.include? '--macports' - exec "open", "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}" - elsif ARGV.include? '--fink' - exec "open", "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}" - end - - check_for_blacklisted_formula(ARGV.named) - puts_columns search_brews(ARGV.first) - - when 'edit' - if ARGV.named.empty? - # EDITOR isn't a good fit here, we need a GUI client that actually has - # a UI for projects, so apologies if this wasn't what you expected, - # please improve it! :) - exec 'mate', *Dir["#{HOMEBREW_REPOSITORY}/Library/*"]<< - "#{HOMEBREW_REPOSITORY}/bin/brew"<< - "#{HOMEBREW_REPOSITORY}/README.md" - else - require 'formula' - # Don't use ARGV.formulae as that will throw if the file doesn't parse - paths = ARGV.named.collect do |name| - path = Formula.path(Formula.resolve_alias(name)) - unless File.exist? path - raise FormulaUnavailableError, name - else - path - end - end - exec_editor(*paths) - end - - when 'up', 'update' - abort "Please `brew install git' first." unless system "/usr/bin/which -s git" - - require 'update' - updater = RefreshBrew.new - unless updater.update_from_masterbrew! - puts "Already up-to-date." - else - updater.report - end - - when 'ln', 'link' - ARGV.kegs.each {|keg| puts "#{keg.link} links created for #{keg}"} - - when 'unlink' - ARGV.kegs.each {|keg| puts "#{keg.unlink} links removed for #{keg}"} - - when 'rm', 'uninstall', 'remove' - if ARGV.flag? "--force" - require 'formula' - ARGV.formulae.each do |f| - formula_cellar = f.prefix.parent - next unless File.exist? formula_cellar - puts "Uninstalling #{f.name}..." - formula_cellar.children do |k| - keg = Keg.new(k) - keg.unlink - end - - formula_cellar.rmtree - end - else - begin - ARGV.kegs.each do |keg| - puts "Uninstalling #{keg}..." - keg.unlink - keg.uninstall - end - rescue MultipleVersionsInstalledError => e - onoe e - puts "Use `brew remove --force #{e.name}` to remove all versions." - end - end - - when 'prune' - prune - - when 'create' - if ARGV.include? '--macports' - exec "open", "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}" - elsif ARGV.include? '--fink' - exec "open", "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}" - elsif ARGV.named.empty? - raise UsageError - else - exec_editor(*ARGV.named.collect {|name| make name}) - end - - when 'diy', 'configure' - puts diy - - when 'info', 'abv' - if ARGV.named.empty? - if ARGV.include? "--all" - require 'formula' - Formula.all.each do |f| - info f - puts '---' - end - else - puts `ls #{HOMEBREW_CELLAR} | wc -l`.strip+" kegs, "+HOMEBREW_CELLAR.abv - end - elsif ARGV[0][0..6] == 'http://' or ARGV[0][0..7] == 'https://' or ARGV[0][0..5] == 'ftp://' - path = Pathname.new(ARGV.shift) - /(.*?)[-_.]?#{path.version}/.match path.basename - unless $1.to_s.empty? - name = $1 - else - name = path.stem - end - puts "#{name} #{path.version}" - else - ARGV.formulae.each{ |f| info f } - end - - when 'cleanup' - if ARGV.named.empty? - require 'formula' - HOMEBREW_CELLAR.children.each do |rack| - begin - cleanup(rack.basename.to_s) if rack.directory? - rescue FormulaUnavailableError => e - opoo "Formula not found for #{e.name}" - end - end - prune # seems like a good time to do some additional cleanup - else - ARGV.named.each { |name| cleanup name} - end - - when 'install' - check_for_blacklisted_formula(ARGV.named) - brew_install - - when 'log' - Dir.chdir HOMEBREW_REPOSITORY - args = ARGV.options_only - args += ARGV.formulae.map{ |formula| formula.path } unless ARGV.named.empty? - exec "git", "log", *args - - # For each formula given, show which other formulas depend on it. - # We only go one level up, ie. direct dependencies. - when 'uses' - uses = ARGV.formulae.map{ |f| Formula.all.select{ |ff| ff.deps.include? f.name }.map{|f| f.name} }.flatten.uniq - if ARGV.include? "--installed" - uses = uses.select { |f| f = HOMEBREW_CELLAR+f; f.directory? and not f.subdirs.empty? } - end - puts uses.sort - - when 'deps' - if ARGV.include?('--all') - require 'formula' - Formula.all.each do |f| - puts "#{f.name}:#{f.deps.join(' ')}" - end - elsif ARGV.include?("-1") or ARGV.include?("--1") - puts ARGV.formulae.map {|f| f.deps or []}.flatten.uniq.sort - else - require 'formula_installer' - puts ARGV.formulae.map {|f| FormulaInstaller.expand_deps(f).map {|f| f.name} }.flatten.uniq.sort - end - - when 'cat' - Dir.chdir HOMEBREW_REPOSITORY - exec "cat", ARGV.formulae.first.path, *ARGV.options_only - - when 'outdated' - outdated_brews.each do |keg, name, version| - if $stdout.tty? and not ARGV.flag? '--quiet' - versions = keg.cd{ Dir['*'] }.join(', ') - puts "#{name} (#{versions} < #{version})" - else - puts name - end + aliases = {'ls' => :list, + 'homepage' => :home, + '-S' => :search, + 'up' => :update, + 'ln' => :link, + 'rm' => :uninstall, + 'remove' => :uninstall, + 'configure' => :diy, + 'abv' => :info, + 'dr' => :doctor, + '--repo' => '--repository'} + + cmd = ARGV.shift + cmd = aliases[cmd] if aliases[cmd] + + # Add example external commands to PATH before checking. + ENV['PATH'] += ":#{HOMEBREW_REPOSITORY}/Library/Contributions/examples" + + if system "/usr/bin/which -s brew-#{cmd}" + %w[CACHE CELLAR LIBRARY_PATH PREFIX REPOSITORY].each do |e| + ENV["HOMEBREW_#{e}"] = eval "HOMEBREW_#{e}" end - - when 'doctor', 'dr' - require 'brew_doctor' - brew_doctor - + exec "brew-#{cmd}", *ARGV + elsif require? `/usr/bin/which brew-#{cmd}.rb` + exit 0 + elsif require? HOMEBREW_REPOSITORY/"Library/Homebrew/cmd"/cmd + Homebrew.send cmd.to_s.gsub('-', '_') else - # Add example external commands to PATH before checking. - ENV['PATH'] += ":#{HOMEBREW_REPOSITORY}/Library/Contributions/examples" - - # Check for an external shell command - if system "/usr/bin/which -s brew-#{arg}" - # Add some Homebrew vars to the ENV - %w(CACHE CELLAR LIBRARY_PATH PREFIX REPOSITORY).each do |e| - ENV["HOMEBREW_#{e}"] = eval("HOMEBREW_#{e}") - end - exec("brew-#{arg}", *ARGV) - end - - # Check for an external ruby command - external_rb = `/usr/bin/which brew-#{arg}.rb`.chomp - unless external_rb.empty? - require external_rb - exit 0 - end - # Check for git commands - if %w(branch checkout pull push rebase reset).include? arg - onoe "Unknown command '#{arg}' (did you mean 'git #{arg}'?)" + if %w[branch checkout pull push rebase reset].include? cmd + onoe "Unknown command: #{cmd} (did you mean `git #{cmd}'?)" else - onoe "Unknown command '#{arg}'" + onoe "Unknown command: #{cmd}" end end @@ -362,24 +97,28 @@ rescue Interrupt => e puts # seemingly a newline is typical exit 130 rescue BuildError => e + require 'cmd/--config' + require 'cmd/--env' + e.backtrace[1] =~ %r{Library/Formula/(.+)\.rb:(\d+)} formula_name = $1 error_line = $2 + puts "Exit status: #{e.exit_status}" puts puts "http://github.com/mxcl/homebrew/blob/master/Library/Formula/#{formula_name}.rb#L#{error_line}" puts ohai "Environment" - dump_config + puts Homebrew.config_s puts ohai "Build Flags" - dump_build_env e.env + Homebrew.dump_build_env e.env onoe e puts PLEASE_REPORT_BUG # this feature can be slow (depends on network conditions and if github is up) # so ideally we'd show feedback, eg. "checking for existing issues..." and # then replace that string with the following when the github api returns - issues = issues_for_formula(formula_name) + issues = GitHub.issues_for_formula formula_name puts "These existing issues may help you:", *issues unless issues.empty? if e.was_running_configure? puts "It looks like an autotools configure failed." |
