|  | @@ -1,8 +1,10 @@
 | 
	
		
			
				|  |  |  /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 | 
	
		
			
				|  |  |     file Copyright.txt or https://cmake.org/licensing for details.  */
 | 
	
		
			
				|  |  | +#include <algorithm>
 | 
	
		
			
				|  |  |  #include <functional>
 | 
	
		
			
				|  |  |  #include <map>
 | 
	
		
			
				|  |  |  #include <string>
 | 
	
		
			
				|  |  | +#include <unordered_set>
 | 
	
		
			
				|  |  |  #include <utility>
 | 
	
		
			
				|  |  |  #include <vector>
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -18,6 +20,8 @@
 | 
	
		
			
				|  |  |  #include "cmCMakePresetsGraph.h"
 | 
	
		
			
				|  |  |  #include "cmCMakePresetsGraphInternal.h"
 | 
	
		
			
				|  |  |  #include "cmJSONHelpers.h"
 | 
	
		
			
				|  |  | +#include "cmStringAlgorithms.h"
 | 
	
		
			
				|  |  | +#include "cmSystemTools.h"
 | 
	
		
			
				|  |  |  #include "cmVersion.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace {
 | 
	
	
		
			
				|  | @@ -406,8 +410,21 @@ cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
 | 
	
		
			
				|  |  | -  const std::string& filename, bool user)
 | 
	
		
			
				|  |  | +  const std::string& filename, RootType rootType, ReadReason readReason,
 | 
	
		
			
				|  |  | +  std::vector<File*>& inProgressFiles, File*& file)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +  for (auto const& f : this->Files) {
 | 
	
		
			
				|  |  | +    if (cmSystemTools::SameFile(filename, f->Filename)) {
 | 
	
		
			
				|  |  | +      file = f.get();
 | 
	
		
			
				|  |  | +      auto fileIt =
 | 
	
		
			
				|  |  | +        std::find(inProgressFiles.begin(), inProgressFiles.end(), file);
 | 
	
		
			
				|  |  | +      if (fileIt != inProgressFiles.end()) {
 | 
	
		
			
				|  |  | +        return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      return cmCMakePresetsGraph::ReadFileResult::READ_OK;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    cmsys::ifstream fin(filename.c_str());
 | 
	
		
			
				|  |  |    if (!fin) {
 | 
	
		
			
				|  |  |      return ReadFileResult::FILE_NOT_FOUND;
 | 
	
	
		
			
				|  | @@ -430,11 +447,6 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
 | 
	
		
			
				|  |  |    if (v < MIN_VERSION || v > MAX_VERSION) {
 | 
	
		
			
				|  |  |      return ReadFileResult::UNRECOGNIZED_VERSION;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  if (user) {
 | 
	
		
			
				|  |  | -    this->UserVersion = v;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    this->Version = v;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Support for build and test presets added in version 2.
 | 
	
		
			
				|  |  |    if (v < 2 &&
 | 
	
	
		
			
				|  | @@ -460,8 +472,16 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
 | 
	
		
			
				|  |  |      return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  auto filePtr = cm::make_unique<File>();
 | 
	
		
			
				|  |  | +  file = filePtr.get();
 | 
	
		
			
				|  |  | +  this->Files.emplace_back(std::move(filePtr));
 | 
	
		
			
				|  |  | +  inProgressFiles.emplace_back(file);
 | 
	
		
			
				|  |  | +  file->Filename = filename;
 | 
	
		
			
				|  |  | +  file->Version = v;
 | 
	
		
			
				|  |  | +  file->ReachableFiles.insert(file);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    for (auto& preset : presets.ConfigurePresets) {
 | 
	
		
			
				|  |  | -    preset.User = user;
 | 
	
		
			
				|  |  | +    preset.OriginFile = file;
 | 
	
		
			
				|  |  |      if (preset.Name.empty()) {
 | 
	
		
			
				|  |  |        return ReadFileResult::INVALID_PRESET;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -494,7 +514,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (auto& preset : presets.BuildPresets) {
 | 
	
		
			
				|  |  | -    preset.User = user;
 | 
	
		
			
				|  |  | +    preset.OriginFile = file;
 | 
	
		
			
				|  |  |      if (preset.Name.empty()) {
 | 
	
		
			
				|  |  |        return ReadFileResult::INVALID_PRESET;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -515,7 +535,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (auto& preset : presets.TestPresets) {
 | 
	
		
			
				|  |  | -    preset.User = user;
 | 
	
		
			
				|  |  | +    preset.OriginFile = file;
 | 
	
		
			
				|  |  |      if (preset.Name.empty()) {
 | 
	
		
			
				|  |  |        return ReadFileResult::INVALID_PRESET;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -535,5 +555,33 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
 | 
	
		
			
				|  |  |      this->TestPresetOrder.push_back(preset.Name);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  auto const includeFile = [this, &inProgressFiles, file](
 | 
	
		
			
				|  |  | +                             const std::string& include, RootType rootType2,
 | 
	
		
			
				|  |  | +                             ReadReason readReason2) -> ReadFileResult {
 | 
	
		
			
				|  |  | +    ReadFileResult r;
 | 
	
		
			
				|  |  | +    File* includedFile;
 | 
	
		
			
				|  |  | +    if ((r = this->ReadJSONFile(include, rootType2, readReason2,
 | 
	
		
			
				|  |  | +                                inProgressFiles, includedFile)) !=
 | 
	
		
			
				|  |  | +        ReadFileResult::READ_OK) {
 | 
	
		
			
				|  |  | +      return r;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    file->ReachableFiles.insert(includedFile->ReachableFiles.begin(),
 | 
	
		
			
				|  |  | +                                includedFile->ReachableFiles.end());
 | 
	
		
			
				|  |  | +    return ReadFileResult::READ_OK;
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (rootType == RootType::User && readReason == ReadReason::Root) {
 | 
	
		
			
				|  |  | +    auto cmakePresetsFilename = GetFilename(this->SourceDir);
 | 
	
		
			
				|  |  | +    if (cmSystemTools::FileExists(cmakePresetsFilename)) {
 | 
	
		
			
				|  |  | +      if ((result = includeFile(cmakePresetsFilename, RootType::Project,
 | 
	
		
			
				|  |  | +                                ReadReason::Root)) !=
 | 
	
		
			
				|  |  | +          ReadFileResult::READ_OK) {
 | 
	
		
			
				|  |  | +        return result;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  inProgressFiles.pop_back();
 | 
	
		
			
				|  |  |    return ReadFileResult::READ_OK;
 | 
	
		
			
				|  |  |  }
 |