Skip to content

Commit

Permalink
Update SPMPackageEditor library to work with current toolchains
Browse files Browse the repository at this point in the history
  • Loading branch information
owenv committed Nov 8, 2020
1 parent 53c735c commit 60d418a
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 61 deletions.
13 changes: 13 additions & 0 deletions Package.swift
Expand Up @@ -305,3 +305,16 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
.package(path: "../swift-driver"),
]
}

// Because SwiftSyntax is closely tied to the compiler, only attempt to build
// the package editor library if we're in a build-script environment and can
// assume we're using a just-built compiler and SwiftSyntax library.
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] != nil {
package.dependencies += [.package(path: "../swift-syntax")]
package.targets += [
.target(name: "SPMPackageEditor",
dependencies: ["Workspace", "PackageModel", "PackageLoading",
"SourceControl", "SwiftSyntax", "SwiftToolsSupport-auto"]),
.testTarget(name: "SPMPackageEditorTests", dependencies: ["SPMPackageEditor", "SPMTestSupport"]),
]
}
120 changes: 60 additions & 60 deletions Sources/SPMPackageEditor/ManifestRewriter.swift
Expand Up @@ -37,7 +37,7 @@ public final class ManifestRewriter {
/// Create a new manfiest editor with the given contents.
public init(_ manifest: String) throws {
self.originalManifest = manifest
self.editedSource = try SyntaxParser.parse(source: manifest)
self.editedSource = Syntax(try SyntaxParser.parse(source: manifest))
}

/// Add a package dependency.
Expand All @@ -47,15 +47,15 @@ public final class ManifestRewriter {
) throws {
// Find Package initializer.
let packageFinder = PackageInitFinder()
editedSource.walk(packageFinder)
packageFinder.walk(editedSource)

guard let initFnExpr = packageFinder.packageInit else {
throw Error.error("Couldn't find Package initializer")
}

// Find dependencies section in the argument list of Package(...).
let packageDependenciesFinder = DependenciesArrayFinder()
initFnExpr.argumentList.walk(packageDependenciesFinder)
packageDependenciesFinder.walk(initFnExpr.argumentList)

let packageDependencies: ArrayExprSyntax
if let existingPackageDependencies = packageDependenciesFinder.dependenciesArrayExpr {
Expand All @@ -66,7 +66,7 @@ public final class ManifestRewriter {

// Find the inserted section.
let packageDependenciesFinder = DependenciesArrayFinder()
argListWithDependencies.walk(packageDependenciesFinder)
packageDependenciesFinder.walk(argListWithDependencies)
packageDependencies = packageDependenciesFinder.dependenciesArrayExpr!
}

Expand All @@ -86,28 +86,28 @@ public final class ManifestRewriter {
) throws {
// Find Package initializer.
let packageFinder = PackageInitFinder()
editedSource.walk(packageFinder)
packageFinder.walk(editedSource)

guard let initFnExpr = packageFinder.packageInit else {
throw Error.error("Couldn't find Package initializer")
}

// Find the `targets: []` array.
let targetsArrayFinder = TargetsArrayFinder()
initFnExpr.argumentList.walk(targetsArrayFinder)
targetsArrayFinder.walk(initFnExpr.argumentList)
guard let targetsArrayExpr = targetsArrayFinder.targets else {
throw Error.error("Couldn't find targets label")
}

// Find the target node.
let targetFinder = TargetFinder(name: target)
targetsArrayExpr.walk(targetFinder)
targetFinder.walk(targetsArrayExpr)
guard let targetNode = targetFinder.foundTarget else {
throw Error.error("Couldn't find target \(target)")
}

let targetDependencyFinder = DependenciesArrayFinder()
targetNode.walk(targetDependencyFinder)
targetDependencyFinder.walk(targetNode)

guard let targetDependencies = targetDependencyFinder.dependenciesArrayExpr else {
throw Error.error("Couldn't find dependencies section")
Expand All @@ -128,14 +128,14 @@ public final class ManifestRewriter {
) throws {
// Find Package initializer.
let packageFinder = PackageInitFinder()
editedSource.walk(packageFinder)
packageFinder.walk(editedSource)

guard let initFnExpr = packageFinder.packageInit else {
throw Error.error("Couldn't find Package initializer")
}

let targetsFinder = TargetsArrayFinder()
initFnExpr.argumentList.walk(targetsFinder)
targetsFinder.walk(initFnExpr.argumentList)

guard let targetsNode = targetsFinder.targets else {
throw Error.error("Couldn't find targets section")
Expand All @@ -157,12 +157,8 @@ final class PackageInitFinder: SyntaxVisitor {
/// Reference to the function call of the package initializer.
private(set) var packageInit: FunctionCallExprSyntax?

override func shouldVisit(_ kind: SyntaxKind) -> Bool {
return kind == .initializerClause
}

override func visit(_ node: InitializerClauseSyntax) -> SyntaxVisitorContinueKind {
if let fnCall = node.value as? FunctionCallExprSyntax,
if let fnCall = FunctionCallExprSyntax(Syntax(node.value)),
let identifier = fnCall.calledExpression.firstToken,
identifier.text == "Package" {
assert(packageInit == nil, "Found two package initializers")
Expand All @@ -177,15 +173,15 @@ final class DependenciesArrayFinder: SyntaxVisitor {

private(set) var dependenciesArrayExpr: ArrayExprSyntax?

override func visit(_ node: FunctionCallArgumentSyntax) -> SyntaxVisitorContinueKind {
override func visit(_ node: TupleExprElementSyntax) -> SyntaxVisitorContinueKind {
guard node.label?.text == "dependencies" else {
return .skipChildren
}

// We have custom code like foo + bar + [] (hopefully there is an array expr here).
if let seq = node.expression as? SequenceExprSyntax {
dependenciesArrayExpr = seq.elements.first(where: { $0 is ArrayExprSyntax }) as? ArrayExprSyntax
} else if let arrayExpr = node.expression as? ArrayExprSyntax {
if let seq = node.expression.as(SequenceExprSyntax.self) {
dependenciesArrayExpr = seq.elements.first(where: { $0.is(ArrayExprSyntax.self) })?.as(ArrayExprSyntax.self)
} else if let arrayExpr = node.expression.as(ArrayExprSyntax.self) {
dependenciesArrayExpr = arrayExpr
}

Expand All @@ -202,9 +198,9 @@ final class TargetsArrayFinder: SyntaxVisitor {
/// The found targets array expr.
private(set) var targets: ArrayExprSyntax?

override func visit(_ node: FunctionCallArgumentSyntax) -> SyntaxVisitorContinueKind {
override func visit(_ node: TupleExprElementSyntax) -> SyntaxVisitorContinueKind {
if node.label?.text == "targets",
let expr = node.expression as? ArrayExprSyntax {
let expr = node.expression.as(ArrayExprSyntax.self) {
assert(targets == nil, "Found two targets labels")
targets = expr
}
Expand All @@ -216,25 +212,27 @@ final class TargetsArrayFinder: SyntaxVisitor {
final class TargetFinder: SyntaxVisitor {

let targetToFind: String
private(set) var foundTarget: FunctionCallArgumentListSyntax?
private(set) var foundTarget: TupleExprElementListSyntax?

init(name: String) {
self.targetToFind = name
}

override func visit(_ node: FunctionCallArgumentSyntax) -> SyntaxVisitorContinueKind {
override func visit(_ node: TupleExprElementSyntax) -> SyntaxVisitorContinueKind {
guard case .identifier(let label)? = node.label?.tokenKind else {
return .skipChildren
}
guard label == "name", let targetNameExpr = node.expression as? StringLiteralExprSyntax else {
guard label == "name", let targetNameExpr = node.expression.as(StringLiteralExprSyntax.self),
targetNameExpr.segments.count == 1, let segment = targetNameExpr.segments.first?.as(StringSegmentSyntax.self) else {
return .skipChildren
}
guard case .stringLiteral(let targetName) = targetNameExpr.stringLiteral.tokenKind else {

guard case .stringSegment(let targetName) = segment.content.tokenKind else {
return .skipChildren
}

if targetName == "\"" + self.targetToFind + "\"" {
self.foundTarget = node.parent as? FunctionCallArgumentListSyntax
if targetName == self.targetToFind {
self.foundTarget = node.parent?.as(TupleExprElementListSyntax.self)
return .skipChildren
}

Expand All @@ -247,22 +245,22 @@ final class TargetFinder: SyntaxVisitor {
/// Writer for "dependencies" array syntax.
final class DependenciesArrayWriter: SyntaxRewriter {

override func visit(_ node: FunctionCallArgumentListSyntax) -> Syntax {
override func visit(_ node: TupleExprElementListSyntax) -> Syntax {
let leadingTrivia = node.firstToken?.leadingTrivia ?? .zero

let dependenciesArg = SyntaxFactory.makeFunctionCallArgument(
let dependenciesArg = SyntaxFactory.makeTupleExprElement(
label: SyntaxFactory.makeIdentifier("dependencies", leadingTrivia: leadingTrivia),
colon: SyntaxFactory.makeColonToken(trailingTrivia: .spaces(1)),
expression: SyntaxFactory.makeArrayExpr(
leftSquare: SyntaxFactory.makeLeftSquareBracketToken(),
elements: SyntaxFactory.makeBlankArrayElementList(),
rightSquare: SyntaxFactory.makeRightSquareBracketToken()),
expression: ExprSyntax(SyntaxFactory.makeArrayExpr(
leftSquare: SyntaxFactory.makeLeftSquareBracketToken(),
elements: SyntaxFactory.makeBlankArrayElementList(),
rightSquare: SyntaxFactory.makeRightSquareBracketToken())),
trailingComma: SyntaxFactory.makeCommaToken()
)

// FIXME: This is not correct, we need to find the
// proper position for inserting `dependencies: []`.
return node.inserting(dependenciesArg, at: 1)
return Syntax(node.inserting(dependenciesArg, at: 1))
}
}

Expand All @@ -276,9 +274,9 @@ final class ArrayTrailingCommaWriter: SyntaxRewriter {

override func visit(_ node: ArrayElementSyntax) -> Syntax {
guard lastElement == node else {
return node
return Syntax(node)
}
return node.withTrailingComma(SyntaxFactory.makeCommaToken(trailingTrivia: .spaces(1)))
return Syntax(node.withTrailingComma(SyntaxFactory.makeCommaToken(trailingTrivia: .spaces(1))))
}
}

Expand Down Expand Up @@ -307,46 +305,47 @@ final class PackageDependencyWriter: SyntaxRewriter {
declNameArguments: nil
)

var args: [FunctionCallArgumentSyntax] = []
var args: [TupleExprElementSyntax] = []

let firstArgLabel = requirement == .localPackage ? "path" : "url"
let url = SyntaxFactory.makeFunctionCallArgument(
let url = SyntaxFactory.makeTupleExprElement(
label: SyntaxFactory.makeIdentifier(firstArgLabel),
colon: SyntaxFactory.makeColonToken(trailingTrivia: .spaces(1)),
expression: SyntaxFactory.makeStringLiteralExpr(self.url),
expression: ExprSyntax(SyntaxFactory.makeStringLiteralExpr(self.url)),
trailingComma: requirement == .localPackage ? nil : SyntaxFactory.makeCommaToken(trailingTrivia: .spaces(1))
)
args.append(url)

// FIXME: Handle other types of requirements.
if requirement != .localPackage {
let secondArg = SyntaxFactory.makeFunctionCallArgument(
let secondArg = SyntaxFactory.makeTupleExprElement(
label: SyntaxFactory.makeIdentifier("from"),
colon: SyntaxFactory.makeColonToken(trailingTrivia: .spaces(1)),
expression: SyntaxFactory.makeStringLiteralExpr(requirement.ref!),
expression: ExprSyntax(SyntaxFactory.makeStringLiteralExpr(requirement.ref!)),
trailingComma: nil
)
args.append(secondArg)
}

let expr = SyntaxFactory.makeFunctionCallExpr(
calledExpression: dotPackageExpr,
calledExpression: ExprSyntax(dotPackageExpr),
leftParen: SyntaxFactory.makeLeftParenToken(),
argumentList: SyntaxFactory.makeFunctionCallArgumentList(args),
argumentList: SyntaxFactory.makeTupleExprElementList(args),
rightParen: SyntaxFactory.makeRightParenToken(),
trailingClosure: nil
trailingClosure: nil,
additionalTrailingClosures: nil
)

let newDependencyElement = SyntaxFactory.makeArrayElement(
expression: expr,
expression: ExprSyntax(expr),
trailingComma: SyntaxFactory.makeCommaToken()
)

let rightBrace = SyntaxFactory.makeRightSquareBracketToken(
leadingTrivia: [.newlines(1), .spaces(4)])

return node.addArrayElement(newDependencyElement)
.withRightSquare(rightBrace)
return ExprSyntax(node.addElement(newDependencyElement)
.withRightSquare(rightBrace))
}
}

Expand All @@ -368,15 +367,15 @@ final class TargetDependencyWriter: SyntaxRewriter {
let lastElement = node.elements.map{$0}.last!
let trailingTriviaWriter = ArrayTrailingCommaWriter(lastElement: lastElement)
let newElements = trailingTriviaWriter.visit(node.elements)
node = node.withElements((newElements as! ArrayElementListSyntax))
node = node.withElements((newElements.as(ArrayElementListSyntax.self)!))
}

let newDependencyElement = SyntaxFactory.makeArrayElement(
expression: SyntaxFactory.makeStringLiteralExpr(self.dependencyName),
expression: ExprSyntax(SyntaxFactory.makeStringLiteralExpr(self.dependencyName)),
trailingComma: nil
)

return node.addArrayElement(newDependencyElement)
return ExprSyntax(node.addElement(newDependencyElement))
}
}

Expand All @@ -403,36 +402,37 @@ final class NewTargetWriter: SyntaxRewriter {
declNameArguments: nil
)

let nameArg = SyntaxFactory.makeFunctionCallArgument(
let nameArg = SyntaxFactory.makeTupleExprElement(
label: SyntaxFactory.makeIdentifier("name", leadingTrivia: leadingTriviaArgs),
colon: SyntaxFactory.makeColonToken(trailingTrivia: .spaces(1)),
expression: SyntaxFactory.makeStringLiteralExpr(self.name),
expression: ExprSyntax(SyntaxFactory.makeStringLiteralExpr(self.name)),
trailingComma: SyntaxFactory.makeCommaToken()
)

let emptyArray = SyntaxFactory.makeArrayExpr(leftSquare: SyntaxFactory.makeLeftSquareBracketToken(), elements: SyntaxFactory.makeBlankArrayElementList(), rightSquare: SyntaxFactory.makeRightSquareBracketToken())
let depenenciesArg = SyntaxFactory.makeFunctionCallArgument(
let depenenciesArg = SyntaxFactory.makeTupleExprElement(
label: SyntaxFactory.makeIdentifier("dependencies", leadingTrivia: leadingTriviaArgs),
colon: SyntaxFactory.makeColonToken(trailingTrivia: .spaces(1)),
expression: emptyArray,
expression: ExprSyntax(emptyArray),
trailingComma: nil
)

let expr = SyntaxFactory.makeFunctionCallExpr(
calledExpression: dotPackageExpr,
calledExpression: ExprSyntax(dotPackageExpr),
leftParen: SyntaxFactory.makeLeftParenToken(),
argumentList: SyntaxFactory.makeFunctionCallArgumentList([
argumentList: SyntaxFactory.makeTupleExprElementList([
nameArg, depenenciesArg,
]),
]),
rightParen: SyntaxFactory.makeRightParenToken(),
trailingClosure: nil
trailingClosure: nil,
additionalTrailingClosures: nil
)

let newDependencyElement = SyntaxFactory.makeArrayElement(
expression: expr,
expression: ExprSyntax(expr),
trailingComma: SyntaxFactory.makeCommaToken()
)

return node.addArrayElement(newDependencyElement)
return ExprSyntax(node.addElement(newDependencyElement))
}
}
5 changes: 4 additions & 1 deletion Sources/SPMPackageEditor/PackageEditor.swift
Expand Up @@ -161,7 +161,9 @@ extension Array where Element == TargetDescription.Dependency {
func containsDependency(_ other: String) -> Bool {
return self.contains {
switch $0 {
case .target(let name), .product(let name, _), .byName(let name):
case .target(name: let name, condition: _),
.product(name: let name, package: _, condition: _),
.byName(name: let name, condition: _):
return name == other
}
}
Expand Down Expand Up @@ -292,6 +294,7 @@ public final class PackageEditorContext {
baseURL: path.description,
version: nil,
toolsVersion: toolsVersion,
packageKind: .local,
fileSystem: fs
)
}
Expand Down

0 comments on commit 60d418a

Please sign in to comment.