Class: Tab

Inherits:
OpenStruct show all
Defined in:
Library/Homebrew/tab.rb

Overview

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.

Constant Summary

FILENAME =
"INSTALL_RECEIPT.json".freeze
CACHE =
{}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.clear_cacheObject



15
16
17
# File 'Library/Homebrew/tab.rb', line 15

def self.clear_cache
  CACHE.clear
end

.create(formula, compiler, stdlib) ⇒ Object

Instantiates a Tab for a new installation of a formula.



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
# File 'Library/Homebrew/tab.rb', line 20

def self.create(formula, compiler, stdlib)
  build = formula.build
  attributes = {
    "homebrew_version" => HOMEBREW_VERSION,
    "used_options" => build.used_options.as_flags,
    "unused_options" => build.unused_options.as_flags,
    "tabfile" => formula.prefix.join(FILENAME),
    "built_as_bottle" => build.bottle?,
    "installed_as_dependency" => false,
    "installed_on_request" => true,
    "poured_from_bottle" => false,
    "time" => Time.now.to_i,
    "source_modified_time" => formula.source_modified_time.to_i,
    "HEAD" => HOMEBREW_REPOSITORY.git_head,
    "compiler" => compiler,
    "stdlib" => stdlib,
    "runtime_dependencies" => formula.runtime_dependencies.map do |dep|
      f = dep.to_formula
      { "full_name" => f.full_name, "version" => f.version.to_s }
    end,
    "source" => {
      "path" => formula.specified_path.to_s,
      "tap" => formula.tap ? formula.tap.name : nil,
      "spec" => formula.active_spec_sym.to_s,
      "versions" => {
        "stable" => formula.stable ? formula.stable.version.to_s : nil,
        "devel" => formula.devel ? formula.devel.version.to_s : nil,
        "head" => formula.head ? formula.head.version.to_s : nil,
        "version_scheme" => formula.version_scheme,
      },
    },
  }

  new(attributes)
end

.emptyObject



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
# File 'Library/Homebrew/tab.rb', line 171

def self.empty
  attributes = {
    "homebrew_version" => HOMEBREW_VERSION,
    "used_options" => [],
    "unused_options" => [],
    "built_as_bottle" => false,
    "installed_as_dependency" => false,
    "installed_on_request" => true,
    "poured_from_bottle" => false,
    "time" => nil,
    "source_modified_time" => 0,
    "HEAD" => nil,
    "stdlib" => nil,
    "compiler" => DevelopmentTools.default_compiler,
    "runtime_dependencies" => [],
    "source" => {
      "path" => nil,
      "tap" => nil,
      "spec" => "stable",
      "versions" => {
        "stable" => nil,
        "devel" => nil,
        "head" => nil,
        "version_scheme" => 0,
      },
    },
  }

  new(attributes)
end

.for_formula(f) ⇒ Object

Returns a Tab for an already installed formula, or a fake one if the formula is not installed.



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
# File 'Library/Homebrew/tab.rb', line 128

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 (dirs = f.installed_prefixes).length == 1
    paths << dirs.first
  end

  paths << f.installed_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
    # Formula is not installed. Return a fake tab.
    tab = empty
    tab.unused_options = f.options.as_flags
    tab.source = {
      "path" => f.specified_path.to_s,
      "tap" => f.tap ? f.tap.name : f.tap,
      "spec" => f.active_spec_sym.to_s,
      "versions" => {
        "stable" => f.stable ? f.stable.version.to_s : nil,
        "devel" => f.devel ? f.devel.version.to_s : nil,
        "head" => f.head ? f.head.version.to_s : nil,
        "version_scheme" => f.version_scheme,
      },
    }
  end

  tab
end

.for_keg(keg) ⇒ Object



100
101
102
103
104
105
106
107
108
# File 'Library/Homebrew/tab.rb', line 100

def self.for_keg(keg)
  path = keg.join(FILENAME)

  if path.exist?
    from_file(path)
  else
    empty
  end
end

.for_name(name) ⇒ Object

Returns a tab for the named formula's installation, or a fake one if the formula is not installed.



112
113
114
# File 'Library/Homebrew/tab.rb', line 112

def self.for_name(name)
  for_formula(Formulary.factory(name))
end

.from_file(path) ⇒ Object

Returns the Tab for an install receipt at path. Results are cached.



58
59
60
# File 'Library/Homebrew/tab.rb', line 58

def self.from_file(path)
  CACHE.fetch(path) { |p| CACHE[p] = from_file_content(File.read(p), p) }
end

.from_file_content(content, path) ⇒ Object

Like Tab.from_file, but bypass the cache.



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
# File 'Library/Homebrew/tab.rb', line 63

def self.from_file_content(content, path)
  attributes = JSON.parse(content)
  attributes["tabfile"] = path
  attributes["source_modified_time"] ||= 0
  attributes["source"] ||= {}

  tapped_from = attributes["tapped_from"]
  unless tapped_from.nil? || tapped_from == "path or URL"
    attributes["source"]["tap"] = attributes.delete("tapped_from")
  end

  if attributes["source"]["tap"] == "mxcl/master" ||
     attributes["source"]["tap"] == "Homebrew/homebrew"
    attributes["source"]["tap"] = "homebrew/core"
  end

  if attributes["source"]["spec"].nil?
    version = PkgVersion.parse path.to_s.split("/")[-2]
    if version.head?
      attributes["source"]["spec"] = "head"
    else
      attributes["source"]["spec"] = "stable"
    end
  end

  if attributes["source"]["versions"].nil?
    attributes["source"]["versions"] = {
      "stable" => nil,
      "devel" => nil,
      "head" => nil,
      "version_scheme" => 0,
    }
  end

  new(attributes)
end

.remap_deprecated_options(deprecated_options, options) ⇒ Object



116
117
118
119
120
121
122
123
124
# File 'Library/Homebrew/tab.rb', line 116

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

Instance Method Details

#bottle?Boolean

Returns:

  • (Boolean)


271
272
273
# File 'Library/Homebrew/tab.rb', line 271

def bottle?
  built_as_bottle
end

#build_bottle?Boolean

Returns:

  • (Boolean)


267
268
269
# File 'Library/Homebrew/tab.rb', line 267

def build_bottle?
  built_as_bottle && !poured_from_bottle
end

#compilerObject



246
247
248
# File 'Library/Homebrew/tab.rb', line 246

def compiler
  super || DevelopmentTools.default_compiler
end

#cxx11?Boolean

Returns:

  • (Boolean)


222
223
224
# File 'Library/Homebrew/tab.rb', line 222

def cxx11?
  include?("c++11")
end

#cxxstdlibObject



261
262
263
264
265
# File 'Library/Homebrew/tab.rb', line 261

def cxxstdlib
  # Older tabs won't have these values, so provide sensible defaults
  lib = stdlib.to_sym if stdlib
  CxxStdlib.create(lib, compiler.to_sym)
end

#devel?Boolean

Returns:

  • (Boolean)


230
231
232
# File 'Library/Homebrew/tab.rb', line 230

def devel?
  spec == :devel
end

#devel_versionObject



297
298
299
# File 'Library/Homebrew/tab.rb', line 297

def devel_version
  Version.create(versions["devel"]) if versions["devel"]
end

#head?Boolean

Returns:

  • (Boolean)


226
227
228
# File 'Library/Homebrew/tab.rb', line 226

def head?
  spec == :head
end

#head_versionObject



301
302
303
# File 'Library/Homebrew/tab.rb', line 301

def head_version
  Version.create(versions["head"]) if versions["head"]
end

#include?(opt) ⇒ Boolean

Returns:

  • (Boolean)


214
215
216
# File 'Library/Homebrew/tab.rb', line 214

def include?(opt)
  used_options.include? opt
end

#parsed_homebrew_versionObject



250
251
252
253
# File 'Library/Homebrew/tab.rb', line 250

def parsed_homebrew_version
  return Version::NULL if homebrew_version.nil?
  Version.new(homebrew_version)
end

#runtime_dependenciesObject



255
256
257
258
259
# File 'Library/Homebrew/tab.rb', line 255

def runtime_dependencies
  # Homebrew versions prior to 1.1.6 generated incorrect runtime dependency
  # lists.
  super unless parsed_homebrew_version < "1.1.6"
end

#source_modified_timeObject



309
310
311
# File 'Library/Homebrew/tab.rb', line 309

def source_modified_time
  Time.at(super)
end

#specObject



285
286
287
# File 'Library/Homebrew/tab.rb', line 285

def spec
  source["spec"].to_sym
end

#stable?Boolean

Returns:

  • (Boolean)


234
235
236
# File 'Library/Homebrew/tab.rb', line 234

def stable?
  spec == :stable
end

#stable_versionObject



293
294
295
# File 'Library/Homebrew/tab.rb', line 293

def stable_version
  Version.create(versions["stable"]) if versions["stable"]
end

#tapObject



275
276
277
278
# File 'Library/Homebrew/tab.rb', line 275

def tap
  tap_name = source["tap"]
  Tap.fetch(tap_name) if tap_name
end

#tap=(tap) ⇒ Object



280
281
282
283
# File 'Library/Homebrew/tab.rb', line 280

def tap=(tap)
  tap_name = tap.respond_to?(:name) ? tap.name : tap
  source["tap"] = tap_name
end

#to_jsonObject



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'Library/Homebrew/tab.rb', line 313

def to_json
  attributes = {
    "homebrew_version" => homebrew_version,
    "used_options" => used_options.as_flags,
    "unused_options" => unused_options.as_flags,
    "built_as_bottle" => built_as_bottle,
    "poured_from_bottle" => poured_from_bottle,
    "installed_as_dependency" => installed_as_dependency,
    "installed_on_request" => installed_on_request,
    "changed_files" => changed_files && changed_files.map(&:to_s),
    "time" => time,
    "source_modified_time" => source_modified_time.to_i,
    "HEAD" => self.HEAD,
    "stdlib" => (stdlib.to_s if stdlib),
    "compiler" => (compiler.to_s if compiler),
    "runtime_dependencies" => runtime_dependencies,
    "source" => source,
  }

  JSON.generate(attributes)
end

#to_sObject



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'Library/Homebrew/tab.rb', line 344

def to_s
  s = []
  if poured_from_bottle
    s << "Poured from bottle"
  else
    s << "Built from source"
  end

  s << Time.at(time).strftime("on %Y-%m-%d at %H:%M:%S") if time

  unless used_options.empty?
    s << "with:"
    s << used_options.to_a.join(" ")
  end
  s.join(" ")
end

#universal?Boolean

Returns:

  • (Boolean)


218
219
220
# File 'Library/Homebrew/tab.rb', line 218

def universal?
  include?("universal")
end

#unused_optionsObject



242
243
244
# File 'Library/Homebrew/tab.rb', line 242

def unused_options
  Options.create(super)
end

#used_optionsObject



238
239
240
# File 'Library/Homebrew/tab.rb', line 238

def used_options
  Options.create(super)
end

#version_schemeObject



305
306
307
# File 'Library/Homebrew/tab.rb', line 305

def version_scheme
  versions["version_scheme"] || 0
end

#versionsObject



289
290
291
# File 'Library/Homebrew/tab.rb', line 289

def versions
  source["versions"]
end

#with?(val) ⇒ Boolean

Returns:

  • (Boolean)


202
203
204
205
206
207
208
# File 'Library/Homebrew/tab.rb', line 202

def with?(val)
  option_names = val.respond_to?(:option_names) ? val.option_names : [val]

  option_names.any? do |name|
    include?("with-#{name}") || unused_options.include?("without-#{name}")
  end
end

#without?(val) ⇒ Boolean

Returns:

  • (Boolean)


210
211
212
# File 'Library/Homebrew/tab.rb', line 210

def without?(val)
  !with?(val)
end

#writeObject



335
336
337
338
339
340
341
342
# File 'Library/Homebrew/tab.rb', line 335

def write
  # If this is a new installation, the cache of installed formulae
  # will no longer be valid.
  Formula.clear_installed_formulae_cache unless tabfile.exist?

  CACHE[tabfile] = self
  tabfile.atomic_write(to_json)
end