Skip to content

refactor location abstractions #3764

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 6 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Sources/Commands/APIDigester.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ struct APIDigesterBaselineDumper {

// Clone the current package in a sandbox and checkout the baseline revision.
let repositoryProvider = GitRepositoryProvider()
let specifier = RepositorySpecifier(url: baselinePackageRoot.pathString)
let specifier = RepositorySpecifier(path: baselinePackageRoot)
let workingCopy = try repositoryProvider.createWorkingCopy(
repository: specifier,
sourcePath: packageRoot,
Expand Down
7 changes: 6 additions & 1 deletion Sources/Commands/Describe.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,12 @@ fileprivate struct DescribedPackage: Encodable {
case .fileSystem(let settings):
self = .fileSystem(identity: settings.identity, path: settings.path)
case .sourceControl(let settings):
self = .sourceControl(identity: settings.identity, location: settings.location, requirement: settings.requirement)
switch settings.location {
case .local(let path):
self = .sourceControl(identity: settings.identity, location: path.pathString, requirement: settings.requirement)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we do a follow-on to separate out the described location similarly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we could, less critical at this point imo

Copy link
Contributor

@abertelrud abertelrud Sep 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, absolutely less critical.

case .remote(let url):
self = .sourceControl(identity: settings.identity, location: url.absoluteString, requirement: settings.requirement)
}
case .registry(let settings):
self = .registry(identity: settings.identity, requirement: settings.requirement)
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/Commands/SwiftPackageCollectionsTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,10 @@ public struct SwiftPackageCollectionsTool: ParsableCommand {

mutating func run() throws {
try with { collections in
let identity = PackageIdentity(url: packageURL)
let identity = PackageIdentity(urlString: self.packageURL)

do { // assume URL is for a package in an imported collection
let result = try tsc_await { collections.getPackageMetadata(identity: identity, location: packageURL, callback: $0) }
let result = try tsc_await { collections.getPackageMetadata(identity: identity, location: self.packageURL, callback: $0) }

if let versionString = version {
guard let version = TSCUtility.Version(versionString), let result = result.package.versions.first(where: { $0.version == version }), let printedResult = printVersion(result) else {
Expand Down
2 changes: 2 additions & 0 deletions Sources/PackageCollections/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public protocol PackageCollectionsProtocol {
/// - Parameters:
/// - reference: The package reference
/// - callback: The closure to invoke when result becomes available
// deprecated 9/21
@available(*, deprecated, message: "user getPackageMetadata(identity:) instead")
func getPackageMetadata(
_ reference: PackageReference,
Expand All @@ -127,6 +128,7 @@ public protocol PackageCollectionsProtocol {
/// - collections: Optional. If specified, only look for package in these collections. Data from the most recently
/// processed collection will be used.
/// - callback: The closure to invoke when result becomes available
// deprecated 9/21
@available(*, deprecated, message: "user getPackageMetadata(identity:) instead")
func getPackageMetadata(
_ reference: PackageReference,
Expand Down
12 changes: 10 additions & 2 deletions Sources/PackageCollections/Model/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,22 @@ extension PackageCollectionsModel {
/// The package's programming languages
public let languages: Set<String>?

// deprecated 9/21
@available(*, deprecated, message: "use identity and location instead")
public var reference: PackageReference {
return .init(identity: self.identity, kind: .remote, location: self.location, name: nil)
guard let url = URL(string: self.location) else {
fatalError("invalid url \(self.location)")
}
return .init(identity: self.identity, kind: .remoteSourceControl(url), name: nil)
}

// deprecated 9/21
@available(*, deprecated, message: "use identity and location instead")
public var repository: RepositorySpecifier {
return .init(url: self.location)
guard let url = URL(string: self.location) else {
fatalError("invalid url \(self.location)")
}
return .init(url: url)
}

/// Initializes a `Package`
Expand Down
5 changes: 4 additions & 1 deletion Sources/PackageCollections/Model/TargetListResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ extension PackageCollectionsModel.TargetListResult {

@available(*, deprecated, message: "use identity and location instead")
public var repository: RepositorySpecifier {
return .init(url: self.location)
guard let url = URL(string: self.location) else {
fatalError("invalid url \(self.location)")
}
return .init(url: url)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ extension PackageCollectionModel.V1 {

// TODO: validate package url?
private func validate(package: Collection.Package, messages: inout [ValidationMessage]) {
let packageID = PackageIdentity(url: package.url.absoluteString).description
let packageID = PackageIdentity(url: package.url).description

guard !package.versions.isEmpty else {
messages.append(.error("Package \(packageID) does not have any versions.", property: "package.versions"))
Expand Down
2 changes: 2 additions & 0 deletions Sources/PackageCollections/PackageCollections.swift
Original file line number Diff line number Diff line change
Expand Up @@ -341,12 +341,14 @@ public struct PackageCollections: PackageCollectionsProtocol {

// MARK: - Package Metadata

// deprecated 9/21
@available(*, deprecated, message: "user identity based API instead")
public func getPackageMetadata(_ reference: PackageReference,
callback: @escaping (Result<PackageCollectionsModel.PackageMetadata, Error>) -> Void) {
self.getPackageMetadata(reference, collections: nil, callback: callback)
}

// deprecated 9/21
@available(*, deprecated, message: "user identity based API instead")
public func getPackageMetadata(_ reference: PackageReference,
collections: Set<PackageCollectionsModel.CollectionIdentifier>?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ struct GitHubPackageMetadataProvider: PackageMetadataProvider {
}
}

// FIXME: use Foundation.URL instead of string
internal static func apiURL(_ url: String) -> Foundation.URL? {
do {
let regex = try NSRegularExpression(pattern: #"([^/@]+)[:/]([^:/]+)/([^/.]+)(\.git)?$"#, options: .caseInsensitive)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ struct JSONPackageCollectionProvider: PackageCollectionProvider {
serializationOkay = false
}

return .init(identity: .init(url: package.url.absoluteString),
return .init(identity: .init(url: package.url),
location: package.url.absoluteString,
summary: package.summary,
keywords: package.keywords,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
while let row = try statement.step() {
if let collectionData = Data(base64Encoded: row.string(at: 0)),
let collection = try? self.decoder.decode(Model.CollectionIdentifier.self, from: collectionData) {
matches.append((collection: collection, package: PackageIdentity(url: row.string(at: 1))))
matches.append((collection: collection, package: PackageIdentity(urlString: row.string(at: 1))))
matchingCollections.insert(collection)
}
}
Expand Down Expand Up @@ -425,7 +425,7 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
while let row = try statement.step() {
if let collectionData = Data(base64Encoded: row.string(at: 0)),
let collection = try? self.decoder.decode(Model.CollectionIdentifier.self, from: collectionData) {
matches.append((collection: collection, package: PackageIdentity(url: row.string(at: 1))))
matches.append((collection: collection, package: PackageIdentity(urlString: row.string(at: 1))))
matchingCollections.insert(collection)
}
}
Expand Down Expand Up @@ -575,7 +575,7 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
let collection = try? self.decoder.decode(Model.CollectionIdentifier.self, from: collectionData) {
matches.append((
collection: collection,
package: PackageIdentity(url: row.string(at: 1)),
package: PackageIdentity(urlString: row.string(at: 1)),
targetName: row.string(at: 2)
))
matchingCollections.insert(collection)
Expand Down Expand Up @@ -859,7 +859,7 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable

if let collectionData = Data(base64Encoded: row.string(at: 0)),
let collection = try? self.decoder.decode(Model.CollectionIdentifier.self, from: collectionData) {
let collectionPackage = CollectionPackage(collection: collection, package: PackageIdentity(url: row.string(at: 1)))
let collectionPackage = CollectionPackage(collection: collection, package: PackageIdentity(urlString: row.string(at: 1)))
self.targetTrie.insert(word: targetName.lowercased(), foundIn: collectionPackage)
}
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/PackageGraph/DependencyResolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ public struct TracingDependencyResolverDelegate: DependencyResolverDelegate {
}

public func willResolve(term: Term) {
self.log("resolving: \(term.node.package.location)")
self.log("resolving: \(term.node.package.identity)")
}

public func didResolve(term: Term, version: Version, duration: DispatchTimeInterval) {
self.log("resolved: \(term.node.package.location) @ \(version)")
self.log("resolved: \(term.node.package.identity) @ \(version)")
}

public func derived(term: Term) {
self.log("derived: \(term.node.package.location)")
self.log("derived: \(term.node.package.identity)")
}

public func conflict(conflict: Incompatibility) {
Expand Down
30 changes: 22 additions & 8 deletions Sources/PackageGraph/LocalPackageContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import TSCUtility
///
/// This class represent packages that are referenced locally in the file system.
/// There is no need to perform any git operations on such packages and they
/// should be used as-is. Infact, they might not even have a git repository.
/// should be used as-is. In fact, they might not even have a git repository.
/// Examples: Root packages, local dependencies, edited packages.
public final class LocalPackageContainer: PackageContainer {
public let package: PackageReference
Expand All @@ -30,27 +30,35 @@ public final class LocalPackageContainer: PackageContainer {
private let toolsVersionLoader: ToolsVersionLoaderProtocol
private let currentToolsVersion: ToolsVersion

/// The file system that shoud be used to load this package.
/// The file system that should be used to load this package.
private let fileSystem: FileSystem

/// cached version of the manifest
private let manifest = ThreadSafeBox<Manifest>()

private func loadManifest() throws -> Manifest {
try manifest.memoize() {
let path: AbsolutePath
switch self.package.kind {
case .root(let _path), .fileSystem(let _path):
path = _path
default:
throw InternalError("invalid package type \(package.kind)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add the package identity to the message here (or is it perhaps already part of the metadata?). That would make it much easier to try to figure out errors coming in from the field that have this message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. this is an internal error so a programmer error and not user one, so less important IMO

}

// Load the tools version.
let toolsVersion = try self.toolsVersionLoader.load(at: AbsolutePath(self.package.location), fileSystem: self.fileSystem)
let toolsVersion = try self.toolsVersionLoader.load(at: path, fileSystem: self.fileSystem)

// Validate the tools version.
try toolsVersion.validateToolsVersion(self.currentToolsVersion, packageIdentity: self.package.identity)

// Load the manifest.
// FIXME: this should not block
return try temp_await {
manifestLoader.load(at: AbsolutePath(self.package.location),
manifestLoader.load(at: path,
packageIdentity: self.package.identity,
packageKind: self.package.kind,
packageLocation: self.package.location,
packageLocation: path.pathString,
version: nil,
revision: nil,
toolsVersion: toolsVersion,
Expand Down Expand Up @@ -80,8 +88,14 @@ public final class LocalPackageContainer: PackageContainer {
toolsVersionLoader: ToolsVersionLoaderProtocol,
currentToolsVersion: ToolsVersion,
fileSystem: FileSystem = localFileSystem
) {
assert(URL.scheme(package.location) == nil, "unexpected scheme \(URL.scheme(package.location)!) in \(package.location)")
) throws {
//assert(URL.scheme(package.location) == nil, "unexpected scheme \(URL.scheme(package.location)!) in \(package.location)")
switch package.kind {
case .root, .fileSystem:
break
default:
throw InternalError("invalid package type \(package.kind)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as the other message. If it's already part of the context for whatever handler wraps this call, so it will show up as metadata for a diagnostic, then that's even better.

}
self.package = package
self.identityResolver = identityResolver
self.manifestLoader = manifestLoader
Expand Down Expand Up @@ -117,6 +131,6 @@ public final class LocalPackageContainer: PackageContainer {

extension LocalPackageContainer: CustomStringConvertible {
public var description: String {
return "LocalPackageContainer(\(package.location))"
return "LocalPackageContainer(\(self.package.identity))"
}
}
15 changes: 10 additions & 5 deletions Sources/PackageGraph/PackageGraph+Loading.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ extension PackageGraph {

// Create a map of the manifests, keyed by their identity.
let rootManifestsMap = root.manifests
let externalManifestsMap = externalManifests.map{ (identityResolver.resolveIdentity(for: $0.packageLocation), $0) }
let externalManifestsMap = try externalManifests.map{ (try identityResolver.resolveIdentity(for: $0.packageKind), $0) }
let manifestMap = rootManifestsMap.merging(externalManifestsMap, uniquingKeysWith: { lhs, rhs in
return lhs
})
Expand Down Expand Up @@ -116,7 +116,7 @@ extension PackageGraph {
binaryArtifacts: binaryArtifacts,
xcTestMinimumDeploymentTargets: xcTestMinimumDeploymentTargets,
shouldCreateMultipleTestProducts: shouldCreateMultipleTestProducts,
createREPLProduct: manifest.packageKind == .root ? createREPLProduct : false,
createREPLProduct: manifest.packageKind.isRoot ? createREPLProduct : false,
fileSystem: fileSystem
)
let package = try builder.construct()
Expand All @@ -125,7 +125,7 @@ extension PackageGraph {
// Throw if any of the non-root package is empty.
if package.targets.isEmpty // System packages have targets in the package but not the manifest.
&& package.manifest.targets.isEmpty // An unneeded dependency will not have loaded anything from the manifest.
&& manifest.packageKind != .root {
&& !manifest.packageKind.isRoot {
throw PackageGraphError.noModules(package)
}
}
Expand Down Expand Up @@ -204,7 +204,7 @@ private func createResolvedPackages(
guard let package = manifestToPackage[node.manifest] else {
return nil
}
let isAllowedToVendUnsafeProducts = unsafeAllowedPackages.contains{ $0.location == package.manifest.packageLocation }
let isAllowedToVendUnsafeProducts = unsafeAllowedPackages.contains{ $0.identity == package.identity }
let allowedToOverride = rootManifestSet.contains(node.manifest)
return ResolvedPackageBuilder(
package,
Expand Down Expand Up @@ -240,7 +240,12 @@ private func createResolvedPackages(
case .fileSystem(let settings):
dependencyLocation = settings.path.pathString
case .sourceControl(let settings):
dependencyLocation = settings.location
switch settings.location {
case .local(let path):
dependencyLocation = path.pathString
case .remote(let url):
dependencyLocation = url.absoluteString
}
case .registry:
// FIXME
fatalError("registry based dependencies not implemented yet")
Expand Down
18 changes: 8 additions & 10 deletions Sources/PackageGraph/PackageModel+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,21 @@ extension PackageDependency {
public func createPackageRef() -> PackageReference {
// TODO (next steps): move the location into PackageKind to preserve path vs. location
let packageKind: PackageReference.Kind
let location: String
switch self {
case .fileSystem(let settings):
packageKind = .local
location = settings.path.pathString
packageKind = .fileSystem(settings.path)
case .sourceControl(let settings):
packageKind = .remote
location = settings.location
switch settings.location {
case .local(let path):
packageKind = .localSourceControl(path)
case .remote(let url):
packageKind = .remoteSourceControl(url)
}
case .registry:
// FIXME
fatalError("registry based dependencies not implemented yet")
}
return PackageReference(
identity: self.identity,
kind: packageKind,
location: location
)
return PackageReference(identity: self.identity, kind: packageKind)
}
}

Expand Down
Loading