From b6adbe2dfe07f9dd0c703d0a91d50bcf7eb21ed2 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sun, 21 May 2023 23:21:46 +0200 Subject: [PATCH 01/14] Add separate Scan command This required to also create a Generate subcommand for the existing functionality. --- .../SwiftPackageList+Generate.swift | 61 ++++++++++++++++ .../SwiftPackageList+Options.swift | 25 +++++++ .../SwiftPackageList+Scan.swift | 52 ++++++++++++++ .../SwiftPackageList.swift | 20 ++++++ .../SwiftPackageListCommand.swift | 71 ------------------- 5 files changed, 158 insertions(+), 71 deletions(-) create mode 100644 Sources/SwiftPackageListCommand/SwiftPackageList+Generate.swift create mode 100644 Sources/SwiftPackageListCommand/SwiftPackageList+Options.swift create mode 100644 Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift create mode 100644 Sources/SwiftPackageListCommand/SwiftPackageList.swift delete mode 100644 Sources/SwiftPackageListCommand/SwiftPackageListCommand.swift diff --git a/Sources/SwiftPackageListCommand/SwiftPackageList+Generate.swift b/Sources/SwiftPackageListCommand/SwiftPackageList+Generate.swift new file mode 100644 index 0000000..8889e36 --- /dev/null +++ b/Sources/SwiftPackageListCommand/SwiftPackageList+Generate.swift @@ -0,0 +1,61 @@ +// +// SwiftPackageList+Generate.swift +// SwiftPackageListCommand +// +// Created by Felix Herrmann on 21.05.23. +// + +import Foundation +import ArgumentParser +import SwiftPackageListCore + +extension SwiftPackageList { + struct Generate: ParsableCommand { + static var configuration: CommandConfiguration { + return CommandConfiguration(abstract: "Generate the specified output for all packages.") + } + + @OptionGroup var options: Options + + @Option(name: .shortAndLong, help: "The path where the package-list file will be stored.") + var outputPath = "\(NSHomeDirectory())/Desktop" + + // swiftlint:disable:next line_length + @Option(name: .shortAndLong, help: "The file type of the generated package-list file. Available options are json, plist, settings-bundle and pdf.") + var fileType: FileType = .json + + @Option(name: .shortAndLong, help: "A custom filename to be used instead of the default ones.") + var customFileName: String? + + mutating func run() throws { + guard let project = Project(path: options.projectPath) else { + throw ValidationError("The project file is not an Xcode Project or Workspace") + } + + guard FileManager.default.fileExists(atPath: project.packageResolvedFileURL.path) else { + throw CleanExit.message("This project has no Swift-Package dependencies") + } + + let checkoutsDirectory: URL + if let sourcePackagesPath = options.sourcePackagesPath { + checkoutsDirectory = URL(fileURLWithPath: sourcePackagesPath).appendingPathComponent("checkouts") + } else { + guard let buildDirectory = try project.buildDirectory(in: options.derivedDataPath) else { + throw RuntimeError("No build-directory found in your DerivedData-folder") + } + checkoutsDirectory = buildDirectory.appendingPathComponent("/SourcePackages/checkouts") + } + guard FileManager.default.fileExists(atPath: checkoutsDirectory.path) else { + throw RuntimeError("No checkouts-directory found in your SourcePackages-folder") + } + + let packageResolved = try PackageResolved(at: project.packageResolvedFileURL) + let packages = try packageResolved.packages(in: checkoutsDirectory, requiresLicense: options.requiresLicense) + + let outputURL = fileType.outputURL(at: outputPath, customFileName: customFileName) + let outputGenerator = fileType.outputGenerator(outputURL: outputURL, packages: packages, project: project) + try outputGenerator.generateOutput() + throw CleanExit.message("Generated \(outputURL.path)") + } + } +} diff --git a/Sources/SwiftPackageListCommand/SwiftPackageList+Options.swift b/Sources/SwiftPackageListCommand/SwiftPackageList+Options.swift new file mode 100644 index 0000000..b9cd49d --- /dev/null +++ b/Sources/SwiftPackageListCommand/SwiftPackageList+Options.swift @@ -0,0 +1,25 @@ +// +// SwiftPackageList+Options.swift +// SwiftPackageListCommand +// +// Created by Felix Herrmann on 21.05.23. +// + +import Foundation +import ArgumentParser + +extension SwiftPackageList { + struct Options: ParsableArguments { + @Argument(help: "The path to your .xcodeproj or .xcworkspace file.") + var projectPath: String + + @Option(name: .shortAndLong, help: "The path to your DerivedData-folder.") + var derivedDataPath = "\(NSHomeDirectory())/Library/Developer/Xcode/DerivedData" + + @Option(name: .shortAndLong, help: "The path to a custom SourcePackages-folder.") + var sourcePackagesPath: String? + + @Flag(help: "Will skip the packages without a license-file.") + var requiresLicense = false + } +} diff --git a/Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift b/Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift new file mode 100644 index 0000000..854b835 --- /dev/null +++ b/Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift @@ -0,0 +1,52 @@ +// +// SwiftPackageList+Scan.swift +// SwiftPackageListCommand +// +// Created by Felix Herrmann on 21.05.23. +// + +import Foundation +import ArgumentParser +import SwiftPackageListCore + +extension SwiftPackageList { + struct Scan: ParsableCommand { + static var configuration: CommandConfiguration { + return CommandConfiguration(abstract: "Print all packages to the console.") + } + + @OptionGroup var options: Options + + mutating func run() throws { + guard let project = Project(path: options.projectPath) else { + throw ValidationError("The project file is not an Xcode Project or Workspace") + } + + guard FileManager.default.fileExists(atPath: project.packageResolvedFileURL.path) else { + throw CleanExit.message("This project has no Swift-Package dependencies") + } + + let checkoutsDirectory: URL + if let sourcePackagesPath = options.sourcePackagesPath { + checkoutsDirectory = URL(fileURLWithPath: sourcePackagesPath).appendingPathComponent("checkouts") + } else { + guard let buildDirectory = try project.buildDirectory(in: options.derivedDataPath) else { + throw RuntimeError("No build-directory found in your DerivedData-folder") + } + checkoutsDirectory = buildDirectory.appendingPathComponent("/SourcePackages/checkouts") + } + guard FileManager.default.fileExists(atPath: checkoutsDirectory.path) else { + throw RuntimeError("No checkouts-directory found in your SourcePackages-folder") + } + + let packageResolved = try PackageResolved(at: project.packageResolvedFileURL) + let packages = try packageResolved.packages(in: checkoutsDirectory, requiresLicense: options.requiresLicense) + + let jsonEncoder = JSONEncoder() + jsonEncoder.outputFormatting = .prettyPrinted + let jsonData = try jsonEncoder.encode(packages) + let jsonString = String(decoding: jsonData, as: UTF8.self) + print(jsonString) + } + } +} diff --git a/Sources/SwiftPackageListCommand/SwiftPackageList.swift b/Sources/SwiftPackageListCommand/SwiftPackageList.swift new file mode 100644 index 0000000..67e5070 --- /dev/null +++ b/Sources/SwiftPackageListCommand/SwiftPackageList.swift @@ -0,0 +1,20 @@ +// +// SwiftPackageList.swift +// SwiftPackageListCommand +// +// Created by Felix Herrmann on 01.11.21. +// + +import Foundation +import ArgumentParser + +@main +struct SwiftPackageList: ParsableCommand { + static var configuration: CommandConfiguration { + return CommandConfiguration( + discussion: "A command-line tool to get all used SPM-dependencies of an Xcode project or workspace.", + version: "2.2.0", + subcommands: [Scan.self, Generate.self] + ) + } +} diff --git a/Sources/SwiftPackageListCommand/SwiftPackageListCommand.swift b/Sources/SwiftPackageListCommand/SwiftPackageListCommand.swift deleted file mode 100644 index 223658d..0000000 --- a/Sources/SwiftPackageListCommand/SwiftPackageListCommand.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// SwiftPackageListCommand.swift -// SwiftPackageListCommand -// -// Created by Felix Herrmann on 01.11.21. -// - -import Foundation -import ArgumentParser -import SwiftPackageListCore - -@main -struct SwiftPackageListCommand: ParsableCommand { - - static var configuration: CommandConfiguration { - return CommandConfiguration(version: "2.2.0") - } - - @Argument(help: "The path to your .xcodeproj or .xcworkspace file.") - var projectPath: String - - @Option(name: .shortAndLong, help: "The path to your DerivedData-folder.") - var derivedDataPath = "\(NSHomeDirectory())/Library/Developer/Xcode/DerivedData" - - @Option(name: .shortAndLong, help: "The path to a custom SourcePackages-folder.") - var sourcePackagesPath: String? - - @Option(name: .shortAndLong, help: "The path where the package-list file will be stored.") - var outputPath = "\(NSHomeDirectory())/Desktop" - - // swiftlint:disable:next line_length - @Option(name: .shortAndLong, help: "The file type of the generated package-list file. Available options are json, plist, settings-bundle and pdf.") - var fileType: FileType = .json - - @Option(name: .shortAndLong, help: "A custom filename to be used instead of the default ones.") - var customFileName: String? - - @Flag(help: "Will skip the packages without a license-file.") - var requiresLicense = false - - mutating func run() throws { - guard let project = Project(path: projectPath) else { - throw ValidationError("The project file is not an Xcode Project or Workspace") - } - - guard FileManager.default.fileExists(atPath: project.packageResolvedFileURL.path) else { - throw CleanExit.message("This project has no Swift-Package dependencies") - } - - let checkoutsDirectory: URL - if let sourcePackagesPath { - checkoutsDirectory = URL(fileURLWithPath: sourcePackagesPath).appendingPathComponent("checkouts") - } else { - guard let buildDirectory = try project.buildDirectory(in: derivedDataPath) else { - throw RuntimeError("No build-directory found in your DerivedData-folder") - } - checkoutsDirectory = buildDirectory.appendingPathComponent("/SourcePackages/checkouts") - } - guard FileManager.default.fileExists(atPath: checkoutsDirectory.path) else { - throw RuntimeError("No checkouts-directory found in your SourcePackages-folder") - } - - let packageResolved = try PackageResolved(at: project.packageResolvedFileURL) - let packages = try packageResolved.packages(in: checkoutsDirectory, requiresLicense: requiresLicense) - - let outputURL = fileType.outputURL(at: outputPath, customFileName: customFileName) - let outputGenerator = fileType.outputGenerator(outputURL: outputURL, packages: packages, project: project) - try outputGenerator.generateOutput() - throw CleanExit.message("Generated \(outputURL.path)") - } -} From c7e69c785418873c1856f406952da76c76c1d85e Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sun, 21 May 2023 23:23:42 +0200 Subject: [PATCH 02/14] Add tests for new subcommands --- .../SwiftPackageListCommandTests.swift | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Tests/SwiftPackageListCommandTests/SwiftPackageListCommandTests.swift b/Tests/SwiftPackageListCommandTests/SwiftPackageListCommandTests.swift index 54ca629..1f7c29d 100644 --- a/Tests/SwiftPackageListCommandTests/SwiftPackageListCommandTests.swift +++ b/Tests/SwiftPackageListCommandTests/SwiftPackageListCommandTests.swift @@ -40,4 +40,42 @@ final class SwiftPackageListCommandTests: XCTestCase { XCTAssertNotNil(Int(minorVersionNumber)) XCTAssertNotNil(Int(patchVersionNumber)) } + + func testScanSubcommandExecution() throws { + let swiftPackageListBinary = productsDirectory.appendingPathComponent("swift-package-list") + + let process = Process() + process.executableURL = swiftPackageListBinary + process.arguments = ["scan", "--help"] + + let pipe = Pipe() + process.standardOutput = pipe + + try process.run() + process.waitUntilExit() + + let data = pipe.fileHandleForReading.readDataToEndOfFile() + let output = String(decoding: data, as: UTF8.self).trimmingCharacters(in: .whitespacesAndNewlines) + + XCTAssertTrue(output.contains("USAGE: swift-package-list scan")) + } + + func testGenerateSubcommandExecution() throws { + let swiftPackageListBinary = productsDirectory.appendingPathComponent("swift-package-list") + + let process = Process() + process.executableURL = swiftPackageListBinary + process.arguments = ["generate", "--help"] + + let pipe = Pipe() + process.standardOutput = pipe + + try process.run() + process.waitUntilExit() + + let data = pipe.fileHandleForReading.readDataToEndOfFile() + let output = String(decoding: data, as: UTF8.self).trimmingCharacters(in: .whitespacesAndNewlines) + + XCTAssertTrue(output.contains("USAGE: swift-package-list generate")) + } } From 461c7c98df911cbe3437a73cb7b4e615560652ee Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sun, 21 May 2023 23:45:19 +0200 Subject: [PATCH 03/14] Improve command description --- Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift b/Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift index 854b835..94bb601 100644 --- a/Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift +++ b/Sources/SwiftPackageListCommand/SwiftPackageList+Scan.swift @@ -12,7 +12,7 @@ import SwiftPackageListCore extension SwiftPackageList { struct Scan: ParsableCommand { static var configuration: CommandConfiguration { - return CommandConfiguration(abstract: "Print all packages to the console.") + return CommandConfiguration(abstract: "Print all packages as JSON to the console.") } @OptionGroup var options: Options From ec93e9e6637b71c7f40d1919c97986c06c83f7d4 Mon Sep 17 00:00:00 2001 From: Felix Herrmann <42500484+FelixHerrmann@users.noreply.github.com> Date: Sun, 21 May 2023 23:47:39 +0200 Subject: [PATCH 04/14] Update README.md to reflect scan/generate subcommand changes --- README.md | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6265989..a326684 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,11 @@ [![Xcode Build](https://github.com/FelixHerrmann/swift-package-list/actions/workflows/xcodebuild.yml/badge.svg)](https://github.com/FelixHerrmann/swift-package-list/actions/workflows/xcodebuild.yml) [![SwiftLint](https://github.com/FelixHerrmann/swift-package-list/actions/workflows/swiftlint.yml/badge.svg)](https://github.com/FelixHerrmann/swift-package-list/actions/workflows/swiftlint.yml) -A command-line tool to generate a JSON, PLIST, Settings.bundle or PDF file with all used SPM-dependencies of an Xcode project or workspace. +A command-line tool to get all used SPM-dependencies of an Xcode project or workspace. + +The output includes all the `Package.resolved` informations and the license from the checkouts. +You can also generate a JSON, PLIST, Settings.bundle or PDF file. -This includes all the `Package.resolved` informations and the license from the checkouts. Additionally there is a Swift Package to read the generated package-list file from the application's bundle with a top-level function or pre-build UI. @@ -32,20 +34,36 @@ Clone or download this repository and run `make install`, `make update` or `make ### Usage -Open the terminal and run `swift-package-list ` with the path to the `.xcodeproj` or `.xcworkspace` file you want to generate the list from. +#### Scan command + +Open the terminal and run `swift-package-list scan ` with the path to the `.xcodeproj` or `.xcworkspace` file you want to get the JSON output from. + +In addition to that you can specify the following options: + +| Option | Description | +| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| -d, --derived-data-path \ | The path to your DerivedData-folder. (default: ~/Library/Developer/Xcode/DerivedData) | +| -s, --source-packages-path \ | The path to a custom SourcePackages-folder. | +| --requires-license | Will skip the packages without a license-file. | +| --version | Show the version. | +| -h, --help | Show help information. | + +#### Generate command + +Open the terminal and run `swift-package-list generate ` with the path to the `.xcodeproj` or `.xcworkspace` file you want to generate the list from. In addition to that you can specify the following options: -| Option | Description | -| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -| -d, --derived-data-path \ | The path to your DerivedData-folder. (default: ~/Library/Developer/Xcode/DerivedData) | -| -s, --source-packages-path | The path to a custom SourcePackages-folder. | -| -o, --output-path \ | The path where the package-list file will be stored. (default: ~/Desktop) | -| -f, --file-type \ | The file type of the generated package-list file. Available options are json, plist, settings-bundle and pdf. (default: json) | -| -c, --custom-file-name | A custom filename to be used instead of the default ones. | -| --requires-license | Will skip the packages without a license-file. | -| --version | Show the version. | -| -h, --help | Show help information. | +| Option | Description | +| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| -d, --derived-data-path \ | The path to your DerivedData-folder. (default: ~/Library/Developer/Xcode/DerivedData) | +| -s, --source-packages-path \ | The path to a custom SourcePackages-folder. | +| -o, --output-path \ | The path where the package-list file will be stored. (default: ~/Desktop) | +| -f, --file-type \ | The file type of the generated package-list file. Available options are json, plist, settings-bundle and pdf. (default: json) | +| -c, --custom-file-name \ | A custom filename to be used instead of the default ones. | +| --requires-license | Will skip the packages without a license-file. | +| --version | Show the version. | +| -h, --help | Show help information. | ### Run Script Phase @@ -56,7 +74,7 @@ You can easily set up a Run Script Phase in your target of your Xcode project to ```shell if command -v swift-package-list &> /dev/null; then OUTPUT_PATH=$SOURCE_ROOT/$TARGETNAME - swift-package-list "$PROJECT_FILE_PATH" --output-path "$OUTPUT_PATH" --requires-license + swift-package-list generate "$PROJECT_FILE_PATH" --output-path "$OUTPUT_PATH" --requires-license else echo "warning: swift-package-list not installed" fi @@ -78,7 +96,7 @@ you just need a slightly modified script for the Run Script Phase: if command -v swift-package-list &> /dev/null; then OUTPUT_PATH=$SOURCE_ROOT/$TARGETNAME WORKSPACE_FILE_PATH=${PROJECT_FILE_PATH%.xcodeproj}.xcworkspace - swift-package-list "$WORKSPACE_FILE_PATH" --output-path "$OUTPUT_PATH" --requires-license + swift-package-list generate "$WORKSPACE_FILE_PATH" --output-path "$OUTPUT_PATH" --requires-license else echo "warning: swift-package-list not installed" fi From 9e7d35e437eaa46538b875a6d5aab04998023c2f Mon Sep 17 00:00:00 2001 From: Felix Herrmann <42500484+FelixHerrmann@users.noreply.github.com> Date: Sun, 21 May 2023 23:48:50 +0200 Subject: [PATCH 05/14] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a326684..2f5dd41 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Clone or download this repository and run `make install`, `make update` or `make ### Usage -#### Scan command +#### Scan Command Open the terminal and run `swift-package-list scan ` with the path to the `.xcodeproj` or `.xcworkspace` file you want to get the JSON output from. @@ -48,7 +48,7 @@ In addition to that you can specify the following options: | --version | Show the version. | | -h, --help | Show help information. | -#### Generate command +#### Generate Command Open the terminal and run `swift-package-list generate ` with the path to the `.xcodeproj` or `.xcworkspace` file you want to generate the list from. From 28ddaec45c8b07c34b1c45517629fe155f458c29 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Mon, 22 May 2023 00:24:22 +0200 Subject: [PATCH 06/14] Bump version --- Sources/SwiftPackageListCommand/SwiftPackageList.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftPackageListCommand/SwiftPackageList.swift b/Sources/SwiftPackageListCommand/SwiftPackageList.swift index 67e5070..b0b0daf 100644 --- a/Sources/SwiftPackageListCommand/SwiftPackageList.swift +++ b/Sources/SwiftPackageListCommand/SwiftPackageList.swift @@ -13,7 +13,7 @@ struct SwiftPackageList: ParsableCommand { static var configuration: CommandConfiguration { return CommandConfiguration( discussion: "A command-line tool to get all used SPM-dependencies of an Xcode project or workspace.", - version: "2.2.0", + version: "3.0.0", subcommands: [Scan.self, Generate.self] ) } From 0094f667de3938e2bb51f2642c0d1059985b1a52 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sat, 27 May 2023 23:11:19 +0200 Subject: [PATCH 07/14] Add SwiftPackageListPlugin --- .../SwiftPackageList-Package.xcscheme | 14 ++++++++ Package.swift | 6 ++++ .../SwiftPackageListPlugin.swift | 36 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 Plugins/SwiftPackageListPlugin/SwiftPackageListPlugin.swift diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme index 88504be..dfca5ab 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme @@ -146,6 +146,20 @@ ReferencedContainer = "container:"> + + + + [Command] { + return [] + } +} + +#if canImport(XcodeProjectPlugin) +import XcodeProjectPlugin + +extension SwiftPackageListPlugin: XcodeBuildToolPlugin { + func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { + let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") + let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") + let outputPath = context.pluginWorkDirectory + return [ + .buildCommand( + displayName: "SwiftPackageListPlugin", + executable: executable, + arguments: ["generate", projectPath, "--output-path", outputPath, "--requires-license"], + outputFiles: [outputPath.appending("package-list.json")] + ) + ] + } +} +#endif From f17bf3287bc2088a38140515543387fb64d6cfbf Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sat, 27 May 2023 23:37:42 +0200 Subject: [PATCH 08/14] Rename SwiftPackageListPlugin to SwiftPackageListJSONPlugin --- .../xcschemes/SwiftPackageList-Package.xcscheme | 6 +++--- Package.swift | 4 ++-- .../SwiftPackageListJSONPlugin.swift} | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) rename Plugins/{SwiftPackageListPlugin/SwiftPackageListPlugin.swift => SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift} (82%) diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme index dfca5ab..e098818 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme @@ -154,9 +154,9 @@ buildForAnalyzing = "YES"> diff --git a/Package.swift b/Package.swift index a2befdf..f4af156 100644 --- a/Package.swift +++ b/Package.swift @@ -15,7 +15,7 @@ let package = Package( ], products: [ .executable(name: "swift-package-list", targets: ["SwiftPackageListCommand"]), - .plugin(name: "SwiftPackageListPlugin", targets: ["SwiftPackageListPlugin"]), + .plugin(name: "SwiftPackageListJSONPlugin", targets: ["SwiftPackageListJSONPlugin"]), .library(name: "SwiftPackageList", targets: ["SwiftPackageList"]), .library(name: "SwiftPackageListObjc", type: .dynamic, targets: ["SwiftPackageListObjc"]), .library(name: "SwiftPackageListUI", targets: ["SwiftPackageListUI"]), @@ -32,7 +32,7 @@ let package = Package( ] ), .plugin( - name: "SwiftPackageListPlugin", + name: "SwiftPackageListJSONPlugin", capability: .buildTool(), dependencies: [.target(name: "SwiftPackageListCommand")] ), diff --git a/Plugins/SwiftPackageListPlugin/SwiftPackageListPlugin.swift b/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift similarity index 82% rename from Plugins/SwiftPackageListPlugin/SwiftPackageListPlugin.swift rename to Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift index 36e37b9..147aeb8 100644 --- a/Plugins/SwiftPackageListPlugin/SwiftPackageListPlugin.swift +++ b/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift @@ -1,5 +1,5 @@ // -// SwiftPackageListPlugin.swift +// SwiftPackageListJSONPlugin.swift // SwiftPackageListPlugin // // Created by Felix Herrmann on 22.05.23. @@ -9,7 +9,7 @@ import Foundation import PackagePlugin @main -struct SwiftPackageListPlugin: BuildToolPlugin { +struct SwiftPackageListJSONPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { return [] } @@ -18,7 +18,7 @@ struct SwiftPackageListPlugin: BuildToolPlugin { #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin -extension SwiftPackageListPlugin: XcodeBuildToolPlugin { +extension SwiftPackageListJSONPlugin: XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") @@ -27,7 +27,7 @@ extension SwiftPackageListPlugin: XcodeBuildToolPlugin { .buildCommand( displayName: "SwiftPackageListPlugin", executable: executable, - arguments: ["generate", projectPath, "--output-path", outputPath, "--requires-license"], + arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", "json", "--requires-license"], outputFiles: [outputPath.appending("package-list.json")] ) ] From 93f67fe8ecfabfddeec7dbe9cc64ee3f071f725d Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sat, 27 May 2023 23:47:15 +0200 Subject: [PATCH 09/14] Fix target name --- .../SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift b/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift index 147aeb8..42e9da7 100644 --- a/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift +++ b/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift @@ -1,6 +1,6 @@ // // SwiftPackageListJSONPlugin.swift -// SwiftPackageListPlugin +// SwiftPackageListJSONPlugin // // Created by Felix Herrmann on 22.05.23. // From 35d24c10fb3a6b58e9ee77744838a40e5ed55f96 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sat, 27 May 2023 23:47:31 +0200 Subject: [PATCH 10/14] Add SwiftPackageListPropertyListPlugin --- .../SwiftPackageList-Package.xcscheme | 14 ++++++++ Package.swift | 6 ++++ .../SwiftPackageListPropertyListPlugin.swift | 36 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 Plugins/SwiftPackageListPropertyListPlugin/SwiftPackageListPropertyListPlugin.swift diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme index e098818..8dbf750 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme @@ -160,6 +160,20 @@ ReferencedContainer = "container:"> + + + + [Command] { + return [] + } +} + +#if canImport(XcodeProjectPlugin) +import XcodeProjectPlugin + +extension SwiftPackageListPropertyListPlugin: XcodeBuildToolPlugin { + func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { + let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") + let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") + let outputPath = context.pluginWorkDirectory + return [ + .buildCommand( + displayName: "SwiftPackageListPlugin", + executable: executable, + arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", "plist", "--requires-license"], + outputFiles: [outputPath.appending("package-list.plist")] + ) + ] + } +} +#endif From 24228299ce4b9d6012c21c225460212f4d5c3cb0 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sat, 27 May 2023 23:51:38 +0200 Subject: [PATCH 11/14] Add SwiftPackageListSettingsBundlePlugin --- .../SwiftPackageList-Package.xcscheme | 14 ++++++++ Package.swift | 6 ++++ ...SwiftPackageListSettingsBundlePlugin.swift | 36 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 Plugins/SwiftPackageListSettingsBundlePlugin/SwiftPackageListSettingsBundlePlugin.swift diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme index 8dbf750..b07803b 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme @@ -174,6 +174,20 @@ ReferencedContainer = "container:"> + + + + [Command] { + return [] + } +} + +#if canImport(XcodeProjectPlugin) +import XcodeProjectPlugin + +extension SwiftPackageListSettingsBundlePlugin: XcodeBuildToolPlugin { + func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { + let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") + let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") + let outputPath = context.pluginWorkDirectory + return [ + .buildCommand( + displayName: "SwiftPackageListPlugin", + executable: executable, + arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", "settings-bundle", "--requires-license"], + outputFiles: [outputPath.appending("Settings.bundle")] + ) + ] + } +} +#endif From e1543024736b9046ae67e5335309a5b0c901a09d Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sat, 27 May 2023 23:57:51 +0200 Subject: [PATCH 12/14] Add SwiftPackageListPDFPlugin --- .../SwiftPackageList-Package.xcscheme | 14 ++++++++ Package.swift | 6 ++++ .../SwiftPackageListPDFPlugin.swift | 36 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 Plugins/SwiftPackageListPDFPlugin/SwiftPackageListPDFPlugin.swift diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme index b07803b..c12c6b3 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/SwiftPackageList-Package.xcscheme @@ -188,6 +188,20 @@ ReferencedContainer = "container:"> + + + + [Command] { + return [] + } +} + +#if canImport(XcodeProjectPlugin) +import XcodeProjectPlugin + +extension SwiftPackageListPDFPlugin: XcodeBuildToolPlugin { + func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { + let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") + let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") + let outputPath = context.pluginWorkDirectory + return [ + .buildCommand( + displayName: "SwiftPackageListPlugin", + executable: executable, + arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", "pdf", "--requires-license"], + outputFiles: [outputPath.appending("Acknowledgements.pdf")] + ) + ] + } +} +#endif From 20c6150b97cd15571b60ea742208316df8e7a95f Mon Sep 17 00:00:00 2001 From: Felix Herrmann <42500484+FelixHerrmann@users.noreply.github.com> Date: Sun, 28 May 2023 00:16:00 +0200 Subject: [PATCH 13/14] Add Build Tool Plugins section --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 2f5dd41..bc0bd06 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,15 @@ In addition to that you can specify the following options: | --version | Show the version. | | -h, --help | Show help information. | +### Build Tool Plugins + +For each file type there is a dedicated plugin available which you can add to your targets. + +Simply add them under the `Run Build Tool Plug-ins` section in the Target's Build Phases tab after you have added this package to the project's Package Dependencies. + +Once added the file(s) will get generated during every build process and are available in the App's bundle. +You can then open them manually or use the various options in the included [Swift Package](#swift-package). + ### Run Script Phase You can easily set up a Run Script Phase in your target of your Xcode project to keep the package-list file up to date automatically: From 0ba13f01a2672bd63d58aac1341064d2dc3f984b Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Sun, 28 May 2023 00:36:29 +0200 Subject: [PATCH 14/14] Fix linting --- .../SwiftPackageListJSONPlugin.swift | 7 +++++-- .../SwiftPackageListPDFPlugin.swift | 7 +++++-- .../SwiftPackageListPropertyListPlugin.swift | 7 +++++-- .../SwiftPackageListSettingsBundlePlugin.swift | 7 +++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift b/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift index 42e9da7..4c5f7fa 100644 --- a/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift +++ b/Plugins/SwiftPackageListJSONPlugin/SwiftPackageListJSONPlugin.swift @@ -21,13 +21,16 @@ import XcodeProjectPlugin extension SwiftPackageListJSONPlugin: XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") - let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") + let executable = try context.tool(named: "SwiftPackageListCommand").path + .removingLastComponent() + .appending("swift-package-list") let outputPath = context.pluginWorkDirectory + let fileType = "json" return [ .buildCommand( displayName: "SwiftPackageListPlugin", executable: executable, - arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", "json", "--requires-license"], + arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", fileType, "--requires-license"], outputFiles: [outputPath.appending("package-list.json")] ) ] diff --git a/Plugins/SwiftPackageListPDFPlugin/SwiftPackageListPDFPlugin.swift b/Plugins/SwiftPackageListPDFPlugin/SwiftPackageListPDFPlugin.swift index a4a2dbd..0e9509d 100644 --- a/Plugins/SwiftPackageListPDFPlugin/SwiftPackageListPDFPlugin.swift +++ b/Plugins/SwiftPackageListPDFPlugin/SwiftPackageListPDFPlugin.swift @@ -21,13 +21,16 @@ import XcodeProjectPlugin extension SwiftPackageListPDFPlugin: XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") - let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") + let executable = try context.tool(named: "SwiftPackageListCommand").path + .removingLastComponent() + .appending("swift-package-list") let outputPath = context.pluginWorkDirectory + let fileType = "pdf" return [ .buildCommand( displayName: "SwiftPackageListPlugin", executable: executable, - arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", "pdf", "--requires-license"], + arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", fileType, "--requires-license"], outputFiles: [outputPath.appending("Acknowledgements.pdf")] ) ] diff --git a/Plugins/SwiftPackageListPropertyListPlugin/SwiftPackageListPropertyListPlugin.swift b/Plugins/SwiftPackageListPropertyListPlugin/SwiftPackageListPropertyListPlugin.swift index 06095d8..ca84457 100644 --- a/Plugins/SwiftPackageListPropertyListPlugin/SwiftPackageListPropertyListPlugin.swift +++ b/Plugins/SwiftPackageListPropertyListPlugin/SwiftPackageListPropertyListPlugin.swift @@ -21,13 +21,16 @@ import XcodeProjectPlugin extension SwiftPackageListPropertyListPlugin: XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") - let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") + let executable = try context.tool(named: "SwiftPackageListCommand").path + .removingLastComponent() + .appending("swift-package-list") let outputPath = context.pluginWorkDirectory + let fileType = "plist" return [ .buildCommand( displayName: "SwiftPackageListPlugin", executable: executable, - arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", "plist", "--requires-license"], + arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", fileType, "--requires-license"], outputFiles: [outputPath.appending("package-list.plist")] ) ] diff --git a/Plugins/SwiftPackageListSettingsBundlePlugin/SwiftPackageListSettingsBundlePlugin.swift b/Plugins/SwiftPackageListSettingsBundlePlugin/SwiftPackageListSettingsBundlePlugin.swift index ca8584a..bd37029 100644 --- a/Plugins/SwiftPackageListSettingsBundlePlugin/SwiftPackageListSettingsBundlePlugin.swift +++ b/Plugins/SwiftPackageListSettingsBundlePlugin/SwiftPackageListSettingsBundlePlugin.swift @@ -21,13 +21,16 @@ import XcodeProjectPlugin extension SwiftPackageListSettingsBundlePlugin: XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { let projectPath = context.xcodeProject.directory.appending("\(context.xcodeProject.displayName).xcodeproj") - let executable = try context.tool(named: "SwiftPackageListCommand").path.removingLastComponent().appending("swift-package-list") + let executable = try context.tool(named: "SwiftPackageListCommand").path + .removingLastComponent() + .appending("swift-package-list") let outputPath = context.pluginWorkDirectory + let fileType = "settings-bundle" return [ .buildCommand( displayName: "SwiftPackageListPlugin", executable: executable, - arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", "settings-bundle", "--requires-license"], + arguments: ["generate", projectPath, "--output-path", outputPath, "--file-type", fileType, "--requires-license"], outputFiles: [outputPath.appending("Settings.bundle")] ) ]