示例#1
0
        // computes all the inputs and outputs that would be used in the compilation of a project
        // ensures that all paths are files
        // ensures no missing inputs
        public static CompilerIO GetCompileIO(ProjectContext project, string config, string outputPath, string intermediaryOutputPath, ProjectDependenciesFacade dependencies)
        {
            var compilerIO = new CompilerIO(new List <string>(), new List <string>());

            // input: project.json
            compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);

            // input: source files
            compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project));

            // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile
            // todo: use lock file insteaf of dependencies. One file vs many
            // input: dependencies
            AddDependencies(dependencies, compilerIO);

            // input: key file
            AddKeyFile(project, config, compilerIO);

            // output: compiler output
            compilerIO.Outputs.Add(CompilerUtil.GetCompilationOutput(project.ProjectFile, project.TargetFramework, config, outputPath));

            // input / output: resources without culture
            AddCultureResources(project, intermediaryOutputPath, compilerIO);

            // input / output: resources with culture
            AddNonCultureResources(project, outputPath, compilerIO);

            return(compilerIO);
        }
示例#2
0
        private IncrementalResult InputItemsChanged(ProjectGraphNode graphNode, CompilerIO compilerIO)
        {
            // check empty inputs / outputs
            if (!compilerIO.Inputs.Any())
            {
                return(new IncrementalResult("the project has no inputs"));
            }

            if (!compilerIO.Outputs.Any())
            {
                return(new IncrementalResult("the project has no outputs"));
            }

            // check non existent items
            var result = CheckMissingIO(compilerIO.Inputs, "inputs");

            if (result.NeedsRebuilding)
            {
                return(result);
            }

            result = CheckMissingIO(compilerIO.Outputs, "outputs");
            if (result.NeedsRebuilding)
            {
                return(result);
            }

            return(CheckInputGlobChanges(graphNode, compilerIO));
        }
示例#3
0
        private IncrementalResult CheckInputGlobChanges(ProjectGraphNode graphNode, CompilerIO compilerIO)
        {
            // check cache against input glob pattern changes
            var incrementalCacheFile = graphNode.ProjectContext.IncrementalCacheFile(_configuration, _buildBasePath, _outputPath);

            if (!File.Exists(incrementalCacheFile))
            {
                // cache is not present (first compilation); can't determine if globs changed; cache will be generated after build processes project
                return(IncrementalResult.DoesNotNeedRebuild);
            }

            var incrementalCache = IncrementalCache.ReadFromFile(incrementalCacheFile);

            var diffResult = compilerIO.DiffInputs(incrementalCache.CompilerIO);

            if (diffResult.Deletions.Any())
            {
                return(new IncrementalResult("Input items removed from last build", diffResult.Deletions));
            }

            if (diffResult.Additions.Any())
            {
                return(new IncrementalResult("Input items added from last build", diffResult.Additions));
            }

            return(IncrementalResult.DoesNotNeedRebuild);
        }
示例#4
0
        private static void AddDependencies(ProjectDependenciesFacade dependencies, CompilerIO compilerIO)
        {
            // add dependency sources that need compilation
            compilerIO.Inputs.AddRange(dependencies.ProjectDependenciesWithSources.Values.SelectMany(p => p.Project.Files.SourceFiles));

            // non project dependencies get captured by changes in the lock file
        }
示例#5
0
        // computes all the inputs and outputs that would be used in the compilation of a project
        // ensures that all paths are files
        // ensures no missing inputs
        public static CompilerIO GetCompileIO(ProjectContext project, string config, string outputPath, string intermediaryOutputPath, ProjectDependenciesFacade dependencies)
        {
            var compilerIO = new CompilerIO(new List<string>(), new List<string>());
            var compilationOutput = CompilerUtil.GetCompilationOutput(project.ProjectFile, project.TargetFramework, config, outputPath);

            // input: project.json
            compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);

            // input: lock file; find when dependencies change
            AddLockFile(project, compilerIO);

            // input: source files
            compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project));

            // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile
            // input: dependencies
            AddDependencies(dependencies, compilerIO);

            // output: compiler output
            compilerIO.Outputs.Add(compilationOutput);

            // input / output: compilation options files
            AddFilesFromCompilationOptions(project, config, compilationOutput, compilerIO);

            // input / output: resources without culture
            AddCultureResources(project, intermediaryOutputPath, compilerIO);

            // input / output: resources with culture
            AddNonCultureResources(project, outputPath, compilerIO);

            return compilerIO;
        }
示例#6
0
        private static void AddDependencies(ProjectDependenciesFacade dependencies, CompilerIO compilerIO)
        {
            // add dependency sources that need compilation
            compilerIO.Inputs.AddRange(dependencies.ProjectDependenciesWithSources.Values.SelectMany(p => p.Project.Files.SourceFiles));

            // add compilation binaries
            compilerIO.Inputs.AddRange(dependencies.Dependencies.SelectMany(d => d.CompilationAssemblies.Select(ca => ca.ResolvedPath)));
        }
示例#7
0
        private static void AddKeyFile(ProjectContext project, string config, CompilerIO compilerIO)
        {
            var keyFile = CompilerUtil.ResolveCompilationOptions(project, config).KeyFile;

            if (keyFile != null)
            {
                compilerIO.Inputs.Add(keyFile);
            }
        }
示例#8
0
        public DiffResult DiffInputs(CompilerIO other)
        {
            var myInputSet = new HashSet<string>(Inputs);
            var otherInputSet = new HashSet<string>(other.Inputs);

            var additions = myInputSet.Except(otherInputSet);
            var deletions = otherInputSet.Except(myInputSet);

            return new DiffResult(additions, deletions);
        }
示例#9
0
        public DiffResult DiffInputs(CompilerIO other)
        {
            var myInputSet    = new HashSet <string>(Inputs);
            var otherInputSet = new HashSet <string>(other.Inputs);

            var additions = myInputSet.Except(otherInputSet);
            var deletions = otherInputSet.Except(myInputSet);

            return(new DiffResult(additions, deletions));
        }
示例#10
0
        private static void AddLockFile(ProjectContext project, CompilerIO compilerIO)
        {
            if (project.LockFile == null)
            {
                var errorMessage = $"Project {project.ProjectName()} does not have a lock file.";
                Reporter.Error.WriteLine(errorMessage);
                throw new InvalidOperationException(errorMessage);
            }

            compilerIO.Inputs.Add(project.LockFile.LockFilePath);
        }
示例#11
0
        // computes all the inputs and outputs that would be used in the compilation of a project
        // ensures that all paths are files
        // ensures no missing inputs
        public CompilerIO GetCompileIO(ProjectContext project, ProjectDependenciesFacade dependencies)
        {
            var buildConfiguration = _args.ConfigValue;
            var buildBasePath      = _args.BuildBasePathValue;
            var outputPath         = _args.OutputValue;
            var isRootProject      = project == _rootProject;

            var compilerIO         = new CompilerIO(new List <string>(), new List <string>());
            var calculator         = project.GetOutputPaths(buildConfiguration, buildBasePath, outputPath);
            var binariesOutputPath = calculator.CompilationOutputPath;

            // input: project.json
            compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);

            // input: lock file; find when dependencies change
            AddLockFile(project, compilerIO);

            // input: source files
            compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project));

            // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile
            // input: dependencies
            AddDependencies(dependencies, compilerIO);

            var allOutputPath = new HashSet <string>(calculator.CompilationFiles.All());

            if (isRootProject && project.ProjectFile.HasRuntimeOutput(buildConfiguration))
            {
                var runtimeContext = project.CreateRuntimeContext(_args.GetRuntimes());
                foreach (var path in runtimeContext.GetOutputPaths(buildConfiguration, buildBasePath, outputPath).RuntimeFiles.All())
                {
                    allOutputPath.Add(path);
                }
            }

            // output: compiler outputs
            foreach (var path in allOutputPath)
            {
                compilerIO.Outputs.Add(path);
            }

            // input compilation options files
            AddCompilationOptions(project, buildConfiguration, compilerIO);

            // input / output: resources with culture
            AddNonCultureResources(project, calculator.IntermediateOutputDirectoryPath, compilerIO);

            // input / output: resources without culture
            AddCultureResources(project, binariesOutputPath, compilerIO);

            return(compilerIO);
        }
示例#12
0
        // computes all the inputs and outputs that would be used in the compilation of a project
        // ensures that all paths are files
        // ensures no missing inputs
        public CompilerIO GetCompileIO(ProjectContext project, ProjectDependenciesFacade dependencies)
        {
            var buildConfiguration = _args.ConfigValue;
            var buildBasePath = _args.BuildBasePathValue;
            var outputPath = _args.OutputValue;
            var isRootProject = project == _rootProject;

            var compilerIO = new CompilerIO(new List<string>(), new List<string>());
            var calculator = project.GetOutputPaths(buildConfiguration, buildBasePath, outputPath);
            var binariesOutputPath = calculator.CompilationOutputPath;

            // input: project.json
            compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);

            // input: lock file; find when dependencies change
            AddLockFile(project, compilerIO);

            // input: source files
            compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project));

            // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile
            // input: dependencies
            AddDependencies(dependencies, compilerIO);

            var allOutputPath = new List<string>(calculator.CompilationFiles.All());
            if (isRootProject && project.ProjectFile.HasRuntimeOutput(buildConfiguration))
            {
                var runtimeContext = project.CreateRuntimeContext(_args.GetRuntimes());
                allOutputPath.AddRange(runtimeContext.GetOutputPaths(buildConfiguration, buildBasePath, outputPath).RuntimeFiles.All());
            }
            // output: compiler outputs
            foreach (var path in allOutputPath)
            {
                compilerIO.Outputs.Add(path);
            }

            // input compilation options files
            AddCompilationOptions(project, buildConfiguration, compilerIO);

            // input / output: resources with culture
            AddNonCultureResources(project, calculator.IntermediateOutputDirectoryPath, compilerIO);

            // input / output: resources without culture
            AddCultureResources(project, binariesOutputPath, compilerIO);

            return compilerIO;
        }
示例#13
0
        // computes all the inputs and outputs that would be used in the compilation of a project
        // ensures that all paths are files
        // ensures no missing inputs
        public static CompilerIO GetCompileIO(
            ProjectContext project,
            string buildConfiguration,
            string outputPath,
            string intermediaryOutputPath,
            ProjectDependenciesFacade dependencies)
        {
            var compilerIO         = new CompilerIO(new List <string>(), new List <string>());
            var calculator         = project.GetOutputPathCalculator(outputPath);
            var binariesOutputPath = calculator.GetOutputDirectoryPath(buildConfiguration);

            intermediaryOutputPath = calculator.GetIntermediateOutputDirectoryPath(buildConfiguration, intermediaryOutputPath);


            // input: project.json
            compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);

            // input: lock file; find when dependencies change
            AddLockFile(project, compilerIO);

            // input: source files
            compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project));

            // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile
            // input: dependencies
            AddDependencies(dependencies, compilerIO);

            // output: compiler outputs
            foreach (var path in calculator.GetBuildOutputs(buildConfiguration))
            {
                compilerIO.Outputs.Add(path);
            }

            // input compilation options files
            AddCompilationOptions(project, buildConfiguration, compilerIO);

            // input / output: resources without culture
            AddCultureResources(project, intermediaryOutputPath, compilerIO);

            // input / output: resources with culture
            AddNonCultureResources(project, binariesOutputPath, compilerIO);

            return(compilerIO);
        }
示例#14
0
        private IncrementalResult CheckInputGlobChanges(ProjectGraphNode graphNode, CompilerIO compilerIO)
        {
            // check cache against input glob pattern changes
            var incrementalCacheFile = graphNode.ProjectContext.IncrementalCacheFile(_configuration, _buildBasePath, _outputPath);

            if (!File.Exists(incrementalCacheFile))
            {
                // cache is not present (first compilation); can't determine if globs changed; cache will be generated after build processes project
                return(IncrementalResult.DoesNotNeedRebuild);
            }

            var incrementalCache = IncrementalCache.ReadFromFile(incrementalCacheFile);

            var diffResult = compilerIO.DiffInputs(incrementalCache.CompilerIO);

            if (diffResult.Deletions.Any())
            {
                return(new IncrementalResult("Input items removed from last build", diffResult.Deletions));
            }

            if (diffResult.Additions.Any())
            {
                return(new IncrementalResult("Input items added from last build", diffResult.Additions));
            }

            var keys           = incrementalCache.BuildArguments.Keys.Union(_incrementalAffectingArguments.Keys);
            var mismatchedKeys = keys.Where(k =>
            {
                string cachedVal;
                string currentVal;

                return(!incrementalCache.BuildArguments.TryGetValue(k, out cachedVal) ||
                       !_incrementalAffectingArguments.TryGetValue(k, out currentVal) ||
                       !string.Equals(cachedVal ?? string.Empty, currentVal ?? string.Empty, StringComparison.Ordinal));
            });

            if (mismatchedKeys.Any())
            {
                return(new IncrementalResult("Build arguments changed since last build", mismatchedKeys));
            }

            return(IncrementalResult.DoesNotNeedRebuild);
        }
示例#15
0
        // computes all the inputs and outputs that would be used in the compilation of a project
        // ensures that all paths are files
        // ensures no missing inputs
        public static CompilerIO GetCompileIO(
            ProjectContext project,
            string buildConfiguration,
            string outputPath,
            string intermediaryOutputPath,
            ProjectDependenciesFacade dependencies)
        {
            var compilerIO = new CompilerIO(new List<string>(), new List<string>());
            var calculator = project.GetOutputPathCalculator(outputPath);
            var binariesOutputPath = calculator.GetOutputDirectoryPath(buildConfiguration);

            // input: project.json
            compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);

            // input: lock file; find when dependencies change
            AddLockFile(project, compilerIO);

            // input: source files
            compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project));

            // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile
            // input: dependencies
            AddDependencies(dependencies, compilerIO);

            // output: compiler outputs
            foreach (var path in calculator.GetBuildOutputs(buildConfiguration))
            {
                compilerIO.Outputs.Add(path);
            }

            // input compilation options files
            AddCompilationOptions(project, buildConfiguration, compilerIO);

            // input / output: resources without culture
            AddCultureResources(project, intermediaryOutputPath, compilerIO);

            // input / output: resources with culture
            AddNonCultureResources(project, binariesOutputPath, compilerIO);

            return compilerIO;
        }
示例#16
0
        private IncrementalResult TimestampsChanged(CompilerIO compilerIO)
        {
            // find the output with the earliest write time
            var minDateUtc = DateTime.MaxValue;

            foreach (var outputPath in compilerIO.Outputs)
            {
                var lastWriteTimeUtc = File.GetLastWriteTimeUtc(outputPath);

                if (lastWriteTimeUtc < minDateUtc)
                {
                    minDateUtc = lastWriteTimeUtc;
                }
            }

            // find inputs that are older than the earliest output
            var newInputs = compilerIO.Inputs.Where(p => File.GetLastWriteTimeUtc(p) >= minDateUtc);

            return(newInputs.Any()
                ? new IncrementalResult("inputs were modified", newInputs)
                : IncrementalResult.DoesNotNeedRebuild);
        }
示例#17
0
        private static void AddLockFile(ProjectContext project, CompilerIO compilerIO)
        {
            if (project.LockFile == null)
            {
                var errorMessage = $"Project {project.ProjectName()} does not have a lock file.";
                Reporter.Error.WriteLine(errorMessage);
                throw new InvalidOperationException(errorMessage);
            }

            compilerIO.Inputs.Add(project.LockFile.LockFilePath);
        }
示例#18
0
        private static void AddDependencies(ProjectDependenciesFacade dependencies, CompilerIO compilerIO)
        {
            // add dependency sources that need compilation
            compilerIO.Inputs.AddRange(dependencies.ProjectDependenciesWithSources.Values.SelectMany(p => p.Project.Files.SourceFiles));

            // non project dependencies get captured by changes in the lock file
        }
示例#19
0
        private static void AddCultureResources(ProjectContext project, string outputPath, CompilerIO compilerIO)
        {
            foreach (var cultureResourceIO in CompilerUtil.GetCultureResources(project.ProjectFile, outputPath))
            {
                compilerIO.Inputs.AddRange(cultureResourceIO.InputFileToMetadata.Keys);

                if (cultureResourceIO.OutputFile != null)
                {
                    compilerIO.Outputs.Add(cultureResourceIO.OutputFile);
                }
            }
        }
示例#20
0
        private static void AddCompilationOptions(ProjectContext project, string config, CompilerIO compilerIO)
        {
            var compilerOptions = CompilerUtil.ResolveCompilationOptions(project, config);

            // input: key file
            if (compilerOptions.KeyFile != null)
            {
                compilerIO.Inputs.Add(compilerOptions.KeyFile);
            }
        }
示例#21
0
        private IncrementalResult TimestampsChanged(CompilerIO compilerIO)
        {
            // find the output with the earliest write time
            var minDateUtc = DateTime.MaxValue;

            foreach (var outputPath in compilerIO.Outputs)
            {
                var lastWriteTimeUtc = File.GetLastWriteTimeUtc(outputPath);

                if (lastWriteTimeUtc < minDateUtc)
                {
                    minDateUtc = lastWriteTimeUtc;
                }
            }

            // find inputs that are newer than the earliest output
            var newInputs = compilerIO.Inputs.Where(p => File.GetLastWriteTimeUtc(p) >= minDateUtc);

            return newInputs.Any()
                ? new IncrementalResult("inputs were modified", newInputs)
                : IncrementalResult.DoesNotNeedRebuild;
        }
示例#22
0
        private IncrementalResult CheckInputGlobChanges(ProjectGraphNode graphNode, CompilerIO compilerIO)
        {
            // check cache against input glob pattern changes
            var incrementalCacheFile = graphNode.ProjectContext.IncrementalCacheFile(_configuration, _buildBasePath, _outputPath);

            if (!File.Exists(incrementalCacheFile))
            {
                // cache is not present (first compilation); can't determine if globs changed; cache will be generated after build processes project
                return IncrementalResult.DoesNotNeedRebuild;
            }

            var incrementalCache = IncrementalCache.ReadFromFile(incrementalCacheFile);

            var diffResult = compilerIO.DiffInputs(incrementalCache.CompilerIO);

            if (diffResult.Deletions.Any())
            {
                return new IncrementalResult("Input items removed from last build", diffResult.Deletions);
            }

            if (diffResult.Additions.Any())
            {
                return new IncrementalResult("Input items added from last build", diffResult.Additions);
            }

            var keys = incrementalCache.BuildArguments.Keys.Union(_incrementalAffectingArguments.Keys);
            var mismatchedKeys = keys.Where(k =>
            {
                string cachedVal;
                string currentVal;

                return !incrementalCache.BuildArguments.TryGetValue(k, out cachedVal) ||
                    !_incrementalAffectingArguments.TryGetValue(k, out currentVal) ||
                    !string.Equals(cachedVal ?? string.Empty, currentVal ?? string.Empty, StringComparison.Ordinal);
            });
            if (mismatchedKeys.Any())
            {
                return new IncrementalResult("Build arguments changed since last build", mismatchedKeys);
            }

            return IncrementalResult.DoesNotNeedRebuild;
        }
示例#23
0
 public IncrementalCache(CompilerIO compilerIO, IEnumerable <KeyValuePair <string, string> > parameters)
 {
     CompilerIO     = compilerIO;
     BuildArguments = parameters.ToDictionary(p => p.Key, p => p.Value);
 }
示例#24
0
        private static void AddCompilationOptions(ProjectContext project, string config, CompilerIO compilerIO)
        {
            var compilerOptions = project.ResolveCompilationOptions(config);

            // input: key file
            if (compilerOptions.KeyFile != null)
            {
                compilerIO.Inputs.Add(compilerOptions.KeyFile);
            }
        }
示例#25
0
        private static void AddKeyFile(ProjectContext project, string config, CompilerIO compilerIO)
        {
            var keyFile = CompilerUtil.ResolveCompilationOptions(project, config).KeyFile;

            if (keyFile != null)
            {
                compilerIO.Inputs.Add(keyFile);
            }
        }
示例#26
0
        private static void AddFilesFromCompilationOptions(ProjectContext project, string config, string compilationOutput, CompilerIO compilerIO)
        {
            var compilerOptions = CompilerUtil.ResolveCompilationOptions(project, config);

            // output: pdb file. They are always emitted (see compiler.csc)
            compilerIO.Outputs.Add(Path.ChangeExtension(compilationOutput, "pdb"));

            // output: documentation file
            if (compilerOptions.GenerateXmlDocumentation == true)
            {
                compilerIO.Outputs.Add(Path.ChangeExtension(compilationOutput, "xml"));
            }

            // input: key file
            if (compilerOptions.KeyFile != null)
            {
                compilerIO.Inputs.Add(compilerOptions.KeyFile);
            }
        }
示例#27
0
        private static void AddCultureResources(ProjectContext project, string outputPath, CompilerIO compilerIO)
        {
            foreach (var cultureResourceIO in CompilerUtil.GetCultureResources(project.ProjectFile, outputPath))
            {
                compilerIO.Inputs.AddRange(cultureResourceIO.InputFileToMetadata.Keys);

                if (cultureResourceIO.OutputFile != null)
                {
                    compilerIO.Outputs.Add(cultureResourceIO.OutputFile);
                }
            }
        }
示例#28
0
        private static void AddNonCultureResources(ProjectContext project, string intermediaryOutputPath, CompilerIO compilerIO)
        {
            foreach (var resourceIO in CompilerUtil.GetNonCultureResources(project.ProjectFile, intermediaryOutputPath))
            {
                compilerIO.Inputs.Add(resourceIO.InputFile);

                if (resourceIO.OutputFile != null)
                {
                    compilerIO.Outputs.Add(resourceIO.OutputFile);
                }
            }
        }
示例#29
0
        private static void AddNonCultureResources(ProjectContext project, string intermediaryOutputPath, CompilerIO compilerIO)
        {
            foreach (var resourceIO in CompilerUtil.GetNonCultureResources(project.ProjectFile, intermediaryOutputPath))
            {
                compilerIO.Inputs.Add(resourceIO.InputFile);

                if (resourceIO.OutputFile != null)
                {
                    compilerIO.Outputs.Add(resourceIO.OutputFile);
                }
            }
        }
示例#30
0
        private IncrementalResult InputItemsChanged(ProjectGraphNode graphNode, CompilerIO compilerIO)
        {
            // check empty inputs / outputs
            if (!compilerIO.Inputs.Any())
            {
                return new IncrementalResult("the project has no inputs");
            }

            if (!compilerIO.Outputs.Any())
            {
                return new IncrementalResult("the project has no outputs");
            }

            // check non existent items
            var result = CheckMissingIO(compilerIO.Inputs, "inputs");
            if (result.NeedsRebuilding)
            {
                return result;
            }

            result = CheckMissingIO(compilerIO.Outputs, "outputs");
            if (result.NeedsRebuilding)
            {
                return result;
            }

            return CheckInputGlobChanges(graphNode, compilerIO);
        }
示例#31
0
 public IncrementalCache(CompilerIO compilerIO)
 {
     CompilerIO = compilerIO;
 }
示例#32
0
        private static void AddDependencies(ProjectDependenciesFacade dependencies, CompilerIO compilerIO)
        {
            // add dependency sources that need compilation
            compilerIO.Inputs.AddRange(dependencies.ProjectDependenciesWithSources.Values.SelectMany(p => p.Project.Files.SourceFiles));

            // add compilation binaries
            compilerIO.Inputs.AddRange(dependencies.Dependencies.SelectMany(d => d.CompilationAssemblies.Select(ca => ca.ResolvedPath)));
        }