From 574157f126866d34a04b30125458d683efc923bc Mon Sep 17 00:00:00 2001 From: LebJe <51171427+LebJe@users.noreply.github.com> Date: Fri, 4 Dec 2020 14:29:30 -0500 Subject: [PATCH] Properly compute hashes on Linux by using swift-crypto. Remove `JSONPointer` and `toJSON`. Remove CryptoSwift dependency. Increase minimum macOS version requirement to 10.15 (Catalina). Increase version number in `main.swift` to 3.0.0. Update README. --- Package.swift | 11 +++-- README.md | 4 +- Sources/LFSPointersExecutable/main.swift | 2 +- Sources/LFSPointersKit/Extensions.swift | 19 ++++++++ Sources/LFSPointersKit/Pointers.swift | 44 ++++++++----------- Tests/LFSPointersTests/LFSPointersTests.swift | 4 +- 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/Package.swift b/Package.swift index 14bd05c..e63461a 100644 --- a/Package.swift +++ b/Package.swift @@ -5,24 +5,27 @@ import PackageDescription let package = Package( name: "LFSPointers", - platforms: [.macOS(.v10_13)], + platforms: [.macOS(.v10_15)], products: [ .executable(name: "LFSPointers", targets: ["LFSPointersExecutable"]), .library(name: "LFSPointersKit", targets: ["LFSPointersKit"]) ], dependencies: [ // Dependencies declare other packages that this package depends on. - .package(url: "https://github.com/krzyzanowskim/CryptoSwift", .exact("1.3.2")), .package(url: "https://github.com/apple/swift-argument-parser.git", from: "0.3.1"), .package(url: "https://github.com/onevcat/Rainbow", from: "3.1.5"), - .package(url: "https://github.com/JohnSundell/Files", from: "4.1.1") + .package(url: "https://github.com/JohnSundell/Files", from: "4.1.1"), + .package(url: "https://github.com/apple/swift-crypto.git", from: "1.1.2") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "LFSPointersKit", - dependencies: ["Files", "CryptoSwift"] + dependencies: [ + "Files", + .product(name: "Crypto", package: "swift-crypto") + ] ), .target( name: "LFSPointersExecutable", diff --git a/README.md b/README.md index 854788d..1ed3fe3 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ $ LFSPointers --generate-completion-script bash > ~/.bash_completions/LFSPointer Add this to the `dependencies` array in `Package.swift`: ```swift -.package(url: "https://github.com/LebJe/LFSPointers.git", from: “2.0.0”) +.package(url: "https://github.com/LebJe/LFSPointers.git", from: “3.0.0”) ``` . Also add this to the `targets` array in the aforementioned file: @@ -241,7 +241,7 @@ let pointer = try LFSPointer(...) try JSONEncoder().encode(pointer) ``` -and to convert an array of tuples consisting of filename, file path, and pointer: +and to convert an array of `LFSPointer`s: ```swift let pointers = try LFSPointer.pointers(...) diff --git a/Sources/LFSPointersExecutable/main.swift b/Sources/LFSPointersExecutable/main.swift index 8e12729..dffa7b8 100644 --- a/Sources/LFSPointersExecutable/main.swift +++ b/Sources/LFSPointersExecutable/main.swift @@ -32,7 +32,7 @@ struct LFSPointersCommand: ParsableCommand { commandName: "LFSPointers", abstract: "Replaces large files in a Git repository directory with Git LFS pointers.", discussion: "JSON STRUCTURE:\n\(jsonStructure)", - version: "2.0.0" + version: "3.0.0" ) @Flag(name: .shortAndLong, help: "Whether to display verbose output.") diff --git a/Sources/LFSPointersKit/Extensions.swift b/Sources/LFSPointersKit/Extensions.swift index 4e2ab44..0d5b797 100644 --- a/Sources/LFSPointersKit/Extensions.swift +++ b/Sources/LFSPointersKit/Extensions.swift @@ -14,3 +14,22 @@ public extension NSRegularExpression { firstMatch(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) != nil } } + +// From: https://github.com/apple/swift-crypto/blob/8f4bfa5bc1951440c15710e9e893721aa4b2765c/Sources/crypto-shasum/main.swift#L73 +public extension String { + init(hexEncoding data: Data) { + self = data.map { byte in + let s = String(byte, radix: 16) + switch s.count { + case 0: + return "00" + case 1: + return "0" + s + case 2: + return s + default: + fatalError("Weirdly hex encoded byte") + } + }.joined() + } +} diff --git a/Sources/LFSPointersKit/Pointers.swift b/Sources/LFSPointersKit/Pointers.swift index c12db09..5490ddb 100644 --- a/Sources/LFSPointersKit/Pointers.swift +++ b/Sources/LFSPointersKit/Pointers.swift @@ -7,7 +7,7 @@ import Foundation import Files -import CryptoSwift +import Crypto /// Represents a Git LFS pointer for a file. /// @@ -68,11 +68,25 @@ public struct LFSPointer: Codable, Equatable, Hashable { let file = try File(path: path.path) self.version = "https://git-lfs.github.com/spec/v1" - - self.oid = try FileHandle(forReadingFrom: file.url).availableData.sha256().toHexString() + + let handle = try FileHandle(forReadingFrom: file.url) + + let readSize = 8192 + var hasher = SHA256() + + while true { + let data = handle.readData(ofLength: readSize) + if data.count == 0 { + break + } + + hasher.update(data: data) + } + + self.oid = String(hexEncoding: Data(hasher.finalize())) let attr = try FileManager.default.attributesOfItem(atPath: file.path) - + self.size = (attr[.size] as? Int) ?? 0 self.filename = file.name @@ -259,28 +273,6 @@ extension LFSPointer: CustomDebugStringConvertible { } } -public struct JSONPointer: Codable { - public let filename: String - public let filePath: String - public let pointer: LFSPointer -} - -/// Generates a string containing `JSON`. -/// - Parameter array: No description. -/// - Returns: A `String` containing `JSON`. -public func toJSON(array: [JSONPointer], jsonFormat: JSONEncoder.OutputFormatting = .init()) -> String { - - let encoder = JSONEncoder() - - encoder.outputFormatting = jsonFormat - - let jsonBytes = (try? encoder.encode(array)) ?? Data() - - let jsonString = String(data: jsonBytes, encoding: .utf8) ?? "" - - return jsonString -} - public extension Array where Self.Element == LFSPointer { /// Converts and `Array` of `LFSPointer`s to `JSON`. /// - Parameter jsonFormat: The format of the generated `JSON`. diff --git a/Tests/LFSPointersTests/LFSPointersTests.swift b/Tests/LFSPointersTests/LFSPointersTests.swift index b5e85f6..7a7bd1b 100644 --- a/Tests/LFSPointersTests/LFSPointersTests.swift +++ b/Tests/LFSPointersTests/LFSPointersTests.swift @@ -8,11 +8,9 @@ final class LFSPointersTests: XCTestCase { func testConvertFileToPointer() throws { let pointer = try LFSPointer(fromFile: resources.file(named: "foo.txt").url) - - #if os(macOS) + XCTAssertEqual(667684, pointer.size) XCTAssertEqual("802cd848ada6f6f7177bc4bd0952e2c3a5c7378757899b1ed16c0f1a243eb930", pointer.oid) - #endif } func testRecursivelyGeneratePointersForFilesInSubdirectories() throws {