Skip to content

Commit b48dd91

Browse files
authored
[6.0] Add swift package add-target-dependency command to edit the manifest (swiftlang#7628)
**Explanation**: Building on SE-0301, add a new command `swift package add-target-dependency` to edit the package manifest and add a new dependency to a given target. **Original** PR: swiftlang#7594 **Risk**: Low. New, very simple code path to edit the package manifest in a narrow way. **Reviewed by**: @MaxDesiatov
1 parent b31f4c2 commit b48dd91

File tree

5 files changed

+124
-0
lines changed

5 files changed

+124
-0
lines changed

Package.swift

+1
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ if ProcessInfo.processInfo.environment["SWIFTCI_DISABLE_SDK_DEPENDENT_TESTS"] ==
751751
"Build",
752752
"Commands",
753753
"PackageModel",
754+
"PackageModelSyntax",
754755
"PackageRegistryCommand",
755756
"SourceControl",
756757
"SPMTestSupport",

Sources/Commands/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_library(Commands
1010
PackageCommands/AddDependency.swift
1111
PackageCommands/AddProduct.swift
1212
PackageCommands/AddTarget.swift
13+
PackageCommands/AddTargetDependency.swift
1314
PackageCommands/APIDiff.swift
1415
PackageCommands/ArchiveSource.swift
1516
PackageCommands/CompletionCommand.swift
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2014-2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import Basics
15+
import CoreCommands
16+
import PackageModel
17+
import PackageModelSyntax
18+
import SwiftParser
19+
import SwiftSyntax
20+
import TSCBasic
21+
import TSCUtility
22+
import Workspace
23+
24+
extension SwiftPackageCommand {
25+
struct AddTargetDependency: SwiftCommand {
26+
package static let configuration = CommandConfiguration(
27+
abstract: "Add a new target dependency to the manifest")
28+
29+
@OptionGroup(visibility: .hidden)
30+
var globalOptions: GlobalOptions
31+
32+
@Argument(help: "The name of the new dependency")
33+
var dependencyName: String
34+
35+
@Argument(help: "The name of the target to update")
36+
var targetName: String
37+
38+
@Option(help: "The package in which the dependency resides")
39+
var package: String?
40+
41+
func run(_ swiftCommandState: SwiftCommandState) throws {
42+
let workspace = try swiftCommandState.getActiveWorkspace()
43+
44+
guard let packagePath = try swiftCommandState.getWorkspaceRoot().packages.first else {
45+
throw StringError("unknown package")
46+
}
47+
48+
// Load the manifest file
49+
let fileSystem = workspace.fileSystem
50+
let manifestPath = packagePath.appending("Package.swift")
51+
let manifestContents: ByteString
52+
do {
53+
manifestContents = try fileSystem.readFileContents(manifestPath)
54+
} catch {
55+
throw StringError("cannot find package manifest in \(manifestPath)")
56+
}
57+
58+
// Parse the manifest.
59+
let manifestSyntax = manifestContents.withData { data in
60+
data.withUnsafeBytes { buffer in
61+
buffer.withMemoryRebound(to: UInt8.self) { buffer in
62+
Parser.parse(source: buffer)
63+
}
64+
}
65+
}
66+
67+
let dependency: TargetDescription.Dependency
68+
if let package {
69+
dependency = .product(name: dependencyName, package: package)
70+
} else {
71+
dependency = .target(name: dependencyName, condition: nil)
72+
}
73+
74+
let editResult = try PackageModelSyntax.AddTargetDependency.addTargetDependency(
75+
dependency,
76+
targetName: targetName,
77+
to: manifestSyntax
78+
)
79+
80+
try editResult.applyEdits(
81+
to: fileSystem,
82+
manifest: manifestSyntax,
83+
manifestPath: manifestPath,
84+
verbose: !globalOptions.logging.quiet
85+
)
86+
}
87+
}
88+
}
89+

Sources/Commands/PackageCommands/SwiftPackageCommand.swift

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public struct SwiftPackageCommand: AsyncParsableCommand {
3636
AddDependency.self,
3737
AddProduct.self,
3838
AddTarget.self,
39+
AddTargetDependency.self,
3940
Clean.self,
4041
PurgeCache.self,
4142
Reset.self,

Tests/CommandsTests/PackageCommandTests.swift

+32
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,38 @@ final class PackageCommandTests: CommandsTestCase {
849849
}
850850
}
851851

852+
func testPackageAddTargetDependency() throws {
853+
try testWithTemporaryDirectory { tmpPath in
854+
let fs = localFileSystem
855+
let path = tmpPath.appending("PackageB")
856+
try fs.createDirectory(path)
857+
858+
try fs.writeFileContents(path.appending("Package.swift"), string:
859+
"""
860+
// swift-tools-version: 5.9
861+
import PackageDescription
862+
let package = Package(
863+
name: "client",
864+
targets: [ .target(name: "library") ]
865+
)
866+
"""
867+
)
868+
try localFileSystem.writeFileContents(path.appending(components: "Sources", "library", "library.swift"), string:
869+
"""
870+
public func Foo() { }
871+
"""
872+
)
873+
874+
_ = try execute(["add-target-dependency", "--package", "other-package", "other-product", "library"], packagePath: path)
875+
876+
let manifest = path.appending("Package.swift")
877+
XCTAssertFileExists(manifest)
878+
let contents: String = try fs.readFileContents(manifest)
879+
880+
XCTAssertMatch(contents, .contains(#".product(name: "other-product", package: "other-package"#))
881+
}
882+
}
883+
852884
func testPackageAddProduct() throws {
853885
try testWithTemporaryDirectory { tmpPath in
854886
let fs = localFileSystem

0 commit comments

Comments
 (0)