Skip to content

Commit d2cb017

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 d2cb017

File tree

4 files changed

+34
-12
lines changed

4 files changed

+34
-12
lines changed

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: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ public class PackageBuilder : IPackageMetadata
3232
private static readonly DateTime ZipFormatMinDate = new DateTime(1980, 1, 1, 0, 0, 0, DateTimeKind.Utc);
3333
private static readonly DateTime ZipFormatMaxDate = new DateTime(2107, 12, 31, 23, 59, 58, DateTimeKind.Utc);
3434
internal const string ManifestRelationType = "manifest";
35+
private readonly IEnvironmentVariableReader _environmentVariableProvider;
3536
private readonly bool _includeEmptyDirectories;
3637
private readonly bool _deterministic;
3738
private readonly ILogger _logger;
39+
private readonly DateTime _deterministicDate;
3840

3941
/// <summary>
4042
/// Maximum Icon file size: 1 megabyte
@@ -68,7 +70,7 @@ public PackageBuilder(string path, string basePath, Func<string, string> propert
6870
}
6971

7072
public PackageBuilder(string path, string basePath, Func<string, string> propertyProvider, bool includeEmptyDirectories, bool deterministic)
71-
: this(includeEmptyDirectories, deterministic)
73+
: this(EnvironmentVariableWrapper.Instance, includeEmptyDirectories, deterministic)
7274
{
7375
if (!File.Exists(path))
7476
{
@@ -95,30 +97,32 @@ public PackageBuilder(Stream stream, string basePath, Func<string, string> prope
9597
}
9698

9799
public PackageBuilder(bool deterministic) :
98-
this(includeEmptyDirectories: false, deterministic: deterministic)
100+
this(EnvironmentVariableWrapper.Instance, includeEmptyDirectories: false, deterministic: deterministic)
99101
{
100102

101103
}
102104

103105
public PackageBuilder()
104-
: this(includeEmptyDirectories: false, deterministic: false)
106+
: this(EnvironmentVariableWrapper.Instance, includeEmptyDirectories: false, deterministic: false)
105107
{
106108
}
107109

108110
public PackageBuilder(bool deterministic, ILogger logger)
109-
: this(includeEmptyDirectories: false, deterministic: deterministic, logger)
111+
: this(EnvironmentVariableWrapper.Instance, includeEmptyDirectories: false, deterministic: deterministic, logger)
110112
{
111113
}
112114

113-
private PackageBuilder(bool includeEmptyDirectories, bool deterministic)
114-
: this(includeEmptyDirectories: false, deterministic: deterministic, logger: NullLogger.Instance)
115+
private PackageBuilder(IEnvironmentVariableReader environmentVariableProvider, bool includeEmptyDirectories, bool deterministic)
116+
: this(environmentVariableProvider, includeEmptyDirectories: false, deterministic: deterministic, logger: NullLogger.Instance)
115117
{
116118
}
117119

118-
private PackageBuilder(bool includeEmptyDirectories, bool deterministic, ILogger logger)
120+
private PackageBuilder(IEnvironmentVariableReader environmentVariableProvider, bool includeEmptyDirectories, bool deterministic, ILogger logger)
119121
{
122+
_environmentVariableProvider = environmentVariableProvider;
120123
_includeEmptyDirectories = includeEmptyDirectories;
121-
_deterministic = false; // fix in https://github.com/NuGet/Home/issues/8601
124+
_deterministic = deterministic;
125+
_deterministicDate = ComputeDeterministicDate();
122126
_logger = logger;
123127
Files = new Collection<IPackageFile>();
124128
DependencyGroups = new Collection<PackageDependencyGroup>();
@@ -135,6 +139,20 @@ private PackageBuilder(bool includeEmptyDirectories, bool deterministic, ILogger
135139
Properties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
136140
}
137141

142+
private DateTime ComputeDeterministicDate()
143+
{
144+
string sourceBuildEpoch = _environmentVariableProvider.GetEnvironmentVariable("SOURCE_DATE_EPOCH");
145+
if (sourceBuildEpoch != null &&
146+
long.TryParse(sourceBuildEpoch, NumberStyles.None, CultureInfo.InvariantCulture, out long unixTimeSeconds))
147+
{
148+
return DateTimeOffset.FromUnixTimeSeconds(unixTimeSeconds).UtcDateTime;
149+
}
150+
else
151+
{
152+
return ZipFormatMinDate;
153+
}
154+
}
155+
138156
public string Id
139157
{
140158
get;
@@ -1004,7 +1022,7 @@ private ZipArchiveEntry CreateEntry(ZipArchive package, string entryName, Compre
10041022
var entry = package.CreateEntry(entryName, compressionLevel);
10051023
if (_deterministic)
10061024
{
1007-
entry.LastWriteTime = ZipFormatMinDate;
1025+
entry.LastWriteTime = _deterministicDate;
10081026
}
10091027
return entry;
10101028
}
@@ -1060,7 +1078,7 @@ private SortedSet<string> WriteFiles(ZipArchive package, SortedSet<string> files
10601078
package,
10611079
file.Path,
10621080
stream,
1063-
lastWriteTime: _deterministic ? ZipFormatMinDate : file.LastWriteTime,
1081+
lastWriteTime: _deterministic ? _deterministicDate : file.LastWriteTime,
10641082
warningMessage);
10651083
var fileExtension = Path.GetExtension(file.Path);
10661084

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)