[Pitch] Additional API available to SwiftPM plugins

Hello,

SE-0303 introduced SwiftPM plugins, focusing in particular on build tool plugins (especially those that generate source code). To keep that proposal bounded, the type and amount of information available to a plugin was geared toward the task of generating build commands.

Before starting to consider new kinds of plugins, it seems prudent to expand the information available to plugins of all kinds. Future proposals might add specific APIs for particular kinds of plugins, but before that, it seems that a good starting point would be to give all plugins access to a distilled form of the package graph that SwiftPM already has internally. This should allow a wide latitude in terms of what any particular plugin wants to do.

I'd like to pitch a draft proposal for extending the API available to SwiftPM plugins, and would love to hear what everyone thinks. There's an implementation in a PR in the SwiftPM repository.

Thanks!

https://github.com/apple/swift-evolution/blob/abd809f3528c8111826979b15f674f2703334941/proposals/NNNN-swiftpm-additional-plugin-apis.md

8 Likes

This is great :+1: Having access to this information by plugins opens up new use cases and is quite important, I don't have much to complain about with the exposed targets etc, looks good.

Minor thing: when I was developing a plugin it was a bit tricky to know what to pass to tool(), could we perhaps do some .availableTools that lists their names or is that not something we can do?

I am wondering about a declarative way to filter inputs, but this is outside of this proposal I think, right?

Great! I did expect it to be rather uncontroversial since it's pretty much just mirroring SwiftPM's conceptual model — there are possibly some nuances with system library targets and binary targets, though this proposal exposes pretty much what's there already, so if more is needed, the manifest might need be extended as well, in a separate proposal. I do expect that future proposals that modify SwiftPM's data model should include a section on how the plugin API evolves along with it.

That's good feedback — in general I would expect that the tools that the plugin would look up would be the ones that it has itself declared a dependency on, but this might indeed be worth exposing in the API. We could also do that by making the name-to-tool mapping available without a lookup function, and then let the plugin just do a subscripted lookup?

Right, I've been thinking the same thing, though in this proposal I wanted to focus entirely on extending the API (though that's not a requirement, I guess).

The original intent in SE-0303 was to try to avoid assumptions about what build tools wanted to look at as their inputs, and thereby unintentionally limiting them. But it's certainly very common for a build tool in particular to want to process files matching a particular naming pattern. In that case perhaps the main entry point should pass those input files up-front so that the tool doesn't have to find them.

I'm also mildly concerned about the performance of making all the inputs available to all build tools, only for the build tool to ignore most of them. I think that can be mitigated in the implementation, and is one reason why the API is an iterator, but it would be even more efficient to just state it up-front rather than filter it later.

I'm concerned about adding more complexity back to the manifest declaration, though. Ideally I think it would make sense to use annotated properties on the plugin type to convey this kind of information, in the manner of SwiftArgumentParser. This could be used for custom parameters to the plugin and also perhaps to declare input filters etc. SwiftPM could then look at those annotations, perhaps even syntactically before even running the plugin if they are literals.

But those are just future ideas. Do you think that, in the immediate term, there should be an optional file name pattern on the .buildTool() capability declaration in the manifest?

1 Like

Something that I realized would also be useful would be the declared tools version of each package. To maintain compatibility, SwiftPM uses this version to gate certain behavior (such as flags to pass) and it seems to me that having this available to plugins would allow the same kind of behavior.