-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[SE-0301] Updating a project and its manifest programmatically and from the command line #7467
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
Conversation
@swift-ci test |
|
||
/// Default indent when we have to introduce indentation but have no context | ||
/// to get it right. | ||
let defaultIndent = TriviaPiece.spaces(4) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do actually have a utility to infer indentation in swift-syntax: https://github.com/apple/swift-syntax/blob/728e2f6d5f9fd4a8e45eab6e52e86ad1519a7e2a/Sources/SwiftBasicFormat/InferIndentation.swift#L19-L27
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, huh. Should I be worried that this is processing the entire file? I suppose I should thread through an optional indentation value if we're going to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think it should be a huge deal if the user actually invokes swift package add
and better than just using 4 spaces which does tend to look stupid if the rest of the file is indented with 2 spaces.
static func findFirst( | ||
in node: some SyntaxProtocol, | ||
matching predicate: (Self) -> Bool | ||
) -> Self? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn’t it make more sense for this to be an instance function on SyntaxProtocol
instead of a static function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because you are looking for something of the Self
type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking if it is a cleaner API to have it be like
tree.findFirst { (node: FunctionCallSyntax) -> Bool in
doChecks(for: node)
}
Instead of
FunctionCallSyntax.findFirst(in: tree) { node in
doChecks(for: node)
}
which reads a little backwards to me. But maybe it’s a matter of taste.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hate requiring type annotations on closures... but I can create an ofType
argument or similar to make this cleaner.
This is in decent shape except that the bootstrap script is totally broken. |
@swift-ci please test |
@swift-ci please test macOS |
@swift-ci please test Windows |
d12eceb
to
8cc4441
Compare
@swift-ci please test macOS |
@swift-ci please test |
@swift-ci please test Windows |
/// The set of argument labels that can occur after the "dependencies" | ||
/// argument in the Package initializers. | ||
/// | ||
/// TODO: Could we generate this from the the PackageDescription module, so |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we ship the abi.json file for PackageDescription in the toolchain, that might work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to look there, we might as well just parse the PackageDescription module sources, since we have swift-syntax around.
@swift-ci test windows |
@swift-ci please test |
@swift-ci please test macOS |
@swift-ci please test Windows |
…ifest file Package manifest files are Swift source code, so editing them means working with the source code directly. Introduce a new library based on swift-syntax that allows us to perform targeted manipulations of the manifest file programmatically, making suggested edits to the file without having to understand everything in it. Introduce one editing operation that adds a particular package dependency to the manifest file. For example, it takes the programmatic representation of a package dependency in the model (`PackageModel.PackageDependency`) and the syntax for a manifest file, then it will produce a set of edits that extend (or add) the dependencies in the `Package` instance to the manifest file, e.g., .package(url: "https://github.com/apple/swift-syntax.git", from: "510.0.1"), We make an attempt to match the surrounding trivia so that we don't make an ugly mess of the resulting manifest. I have tests for a number of cases to make sure they look nice, but I expect we'll have to refine the heuristics over time.
…nifest Introduce a new `package add-dependency` command that adds a package dependency to your manifest file, given command-line arguments containing the URL and the version requiements (branch, from-version, etc.). This utilizes the new infrastructure for swift-syntax based package editing, putting a command-line interface over it. Here's the help output: OVERVIEW: Add a package dependency to the manifest USAGE: swift package add-dependency <dependency> [--exact <exact>] [--revision <revision>] [--branch <branch>] [--from <from>] [--up-to-next-minor-from <up-to-next-minor-from>] [--to <to>] ARGUMENTS: <dependency> The URL or directory of the package to add OPTIONS: --exact <exact> The exact package version to depend on --revision <revision> The specific package revision to depend on --branch <branch> The branch of the package to depend on --from <from> The package version to depend on (up to the next major version) --up-to-next-minor-from <up-to-next-minor-from> The package version to depend on (up to the next minor version) --to <to> Specify upper bound on the package version range (exclusive) --version Show the version. -h, -help, --help Show help information.
Blame Owen for the evil genius of this hack, me for trying to put it in
The formatting is a mess, but the functionality is sound.
… to a package Add a new package command to add a target with the given name, type, and dependencies to the package. This includes adding the target to the package manifest as well as creating stub source files for the target to guide the user. For example, this command: swift package add-target SocialGraphClientTests --dependencies SocialGraphClient --type test adds the following to the targets in the package manifest: .testTarget(name: "SocialGraphClientTests", dependencies: ["SocialGraphClient"]), as well as creating the file `Tests/SocialGraphClientTests/SocialGraphClientTests.swift`, which looks like this: import SocialGraphClient import XCTest class SocialGraphClientTests: XCTestCase { func testSocialGraphClientTests() { XCTAssertEqual(42, 17 + 25) } } There is, undoubtedly, some tuning to do to clean this up. Here's the command-line interface, which mostly aligns with SE-0301: OVERVIEW: Add a new target to the manifest USAGE: swift package add-target <name> [--type <type>] [--dependencies <dependencies> ...] [--url <url>] [--path <path>] [--checksum <checksum>] ARGUMENTS: <name> The name of the new target OPTIONS: --type <type> The type of target to add, which can be one of (default: library) --dependencies <dependencies> A list of target dependency names --url <url> The URL for a remote binary target --path <path> The path to a local binary target --checksum <checksum> The checksum for a remote binary target --version Show the version. -h, -help, --help Show help information.
Rather than trying to thread through trivia everywhere, apply BasicFormat to arguments.
For macro targets, we need to add two new files: one with a macro definition, and another with the list of provided macros for the macro plugin. Reshuffle some code to make that easier.
…ands Start building package editing commands with the CMake build system as well, using FetchContent to get the swift-syntax libraries.
086cd4d
to
bad178b
Compare
@swift-ci please test |
1 similar comment
@swift-ci please test |
…om the command line (swiftlang#7467) (cherry picked from commit 47573ce)
#7494) * **Explanation**: Implement package manifest editing commands (`swift package add-dependency`, `swift package add-target`, `swift package add-product`) described in [SE-0301](https://github.com/apple/swift-evolution/blob/main/proposals/0301-package-editing-commands.md), using swift-syntax under the hood to perform the edits. * **Original PR**: #7467, #7476, #7477 * **Risk**: Very low. All new code for new commands. * **Reviewed by**: @ahoppen , @bnbarham , @owenv , @MaxDesiatov * **Testing**: New tests. --------- Co-authored-by: Rintaro Ishizaki <[email protected]> Co-authored-by: Saleem Abdulrasool <[email protected]>
This reflects swiftlang/swift-package-manager#7467 (cherry picked from commit 56d91588206c67032c5a0a244918254dba7e3cc3)
…om the command line (swiftlang#7467)
…om the command line (swiftlang#7467)
This reflects swiftlang/swift-package-manager#7467 (cherry picked from commit 56d9158)
Package manifest files are Swift source code, so editing them means working with the source code directly. Introduce a new library
PackageModelSyntax
based on swift-syntax that allows us to perform targeted manipulations of the manifest file programmatically, making suggested edits to the file without having to understand everything in it.Introduce two editing commands:
addPackageDependency
: adds a new package dependency to the manifest file, e.g.,addTarget
: adds a new target to the manifest file, e.g.,In both cases, this is handled as a limited transform on the swift-syntax tree that then produces a series of edits that update the package manifest. We don't make any attempts to reason about the whole package, so this doesn't require any round-tripping with a semantic model. The editing commands can also introduce new files into the package. For example, adding target will create a new source file
Sources/\(targetName)/\(targetName).swift
with contents appropriate for the target type (struct for a library,@main
for an executable, macro implementation struct for a macro target, etc.).These editing operations are surfaced by implementing two of the commands from SE-0301 "Package Editing Commands",
swift package add-dependency
andswift package add-target
. Adding a dependency looks a bit like this:and will produce the
.package(...)
example above and insert it into the appropriate place in the manifest.Adding a target looks like this:
and adds this target to the manifest
as well as
Sources/MyProgram/MyProgram.swift
: