Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/SwiftDependencyUpdaterLibrary/Dependency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct Dependency {
}

static func loadDependencies(from folder: URL) throws -> [Dependency] {
let packageDescription = try PackageDescription.loadPackageDescription(from: folder)
let packageDescription = try PackageDescriptionFactory.loadPackageDescription(from: folder)
if packageDescription.dependencies.isEmpty {
return []
}
Expand Down
67 changes: 61 additions & 6 deletions Sources/SwiftDependencyUpdaterLibrary/PackageDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,29 @@ import Foundation
import Releases
import ShellOut

struct PackageDependency: Decodable {
protocol PackageDependency: Decodable {

var name: String { get }
var requirement: DependencyRequirement { get }
var url: URL { get }

}

private struct PackageDependencyV54: PackageDependency {

let name: String
let requirement: DependencyRequirement
let url: URL
}

private struct PackageDependencyV55: PackageDependency {

enum CodingKeys: String, CodingKey {
case name = "identity"
case requirement
case url = "location"
}

let name: String
let requirement: DependencyRequirement
let url: URL
Expand Down Expand Up @@ -68,18 +90,47 @@ enum PackageDescriptionError: Error, Equatable {
case parsingFailed(String, String)
}

struct PackageDescription: Decodable {
let dependencies: [PackageDependency]
struct PackageDescriptionV54: PackageDescription {

static func loadPackageDescription(from folder: URL) throws -> Self {
enum CodingKeys: String, CodingKey {
case dependenciesArray = "dependencies"
}

private let dependenciesArray: [PackageDependencyV54]
var dependencies: [PackageDependency] {
dependenciesArray
}

}

struct PackageDescriptionV55: PackageDescription {

enum CodingKeys: String, CodingKey {
case dependencyMap = "dependencies"
}

private let dependencyMap: [[String: [PackageDependencyV55]]]
var dependencies: [PackageDependency] {
dependencyMap.flatMap { $0.values.flatMap { $0 } }
}

}

enum PackageDescriptionFactory {
static func loadPackageDescription(from folder: URL) throws -> PackageDescription {
let json = try readPackageDescription(from: folder)
let data = json.data(using: .utf8)!
let decoder = JSONDecoder()
do {
let packageDescription = try decoder.decode(Self.self, from: data)
let packageDescription = try decoder.decode(PackageDescriptionV55.self, from: data)
return packageDescription
} catch {
throw PackageDescriptionError.parsingFailed(error.localizedDescription, json)
do {
let packageDescription = try decoder.decode(PackageDescriptionV54.self, from: data)
return packageDescription
} catch {
}
throw PackageDescriptionError.parsingFailed(String(describing: error), json)
}
}

Expand All @@ -94,6 +145,10 @@ struct PackageDescription: Decodable {
}
}

protocol PackageDescription: Decodable {
var dependencies: [PackageDependency] { get }
}

extension PackageDescriptionError: LocalizedError {
public var errorDescription: String? {
switch self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,34 @@ class PackageDescriptionTest: XCTestCase {
func testEmptyFolder() {
let folder = emptyFolderURL()
assert(
try PackageDescription.loadPackageDescription(from: folder),
try PackageDescriptionFactory.loadPackageDescription(from: folder),
throws: PackageDescriptionError.loadingFailed("error: root manifest not found")
)
}

func testInvalidFile() {
var caughtError: Error?
let folder = emptyFolderURL()
let file = temporaryFileURL(in: folder, name: "Package.swift")
createFile(at: file, content: "// swift-tools-version:5.4.0\n")
#if os(Linux)
assert(
try PackageDescription.loadPackageDescription(from: folder),
throws: PackageDescriptionError.loadingFailed("\(folder.path): error: malformed")
)
#else
assert(
try PackageDescription.loadPackageDescription(from: folder),
throws: PackageDescriptionError.loadingFailed("/private\(folder.path): error: malformed")
)
#endif

XCTAssertThrowsError(try PackageDescriptionFactory.loadPackageDescription(from: folder)) {
caughtError = $0
}

guard let error = caughtError as? PackageDescriptionError, case let .loadingFailed(description) = error else {
XCTFail("Unexpected error, got \(type(of: caughtError!)) \(caughtError!)) instead of PackageDescriptionError.loadingFailed")
return
}

XCTAssert(description.contains("\(folder.path): error: malformed"))
}

func testParsing() {
let folder = emptyFolderURL()
let file = temporaryFileURL(in: folder, name: "Package.swift")
createFile(at: file, content: TestUtils.packageSwiftFileContent)
let result = try! PackageDescription.loadPackageDescription(from: folder)
let result = try! PackageDescriptionFactory.loadPackageDescription(from: folder)
XCTAssertEqual(result.dependencies.count, 8)

XCTAssertEqual(result.dependencies[0].name, "a")
Expand Down