File: PackageContainer.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (209 lines) | stat: -rw-r--r-- 8,154 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift 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 the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import Basics
import Dispatch
import PackageModel

import struct TSCUtility.Version

/// A container of packages.
///
/// This is the top-level unit of package resolution, i.e. the unit at which
/// versions are associated.
///
/// It represents a package container (e.g., a source repository) which can be
/// identified unambiguously and which contains a set of available package
/// versions and the ability to retrieve the dependency constraints for each of
/// those versions.
///
/// We use the "container" terminology here to differentiate between two
/// conceptual notions of what the package is: (1) informally, the repository
/// containing the package, but from which a package cannot be loaded by itself
/// and (2) the repository at a particular version, at which point the package
/// can be loaded and dependencies enumerated.
///
/// This is also designed in such a way to extend naturally to multiple packages
/// being contained within a single repository, should we choose to support that
/// later.
public protocol PackageContainer {

    /// The identifier for the package.
    var package: PackageReference { get }

    var shouldInvalidatePinnedVersions: Bool { get }

    /// Returns true if the tools version is compatible at the given version.
    func isToolsVersionCompatible(at version: Version) -> Bool

    /// Returns the tools version for the given version
    func toolsVersion(for version: Version) throws -> ToolsVersion

    /// Get the list of versions which are available for the package.
    ///
    /// The list will be returned in sorted order, with the latest version *first*.
    /// All versions will not be requested at once. Resolver will request the next one only
    /// if the previous one did not satisfy all constraints.
    func toolsVersionsAppropriateVersionsDescending() throws -> [Version]

    /// Get the list of versions in the repository sorted in the ascending order, that is the earliest
    /// version appears first.
    func versionsAscending() throws -> [Version]

    /// Get the list of versions in the repository sorted in the descending order, that is the latest
    /// version appears first.
    func versionsDescending() throws -> [Version]

    // FIXME: We should perhaps define some particularly useful error codes
    // here, so the resolver can handle errors more meaningfully.
    //
    /// Fetch the declared dependencies for a particular version.
    ///
    /// This property is expected to be efficient to access, and cached by the
    /// client if necessary.
    ///
    /// - Precondition: `versions.contains(version)`
    /// - Throws: If the version could not be resolved; this will abort
    ///   dependency resolution completely.
    func getDependencies(at version: Version, productFilter: ProductFilter) throws -> [PackageContainerConstraint]

    /// Fetch the declared dependencies for a particular revision.
    ///
    /// This property is expected to be efficient to access, and cached by the
    /// client if necessary.
    ///
    /// - Throws: If the revision could not be resolved; this will abort
    ///   dependency resolution completely.
    func getDependencies(at revision: String, productFilter: ProductFilter) throws -> [PackageContainerConstraint]

    /// Fetch the dependencies of an unversioned package container.
    ///
    /// NOTE: This method should not be called on a versioned container.
    func getUnversionedDependencies(productFilter: ProductFilter) throws -> [PackageContainerConstraint]

    /// Get the updated identifier at a bound version.
    ///
    /// This can be used by the containers to fill in the missing information that is obtained
    /// after the container is available. The updated identifier is returned in result of the
    /// dependency resolution.
    func loadPackageReference(at boundVersion: BoundVersion) throws -> PackageReference
}

extension PackageContainer {
    public func reversedVersions() throws -> [Version] {
        try self.versionsDescending()
    }

    public func versionsDescending() throws -> [Version] {
        try self.versionsAscending().reversed()
    }

    public var shouldInvalidatePinnedVersions: Bool {
        return true
    }
}

public protocol CustomPackageContainer: PackageContainer {
    /// Retrieve the package using this package container.
    func retrieve(
       at version: Version,
       progressHandler: ((_ bytesReceived: Int64, _ totalBytes: Int64?) -> Void)?,
       observabilityScope: ObservabilityScope
    ) throws -> AbsolutePath

    /// Get the custom file system for this package container.
    func getFileSystem() throws -> FileSystem?
}

public extension CustomPackageContainer {
    func retrieve(at version: Version, observabilityScope: ObservabilityScope) throws -> AbsolutePath {
        return try self.retrieve(at: version, progressHandler: .none, observabilityScope: observabilityScope)
    }
}

// MARK: - PackageContainerConstraint

/// An individual constraint onto a container.
public struct PackageContainerConstraint: Equatable, Hashable {

    /// The identifier for the container the constraint is on.
    public let package: PackageReference

    /// The constraint requirement.
    public let requirement: PackageRequirement

    /// The required products.
    public let products: ProductFilter

    /// Create a constraint requiring the given `container` satisfying the
    /// `requirement`.
    public init(package: PackageReference, requirement: PackageRequirement, products: ProductFilter) {
        self.package = package
        self.requirement = requirement
        self.products = products
    }

    /// Create a constraint requiring the given `container` satisfying the
    /// `versionRequirement`.
    public init(package: PackageReference, versionRequirement: VersionSetSpecifier, products: ProductFilter) {
        self.init(package: package, requirement: .versionSet(versionRequirement), products: products)
    }
}

extension PackageContainerConstraint: CustomStringConvertible {
    public var description: String {
        return "Constraint(\(self.package), \(requirement), \(products)"
    }
}

// MARK: - PackageContainerProvider

/// An interface for resolving package containers.
public protocol PackageContainerProvider {
    /// Get the container for a particular identifier asynchronously.

    @available(*, noasync, message: "Use the async alternative")
    func getContainer(
        for package: PackageReference,
        updateStrategy: ContainerUpdateStrategy,
        observabilityScope: ObservabilityScope,
        on queue: DispatchQueue,
        completion: @escaping (Result<PackageContainer, Error>) -> Void
    )
}

public extension PackageContainerProvider {
    func getContainer(
        for package: PackageReference,
        updateStrategy: ContainerUpdateStrategy,
        observabilityScope: ObservabilityScope,
        on queue: DispatchQueue
    ) async throws -> PackageContainer {
        try await safe_async {
            self.getContainer(
                for: package,
                updateStrategy: updateStrategy,
                observabilityScope: observabilityScope,
                on: queue,
                completion: $0)
        }
    }
}

/// Only used for source control containers and as such a mirror of RepositoryUpdateStrategy
/// This duplication is unfortunate - ideally this is not a concern of the ContainerProvider at all
/// but it is required give how PackageContainerProvider currently integrated into the resolver
public enum ContainerUpdateStrategy {
    case never
    case always
    case ifNeeded(revision: String)
}