aboutsummaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorMax Howell2010-09-11 20:22:54 +0100
committerAdam Vandenberg2011-03-12 11:55:02 -0800
commit9afc85ad338f9e053fe36127937d308ad62593bc (patch)
tree610d3c0ae869d9e58e283f065c914566316ddd8c /bin
parentf57463eee6333f8dbeb42a122290677d6c755871 (diff)
downloadhomebrew-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-xbin/brew345
1 files changed, 42 insertions, 303 deletions
diff --git a/bin/brew b/bin/brew
index 4ec64f0a1..645e933e4 100755
--- a/bin/brew
+++ b/bin/brew
@@ -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."