@@ -16,6 +16,19 @@ namespace Fallout.Common.IO;
1616
1717public static class CompressionExtensions
1818{
19+ /// <summary>
20+ /// Compresses <paramref name="directory" /> into <paramref name="archiveFile" />, choosing the compression format based on the
21+ /// archive file's extension.
22+ /// </summary>
23+ /// <param name="directory">The directory whose contents should be compressed.</param>
24+ /// <param name="archiveFile">
25+ /// The archive file to create. Its extension determines the compression format (e.g. <c>.zip</c>,
26+ /// <c>.tar.gz</c>, <c>.tar.bz2</c>).
27+ /// </param>
28+ /// <param name="filter">
29+ /// An optional predicate used to filter which files are included in the archive. If <c>null</c>, all files are
30+ /// included.
31+ /// </param>
1932 public static void CompressTo ( this AbsolutePath directory , AbsolutePath archiveFile , Func < AbsolutePath , bool > filter = null )
2033 {
2134 if ( archiveFile . HasExtension ( ".zip" ) )
@@ -32,14 +45,24 @@ public static void CompressTo(this AbsolutePath directory, AbsolutePath archiveF
3245 }
3346 else if ( archiveFile . HasExtension ( ".tar.xz" , ".txz" ) )
3447 {
35- Assert . Fail ( $ "Compressing a .tar.xz archive currently not supported. Archive file: '{ Path . GetFileName ( archiveFile ) } '") ;
48+ Assert . Fail (
49+ $ "Compressing a .tar.xz archive currently not supported. Archive file: '{ Path . GetFileName ( archiveFile ) } '") ;
3650 }
3751 else
3852 {
3953 Assert . Fail ( $ "Unknown archive extension for archive '{ Path . GetFileName ( archiveFile ) } '") ;
4054 }
4155 }
4256
57+ /// <summary>
58+ /// Uncompresses <paramref name="archiveFile" /> into <paramref name="directory" />, choosing the decompression format based on
59+ /// the archive file's extension.
60+ /// </summary>
61+ /// <param name="archiveFile">
62+ /// The archive file to extract. Its extension determines the decompression format (e.g. <c>.zip</c>,
63+ /// <c>.tar.gz</c>, <c>.tar.bz2</c>, <c>.tar.xz</c>).
64+ /// </param>
65+ /// <param name="directory">The directory into which the archive's contents are extracted.</param>
4366 public static void UncompressTo ( this AbsolutePath archiveFile , AbsolutePath directory )
4467 {
4568 if ( archiveFile . HasExtension ( ".zip" ) )
@@ -64,6 +87,17 @@ public static void UncompressTo(this AbsolutePath archiveFile, AbsolutePath dire
6487 }
6588 }
6689
90+ /// <summary>
91+ /// Compresses <paramref name="directory" /> into a ZIP archive at <paramref name="archiveFile" />.
92+ /// </summary>
93+ /// <param name="directory">The directory whose contents should be added to the ZIP archive.</param>
94+ /// <param name="archiveFile">The ZIP archive file to create.</param>
95+ /// <param name="filter">
96+ /// An optional predicate used to filter which files are included in the archive. If <c>null</c>, all files are
97+ /// included.
98+ /// </param>
99+ /// <param name="compressionLevel">The compression level to use for the archive entries.</param>
100+ /// <param name="fileMode">The <see cref="FileMode" /> used to open the archive file.</param>
67101 public static void ZipTo (
68102 this AbsolutePath directory ,
69103 AbsolutePath archiveFile ,
@@ -74,95 +108,145 @@ public static void ZipTo(
74108 archiveFile . Parent . CreateDirectory ( ) ;
75109
76110 filter ??= _ => true ;
77- var files = directory . GetFiles ( depth : int . MaxValue ) . Where ( filter ) . ToList ( ) ;
111+ List < AbsolutePath > files = directory . GetFiles ( depth : int . MaxValue ) . Where ( filter ) . ToList ( ) ;
78112
79- using var fileStream = File . Open ( archiveFile , fileMode , FileAccess . ReadWrite ) ;
80- using var zipArchive = new ZipArchive ( fileStream , ZipArchiveMode . Create ) ;
113+ using FileStream fileStream = File . Open ( archiveFile , fileMode , FileAccess . ReadWrite ) ;
114+ using ZipArchive zipArchive = new ( fileStream , ZipArchiveMode . Create ) ;
81115
82116 void AddFile ( AbsolutePath file )
83117 {
84- var relativePath = directory . GetRelativePathTo ( file ) ;
85- var entryName = ZipEntry . CleanName ( relativePath ) ;
118+ RelativePath relativePath = directory . GetRelativePathTo ( file ) ;
119+ string entryName = ZipEntry . CleanName ( relativePath ) ;
86120 zipArchive . CreateEntryFromFile ( file , entryName , compressionLevel ) ;
87121 }
88122
89123 files . ForEach ( AddFile ) ;
90124 }
91125
126+ /// <summary>
127+ /// Extracts the contents of a ZIP archive at <paramref name="archiveFile" /> into <paramref name="directory" />.
128+ /// Destination directory is created, and conflicting files are overwritten.
129+ /// </summary>
130+ /// <param name="archiveFile">The ZIP archive file to extract.</param>
131+ /// <param name="directory">The directory into which the archive's contents are extracted.</param>
92132 public static void UnZipTo ( this AbsolutePath archiveFile , AbsolutePath directory )
93133 {
94- using var fileStream = File . OpenRead ( archiveFile ) ;
95- using var zipFile = new ZipFile ( fileStream ) ;
134+ using FileStream fileStream = File . OpenRead ( archiveFile ) ;
135+ using ZipFile zipFile = new ( fileStream ) ;
96136
97- var entries = zipFile . Cast < ZipEntry > ( ) . Where ( x => ! x . IsDirectory ) ;
137+ IEnumerable < ZipEntry > entries = zipFile . Cast < ZipEntry > ( ) . Where ( x => ! x . IsDirectory ) ;
98138
99139 void HandleEntry ( ZipEntry entry )
100140 {
101- var file = directory / entry . Name ;
141+ AbsolutePath file = directory / entry . Name ;
102142 Directory . CreateDirectory ( file . Parent . NotNull ( ) ) ;
103143
104- using var entryStream = zipFile . GetInputStream ( entry ) ;
105- using var outputStream = File . Open ( file , FileMode . Create ) ;
144+ using Stream entryStream = zipFile . GetInputStream ( entry ) ;
145+ using FileStream outputStream = File . Open ( file , FileMode . Create ) ;
106146 entryStream . CopyTo ( outputStream ) ;
107147 }
108148
109149 entries . ForEach ( HandleEntry ) ;
110150 }
111151
152+ /// <summary>
153+ /// Compresses the given <paramref name="files" /> into a gzip-compressed tar archive at <paramref name="archiveFile" />.
154+ /// </summary>
155+ /// <param name="baseDirectory">The base directory used to compute the relative entry names of the archived files.</param>
156+ /// <param name="archiveFile">The tar.gz archive file to create.</param>
157+ /// <param name="files">The files to add to the archive.</param>
158+ /// <param name="fileMode">The <see cref="FileMode" /> used to open the archive file.</param>
112159 public static void TarGZipTo (
113160 this AbsolutePath baseDirectory ,
114161 AbsolutePath archiveFile ,
115162 IEnumerable < AbsolutePath > files ,
116- FileMode fileMode = FileMode . CreateNew )
117- {
163+ FileMode fileMode = FileMode . CreateNew ) =>
118164 CompressTar ( baseDirectory , archiveFile , files . ToList ( ) , fileMode , x => new GZipOutputStream ( x ) ) ;
119- }
120165
166+ /// <summary>
167+ /// Compresses <paramref name="directory" /> into a gzip-compressed tar archive at <paramref name="archiveFile" />.
168+ /// </summary>
169+ /// <param name="directory">The directory whose contents should be added to the archive.</param>
170+ /// <param name="archiveFile">The tar.gz archive file to create.</param>
171+ /// <param name="filter">
172+ /// An optional predicate used to filter which files are included in the archive. If <c>null</c>, all files are
173+ /// included.
174+ /// </param>
175+ /// <param name="fileMode">The <see cref="FileMode" /> used to open the archive file.</param>
121176 public static void TarGZipTo (
122177 this AbsolutePath directory ,
123178 AbsolutePath archiveFile ,
124179 Func < AbsolutePath , bool > filter = null ,
125180 FileMode fileMode = FileMode . CreateNew )
126181 {
127182 filter ??= _ => true ;
128- var files = directory . GetFiles ( depth : int . MaxValue ) . Where ( filter ) ;
183+ IEnumerable < AbsolutePath > files = directory . GetFiles ( depth : int . MaxValue ) . Where ( filter ) ;
129184 directory . TarGZipTo ( archiveFile , files , fileMode ) ;
130185 }
131186
187+ /// <summary>
188+ /// Compresses the given <paramref name="files" /> into a bzip2-compressed tar archive at <paramref name="archiveFile" />.
189+ /// </summary>
190+ /// <param name="directory">The base directory used to compute the relative entry names of the archived files.</param>
191+ /// <param name="archiveFile">The tar.bz2 archive file to create.</param>
192+ /// <param name="files">The files to add to the archive.</param>
193+ /// <param name="fileMode">The <see cref="FileMode" /> used to open the archive file.</param>
132194 public static void TarBZip2To (
133195 this AbsolutePath directory ,
134196 AbsolutePath archiveFile ,
135197 IEnumerable < AbsolutePath > files ,
136- FileMode fileMode = FileMode . CreateNew )
137- {
198+ FileMode fileMode = FileMode . CreateNew ) =>
138199 CompressTar ( directory , archiveFile , files . ToList ( ) , fileMode , x => new BZip2OutputStream ( x ) ) ;
139- }
140200
201+ /// <summary>
202+ /// Compresses <paramref name="directory" /> into a bzip2-compressed tar archive at <paramref name="archiveFile" />.
203+ /// </summary>
204+ /// <param name="directory">The directory whose contents should be added to the archive.</param>
205+ /// <param name="archiveFile">The tar.bz2 archive file to create.</param>
206+ /// <param name="filter">
207+ /// An optional predicate used to filter which files are included in the archive. If <c>null</c>, all files are
208+ /// included.
209+ /// </param>
210+ /// <param name="fileMode">The <see cref="FileMode" /> used to open the archive file.</param>
141211 public static void TarBZip2To (
142212 this AbsolutePath directory ,
143213 AbsolutePath archiveFile ,
144214 Func < AbsolutePath , bool > filter = null ,
145215 FileMode fileMode = FileMode . CreateNew )
146216 {
147217 filter ??= _ => true ;
148- var files = directory . GetFiles ( depth : int . MaxValue ) . Where ( filter ) ;
218+ IEnumerable < AbsolutePath > files = directory . GetFiles ( depth : int . MaxValue ) . Where ( filter ) ;
149219 directory . TarBZip2To ( archiveFile , files , fileMode ) ;
150220 }
151221
152- public static void UnTarGZipTo ( this AbsolutePath archiveFile , AbsolutePath directory )
153- {
222+ /// <summary>
223+ /// Extracts the contents of a gzip-compressed tar archive at <paramref name="archiveFile" /> into <paramref name="directory" />.
224+ /// Destination directory is created, and conflicting files are overwritten.
225+ /// </summary>
226+ /// <param name="archiveFile">The tar.gz archive file to extract.</param>
227+ /// <param name="directory">The directory into which the archive's contents are extracted.</param>
228+ public static void UnTarGZipTo ( this AbsolutePath archiveFile , AbsolutePath directory ) =>
154229 UncompressTar ( archiveFile , directory , x => new GZipInputStream ( x ) ) ;
155- }
156230
157- public static void UnTarBZip2To ( this AbsolutePath archiveFile , AbsolutePath directory )
158- {
231+ /// <summary>
232+ /// Extracts the contents of a bzip2-compressed tar archive at <paramref name="archiveFile" /> into <paramref name="directory" />.
233+ /// Destination directory is created, and conflicting files are overwritten.
234+ /// </summary>
235+ /// <param name="archiveFile">The tar.bz2 archive file to extract.</param>
236+ /// <param name="directory">The directory into which the archive's contents are extracted.</param>
237+ public static void UnTarBZip2To ( this AbsolutePath archiveFile , AbsolutePath directory ) =>
159238 UncompressTar ( archiveFile , directory , x => new BZip2InputStream ( x ) ) ;
160- }
161239
240+ /// <summary>
241+ /// Extracts the contents of an xz-compressed tar archive at <paramref name="archive" /> into <paramref name="directory" />.
242+ /// Destination directory is created, and conflicting files are skipped.
243+ /// </summary>
244+ /// <param name="archive">The tar.xz archive file to extract.</param>
245+ /// <param name="directory">The directory into which the archive's contents are extracted.</param>
162246 public static void UnTarXzTo ( this AbsolutePath archive , AbsolutePath directory )
163247 {
164248 using Stream stream = File . OpenRead ( archive ) ;
165- using var reader = ReaderFactory . OpenReader ( stream ) ;
249+ using IReader reader = ReaderFactory . OpenReader ( stream ) ;
166250
167251 while ( reader . MoveToNextEntry ( ) )
168252 {
@@ -179,6 +263,15 @@ public static void UnTarXzTo(this AbsolutePath archive, AbsolutePath directory)
179263 }
180264 }
181265
266+ /// <summary>
267+ /// Compresses the given <paramref name="files" /> into a tar archive at <paramref name="archiveFile" />, wrapping the underlying
268+ /// file stream with the compression stream produced by <paramref name="outputStreamFactory" />.
269+ /// </summary>
270+ /// <param name="baseDirectory">The base directory used to compute the relative entry names of the archived files.</param>
271+ /// <param name="archiveFile">The archive file to create.</param>
272+ /// <param name="files">The files to add to the archive.</param>
273+ /// <param name="fileMode">The <see cref="FileMode" /> used to open the archive file.</param>
274+ /// <param name="outputStreamFactory">A factory that wraps the raw archive file stream with the desired compression stream.</param>
182275 private static void CompressTar (
183276 AbsolutePath baseDirectory ,
184277 AbsolutePath archiveFile ,
@@ -188,26 +281,33 @@ private static void CompressTar(
188281 {
189282 archiveFile . Parent . CreateDirectory ( ) ;
190283
191- using var fileStream = File . Open ( archiveFile , fileMode , FileAccess . ReadWrite ) ;
192- using var outputStream = outputStreamFactory ( fileStream ) ;
193- using var tarArchive = TarArchive . CreateOutputTarArchive ( outputStream ) ;
284+ using FileStream fileStream = File . Open ( archiveFile , fileMode , FileAccess . ReadWrite ) ;
285+ using Stream outputStream = outputStreamFactory ( fileStream ) ;
286+ using TarArchive tarArchive = TarArchive . CreateOutputTarArchive ( outputStream ) ;
194287
195288 void AddFile ( AbsolutePath file )
196289 {
197- var entry = TarEntry . CreateEntryFromFile ( file ) ;
290+ TarEntry entry = TarEntry . CreateEntryFromFile ( file ) ;
198291 entry . Name = baseDirectory . GetUnixRelativePathTo ( file ) ;
199292
200- tarArchive . WriteEntry ( entry , recurse : false ) ;
293+ tarArchive . WriteEntry ( entry , false ) ;
201294 }
202295
203296 files . ForEach ( AddFile ) ;
204297 }
205298
299+ /// <summary>
300+ /// Extracts the contents of a tar archive at <paramref name="archiveFile" /> into <paramref name="directory" />, wrapping the
301+ /// underlying file stream with the decompression stream produced by <paramref name="inputStreamFactory" />.
302+ /// </summary>
303+ /// <param name="archiveFile">The archive file to extract.</param>
304+ /// <param name="directory">The directory into which the archive's contents are extracted.</param>
305+ /// <param name="inputStreamFactory">A factory that wraps the raw archive file stream with the desired decompression stream.</param>
206306 private static void UncompressTar ( AbsolutePath archiveFile , AbsolutePath directory , Func < Stream , Stream > inputStreamFactory )
207307 {
208- using var fileStream = File . OpenRead ( archiveFile ) ;
209- using var inputStream = inputStreamFactory ( fileStream ) ;
210- using var tarArchive = TarArchive . CreateInputTarArchive ( inputStream , nameEncoding : null ) ;
308+ using FileStream fileStream = File . OpenRead ( archiveFile ) ;
309+ using Stream inputStream = inputStreamFactory ( fileStream ) ;
310+ using TarArchive tarArchive = TarArchive . CreateInputTarArchive ( inputStream , null ) ;
211311
212312 directory . CreateDirectory ( ) ;
213313
0 commit comments