Skip to content

Commit 8037e95

Browse files
committed
[Commands] Switch AddTarget to use refactoring action from swift-syntax
1 parent af2f096 commit 8037e95

File tree

1 file changed

+78
-31
lines changed

1 file changed

+78
-31
lines changed

Sources/Commands/PackageCommands/AddTarget.swift

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ import CoreCommands
1616
import Foundation
1717
import PackageGraph
1818
import PackageModel
19-
import PackageModelSyntax
2019
import SwiftParser
20+
@_spi(PackageRefactor) import SwiftRefactor
2121
import SwiftSyntax
2222
import TSCBasic
2323
import TSCUtility
2424
import Workspace
2525

26-
extension AddTarget.TestHarness: ExpressibleByArgument { }
26+
extension AddPackageTarget.TestHarness: @retroactive ExpressibleByArgument { }
2727

2828
extension SwiftPackageCommand {
29-
struct AddTarget: SwiftCommand {
29+
struct AddTarget: AsyncSwiftCommand {
3030
/// The type of target that can be specified on the command line.
3131
enum TargetType: String, Codable, ExpressibleByArgument, CaseIterable {
3232
case library
@@ -63,9 +63,9 @@ extension SwiftPackageCommand {
6363
var checksum: String?
6464

6565
@Option(help: "The testing library to use when generating test targets, which can be one of 'xctest', 'swift-testing', or 'none'.")
66-
var testingLibrary: PackageModelSyntax.AddTarget.TestHarness = .default
66+
var testingLibrary: AddPackageTarget.TestHarness = .default
6767

68-
func run(_ swiftCommandState: SwiftCommandState) throws {
68+
func run(_ swiftCommandState: SwiftCommandState) async throws {
6969
let workspace = try swiftCommandState.getActiveWorkspace()
7070

7171
guard let packagePath = try swiftCommandState.getWorkspaceRoot().packages.first else {
@@ -92,43 +92,39 @@ extension SwiftPackageCommand {
9292
}
9393

9494
// Move sources into their own folder if they're directly in `./Sources`.
95-
try PackageModelSyntax.AddTarget.moveSingleTargetSources(
95+
try await moveSingleTargetSources(
96+
workspace: workspace,
9697
packagePath: packagePath,
97-
manifest: manifestSyntax,
98-
fileSystem: fileSystem,
99-
verbose: !globalOptions.logging.quiet
98+
verbose: !globalOptions.logging.quiet,
99+
observabilityScope: swiftCommandState.observabilityScope
100100
)
101101

102102
// Map the target type.
103-
let type: TargetDescription.TargetKind = switch self.type {
104-
case .library: .regular
103+
let type: PackageTarget.TargetKind = switch self.type {
104+
case .library: .library
105105
case .executable: .executable
106106
case .test: .test
107107
case .macro: .macro
108108
}
109109

110110
// Map dependencies
111-
let dependencies: [TargetDescription.Dependency] =
112-
self.dependencies.map {
113-
.byName(name: $0, condition: nil)
114-
}
115-
116-
let target = try TargetDescription(
117-
name: name,
118-
dependencies: dependencies,
119-
path: path,
120-
url: url,
121-
type: type,
122-
checksum: checksum
123-
)
111+
let dependencies: [PackageTarget.Dependency] = self.dependencies.map {
112+
.byName(name: $0)
113+
}
124114

125-
let editResult = try PackageModelSyntax.AddTarget.addTarget(
126-
target,
127-
to: manifestSyntax,
128-
configuration: .init(testHarness: testingLibrary),
129-
installedSwiftPMConfiguration: swiftCommandState
130-
.getHostToolchain()
131-
.installedSwiftPMConfiguration
115+
let editResult = try AddPackageTarget.manifestRefactor(
116+
syntax: manifestSyntax,
117+
in: .init(
118+
target: .init(
119+
name: name,
120+
type: type,
121+
dependencies: dependencies,
122+
path: path,
123+
url: url,
124+
checksum: checksum
125+
),
126+
testHarness: testingLibrary
127+
)
132128
)
133129

134130
try editResult.applyEdits(
@@ -138,6 +134,57 @@ extension SwiftPackageCommand {
138134
verbose: !globalOptions.logging.quiet
139135
)
140136
}
137+
138+
// Check if the package has a single target with that target's sources located
139+
// directly in `./Sources`. If so, move the sources into a folder named after
140+
// the target before adding a new target.
141+
private func moveSingleTargetSources(
142+
workspace: Workspace,
143+
packagePath: Basics.AbsolutePath,
144+
verbose: Bool = false,
145+
observabilityScope: ObservabilityScope
146+
) async throws {
147+
let manifest = try await workspace.loadRootManifest(
148+
at: packagePath,
149+
observabilityScope: observabilityScope
150+
)
151+
152+
guard let target = manifest.targets.first, manifest.targets.count == 1 else {
153+
return
154+
}
155+
156+
let sourcesFolder = packagePath.appending("Sources")
157+
let expectedTargetFolder = sourcesFolder.appending(target.name)
158+
159+
let fileSystem = workspace.fileSystem
160+
// If there is one target then pull its name out and use that to look for a folder in `Sources/TargetName`.
161+
// If the folder doesn't exist then we know we have a single target package and we need to migrate files
162+
// into this folder before we can add a new target.
163+
if !fileSystem.isDirectory(expectedTargetFolder) {
164+
if verbose {
165+
print(
166+
"""
167+
Moving existing files from \(
168+
sourcesFolder.relative(to: packagePath)
169+
) to \(
170+
expectedTargetFolder.relative(to: packagePath)
171+
)...
172+
""",
173+
terminator: ""
174+
)
175+
}
176+
let contentsToMove = try fileSystem.getDirectoryContents(sourcesFolder)
177+
try fileSystem.createDirectory(expectedTargetFolder)
178+
for file in contentsToMove {
179+
let source = sourcesFolder.appending(file)
180+
let destination = expectedTargetFolder.appending(file)
181+
try fileSystem.move(from: source, to: destination)
182+
}
183+
if verbose {
184+
print(" done.")
185+
}
186+
}
187+
}
141188
}
142189
}
143190

0 commit comments

Comments
 (0)