Skip to content

Commit

Permalink
Merge pull request #21 from SwiftPackageIndex/wrap-zip-library
Browse files Browse the repository at this point in the history
Add wrapper to isolate use of zip library
  • Loading branch information
finestructure committed May 27, 2024
2 parents 3007062 + 8a03150 commit dd73918
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ let package = Package(
.product(name: "Zip", package: "Zip"),
.product(name: "Dependencies", package: "swift-dependencies")
]),
.testTarget(name: "DocUploadBundleTests", dependencies: ["DocUploadBundle"]),
.testTarget(name: "DocUploadBundleTests", dependencies: ["DocUploadBundle"], exclude: ["Fixtures"]),
.testTarget(name: "DocUploaderTests", dependencies: ["DocUploader"]),
]
)
26 changes: 8 additions & 18 deletions Sources/DocUploadBundle/DocUploadBundle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import Foundation

import Dependencies
import Zip


public struct DocUploadBundle {
Expand Down Expand Up @@ -107,26 +106,17 @@ public struct DocUploadBundle {
}

public func zip(to workDir: String) throws -> String {
let archiveURL = URL(fileURLWithPath: "\(workDir)/\(archiveName)")
let metadataURL = URL(fileURLWithPath: "\(workDir)/metadata.json")
try JSONEncoder().encode(metadata).write(to: metadataURL)

try Zip.zipFiles(
paths: [metadataURL, URL(fileURLWithPath: sourcePath)],
zipFilePath: archiveURL,
password: nil,
progress: nil
)

return archiveURL.path
let archiveURL = URL(fileURLWithPath: "\(workDir)/\(archiveName)")
let metadataURL = URL(fileURLWithPath: "\(workDir)/metadata.json")
try JSONEncoder().encode(metadata).write(to: metadataURL)

try Zipper.zip(paths: [metadataURL, URL(fileURLWithPath: sourcePath)], to: archiveURL)

return archiveURL.path
}

public static func unzip(bundle: String, outputPath: String, fileOutputHandler: ((_ unzippedFile: URL) -> Void)? = nil) throws -> Metadata {
try Zip.unzipFile(URL(fileURLWithPath: bundle),
destination: URL(fileURLWithPath: outputPath),
overwrite: true,
password: nil,
fileOutputHandler: fileOutputHandler)
try Zipper.unzip(from: bundle, to: outputPath, fileOutputHandler: fileOutputHandler)
let metadataURL = URL(fileURLWithPath: "\(outputPath)/metadata.json")
let data = try Data(contentsOf: metadataURL)
return try JSONDecoder().decode(Metadata.self, from: data)
Expand Down
35 changes: 35 additions & 0 deletions Sources/DocUploadBundle/Zipper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Foundation

import Zip


enum Zipper {
static func zip(paths inputPaths: [URL], to outputPath: URL) throws {
try Zip.zipFiles(paths: inputPaths, zipFilePath: outputPath, password: nil, progress: nil)
}

static func unzip(from inputPath: URL, to outputPath: URL, fileOutputHandler: ((_ unzippedFile: URL) -> Void)? = nil) throws {
try Zip.unzipFile(inputPath, destination: outputPath, overwrite: true, password: nil, fileOutputHandler: fileOutputHandler)
}
}


extension Zipper {
static func unzip(from inputPath: String, to outputPath: String, fileOutputHandler: ((_ unzippedFile: URL) -> Void)? = nil) throws {
try unzip(from: URL(fileURLWithPath: inputPath), to: URL(fileURLWithPath: outputPath), fileOutputHandler: fileOutputHandler)
}
}
Binary file added Tests/DocUploadBundleTests/Fixtures/out.zip
Binary file not shown.
70 changes: 70 additions & 0 deletions Tests/DocUploadBundleTests/Utils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


import Foundation


// Helpers

func fixtureData(for fixture: String) throws -> Data {
try Data(contentsOf: fixtureUrl(for: fixture))
}


func fixtureUrl(for fixture: String) -> URL {
fixturesDirectory().appendingPathComponent(fixture)
}


func fixturesDirectory(path: String = #file) -> URL {
let url = URL(fileURLWithPath: path)
let testsDir = url.deletingLastPathComponent()
return testsDir.appendingPathComponent("Fixtures")
}


// TempDir

enum TempDirError: LocalizedError {
case invalidPath(String)
}


class TempDir {
let path: String

init() throws {
let tempDir = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
path = tempDir.path
try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
precondition(FileManager.default.fileExists(atPath: path), "failed to create temp dir")
}

deinit {
do {
try FileManager.default.removeItem(atPath: path)
} catch {
print("⚠️ failed to delete temp directory: \(error.localizedDescription)")
}
}

}


func withTempDir<T>(body: (String) async throws -> T) async throws -> T {
let tmp = try TempDir()
return try await body(tmp.path)
}
53 changes: 53 additions & 0 deletions Tests/DocUploadBundleTests/ZipTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import XCTest

@testable import DocUploadBundle


final class ZipTests: XCTestCase {

func test_zip() async throws {
// Test basic zip behaviour we expect from the library we use
try await withTempDir { tempDir in
let tempURL = URL(fileURLWithPath: tempDir)
let fileA = tempURL.appendingPathComponent("a.txt")
let fileB = tempURL.appendingPathComponent("b.txt")
try "a".write(to: fileA, atomically: true, encoding: .utf8)
try "b".write(to: fileB, atomically: true, encoding: .utf8)
let zipFile = tempURL.appendingPathComponent("out.zip")
try Zipper.zip(paths: [fileA, fileB], to: zipFile)
XCTAssert(FileManager.default.fileExists(atPath: zipFile.path))
}
}

func test_unzip() async throws {
// Test basic unzip behaviour we expect from the library we use
try await withTempDir { tempDir in
let tempURL = URL(fileURLWithPath: tempDir)
let zipFile = fixtureUrl(for: "out.zip")
let outDir = tempURL.appendingPathComponent("out")
try Zipper.unzip(from: zipFile, to: outDir)
XCTAssert(FileManager.default.fileExists(atPath: outDir.path))
let fileA = outDir.appendingPathComponent("a.txt")
let fileB = outDir.appendingPathComponent("b.txt")
XCTAssert(FileManager.default.fileExists(atPath: fileA.path))
XCTAssert(FileManager.default.fileExists(atPath: fileB.path))
XCTAssertEqual(try String(contentsOf: fileA), "a")
XCTAssertEqual(try String(contentsOf: fileB), "b")
}
}

}

0 comments on commit dd73918

Please sign in to comment.