aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/cmd/versions.rb
blob: b634e24a87af219c879f09d73da2d0acdaa331a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
require 'formula'

module Homebrew extend self
  def versions
    raise "Please `brew install git` first" unless which "git"
    raise "Please `brew update' first" unless (HOMEBREW_REPOSITORY/".git").directory?

    raise FormulaUnspecifiedError if ARGV.named.empty?

    opoo <<-EOS.undent
      brew-versions is unsupported and may be removed soon.
      Please use the homebrew-versions tap instead:
        https://github.com/Homebrew/homebrew-versions
    EOS
    ARGV.formulae.all? do |f|
      if ARGV.include? '--compact'
        puts f.versions * " "
      else
        relative_path = f.pretty_relative_path
        f.versions do |version, sha|
          print Tty.white.to_s
          print "#{version.to_s.ljust(8)} "
          print Tty.reset.to_s
          puts "git checkout #{sha} #{relative_path}"
        end
      end
    end
  end
end


class Formula
  def versions
    versions = []
    rev_list do |sha|
      version = version_for_sha sha
      unless versions.include? version or version.nil?
        yield version, sha if block_given?
        versions << version
      end
    end
    return versions
  end

  def bottle_version_map branch='HEAD'
    map = Hash.new { |h, k| h[k] = [] }
    rev_list(branch) do |rev|
      formula_for_sha(rev) do |f|
        bottle = f.stable.bottle_specification
        unless bottle.checksums.empty?
          map[f.pkg_version] << bottle.revision
        end
      end
    end
    map
  end

  def pretty_relative_path
    if Pathname.pwd == repository
      entry_name
    else
      path
    end
  end

  private
    def repository
      @repository ||= begin
        if path.to_s =~ HOMEBREW_TAP_DIR_REGEX
          HOMEBREW_REPOSITORY/"Library/Taps/#$1/#$2"
        else
          HOMEBREW_REPOSITORY
        end
      end
    end

    def entry_name
      @entry_name ||= path.relative_path_from(repository).to_s
    end

    def rev_list branch='HEAD'
      repository.cd do
        IO.popen("git rev-list --abbrev-commit --remove-empty #{branch} -- #{entry_name}") do |io|
          yield io.readline.chomp until io.eof?
        end
      end
    end

    def text_from_sha sha
      repository.cd do
        `git cat-file blob #{sha}:#{entry_name}`
      end
    end

    IGNORED_EXCEPTIONS = [SyntaxError, TypeError, NameError,
                          ArgumentError, FormulaSpecificationError,
                          FormulaValidationError,]

    def version_for_sha sha
      formula_for_sha(sha) {|f| f.version }
    end

    def formula_for_sha sha, &block
      mktemp do
        path = Pathname.pwd.join("#{name}.rb")
        path.write text_from_sha(sha)

        # Unload the class so Formula#version returns the correct value
        begin
          old_const = Formulary.unload_formula name
          nostdout { yield Formula.factory(path.to_s) }
        rescue *IGNORED_EXCEPTIONS => e
          # We rescue these so that we can skip bad versions and
          # continue walking the history
          ohai "#{e} in #{name} at revision #{sha}", e.backtrace if ARGV.debug?
        rescue FormulaUnavailableError
          # Suppress this error
        ensure
          Formulary.restore_formula name, old_const
        end
      end
    end
end