@@ -32,6 +32,9 @@ class CppLibrary
3232 # @return [String] the last command
3333 attr_reader :last_cmd
3434
35+ # @return [Array<Pathname>] Directories suspected of being vendor-bundle
36+ attr_reader :vendor_bundle_cache
37+
3538 # @param base_dir [Pathname] The path to the library being tested
3639 # @param arduino_lib_dir [Pathname] The path to the libraries directory
3740 def initialize ( base_dir , arduino_lib_dir )
@@ -45,26 +48,57 @@ def initialize(base_dir, arduino_lib_dir)
4548 @last_out = ""
4649 @last_msg = ""
4750 @has_libasan_cache = { }
51+ @vendor_bundle_cache = nil
4852 end
4953
5054 # Guess whether a file is part of the vendor bundle (indicating we should ignore it).
5155 #
52- # This assumes the vendor bundle will be at `vendor/bundle` and not some other location
56+ # A safe way to do this seems to be to check whether any of the installed gems
57+ # appear to be a subdirectory of (but not equal to) the working directory.
58+ # That gets us the vendor directory (or multiple directories). We can check
59+ # if the given path is contained by any of those.
60+ #
5361 # @param path [Pathname] The path to check
5462 # @return [bool]
5563 def vendor_bundle? ( path )
56- # TODO: look for Gemfile, look for .bundle/config and get BUNDLE_PATH from there?
57- base = @base_dir + "vendor"
58- return false unless base . exist?
64+ # Cache bundle information, as it is (1) time consuming to fetch and (2) not going to change while we run
65+ if @vendor_bundle_cache . nil?
66+ bundle_info = Host . run_and_capture ( "bundle show --paths" )
67+ if !bundle_info [ :success ]
68+ # if the bundle show command fails, assume there isn't a bundle
69+ @vendor_bundle_cache = false
70+ else
71+ # Get all the places where gems are stored. We combine a few things here:
72+ # by preemptively switching to the parent directory, we can both ensure that
73+ # we skip any gems that are equal to the working directory AND exploit some
74+ # commonality in the paths to cut down our search locations
75+ #
76+ # NOT CONFUSING THE WORKING DIRECTORY WITH VENDOR BUNDLE IS SUPER IMPORTANT
77+ # because if we do, we won't be able to run CI on this library itself.
78+ bundle_paths = bundle_info [ :out ] . lines
79+ . map { |l | Pathname . new ( l . chomp ) }
80+ . select ( &:exist? )
81+ . map ( &:realpath )
82+ . map ( &:parent )
83+ . uniq
84+ wd = Pathname . new ( "." ) . realpath
85+ @vendor_bundle_cache = bundle_paths . select do |gem_path |
86+ gem_path . ascend do |part |
87+ break true if wd == part
88+ end
89+ end
90+ end
91+ end
5992
60- vendor_bundle_aliases = [ base , base . realpath ]
93+ # no bundle existed
94+ return false if @vendor_bundle_cache == false
6195
62- # we could do this but some rubies don't return an enumerator for ascend
63- # path.ascend.any? { |part| vendor_bundle_aliases.include?(part) }
64- path . ascend do |part |
65- return true if vendor_bundle_aliases . include? ( part )
96+ # With vendor bundles located, check this file against those
97+ @vendor_bundle_cache . any? do |gem_path |
98+ path . ascend do |part |
99+ break true if gem_path == part
100+ end
66101 end
67- false
68102 end
69103
70104 # Guess whether a file is part of the tests/ dir (indicating library compilation should ignore it).
0 commit comments