/// <inheritdoc/>
        protected override bool TryFindGraphBuilderToolLocation(ILageResolverSettings resolverSettings, BuildParameters.IBuildParameters buildParameters, out AbsolutePath npmLocation, out string failure)
        {
            // If the base location was provided at configuration time, we honor it as is
            if (resolverSettings.NpmLocation.HasValue)
            {
                npmLocation = resolverSettings.NpmLocation.Value.Path;
                failure     = string.Empty;
                return(true);
            }

            // If the location was not provided, let's try to see if NPM is under %PATH%
            string paths = buildParameters["PATH"];

            if (!FrontEndUtilities.TryFindToolInPath(m_context, m_host, paths, new[] { "npm", "npm.cmd" }, out npmLocation))
            {
                failure = "A location for 'npm' is not explicitly specified. However, 'npm' doesn't seem to be part of PATH. You can either specify the location explicitly using 'npmLocation' field in " +
                          $"the Lage resolver configuration, or make sure 'npm' is part of your PATH. Current PATH is '{paths}'.";
                return(false);
            }

            failure = string.Empty;

            // Just verbose log this
            Tracing.Logger.Log.UsingNpmAt(m_context.LoggingContext, resolverSettings.Location(m_context.PathTable), npmLocation.ToString(m_context.PathTable));

            return(true);
        }
示例#2
0
        /// <inheritdoc/>
        protected override bool TryFindGraphBuilderToolLocation(IYarnResolverSettings resolverSettings, BuildParameters.IBuildParameters buildParameters, out AbsolutePath finalYarnLocation, out string failure)
        {
            // If the base location was provided at configuration time, we honor it as is
            string paths;

            if (resolverSettings.YarnLocation != null)
            {
                var value = resolverSettings.YarnLocation.GetValue();
                if (value is FileArtifact file)
                {
                    finalYarnLocation = file;
                    failure           = string.Empty;
                    return(true);
                }
                else
                {
                    var pathCollection = ((IReadOnlyList <DirectoryArtifact>)value).Select(dir => dir.Path);
                    if (!FrontEndUtilities.TryFindToolInPath(m_context, m_host, pathCollection, new[] { "yarn", "yarn.cmd" }, out finalYarnLocation))
                    {
                        failure = $"'yarn' cannot be found under any of the provided paths '{string.Join(Path.PathSeparator.ToString(), pathCollection.Select(path => path.ToString(m_context.PathTable)))}'.";
                        return(false);
                    }

                    failure = string.Empty;
                    return(true);
                }
            }

            // If the location was not provided, let's try to see if Yarn is under %PATH%
            paths = buildParameters["PATH"];

            if (!FrontEndUtilities.TryFindToolInPath(m_context, m_host, paths, new[] { "yarn", "yarn.cmd" }, out finalYarnLocation))
            {
                failure = "A location for 'yarn' is not explicitly specified. However, 'yarn' doesn't seem to be part of PATH. You can either specify the location explicitly using 'yarnLocation' field in " +
                          $"the Yarn resolver configuration, or make sure 'yarn' is part of your PATH. Current PATH is '{paths}'.";
                return(false);
            }

            failure = string.Empty;

            // Just verbose log this
            Tracing.Logger.Log.UsingYarnAt(m_context.LoggingContext, resolverSettings.Location(m_context.PathTable), finalYarnLocation.ToString(m_context.PathTable));

            return(true);
        }
示例#3
0
        private async Task <Possible <(JavaScriptGraph <TGraphConfiguration>, GenericJavaScriptGraph <DeserializedJavaScriptProject, TGraphConfiguration>)> > ComputeBuildGraphAsync(
            AbsolutePath outputFile,
            BuildParameters.IBuildParameters buildParameters)
        {
            // Determine the base location to use for finding the graph construction tool
            if (!TryFindGraphBuilderToolLocation(
                    m_resolverSettings,
                    buildParameters,
                    out AbsolutePath foundLocation,
                    out string failure))
            {
                Tracing.Logger.Log.CannotFindGraphBuilderTool(
                    m_context.LoggingContext,
                    m_resolverSettings.Location(m_context.PathTable),
                    failure);

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

            string nodeExeLocation;

            if (m_resolverSettings.NodeExeLocation != null)
            {
                var          specifiedNodeExe = m_resolverSettings.NodeExeLocation.GetValue();
                AbsolutePath nodeExeLocationPath;

                if (specifiedNodeExe is FileArtifact fileArtifact)
                {
                    nodeExeLocationPath = fileArtifact.Path;
                }
                else
                {
                    var pathCollection = ((IReadOnlyList <DirectoryArtifact>)specifiedNodeExe).Select(dir => dir.Path);
                    if (!FrontEndUtilities.TryFindToolInPath(m_context, m_host, pathCollection, new[] { "node", "node.exe" }, out nodeExeLocationPath))
                    {
                        failure = $"'node' cannot be found under any of the provided paths '{string.Join(";", pathCollection.Select(path => path.ToString(m_context.PathTable)))}'.";
                        Tracing.Logger.Log.CannotFindGraphBuilderTool(
                            m_context.LoggingContext,
                            m_resolverSettings.Location(m_context.PathTable),
                            failure);

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

                nodeExeLocation = nodeExeLocationPath.ToString(m_context.PathTable);

                // Most graph construction tools (yarn, rush, etc.) rely on node.exe being on the PATH. Make sure
                // that's the case by appending the PATH exposed to the graph construction process with the location of the
                // specified node.exe. By prepending PATH with it, we also make sure yarn/rush will be using the same version
                // of node the user specified.
                string pathWithNode  = buildParameters.ContainsKey("PATH") ? buildParameters["PATH"] : string.Empty;
                var    nodeDirectory = nodeExeLocationPath.GetParent(m_context.PathTable);
                if (nodeDirectory.IsValid)
                {
                    pathWithNode = nodeDirectory.ToString(m_context.PathTable) + Path.PathSeparator + pathWithNode;
                }

                buildParameters = buildParameters.Override(new[] { new KeyValuePair <string, string>("PATH", pathWithNode) });
            }
            else
            {
                // We always use cmd.exe as the tool so if the node.exe location is not provided we can just pass 'node.exe' and let PATH do the work.
                nodeExeLocation = "node.exe";
            }

            SandboxedProcessResult result = await RunJavaScriptGraphBuilderAsync(nodeExeLocation, outputFile, buildParameters, foundLocation);

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

            if (result.ExitCode != 0)
            {
                Tracing.Logger.Log.ProjectGraphConstructionError(
                    m_context.LoggingContext,
                    m_resolverSettings.Location(m_context.PathTable),
                    standardError);

                return(new JavaScriptGraphConstructionFailure(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(JsonSerializerSettings);

            using (var sr = new StreamReader(outputFile.ToString(m_context.PathTable)))
                using (var reader = new JsonTextReader(sr))
                {
                    var flattenedJavaScriptGraph = serializer.Deserialize <GenericJavaScriptGraph <DeserializedJavaScriptProject, TGraphConfiguration> >(reader);

                    // If a custom script command callback is specified, give it a chance to alter the script commands of
                    // each package
                    if (m_resolverSettings.CustomScripts != null)
                    {
                        var projectsWithCustomScripts = new List <DeserializedJavaScriptProject>(flattenedJavaScriptGraph.Projects.Count);
                        foreach (var project in flattenedJavaScriptGraph.Projects)
                        {
                            m_resolverSettings.Root.TryGetRelative(m_context.PathTable, project.ProjectFolder, out var relativeFolder);

                            var maybeCustomScripts = ResolveCustomScripts(project.Name, relativeFolder);
                            if (!maybeCustomScripts.Succeeded)
                            {
                                return(maybeCustomScripts.Failure);
                            }
                            var customScripts = maybeCustomScripts.Result;

                            // A null customScript means the callback did not provide any customization
                            projectsWithCustomScripts.Add(customScripts == null ? project : project.WithCustomScripts(customScripts));
                        }

                        flattenedJavaScriptGraph = new GenericJavaScriptGraph <DeserializedJavaScriptProject, TGraphConfiguration>(
                            projectsWithCustomScripts, flattenedJavaScriptGraph.Configuration);
                    }

                    Possible <JavaScriptGraph <TGraphConfiguration> > graph = ApplyBxlExecutionSemantics() ? ResolveGraphWithExecutionSemantics(flattenedJavaScriptGraph) : ResolveGraphWithoutExecutionSemantics(flattenedJavaScriptGraph);

                    return(graph.Then(graph => new Possible <(JavaScriptGraph <TGraphConfiguration>, GenericJavaScriptGraph <DeserializedJavaScriptProject, TGraphConfiguration>)>((graph, flattenedJavaScriptGraph))));
                }
        }