Skip to content

Commit de1b620

Browse files
committed
Add wrapper to isolate use of zip library
1 parent 3007062 commit de1b620

File tree

5 files changed

+166
-18
lines changed

5 files changed

+166
-18
lines changed

Sources/DocUploadBundle/DocUploadBundle.swift

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import Foundation
1616

1717
import Dependencies
18-
import Zip
1918

2019

2120
public struct DocUploadBundle {
@@ -107,26 +106,17 @@ public struct DocUploadBundle {
107106
}
108107

109108
public func zip(to workDir: String) throws -> String {
110-
let archiveURL = URL(fileURLWithPath: "\(workDir)/\(archiveName)")
111-
let metadataURL = URL(fileURLWithPath: "\(workDir)/metadata.json")
112-
try JSONEncoder().encode(metadata).write(to: metadataURL)
113-
114-
try Zip.zipFiles(
115-
paths: [metadataURL, URL(fileURLWithPath: sourcePath)],
116-
zipFilePath: archiveURL,
117-
password: nil,
118-
progress: nil
119-
)
120-
121-
return archiveURL.path
109+
let archiveURL = URL(fileURLWithPath: "\(workDir)/\(archiveName)")
110+
let metadataURL = URL(fileURLWithPath: "\(workDir)/metadata.json")
111+
try JSONEncoder().encode(metadata).write(to: metadataURL)
112+
113+
try Zipping.zip(paths: [metadataURL, URL(fileURLWithPath: sourcePath)], to: archiveURL)
114+
115+
return archiveURL.path
122116
}
123117

124118
public static func unzip(bundle: String, outputPath: String, fileOutputHandler: ((_ unzippedFile: URL) -> Void)? = nil) throws -> Metadata {
125-
try Zip.unzipFile(URL(fileURLWithPath: bundle),
126-
destination: URL(fileURLWithPath: outputPath),
127-
overwrite: true,
128-
password: nil,
129-
fileOutputHandler: fileOutputHandler)
119+
try Zipping.unzip(from: bundle, to: outputPath, fileOutputHandler: fileOutputHandler)
130120
let metadataURL = URL(fileURLWithPath: "\(outputPath)/metadata.json")
131121
let data = try Data(contentsOf: metadataURL)
132122
return try JSONDecoder().decode(Metadata.self, from: data)

Sources/DocUploadBundle/Zipping.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import Foundation
16+
17+
import Zip
18+
19+
20+
enum Zipping {
21+
static func zip(paths inputPaths: [URL], to outputPath: URL) throws {
22+
try Zip.zipFiles(paths: inputPaths, zipFilePath: outputPath, password: nil, progress: nil)
23+
}
24+
25+
static func unzip(from inputPath: URL, to outputPath: URL, fileOutputHandler: ((_ unzippedFile: URL) -> Void)? = nil) throws {
26+
try Zip.unzipFile(inputPath, destination: outputPath, overwrite: true, password: nil, fileOutputHandler: fileOutputHandler)
27+
}
28+
}
29+
30+
31+
extension Zipping {
32+
static func unzip(from inputPath: String, to outputPath: String, fileOutputHandler: ((_ unzippedFile: URL) -> Void)? = nil) throws {
33+
try unzip(from: URL(fileURLWithPath: inputPath), to: URL(fileURLWithPath: outputPath), fileOutputHandler: fileOutputHandler)
34+
}
35+
}
200 Bytes
Binary file not shown.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
16+
import Foundation
17+
18+
19+
// Helpers
20+
21+
func fixtureData(for fixture: String) throws -> Data {
22+
try Data(contentsOf: fixtureUrl(for: fixture))
23+
}
24+
25+
26+
func fixtureUrl(for fixture: String) -> URL {
27+
fixturesDirectory().appendingPathComponent(fixture)
28+
}
29+
30+
31+
func fixturesDirectory(path: String = #file) -> URL {
32+
let url = URL(fileURLWithPath: path)
33+
let testsDir = url.deletingLastPathComponent()
34+
return testsDir.appendingPathComponent("Fixtures")
35+
}
36+
37+
38+
// TempDir
39+
40+
enum TempDirError: LocalizedError {
41+
case invalidPath(String)
42+
}
43+
44+
45+
class TempDir {
46+
let path: String
47+
48+
init() throws {
49+
let tempDir = FileManager.default.temporaryDirectory
50+
.appendingPathComponent(UUID().uuidString)
51+
path = tempDir.path
52+
try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
53+
precondition(FileManager.default.fileExists(atPath: path), "failed to create temp dir")
54+
}
55+
56+
deinit {
57+
do {
58+
try FileManager.default.removeItem(atPath: path)
59+
} catch {
60+
print("⚠️ failed to delete temp directory: \(error.localizedDescription)")
61+
}
62+
}
63+
64+
}
65+
66+
67+
func withTempDir<T>(body: (String) async throws -> T) async throws -> T {
68+
let tmp = try TempDir()
69+
return try await body(tmp.path)
70+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import XCTest
16+
17+
@testable import DocUploadBundle
18+
19+
20+
final class ZipTests: XCTestCase {
21+
22+
func test_zip() async throws {
23+
// Test basic zip behaviour we expect from the library we use
24+
try await withTempDir { tempDir in
25+
let tempURL = URL(filePath: tempDir)
26+
let fileA = tempURL.appending(path: "a.txt")
27+
let fileB = tempURL.appending(path: "b.txt")
28+
try "a".write(to: fileA, atomically: true, encoding: .utf8)
29+
try "b".write(to: fileB, atomically: true, encoding: .utf8)
30+
let zipFile = tempURL.appending(path: "out.zip")
31+
try Zipping.zip(paths: [fileA, fileB], to: zipFile)
32+
XCTAssert(FileManager.default.fileExists(atPath: zipFile.path()))
33+
}
34+
}
35+
36+
func test_unzip() async throws {
37+
// Test basic unzip behaviour we expect from the library we use
38+
try await withTempDir { tempDir in
39+
let tempURL = URL(filePath: tempDir)
40+
let zipFile = fixtureUrl(for: "out.zip")
41+
let outDir = tempURL.appending(path: "out")
42+
try Zipping.unzip(from: zipFile, to: outDir)
43+
XCTAssert(FileManager.default.fileExists(atPath: outDir.path()))
44+
let fileA = outDir.appending(path: "a.txt")
45+
let fileB = outDir.appending(path: "b.txt")
46+
XCTAssert(FileManager.default.fileExists(atPath: fileA.path()))
47+
XCTAssert(FileManager.default.fileExists(atPath: fileB.path()))
48+
XCTAssertEqual(try String(contentsOf: fileA), "a")
49+
XCTAssertEqual(try String(contentsOf: fileB), "b")
50+
}
51+
}
52+
53+
}

0 commit comments

Comments
 (0)