diff --git a/Library/Homebrew/cmd/versions.rb b/Library/Homebrew/cmd/versions.rb index 15a0a77800..38d9720b2a 100644 --- a/Library/Homebrew/cmd/versions.rb +++ b/Library/Homebrew/cmd/versions.rb @@ -3,89 +3,64 @@ require 'formula' module Homebrew extend self module Versions - - # The commit SHA for a specific version of a formula - def self.sha_for name, version - shas_for(name).each do |sha| - return sha if version == version_for(name, sha) - end - - nil - end - - # All SHAs of the commits the named formula has been changed in - def self.shas_for name - `git --git-dir=#{HOMEBREW_REPOSITORY}/.git rev-list HEAD^ -- Library/Formula/#{name}.rb`.split - end - - # Returns the version number for the named formula and the given commit SHA - def self.version_for name, sha - code = `git --git-dir=#{HOMEBREW_REPOSITORY}/.git show #{sha}:Library/Formula/#{name}.rb` - version = code.match(/class #{Formula.class_s name} < ?Formula.*?(?:version\s|@version\s*=)\s*(?:'|")(.+?)(?:'|").*?end\s/m) - if version.nil? - url = code.match(/class #{Formula.class_s name} < ?Formula.*?(?:url\s|@url\s*=)\s*(?:'|")(.+?)(?:'|").*?end\s/m) - if url.nil? - head = code.match(/class #{Formula.class_s name} < ?Formula.*?head\s'(.*?)'.*?end\s\s/m) - if head.nil? - opoo "Version of #{name} could not be determined for #{sha}." - nil - else - 'HEAD' - end - else - Pathname.new(url[1]).version - end - else - version[1] - end - end - - # All older versions of a formula together with the SHA of their most recent - # revision - def self.old_versions(formula) - old_versions = [] - - shas_for(formula.name).each do |sha| - old_version = version_for formula.name, sha - - if old_version != formula.version && - (old_versions.empty? || old_version != old_versions.last[0]) - old_versions << [old_version, sha] + # yields version, sha for all versions in the git history + def self.old_versions f + yielded = [] + f.rev_list.each do |sha| + version = f.version_for_sha sha + unless yielded.include? version + yield version, sha + yielded << version end end - - old_versions end - end def versions - puts "Listing older versions for: #{ARGV.formulae.join(', ')}" - - puts <<-EOS.undent - - If you want to install one of these old versions run `git reset --hard - $COMMIT_ID_OF_VERSION` in "#{HOMEBREW_REPOSITORY}". After that you can install the formula - like usual with `brew install formula`. When you're done use `git reset --hard - master@{1}` in "#{HOMEBREW_REPOSITORY}" to get back to the most recent versions again. - - WARNING: This also reverts Homebrew itself to an old revision. This may lead to - broken installations and/or not being able to install an old formula at all. - EOS + raise "Please `brew install git` first" unless system "/usr/bin/which -s git" ARGV.formulae.all? do |f| - old_versions = Versions.old_versions f - - if old_versions.empty? - puts "\nThere are no older versions for \"#{f.name}\" (current: #{f.version})." - else - puts "\nOlder versions for \"#{f.name}\" (current: #{f.version}):\n" - - max_size = 0 - old_versions.each { |v| max_size = v[0].size if v[0].size > max_size } - old_versions.each { |v| puts ' %s (%s)' % [v[0].ljust(max_size), v[1]] } + old_versions = Versions.old_versions f do |version, sha| + print Tty.white + print "#{version.ljust(8)} " + print Tty.reset + puts "git checkout #{sha} #{HOMEBREW_REPOSITORY}/Library/Formula/#{name}.rb" end end end end + + +class Formula + def rev_list + Dir.chdir HOMEBREW_REPOSITORY do + `git rev-list --abbrev-commit HEAD Library/Formula/#{name}.rb`.split + end + end + + def sha_for_version version + revlist.find{ |sha| version == version_for(sha) } + end + + def version_for_sha sha + # TODO really we should open a new ruby instance and parse the formula + # class and then get the version but this would be too slow (?) + + code = Dir.chdir(HOMEBREW_REPOSITORY) do + `git show #{sha}:Library/Formula/#{name}.rb` + end + + version = code.match(/class #{Formula.class_s name} < ?Formula.*?(?:version\s|@version\s*=)\s*(?:'|")(.+?)(?:'|").*?end\s/m) + return version[1] unless version.nil? + + url = code.match(/class #{Formula.class_s name} < ?Formula.*?(?:url\s|@url\s*=)\s*(?:'|")(.+?)(?:'|").*?end\s/m) + return Pathname.new(url[1]).version unless url.nil? + + head = code.match(/class #{Formula.class_s name} < ?Formula.*?head\s'(.*?)'.*?end\s\s/m) + return 'HEAD' unless head.nil? + + opoo "Version of #{name} could not be determined for #{sha}." + end + +end