コード例 #1
0
        /// <summary>
        /// Logs that a target has finished.
        /// </summary>
        /// <param name="targetBuildEventContext">Event context for the target</param>
        /// <param name="targetName">Target which has just finished</param>
        /// <param name="projectFile">Project file being built</param>
        /// <param name="projectFileOfTargetElement">Project file which contains the target</param>
        /// <param name="success">Did the target pass or fail</param>
        /// <param name="targetOutputs">Target outputs for the target.</param>
        /// <exception cref="InternalErrorException">BuildEventContext is null</exception>
        public void LogTargetFinished(BuildEventContext targetBuildEventContext, string targetName, string projectFile, string projectFileOfTargetElement, bool success, IEnumerable <TaskItem> targetOutputs)
        {
            lock (_lockObject)
            {
                if (!OnlyLogCriticalEvents)
                {
                    ErrorUtilities.VerifyThrow(targetBuildEventContext != null, "targetBuildEventContext is null");

                    string message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword(success ? "TargetFinishedSuccess" : "TargetFinishedFailure", targetName, Path.GetFileName(projectFile));

                    TargetFinishedEventArgs buildEvent = new TargetFinishedEventArgs
                                                         (
                        message,
                        null,                 // no help keyword
                        targetName,
                        projectFile,
                        projectFileOfTargetElement,
                        success,
                        targetOutputs
                                                         );

                    buildEvent.BuildEventContext = targetBuildEventContext;
                    ProcessLoggingEvent(buildEvent);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Logs that task execution has started.
        /// </summary>
        /// <param name="targetBuildEventContext">Event context for the target spawning this task.</param>
        /// <param name="taskName">Task Name</param>
        /// <param name="projectFile">Project file being built</param>
        /// <param name="projectFileOfTaskNode">Project file which contains the task</param>
        /// <returns>The build event context for the task.</returns>
        /// <exception cref="InternalErrorException">BuildEventContext is null</exception>
        public BuildEventContext LogTaskStarted2(BuildEventContext targetBuildEventContext, string taskName, string projectFile, string projectFileOfTaskNode)
        {
            lock (_lockObject)
            {
                ErrorUtilities.VerifyThrow(targetBuildEventContext != null, "targetBuildEventContext is null");
                BuildEventContext taskBuildEventContext = new BuildEventContext
                                                          (
                    targetBuildEventContext.SubmissionId,
                    targetBuildEventContext.NodeId,
                    targetBuildEventContext.ProjectInstanceId,
                    targetBuildEventContext.ProjectContextId,
                    targetBuildEventContext.TargetId,
                    NextTaskId
                                                          );

                if (!OnlyLogCriticalEvents)
                {
                    TaskStartedEventArgs buildEvent = new TaskStartedEventArgs
                                                      (
                        ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TaskStarted", taskName),
                        null,     // no help keyword
                        projectFile,
                        projectFileOfTaskNode,
                        taskName
                                                      );
                    buildEvent.BuildEventContext = taskBuildEventContext;
                    ProcessLoggingEvent(buildEvent);
                }

                return(taskBuildEventContext);
            }
        }
コード例 #3
0
        public static async Task <ProjectCacheService> FromDescriptorAsync(
            ProjectCacheDescriptor pluginDescriptor,
            BuildManager buildManager,
            ILoggingService loggingService,
            CancellationToken cancellationToken)
        {
            var plugin = await Task.Run(() => GetPluginInstance(pluginDescriptor), cancellationToken)
                         .ConfigureAwait(false);

            // TODO: Detect and use the highest verbosity from all the user defined loggers. That's tricky because right now we can't discern between user set loggers and msbuild's internally added loggers.
            var logger = new LoggingServiceToPluginLoggerAdapter(LoggerVerbosity.Normal, loggingService);

            await plugin.BeginBuildAsync(
                new CacheContext(
                    pluginDescriptor.PluginSettings,
                    new IFileSystemAdapter(FileSystems.Default),
                    pluginDescriptor.ProjectGraph,
                    pluginDescriptor.EntryPoints),
                // TODO: Detect verbosity from logging service.
                logger,
                cancellationToken);

            if (logger.HasLoggedErrors)
            {
                throw new Exception(
                          ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectCacheInitializationFailed"));
            }

            return(new ProjectCacheService(plugin, buildManager, logger, pluginDescriptor, cancellationToken));
        }
コード例 #4
0
        /// <summary>
        /// Logs that a project has finished
        /// </summary>
        /// <param name="projectBuildEventContext">Event context for the project.</param>
        /// <param name="projectFile">Project file being built</param>
        /// <param name="success">Did the project pass or fail</param>
        /// <exception cref="InternalErrorException">BuildEventContext is null</exception>
        public void LogProjectFinished(BuildEventContext projectBuildEventContext, string projectFile, bool success)
        {
            lock (_lockObject)
            {
                ErrorUtilities.VerifyThrow(projectBuildEventContext != null, "projectBuildEventContext");

                string message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword(success ? "ProjectFinishedSuccess" : "ProjectFinishedFailure", Path.GetFileName(projectFile));

                ProjectFinishedEventArgs buildEvent = new ProjectFinishedEventArgs
                                                      (
                    message,
                    null,     // no help keyword
                    projectFile,
                    success
                                                      );
                buildEvent.BuildEventContext = projectBuildEventContext;
                ProcessLoggingEvent(buildEvent);

                // PERF: Not using VerifyThrow to avoid boxing of projectBuildEventContext.ProjectContextId in the non-error case.
                if (!_projectFileMap.ContainsKey(projectBuildEventContext.ProjectContextId))
                {
                    ErrorUtilities.ThrowInternalError("ContextID {0} for project {1} should be in the ID-to-file mapping!", projectBuildEventContext.ProjectContextId, projectFile);
                }

                _projectFileMap.Remove(projectBuildEventContext.ProjectContextId);
            }
        }
コード例 #5
0
        /// <summary>
        /// Logs that a target started
        /// </summary>
        /// <param name="projectBuildEventContext">Event context for the project spawning this target</param>
        /// <param name="targetName">Name of target</param>
        /// <param name="projectFile">Project file being built</param>
        /// <param name="projectFileOfTargetElement">Project file which contains the target</param>
        /// <param name="parentTargetName">The name of the parent target.</param>
        /// <param name="buildReason">The reason the parent target built the target.</param>
        /// <returns>The build event context for the target.</returns>
        /// <exception cref="InternalErrorException">BuildEventContext is null</exception>
        public BuildEventContext LogTargetStarted(BuildEventContext projectBuildEventContext, string targetName, string projectFile, string projectFileOfTargetElement, string parentTargetName, TargetBuiltReason buildReason)
        {
            lock (_lockObject)
            {
                ErrorUtilities.VerifyThrow(projectBuildEventContext != null, "projectBuildEventContext is null");
                BuildEventContext targetBuildEventContext = new BuildEventContext
                                                            (
                    projectBuildEventContext.SubmissionId,
                    projectBuildEventContext.NodeId,
                    projectBuildEventContext.ProjectInstanceId,
                    projectBuildEventContext.ProjectContextId,
                    NextTargetId,
                    BuildEventContext.InvalidTaskId
                                                            );

                string message = String.Empty;
                if (!OnlyLogCriticalEvents)
                {
                    if (String.Equals(projectFile, projectFileOfTargetElement, StringComparison.OrdinalIgnoreCase))
                    {
                        if (!String.IsNullOrEmpty(parentTargetName))
                        {
                            message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TargetStartedProjectDepends", targetName, projectFile, parentTargetName);
                        }
                        else
                        {
                            message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TargetStartedProjectEntry", targetName, projectFile);
                        }
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(parentTargetName))
                        {
                            message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TargetStartedFileProjectDepends", targetName, projectFileOfTargetElement, projectFile, parentTargetName);
                        }
                        else
                        {
                            message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TargetStartedFileProjectEntry", targetName, projectFileOfTargetElement, projectFile);
                        }
                    }

                    TargetStartedEventArgs buildEvent = new TargetStartedEventArgs
                                                        (
                        message,
                        null,     // no help keyword
                        targetName,
                        projectFile,
                        projectFileOfTargetElement,
                        parentTargetName,
                        buildReason,
                        DateTime.UtcNow
                                                        );
                    buildEvent.BuildEventContext = targetBuildEventContext;
                    ProcessLoggingEvent(buildEvent);
                }

                return(targetBuildEventContext);
            }
        }
コード例 #6
0
        /// <summary>
        /// Logs that a project build has started
        /// </summary>
        /// <param name="nodeBuildEventContext">The event context of the node which is spawning this project.</param>
        /// <param name="submissionId">The id of the submission.</param>
        /// <param name="projectInstanceId">Id of the project instance which is being started</param>
        /// <param name="parentBuildEventContext">BuildEventContext of the project who is requesting "projectFile" to build</param>
        /// <param name="projectFile">Project file to build</param>
        /// <param name="targetNames">Target names to build</param>
        /// <param name="properties">Initial property list</param>
        /// <param name="items">Initial items list</param>
        /// <param name="evaluationId">EvaluationId of the project instance</param>
        /// <returns>The build event context for the project.</returns>
        /// <exception cref="InternalErrorException">parentBuildEventContext is null</exception>
        /// <exception cref="InternalErrorException">projectBuildEventContext is null</exception>
        public BuildEventContext LogProjectStarted(BuildEventContext nodeBuildEventContext, int submissionId, int projectInstanceId, BuildEventContext parentBuildEventContext, string projectFile, string targetNames, IEnumerable <DictionaryEntry> properties, IEnumerable <DictionaryEntry> items, int evaluationId = BuildEventContext.InvalidEvaluationId)
        {
            lock (_lockObject)
            {
                ErrorUtilities.VerifyThrow(nodeBuildEventContext != null, "Need a nodeBuildEventContext");
                BuildEventContext projectBuildEventContext = new BuildEventContext(submissionId, nodeBuildEventContext.NodeId, evaluationId, projectInstanceId, NextProjectId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId);

                // PERF: Not using VerifyThrow to avoid boxing of projectBuildEventContext.ProjectContextId in the non-error case.
                if (_projectFileMap.ContainsKey(projectBuildEventContext.ProjectContextId))
                {
                    ErrorUtilities.ThrowInternalError("ContextID {0} for project {1} should not already be in the ID-to-file mapping!", projectBuildEventContext.ProjectContextId, projectFile);
                }

                _projectFileMap[projectBuildEventContext.ProjectContextId] = projectFile;

                ErrorUtilities.VerifyThrow(parentBuildEventContext != null, "Need a parentBuildEventContext");

                string message         = string.Empty;
                string projectFilePath = Path.GetFileName(projectFile);

                // Check to see if the there are any specific target names to be built.
                // If targetNames is null or empty then we will be building with the
                // default targets.
                if (!String.IsNullOrEmpty(targetNames))
                {
                    message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectStartedPrefixForTopLevelProjectWithTargetNames", projectFilePath, targetNames);
                }
                else
                {
                    message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectStartedPrefixForTopLevelProjectWithDefaultTargets", projectFilePath);
                }

                ErrorUtilities.VerifyThrow(_configCache.Value.HasConfiguration(projectInstanceId), "Cannot find the project configuration while injecting non-serialized data from out-of-proc node.");
                var buildRequestConfiguration = _configCache.Value[projectInstanceId];

                // Always log GlobalProperties on ProjectStarted
                // See https://github.com/dotnet/msbuild/issues/6341 for details
                IDictionary <string, string> globalProperties = buildRequestConfiguration.GlobalProperties.ToDictionary();

                var buildEvent = new ProjectStartedEventArgs
                                 (
                    projectInstanceId,
                    message,
                    helpKeyword: null,
                    projectFile,
                    targetNames,
                    properties,
                    items,
                    parentBuildEventContext,
                    globalProperties,
                    buildRequestConfiguration.ToolsVersion
                                 );
                buildEvent.BuildEventContext = projectBuildEventContext;

                ProcessLoggingEvent(buildEvent);

                return(projectBuildEventContext);
            }
        }
コード例 #7
0
        public async Task ShutDown()
        {
            await _projectCachePlugin.EndBuildAsync(_logger, _cancellationToken);

            if (_logger.HasLoggedErrors)
            {
                throw new Exception(
                          ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectCacheShutdownFailed"));
            }
        }
コード例 #8
0
        public override void TargetFinishedHandler(object sender, TargetFinishedEventArgs e)
        {
            // Done with the target, so shift everything left again.
            this.currentIndentLevel--;

            if (this.showPerfSummary)
            {
                PerformanceCounter counter = GetPerformanceCounter(e.TargetName, ref targetPerformanceCounters);

                // Place the counter "in scope" meaning the target is done executing right now.
                counter.InScope = false;
            }

            bool targetHasErrorsOrWarnings = contextStack.Peek().hasErrorsOrWarnings;

            // if verbosity is diagnostic,
            // or there was an error or warning and verbosity is normal or detailed
            if ((targetHasErrorsOrWarnings && (IsVerbosityAtLeast(LoggerVerbosity.Normal))) ||
                Verbosity == LoggerVerbosity.Diagnostic)
            {
                setColor(ConsoleColor.Cyan);

                if (showTargetOutputs)
                {
                    IEnumerable targetOutputs = e.TargetOutputs;

                    if (targetOutputs != null)
                    {
                        WriteLinePretty(ResourceUtilities.GetResourceString("TargetOutputItemsHeader"));
                        foreach (ITaskItem item in targetOutputs)
                        {
                            WriteLinePretty(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TargetOutputItem", item.ItemSpec));
                        }
                    }
                }

                WriteLinePretty(e.Message);
                resetColor();
            }

            Frame top = contextStack.Pop();

            this.VerifyStack(top.type == FrameType.Target, "bad stack frame type");
            this.VerifyStack(top.ID == e.TargetName, "bad stack frame id");

            // set the value on the Project frame, for the ProjectFinished handler
            if (targetHasErrorsOrWarnings)
            {
                SetErrorsOrWarningsOnCurrentFrame();
            }
        }
コード例 #9
0
        public async Task <CacheResult> GetCacheResultAsync(BuildRequestData buildRequest)
        {
            // TODO: Parent these logs under the project build event so they appear nested under the project in the binlog viewer.
            var queryDescription = $"{buildRequest.ProjectFullPath}" +
                                   $"\n\tTargets:[{string.Join(", ", buildRequest.TargetNames)}]" +
                                   $"\n\tGlobal Properties: {{{string.Join(",", buildRequest.GlobalProperties.Select(kvp => $"{kvp.Name}={kvp.EvaluatedValue}"))}}}";

            _logger.LogMessage(
                "\n====== Querying project cache for project " + queryDescription,
                MessageImportance.High);

            var cacheResult = await _projectCachePlugin.GetCacheResultAsync(buildRequest, _logger, _cancellationToken);

            if (_logger.HasLoggedErrors || cacheResult.ResultType == CacheResultType.None)
            {
                throw new Exception(
                          ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectCacheQueryFailed", queryDescription));
            }

            var message = $"Plugin result: {cacheResult.ResultType}.";

            switch (cacheResult.ResultType)
            {
            case CacheResultType.CacheHit:
                message += " Skipping project.";
                break;

            case CacheResultType.CacheMiss:
            case CacheResultType.CacheNotApplicable:
                message += " Building project.";
                break;

            case CacheResultType.None:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            _logger.LogMessage(
                message,
                MessageImportance.High);

            return(cacheResult);
        }
コード例 #10
0
ファイル: ElementLocation.cs プロジェクト: avco2018/azure123
        /// <summary>
        /// The location in a form suitable for replacement
        /// into a message.
        /// Example: "c:\foo\bar.csproj (12,34)"
        /// Calling this creates and formats a new string.
        /// PREFER TO PUT THE LOCATION INFORMATION AT THE START OF THE MESSAGE INSTEAD.
        /// Only in rare cases should the location go within the message itself.
        /// </summary>
        private static string GetLocationString(string file, int line, int column)
        {
            string locationString = String.Empty;

            if (line != 0 && column != 0)
            {
                locationString = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("FileLocation", file, line, column);
            }
            else if (line != 0)
            {
                locationString = file + " (" + line + ")";
            }
            else
            {
                locationString = file;
            }

            return(locationString);
        }
コード例 #11
0
        /// <summary>
        /// Try to get a message to inform the user which processes have a lock on a given file.
        /// </summary>
        private static string GetLockedFileMessage(string file)
        {
            string message = string.Empty;

#if !RUNTIME_TYPE_NETCORE && !MONO
            try
            {
                var processes = LockCheck.GetProcessesLockingFile(file);
                message = !string.IsNullOrEmpty(processes)
                    ? ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("Copy.FileLocked", processes)
                    : String.Empty;
            }
            catch (Exception)
            {
                // Never throw if we can't get the processes locking the file.
            }
#endif
            return(message);
        }
コード例 #12
0
 /// <summary>
 /// Logs that task execution has started.
 /// </summary>
 /// <param name="taskBuildEventContext">Event context for the task</param>
 /// <param name="taskName">Task Name</param>
 /// <param name="projectFile">Project file being built</param>
 /// <param name="projectFileOfTaskNode">Project file which contains the task</param>
 /// <exception cref="InternalErrorException">BuildEventContext is null</exception>
 public void LogTaskStarted(BuildEventContext taskBuildEventContext, string taskName, string projectFile, string projectFileOfTaskNode)
 {
     lock (_lockObject)
     {
         ErrorUtilities.VerifyThrow(taskBuildEventContext != null, "targetBuildEventContext is null");
         if (!OnlyLogCriticalEvents)
         {
             TaskStartedEventArgs buildEvent = new TaskStartedEventArgs
                                               (
                 ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("TaskStarted", taskName),
                 null,     // no help keyword
                 projectFile,
                 projectFileOfTaskNode,
                 taskName
                                               );
             buildEvent.BuildEventContext = taskBuildEventContext;
             ProcessLoggingEvent(buildEvent);
         }
     }
 }
コード例 #13
0
        private static string GetLockedFileMessage(string file)
        {
            string message = string.Empty;

            try
            {
                if (NativeMethodsShared.IsWindows && ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4))
                {
                    var processes = LockCheck.GetProcessesLockingFile(file);
                    message = !string.IsNullOrEmpty(processes)
                        ? ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("Copy.FileLocked", processes)
                        : String.Empty;
                }
            }
            catch (Exception)
            {
                // Never throw if we can't get the processes locking the file.
            }

            return(message);
        }
コード例 #14
0
ファイル: SuggestedRedirects.cs プロジェクト: xen2/msbuild
        public void ConflictWithBackVersionPrimaryWithAutoUnify()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);

            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("B"),
                new TaskItem("A"),
                new TaskItem("D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa")
            };

            t.AutoUnify = true;

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V2Path, s_myLibraries_V1Path
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            bool result = Execute(t);

            Assert.Equal(1, e.Warnings); // @"Expected one warning."

            // Check that we have a message identifying conflicts with "D"
            string warningMessage = e.WarningEvents[0].Message;

            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveAssemblyReference.FoundConflicts", "D", string.Empty));
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.ConflictFound", "D, Version=1.0.0.0, CulTUre=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa", "D, Version=2.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa"));
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.FourSpaceIndent", ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.ReferenceDependsOn", "D, Version=1.0.0.0, CulTUre=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa", Path.Combine(s_myLibraries_V1Path, "D.dll"))));

            Assert.Empty(t.SuggestedRedirects);
            Assert.Equal(3, t.ResolvedFiles.Length);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_V1_DDllPath)); // "Expected to find assembly, but didn't."
        }
コード例 #15
0
        private List <ProjectInterpretation.ReferenceInfo> ParseReferences(ProjectGraphNode parsedProject)
        {
            var referenceInfos = new List <ProjectInterpretation.ReferenceInfo>();

            foreach (var referenceInfo in _projectInterpretation.GetReferences(parsedProject.ProjectInstance))
            {
                if (FileUtilities.IsSolutionFilename(referenceInfo.ReferenceConfiguration.ProjectFullPath))
                {
                    throw new InvalidOperationException(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword(
                                                            "StaticGraphDoesNotSupportSlnReferences",
                                                            referenceInfo.ReferenceConfiguration.ProjectFullPath,
                                                            referenceInfo.ReferenceConfiguration.ProjectFullPath
                                                            ));
                }

                SubmitProjectForParsing(referenceInfo.ReferenceConfiguration);

                referenceInfos.Add(referenceInfo);
            }

            return(referenceInfos);
        }
コード例 #16
0
        /// <summary>
        /// Logs that a task has finished executing.
        /// </summary>
        /// <param name="taskBuildEventContext">Event context for the task</param>
        /// <param name="taskName">Name of the task</param>
        /// <param name="projectFile">Project which is being processed</param>
        /// <param name="projectFileOfTaskNode">Project file which contains the task</param>
        /// <param name="success">Did the task pass or fail</param>
        /// <exception cref="InternalErrorException">BuildEventContext is null</exception>
        public void LogTaskFinished(BuildEventContext taskBuildEventContext, string taskName, string projectFile, string projectFileOfTaskNode, bool success)
        {
            lock (_lockObject)
            {
                if (!OnlyLogCriticalEvents)
                {
                    ErrorUtilities.VerifyThrow(taskBuildEventContext != null, "taskBuildEventContext is null");
                    string message = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword(success ? "TaskFinishedSuccess" : "TaskFinishedFailure", taskName);

                    TaskFinishedEventArgs buildEvent = new TaskFinishedEventArgs
                                                       (
                        message,
                        null,     // no help keyword
                        projectFile,
                        projectFileOfTaskNode,
                        taskName,
                        success
                                                       );
                    buildEvent.BuildEventContext = taskBuildEventContext;
                    ProcessLoggingEvent(buildEvent);
                }
            }
        }
コード例 #17
0
        /// <summary>
        /// Fills in the property data structure
        /// </summary>
        private bool ParseParameter(XamlTypes.BaseProperty baseProperty, LinkedList <Property> propertyList, Property property, Dictionary <string, Property> argumentDependencyLookup)
        {
            Property propertyToAdd = ObtainAttributes(baseProperty, property);

            if (String.IsNullOrEmpty(propertyToAdd.Name))
            {
                propertyToAdd.Name = "AlwaysAppend";
            }

            // generate the list of parameters in order
            if (!_switchOrderList.Contains(propertyToAdd.Name))
            {
                _switchOrderList.Add(propertyToAdd.Name);
            }
            else
            {
                throw new XamlParseException(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("Xaml.DuplicatePropertyName", propertyToAdd.Name));
            }

            // Inherit the Prefix from the Tool
            if (String.IsNullOrEmpty(propertyToAdd.Prefix))
            {
                propertyToAdd.Prefix = DefaultPrefix;
            }

            // If the property is an enum type, parse that.
            XamlTypes.EnumProperty enumProperty = baseProperty as XamlTypes.EnumProperty;
            if (enumProperty != null)
            {
                foreach (XamlTypes.EnumValue enumValue in enumProperty.AdmissibleValues)
                {
                    var value = new Value
                    {
                        Name       = enumValue.Name,
                        SwitchName = enumValue.Switch
                    };

                    if (value.SwitchName == null)
                    {
                        value.SwitchName = String.Empty;
                    }

                    value.DisplayName = enumValue.DisplayName;
                    value.Description = enumValue.Description;
                    value.Prefix      = enumValue.SwitchPrefix;
                    if (String.IsNullOrEmpty(value.Prefix))
                    {
                        value.Prefix = enumProperty.SwitchPrefix;
                    }

                    if (String.IsNullOrEmpty(value.Prefix))
                    {
                        value.Prefix = DefaultPrefix;
                    }

                    if (enumValue.Arguments.Count > 0)
                    {
                        value.Arguments = new List <Argument>();
                        foreach (XamlTypes.Argument argument in enumValue.Arguments)
                        {
                            var arg = new Argument
                            {
                                Parameter = argument.Property,
                                Separator = argument.Separator,
                                Required  = argument.IsRequired
                            };
                            value.Arguments.Add(arg);
                        }
                    }

                    if (value.Prefix == null)
                    {
                        value.Prefix = propertyToAdd.Prefix;
                    }

                    propertyToAdd.Values.Add(value);
                }
            }

            // build the dependencies and the values for a parameter
            foreach (XamlTypes.Argument argument in baseProperty.Arguments)
            {
                // To refactor into a separate func
                if (propertyToAdd.Arguments == null)
                {
                    propertyToAdd.Arguments = new List <Argument>();
                }

                var arg = new Argument
                {
                    Parameter = argument.Property,
                    Separator = argument.Separator,
                    Required  = argument.IsRequired
                };
                propertyToAdd.Arguments.Add(arg);
            }

            if (argumentDependencyLookup != null && !argumentDependencyLookup.ContainsKey(propertyToAdd.Name))
            {
                argumentDependencyLookup.Add(propertyToAdd.Name, propertyToAdd);
            }

            // We've read any enumerated values and any dependencies, so we just
            // have to add the property
            propertyList.AddLast(propertyToAdd);
            return(true);
        }
コード例 #18
0
ファイル: MSBuild.cs プロジェクト: maoxingda/msbuild-1
        internal static async Task <bool> ExecuteTargets(
            ITaskItem[] projects,
            Dictionary <string, string> propertiesTable,
            string[] undefineProperties,
            List <string[]> targetLists,
            bool stopOnFirstFailure,
            bool rebaseOutputs,
            IBuildEngine3 buildEngine,
            TaskLoggingHelper log,
            List <ITaskItem> targetOutputs,
            bool unloadProjectsOnCompletion,
            string toolsVersion,
            bool skipNonexistentTargets)
        {
            bool success = true;

            // We don't log a message about the project and targets we're going to
            // build, because it'll all be in the immediately subsequent ProjectStarted event.

            var projectDirectory             = new string[projects.Length];
            var projectNames                 = new string[projects.Length];
            var toolsVersions                = new string[projects.Length];
            var projectProperties            = new Dictionary <string, string> [projects.Length];
            var undefinePropertiesPerProject = new List <string> [projects.Length];

            for (int i = 0; i < projectNames.Length; i++)
            {
                projectNames[i]      = null;
                projectProperties[i] = propertiesTable;

                if (projects[i] != null)
                {
                    // Retrieve projectDirectory only the first time.  It never changes anyway.
                    string projectPath = FileUtilities.AttemptToShortenPath(projects[i].ItemSpec);
                    projectDirectory[i] = Path.GetDirectoryName(projectPath);
                    projectNames[i]     = projects[i].ItemSpec;
                    toolsVersions[i]    = toolsVersion;

                    // If the user specified a different set of global properties for this project, then
                    // parse the string containing the properties
                    if (!String.IsNullOrEmpty(projects[i].GetMetadata("Properties")))
                    {
                        if (!PropertyParser.GetTableWithEscaping
                                (log, ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("General.OverridingProperties", projectNames[i]), "Properties", projects[i].GetMetadata("Properties").Split(MSBuildConstants.SemicolonChar, StringSplitOptions.RemoveEmptyEntries),
                                out Dictionary <string, string> preProjectPropertiesTable)
                            )
                        {
                            return(false);
                        }

                        projectProperties[i] = preProjectPropertiesTable;
                    }

                    if (undefineProperties != null)
                    {
                        undefinePropertiesPerProject[i] = new List <string>(undefineProperties);
                    }

                    // If the user wanted to undefine specific global properties for this project, parse
                    // that string and remove them now.
                    string projectUndefineProperties = projects[i].GetMetadata("UndefineProperties");
                    if (!String.IsNullOrEmpty(projectUndefineProperties))
                    {
                        string[] propertiesToUndefine = projectUndefineProperties.Split(MSBuildConstants.SemicolonChar, StringSplitOptions.RemoveEmptyEntries);
                        if (undefinePropertiesPerProject[i] == null)
                        {
                            undefinePropertiesPerProject[i] = new List <string>(propertiesToUndefine.Length);
                        }

                        if (log != null && propertiesToUndefine.Length > 0)
                        {
                            log.LogMessageFromResources(MessageImportance.Low, "General.ProjectUndefineProperties", projectNames[i]);
                            foreach (string property in propertiesToUndefine)
                            {
                                undefinePropertiesPerProject[i].Add(property);
                                log.LogMessageFromText(String.Format(CultureInfo.InvariantCulture, "  {0}", property), MessageImportance.Low);
                            }
                        }
                    }

                    // If the user specified a different set of global properties for this project, then
                    // parse the string containing the properties
                    if (!String.IsNullOrEmpty(projects[i].GetMetadata("AdditionalProperties")))
                    {
                        if (!PropertyParser.GetTableWithEscaping
                                (log, ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("General.AdditionalProperties", projectNames[i]), "AdditionalProperties", projects[i].GetMetadata("AdditionalProperties").Split(MSBuildConstants.SemicolonChar, StringSplitOptions.RemoveEmptyEntries),
                                out Dictionary <string, string> additionalProjectPropertiesTable)
                            )
                        {
                            return(false);
                        }

                        var combinedTable = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
                        // First copy in the properties from the global table that not in the additional properties table
                        if (projectProperties[i] != null)
                        {
                            foreach (KeyValuePair <string, string> entry in projectProperties[i])
                            {
                                if (!additionalProjectPropertiesTable.ContainsKey(entry.Key))
                                {
                                    combinedTable.Add(entry.Key, entry.Value);
                                }
                            }
                        }
                        // Add all the additional properties
                        foreach (KeyValuePair <string, string> entry in additionalProjectPropertiesTable)
                        {
                            combinedTable.Add(entry.Key, entry.Value);
                        }
                        projectProperties[i] = combinedTable;
                    }

                    // If the user specified a different toolsVersion for this project - then override the setting
                    if (!String.IsNullOrEmpty(projects[i].GetMetadata("ToolsVersion")))
                    {
                        toolsVersions[i] = projects[i].GetMetadata("ToolsVersion");
                    }
                }
            }

            foreach (string[] targetList in targetLists)
            {
                if (stopOnFirstFailure && !success)
                {
                    // Inform the user that we skipped the remaining targets StopOnFirstFailure=true.
                    log.LogMessageFromResources(MessageImportance.Low, "MSBuild.SkippingRemainingTargets");

                    // We have encountered a failure.  Caller has requested that we not
                    // continue with remaining targets.
                    break;
                }

                // Send the project off to the build engine.  By passing in null to the
                // first param, we are indicating that the project to build is the same
                // as the *calling* project file.

                var taskHost             = (TaskHost)buildEngine;
                BuildEngineResult result = await taskHost.InternalBuildProjects(projectNames, targetList, projectProperties, undefinePropertiesPerProject, toolsVersions, true /* ask that target outputs are returned in the buildengineresult */, skipNonexistentTargets);

                bool currentTargetResult = result.Result;
                IList <IDictionary <string, ITaskItem[]> > targetOutputsPerProject = result.TargetOutputsPerProject;
                success = success && currentTargetResult;

                // If the engine was able to satisfy the build request
                if (currentTargetResult)
                {
                    for (int i = 0; i < projects.Length; i++)
                    {
                        IEnumerable <string> nonNullTargetList = targetList ?? targetOutputsPerProject[i].Keys;

                        foreach (string targetName in nonNullTargetList)
                        {
                            if (targetOutputsPerProject[i].ContainsKey(targetName))
                            {
                                ITaskItem[] outputItemsFromTarget = targetOutputsPerProject[i][targetName];

                                foreach (ITaskItem outputItemFromTarget in outputItemsFromTarget)
                                {
                                    // No need to rebase if the calling project is the same as the callee project
                                    // (project == null).  Also no point in trying to copy item metadata either,
                                    // because no items were passed into the Projects parameter!
                                    if (projects[i] != null)
                                    {
                                        // Rebase the output item paths if necessary.  No need to rebase if the calling
                                        // project is the same as the callee project (project == null).
                                        if (rebaseOutputs)
                                        {
                                            try
                                            {
                                                outputItemFromTarget.ItemSpec = Path.Combine(projectDirectory[i], outputItemFromTarget.ItemSpec);
                                            }
                                            catch (ArgumentException e)
                                            {
                                                log.LogWarningWithCodeFromResources(null, projects[i].ItemSpec, 0, 0, 0, 0, "MSBuild.CannotRebaseOutputItemPath", outputItemFromTarget.ItemSpec, e.Message);
                                            }
                                        }

                                        // Copy the custom item metadata from the "Projects" items to these
                                        // output items.
                                        projects[i].CopyMetadataTo(outputItemFromTarget);

                                        // Set a metadata on the output items called "MSBuildProjectFile" which tells you which project file produced this item.
                                        if (String.IsNullOrEmpty(outputItemFromTarget.GetMetadata(ItemMetadataNames.msbuildSourceProjectFile)))
                                        {
                                            outputItemFromTarget.SetMetadata(ItemMetadataNames.msbuildSourceProjectFile, projects[i].GetMetadata(FileUtilities.ItemSpecModifiers.FullPath));
                                        }
                                    }

                                    // Set a metadata on the output items called "MSBuildTargetName" which tells you which target produced this item.
                                    if (String.IsNullOrEmpty(outputItemFromTarget.GetMetadata(ItemMetadataNames.msbuildSourceTargetName)))
                                    {
                                        outputItemFromTarget.SetMetadata(ItemMetadataNames.msbuildSourceTargetName, targetName);
                                    }
                                }

                                targetOutputs.AddRange(outputItemsFromTarget);
                            }
                        }
                    }
                }
            }

            return(success);
        }
コード例 #19
0
        /// <returns>True if the operation was successful</returns>
        internal static bool ExecuteTargets
        (
            List <ITaskItem> projects,
            Dictionary <string, string> propertiesTable,
            string[] undefineProperties,
            List <string[]> targetLists,
            bool stopOnFirstFailure,
            bool rebaseOutputs,
            IBuildEngine3 buildEngine,
            TaskLoggingHelper log,
            List <ITaskItem> targetOutputs,
            bool unloadProjectsOnCompletion,
            string toolsVersion
        )
        {
            bool success = true;

            // We don't log a message about the project and targets we're going to
            // build, because it'll all be in the immediately subsequent ProjectStarted event.

            var projectDirectory             = new string[projects.Count];
            var projectNames                 = new string[projects.Count];
            var toolsVersions                = new string[projects.Count];
            var projectProperties            = new Dictionary <string, string> [projects.Count];
            var undefinePropertiesPerProject = new IList <string> [projects.Count];

            for (int i = 0; i < projectNames.Length; i++)
            {
                projectNames[i]      = null;
                projectProperties[i] = propertiesTable;

                if (projects[i] != null)
                {
                    // Retrieve projectDirectory only the first time.  It never changes anyway.
                    string projectPath = FileUtilities.AttemptToShortenPath(projects[i].ItemSpec);
                    projectDirectory[i] = Path.GetDirectoryName(projectPath);
                    projectNames[i]     = projects[i].ItemSpec;
                    toolsVersions[i]    = toolsVersion;

                    // If the user specified a different set of global properties for this project, then
                    // parse the string containing the properties
                    if (!String.IsNullOrEmpty(projects[i].GetMetadata("Properties")))
                    {
                        if (!PropertyParser.GetTableWithEscaping
                                (log, ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("General.OverridingProperties", projectNames[i]), "Properties", projects[i].GetMetadata("Properties").Split(MSBuildConstants.SemicolonChar),
                                out Dictionary <string, string> preProjectPropertiesTable)
                            )
                        {
                            return(false);
                        }
                        projectProperties[i] = preProjectPropertiesTable;
                    }

                    if (undefineProperties != null)
                    {
                        undefinePropertiesPerProject[i] = new List <string>(undefineProperties);
                    }

                    // If the user wanted to undefine specific global properties for this project, parse
                    // that string and remove them now.
                    string projectUndefineProperties = projects[i].GetMetadata("UndefineProperties");
                    if (!String.IsNullOrEmpty(projectUndefineProperties))
                    {
                        string[] propertiesToUndefine = projectUndefineProperties.Split(MSBuildConstants.SemicolonChar);
                        if (undefinePropertiesPerProject[i] == null)
                        {
                            undefinePropertiesPerProject[i] = new List <string>(propertiesToUndefine.Length);
                        }

                        if (log != null && propertiesToUndefine.Length > 0)
                        {
                            log.LogMessageFromResources(MessageImportance.Low, "General.ProjectUndefineProperties", projectNames[i]);
                            foreach (string property in propertiesToUndefine)
                            {
                                undefinePropertiesPerProject[i].Add(property);
                                log.LogMessageFromText($"  {property}", MessageImportance.Low);
                            }
                        }
                    }

                    // If the user specified a different set of global properties for this project, then
                    // parse the string containing the properties
                    if (!String.IsNullOrEmpty(projects[i].GetMetadata("AdditionalProperties")))
                    {
                        if (!PropertyParser.GetTableWithEscaping
                                (log, ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("General.AdditionalProperties", projectNames[i]), "AdditionalProperties", projects[i].GetMetadata("AdditionalProperties").Split(MSBuildConstants.SemicolonChar),
                                out Dictionary <string, string> additionalProjectPropertiesTable)
                            )
                        {
                            return(false);
                        }
                        var combinedTable = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
                        // First copy in the properties from the global table that not in the additional properties table
                        if (projectProperties[i] != null)
                        {
                            foreach (KeyValuePair <string, string> entry in projectProperties[i])
                            {
                                if (!additionalProjectPropertiesTable.ContainsKey(entry.Key))
                                {
                                    combinedTable.Add(entry.Key, entry.Value);
                                }
                            }
                        }
                        // Add all the additional properties
                        foreach (KeyValuePair <string, string> entry in additionalProjectPropertiesTable)
                        {
                            combinedTable.Add(entry.Key, entry.Value);
                        }
                        projectProperties[i] = combinedTable;
                    }

                    // If the user specified a different toolsVersion for this project - then override the setting
                    if (!String.IsNullOrEmpty(projects[i].GetMetadata("ToolsVersion")))
                    {
                        toolsVersions[i] = projects[i].GetMetadata("ToolsVersion");
                    }
                }
            }

            foreach (string[] targetList in targetLists)
            {
                if (stopOnFirstFailure && !success)
                {
                    // Inform the user that we skipped the remaining targets StopOnFirstFailure=true.
                    log.LogMessageFromResources(MessageImportance.Low, "MSBuild.SkippingRemainingTargets");

                    // We have encountered a failure.  Caller has requested that we not
                    // continue with remaining targets.
                    break;
                }

                // Send the project off to the build engine.  By passing in null to the
                // first param, we are indicating that the project to build is the same
                // as the *calling* project file.

                BuildEngineResult result =
                    buildEngine.BuildProjectFilesInParallel(projectNames, targetList, projectProperties, undefinePropertiesPerProject, toolsVersions, true /* ask that target outputs are returned in the buildengineresult */);

                bool currentTargetResult = result.Result;
                IList <IDictionary <string, ITaskItem[]> > targetOutputsPerProject = result.TargetOutputsPerProject;
                success = success && currentTargetResult;

                // If the engine was able to satisfy the build request
                if (currentTargetResult)
                {
                    for (int i = 0; i < projects.Count; i++)
                    {
                        IEnumerable <string> nonNullTargetList = targetList ?? targetOutputsPerProject[i].Keys;

                        foreach (string targetName in nonNullTargetList)
                        {
                            if (targetOutputsPerProject[i].TryGetValue(targetName, out ITaskItem[] outputItemsFromTarget))
コード例 #20
0
        public static string SerializeCaches(IConfigCache configCache, IResultsCache resultsCache, string outputCacheFile)
        {
            ErrorUtilities.VerifyThrowInternalNull(outputCacheFile, nameof(outputCacheFile));

            try
            {
                if (string.IsNullOrWhiteSpace(outputCacheFile))
                {
                    return(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("EmptyOutputCacheFile"));
                }

                var fullPath = FileUtilities.NormalizePath(outputCacheFile);

                Directory.CreateDirectory(Path.GetDirectoryName(fullPath));

                // Use FileStream constructor (File.OpenWrite should not be used as it doesn't reset the length of the file!)
                using (var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    var translator = BinaryTranslator.GetWriteTranslator(fileStream);

                    ConfigCache  configCacheToSerialize  = null;
                    ResultsCache resultsCacheToSerialize = null;

                    switch (configCache)
                    {
                    case ConfigCache asConfigCache:
                        configCacheToSerialize = asConfigCache;
                        break;

                    case ConfigCacheWithOverride configCacheWithOverride:
                        configCacheToSerialize = configCacheWithOverride.CurrentCache;
                        break;

                    default:
                        ErrorUtilities.ThrowInternalErrorUnreachable();
                        break;
                    }

                    switch (resultsCache)
                    {
                    case ResultsCache asResultsCache:
                        resultsCacheToSerialize = asResultsCache;
                        break;

                    case ResultsCacheWithOverride resultsCacheWithOverride:
                        resultsCacheToSerialize = resultsCacheWithOverride.CurrentCache;
                        break;

                    default:
                        ErrorUtilities.ThrowInternalErrorUnreachable();
                        break;
                    }

                    translator.Translate(ref configCacheToSerialize);
                    translator.Translate(ref resultsCacheToSerialize);
                }
            }
            catch (Exception e)
            {
                return(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ErrorWritingCacheFile", outputCacheFile, e.Message));
            }

            return(null);
        }
コード例 #21
0
        private (IReadOnlyCollection <ProjectGraphEntryPoint> NewEntryPoints, IReadOnlyDictionary <string, IReadOnlyCollection <string> > SolutionDependencies) ExpandSolutionIfPresent(IReadOnlyCollection <ProjectGraphEntryPoint> entryPoints)
        {
            if (entryPoints.Count == 0 || !entryPoints.Any(e => FileUtilities.IsSolutionFilename(e.ProjectFile)))
            {
                return(entryPoints, null);
            }

            if (entryPoints.Count != 1)
            {
                throw new ArgumentException(
                          ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword(
                              "StaticGraphAcceptsSingleSolutionEntryPoint",
                              string.Join(";", entryPoints.Select(e => e.ProjectFile))));
            }

            ErrorUtilities.VerifyThrowArgument(entryPoints.Count == 1, "StaticGraphAcceptsSingleSolutionEntryPoint");

            var solutionEntryPoint       = entryPoints.Single();
            var solutionGlobalProperties = ImmutableDictionary.CreateRange(
                keyComparer: StringComparer.OrdinalIgnoreCase,
                valueComparer: StringComparer.OrdinalIgnoreCase,
                items: solutionEntryPoint.GlobalProperties ?? ImmutableDictionary <string, string> .Empty);

            var solution = SolutionFile.Parse(FileUtilities.NormalizePath(solutionEntryPoint.ProjectFile));

            if (solution.SolutionParserWarnings.Count != 0 || solution.SolutionParserErrorCodes.Count != 0)
            {
                throw new InvalidProjectFileException(
                          ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword(
                              "StaticGraphSolutionLoaderEncounteredSolutionWarningsAndErrors",
                              solutionEntryPoint.ProjectFile,
                              string.Join(";", solution.SolutionParserWarnings),
                              string.Join(";", solution.SolutionParserErrorCodes)));
            }

            var projectsInSolution = GetBuildableProjects(solution);

            var currentSolutionConfiguration = SelectSolutionConfiguration(solution, solutionGlobalProperties);

            var newEntryPoints = new List <ProjectGraphEntryPoint>(projectsInSolution.Count);

            foreach (var project in projectsInSolution)
            {
                if (project.ProjectConfigurations.Count == 0)
                {
                    continue;
                }

                var projectConfiguration = SelectProjectConfiguration(currentSolutionConfiguration, project.ProjectConfigurations);

                if (projectConfiguration.IncludeInBuild)
                {
                    newEntryPoints.Add(
                        new ProjectGraphEntryPoint(
                            FileUtilities.NormalizePath(project.AbsolutePath),
                            solutionGlobalProperties
                            .SetItem("Configuration", projectConfiguration.ConfigurationName)
                            .SetItem("Platform", projectConfiguration.PlatformName)
                            ));
                }
            }

            newEntryPoints.TrimExcess();

            return(newEntryPoints, GetSolutionDependencies(solution));

            IReadOnlyCollection <ProjectInSolution> GetBuildableProjects(SolutionFile solutionFile)
            {
                return(solutionFile.ProjectsInOrder.Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat).ToImmutableArray());
            }

            SolutionConfigurationInSolution SelectSolutionConfiguration(SolutionFile solutionFile, ImmutableDictionary <string, string> globalProperties)
            {
                var solutionConfiguration = globalProperties.ContainsKey("Configuration")
                    ? globalProperties["Configuration"]
                    : solutionFile.GetDefaultConfigurationName();

                var solutionPlatform = globalProperties.ContainsKey("Platform")
                    ? globalProperties["Platform"]
                    : solutionFile.GetDefaultPlatformName();

                return(new SolutionConfigurationInSolution(solutionConfiguration, solutionPlatform));
            }

            ProjectConfigurationInSolution SelectProjectConfiguration(
                SolutionConfigurationInSolution solutionConfig,
                IReadOnlyDictionary <string, ProjectConfigurationInSolution> projectConfigs)
            {
                // implements the matching described in https://docs.microsoft.com/en-us/visualstudio/ide/understanding-build-configurations?view=vs-2019#how-visual-studio-assigns-project-configuration

                var solutionConfigFullName = solutionConfig.FullName;

                if (projectConfigs.ContainsKey(solutionConfigFullName))
                {
                    return(projectConfigs[solutionConfigFullName]);
                }

                var partiallyMarchedConfig = projectConfigs.FirstOrDefault(pc => pc.Value.ConfigurationName.Equals(solutionConfig.ConfigurationName, StringComparison.OrdinalIgnoreCase)).Value;

                return(partiallyMarchedConfig ?? projectConfigs.First().Value);
            }

            IReadOnlyDictionary <string, IReadOnlyCollection <string> > GetSolutionDependencies(SolutionFile solutionFile)
            {
                var solutionDependencies = new Dictionary <string, IReadOnlyCollection <string> >();

                foreach (var projectWithDependencies in solutionFile.ProjectsInOrder.Where(p => p.Dependencies.Count != 0))
                {
                    solutionDependencies[FileUtilities.NormalizePath(projectWithDependencies.AbsolutePath)] = projectWithDependencies.Dependencies.Select(
                        dependencyGuid =>
                    {
                        // code snippet cloned from SolutionProjectGenerator.AddPropertyGroupForSolutionConfiguration

                        if (!solutionFile.ProjectsByGuid.TryGetValue(dependencyGuid, out var dependencyProject))
                        {
                            // If it's not itself part of the solution, that's an invalid solution
                            ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(
                                dependencyProject != null,
                                "SubCategoryForSolutionParsingErrors",
                                new BuildEventFileInfo(solutionFile.FullPath),
                                "SolutionParseProjectDepNotFoundError",
                                projectWithDependencies.ProjectGuid,
                                dependencyGuid);
                        }

                        // Add it to the list of dependencies, but only if it should build in this solution configuration
                        // (If a project is not selected for build in the solution configuration, it won't build even if it's depended on by something that IS selected for build)
                        // .. and only if it's known to be MSBuild format, as projects can't use the information otherwise
                        return(dependencyProject?.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat
                                ? FileUtilities.NormalizePath(dependencyProject.AbsolutePath)
                                : null);
                    })
                                                                                                              .Where(p => p != null)
                                                                                                              .ToArray();
                }

                return(solutionDependencies);
            }
        }