Skip to content

Cleanup PackageGraph Module #2992

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

Merged
merged 27 commits into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b753bd0
Extract PackageRequirement into separate file
mattt Sep 17, 2020
280dac7
Extract PackageContainer into separate file
mattt Sep 17, 2020
7530793
Move BasePackageContainer to PackageContainer file
mattt Sep 17, 2020
b1fa7b6
Extract LocalPackageContainer into separate file
mattt Sep 17, 2020
0473fd8
Rename RepositoryPackageContainerProvider.swift to RepositoryPackageC…
mattt Sep 17, 2020
14ebd7f
Move CheckoutState.requirement to original type declaration
mattt Oct 14, 2020
47bd01e
Extract BoundVersion to separate file
mattt Oct 14, 2020
044b849
Extract DependencyResolutionNode to separate file
mattt Oct 14, 2020
7335ca2
Extract GraphLoadingNode to separate file
mattt Oct 14, 2020
ceb8e59
Move PackageGraphError to PackageGraph declaration
mattt Oct 14, 2020
3267ffa
Extract diagnostics concerns to separate file
mattt Oct 14, 2020
939c484
Rename RawPackageConstraints.swift to PackageModel+Extensions.swift
mattt Oct 14, 2020
889b797
Refactor PackageGraphLoader functionality into extension on PackageGraph
mattt Oct 14, 2020
4544a00
Extract Pubgrub resolver into separate files
mattt Oct 14, 2020
f64b96e
Conform to protocols in extensions
mattt Oct 14, 2020
45e284b
Use built-in Result type
mattt Oct 14, 2020
41abec0
Convert requirement to computed property
mattt Oct 21, 2020
6f448b0
Convert nameForDiagnostics into computed property
mattt Oct 21, 2020
8477fe4
Convert productFilter into computed property
mattt Oct 21, 2020
eeaca73
Remove leading underscore for public property isRemoteContainer
mattt Oct 21, 2020
de9958f
Move PackageReference extension into PackageModel+Extensions
mattt Oct 21, 2020
25a9b47
Extract extension on Version into separate file
mattt Oct 21, 2020
fec3895
Make constrained extension on Range fileprivate
mattt Oct 21, 2020
246b96c
Reorganize PinsStore protocol conformance and headings
mattt Oct 21, 2020
40bb8e8
Move findCycles helper function to PackageGraph+Loading
mattt Oct 21, 2020
eb0193c
Remove unused delegate APIs for DependencyResolver
mattt Oct 21, 2020
bc81953
Fix CMakeLists source list
mattt Oct 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Sources/Commands/SwiftTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ private class ToolWorkspaceDelegate: WorkspaceDelegate {

switch state {
case .checkout(let checkoutState)?:
let requirement = checkoutState.requirement()
switch requirement {
switch checkoutState.requirement {
case .versionSet(.exact(let version)):
stdoutStream <<< "resolved to '\(version)'"
case .versionSet(_):
Expand Down
45 changes: 45 additions & 0 deletions Sources/PackageGraph/BoundVersion.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2014 - 2020 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 Swift project authors
*/

import struct TSCUtility.Version

/// A bound version for a package within an assignment.
public enum BoundVersion: Equatable, Hashable {
/// The assignment should not include the package.
///
/// This is different from the absence of an assignment for a particular
/// package, which only indicates the assignment is agnostic to its
/// version. This value signifies the package *may not* be present.
case excluded

/// The version of the package to include.
case version(Version)

/// The package assignment is unversioned.
case unversioned

/// The package assignment is this revision.
case revision(String)
}

extension BoundVersion: CustomStringConvertible {
public var description: String {
switch self {
case .excluded:
return "excluded"
case .version(let version):
return version.description
case .unversioned:
return "unversioned"
case .revision(let identifier):
return identifier
}
}
}
20 changes: 16 additions & 4 deletions Sources/PackageGraph/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,30 @@
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors

add_library(PackageGraph
BoundVersion.swift
CheckoutState.swift
DependencyResolutionNode.swift
DependencyResolver.swift
Diagnostics.swift
GraphLoadingNode.swift
LocalPackageContainer.swift
PackageContainer.swift
PackageGraph.swift
PackageGraphLoader.swift
PackageGraph+Loading.swift
PackageGraphRoot.swift
PackageModel+Extensions.swift
PackageRequirement.swift
PinsStore.swift
Pubgrub.swift
RawPackageConstraints.swift
Pubgrub/Assignment.swift
Pubgrub/Incompatibility.swift
Pubgrub/PartialSolution.swift
Pubgrub/PubgrubDependencyResolver.swift
Pubgrub/Term.swift
RepositoryPackageContainer.swift
ResolvedPackage.swift
ResolvedProduct.swift
ResolvedTarget.swift
RepositoryPackageContainerProvider.swift
Version+Extensions.swift
VersionSetSpecifier.swift)
target_link_libraries(PackageGraph PUBLIC
TSCBasic
Expand Down
22 changes: 12 additions & 10 deletions Sources/PackageGraph/CheckoutState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import TSCUtility
/// A checkout state represents the current state of a repository.
///
/// A state will always has a revision. It can also have a branch or a version but not both.
public struct CheckoutState: Equatable, CustomStringConvertible {
public struct CheckoutState: Equatable, Hashable {

/// The revision of the checkout.
public let revision: Revision
Expand Down Expand Up @@ -47,25 +47,27 @@ public struct CheckoutState: Equatable, CustomStringConvertible {
self.init(revision: revision, version: version, branch: nil)
}

public var description: String {
return version?.description ?? branch ?? revision.identifier
}

public var isBranchOrRevisionBased: Bool {
return version == nil
}
}

extension CheckoutState {

/// Returns requirement induced by this state.
public func requirement() -> PackageRequirement {
public var requirement: PackageRequirement {
if let version = version {
return .versionSet(.exact(version))
} else if let branch = branch {
return .revision(branch)
} else {
return .revision(revision.identifier)
}
return .revision(revision.identifier)
}
}

// MARK: - CustomStringConvertible

extension CheckoutState: CustomStringConvertible {
public var description: String {
return version?.description ?? branch ?? revision.identifier
}
}

Expand Down
135 changes: 135 additions & 0 deletions Sources/PackageGraph/DependencyResolutionNode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2014 - 2020 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 Swift project authors
*/

import TSCBasic
import PackageModel
import struct TSCUtility.Version

/// A node in the dependency resolution graph.
///
/// See the documentation of each case for more detailed descriptions of each kind and how they interact.
///
/// - SeeAlso: `GraphLoadingNode`
public enum DependencyResolutionNode {

/// An empty package node.
///
/// This node indicates that a package needs to be present, but does not indicate that any of its contents are needed.
///
/// Empty package nodes are always leaf nodes; they have no dependencies.
case empty(package: PackageReference)

/// A product node.
///
/// This node indicates that a particular product in a particular package is required.
///
/// Product nodes always have dependencies. A product node has...
///
/// - one implicit dependency on its own package at an exact version (as an empty package node).
/// This dependency is what ensures the resolver does not select two products from the same package at different versions.
/// - zero or more dependencies on the product nodes of other packages.
/// These are all the external products required to build all of the targets vended by this product.
/// They derive from the manifest.
///
/// Tools versions before 5.2 do not know which products belong to which packages, so each product is required from every dependency.
/// Since a non‐existant product ends up with only its implicit dependency on its own package,
/// only whichever package contains the product will end up adding additional constraints.
/// See `ProductFilter` and `Manifest.register(...)`.
case product(String, package: PackageReference)

/// A root node.
///
/// This node indicates a root node in the graph, which is required no matter what.
///
/// Root nodes may have dependencies. A root node has...
///
/// - zero or more dependencies on each external product node required to build any of its targets (vended or not).
/// - zero or more dependencies directly on external empty package nodes.
/// This special case occurs when a dependecy is declared but not used.
/// It is a warning condition, and builds do not actually need these dependencies.
/// However, forcing the graph to resolve and fetch them anyway allows the diagnostics passes access
/// to the information needed in order to provide actionable suggestions to help the user stitch up the dependency declarations properly.
case root(package: PackageReference)

/// The package.
public var package: PackageReference {
switch self {
case .empty(let package), .product(_, let package), .root(let package):
return package
}
}

/// The name of the specific product if the node is a product node, otherwise `nil`.
public var specificProduct: String? {
switch self {
case .empty, .root:
return nil
case .product(let product, _):
return product
}
}

/// Assembles the product filter to use on the manifest for this node to determine its dependencies.
public var productFilter: ProductFilter {
switch self {
case .empty:
return .specific([])
case .product(let product, _):
return .specific([product])
case .root:
return .everything
}
}

/// Returns the dependency that a product has on its own package, if relevant.
///
/// This is the constraint that requires all products from a package resolve to the same version.
internal func versionLock(version: Version) -> RepositoryPackageConstraint? {
// Don’t create a version lock for anything but a product.
guard specificProduct != nil else { return nil }
return RepositoryPackageConstraint(
container: package,
versionRequirement: .exact(version),
products: .specific([])
)
}

/// Returns the dependency that a product has on its own package, if relevant.
///
/// This is the constraint that requires all products from a package resolve to the same revision.
internal func revisionLock(revision: String) -> RepositoryPackageConstraint? {
// Don’t create a revision lock for anything but a product.
guard specificProduct != nil else { return nil }
return RepositoryPackageConstraint(
container: package,
requirement: .revision(revision),
products: .specific([])
)
}
}

extension DependencyResolutionNode: Equatable {
public static func ==(lhs: DependencyResolutionNode, rhs: DependencyResolutionNode) -> Bool {
return (lhs.package, lhs.specificProduct) == (rhs.package, rhs.specificProduct)
}
}

extension DependencyResolutionNode: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(package)
hasher.combine(specificProduct)
}
}

extension DependencyResolutionNode: CustomStringConvertible {
public var description: String {
return "\(package.name)\(productFilter)"
}
}
Loading