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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
require 'cxxstdlib'
require 'ostruct'
require 'options'
require 'utils/json'
# Inherit from OpenStruct to gain a generic initialization method that takes a
# hash and creates an attribute for each key and value. `Tab.new` probably
# should not be called directly, instead use one of the class methods like
# `Tab.create`.
class Tab < OpenStruct
FILENAME = 'INSTALL_RECEIPT.json'
def self.create(formula, compiler, stdlib, build)
attributes = {
"used_options" => build.used_options.as_flags,
"unused_options" => build.unused_options.as_flags,
"tabfile" => formula.prefix.join(FILENAME),
"built_as_bottle" => build.bottle?,
"poured_from_bottle" => false,
"time" => Time.now.to_i,
"HEAD" => Homebrew.git_head,
"compiler" => compiler,
"stdlib" => stdlib,
"source" => {
"path" => formula.path.to_s,
"tap" => formula.tap,
},
}
new(attributes)
end
def self.from_file path
attributes = Utils::JSON.load(File.read(path))
attributes["tabfile"] = path
attributes["source"] ||= {}
tapped_from = attributes["tapped_from"]
unless tapped_from.nil? || tapped_from == "path or URL"
attributes["source"]["tap"] = attributes.delete("tapped_from")
end
new(attributes)
end
def self.for_keg keg
path = keg.join(FILENAME)
if path.exist?
from_file(path)
else
empty
end
end
def self.for_name name
for_formula(Formulary.factory(name))
end
def self.remap_deprecated_options deprecated_options, options
deprecated_options.each do |deprecated_option|
option = options.find { |o| o.name == deprecated_option.old }
next unless option
options -= [option]
options << Option.new(deprecated_option.current, option.description)
end
options
end
def self.for_formula f
paths = []
if f.opt_prefix.symlink? && f.opt_prefix.directory?
paths << f.opt_prefix.resolved_path
end
if f.linked_keg.symlink? && f.linked_keg.directory?
paths << f.linked_keg.resolved_path
end
if f.rack.directory? && (dirs = f.rack.subdirs).length == 1
paths << dirs.first
end
paths << f.prefix
path = paths.map { |pn| pn.join(FILENAME) }.find(&:file?)
if path
tab = from_file(path)
used_options = remap_deprecated_options(f.deprecated_options, tab.used_options)
tab.used_options = used_options.as_flags
else
tab = empty
tab.unused_options = f.options.as_flags
tab.source = { "path" => f.path.to_s, "tap" => f.tap }
end
tab
end
def self.empty
attributes = {
"used_options" => [],
"unused_options" => [],
"built_as_bottle" => false,
"poured_from_bottle" => false,
"time" => nil,
"HEAD" => nil,
"stdlib" => nil,
"compiler" => "clang",
"source" => {
"path" => nil,
"tap" => nil,
},
}
new(attributes)
end
def with? val
name = val.respond_to?(:option_name) ? val.option_name : val
include?("with-#{name}") || unused_options.include?("without-#{name}")
end
def without? name
not with? name
end
def include? opt
used_options.include? opt
end
def universal?
include?("universal")
end
def cxx11?
include?("c++11")
end
def build_32_bit?
include?("32-bit")
end
def used_options
Options.create(super)
end
def unused_options
Options.create(super)
end
def cxxstdlib
# Older tabs won't have these values, so provide sensible defaults
lib = stdlib.to_sym if stdlib
cc = compiler || MacOS.default_compiler
CxxStdlib.create(lib, cc.to_sym)
end
def build_bottle?
built_as_bottle && !poured_from_bottle
end
def bottle?
built_as_bottle
end
def tap
source["tap"]
end
def to_json
attributes = {
"used_options" => used_options.as_flags,
"unused_options" => unused_options.as_flags,
"built_as_bottle" => built_as_bottle,
"poured_from_bottle" => poured_from_bottle,
"time" => time,
"HEAD" => self.HEAD,
"stdlib" => (stdlib.to_s if stdlib),
"compiler" => (compiler.to_s if compiler),
"source" => source,
}
Utils::JSON.dump(attributes)
end
def write
tabfile.atomic_write(to_json)
end
def to_s
s = []
case poured_from_bottle
when true then s << "Poured from bottle"
when false then s << "Built from source"
end
unless used_options.empty?
s << "Installed" if s.empty?
s << "with:"
s << used_options.to_a.join(", ")
end
s.join(" ")
end
end
|