protected override CompilationResult Build(ProjectGraphNode projectNode) { var result = base.Build(projectNode); AfterRootBuild(projectNode, result); return(result); }
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)); }
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); }
private IncrementalResult CLIChanged(ProjectGraphNode graphNode) { var currentVersionFile = DotnetFiles.VersionFile; var versionFileFromLastCompile = graphNode.ProjectContext.GetSDKVersionFile(_configuration, _buildBasePath, _outputPath); if (!File.Exists(currentVersionFile)) { // this CLI does not have a version file; cannot tell if CLI changed return(IncrementalResult.DoesNotNeedRebuild); } if (!File.Exists(versionFileFromLastCompile)) { // this is the first compilation; cannot tell if CLI changed return(IncrementalResult.DoesNotNeedRebuild); } var currentContent = DotnetFiles.ReadAndInterpretVersionFile(); var versionsAreEqual = string.Equals(currentContent, File.ReadAllText(versionFileFromLastCompile), StringComparison.OrdinalIgnoreCase); return(versionsAreEqual ? IncrementalResult.DoesNotNeedRebuild : new IncrementalResult("the version or bitness of the CLI changed since the last build")); }
private IncrementalResult CLIChanged(ProjectGraphNode graphNode) { var currentVersionFile = DotnetFiles.VersionFile; var versionFileFromLastCompile = graphNode.ProjectContext.GetSDKVersionFile(_configuration, _buildBasePath, _outputPath); if (!File.Exists(currentVersionFile)) { // this CLI does not have a version file; cannot tell if CLI changed return IncrementalResult.DoesNotNeedRebuild; } if (!File.Exists(versionFileFromLastCompile)) { // this is the first compilation; cannot tell if CLI changed return IncrementalResult.DoesNotNeedRebuild; } var currentContent = DotnetFiles.ReadAndInterpretVersionFile(); var versionsAreEqual = string.Equals(currentContent, File.ReadAllText(versionFileFromLastCompile), StringComparison.OrdinalIgnoreCase); return versionsAreEqual ? IncrementalResult.DoesNotNeedRebuild : new IncrementalResult("the version or bitness of the CLI changed since the last build"); }
protected override bool NeedsRebuilding(ProjectGraphNode graphNode) { var result = _incrementalManager.NeedsRebuilding(graphNode); PrintIncrementalResult(graphNode.ProjectContext.GetDisplayName(), result); return(result.NeedsRebuilding); }
public void CacheIncrementalState(ProjectGraphNode graphNode) { var incrementalCacheFile = graphNode.ProjectContext.IncrementalCacheFile(_configuration, _buildBasePath, _outputPath); var incrementalCache = new IncrementalCache(_compilerIoManager.GetCompileIO(graphNode)); incrementalCache.WriteToFile(incrementalCacheFile); }
private CompilerIO ComputeIO(ProjectGraphNode graphNode) { var inputs = new List <string>(); var outputs = new List <string>(); var isRootProject = graphNode.IsRoot; var project = graphNode.ProjectContext; var calculator = project.GetOutputPaths(_configuration, _buildBasePath, _outputPath); var binariesOutputPath = calculator.CompilationOutputPath; var compilerOptions = project.ProjectFile.GetCompilerOptions(project.TargetFramework, _configuration); // input: project.json inputs.Add(project.ProjectFile.ProjectFilePath); // input: lock file; find when dependencies change AddLockFile(project, inputs); // input: source files inputs.AddRange(CompilerUtil.GetCompilationSources(project, compilerOptions)); var allOutputPath = new HashSet <string>(calculator.CompilationFiles.All()); if (isRootProject && project.ProjectFile.HasRuntimeOutput(_configuration)) { var runtimeContext = _workspace.GetRuntimeContext(project, _runtimes); foreach (var path in runtimeContext.GetOutputPaths(_configuration, _buildBasePath, _outputPath).RuntimeFiles.All()) { allOutputPath.Add(path); } } foreach (var dependency in graphNode.Dependencies) { var outputFiles = dependency.ProjectContext .GetOutputPaths(_configuration, _buildBasePath, _outputPath) .CompilationFiles; inputs.Add(outputFiles.Assembly); } // output: compiler outputs foreach (var path in allOutputPath) { outputs.Add(path); } // input compilation options files AddCompilationOptions(project, _configuration, inputs); // input / output: resources with culture AddNonCultureResources(project, calculator.IntermediateOutputDirectoryPath, inputs, outputs, compilerOptions); // input / output: resources without culture AddCultureResources(project, binariesOutputPath, inputs, outputs, compilerOptions); return(new CompilerIO(inputs, outputs)); }
public CompilationResult? GetCompilationResult(ProjectGraphNode projectNode) { CompilationResult result; if (_compilationResults.TryGetValue(projectNode.ProjectContext.Identity, out result)) { return result; } return null; }
private CompilerIO ComputeIO(ProjectGraphNode graphNode) { var inputs = new List<string>(); var outputs = new List<string>(); var isRootProject = graphNode.IsRoot; var project = graphNode.ProjectContext; var calculator = project.GetOutputPaths(_configuration, _buildBasePath, _outputPath); var binariesOutputPath = calculator.CompilationOutputPath; var compilerOptions = project.ProjectFile.GetCompilerOptions(project.TargetFramework, _configuration); // input: project.json inputs.Add(project.ProjectFile.ProjectFilePath); // input: lock file; find when dependencies change AddLockFile(project, inputs); // input: source files inputs.AddRange(CompilerUtil.GetCompilationSources(project, compilerOptions)); var allOutputPath = new HashSet<string>(calculator.CompilationFiles.All()); if (isRootProject && project.ProjectFile.HasRuntimeOutput(_configuration)) { var runtimeContext = _workspace.GetRuntimeContext(project, _runtimes); foreach (var path in runtimeContext.GetOutputPaths(_configuration, _buildBasePath, _outputPath).RuntimeFiles.All()) { allOutputPath.Add(path); } } foreach (var dependency in graphNode.Dependencies) { var outputFiles = dependency.ProjectContext .GetOutputPaths(_configuration, _buildBasePath, _outputPath) .CompilationFiles; inputs.Add(outputFiles.Assembly); } // output: compiler outputs foreach (var path in allOutputPath) { outputs.Add(path); } // input compilation options files AddCompilationOptions(project, _configuration, inputs); // input / output: resources with culture AddNonCultureResources(project, calculator.IntermediateOutputDirectoryPath, inputs, outputs, compilerOptions); // input / output: resources without culture AddCultureResources(project, binariesOutputPath, inputs, outputs, compilerOptions); return new CompilerIO(inputs, outputs); }
public CompilationResult?GetCompilationResult(ProjectGraphNode projectNode) { CompilationResult result; if (_compilationResults.TryGetValue(projectNode.ProjectContext.Identity, out result)) { return(result); } return(null); }
private void PrintSummary(ProjectGraphNode projectNode, bool success) { // todo: Ideally it's the builder's responsibility for adding the time elapsed. That way we avoid cross cutting display concerns between compile and build for printing time elapsed if (success) { var preconditions = _preconditionManager.GetIncrementalPreconditions(projectNode); Reporter.Output.Write(" " + preconditions.LogMessage()); Reporter.Output.WriteLine(); } Reporter.Output.WriteLine(); }
protected void AfterRootBuild(ProjectGraphNode projectNode, CompilationResult result) { if (result != CompilationResult.IncrementalSkip && projectNode.IsRoot) { var success = result == CompilationResult.Success; if (success) { MakeRunnable(projectNode); } PrintSummary(projectNode, success); } }
protected virtual CompilationResult Build(ProjectGraphNode projectNode) { CompilationResult result; if (_compilationResults.TryGetValue(projectNode.ProjectContext.Identity, out result)) { return result; } result = CompileWithDependencies(projectNode); _compilationResults[projectNode.ProjectContext.Identity] = result; return result; }
protected virtual CompilationResult Build(ProjectGraphNode projectNode) { CompilationResult result; if (_compilationResults.TryGetValue(projectNode.ProjectContext.Identity, out result)) { return(result); } result = CompileWithDependencies(projectNode); _compilationResults[projectNode.ProjectContext.Identity] = result; return(result); }
protected override CompilationResult RunCompile(ProjectGraphNode projectNode) { try { var managedCompiler = new ManagedCompiler(_scriptRunner, _commandFactory); var success = managedCompiler.Compile(projectNode.ProjectContext, _args); return(success ? CompilationResult.Success : CompilationResult.Failure); } finally { StampProjectWithSDKVersion(projectNode.ProjectContext); _incrementalManager.CacheIncrementalState(projectNode); } }
private CompilationResult CompileWithDependencies(ProjectGraphNode projectNode) { if (!_skipDependencies) { foreach (var dependency in projectNode.Dependencies) { var result = Build(dependency); if (result == CompilationResult.Failure) { return(CompilationResult.Failure); } } } var context = projectNode.ProjectContext; using (PerfTrace.Current.CaptureTiming($"{projectNode.ProjectContext.ProjectName()}", nameof(HasSourceFiles))) { if (!HasSourceFiles(context)) { return(CompilationResult.IncrementalSkip); } } bool needsRebuilding; using (PerfTrace.Current.CaptureTiming($"{projectNode.ProjectContext.ProjectName()}", nameof(NeedsRebuilding))) { needsRebuilding = NeedsRebuilding(projectNode); } if (needsRebuilding) { using (PerfTrace.Current.CaptureTiming($"{projectNode.ProjectContext.ProjectName()}", nameof(RunCompile))) { return(RunCompile(projectNode)); } } else { using (PerfTrace.Current.CaptureTiming($"{projectNode.ProjectContext.ProjectName()}", nameof(ProjectSkiped))) { ProjectSkiped(projectNode); } return(CompilationResult.IncrementalSkip); } }
private CompilationResult CompileWithDependencies(ProjectGraphNode projectNode) { if (!_skipDependencies) { foreach (var dependency in projectNode.Dependencies) { var result = Build(dependency); if (result == CompilationResult.Failure) { return CompilationResult.Failure; } } } var context = projectNode.ProjectContext; using (PerfTrace.Current.CaptureTiming($"{projectNode.ProjectContext.ProjectName()}", nameof(HasSourceFiles))) { if (!HasSourceFiles(context)) { return CompilationResult.IncrementalSkip; } } bool needsRebuilding; using (PerfTrace.Current.CaptureTiming($"{projectNode.ProjectContext.ProjectName()}", nameof(NeedsRebuilding))) { needsRebuilding = NeedsRebuilding(projectNode); } if (needsRebuilding) { using (PerfTrace.Current.CaptureTiming($"{projectNode.ProjectContext.ProjectName()}",nameof(RunCompile))) { return RunCompile(projectNode); } } else { using (PerfTrace.Current.CaptureTiming($"{projectNode.ProjectContext.ProjectName()}", nameof(ProjectSkiped))) { ProjectSkiped(projectNode); } return CompilationResult.IncrementalSkip; } }
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); }
private void MakeRunnable(ProjectGraphNode graphNode) { try { var runtimeContext = graphNode.ProjectContext.ProjectFile.HasRuntimeOutput(_args.ConfigValue) ? _args.Workspace.GetRuntimeContext(graphNode.ProjectContext, _args.GetRuntimes()) : graphNode.ProjectContext; var outputPaths = runtimeContext.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue); var libraryExporter = runtimeContext.CreateExporter(_args.ConfigValue, _args.BuildBasePathValue); CopyCompilationOutput(outputPaths); var executable = new Executable(runtimeContext, outputPaths, libraryExporter, _args.ConfigValue); executable.MakeCompilationOutputRunnable(); } catch (Exception e) { throw new Exception($"Failed to make the following project runnable: {graphNode.ProjectContext.GetDisplayName()} reason: {e.Message}", e); } }
public IncrementalPreconditions GetIncrementalPreconditions(ProjectGraphNode projectNode) { IncrementalPreconditions preconditions; if (_preconditions.TryGetValue(projectNode.ProjectContext.Identity, out preconditions)) { return preconditions; } preconditions = new IncrementalPreconditions(_printPreconditions); if (_forceNonIncremental) { preconditions.AddForceUnsafePrecondition(); } var project = projectNode.ProjectContext; CollectScriptPreconditions(project, preconditions); CollectCompilerNamePreconditions(project, preconditions); CollectCheckPathProbingPreconditions(project, preconditions); _preconditions[projectNode.ProjectContext.Identity] = preconditions; return preconditions; }
public IncrementalResult NeedsRebuilding(ProjectGraphNode graphNode) { if (!_shouldSkipDependencies && graphNode.Dependencies.Any(d => _projectBuilder.GetCompilationResult(d) != CompilationResult.IncrementalSkip)) { return(new IncrementalResult("dependencies changed")); } var preconditions = _preconditionManager.GetIncrementalPreconditions(graphNode); if (preconditions.PreconditionsDetected()) { return(new IncrementalResult($"project is not safe for incremental compilation. Use {BuildCommandApp.BuildProfileFlag} flag for more information.")); } var compilerIO = _compilerIoManager.GetCompileIO(graphNode); var result = CLIChanged(graphNode); if (result.NeedsRebuilding) { return(result); } result = InputItemsChanged(graphNode, compilerIO); if (result.NeedsRebuilding) { return(result); } result = TimestampsChanged(compilerIO); if (result.NeedsRebuilding) { return(result); } return(IncrementalResult.DoesNotNeedRebuild); }
public IncrementalPreconditions GetIncrementalPreconditions(ProjectGraphNode projectNode) { IncrementalPreconditions preconditions; if (_preconditions.TryGetValue(projectNode.ProjectContext.Identity, out preconditions)) { return(preconditions); } preconditions = new IncrementalPreconditions(_printPreconditions); if (_forceNonIncremental) { preconditions.AddForceUnsafePrecondition(); } var project = projectNode.ProjectContext; CollectScriptPreconditions(project, preconditions); CollectCompilerNamePreconditions(project, preconditions); CollectCheckPathProbingPreconditions(project, preconditions); _preconditions[projectNode.ProjectContext.Identity] = preconditions; return(preconditions); }
public IncrementalResult NeedsRebuilding(ProjectGraphNode graphNode) { if (!_shouldSkipDependencies && graphNode.Dependencies.Any(d => _projectBuilder.GetCompilationResult(d) != CompilationResult.IncrementalSkip)) { return new IncrementalResult("dependencies changed"); } var preconditions = _preconditionManager.GetIncrementalPreconditions(graphNode); if (preconditions.PreconditionsDetected()) { return new IncrementalResult($"project is not safe for incremental compilation. Use {BuildCommandApp.BuildProfileFlag} flag for more information."); } var compilerIO = _compilerIoManager.GetCompileIO(graphNode); var result = CLIChanged(graphNode); if (result.NeedsRebuilding) { return result; } result = InputItemsChanged(graphNode, compilerIO); if (result.NeedsRebuilding) { return result; } result = TimestampsChanged(compilerIO); if (result.NeedsRebuilding) { return result; } return IncrementalResult.DoesNotNeedRebuild; }
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); }
protected virtual void ProjectSkiped(ProjectGraphNode projectNode) { }
protected abstract CompilationResult RunCompile(ProjectGraphNode projectNode);
protected override CompilationResult RunCompile(ProjectGraphNode projectNode) { try { var managedCompiler = new ManagedCompiler(_scriptRunner, _commandFactory); var success = managedCompiler.Compile(projectNode.ProjectContext, _args); return success ? CompilationResult.Success : CompilationResult.Failure; } finally { StampProjectWithSDKVersion(projectNode.ProjectContext); _incrementalManager.CacheIncrementalState(projectNode); } }
protected override void ProjectSkiped(ProjectGraphNode projectNode) { StampProjectWithSDKVersion(projectNode.ProjectContext); _incrementalManager.CacheIncrementalState(projectNode); }
protected override bool NeedsRebuilding(ProjectGraphNode graphNode) { var result = _incrementalManager.NeedsRebuilding(graphNode); PrintIncrementalResult(graphNode.ProjectContext.GetDisplayName(), result); return result.NeedsRebuilding; }
protected virtual bool NeedsRebuilding(ProjectGraphNode projectNode) { return true; }
// computes all the inputs and outputs that would be used in the compilation of a project public CompilerIO GetCompileIO(ProjectGraphNode graphNode) { return(_cache.GetOrAdd(graphNode.ProjectContext.Identity, i => ComputeIO(graphNode))); }
protected override CompilationResult Build(ProjectGraphNode projectNode) { var result = base.Build(projectNode); AfterRootBuild(projectNode, result); return result; }
protected virtual bool NeedsRebuilding(ProjectGraphNode projectNode) { return(true); }
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; }
public void CacheIncrementalState(ProjectGraphNode graphNode) { var incrementalCacheFile = graphNode.ProjectContext.IncrementalCacheFile(_configuration, _buildBasePath, _outputPath); var incrementalCache = new IncrementalCache(_compilerIoManager.GetCompileIO(graphNode), _incrementalAffectingArguments); incrementalCache.WriteToFile(incrementalCacheFile); }
// computes all the inputs and outputs that would be used in the compilation of a project public CompilerIO GetCompileIO(ProjectGraphNode graphNode) { return _cache.GetOrAdd(graphNode.ProjectContext.Identity, i => ComputeIO(graphNode)); }