Skip to content

Commit a0a2f74

Browse files
committed
Ensure stable order in .deps.json file
When writing out the .deps.json file through DependencyContextCreator, sort as much information as possible to ensure a stable order of the file contents. This helps make application builds deterministic. Contribute to dotnet/source-build#4963
1 parent 97d9422 commit a0a2f74

File tree

1 file changed

+19
-10
lines changed

1 file changed

+19
-10
lines changed

src/libraries/Microsoft.Extensions.DependencyModel/src/DependencyContextWriter.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ private static void WriteRuntimeTargetInfo(DependencyContext context, Utf8JsonWr
5959
private static void WriteRuntimeGraph(DependencyContext context, Utf8JsonWriter jsonWriter)
6060
{
6161
jsonWriter.WriteStartObject(DependencyContextStrings.RuntimesPropertyName);
62-
foreach (RuntimeFallbacks runtimeFallback in context.RuntimeGraph)
62+
foreach (RuntimeFallbacks runtimeFallback in context.RuntimeGraph.OrderBy(r => r.Runtime, StringComparer.Ordinal))
6363
{
6464
jsonWriter.WriteStartArray(runtimeFallback.Runtime);
65-
foreach (string? fallback in runtimeFallback.Fallbacks)
65+
foreach (string? fallback in runtimeFallback.Fallbacks.OrderBy(s => s, StringComparer.Ordinal))
6666
{
6767
jsonWriter.WriteStringValue(fallback);
6868
}
@@ -148,7 +148,7 @@ private static void WritePortableTarget(string key, IReadOnlyList<RuntimeLibrary
148148

149149
jsonWriter.WriteStartObject(key);
150150

151-
foreach (string packageName in runtimeLookup.Keys.Concat(compileLookup.Keys).Distinct())
151+
foreach (string packageName in runtimeLookup.Keys.Concat(compileLookup.Keys).Distinct().OrderBy(s => s, StringComparer.Ordinal))
152152
{
153153
runtimeLookup.TryGetValue(packageName, out RuntimeLibrary? runtimeLibrary);
154154

@@ -201,7 +201,7 @@ private static void AddDependencies(IReadOnlyCollection<Dependency> dependencies
201201
}
202202

203203
jsonWriter.WriteStartObject(DependencyContextStrings.DependenciesPropertyName);
204-
foreach (Dependency dependency in dependencies)
204+
foreach (Dependency dependency in dependencies.OrderBy(d => d.Name, StringComparer.Ordinal).ThenBy(d => d.Version, StringComparer.Ordinal))
205205
{
206206
jsonWriter.WriteString(dependency.Name, dependency.Version);
207207
}
@@ -210,6 +210,7 @@ private static void AddDependencies(IReadOnlyCollection<Dependency> dependencies
210210

211211
private static void AddResourceAssemblies(IReadOnlyList<ResourceAssembly> resourceAssemblies, Utf8JsonWriter jsonWriter)
212212
{
213+
resourceAssemblies = resourceAssemblies.OrderBy(r => r.Path, StringComparer.Ordinal).ToList();
213214
int count = resourceAssemblies.Count;
214215
if (count == 0)
215216
{
@@ -264,7 +265,12 @@ private static void WritePortableTargetLibrary(string key, RuntimeLibrary? runti
264265
{
265266
jsonWriter.WriteStartObject(key);
266267

267-
var dependencies = new HashSet<Dependency>();
268+
var dependencyComparer = Comparer<Dependency>.Create((d1, d2) =>
269+
{
270+
int nameComparison = string.Compare(d1.Name, d2.Name, StringComparison.Ordinal);
271+
return (nameComparison != 0) ? nameComparison : string.Compare(d1.Version, d2.Version, StringComparison.Ordinal);
272+
});
273+
var dependencies = new SortedSet<Dependency>(dependencyComparer);
268274
if (runtimeLibrary != null)
269275
{
270276
dependencies.UnionWith(runtimeLibrary.Dependencies);
@@ -310,7 +316,9 @@ private static void WritePortableTargetLibrary(string key, RuntimeLibrary? runti
310316

311317
private static bool AddRuntimeSpecificAssetGroups(string assetType, IEnumerable<RuntimeAssetGroup> assetGroups, bool wroteObjectStart, Utf8JsonWriter jsonWriter)
312318
{
313-
using IEnumerator<RuntimeAssetGroup> groups = assetGroups.Where(g => !string.IsNullOrEmpty(g.Runtime)).GetEnumerator();
319+
using IEnumerator<RuntimeAssetGroup> groups = assetGroups.Where(g => !string.IsNullOrEmpty(g.Runtime))
320+
.OrderBy(g => g.Runtime, StringComparer.Ordinal)
321+
.GetEnumerator();
314322

315323
if (groups.MoveNext())
316324
{
@@ -351,7 +359,7 @@ private static bool AddRuntimeSpecificAssetGroups(string assetType, IEnumerable<
351359

352360
private static void AddRuntimeSpecificAssets(IEnumerable<RuntimeFile> assets, string? runtime, string? assetType, Utf8JsonWriter jsonWriter)
353361
{
354-
foreach (RuntimeFile asset in assets)
362+
foreach (RuntimeFile asset in assets.OrderBy(f => f.Path, StringComparer.Ordinal))
355363
{
356364
jsonWriter.WriteStartObject(NormalizePath(asset.Path));
357365

@@ -380,7 +388,7 @@ private static void AddRuntimeSpecificAssets(IEnumerable<RuntimeFile> assets, st
380388
private static void WriteAssetList(string key, IEnumerable<string> assetPaths, Utf8JsonWriter jsonWriter)
381389
{
382390
jsonWriter.WriteStartObject(key);
383-
foreach (string assembly in assetPaths)
391+
foreach (string assembly in assetPaths.OrderBy(s => s, StringComparer.Ordinal))
384392
{
385393
jsonWriter.WriteStartObject(NormalizePath(assembly));
386394
jsonWriter.WriteEndObject();
@@ -392,7 +400,7 @@ private static void WriteAssetList(string key, IEnumerable<RuntimeFile> runtimeF
392400
{
393401
jsonWriter.WriteStartObject(key);
394402

395-
foreach (RuntimeFile runtimeFile in runtimeFiles)
403+
foreach (RuntimeFile runtimeFile in runtimeFiles.OrderBy(r => r.Path, StringComparer.Ordinal))
396404
{
397405
jsonWriter.WriteStartObject(NormalizePath(runtimeFile.Path));
398406

@@ -421,7 +429,8 @@ private static void WriteLibraries(DependencyContext context, Utf8JsonWriter jso
421429
{
422430
IEnumerable<IGrouping<string, Library>> allLibraries =
423431
context.RuntimeLibraries.Cast<Library>().Concat(context.CompileLibraries)
424-
.GroupBy(library => library.Name + DependencyContextStrings.VersionSeparator + library.Version);
432+
.GroupBy(library => library.Name + DependencyContextStrings.VersionSeparator + library.Version)
433+
.OrderBy(grouping => grouping.Key, StringComparer.Ordinal);
425434

426435
jsonWriter.WriteStartObject(DependencyContextStrings.LibrariesPropertyName);
427436
foreach (IGrouping<string, Library> libraryGroup in allLibraries)

0 commit comments

Comments
 (0)