Codebase list facter / 9464859
(FACT-1778) Attempt to canonicalize search paths Attempt to canonicalize search paths, then fall back to using absolute path. This preserves the fix for FACT-1510, but also ensures we deduplicate most paths. This primarily fixes that in Puppet we load `lib/facter` from both Puppet's search paths and Facter's internal handling of Ruby's LOAD_PATH. Previously canonicalization would ensure that the resulting file paths for custom facts were identical, so when we check whether we've previously loaded a file we would identify duplicates and avoid loading them again. The fix for FACT-1510 broke that. This is the least-impact approach to fixing it. Also use forward-slash explicitly when working with paths that come from Ruby, to avoid inconsistent representations when we can't determine the canonical path. Michael Smith 6 years ago
1 changed file(s) with 23 addition(s) and 21 deletion(s). Raw diff Collapse all Expand all
172172 }
173173
174174 namespace facter { namespace ruby {
175
176 static string canonicalize(string p)
177 {
178 // Get the canonical/absolute directory name
179 // If it can be resolved, use canonical to avoid duplicate search paths.
180 // Fall back to absolute because canonical on Windows won't recognize paths as valid if
181 // they resolve to symlinks to non-NTFS volumes.
182 boost::system::error_code ec;
183 auto directory = canonical(p, ec);
184 if (ec) {
185 return absolute(p).string();
186 }
187 return directory.string();
188 }
175189
176190 map<VALUE, module*> module::_instances;
177191
302316 {
303317 for (auto dir : paths) {
304318 _additional_search_paths.emplace_back(dir);
305
306 // Get the absolute directory name
307 // Absolute is used over canonical because canonical on Windows won't recognize paths as valid if
308 // they resolve to symlinks to non-NTFS volumes.
309 path directory = absolute(_additional_search_paths.back());
310
311 _search_paths.push_back(directory.string());
319 _search_paths.emplace_back(canonicalize(_additional_search_paths.back()));
312320 }
313321 }
314322
759767 if (!ruby.is_string(argv[i])) {
760768 continue;
761769 }
770
762771 instance->_additional_search_paths.emplace_back(ruby.to_string(argv[i]));
763
764 // Get the absolute directory name
765 path directory = absolute(instance->_additional_search_paths.back());
766
767 instance->_search_paths.push_back(directory.string());
772 instance->_search_paths.emplace_back(canonicalize(instance->_additional_search_paths.back()));
768773 }
769774 return ruby.nil_value();
770775 });
952957
953958 // Look for "facter" subdirectories on the load path
954959 for (auto const& directory : ruby.get_load_path()) {
955 // Get the absolute directory name
956960 boost::system::error_code ec;
957 path dir = absolute(directory);
961 // Use forward-slash to keep this consistent with Ruby conventions.
962 auto dir = canonicalize(directory) + "/facter";
958963
959964 // Ignore facter itself if it's on the load path
960 if (is_regular_file(dir / "facter.rb", ec)) {
965 if (is_regular_file(dir, ec)) {
961966 continue;
962967 }
963968
964 dir = dir / "facter";
965969 if (!is_directory(dir, ec)) {
966970 continue;
967971 }
968 _search_paths.push_back(dir.string());
972 _search_paths.push_back(dir);
969973 }
970974
971975 // Append the FACTERLIB paths
979983 // Insert the given paths last
980984 _search_paths.insert(_search_paths.end(), paths.begin(), paths.end());
981985
982 // Do a absolute transform
986 // Do a canonical/absolute transform
983987 transform(_search_paths.begin(), _search_paths.end(), _search_paths.begin(), [](string const& directory) -> string {
984 // Get the absolute directory name
985 path dir = absolute(directory);
986 return dir.string();
988 return canonicalize(directory);
987989 });
988990
989991 // Remove anything that is empty using the erase-remove idiom.