/// <summary> /// Loads the <paramref name="registry"/> and Purges Generated Code given /// <paramref name="serviceManager"/>. /// </summary> /// <param name="serviceManager"></param> /// <param name="registry"></param> private void LoadAndPurgeGeneratedCode(CodeGenerationServiceManager serviceManager , out OrToolsSatGeneratedSyntaxTreeRegistry registry) { if (DebugMessagesSwitch) { Writer.WriteLine("Loading and purging registry."); } /* Should not need to re-load any ServiceManager Registries, * since this is done inherently by the SM itself. */ registry = serviceManager.Registry; if (!registry.Any()) { if (DebugMessagesSwitch) { Writer.WriteLine("There are no Registry entries."); } return; } // Work around output or reference parameters. var local = registry; var outputDirectory = local.OutputDirectory; var anUpdateOccurred = local.GoogleOrToolsVersion < GoogleOrToolsVersion; // Purge All if any of them are missing. bool ShouldPurgeRegistry(GeneratedSyntaxTreeDescriptor descriptor) { /* Easy Purge to make by Version first, followed closely by whether * any previously registered files have themselves disappeared. */ bool WhetherSomeFilesAreMissing() { var someFilesAreMissing = descriptor.GeneratedAssetKeys .Select(y => Path.Combine(outputDirectory, y.RenderGeneratedFileName())) .Any(filePath => !File.Exists(filePath)); return(someFilesAreMissing); } var should = anUpdateOccurred || WhetherSomeFilesAreMissing(); if (DebugMessagesSwitch) { Writer.WriteLine($"Should{(should ? " " : " not ")}purge generated code."); } return(should); } registry.PurgeWhere(ShouldPurgeRegistry); }
/// <summary> /// We need to Evaluate a further and much more in depth Purge opportunity given the /// <paramref name="registry"/> and set of <paramref name="renderedCompilationUnits"/>. /// </summary> /// <param name="registry"></param> /// <param name="renderedCompilationUnits"></param> /// <returns></returns> private bool TryEvaluateCompilationUnits(OrToolsSatGeneratedSyntaxTreeRegistry registry , IRenderedCompilationUnitDictionary renderedCompilationUnits) { // Pretty sure we want to do an Ordinal comparison here. But this is a function of the Invocation. bool StringEquals(string a, string b, StringComparison comparisonType) => !(a == null || b == null) && string.Equals(a.Trim(), b.Trim(), comparisonType); bool TryDecomposeCompilationUnitSyntaxPair(CompilationUnitSyntaxPair pair , out string generatedCode) => !IsNullOrEmpty(generatedCode = pair.Value); // This is a bit involved, but this gains us sufficient accounting of Generated Code. bool ThereAreCodeGenerationInconsistencies(GeneratedSyntaxTreeDescriptor _) { var outputDirectory = registry.OutputDirectory; var filePaths = Directory.EnumerateFiles(outputDirectory, $"*{g}{cs}", TopDirectoryOnly); // Obtain any Previously Existing Baseline Generated Code in the form of a Stream Factory. var streamFactories = filePaths.Select(filePath => (Func <Stream>)( () => File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read) )); // Which has the added benefit of deferring Stream operations until we absolutely need them. foreach (var streamFactory in streamFactories) { string baselineGeneratedCode; /* And which also defers the actual delegate formation given the nature of the LINQ * provider. Performance may vary from OS to OS, from Run-time to Run-time. */ using (var fs = streamFactory.Invoke()) { // Do this operation Once and Only Once for the breadth of the candidate set of Generated Code. using (var sr = new StreamReader(fs)) { baselineGeneratedCode = sr.ReadToEndAsync().Result; } } // Continue when Code Generation Consistency checks can be verified. if (renderedCompilationUnits.Any( pair => TryDecomposeCompilationUnitSyntaxPair(pair, out var x) && StringEquals(x, baselineGeneratedCode, Ordinal))) { continue; } if (DebugMessagesSwitch) { Writer.WriteLine("Generated code inconsistencies discovered, purge required."); } // Otherwise, break, we know the set to be Inconsistent, i.e. re-Generation required. return(true); } if (DebugMessagesSwitch) { Writer.WriteLine("Generated code found to be consistent, purge not required."); } // If everything checked out, All Consistent, then we are Clear to Bypass Code Generation. return(false); } var areNonePreviouslyGenerated = !registry.SelectMany(x => x.GeneratedAssetKeys).Any(); var areObviouslyDifferent = registry.SelectMany(x => x.GeneratedAssetKeys).Count() != renderedCompilationUnits.Count; var thereAreCodeGenerationInconsistencies = registry.Any(ThereAreCodeGenerationInconsistencies); var shouldPurge = areNonePreviouslyGenerated || areObviouslyDifferent || thereAreCodeGenerationInconsistencies; registry.PurgeWhere(_ => shouldPurge); return(shouldPurge); }