From c2d26b62c7bfc6bb3590bc5e4ff16115fe483468 Mon Sep 17 00:00:00 2001 From: Joe Heck Date: Mon, 16 Jun 2025 14:54:52 -0700 Subject: [PATCH 1/3] adds documentation catalog for PackagePlugin --- .../Documentation.docc/Documentation.md | 13 ++++++++++ .../Documentation.docc/Info.plist | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 Sources/PackagePlugin/Documentation.docc/Documentation.md create mode 100644 Sources/PackagePlugin/Documentation.docc/Info.plist diff --git a/Sources/PackagePlugin/Documentation.docc/Documentation.md b/Sources/PackagePlugin/Documentation.docc/Documentation.md new file mode 100644 index 00000000000..2621b6c476f --- /dev/null +++ b/Sources/PackagePlugin/Documentation.docc/Documentation.md @@ -0,0 +1,13 @@ +# ``PackagePlugin`` + +Summary + +## Overview + +Text + +## Topics + +### Group + +- ``Symbol`` diff --git a/Sources/PackagePlugin/Documentation.docc/Info.plist b/Sources/PackagePlugin/Documentation.docc/Info.plist new file mode 100644 index 00000000000..1d479ae109f --- /dev/null +++ b/Sources/PackagePlugin/Documentation.docc/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleName + PackagePlugin + CFBundleDisplayName + PackagePlugin + CFBundleIdentifier + org.swift.swiftpm.packageplugin + CFBundleDevelopmentRegion + en + CFBundleIconFile + DocumentationIcon + CFBundleIconName + DocumentationIcon + CFBundlePackageType + DOCS + CFBundleShortVersionString + 0.1.0 + CDDefaultCodeListingLanguage + swift + CFBundleVersion + 0.1.0 + + From 170e8f760c205ddb4548d13091b5dfbef870c9bd Mon Sep 17 00:00:00 2001 From: Joe Heck Date: Fri, 20 Jun 2025 13:49:57 -0700 Subject: [PATCH 2/3] first cut of curation, breaking doc comments into single-sentence abstracts across the public API of the module, resolving warnings for doc comments to argument mismatches --- Sources/PackagePlugin/ArgumentExtractor.swift | 7 +- Sources/PackagePlugin/Command.swift | 10 +- Sources/PackagePlugin/Context.swift | 13 ++- Sources/PackagePlugin/Diagnostics.swift | 4 +- .../Documentation.docc/Documentation.md | 52 +++++++++- Sources/PackagePlugin/Errors.swift | 6 +- .../PackagePlugin/PackageManagerProxy.swift | 4 +- Sources/PackagePlugin/PackageModel.swift | 98 ++++++++++++++----- Sources/PackagePlugin/Plugin.swift | 4 +- Sources/PackagePlugin/Utilities.swift | 12 ++- 10 files changed, 166 insertions(+), 44 deletions(-) diff --git a/Sources/PackagePlugin/ArgumentExtractor.swift b/Sources/PackagePlugin/ArgumentExtractor.swift index 4b39c9eba6b..d74d36abae4 100644 --- a/Sources/PackagePlugin/ArgumentExtractor.swift +++ b/Sources/PackagePlugin/ArgumentExtractor.swift @@ -10,7 +10,12 @@ // //===----------------------------------------------------------------------===// -/// A rudimentary helper for extracting options and flags from a string list representing command line arguments. The idea is to extract all known options and flags, leaving just the positional arguments. This does not handle well the case in which positional arguments (or option argument values) happen to have the same name as an option or a flag. It only handles the long `--` form of options, but it does respect `--` as an indication that all remaining arguments are positional. +/// A rudimentary helper for extracting options and flags from a string list representing command line arguments. +/// +/// The idea is to extract all known options and flags, leaving just the positional arguments. +/// This does not handle well the case in which positional arguments (or option argument values) happen to +/// have the same name as an option or a flag. It only handles the long `--` form of options, +/// but it does respect `--` as an indication that all remaining arguments are positional. public struct ArgumentExtractor { private var args: [String] private let literals: [String] diff --git a/Sources/PackagePlugin/Command.swift b/Sources/PackagePlugin/Command.swift index 3dd5e50b37d..99416d5c640 100644 --- a/Sources/PackagePlugin/Command.swift +++ b/Sources/PackagePlugin/Command.swift @@ -13,7 +13,9 @@ import Foundation /// A command to run during the build, including executable, command lines, -/// environment variables, initial working directory, etc. All paths should be +/// environment variables, initial working directory, etc. +/// +/// All paths should be /// based on the ones passed to the plugin in the target build context. public enum Command { /// Returns a command that runs when any of its output files are needed by @@ -157,7 +159,7 @@ extension Command { /// was generated as if in its source directory; other files are treated /// as resources as if explicitly listed in `Package.swift` using /// `.process(...)`. - @available(*, unavailable, message: "specifying the initial working directory for a command is not yet supported") + @available(*, unavailable, message: "specifying the initial working directory for a command is not supported") public static func buildCommand( displayName: String?, executable: Path, @@ -194,8 +196,6 @@ extension Command { /// - executable: The absolute path to the executable to be invoked. /// - arguments: Command-line arguments to be passed to the executable. /// - environment: Environment variable assignments visible to the executable. - /// - workingDirectory: Optional initial working directory when the executable - /// runs. /// - outputFilesDirectory: A directory into which the command writes its /// output files. Any files there recognizable by their extension as /// source files (e.g. `.swift`) are compiled into the target for which @@ -244,7 +244,7 @@ extension Command { /// this command was generated as if in its source directory; other /// files are treated as resources as if explicitly listed in /// `Package.swift` using `.process(...)`. - @available(*, unavailable, message: "specifying the initial working directory for a command is not yet supported") + @available(*, unavailable, message: "specifying the initial working directory for a command is not supported") public static func prebuildCommand( displayName: String?, executable: Path, diff --git a/Sources/PackagePlugin/Context.swift b/Sources/PackagePlugin/Context.swift index 9e048079d32..1e4bf987321 100644 --- a/Sources/PackagePlugin/Context.swift +++ b/Sources/PackagePlugin/Context.swift @@ -20,7 +20,9 @@ public struct PluginContext { public let package: Package /// The path of a writable directory into which the plugin or the build - /// commands it constructs can write anything it wants. This could include + /// commands it constructs can write anything it wants. + /// + /// This could include /// any generated source files that should be processed further, and it /// could include any caches used by the build tool or the plugin itself. /// The plugin is in complete control of what is written under this di- @@ -35,7 +37,9 @@ public struct PluginContext { public let pluginWorkDirectory: Path /// The path of a writable directory into which the plugin or the build - /// commands it constructs can write anything it wants. This could include + /// commands it constructs can write anything it wants. + /// + /// This could include /// any generated source files that should be processed further, and it /// could include any caches used by the build tool or the plugin itself. /// The plugin is in complete control of what is written under this di- @@ -50,6 +54,7 @@ public struct PluginContext { public let pluginWorkDirectoryURL: URL /// Looks up and returns the path of a named command line executable tool. + /// /// The executable must be provided by an executable target or a binary /// target on which the package plugin target depends. This function throws /// an error if the tool cannot be found. The lookup is case sensitive. @@ -81,7 +86,9 @@ public struct PluginContext { throw PluginContextError.toolNotFound(name: name) } - /// A mapping from tool names to their paths and triples. Not directly available + /// A mapping from tool names to their paths and triples. + /// + /// Not directly available /// to the plugin, but used by the `tool(named:)` API. let accessibleTools: [String: (path: URL, triples: [String]?)] diff --git a/Sources/PackagePlugin/Diagnostics.swift b/Sources/PackagePlugin/Diagnostics.swift index 0d05eff2f92..8940159cf09 100644 --- a/Sources/PackagePlugin/Diagnostics.swift +++ b/Sources/PackagePlugin/Diagnostics.swift @@ -11,7 +11,9 @@ //===----------------------------------------------------------------------===// /// Emits errors, warnings, and remarks to be shown as a result of running the -/// plugin. After emitting one or more errors, the plugin should return a +/// plugin. +/// +/// After emitting one or more errors, the plugin should return a /// non-zero exit code. public struct Diagnostics { diff --git a/Sources/PackagePlugin/Documentation.docc/Documentation.md b/Sources/PackagePlugin/Documentation.docc/Documentation.md index 2621b6c476f..b4e067827f1 100644 --- a/Sources/PackagePlugin/Documentation.docc/Documentation.md +++ b/Sources/PackagePlugin/Documentation.docc/Documentation.md @@ -2,12 +2,60 @@ Summary + ## Overview Text ## Topics -### Group +### Command Plugins -- ``Symbol`` +- ``CommandPlugin`` +- ``PluginContext`` +- ``Plugin`` + +### Build Plugins + +- ``BuildToolPlugin`` +- ``PluginContext`` +- ``Target`` +- ``Command`` + +### Plugin Diagnostics and Errors + +- ``Diagnostics`` +- ``PluginContextError`` +- ``PluginDeserializationError`` + +### Extracting Arguments + +- ``ArgumentExtractor`` + +### Interacting with Package Manager + +- ``PackageManager`` +- ``PackageManagerProxyError`` + +### Inspecting the Package Representation + +- ``Package`` +- ``ToolsVersion`` +- ``PackageOrigin`` +- ``PackageDependency`` +- ``Product`` +- ``ExecutableProduct`` +- ``LibraryProduct`` +- ``Target`` +- ``TargetDependency`` +- ``SourceModuleTarget`` +- ``ModuleKind`` +- ``SwiftSourceModuleTarget`` +- ``ClangSourceModuleTarget`` +- ``BinaryArtifactTarget`` +- ``SystemLibraryTarget`` +- ``FileList`` +- ``File`` +- ``FileType`` +- ``Path`` +- ``PathList`` diff --git a/Sources/PackagePlugin/Errors.swift b/Sources/PackagePlugin/Errors.swift index 2d7a08c21f5..fb6265125c2 100644 --- a/Sources/PackagePlugin/Errors.swift +++ b/Sources/PackagePlugin/Errors.swift @@ -10,8 +10,11 @@ // //===----------------------------------------------------------------------===// +/// Errors thrown while using a plugin. public enum PluginContextError: Error { - /// Could not find a tool with the given name. This could be either because + /// Could not find a tool with the given name. + /// + /// This could be either because /// it doesn't exist, or because the plugin doesn't have a dependency on it. case toolNotFound(name: String) @@ -40,6 +43,7 @@ extension PluginContextError: CustomStringConvertible { } } +/// Errors thrown while loading a plugin. public enum PluginDeserializationError: Error { /// The input JSON is malformed in some way; the message provides more details. case malformedInputJSON(_ message: String) diff --git a/Sources/PackagePlugin/PackageManagerProxy.swift b/Sources/PackagePlugin/PackageManagerProxy.swift index 0119f149695..bf36dd8dcde 100644 --- a/Sources/PackagePlugin/PackageManagerProxy.swift +++ b/Sources/PackagePlugin/PackageManagerProxy.swift @@ -13,7 +13,9 @@ import Foundation /// Provides specialized information and services from the Swift Package Manager -/// or an IDE that supports Swift Packages. Different plugin hosts implement the +/// or an IDE that supports Swift Packages. +/// +/// Different plugin hosts implement the /// functionality in whatever way is appropriate for them, but should preserve /// the same semantics described here. public struct PackageManager { diff --git a/Sources/PackagePlugin/PackageModel.swift b/Sources/PackagePlugin/PackageModel.swift index 88d229ca26f..aa7dd587713 100644 --- a/Sources/PackagePlugin/PackageModel.swift +++ b/Sources/PackagePlugin/PackageModel.swift @@ -33,6 +33,7 @@ public struct Package { public let origin: PackageOrigin /// The tools version specified by the resolved version of the package. + /// /// Behavior is often gated on the tools version, to make sure older /// packages continue to work as intended. public let toolsVersion: ToolsVersion @@ -60,7 +61,9 @@ public enum PackageOrigin { /// A package from a Git repository, with a URL and with a textual /// description of the resolved version or branch name (for display - /// purposes only), along with the corresponding SCM revision. The + /// purposes only), along with the corresponding SCM revision. + /// + /// The /// revision is the Git commit hash and may be useful for plugins /// that generates source code that includes version information. case repository(url: String, displayVersion: String, scmRevision: String) @@ -89,8 +92,9 @@ public struct ToolsVersion { } } -/// Represents a resolved dependency of a package on another package. This is a -/// separate entity in order to make it easier for future versions of the API to +/// Represents a resolved dependency of a package on another package. +/// +/// This is a separate entity in order to make it easier for future versions of the API to /// add information about the dependency itself. public struct PackageDependency { /// The package to which the dependency was resolved. @@ -107,12 +111,16 @@ public protocol Product { var id: ID { get } typealias ID = String - /// The name of the product, as defined in the package manifest. This name + /// The name of the product, as defined in the package manifest. + /// + /// This name /// is unique among the products of the package in which it is defined. var name: String { get } /// The targets that directly comprise the product, in the order in which - /// they are declared in the package manifest. The product will contain the + /// they are declared in the package manifest. + /// + /// The product will contain the /// transitive closure of the these targets and their dependencies. Some /// kinds of products have further restrictions on the set of targets (for /// example, an executable product must have one and only one target that @@ -125,18 +133,24 @@ public struct ExecutableProduct: Product { /// Unique identifier for the product. public let id: ID - /// The name of the product, as defined in the package manifest. This name + /// The name of the product, as defined in the package manifest. + /// + /// This name /// is unique among the products of the package in which it is defined. public let name: String /// The targets that directly comprise the product, in the order in which - /// they are declared in the package manifest. The product will contain the + /// they are declared in the package manifest. + /// + /// The product will contain the /// transitive closure of the these targets and their dependencies. For an /// ExecutableProduct, exactly one of the targets in this list must be an /// ExecutableTarget. public let targets: [Target] - /// The target that contains the main entry point of the executable. Every + /// The target that contains the main entry point of the executable. + /// + /// Every /// executable product has exactly one main executable target. This target /// will always be one of the targets in the product's `targets` array. public let mainTarget: Target @@ -147,12 +161,16 @@ public struct LibraryProduct: Product { /// Unique identifier for the product. public let id: ID - /// The name of the product, as defined in the package manifest. This name + /// The name of the product, as defined in the package manifest. + /// + /// This name /// is unique among the products of the package in which it is defined. public let name: String /// The targets that directly comprise the product, in the order in which - /// they are declared in the package manifest. The product will contain the + /// they are declared in the package manifest. + /// + /// The product will contain the /// transitive closure of the these targets and their dependencies. public let targets: [Target] @@ -179,7 +197,9 @@ public protocol Target { var id: ID { get } typealias ID = String - /// The name of the target, as defined in the package manifest. This name + /// The name of the target, as defined in the package manifest. + /// + /// This name /// is unique among the targets of the package in which it is defined. var name: String { get } @@ -192,7 +212,9 @@ public protocol Target { var directoryURL: URL { get } /// Any other targets on which this target depends, in the same order as - /// they are specified in the package manifest. Conditional dependencies + /// they are specified in the package manifest. + /// + /// Conditional dependencies /// that do not apply have already been filtered out. var dependencies: [TargetDependency] { get } } @@ -209,16 +231,20 @@ public enum TargetDependency { /// Represents a target consisting of a source code module, containing either /// Swift or source files in one of the C-based languages. public protocol SourceModuleTarget: Target { - /// The name of the module produced by the target (derived from the target - /// name, though future SwiftPM versions may allow this to be customized). + /// The name of the module produced by the target + /// + /// Derived from the target + /// name, though future SwiftPM versions may allow this to be customized. var moduleName: String { get } /// The kind of module, describing whether it contains unit tests, contains /// the main entry point of an executable, or neither. var kind: ModuleKind { get } - /// The source files that are associated with this target (any files that - /// have been excluded in the manifest have already been filtered out). + /// The source files that are associated with this target. + /// + /// Any files that + /// have been excluded in the manifest have already been filtered out. var sourceFiles: FileList { get } /// Any custom linked libraries required by the module, as specified in the @@ -267,7 +293,9 @@ public struct SwiftSourceModuleTarget: SourceModuleTarget { /// Unique identifier for the target. public let id: ID - /// The name of the target, as defined in the package manifest. This name + /// The name of the target, as defined in the package manifest. + /// + /// This name /// is unique among the targets of the package in which it is defined. public let name: String @@ -284,7 +312,9 @@ public struct SwiftSourceModuleTarget: SourceModuleTarget { public let directoryURL: URL /// Any other targets on which this target depends, in the same order as - /// they are specified in the package manifest. Conditional dependencies + /// they are specified in the package manifest. + /// + /// Conditional dependencies /// that do not apply have already been filtered out. public let dependencies: [TargetDependency] @@ -341,7 +371,9 @@ public struct ClangSourceModuleTarget: SourceModuleTarget { public let directoryURL: URL /// Any other targets on which this target depends, in the same order as - /// they are specified in the package manifest. Conditional dependencies + /// they are specified in the package manifest. + /// + /// Conditional dependencies /// that do not apply have already been filtered out. public let dependencies: [TargetDependency] @@ -394,7 +426,9 @@ public struct BinaryArtifactTarget: Target { /// Unique identifier for the target. public let id: ID - /// The name of the target, as defined in the package manifest. This name + /// The name of the target, as defined in the package manifest. + /// + /// This name /// is unique among the targets of the package in which it is defined. public let name: String @@ -407,7 +441,9 @@ public struct BinaryArtifactTarget: Target { public let directoryURL: URL /// Any other targets on which this target depends, in the same order as - /// they are specified in the package manifest. Conditional dependencies + /// they are specified in the package manifest. + /// + /// Conditional dependencies /// that do not apply have already been filtered out. public let dependencies: [TargetDependency] @@ -447,7 +483,9 @@ public struct SystemLibraryTarget: Target { /// Unique identifier for the target. public let id: ID - /// The name of the target, as defined in the package manifest. This name + /// The name of the target, as defined in the package manifest. + /// + /// This name /// is unique among the targets of the package in which it is defined. public var name: String @@ -460,7 +498,9 @@ public struct SystemLibraryTarget: Target { public var directoryURL: URL /// Any other targets on which this target depends, in the same order as - /// they are specified in the package manifest. Conditional dependencies + /// they are specified in the package manifest. + /// + /// Conditional dependencies /// that do not apply have already been filtered out. public var dependencies: [TargetDependency] @@ -474,7 +514,9 @@ public struct SystemLibraryTarget: Target { public let linkerFlags: [String] } -/// Provides information about a list of files. The order is not defined +/// Provides information about a list of files. +/// +/// The order is not defined /// but is guaranteed to be stable. This allows the implementation to be /// more efficient than a static file list. public struct FileList { @@ -533,7 +575,9 @@ public struct File { } } -/// Provides information about the type of a file. Any future cases will +/// Provides information about the type of a file. +/// +/// Any future cases will /// use availability annotations to make sure existing plugins still work /// until they increase their required tools version. public enum FileType { @@ -550,7 +594,9 @@ public enum FileType { case unknown } -/// Provides information about a list of paths. The order is not defined +/// Provides information about a list of paths. +/// +/// The order is not defined /// but is guaranteed to be stable. This allows the implementation to be /// more efficient than a static path list. public struct PathList { diff --git a/Sources/PackagePlugin/Plugin.swift b/Sources/PackagePlugin/Plugin.swift index 5589c23462e..c5146a83bb9 100644 --- a/Sources/PackagePlugin/Plugin.swift +++ b/Sources/PackagePlugin/Plugin.swift @@ -79,7 +79,9 @@ import Android extension Plugin { - /// Main entry point of the plugin — sets up a communication channel with + /// Main entry point of the plugin + /// + /// Sets up a communication channel with /// the plugin host and runs the main message loop. public static func main() async throws { // Duplicate the `stdin` file descriptor, which we will then use for diff --git a/Sources/PackagePlugin/Utilities.swift b/Sources/PackagePlugin/Utilities.swift index d84382d8139..677deeba64e 100644 --- a/Sources/PackagePlugin/Utilities.swift +++ b/Sources/PackagePlugin/Utilities.swift @@ -13,7 +13,9 @@ import Foundation extension Package { - /// The list of targets matching the given names. Throws an error if any of + /// The list of targets matching the given names. + /// + /// Throws an error if any of /// the targets cannot be found. public func targets(named targetNames: [String]) throws -> [Target] { return try targetNames.map { name in @@ -24,7 +26,9 @@ extension Package { } } - /// The list of products matching the given names. Throws an error if any of + /// The list of products matching the given names. + /// + /// Throws an error if any of /// the products cannot be found. public func products(named productNames: [String]) throws -> [Product] { return try productNames.map { name in @@ -51,7 +55,9 @@ extension Product { extension Target { /// The transitive closure of all the targets on which the receiver depends, /// ordered such that every dependency appears before any other target that - /// depends on it (i.e. in "topological sort order"). + /// depends on it. + /// + /// The dependencies are sorted in topological sort order. public var recursiveTargetDependencies: [Target] { // FIXME: We can rewrite this to use a stack instead of recursion. var visited = Set() From e8f89a33901f5e56f02c98364cf67e3ae84ebc57 Mon Sep 17 00:00:00 2001 From: Joe Heck Date: Fri, 20 Jun 2025 14:18:11 -0700 Subject: [PATCH 3/3] abstracts and first level overview for module --- .../Documentation.docc/Documentation.md | 39 ++++++++++++------- .../PackagePlugin/PackageManagerProxy.swift | 1 + 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/Sources/PackagePlugin/Documentation.docc/Documentation.md b/Sources/PackagePlugin/Documentation.docc/Documentation.md index b4e067827f1..6e303524b16 100644 --- a/Sources/PackagePlugin/Documentation.docc/Documentation.md +++ b/Sources/PackagePlugin/Documentation.docc/Documentation.md @@ -1,37 +1,35 @@ # ``PackagePlugin`` -Summary +Create plugins that extend the Swift Package Manager. ## Overview -Text +Build tool plugins generate source files that as part of a build, or perform other actions at the start of every build. +Build tool plugins are invoked before a package is built in order to construct command invocations to run as part of the build. +Command plugins provide actions that users can perform at any time and aren't associated with a build. + +Read [Writing a build tool plugin](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/WritingBuildToolPlugin) to learn how to create build tool plugins, or [Writing a command plugin](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/WritingCommandPlugin) to learn how to create command plugins. ## Topics -### Command Plugins +### Implementing Command Plugins - ``CommandPlugin`` - ``PluginContext`` - ``Plugin`` -### Build Plugins +### Extracting Arguments + +- ``ArgumentExtractor`` + +### Implementing Build Plugins - ``BuildToolPlugin`` - ``PluginContext`` - ``Target`` - ``Command`` -### Plugin Diagnostics and Errors - -- ``Diagnostics`` -- ``PluginContextError`` -- ``PluginDeserializationError`` - -### Extracting Arguments - -- ``ArgumentExtractor`` - ### Interacting with Package Manager - ``PackageManager`` @@ -46,6 +44,9 @@ - ``Product`` - ``ExecutableProduct`` - ``LibraryProduct`` + +### Inspecting Package Targets + - ``Target`` - ``TargetDependency`` - ``SourceModuleTarget`` @@ -54,8 +55,18 @@ - ``ClangSourceModuleTarget`` - ``BinaryArtifactTarget`` - ``SystemLibraryTarget`` + +### Inspecting Package Files + - ``FileList`` - ``File`` - ``FileType`` + - ``Path`` - ``PathList`` + +### Plugin Diagnostics and Errors + +- ``Diagnostics`` +- ``PluginContextError`` +- ``PluginDeserializationError`` diff --git a/Sources/PackagePlugin/PackageManagerProxy.swift b/Sources/PackagePlugin/PackageManagerProxy.swift index bf36dd8dcde..8ff8d30cc32 100644 --- a/Sources/PackagePlugin/PackageManagerProxy.swift +++ b/Sources/PackagePlugin/PackageManagerProxy.swift @@ -307,6 +307,7 @@ extension PackageManager { } } +/// Errors from methods using the package manager. public enum PackageManagerProxyError: Error { /// Indicates that the functionality isn't implemented in the plugin host. case unimplemented(_ message: String)