From 8d2550c563669bed2784c5f8ba991bbaa491e839 Mon Sep 17 00:00:00 2001 From: Russ Cam Date: Thu, 6 Aug 2020 15:12:58 +1000 Subject: [PATCH] Consistent file string comparison across Windows and Linux (#4948) This commit fixes a difference in the default string comparison on .NET core across Windows and Linux which was causing the Stale docs github action to fail on CI because generated documentation was ordering asciidoc includes and list items in a different order. This fix sets a specific culture to use and uses ordinal string comparison. --- docs/aggregations.asciidoc | 8 +-- docs/query-dsl.asciidoc | 28 +++++----- .../AsciiDoc/RawAsciidocVisitor.cs | 55 +++++++++---------- src/DocGenerator/Program.cs | 4 +- src/DocGenerator/StringExtensions.cs | 3 +- src/DocGenerator/SyntaxNodeExtensions.cs | 9 ++- 6 files changed, 54 insertions(+), 53 deletions(-) diff --git a/docs/aggregations.asciidoc b/docs/aggregations.asciidoc index 322d5bb1843..9af135cb6a8 100644 --- a/docs/aggregations.asciidoc +++ b/docs/aggregations.asciidoc @@ -64,12 +64,12 @@ The values are typically extracted from the fields of the document (using the fi * <> +* <> + * <> * <> -* <> - * <> * <> @@ -108,12 +108,12 @@ include::aggregations/metric/string-stats/string-stats-aggregation-usage.asciido include::aggregations/metric/sum/sum-aggregation-usage.asciidoc[] +include::aggregations/metric/t-test/t-test-aggregation-usage.asciidoc[] + include::aggregations/metric/top-hits/top-hits-aggregation-usage.asciidoc[] include::aggregations/metric/top-metrics/top-metrics-aggregation-usage.asciidoc[] -include::aggregations/metric/t-test/t-test-aggregation-usage.asciidoc[] - include::aggregations/metric/value-count/value-count-aggregation-usage.asciidoc[] include::aggregations/metric/weighted-average/weighted-average-aggregation-usage.asciidoc[] diff --git a/docs/query-dsl.asciidoc b/docs/query-dsl.asciidoc index cb77994271c..dbd4bf2de7f 100644 --- a/docs/query-dsl.asciidoc +++ b/docs/query-dsl.asciidoc @@ -49,13 +49,13 @@ NEST exposes all of the full text queries available in Elasticsearch * <> -* <> - * <> +* <> + * <> -* <> +* <> * <> @@ -71,13 +71,13 @@ include::query-dsl/full-text/common-terms/common-terms-usage.asciidoc[] include::query-dsl/full-text/intervals/intervals-usage.asciidoc[] -include::query-dsl/full-text/match/match-usage.asciidoc[] - include::query-dsl/full-text/match-bool-prefix/match-bool-prefix-usage.asciidoc[] +include::query-dsl/full-text/match-phrase-prefix/match-phrase-prefix-usage.asciidoc[] + include::query-dsl/full-text/match-phrase/match-phrase-usage.asciidoc[] -include::query-dsl/full-text/match-phrase-prefix/match-phrase-prefix-usage.asciidoc[] +include::query-dsl/full-text/match/match-usage.asciidoc[] include::query-dsl/full-text/multi-match/multi-match-usage.asciidoc[] @@ -122,14 +122,14 @@ NEST exposes all of the term queries available in Elasticsearch * <> +* <> + * <> * <> * <> -* <> - * <> See the Elasticsearch documentation on {ref_current}/term-level-queries.html[Term level queries] for more details. @@ -160,14 +160,14 @@ include::query-dsl/term-level/regexp/regexp-query-usage.asciidoc[] include::query-dsl/term-level/term/term-query-usage.asciidoc[] +include::query-dsl/term-level/terms-set/terms-set-query-usage.asciidoc[] + include::query-dsl/term-level/terms/terms-list-query-usage.asciidoc[] include::query-dsl/term-level/terms/terms-lookup-query-usage.asciidoc[] include::query-dsl/term-level/terms/terms-query-usage.asciidoc[] -include::query-dsl/term-level/terms-set/terms-set-query-usage.asciidoc[] - include::query-dsl/term-level/wildcard/wildcard-query-usage.asciidoc[] [[compound-queries]] @@ -283,10 +283,10 @@ Specialized types of queries that do not fit into other groups * <> -* <> - * <> +* <> + * <> See the Elasticsearch documentation on {ref_current}/specialized-queries.html[Specialized queries] for more details. @@ -305,10 +305,10 @@ include::query-dsl/specialized/pinned/pinned-query-usage.asciidoc[] include::query-dsl/specialized/rank-feature/rank-feature-query-usage.asciidoc[] -include::query-dsl/specialized/script/script-query-usage.asciidoc[] - include::query-dsl/specialized/script-score/script-score-query-usage.asciidoc[] +include::query-dsl/specialized/script/script-query-usage.asciidoc[] + include::query-dsl/specialized/shape/shape-query-usage.asciidoc[] [[span-queries]] diff --git a/src/DocGenerator/AsciiDoc/RawAsciidocVisitor.cs b/src/DocGenerator/AsciiDoc/RawAsciidocVisitor.cs index 741fa761ffb..4633e674ec8 100644 --- a/src/DocGenerator/AsciiDoc/RawAsciidocVisitor.cs +++ b/src/DocGenerator/AsciiDoc/RawAsciidocVisitor.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -53,50 +54,38 @@ public override void VisitAttributeEntry(AttributeEntry attributeEntry) { var thisFileUri = new Uri(_destination.FullName); var directories = attributeEntry.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - var counter = 1; - foreach (var directory in directories.OrderBy(s=>s)) + foreach (var file in DirectoryFiles(directories)) { - var files = Directory.EnumerateFiles( - Path.Combine(Program.TmpOutputDirPath, directory), "*.asciidoc", SearchOption.AllDirectories); - foreach (var file in files.OrderBy(s=>s)) - { - var fileInfo = new FileInfo(file); - var referencedFileUri = new Uri(fileInfo.FullName); - var relativePath = thisFileUri.MakeRelativeUri(referencedFileUri); - var include = new Include(relativePath.OriginalString); + var fileInfo = new FileInfo(file); + var referencedFileUri = new Uri(fileInfo.FullName); + var relativePath = thisFileUri.MakeRelativeUri(referencedFileUri); + var include = new Include(relativePath.OriginalString); - if (attributeEntry.Parent != null) - { - attributeEntry.Parent.Insert(attributeEntry.Parent.IndexOf(attributeEntry) + counter, include); - ++counter; - } - else - _document.Add(include); + if (attributeEntry.Parent != null) + { + attributeEntry.Parent.Insert(attributeEntry.Parent.IndexOf(attributeEntry) + counter, include); + ++counter; } + else + _document.Add(include); } } else if (attributeEntry.Name == "anchor-list") { var directories = attributeEntry.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - var list = new UnorderedList(); - foreach (var directory in directories.OrderBy(s=>s)) + foreach (var file in DirectoryFiles(directories)) { - var files = Directory.EnumerateFiles( - Path.Combine(Program.TmpOutputDirPath, directory), "*.asciidoc", SearchOption.AllDirectories); - foreach (var file in files.OrderBy(s=>s)) - { - var fileInfo = new FileInfo(file); - var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.Name); + var fileInfo = new FileInfo(file); + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.Name); - list.Items.Add(new UnorderedListItem - { - new Paragraph(new InternalAnchor(fileNameWithoutExtension, fileNameWithoutExtension.LowercaseHyphenToPascal())) - }); - } + list.Items.Add(new UnorderedListItem + { + new Paragraph(new InternalAnchor(fileNameWithoutExtension, fileNameWithoutExtension.LowercaseHyphenToPascal())) + }); } if (attributeEntry.Parent != null) @@ -107,5 +96,11 @@ public override void VisitAttributeEntry(AttributeEntry attributeEntry) base.VisitAttributeEntry(attributeEntry); } + + private static IEnumerable DirectoryFiles(string[] directories) => + directories + .SelectMany(directory => + Directory.EnumerateFiles(Path.Combine(Program.TmpOutputDirPath, directory), "*.asciidoc", SearchOption.AllDirectories)) + .OrderBy(f => f, StringComparer.Ordinal); } } diff --git a/src/DocGenerator/Program.cs b/src/DocGenerator/Program.cs index 92dc60e2ea4..c6bdf029203 100644 --- a/src/DocGenerator/Program.cs +++ b/src/DocGenerator/Program.cs @@ -3,7 +3,8 @@ // See the LICENSE file in the project root for more information using System; -using System.IO; + using System.Globalization; + using System.IO; using System.Linq; using CommandLine; using Newtonsoft.Json.Linq; @@ -14,6 +15,7 @@ public static class Program { static Program() { + CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-us"); var root = new DirectoryInfo(Directory.GetCurrentDirectory()); do diff --git a/src/DocGenerator/StringExtensions.cs b/src/DocGenerator/StringExtensions.cs index 9175df0dde0..a122dd64746 100644 --- a/src/DocGenerator/StringExtensions.cs +++ b/src/DocGenerator/StringExtensions.cs @@ -224,7 +224,8 @@ public static bool TryGetJsonForExpressionSyntax(this string anonymousTypeString { json = null; - foreach (var substitution in Substitutions) anonymousTypeString = anonymousTypeString.Replace(substitution.Key, substitution.Value); + foreach (var substitution in Substitutions) + anonymousTypeString = anonymousTypeString.Replace(substitution.Key, substitution.Value); var text = $@" diff --git a/src/DocGenerator/SyntaxNodeExtensions.cs b/src/DocGenerator/SyntaxNodeExtensions.cs index 271ff577f30..8cd1550433e 100644 --- a/src/DocGenerator/SyntaxNodeExtensions.cs +++ b/src/DocGenerator/SyntaxNodeExtensions.cs @@ -39,7 +39,7 @@ public static bool ShouldBeConvertedToJson(this SyntaxNode node) => /// public static bool ShouldBeConvertedToJson(this SyntaxNode node, SyntaxTriviaList leadingTrivia) { - if (leadingTrivia == default(SyntaxTriviaList)) + if (leadingTrivia == default) return false; var singleLineCommentIndex = leadingTrivia.IndexOf(SyntaxKind.SingleLineCommentTrivia); @@ -77,7 +77,10 @@ public static bool TryGetJsonForSyntaxNode(this SyntaxNode node, out string json // find the first anonymous object or new object expression var syntax = node.DescendantNodes() - .FirstOrDefault(n => n is AnonymousObjectCreationExpressionSyntax || n is ObjectCreationExpressionSyntax || n is LiteralExpressionSyntax); + .FirstOrDefault(n => + n is AnonymousObjectCreationExpressionSyntax || + n is ObjectCreationExpressionSyntax || + n is LiteralExpressionSyntax); return syntax != null && syntax.ToFullString().TryGetJsonForExpressionSyntax(out json); } @@ -107,7 +110,7 @@ public static SyntaxNode WithLeadingEndOfLineTrivia(this SyntaxNode node) public static string ToFullStringWithoutPragmaWarningDirectiveTrivia(this SyntaxNode node) { var pragma = node.DescendantTrivia(s => true, true).Where(t => t.IsKind(SyntaxKind.PragmaWarningDirectiveTrivia)); - return node.ReplaceTrivia(pragma, (s, r) => default(SyntaxTrivia)).ToFullString(); + return node.ReplaceTrivia(pragma, (s, r) => default).ToFullString(); } } }