 3657393017
			
		
	
	
		3657393017
		
	
	
	
	
		
			
			This moves stdlib tracking after the install completes, which allows the tracking to have access to the actual stdlib in use. This unfortunately means that builds can error out *after* a build, resulting in wasted time; however, it reduces false positives, and the overall user experience is still likely to be better this way.
		
			
				
	
	
		
			137 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| 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 f, compiler, stdlib, args
 | |
|     f.build.args = args
 | |
| 
 | |
|     sha = HOMEBREW_REPOSITORY.cd do
 | |
|       `git rev-parse --verify -q HEAD 2>/dev/null`.chuzzle
 | |
|     end
 | |
| 
 | |
|     Tab.new :used_options => f.build.used_options,
 | |
|             :unused_options => f.build.unused_options,
 | |
|             :tabfile => f.prefix.join(FILENAME),
 | |
|             :built_as_bottle => !!ARGV.build_bottle?,
 | |
|             :poured_from_bottle => false,
 | |
|             :tapped_from => f.tap,
 | |
|             :time => Time.now.to_i, # to_s would be better but Ruby has no from_s function :P
 | |
|             :HEAD => sha,
 | |
|             :compiler => compiler,
 | |
|             :stdlib => stdlib
 | |
|   end
 | |
| 
 | |
|   def self.from_file path
 | |
|     tab = Tab.new Utils::JSON.load(File.read(path))
 | |
|     tab.tabfile = path
 | |
|     tab
 | |
|   end
 | |
| 
 | |
|   def self.for_keg keg
 | |
|     path = keg.join(FILENAME)
 | |
| 
 | |
|     if path.exist?
 | |
|       self.from_file(path)
 | |
|     else
 | |
|       self.dummy_tab
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def self.for_name name
 | |
|     for_formula(Formula.factory(name))
 | |
|   end
 | |
| 
 | |
|   def self.for_formula f
 | |
|     path = [f.opt_prefix, f.linked_keg].map{ |pn| pn.join(FILENAME) }.find{ |pn| pn.exist? }
 | |
|     # Legacy kegs may lack a receipt. If it doesn't exist, fake one
 | |
|     if path.nil? then self.dummy_tab(f) else self.from_file(path) end
 | |
|   end
 | |
| 
 | |
|   def self.dummy_tab f=nil
 | |
|     Tab.new :used_options => [],
 | |
|             :unused_options => (f.build.as_flags rescue []),
 | |
|             :built_as_bottle => false,
 | |
|             :poured_from_bottle => false,
 | |
|             :tapped_from => "",
 | |
|             :time => nil,
 | |
|             :HEAD => nil,
 | |
|             :compiler => :clang
 | |
|   end
 | |
| 
 | |
|   def with? name
 | |
|     if options.include? "with-#{name}"
 | |
|       used_options.include? "with-#{name}"
 | |
|     elsif options.include? "without-#{name}"
 | |
|       not used_options.include? "without-#{name}"
 | |
|     else
 | |
|       false
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def include? opt
 | |
|     used_options.include? opt
 | |
|   end
 | |
| 
 | |
|   def universal?
 | |
|     used_options.include? "universal"
 | |
|   end
 | |
| 
 | |
|   def used_options
 | |
|     Options.coerce(super)
 | |
|   end
 | |
| 
 | |
|   def unused_options
 | |
|     Options.coerce(super)
 | |
|   end
 | |
| 
 | |
|   def options
 | |
|     used_options + unused_options
 | |
|   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.new(lib, cc.to_sym)
 | |
|   end
 | |
| 
 | |
|   def to_json
 | |
|     Utils::JSON.dump({
 | |
|       :used_options => used_options.map(&:to_s),
 | |
|       :unused_options => unused_options.map(&:to_s),
 | |
|       :built_as_bottle => built_as_bottle,
 | |
|       :poured_from_bottle => poured_from_bottle,
 | |
|       :tapped_from => tapped_from,
 | |
|       :time => time,
 | |
|       :HEAD => send("HEAD"),
 | |
|       :stdlib => (stdlib.to_s if stdlib),
 | |
|       :compiler => (compiler.to_s if compiler)})
 | |
|   end
 | |
| 
 | |
|   def write
 | |
|     tabfile.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
 |