diff --git a/README.md b/README.md index 8240fe2..c7bbb79 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,27 +66,59 @@ 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", "tag": "0.9.0", - "checksum": "d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2", + "checksum": "7ab14dda40c47f9c4d1829b4c214898e4c61a2d3055c773169b7291d0f48cd0c", "pattern": "AnotherBinary.zip" } ] ``` +```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: 7ab14dda40c47f9c4d1829b4c214898e4c61a2d3055c773169b7291d0f48cd0c + 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 e00e947..2823e47 100644 --- a/Sources/CommandLine/Commands/ResolveCommand.swift +++ b/Sources/CommandLine/Commands/ResolveCommand.swift @@ -1,28 +1,87 @@ 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. + /// + /// 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 dependencies json - @Option(name: .shortAndLong, help: "Path to dependencies json") - var dependenciesJSONPath: String + /// Path to the output directory. + /// + /// 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 cache directory - @Option(name: .shortAndLong, help: "Path to cache directory") - var cacheDirectoryPath: 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? - // 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() + + 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. + outputDirectoryPath = configurationReader + .resolveOutputDirectoryURL(outputDirectoryPath ?? configuration.outputDirectory) + .path + cacheDirectoryPath = configurationReader + .resolveCacheDirectoryURL(cacheDirectoryPath ?? configuration.cacheDirectory) + .path + + } func run() throws { - let resolver = DependenciesResolverRunner( - dependenciesJSONPath: dependenciesJSONPath, + 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("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, - outputDirectoryPath: outputDirectoryPath ) - try resolver.run() + + // Run the dependencies resolver. + try dependenciesResolver.run() } }