Skip to content

Commit

Permalink
Add SwiftPackageListPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixHerrmann committed Feb 4, 2024
1 parent 67cbe05 commit 1af10e2
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ let package = Package(
],
products: [
.executable(name: "swift-package-list", targets: ["swift-package-list"]),
.plugin(name: "SwiftPackageListPlugin", targets: ["SwiftPackageListPlugin"]),
.plugin(name: "SwiftPackageListJSONPlugin", targets: ["SwiftPackageListJSONPlugin"]),
.plugin(name: "SwiftPackageListPropertyListPlugin", targets: ["SwiftPackageListPropertyListPlugin"]),
.plugin(name: "SwiftPackageListSettingsBundlePlugin", targets: ["SwiftPackageListSettingsBundlePlugin"]),
Expand All @@ -34,6 +35,11 @@ let package = Package(
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]
),
.plugin(
name: "SwiftPackageListPlugin",
capability: .buildTool(),
dependencies: [.target(name: "swift-package-list")]
),
.plugin(
name: "SwiftPackageListJSONPlugin",
capability: .buildTool(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// SwiftPackageListPlugin+BuildToolPlugin.swift
// SwiftPackageListPlugin
//
// Created by Felix Herrmann on 03.02.24.
//

import PackagePlugin

extension SwiftPackageListPlugin: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
let executable = try context.tool(named: "swift-package-list").path

let configurationPath = context.package.directory.appending(Configuration.fileName)
let configuration = try Configuration(path: configurationPath)
let targetConfiguration = configuration?.targets?[target.name] ?? configuration?.project

let relativeProjectPath = configuration?.projectPath ?? "Package.swift"
let projectPath = context.package.directory.appending(relativeProjectPath)

return try createBuildCommands(
executable: executable,
targetConfiguration: targetConfiguration,
projectPath: projectPath,
pluginWorkDirectory: context.pluginWorkDirectory
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// SwiftPackageListPlugin+XcodeBuildToolPlugin.swift
// SwiftPackageListPlugin
//
// Created by Felix Herrmann on 03.02.24.
//

#if canImport(XcodeProjectPlugin)
import PackagePlugin
import XcodeProjectPlugin

extension SwiftPackageListPlugin: XcodeBuildToolPlugin {
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
let executable = try context.tool(named: "swift-package-list").path

let configurationPath = context.xcodeProject.directory.appending(Configuration.fileName)
let configuration = try Configuration(path: configurationPath)
let targetConfiguration = configuration?.targets?[target.displayName] ?? configuration?.project

let relativeProjectPath = configuration?.projectPath ?? "\(context.xcodeProject.displayName).xcodeproj"
let projectPath = context.xcodeProject.directory.appending(relativeProjectPath)

return try createBuildCommands(
executable: executable,
targetConfiguration: targetConfiguration,
projectPath: projectPath,
pluginWorkDirectory: context.pluginWorkDirectory
)
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// SwiftPackageListPlugin.Configuration.swift
// SwiftPackageListPlugin
//
// Created by Felix Herrmann on 03.02.24.
//

import Foundation
import PackagePlugin

extension SwiftPackageListPlugin {
struct Configuration: Decodable {
let projectPath: String?
let project: TargetConfiguration?
let targets: [String: TargetConfiguration]?
}
}

extension SwiftPackageListPlugin.Configuration {
struct TargetConfiguration: Decodable {
let outputType: OutputType?
let requiresLicense: Bool?
}
}

extension SwiftPackageListPlugin.Configuration {
enum OutputType: String, Decodable {
case stdout
case json
case plist
case settingsBundle = "settings-bundle"
case pdf
}
}

extension SwiftPackageListPlugin.Configuration.OutputType {
var fileName: String? {
switch self {
case .stdout:
return nil
case .json:
return "package-list.json"
case .plist:
return "package-list.plist"
case .settingsBundle:
return "Settings.bundle"
case .pdf:
return "Acknowledgements.pdf"
}
}
}

extension SwiftPackageListPlugin.Configuration {
static let fileName = "swift-package-list-config.json"
}

extension SwiftPackageListPlugin.Configuration {
init?(path: Path) throws {
guard FileManager.default.fileExists(atPath: path.string) else { return nil }
let url = URL(filePath: path.string)

let data: Data
do {
data = try Data(contentsOf: url)
} catch {
throw SwiftPackageListPlugin.Error.configurationUnavailable(path: path, underlyingError: error)
}

let decoder = JSONDecoder()
do {
self = try decoder.decode(SwiftPackageListPlugin.Configuration.self, from: data)
} catch {
throw SwiftPackageListPlugin.Error.configurationInvalid(path: path, underlyingError: error)
}
}
}
29 changes: 29 additions & 0 deletions Plugins/SwiftPackageListPlugin/SwiftPackageListPlugin.Error.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// SwiftPackageListPlugin.Error.swift
// SwiftPackageListPlugin
//
// Created by Felix Herrmann on 03.02.24.
//

import PackagePlugin

extension SwiftPackageListPlugin {
enum Error: Swift.Error {
case configurationUnavailable(path: Path, underlyingError: Swift.Error)
case configurationInvalid(path: Path, underlyingError: Swift.Error)
case sourcePackagesNotFound(pluginWorkDirectory: Path)
}
}

extension SwiftPackageListPlugin.Error: CustomDebugStringConvertible {
var debugDescription: String {
switch self {
case .configurationUnavailable(path: let path, underlyingError: let error):
return "The configuration at \(path.string) is unavailable: \(error)"
case .configurationInvalid(path: let path, underlyingError: let error):
return "The configuration at \(path.string) has an invalid format: \(error)"
case .sourcePackagesNotFound(pluginWorkDirectory: let directory):
return "SourcePackages directory not found in \(directory.string)"
}
}
}
56 changes: 56 additions & 0 deletions Plugins/SwiftPackageListPlugin/SwiftPackageListPlugin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// SwiftPackageListPlugin.swift
// SwiftPackageListPlugin
//
// Created by Felix Herrmann on 03.02.24.
//

import PackagePlugin

@main
struct SwiftPackageListPlugin: Plugin {
func createBuildCommands(
executable: Path,
targetConfiguration: Configuration.TargetConfiguration?,
projectPath: Path,
pluginWorkDirectory: Path
) throws -> [Command] {
let sourcePackagesPath = try sourcePackagesDirectory(pluginWorkDirectory: pluginWorkDirectory)
let outputType = targetConfiguration?.outputType ?? .json
let outputPath = pluginWorkDirectory
let requiresLicense = targetConfiguration?.requiresLicense ?? true

let outputFiles: [Path]
if let fileName = outputType.fileName {
outputFiles = [outputPath.appending(fileName)]
} else {
outputFiles = []
}

return [
.buildCommand(
displayName: "SwiftPackageListPlugin",
executable: executable,
arguments: [
projectPath,
"--custom-source-packages-path", sourcePackagesPath,
"--output-type", outputType.rawValue,
"--output-path", outputPath,
requiresLicense ? "--requires-license" : "",
],
outputFiles: outputFiles
)
]
}

private func sourcePackagesDirectory(pluginWorkDirectory: Path) throws -> Path {
var path = pluginWorkDirectory
while path.lastComponent != "SourcePackages" {
guard path.string != "/" else {
throw SwiftPackageListPlugin.Error.sourcePackagesNotFound(pluginWorkDirectory: pluginWorkDirectory)
}
path = path.removingLastComponent()
}
return path
}
}

0 comments on commit 1af10e2

Please sign in to comment.