2015-08-03 13:09:07 +01:00
|
|
|
require "cxxstdlib"
|
|
|
|
require "ostruct"
|
|
|
|
require "options"
|
|
|
|
require "utils/json"
|
2011-09-22 20:07:39 -07:00
|
|
|
|
|
|
|
# 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
|
2013-01-23 00:26:20 -06:00
|
|
|
# `Tab.create`.
|
2011-09-22 20:07:39 -07:00
|
|
|
class Tab < OpenStruct
|
2015-08-03 13:09:07 +01:00
|
|
|
FILENAME = "INSTALL_RECEIPT.json"
|
2015-11-27 16:40:16 +00:00
|
|
|
CACHE = {}
|
|
|
|
|
|
|
|
def self.clear_cache
|
|
|
|
CACHE.clear
|
|
|
|
end
|
2013-01-23 00:26:20 -06:00
|
|
|
|
2014-07-30 20:27:46 -05:00
|
|
|
def self.create(formula, compiler, stdlib, build)
|
2015-02-18 20:05:50 -05:00
|
|
|
attributes = {
|
2015-02-21 18:32:52 -05:00
|
|
|
"used_options" => build.used_options.as_flags,
|
|
|
|
"unused_options" => build.unused_options.as_flags,
|
|
|
|
"tabfile" => formula.prefix.join(FILENAME),
|
2015-03-07 23:53:33 -05:00
|
|
|
"built_as_bottle" => build.bottle?,
|
2015-02-21 18:32:52 -05:00
|
|
|
"poured_from_bottle" => false,
|
|
|
|
"time" => Time.now.to_i,
|
|
|
|
"HEAD" => Homebrew.git_head,
|
|
|
|
"compiler" => compiler,
|
|
|
|
"stdlib" => stdlib,
|
|
|
|
"source" => {
|
|
|
|
"path" => formula.path.to_s,
|
2015-03-13 00:41:10 -04:00
|
|
|
"tap" => formula.tap,
|
2015-08-03 13:09:07 +01:00
|
|
|
"spec" => formula.active_spec_sym.to_s
|
|
|
|
}
|
2015-02-18 20:05:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
new(attributes)
|
2011-09-22 20:07:39 -07:00
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def self.from_file(path)
|
2015-11-27 16:40:16 +00:00
|
|
|
CACHE.fetch(path) { |p| CACHE[p] = from_file_content(File.read(p), p) }
|
2015-05-23 18:08:07 +08:00
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def self.from_file_content(content, path)
|
2015-05-23 18:08:07 +08:00
|
|
|
attributes = Utils::JSON.load(content)
|
2015-02-21 18:32:52 -05:00
|
|
|
attributes["tabfile"] = path
|
2015-03-13 00:41:10 -04:00
|
|
|
attributes["source"] ||= {}
|
|
|
|
|
|
|
|
tapped_from = attributes["tapped_from"]
|
|
|
|
unless tapped_from.nil? || tapped_from == "path or URL"
|
|
|
|
attributes["source"]["tap"] = attributes.delete("tapped_from")
|
2015-08-02 16:34:45 +08:00
|
|
|
end
|
2015-08-02 16:12:14 +08:00
|
|
|
|
2015-08-02 16:34:45 +08:00
|
|
|
if attributes["source"]["tap"] == "mxcl/master"
|
|
|
|
attributes["source"]["tap"] = "Homebrew/homebrew"
|
2015-03-13 00:41:10 -04:00
|
|
|
end
|
|
|
|
|
2015-07-28 15:33:07 +08:00
|
|
|
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
|
|
|
|
|
2014-06-29 23:15:13 -05:00
|
|
|
new(attributes)
|
2011-09-23 08:36:40 -07:00
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def self.for_keg(keg)
|
2013-01-23 00:26:20 -06:00
|
|
|
path = keg.join(FILENAME)
|
2012-01-01 15:22:36 -06:00
|
|
|
|
|
|
|
if path.exist?
|
2014-06-29 22:26:14 -05:00
|
|
|
from_file(path)
|
2012-01-01 15:22:36 -06:00
|
|
|
else
|
2015-02-21 12:15:39 -05:00
|
|
|
empty
|
2012-01-01 15:22:36 -06:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def self.for_name(name)
|
2014-06-22 15:00:15 -05:00
|
|
|
for_formula(Formulary.factory(name))
|
2013-06-26 10:37:09 -07:00
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def self.remap_deprecated_options(deprecated_options, options)
|
2014-10-16 13:01:48 +01:00
|
|
|
deprecated_options.each do |deprecated_option|
|
2014-12-26 11:58:09 -05:00
|
|
|
option = options.find { |o| o.name == deprecated_option.old }
|
2014-10-16 13:01:48 +01:00
|
|
|
next unless option
|
|
|
|
options -= [option]
|
|
|
|
options << Option.new(deprecated_option.current, option.description)
|
|
|
|
end
|
|
|
|
options
|
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def self.for_formula(f)
|
2014-06-29 19:19:24 -05:00
|
|
|
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
|
2014-03-22 11:34:26 -05:00
|
|
|
|
|
|
|
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
|
2014-10-16 13:01:48 +01:00
|
|
|
tab = from_file(path)
|
|
|
|
used_options = remap_deprecated_options(f.deprecated_options, tab.used_options)
|
|
|
|
tab.used_options = used_options.as_flags
|
2014-03-22 11:34:26 -05:00
|
|
|
else
|
2015-02-21 12:15:39 -05:00
|
|
|
tab = empty
|
|
|
|
tab.unused_options = f.options.as_flags
|
2015-07-28 15:33:07 +08:00
|
|
|
tab.source = { "path" => f.path.to_s, "tap" => f.tap, "spec" => f.active_spec_sym.to_s }
|
2014-03-22 11:34:26 -05:00
|
|
|
end
|
2015-02-21 12:15:39 -05:00
|
|
|
|
|
|
|
tab
|
2011-09-23 08:36:40 -07:00
|
|
|
end
|
|
|
|
|
2015-02-21 12:15:39 -05:00
|
|
|
def self.empty
|
2015-02-18 20:05:50 -05:00
|
|
|
attributes = {
|
2015-02-21 18:32:52 -05:00
|
|
|
"used_options" => [],
|
|
|
|
"unused_options" => [],
|
|
|
|
"built_as_bottle" => false,
|
|
|
|
"poured_from_bottle" => false,
|
|
|
|
"time" => nil,
|
|
|
|
"HEAD" => nil,
|
|
|
|
"stdlib" => nil,
|
|
|
|
"compiler" => "clang",
|
|
|
|
"source" => {
|
|
|
|
"path" => nil,
|
2015-03-13 00:41:10 -04:00
|
|
|
"tap" => nil,
|
2015-08-03 13:09:07 +01:00
|
|
|
"spec" => "stable"
|
|
|
|
}
|
2015-02-18 20:05:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
new(attributes)
|
2012-01-01 15:22:36 -06:00
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def with?(val)
|
2014-10-09 00:20:15 -05:00
|
|
|
name = val.respond_to?(:option_name) ? val.option_name : val
|
2014-08-09 16:26:59 -05:00
|
|
|
include?("with-#{name}") || unused_options.include?("without-#{name}")
|
2013-01-23 00:26:24 -06:00
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def without?(name)
|
|
|
|
!with? name
|
2014-07-30 21:04:17 -05:00
|
|
|
end
|
|
|
|
|
2015-08-03 13:09:07 +01:00
|
|
|
def include?(opt)
|
2011-09-23 08:36:40 -07:00
|
|
|
used_options.include? opt
|
|
|
|
end
|
|
|
|
|
2013-01-23 00:26:24 -06:00
|
|
|
def universal?
|
2014-08-03 18:17:12 -05:00
|
|
|
include?("universal")
|
|
|
|
end
|
|
|
|
|
|
|
|
def cxx11?
|
|
|
|
include?("c++11")
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_32_bit?
|
|
|
|
include?("32-bit")
|
2013-01-23 00:26:24 -06:00
|
|
|
end
|
|
|
|
|
2013-01-23 00:26:23 -06:00
|
|
|
def used_options
|
2014-08-13 11:09:57 -05:00
|
|
|
Options.create(super)
|
2013-01-23 00:26:23 -06:00
|
|
|
end
|
|
|
|
|
|
|
|
def unused_options
|
2014-08-13 11:09:57 -05:00
|
|
|
Options.create(super)
|
2013-01-23 00:26:23 -06:00
|
|
|
end
|
|
|
|
|
2015-06-27 20:04:45 -04:00
|
|
|
def compiler
|
|
|
|
super || MacOS.default_compiler
|
|
|
|
end
|
|
|
|
|
2013-07-27 00:11:45 -07:00
|
|
|
def cxxstdlib
|
|
|
|
# Older tabs won't have these values, so provide sensible defaults
|
2013-10-07 00:25:26 -07:00
|
|
|
lib = stdlib.to_sym if stdlib
|
2015-06-27 20:04:45 -04:00
|
|
|
CxxStdlib.create(lib, compiler.to_sym)
|
2013-07-27 00:11:45 -07:00
|
|
|
end
|
|
|
|
|
2014-10-15 00:52:57 -05:00
|
|
|
def build_bottle?
|
|
|
|
built_as_bottle && !poured_from_bottle
|
|
|
|
end
|
|
|
|
|
2015-03-11 20:23:22 -07:00
|
|
|
def bottle?
|
|
|
|
built_as_bottle
|
|
|
|
end
|
|
|
|
|
2015-03-13 00:41:10 -04:00
|
|
|
def tap
|
|
|
|
source["tap"]
|
|
|
|
end
|
|
|
|
|
2015-05-27 09:57:41 +01:00
|
|
|
def tap=(tap)
|
|
|
|
source["tap"] = tap
|
|
|
|
end
|
|
|
|
|
2015-07-28 15:33:07 +08:00
|
|
|
def spec
|
|
|
|
source["spec"].to_sym
|
|
|
|
end
|
|
|
|
|
2011-09-22 20:07:39 -07:00
|
|
|
def to_json
|
2015-02-18 20:05:50 -05:00
|
|
|
attributes = {
|
2015-02-21 18:32:52 -05:00
|
|
|
"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),
|
2015-08-03 13:09:07 +01:00
|
|
|
"source" => source
|
2015-02-18 20:05:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Utils::JSON.dump(attributes)
|
2011-09-22 20:07:39 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def write
|
2015-11-27 16:40:16 +00:00
|
|
|
CACHE[tabfile] = self
|
2014-03-22 11:13:33 -05:00
|
|
|
tabfile.atomic_write(to_json)
|
2011-09-22 20:07:39 -07:00
|
|
|
end
|
2013-03-27 23:07:25 -05:00
|
|
|
|
|
|
|
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:"
|
2015-06-26 10:08:41 +01:00
|
|
|
s << used_options.to_a.join(" ")
|
2013-03-27 23:07:25 -05:00
|
|
|
end
|
|
|
|
s.join(" ")
|
|
|
|
end
|
2011-09-22 20:07:39 -07:00
|
|
|
end
|