diff --git a/Sources/BinaryDependencyManager/Models/BinaryDependenciesConfiguration.swift b/Sources/BinaryDependencyManager/Models/BinaryDependenciesConfiguration.swift new file mode 100644 index 0000000..280cad7 --- /dev/null +++ b/Sources/BinaryDependencyManager/Models/BinaryDependenciesConfiguration.swift @@ -0,0 +1,55 @@ +import Foundation + +/// Binary dependencies configuration. +struct BinaryDependenciesConfiguration: Equatable { + /// Minimum version of the `binary-dependencies-manager` CLI. + var minimumVersion: Version? + /// Path to the output directory, where downloaded dependencies will be placed. + var outputDirectory: String? + /// Path to the cache directory. + var cacheDirectory: String? + /// Dependencies list. + var dependencies: [Dependency] +} + +extension BinaryDependenciesConfiguration: Codable { + + private enum CodingKeys: String, CodingKey { + case minimumVersion + case outputDirectory + case cacheDirectory + case dependencies + } + + init(from decoder: any Decoder) throws { + do { + // Decode full schema + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.dependencies = try container.decode([Dependency].self, forKey: .dependencies) + + let minimumVersion = try container.decodeIfPresent(String.self, forKey: .minimumVersion) + self.minimumVersion = minimumVersion.flatMap(Version.init(_:)) + + self.outputDirectory = try container.decodeIfPresent(String.self, forKey: .outputDirectory) + self.cacheDirectory = try container.decodeIfPresent(String.self, forKey: .cacheDirectory) + + } catch { + // Try to decode array + var container = try decoder.unkeyedContainer() + var dependencies: [Dependency] = [] + while !container.isAtEnd { + try dependencies.append(container.decode(Dependency.self)) + } + self.dependencies = dependencies + } + } + + func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(self.minimumVersion?.description, forKey: .minimumVersion) + try container.encodeIfPresent(self.outputDirectory, forKey: .outputDirectory) + try container.encodeIfPresent(self.cacheDirectory, forKey: .cacheDirectory) + try container.encode(self.dependencies, forKey: .dependencies) + } +} diff --git a/Tests/BinaryDependencyManagerTests/BinaryDependenciesConfigurationTests.swift b/Tests/BinaryDependencyManagerTests/BinaryDependenciesConfigurationTests.swift new file mode 100644 index 0000000..ddc2b74 --- /dev/null +++ b/Tests/BinaryDependencyManagerTests/BinaryDependenciesConfigurationTests.swift @@ -0,0 +1,92 @@ +@testable import binary_dependencies_manager +import XCTest +import Testing +import Yams +import Foundation + +final class BinaryDependenciesConfigurationTests: XCTestCase { + + func testDecodingJSONShort() throws { + let jsonString = """ + [ + { + "repo": "A", + "tag": "0.0.1", + "pattern": "pattern1", + "checksum": "check1" + }, + { + "repo": "B", + "tag": "0.0.2", + "contents": "contents2", + "output": "output/directory2", + "checksum": "check2" + } + ] + """ + + let decoder = JSONDecoder() + let decoded = try decoder.decode(BinaryDependenciesConfiguration.self, from: Data(jsonString.utf8)) + + XCTAssertEqual( + decoded, + BinaryDependenciesConfiguration( + dependencies: [ + .init( + repo: "A", + tag: "0.0.1", + assets: [.init(checksum: "check1", pattern: "pattern1")] + ), + .init( + repo: "B", + tag: "0.0.2", + assets: [.init(checksum: "check2", contents: "contents2", outputDirectory: "output/directory2")] + ) + ] + ) + ) + } + + func testDecodingYAMLFull() throws { + let yamlString = """ + minimumVersion: 0.0.1 + outputDirectory: output/directory + cacheDirectory: cache/directory + dependencies: + - repo: A + tag: "0.0.1" + pattern: pattern1 + checksum: "check1" + - repo: B + tag: 0.0.2 + assets: + - contents: contents2 + output: output/directory2 + checksum: check2 + """ + + let decoder = YAMLDecoder() + let decoded = try decoder.decode(BinaryDependenciesConfiguration.self, from: Data(yamlString.utf8)) + + XCTAssertEqual( + decoded, + BinaryDependenciesConfiguration( + minimumVersion: "0.0.1", + outputDirectory: "output/directory", + cacheDirectory: "cache/directory", + dependencies: [ + .init( + repo: "A", + tag: "0.0.1", + assets: [.init(checksum: "check1", pattern: "pattern1")] + ), + .init( + repo: "B", + tag: "0.0.2", + assets: [.init(checksum: "check2", contents: "contents2", outputDirectory: "output/directory2")] + ) + ] + ) + ) + } +}