Skip to content

Docs/package plugin api docs #8901

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions Sources/PackagePlugin/ArgumentExtractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,29 @@
//
//===----------------------------------------------------------------------===//

/// 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 `--<name>` 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 list of strings that represents command line arguments.
///
/// Create the extractor with the full command line arguments provided, then extract all known
/// options and flags, leaving the positional arguments.
///
/// This does not handle the case where positional arguments (or option argument values) have the same
/// name as an option or a flag. It only handles the long form of options, not short forms, for example: `--<name>`.
/// It respects an argument that consists of two hyphens (`--`) as an indication that all remaining arguments are positional.
public struct ArgumentExtractor {
private var args: [String]
private let literals: [String]

/// Initializes a ArgumentExtractor with a list of strings from which to extract flags and options. If the list contains `--`, any arguments that follow it are considered to be literals.
/// Creates an argument extractor with a list of strings from which to extract flags and options.
///
/// If the list contains `--`, any arguments that follow it are considered to be positional arguments.
public init(_ arguments: [String]) {
// Split the array on the first `--`, if there is one. Everything after that is a literal.
let parts = arguments.split(separator: "--", maxSplits: 1, omittingEmptySubsequences: false)
self.args = Array(parts[0])
self.literals = Array(parts.count == 2 ? parts[1] : [])
}

/// Extracts options of the form `--<name> <value>` or `--<name>=<value>` from the remaining arguments, and returns the extracted values.
/// Extracts options of the form `--<name> <value>` or `--<name>=<value>` from the remaining arguments and returns the extracted values.
public mutating func extractOption(named name: String) -> [String] {
var values: [String] = []
var idx = 0
Expand Down Expand Up @@ -66,12 +75,16 @@ public struct ArgumentExtractor {
return count
}

/// Returns any unextracted flags or options (based strictly on whether remaining arguments have a "--" prefix).
/// Returns any unextracted flags or options.
///
/// This is based strictly on whether remaining arguments have a "--" prefix.
public var unextractedOptionsOrFlags: [String] {
return args.filter{ $0.hasPrefix("--") }
}

/// Returns all remaining arguments, including any literals after the first `--` if there is one.
/// Returns all remaining arguments.
///
/// The returned values include any positional arguments after the first `--`, if there is one.
public var remainingArguments: [String] {
return args + literals
}
Expand Down
70 changes: 39 additions & 31 deletions Sources/PackagePlugin/Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,35 @@

import Foundation

/// A command to run during the build, including executable, command lines,
/// environment variables, initial working directory, etc. All paths should be
/// based on the ones passed to the plugin in the target build context.
/// A command to run during the build.
///
/// The command includes the executable, command lines, environment variables, initial working directory, and so on.
/// 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
/// the build, but out-of-date.
/// the build and are out-of-date.
///
/// An output file is out-of-date if it doesn't exist, or if any input files
/// have changed since the command was last run.
///
/// - Note: the paths in the list of output files may depend on the list of
/// input file paths, but **must not** depend on reading the contents of
/// any input files. Such cases must be handled using a `prebuildCommand`.
/// any input files. Use a `prebuildCommand`instead, if your functionality
/// requires you to read the contents of an input file.
///
/// - parameters:
/// - displayName: An optional string to show in build logs and other
/// status areas.
/// - 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
/// - arguments: The command-line arguments to be passed to the executable.
/// - environment: Any environment variable assignments visible to the
/// executable.
/// - inputFiles: Files on which the contents of output files may depend.
/// - inputFiles: A list of files on which the contents of output files may depend.
/// Any paths passed as `arguments` should typically be passed here as
/// well.
/// - outputFiles: Files to be generated or updated by the executable.
/// - outputFiles: A list of files to be generated or updated by the executable.
/// Any files recognizable by their extension as source files
/// (e.g. `.swift`) are compiled into the target for which this command
/// (for example, `.swift`) are compiled into the target for which 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(...)`.
Expand Down Expand Up @@ -67,11 +69,11 @@ public enum Command {
/// - displayName: An optional string to show in build logs and other
/// status areas.
/// - 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.
/// - arguments: The command-line arguments to be passed to the executable.
/// - environment: Any environment variable assignments visible to the executable.
/// - 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
/// source files (for example, `.swift`) are compiled into the target for which
/// 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(...)`.
Expand All @@ -87,7 +89,7 @@ public enum Command {

extension Command {
/// Returns a command that runs when any of its output files are needed by
/// the build, but out-of-date.
/// the build and are out-of-date.
///
/// An output file is out-of-date if it doesn't exist, or if any input files
/// have changed since the command was last run.
Expand All @@ -112,6 +114,10 @@ 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(...)`.
///
/// @DeprecationSummary {
/// Use ``buildCommand(displayName:executable:arguments:environment:inputFiles:outputFiles:)-swift.enum.case`` instead.
/// }
@available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
public static func buildCommand(
displayName: String?,
Expand All @@ -132,32 +138,33 @@ extension Command {
}

/// Returns a command that runs when any of its output files are needed
/// by the build, but out-of-date.
/// by the build and are out-of-date.
///
/// An output file is out-of-date if it doesn't exist, or if any input
/// files have changed since the command was last run.
///
/// - Note: the paths in the list of output files may depend on the list
/// of input file paths, but **must not** depend on reading the contents
/// of any input files. Such cases must be handled using a `prebuildCommand`.
/// of any input files. Use a `prebuildCommand`instead, if your functionality
/// requires you to read the contents of an input file.
///
/// - parameters:
/// - displayName: An optional string to show in build logs and other
/// status areas.
/// - 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.
/// - arguments: The command-line arguments to be passed to the executable.
/// - environment: Any environment variable assignments visible to the executable.
/// - workingDirectory: Optional initial working directory when the executable
/// runs.
/// - inputFiles: Files on which the contents of output files may depend.
/// - inputFiles: A list of files on which the contents of output files may depend.
/// Any paths passed as `arguments` should typically be passed here as well.
/// - outputFiles: Files to be generated or updated by the executable.
/// - outputFiles: A list of files to be generated or updated by the executable.
/// Any files recognizable by their extension as source files
/// (e.g. `.swift`) are compiled into the target for which this command
/// (for example, `.swift`) are compiled into the target for which 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 buildCommand(
displayName: String?,
executable: Path,
Expand Down Expand Up @@ -192,16 +199,17 @@ extension Command {
/// - displayName: An optional string to show in build logs and other
/// status areas.
/// - 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.
/// - arguments: The command-line arguments to be passed to the executable.
/// - environment: Any environment variable assignments visible to the executable.
/// - 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
/// source files (for example, `.swift`) are compiled into the target for which
/// 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(...)`.
/// @DeprecationSummary {
/// Use ``prebuildCommand(displayName:executable:arguments:environment:outputFilesDirectory:)-swift.enum.case`` instead.
/// }
@available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
public static func prebuildCommand(
displayName: String?,
Expand Down Expand Up @@ -234,17 +242,17 @@ extension Command {
/// - displayName: An optional string to show in build logs and other
/// status areas.
/// - 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.
/// - arguments: The command-line arguments to be passed to the executable.
/// - environment: Any 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
/// source files (for example, `.swift`) are compiled into the target for which
/// 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,
Expand Down
52 changes: 29 additions & 23 deletions Sources/PackagePlugin/Context.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@

import Foundation

/// Provides information about the package for which the plugin is invoked,
/// as well as contextual information based on the plugin's stated intent
/// and requirements.
/// A collection of information about the package on which the plugin is invoked,
/// as well as contextual information based on the plugin's intent and requirements.
public struct PluginContext {
/// Information about the package to which the plugin is being applied.
/// Information about the package on which the plugin is being applied.
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-
/// rectory, and the contents are preserved between builds.
/// The plugin is in complete control of what is written under this directory,
/// and the contents are preserved between builds.
///
/// A plugin would usually create a separate subdirectory of this directory
/// for each command it creates, and the command would be configured to
Expand All @@ -35,24 +36,28 @@ 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-
/// rectory, and the contents are preserved between builds.
/// The plugin is in complete control of what is written under this directory,
/// and the contents are preserved between builds.
///
/// A plugin would usually create a separate subdirectory of this directory
/// for each command it creates, and the command would be configured to
/// A plugin should create a separate subdirectory in this directory
/// for each command it creates, and the command configured to
/// write its outputs to that directory. The plugin may also create other
/// directories for cache files and other file system content that either
/// it or the command will need.
/// directories for cache files, and other file system content that either
/// it or a command may need.
@available(_PackageDescription, introduced: 6.0)
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
/// Looks up and returns the path of a named command line executable.
///
/// The executable must be provided by an executable target or 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.
/// - Parameter name: The name of the executable to find.
public func tool(named name: String) throws -> Tool {
if let tool = self.accessibleTools[name] {
// For PluginAccessibleTool.builtTool, the triples value is not saved, thus
Expand Down Expand Up @@ -81,32 +86,33 @@ public struct PluginContext {
throw PluginContextError.toolNotFound(name: name)
}

/// A mapping from tool names to their paths and triples. Not directly available
/// to the plugin, but used by the `tool(named:)` API.
/// A mapping from tool names to their paths and triples.
///
/// This is not directly available to the plugin, but is used by ``tool(named:)``.
let accessibleTools: [String: (path: URL, triples: [String]?)]

/// The paths of directories of in which to search for tools that aren't in
/// The paths of directories in which to search for tools that aren't in
/// the `toolNamesToPaths` map.
@available(_PackageDescription, deprecated: 6.0, renamed: "toolSearchDirectoryURLs")
let toolSearchDirectories: [Path]

/// The paths of directories of in which to search for tools that aren't in
/// The paths of directories in which to search for tools that aren't in
/// the `toolNamesToPaths` map.
@available(_PackageDescription, introduced: 6.0)
let toolSearchDirectoryURLs: [URL]

/// Information about a particular tool that is available to a plugin.
public struct Tool {
/// Name of the tool (suitable for display purposes).
/// The name of the tool, suitable for display purposes.
public let name: String

/// Full path of the built or provided tool in the file system.
/// The path of the tool in the file system.
@available(_PackageDescription, deprecated: 6.0, renamed: "url")
public var path: Path {
get { _path }
}

/// Full path of the built or provided tool in the file system.
/// The file URL of the tool in the file system.
@available(_PackageDescription, introduced: 6.0)
public let url: URL

Expand Down
Loading