Skip to content

Commit f5e8987

Browse files
committed
Re-enable deterministic nuget pack
Deterministic support was disabled due to various concerns some time ago: NuGet/Home#8601 This PR re-enables deterministic support, while adding support for SOURCE_DATE_EPOCH to override it. SOURCE_DATE_EPOCH is specified at: https://reproducible-builds.org/docs/source-date-epoch/
1 parent d47c93e commit f5e8987

4 files changed

Lines changed: 35 additions & 12 deletions

File tree

src/NuGet.Clients/NuGet.CommandLine/Commands/PackCommand.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ public Dictionary<string, string> Properties
103103
[Option(typeof(NuGetCommand), "PackageCommandConfigFile")]
104104
public new string ConfigFile { get; set; }
105105

106+
[Option(typeof(NuGetCommand), "PackageCommandDeterministic")]
107+
public bool Deterministic { get; set; }
108+
106109
public override void ExecuteCommand()
107110
{
108111
var packArgs = new PackArgs();
@@ -111,6 +114,7 @@ public override void ExecuteCommand()
111114
packArgs.OutputDirectory = OutputDirectory;
112115
packArgs.BasePath = BasePath;
113116
packArgs.MsBuildDirectory = new Lazy<string>(() => MsBuildUtility.GetMsBuildDirectoryFromMsBuildPath(MSBuildPath, MSBuildVersion, Console).Value.Path);
117+
packArgs.Deterministic = Deterministic;
114118

115119
if (!string.IsNullOrEmpty(PackagesDirectory))
116120
{

src/NuGet.Core/NuGet.Packaging/PackageCreation/Authoring/PackageBuilder.cs

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using System;
77
using System.Collections.Generic;
8+
using System.Collections.Immutable;
89
using System.Collections.ObjectModel;
910
using System.Diagnostics;
1011
using System.Globalization;
@@ -32,9 +33,11 @@ public class PackageBuilder : IPackageMetadata
3233
private static readonly DateTime ZipFormatMinDate = new DateTime(1980, 1, 1, 0, 0, 0, DateTimeKind.Utc);
3334
private static readonly DateTime ZipFormatMaxDate = new DateTime(2107, 12, 31, 23, 59, 58, DateTimeKind.Utc);
3435
internal const string ManifestRelationType = "manifest";
36+
private readonly IEnvironmentVariableReader _environmentVariableProvider;
3537
private readonly bool _includeEmptyDirectories;
3638
private readonly bool _deterministic;
3739
private readonly ILogger _logger;
40+
private readonly DateTime _deterministicDate;
3841

3942
/// <summary>
4043
/// Maximum Icon file size: 1 megabyte
@@ -68,7 +71,7 @@ public PackageBuilder(string path, string basePath, Func<string, string> propert
6871
}
6972

7073
public PackageBuilder(string path, string basePath, Func<string, string> propertyProvider, bool includeEmptyDirectories, bool deterministic)
71-
: this(includeEmptyDirectories, deterministic)
74+
: this(EnvironmentVariableWrapper.Instance, includeEmptyDirectories, deterministic)
7275
{
7376
if (!File.Exists(path))
7477
{
@@ -95,30 +98,32 @@ public PackageBuilder(Stream stream, string basePath, Func<string, string> prope
9598
}
9699

97100
public PackageBuilder(bool deterministic) :
98-
this(includeEmptyDirectories: false, deterministic: deterministic)
101+
this(EnvironmentVariableWrapper.Instance, includeEmptyDirectories: false, deterministic: deterministic)
99102
{
100103

101104
}
102105

103106
public PackageBuilder()
104-
: this(includeEmptyDirectories: false, deterministic: false)
107+
: this(EnvironmentVariableWrapper.Instance, includeEmptyDirectories: false, deterministic: false)
105108
{
106109
}
107110

108111
public PackageBuilder(bool deterministic, ILogger logger)
109-
: this(includeEmptyDirectories: false, deterministic: deterministic, logger)
112+
: this(EnvironmentVariableWrapper.Instance, includeEmptyDirectories: false, deterministic: deterministic, logger)
110113
{
111114
}
112115

113-
private PackageBuilder(bool includeEmptyDirectories, bool deterministic)
114-
: this(includeEmptyDirectories: false, deterministic: deterministic, logger: NullLogger.Instance)
116+
private PackageBuilder(IEnvironmentVariableReader environmentVariableProvider, bool includeEmptyDirectories, bool deterministic)
117+
: this(environmentVariableProvider, includeEmptyDirectories: false, deterministic: deterministic, logger: NullLogger.Instance)
115118
{
116119
}
117120

118-
private PackageBuilder(bool includeEmptyDirectories, bool deterministic, ILogger logger)
121+
private PackageBuilder(IEnvironmentVariableReader environmentVariableProvider, bool includeEmptyDirectories, bool deterministic, ILogger logger)
119122
{
123+
_environmentVariableProvider = environmentVariableProvider;
120124
_includeEmptyDirectories = includeEmptyDirectories;
121-
_deterministic = false; // fix in https://github.com/NuGet/Home/issues/8601
125+
_deterministic = deterministic;
126+
_deterministicDate = ComputeDeterministicDate();
122127
_logger = logger;
123128
Files = new Collection<IPackageFile>();
124129
DependencyGroups = new Collection<PackageDependencyGroup>();
@@ -135,6 +140,20 @@ private PackageBuilder(bool includeEmptyDirectories, bool deterministic, ILogger
135140
Properties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
136141
}
137142

143+
private DateTime ComputeDeterministicDate()
144+
{
145+
string sourceBuildEpoch = _environmentVariableProvider.GetEnvironmentVariable("SOURCE_DATE_EPOCH");
146+
if (sourceBuildEpoch != null &&
147+
long.TryParse(sourceBuildEpoch, NumberStyles.None, CultureInfo.InvariantCulture, out long unixTimeSeconds))
148+
{
149+
return DateTimeOffset.FromUnixTimeSeconds(unixTimeSeconds).UtcDateTime;
150+
}
151+
else
152+
{
153+
return ZipFormatMinDate;
154+
}
155+
}
156+
138157
public string Id
139158
{
140159
get;
@@ -1004,7 +1023,7 @@ private ZipArchiveEntry CreateEntry(ZipArchive package, string entryName, Compre
10041023
var entry = package.CreateEntry(entryName, compressionLevel);
10051024
if (_deterministic)
10061025
{
1007-
entry.LastWriteTime = ZipFormatMinDate;
1026+
entry.LastWriteTime = _deterministicDate;
10081027
}
10091028
return entry;
10101029
}
@@ -1060,7 +1079,7 @@ private SortedSet<string> WriteFiles(ZipArchive package, SortedSet<string> files
10601079
package,
10611080
file.Path,
10621081
stream,
1063-
lastWriteTime: _deterministic ? ZipFormatMinDate : file.LastWriteTime,
1082+
lastWriteTime: _deterministic ? _deterministicDate : file.LastWriteTime,
10641083
warningMessage);
10651084
var fileExtension = Path.GetExtension(file.Path);
10661085

test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPackCommandTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6296,7 +6296,7 @@ private static void VerifyNuspecRoundTrips(PackageArchiveReader nupkgReader, str
62966296
}
62976297
}
62986298

6299-
[Fact(Skip = "https://github.com/NuGet/Home/issues/8601")]
6299+
[Fact]
63006300
public void PackCommand_Deterministic_MultiplePackInvocations_CreateIdenticalPackages()
63016301
{
63026302
var nugetexe = Util.GetNuGetExePath();

test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4950,7 +4950,7 @@ public void PackCommand_WithGeneratePackageOnBuildSet_CanPublish()
49504950
}
49514951
}
49524952

4953-
[PlatformFact(Platform.Windows, Skip = "https://github.com/NuGet/Home/issues/8601")]
4953+
[PlatformFact(Platform.Windows)]
49544954
public void PackCommand_Deterministic_MultiplePackInvocations_CreateIdenticalPackages()
49554955
{
49564956
using (var testDirectory = _dotnetFixture.CreateTestDirectory())

0 commit comments

Comments
 (0)