From 91174c7b7ea6c2a6cd2349b4255dcd37bbb64428 Mon Sep 17 00:00:00 2001 From: Vitalii Budnik Date: Mon, 23 Jun 2025 13:40:18 +0300 Subject: [PATCH 1/6] chore: refactor resolve command --- .../CommandLine/Commands/ResolveCommand.swift | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/Sources/CommandLine/Commands/ResolveCommand.swift b/Sources/CommandLine/Commands/ResolveCommand.swift index e00e947..485b98c 100644 --- a/Sources/CommandLine/Commands/ResolveCommand.swift +++ b/Sources/CommandLine/Commands/ResolveCommand.swift @@ -1,27 +1,48 @@ import ArgumentParser import BinaryDependencyManager +import Foundation +import Yams +import Utils struct ResolveCommand: ParsableCommand { + static var configuration = CommandConfiguration( + commandName: "resolve", + version: BinaryDependenciesManager.configuration.version + ) - static var configuration = CommandConfiguration(commandName: "resolve") + /// Path to the configuration file. + @Option(name: .shortAndLong, help: "Path to the configuration file") + var configurationFilePath: String? - // Path to dependencies json - @Option(name: .shortAndLong, help: "Path to dependencies json") - var dependenciesJSONPath: String + /// Path to the cache directory. + @Option(name: .long, help: "Path to the cache directory") + var cacheDirectoryPath: String? - // Path to cache directory - @Option(name: .shortAndLong, help: "Path to cache directory") - var cacheDirectoryPath: String + /// Path to the output directory. + @Option(name: .long, help: "Path to the output directory, where downloaded dependencies will be placed") + var outputDirectoryPath: String? - // Path to output directory - @Option(name: .shortAndLong, help: "Path to output directory, where downloaded dependencies will be placed") - var outputDirectoryPath: String + /// Dependencies to resolve. + var configuration: BinaryDependenciesConfiguration? + + /// Validates a given configuration file. + mutating func validate() throws { + let configurationReader: BinaryDependenciesConfigurationReader = .init() + configuration = try configurationReader + .readConfiguration(at: configurationFilePath, currentToolVersion: BinaryDependenciesManager.version) + outputDirectoryPath = configurationReader + .resolveOutputDirectoryURL(outputDirectoryPath ?? configuration?.outputDirectory) + .path + cacheDirectoryPath = configurationReader + .resolveCacheDirectoryURL(cacheDirectoryPath ?? configuration?.cacheDirectory) + .path + } func run() throws { let resolver = DependenciesResolverRunner( - dependenciesJSONPath: dependenciesJSONPath, - cacheDirectoryPath: cacheDirectoryPath, - outputDirectoryPath: outputDirectoryPath + dependencies: configuration!.dependencies, + cacheDirectoryPath: cacheDirectoryPath!, + outputDirectoryPath: outputDirectoryPath! ) try resolver.run() } From baabb268edbc983f275b38f41ff8a5e475055318 Mon Sep 17 00:00:00 2001 From: Vitalii Budnik Date: Tue, 24 Jun 2025 12:34:41 +0300 Subject: [PATCH 2/6] chore: update resolve command --- README.md | 48 +++++++++++++++---- .../CommandLine/Commands/ResolveCommand.swift | 29 ++++++++--- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 8240fe2..f3f5156 100644 --- a/README.md +++ b/README.md @@ -51,14 +51,14 @@ Run the tool by specifying the required paths: ```sh ./Binary/binary-dependencies-manager \ - --dependencies path/to/dependencies.json \ + --config path/to/.binary-dependencies.yaml \ --cache path/to/cache \ --output path/to/output ``` -- `--dependencies`: Path to your `dependencies.json` file (see format below) +- `--config`, `-c`: Path to your `.binary-dependencies.yaml` file (see format below) +- `--output`, `-o`: Directory where resolved dependencies will be extracted - `--cache`: Directory to use for caching downloads -- `--output`: Directory where resolved dependencies will be extracted ## Example `dependencies.json` ```json @@ -66,10 +66,12 @@ Run the tool by specifying the required paths: { "repo": "MyOrg/MyLibrary", "tag": "1.2.3", - "checksum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "contents": "XCFrameworks/MyLibrary.xcframework", - "pattern": "MyLibrary.xcframework.zip", - "output": "MyLibrary" + "assets": { + "checksum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "contents": "XCFrameworks/MyLibrary.xcframework", + "pattern": "MyLibrary.xcframework.zip", + "output": "MyLibrary" + } }, { "repo": "AnotherOrg/AnotherBinary", @@ -80,13 +82,43 @@ Run the tool by specifying the required paths: ] ``` +```yaml +--- +minimumVersion: 0.0.5 +outputDirectory: Dependencies +cacheDirectory: .cache/binary-dependencies/ +dependencies: + - repo: MyOrg/MyLibrary + tag: 1.2.3 + assets: + - contents: XCFrameworks/MyLibrary.xcframework + checksum: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + pattern: MyLibrary.xcframework.zip + output: MyLibrary + - repo: AnotherOrg/AnotherBinary + tag: 0.9.0 + checksum: d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2 + pattern: AnotherBinary.zip +``` +## Top level parameters +- `minimumVersion` (optional): Minimum required binary-dependencies-manager version. Optional. Defaults to the current version. +- `outputDirectory` (optional): Path to the output directory. Optional. Defaults to `Dependencies/Binary`. +- `cacheDirectory` (optional): Path to the cache directory. Optional. Defaults to the `.cache/binary-dependencies`. + + ## Dependency Parameters - `repo` (**required**): GitHub repository in the format `owner/repo` (e.g., `apple/swift-argument-parser`) - `tag` (**required**): Release tag to download (e.g., `1.0.0`) +- `assets` (optional): A list of multiple binary assets to download from a given repo release. + +> ℹ️ If no assets are provided you can specify asset parameters as a dependency parameters to download a single release artifact. + +## Asset Parameters - `checksum` (**required**): SHA256 checksum of the zip archive for integrity verification - `contents` (optional): If provided, only the contents of this directory inside the archive will be extracted to the output directory - `pattern` (optional): Pattern to select a specific artifact from the release (useful if multiple assets are present) -- `output` (optional): Subdirectory name to use for this dependency in the output directory (useful for organizing multiple artifacts) +- `output` (optional): Subdirectory name to use for this dependency asset in the output directory (useful for organizing multiple artifacts) + ## Example Scenarios - **Download a single artifact:** diff --git a/Sources/CommandLine/Commands/ResolveCommand.swift b/Sources/CommandLine/Commands/ResolveCommand.swift index 485b98c..2dbc3b6 100644 --- a/Sources/CommandLine/Commands/ResolveCommand.swift +++ b/Sources/CommandLine/Commands/ResolveCommand.swift @@ -11,17 +11,34 @@ struct ResolveCommand: ParsableCommand { ) /// Path to the configuration file. - @Option(name: .shortAndLong, help: "Path to the configuration file") + /// + /// Example: + /// ``` + /// $ binary-dependencies-manager resolve --config ./.binary-dependencies.yaml + /// $ binary-dependencies-manager resolve -c ./.binary-dependencies.yaml + /// ``` + @Option(name: [.customLong("config", withSingleDash: true), .short], help: "Path to the configuration file") var configurationFilePath: String? - /// Path to the cache directory. - @Option(name: .long, help: "Path to the cache directory") - var cacheDirectoryPath: String? - /// Path to the output directory. - @Option(name: .long, help: "Path to the output directory, where downloaded dependencies will be placed") + /// + /// Example: + /// ``` + /// $ binary-dependencies-manager resolve --output ./output + /// $ binary-dependencies-manager resolve -o ./output + /// ``` + @Option(name: [.customLong("output"), .short], help: "Path to the output directory, where downloaded dependencies will be placed") var outputDirectoryPath: String? + /// Path to the cache directory. + /// + /// Example: + /// ``` + /// $ binary-dependencies-manager resolve --cache ./cache + /// ``` + @Option(name: [.customLong("cache")], help: "Path to the cache directory") + var cacheDirectoryPath: String? + /// Dependencies to resolve. var configuration: BinaryDependenciesConfiguration? From f626636ecb164b13633b9d9a5a89bc6ddf225425 Mon Sep 17 00:00:00 2001 From: Vitalii Budnik Date: Tue, 24 Jun 2025 12:56:20 +0300 Subject: [PATCH 3/6] chore: add precondition --- Sources/CommandLine/Commands/ResolveCommand.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/CommandLine/Commands/ResolveCommand.swift b/Sources/CommandLine/Commands/ResolveCommand.swift index 2dbc3b6..7688eb7 100644 --- a/Sources/CommandLine/Commands/ResolveCommand.swift +++ b/Sources/CommandLine/Commands/ResolveCommand.swift @@ -56,8 +56,13 @@ struct ResolveCommand: ParsableCommand { } func run() throws { + guard let configuration = configuration else { + // Should never happen, because we validate the configuration in `validate()` method. + preconditionFailure("Configuration is not set. Please check your configuration file path.") + } + let resolver = DependenciesResolverRunner( - dependencies: configuration!.dependencies, + dependencies: configuration.dependencies, cacheDirectoryPath: cacheDirectoryPath!, outputDirectoryPath: outputDirectoryPath! ) From a022869a43753df14327448aaacfa9c809724338 Mon Sep 17 00:00:00 2001 From: Vitalii Budnik Date: Tue, 24 Jun 2025 12:58:19 +0300 Subject: [PATCH 4/6] chore: add easter egg --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f3f5156..c7bbb79 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Run the tool by specifying the required paths: { "repo": "AnotherOrg/AnotherBinary", "tag": "0.9.0", - "checksum": "d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2", + "checksum": "7ab14dda40c47f9c4d1829b4c214898e4c61a2d3055c773169b7291d0f48cd0c", "pattern": "AnotherBinary.zip" } ] @@ -97,7 +97,7 @@ dependencies: output: MyLibrary - repo: AnotherOrg/AnotherBinary tag: 0.9.0 - checksum: d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2 + checksum: 7ab14dda40c47f9c4d1829b4c214898e4c61a2d3055c773169b7291d0f48cd0c pattern: AnotherBinary.zip ``` ## Top level parameters From fe018d4895f2249848faec691c1e459237d1db2c Mon Sep 17 00:00:00 2001 From: Vitalii Budnik Date: Tue, 24 Jun 2025 13:37:29 +0300 Subject: [PATCH 5/6] chore: store dependenciesResolver --- .../DepeneciesResolverRunner.swift | 2 +- .../CommandLine/Commands/ResolveCommand.swift | 35 +++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Sources/BinaryDependencyManager/DepeneciesResolverRunner.swift b/Sources/BinaryDependencyManager/DepeneciesResolverRunner.swift index 8b95827..f4f6a0f 100644 --- a/Sources/BinaryDependencyManager/DepeneciesResolverRunner.swift +++ b/Sources/BinaryDependencyManager/DepeneciesResolverRunner.swift @@ -2,7 +2,7 @@ import Crypto import Foundation import Utils -public struct DependenciesResolverRunner { +public struct DependenciesResolverRunner: Codable { let dependenciesJSONPath: String let cacheDirectoryPath: String diff --git a/Sources/CommandLine/Commands/ResolveCommand.swift b/Sources/CommandLine/Commands/ResolveCommand.swift index 7688eb7..d7d431b 100644 --- a/Sources/CommandLine/Commands/ResolveCommand.swift +++ b/Sources/CommandLine/Commands/ResolveCommand.swift @@ -42,30 +42,37 @@ struct ResolveCommand: ParsableCommand { /// Dependencies to resolve. var configuration: BinaryDependenciesConfiguration? + /// Binary dependencies resolver. + var dependenciesResolver: DependenciesResolverRunner? + /// Validates a given configuration file. mutating func validate() throws { let configurationReader: BinaryDependenciesConfigurationReader = .init() - configuration = try configurationReader + + let configuration = try configurationReader .readConfiguration(at: configurationFilePath, currentToolVersion: BinaryDependenciesManager.version) - outputDirectoryPath = configurationReader - .resolveOutputDirectoryURL(outputDirectoryPath ?? configuration?.outputDirectory) + + // Paths from CLI arguments take precedence over those from the configuration file. + let outputDirectoryPath = configurationReader + .resolveOutputDirectoryURL(outputDirectoryPath ?? configuration.outputDirectory) .path - cacheDirectoryPath = configurationReader - .resolveCacheDirectoryURL(cacheDirectoryPath ?? configuration?.cacheDirectory) + let cacheDirectoryPath = configurationReader + .resolveCacheDirectoryURL(cacheDirectoryPath ?? configuration.cacheDirectory) .path + + dependenciesResolver = DependenciesResolverRunner( + dependencies: configuration.dependencies, + outputDirectoryPath: outputDirectoryPath, + cacheDirectoryPath: cacheDirectoryPath, + ) } func run() throws { - guard let configuration = configuration else { + guard let dependenciesResolver else { // Should never happen, because we validate the configuration in `validate()` method. - preconditionFailure("Configuration is not set. Please check your configuration file path.") + preconditionFailure("Dependencies resolver is not initialized") } - - let resolver = DependenciesResolverRunner( - dependencies: configuration.dependencies, - cacheDirectoryPath: cacheDirectoryPath!, - outputDirectoryPath: outputDirectoryPath! - ) - try resolver.run() + // Run the dependencies resolver. + try dependenciesResolver.run() } } From 3d5d165f96a1faf1af758ee0d77645f57d2f950a Mon Sep 17 00:00:00 2001 From: Vitalii Budnik Date: Tue, 24 Jun 2025 14:23:08 +0300 Subject: [PATCH 6/6] chore: fix unwrapping --- .../DepeneciesResolverRunner.swift | 2 +- .../CommandLine/Commands/ResolveCommand.swift | 33 ++++++++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Sources/BinaryDependencyManager/DepeneciesResolverRunner.swift b/Sources/BinaryDependencyManager/DepeneciesResolverRunner.swift index f4f6a0f..8b95827 100644 --- a/Sources/BinaryDependencyManager/DepeneciesResolverRunner.swift +++ b/Sources/BinaryDependencyManager/DepeneciesResolverRunner.swift @@ -2,7 +2,7 @@ import Crypto import Foundation import Utils -public struct DependenciesResolverRunner: Codable { +public struct DependenciesResolverRunner { let dependenciesJSONPath: String let cacheDirectoryPath: String diff --git a/Sources/CommandLine/Commands/ResolveCommand.swift b/Sources/CommandLine/Commands/ResolveCommand.swift index d7d431b..2823e47 100644 --- a/Sources/CommandLine/Commands/ResolveCommand.swift +++ b/Sources/CommandLine/Commands/ResolveCommand.swift @@ -42,9 +42,6 @@ struct ResolveCommand: ParsableCommand { /// Dependencies to resolve. var configuration: BinaryDependenciesConfiguration? - /// Binary dependencies resolver. - var dependenciesResolver: DependenciesResolverRunner? - /// Validates a given configuration file. mutating func validate() throws { let configurationReader: BinaryDependenciesConfigurationReader = .init() @@ -52,26 +49,38 @@ struct ResolveCommand: ParsableCommand { let configuration = try configurationReader .readConfiguration(at: configurationFilePath, currentToolVersion: BinaryDependenciesManager.version) + self.configuration = configuration + // Paths from CLI arguments take precedence over those from the configuration file. - let outputDirectoryPath = configurationReader + outputDirectoryPath = configurationReader .resolveOutputDirectoryURL(outputDirectoryPath ?? configuration.outputDirectory) .path - let cacheDirectoryPath = configurationReader + cacheDirectoryPath = configurationReader .resolveCacheDirectoryURL(cacheDirectoryPath ?? configuration.cacheDirectory) .path - dependenciesResolver = DependenciesResolverRunner( - dependencies: configuration.dependencies, - outputDirectoryPath: outputDirectoryPath, - cacheDirectoryPath: cacheDirectoryPath, - ) } func run() throws { - guard let dependenciesResolver else { + guard let configuration else { + // Should never happen, because we validate the configuration in `validate()` method. + preconditionFailure("Configuration is not initialized") + } + guard let outputDirectoryPath else { // Should never happen, because we validate the configuration in `validate()` method. - preconditionFailure("Dependencies resolver is not initialized") + preconditionFailure("Output directory path is not initialized") } + guard let cacheDirectoryPath else { + // Should never happen, because we validate the configuration in `validate()` method. + preconditionFailure("Cache directory path is not initialized") + } + + let dependenciesResolver = DependenciesResolverRunner( + dependencies: configuration.dependencies, + outputDirectoryPath: outputDirectoryPath, + cacheDirectoryPath: cacheDirectoryPath, + ) + // Run the dependencies resolver. try dependenciesResolver.run() }