aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/descriptions.rb
blob: 804fc39cdc5e47b625381c9bf1b9ce80cf275bd5 (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
124
125
126
127
128
129
130
require "formula"
require "formula_versions"

class Descriptions
  CACHE_FILE = HOMEBREW_CACHE + "desc_cache.json"

  def self.cache
    @cache || self.load_cache
  end

  # If the cache file exists, load it into, and return, a hash; otherwise,
  # return nil.
  def self.load_cache
    if CACHE_FILE.exist?
      @cache = Utils::JSON.load(CACHE_FILE.read)
    end
  end

  # Write the cache to disk after ensuring the existence of the containing
  # directory.
  def self.save_cache
    HOMEBREW_CACHE.mkpath
    CACHE_FILE.atomic_write Utils::JSON.dump(@cache)
  end

  # Create a hash mapping all formulae to their descriptions;
  # save it for future use.
  def self.generate_cache
    @cache = {}
    Formula.each do |f|
      @cache[f.full_name] = f.desc
    end
    self.save_cache
  end

  # Return true if the cache exists, and none of the Taps
  # repos were updated more recently than it was.
  def self.cache_fresh?
    return false unless CACHE_FILE.exist?

    Tap.each do |tap|
      next unless tap.git?
      repo_mtime = File.mtime(tap.path/".git/refs/heads/master")
      return false if repo_mtime > cache_mtime
    end

    true
  end

  # Create the cache if it doesn't already exist.
  def self.ensure_cache
    self.generate_cache unless self.cache_fresh? && self.cache
  end

  # Take a {Report}, as generated by cmd/update.rb.
  # Unless the cache file exists, do nothing.
  # If it does exist, but the Report is empty, just touch the cache file.
  # Otherwise, use the report to update the cache.
  def self.update_cache(report)
    if CACHE_FILE.exist?
      if report.empty?
        FileUtils.touch CACHE_FILE
      else
        renamings = report.select_formula(:R)
        alterations = report.select_formula(:A) + report.select_formula(:M) +
                      renamings.map(&:last)
        self.cache_formulae(alterations, :save => false)
        self.uncache_formulae(report.select_formula(:D) +
                              renamings.map(&:first))
      end
    end
  end

  # Given an array of formula names, add them and their descriptions to the
  # cache. Save the updated cache to disk, unless explicitly told not to.
  def self.cache_formulae(formula_names, options = { :save => true })
    if self.cache
      formula_names.each do |name|
        begin
          desc = Formulary.factory(name).desc
        rescue FormulaUnavailableError, *FormulaVersions::IGNORED_EXCEPTIONS
        end
        @cache[name] = desc
      end
      self.save_cache if options[:save]
    end
  end

  # Given an array of formula names, remove them and their descriptions from
  # the cache. Save the updated cache to disk, unless explicitly told not to.
  def self.uncache_formulae(formula_names, options = { :save => true })
    if self.cache
      formula_names.each { |name| @cache.delete(name) }
      self.save_cache if options[:save]
    end
  end

  # Given a regex, find all formulae whose specified fields contain a match.
  def self.search(regex, field = :either)
    self.ensure_cache

    results = case field
    when :name
      @cache.select { |name, _| name =~ regex }
    when :desc
      @cache.select { |_, desc| desc =~ regex }
    when :either
      @cache.select { |name, desc| (name =~ regex) || (desc =~ regex) }
    end

    results = Hash[results] if RUBY_VERSION <= "1.8.7"

    new(results)
  end

  # Create an actual instance.
  def initialize(descriptions)
    @descriptions = descriptions
  end

  # Take search results -- a hash mapping formula names to descriptions -- and
  # print them.
  def print
    blank = "#{Tty.yellow}[no description]#{Tty.reset}"
    @descriptions.keys.sort.each do |name|
      description = @descriptions[name] || blank
      puts "#{Tty.white}#{name}:#{Tty.reset} #{description}"
    end
  end
end