2013-07-27 00:11:45 -07:00
|
|
|
require 'cxxstdlib'
|
2011-09-22 20:07:39 -07:00
|
|
|
require 'ostruct'
|
2013-01-23 00:26:23 -06:00
|
|
|
require 'options'
|
2013-06-22 16:51:08 -05:00
|
|
|
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
|
2013-01-23 00:26:20 -06:00
|
|
|
FILENAME = 'INSTALL_RECEIPT.json'
|
|
|
|
|
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-02-18 20:05:50 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
new(attributes)
|
2011-09-22 20:07:39 -07:00
|
|
|
end
|
|
|
|
|
2011-09-23 08:36:40 -07:00
|
|
|
def self.from_file path
|
2015-05-23 18:08:07 +08:00
|
|
|
from_file_content(File.read(path), path)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.from_file_content content, path
|
|
|
|
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")
|
|
|
|
end
|
|
|
|
|
2014-06-29 23:15:13 -05:00
|
|
|
new(attributes)
|
2011-09-23 08:36:40 -07:00
|
|
|
end
|
|
|
|
|
2012-01-01 15:22:36 -06: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
|
|
|
|
|
2013-06-26 10:37:09 -07: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
|
|
|
|
|
2014-10-16 13:01:48 +01:00
|
|
|
def self.remap_deprecated_options deprecated_options, options
|
|
|
|
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
|
|
|
|
|
2011-09-23 08:36:40 -07: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-03-13 00:41:10 -04:00
|
|
|
tab.source = { "path" => f.path.to_s, "tap" => f.tap }
|
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-02-18 20:05:50 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
new(attributes)
|
2012-01-01 15:22:36 -06:00
|
|
|
end
|
|
|
|
|
2014-10-09 00:20:15 -05:00
|
|
|
def with? val
|
|
|
|
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
|
|
|
|
|
2014-07-30 21:04:17 -05:00
|
|
|
def without? name
|
|
|
|
not with? name
|
|
|
|
end
|
|
|
|
|
2013-01-23 00:26:24 -06: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
|
|
|
|
|
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
|
2013-07-27 00:11:45 -07:00
|
|
|
cc = compiler || MacOS.default_compiler
|
2014-08-02 19:29:59 -05:00
|
|
|
CxxStdlib.create(lib, cc.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
|
|
|
|
|
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-03-13 00:41:10 -04: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
|
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:"
|
|
|
|
s << used_options.to_a.join(", ")
|
|
|
|
end
|
|
|
|
s.join(" ")
|
|
|
|
end
|
2011-09-22 20:07:39 -07:00
|
|
|
end
|