Exemplo n.º 1
0
        private static ProjectGraphWithPredictionsResult BuildGraph(
            IMsBuildAssemblyLoader assemblyLoader,
            GraphBuilderReporter reporter,
            MSBuildGraphBuilderArguments arguments,
            IReadOnlyCollection <IProjectPredictor> projectPredictorsForTesting)
        {
            reporter.ReportMessage("Looking for MSBuild toolset...");

            if (!assemblyLoader.TryLoadMsBuildAssemblies(arguments.MSBuildSearchLocations, reporter, out string failure, out IReadOnlyDictionary <string, string> locatedAssemblyPaths, out string locatedMsBuildPath))
            {
                return(ProjectGraphWithPredictionsResult.CreateFailure(
                           GraphConstructionError.CreateFailureWithoutLocation(failure),
                           locatedAssemblyPaths,
                           locatedMsBuildPath));
            }

            reporter.ReportMessage("Done looking for MSBuild toolset.");

            return(BuildGraphInternal(
                       reporter,
                       locatedAssemblyPaths,
                       locatedMsBuildPath,
                       arguments,
                       projectPredictorsForTesting));
        }
Exemplo n.º 2
0
 private static ProjectGraphWithPredictionsResult <string> CreateFailureFromInvalidProjectFile(IReadOnlyDictionary <string, string> assemblyPathsToLoad, string locatedMsBuildPath, InvalidProjectFileException e)
 {
     return(ProjectGraphWithPredictionsResult.CreateFailure(
                GraphConstructionError.CreateFailureWithLocation(
                    new Location {
         File = e.ProjectFile, Line = e.LineNumber, Position = e.ColumnNumber
     },
                    e.Message),
                assemblyPathsToLoad,
                locatedMsBuildPath));
 }
Exemplo n.º 3
0
        private async Task <Possible <ProjectGraphWithPredictionsResult <AbsolutePath> > > ComputeBuildGraphAsync(
            AbsolutePath responseFile,
            IEnumerable <AbsolutePath> projectEntryPoints,
            AbsolutePath outputFile,
            IEnumerable <AbsolutePath> msBuidSearchLocations,
            IEnumerable <AbsolutePath> dotnetSearchLocations,
            BuildParameters.IBuildParameters buildParameters)
        {
            AbsolutePath dotnetExeLocation = AbsolutePath.Invalid;

            if (m_resolverSettings.ShouldRunDotNetCoreMSBuild())
            {
                if (!TryFindDotNetExe(dotnetSearchLocations, out dotnetExeLocation, out string failure))
                {
                    return(ProjectGraphWithPredictionsResult <AbsolutePath> .CreateFailure(
                               GraphConstructionError.CreateFailureWithoutLocation(failure),
                               CollectionUtilities.EmptyDictionary <string, AbsolutePath>(), AbsolutePath.Invalid));
                }
            }
            SandboxedProcessResult result = await RunMsBuildGraphBuilderAsync(responseFile, projectEntryPoints, outputFile, msBuidSearchLocations, dotnetExeLocation, buildParameters);

            string standardError = result.StandardError.CreateReader().ReadToEndAsync().GetAwaiter().GetResult();

            if (result.ExitCode != 0)
            {
                // In case of a cancellation, the tool may have exited with a non-zero
                // code, but that's expected
                if (!m_context.CancellationToken.IsCancellationRequested)
                {
                    // This should never happen! Report the standard error and exit gracefully
                    Tracing.Logger.Log.GraphConstructionInternalError(
                        m_context.LoggingContext,
                        m_resolverSettings.Location(m_context.PathTable),
                        standardError);
                }

                return(new MsBuildGraphConstructionFailure(m_resolverSettings, m_context.PathTable));
            }

            // If the tool exited gracefully, but standard error is not empty, that
            // is interpreted as a warning. We propagate that to the BuildXL log
            if (!string.IsNullOrEmpty(standardError))
            {
                Tracing.Logger.Log.GraphConstructionFinishedSuccessfullyButWithWarnings(
                    m_context.LoggingContext,
                    m_resolverSettings.Location(m_context.PathTable),
                    standardError);
            }

            TrackFilesAndEnvironment(result.AllUnexpectedFileAccesses, outputFile.GetParent(m_context.PathTable));
            JsonSerializer serializer = ConstructProjectGraphSerializer();

            using (var sr = new StreamReader(outputFile.ToString(m_context.PathTable)))
                using (var reader = new JsonTextReader(sr))
                {
                    var projectGraphWithPredictionsResult = serializer.Deserialize <ProjectGraphWithPredictionsResult <AbsolutePath> >(reader);

                    // A successfully constructed graph should always have a valid path to MsBuild
                    Contract.Assert(!projectGraphWithPredictionsResult.Succeeded || projectGraphWithPredictionsResult.PathToMsBuild.IsValid);
                    // A successfully constructed graph should always have at least one project node
                    Contract.Assert(!projectGraphWithPredictionsResult.Succeeded || projectGraphWithPredictionsResult.Result.ProjectNodes.Length > 0);
                    // A failed construction should always have a failure set
                    Contract.Assert(projectGraphWithPredictionsResult.Succeeded || projectGraphWithPredictionsResult.Failure != null);

                    // Let's log the paths to the used MsBuild assemblies, just for debugging purposes
                    Tracing.Logger.Log.GraphConstructionToolCompleted(
                        m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable),
                        string.Join(",\n", projectGraphWithPredictionsResult.MsBuildAssemblyPaths.Select(kvp => I($"[{kvp.Key}]:{kvp.Value.ToString(m_context.PathTable)}"))),
                        projectGraphWithPredictionsResult.PathToMsBuild.ToString(m_context.PathTable));

                    return(m_resolverSettings.ShouldRunDotNetCoreMSBuild() ? projectGraphWithPredictionsResult.WithPathToDotNetExe(dotnetExeLocation) : projectGraphWithPredictionsResult);
                }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Assumes the proper MsBuild assemblies are loaded already
        /// </summary>
        private static ProjectGraphWithPredictionsResult BuildGraphInternal(
            GraphBuilderReporter reporter,
            IReadOnlyDictionary <string, string> assemblyPathsToLoad,
            string locatedMsBuildPath,
            MSBuildGraphBuilderArguments graphBuildArguments,
            IReadOnlyCollection <IProjectPredictor> projectPredictorsForTesting)
        {
            try
            {
                reporter.ReportMessage("Parsing MSBuild specs and constructing the build graph...");

                var projectInstanceToProjectCache = new ConcurrentDictionary <ProjectInstance, Project>();

                if (!TryBuildEntryPoints(
                        graphBuildArguments.ProjectsToParse,
                        graphBuildArguments.RequestedQualifiers,
                        graphBuildArguments.GlobalProperties,
                        out List <ProjectGraphEntryPoint> entryPoints,
                        out string failure))
                {
                    return(ProjectGraphWithPredictionsResult.CreateFailure(
                               GraphConstructionError.CreateFailureWithoutLocation(failure),
                               assemblyPathsToLoad,
                               locatedMsBuildPath));
                }

                var projectGraph = new ProjectGraph(
                    entryPoints,
                    // The project collection doesn't need any specific global properties, since entry points already contain all the ones that are needed, and the project graph will merge them
                    new ProjectCollection(),
                    (projectPath, globalProps, projectCollection) => ProjectInstanceFactory(projectPath, globalProps, projectCollection, projectInstanceToProjectCache));

                // This is a defensive check to make sure the assembly loader actually honored the search locations provided by the user. The path of the assembly where ProjectGraph
                // comes from has to be one of the provided search locations.
                // If that's not the case, this is really an internal error. For example, the MSBuild dlls we use to compile against (that shouldn't be deployed) somehow sneaked into
                // the deployment. This happened in the past, and it prevents the loader to redirect appropriately.
                Assembly assembly         = Assembly.GetAssembly(projectGraph.GetType());
                string   assemblylocation = assembly.Location;
                if (!assemblyPathsToLoad.Values.Contains(assemblylocation, StringComparer.InvariantCultureIgnoreCase))
                {
                    return(ProjectGraphWithPredictionsResult.CreateFailure(
                               GraphConstructionError.CreateFailureWithoutLocation($"Internal error: the assembly '{assembly.GetName().Name}' was loaded from '{assemblylocation}'. This path doesn't match any of the provided search locations. Please contact the BuildXL team."),
                               assemblyPathsToLoad,
                               locatedMsBuildPath));
                }

                reporter.ReportMessage("Done parsing MSBuild specs.");

                if (!TryConstructGraph(
                        projectGraph,
                        reporter,
                        projectInstanceToProjectCache,
                        graphBuildArguments.EntryPointTargets,
                        projectPredictorsForTesting,
                        graphBuildArguments.AllowProjectsWithoutTargetProtocol,
                        out ProjectGraphWithPredictions projectGraphWithPredictions,
                        out failure))
                {
                    return(ProjectGraphWithPredictionsResult.CreateFailure(
                               GraphConstructionError.CreateFailureWithoutLocation(failure),
                               assemblyPathsToLoad,
                               locatedMsBuildPath));
                }

                return(ProjectGraphWithPredictionsResult.CreateSuccessfulGraph(projectGraphWithPredictions, assemblyPathsToLoad, locatedMsBuildPath));
            }
            catch (InvalidProjectFileException e)
            {
                return(CreateFailureFromInvalidProjectFile(assemblyPathsToLoad, locatedMsBuildPath, e));
            }
            catch (AggregateException e)
            {
                // If there is an invalid project file exception, use that one since it contains the location.
                var invalidProjectFileException = (InvalidProjectFileException)e.Flatten().InnerExceptions.FirstOrDefault(ex => ex is InvalidProjectFileException);
                if (invalidProjectFileException != null)
                {
                    return(CreateFailureFromInvalidProjectFile(assemblyPathsToLoad, locatedMsBuildPath, invalidProjectFileException));
                }

                // Otherwise, we don't have a location, so we use the message of the originating exception
                return(ProjectGraphWithPredictionsResult.CreateFailure(
                           GraphConstructionError.CreateFailureWithoutLocation(
                               e.InnerException != null ? e.InnerException.Message : e.Message),
                           assemblyPathsToLoad,
                           locatedMsBuildPath));
            }
        }