55
66using System ;
77using System . Collections . Generic ;
8+ using System . Collections . Immutable ;
89using System . Collections . ObjectModel ;
910using System . Diagnostics ;
1011using 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
0 commit comments