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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
require "formula"
require "formula_versions"
require "csv"
class Descriptions
CACHE_FILE = HOMEBREW_CACHE + "desc_cache"
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 = {}
CSV.foreach(CACHE_FILE) { |name, desc| @cache[name] = desc }
@cache
end
end
# Write the cache to disk after ensuring the existence of the containing
# directory.
def self.save_cache
HOMEBREW_CACHE.mkpath
CSV.open(CACHE_FILE, 'w') do |csv|
@cache.each do |name, desc|
csv << [name, desc]
end
end
end
# Create a hash mapping all formulae to their descriptions;
# save it for future use.
def self.generate_cache
@cache = {}
Formula.map do |f|
@cache[f.full_name] = f.desc
end
self.save_cache
end
# Return true if the cache exists, and neither Homebrew nor any of the Taps
# repos were updated more recently than it was.
def self.cache_fresh?
return false unless CACHE_FILE.exist?
cache_mtime = File.mtime(CACHE_FILE)
ref_master = ".git/refs/heads/master"
master = HOMEBREW_REPOSITORY/ref_master
# If ref_master doesn't exist, it means brew update is never run.
# Since cache is found, we can assume it's fresh.
if master.exist?
core_mtime = File.mtime(master)
return false if core_mtime > cache_mtime
end
Tap.each do |tap|
next unless tap.git?
repo_mtime = File.mtime(tap.path/ref_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 an array of formula names, return a {Descriptions} object mapping
# those names to their descriptions.
def self.named(names)
self.ensure_cache
results = {}
unless names.empty?
results = names.inject({}) do |accum, name|
accum[name] = @cache[name]
accum
end
end
new(results)
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
|