Esempio n. 1
0
        /// <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);
        }
Esempio n. 2
0
        /// <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);
        }