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
|
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)
Tab.new :used_options => build.used_options.as_flags,
:unused_options => build.unused_options.as_flags,
:tabfile => formula.prefix.join(FILENAME),
:built_as_bottle => !!ARGV.build_bottle?,
:poured_from_bottle => false,
:tapped_from => formula.tap,
:time => Time.now.to_i,
:HEAD => Homebrew.git_head,
:compiler => compiler,
:stdlib => stdlib
end
def self.from_file path
attributes = Utils::JSON.load(File.read(path))
attributes[:tabfile] = path
new(attributes)
end
def self.for_keg keg
path = keg.join(FILENAME)
if path.exist?
from_file(path)
else
dummy_tab
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
tab
else
dummy_tab(f)
end
end
def self.dummy_tab f=nil
Tab.new :used_options => [],
:unused_options => (f.options.as_flags rescue []),
:built_as_bottle => false,
:poured_from_bottle => false,
:tapped_from => "",
:time => nil,
:HEAD => nil,
:stdlib => nil,
:compiler => :clang
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 to_json
Utils::JSON.dump({
:used_options => used_options.as_flags,
:unused_options => unused_options.as_flags,
:built_as_bottle => built_as_bottle,
:poured_from_bottle => poured_from_bottle,
:tapped_from => tapped_from,
:time => time,
:HEAD => self.HEAD,
:stdlib => (stdlib.to_s if stdlib),
:compiler => (compiler.to_s if compiler)})
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
|