Skip to content
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

[SE-0301] Introduce swift package add-target support to add targets to a package #7474

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
62d8e55
Add a PackageModelSyntax library that manipulates the source of a man…
DougGregor Apr 17, 2024
828a506
Add `swift package add` command to add a package dependency to the ma…
DougGregor Apr 17, 2024
7a4f414
Handle insertion into a dependencies array like "[] + a"
DougGregor Apr 18, 2024
f1491d2
Improve error handling for adding a package dependency to a manifest
DougGregor Apr 18, 2024
3b401f4
Don't allow programmatic editing of manifest files for manifests < 5.5
DougGregor Apr 18, 2024
d8cb0c0
Use 'package' access for newly-promoted-to-public APIs
DougGregor Apr 18, 2024
a108783
Align "add dependency" command line with SE-0301
DougGregor Apr 18, 2024
9127588
Render package dependencies with the SwiftPM 5.5 syntax
DougGregor Apr 18, 2024
d4309cf
Address code review comments and fix some trivia issues
DougGregor Apr 18, 2024
9894c43
Update CMake build and bootstrap script for PackageModelSyntax module
DougGregor Apr 18, 2024
8cc4441
HACK to try to debug CI failure
DougGregor Apr 19, 2024
3f1bb35
Make sure to exclude CMakeLists.txt from manifest
DougGregor Apr 19, 2024
3d7cac5
Add missing source file to CMakeLists.txt
DougGregor Apr 19, 2024
de8eb4f
Introduce an egregious hack to work around older CI toolchains
DougGregor Apr 19, 2024
086cd4d
Add PackageModelSyntax to CMake
DougGregor Apr 19, 2024
0b171f6
Add a new package manifest "edit" operation for adding a new target
DougGregor Apr 19, 2024
2ed18a5
[SE-0301] Introduce `swift package add-target` support to add targets…
DougGregor Apr 19, 2024
79459fe
Fix CMake syntax again, I think, maybe
DougGregor Apr 21, 2024
1c1c2fc
Use SwiftBasicFormat to improve formatting of edited manifest
DougGregor Apr 21, 2024
bf7eaef
[CMake] Use FetchContent for building swift-syntax
DougGregor Apr 21, 2024
2a42d47
Implement add-target support for macro targets
DougGregor Apr 22, 2024
1e0a269
More CMake build fixes
DougGregor Apr 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions BuildSupport/SwiftSyntax/CMakeLists.txt
@@ -0,0 +1,17 @@
SET(SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE ${CMAKE_SOURCE_DIR}/../swift-syntax)
message(STATUS "swift-syntax path: ${SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE}")

include(FetchContent)

if(NOT EXISTS "${SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE}")
message(SEND_ERROR "swift-syntax is required to build SwiftPM. Please run update-checkout or specify SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE")
return()
endif()

# Build swift-syntax libraries with FetchContent.
# set(CMAKE_Swift_COMPILER_TARGET ${SWIFT_HOST_TRIPLE})
set(BUILD_SHARED_LIBS OFF)

file(TO_CMAKE_PATH "${SWIFTPM_PATH_TO_SWIFT_SYNTAX_SOURCE}" swift_syntax_path)
FetchContent_Declare(SwiftSyntax SOURCE_DIR "${swift_syntax_path}")
FetchContent_MakeAvailable(SwiftSyntax)
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -54,5 +54,6 @@ find_package(SQLite3 REQUIRED)
# Enable `package` modifier for the whole package.
add_compile_options("$<$<COMPILE_LANGUAGE:Swift>:-package-name;SwiftPM>")

add_subdirectory(BuildSupport/SwiftSyntax)
add_subdirectory(Sources)
add_subdirectory(cmake/modules)
30 changes: 30 additions & 0 deletions Package.swift
Expand Up @@ -49,6 +49,7 @@ let swiftPMDataModelProduct = (
"PackageLoading",
"PackageMetadata",
"PackageModel",
"PackageModelSyntax",
"SourceControl",
"Workspace",
]
Expand Down Expand Up @@ -246,6 +247,23 @@ let package = Package(
swiftSettings: packageModelResourcesSettings
),

.target(
/** Primary Package model objects relationship to SwiftSyntax */
name: "PackageModelSyntax",
dependencies: [
"Basics",
"PackageLoading",
"PackageModel",
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
.product(name: "SwiftIDEUtils", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
],
exclude: ["CMakeLists.txt"]
),

.target(
/** Package model conventions and loading support */
name: "PackageLoading",
Expand Down Expand Up @@ -414,10 +432,12 @@ let package = Package(
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "OrderedCollections", package: "swift-collections"),
.product(name: "SwiftIDEUtils", package: "swift-syntax"),
"Basics",
"Build",
"CoreCommands",
"PackageGraph",
"PackageModelSyntax",
"SourceControl",
"Workspace",
"XCBuildSupport",
Expand Down Expand Up @@ -635,6 +655,14 @@ let package = Package(
name: "PackageModelTests",
dependencies: ["PackageModel", "SPMTestSupport"]
),
.testTarget(
name: "PackageModelSyntaxTests",
dependencies: [
"PackageModelSyntax",
"SPMTestSupport",
.product(name: "SwiftIDEUtils", package: "swift-syntax"),
]
),
.testTarget(
name: "PackageGraphTests",
dependencies: ["PackageGraph", "SPMTestSupport"]
Expand Down Expand Up @@ -785,6 +813,7 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.2")),
.package(url: "https://github.com/apple/swift-driver.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/apple/swift-crypto.git", .upToNextMinor(from: "3.0.0")),
.package(url: "https://github.com/apple/swift-syntax.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/apple/swift-system.git", .upToNextMinor(from: "1.1.1")),
.package(url: "https://github.com/apple/swift-collections.git", .upToNextMinor(from: "1.0.1")),
.package(url: "https://github.com/apple/swift-certificates.git", .upToNextMinor(from: "1.0.1")),
Expand All @@ -795,6 +824,7 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
.package(path: "../swift-argument-parser"),
.package(path: "../swift-driver"),
.package(path: "../swift-crypto"),
.package(path: "../swift-syntax"),
.package(path: "../swift-system"),
.package(path: "../swift-collections"),
.package(path: "../swift-certificates"),
Expand Down
1 change: 1 addition & 0 deletions Sources/CMakeLists.txt
Expand Up @@ -21,6 +21,7 @@ add_subdirectory(PackageFingerprint)
add_subdirectory(PackageGraph)
add_subdirectory(PackageLoading)
add_subdirectory(PackageModel)
add_subdirectory(PackageModelSyntax)
add_subdirectory(PackagePlugin)
add_subdirectory(PackageRegistry)
add_subdirectory(PackageSigning)
Expand Down
3 changes: 3 additions & 0 deletions Sources/Commands/CMakeLists.txt
Expand Up @@ -7,6 +7,8 @@
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors

add_library(Commands
PackageCommands/AddDependency.swift
PackageCommands/AddTarget.swift
PackageCommands/APIDiff.swift
PackageCommands/ArchiveSource.swift
PackageCommands/CompletionCommand.swift
Expand Down Expand Up @@ -56,6 +58,7 @@ target_link_libraries(Commands PUBLIC
CoreCommands
LLBuildManifest
PackageGraph
PackageModelSyntax
SourceControl
TSCBasic
TSCUtility
Expand Down
155 changes: 155 additions & 0 deletions Sources/Commands/PackageCommands/AddDependency.swift
@@ -0,0 +1,155 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2014-2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import ArgumentParser
import Basics
import CoreCommands
import PackageModel
import PackageModelSyntax
import SwiftParser
import SwiftSyntax
import TSCBasic
import TSCUtility
import Workspace

extension SwiftPackageCommand {
struct AddDependency: SwiftCommand {
package static let configuration = CommandConfiguration(
abstract: "Add a package dependency to the manifest")

@Argument(help: "The URL or directory of the package to add")
var dependency: String

@OptionGroup(visibility: .hidden)
var globalOptions: GlobalOptions

@Option(help: "The exact package version to depend on")
var exact: Version?

@Option(help: "The specific package revision to depend on")
var revision: String?

@Option(help: "The branch of the package to depend on")
var branch: String?

@Option(help: "The package version to depend on (up to the next major version)")
var from: Version?

@Option(help: "The package version to depend on (up to the next minor version)")
var upToNextMinorFrom: Version?

@Option(help: "Specify upper bound on the package version range (exclusive)")
var to: Version?

func run(_ swiftCommandState: SwiftCommandState) throws {
let workspace = try swiftCommandState.getActiveWorkspace()

guard let packagePath = try swiftCommandState.getWorkspaceRoot().packages.first else {
throw StringError("unknown package")
}

// Load the manifest file
let fileSystem = workspace.fileSystem
let manifestPath = packagePath.appending("Package.swift")
let manifestContents: ByteString
do {
manifestContents = try fileSystem.readFileContents(manifestPath)
} catch {
throw StringError("cannot find package manifest in \(manifestPath)")
}

// Parse the manifest.
let manifestSyntax = manifestContents.withData { data in
data.withUnsafeBytes { buffer in
buffer.withMemoryRebound(to: UInt8.self) { buffer in
Parser.parse(source: buffer)
}
}
}

let identity = PackageIdentity(url: .init(dependency))

// Collect all of the possible version requirements.
var requirements: [PackageDependency.SourceControl.Requirement] = []
if let exact {
requirements.append(.exact(exact))
}

if let branch {
requirements.append(.branch(branch))
}

if let revision {
requirements.append(.revision(revision))
}

if let from {
requirements.append(.range(.upToNextMajor(from: from)))
}

if let upToNextMinorFrom {
requirements.append(.range(.upToNextMinor(from: upToNextMinorFrom)))
}

if requirements.count > 1 {
throw StringError("must specify at most one of --exact, --branch, --revision, --from, or --up-to-next-minor-from")
}

guard let firstRequirement = requirements.first else {
throw StringError("must specify one of --exact, --branch, --revision, --from, or --up-to-next-minor-from")
}

let requirement: PackageDependency.SourceControl.Requirement
if case .range(let range) = firstRequirement {
if let to {
requirement = .range(range.lowerBound..<to)
} else {
requirement = .range(range)
}
} else {
requirement = firstRequirement

if to != nil {
throw StringError("--to can only be specified with --from or --up-to-next-minor-from")
}
}

// Figure out the location of the package.
let location: PackageDependency.SourceControl.Location
if let path = try? Basics.AbsolutePath(validating: dependency) {
location = .local(path)
} else {
location = .remote(.init(dependency))
}

let packageDependency: PackageDependency = .sourceControl(
identity: identity,
nameForTargetDependencyResolutionOnly: nil,
location: location,
requirement: requirement,
productFilter: .everything
)

let editResult = try AddPackageDependency.addPackageDependency(
packageDependency,
to: manifestSyntax
)

try editResult.applyEdits(
to: fileSystem,
manifest: manifestSyntax,
manifestPath: manifestPath,
verbose: !globalOptions.logging.quiet
)
}
}
}