Skip to content

improve correctness by using identity more broadly throughout the code #3244

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 1 commit into from
Feb 12, 2021

Conversation

tomerd
Copy link
Contributor

@tomerd tomerd commented Feb 8, 2021

motivation: improve correctness by using identity more broadly throughout the code, prepare to package registry

changes:

  • refector as PackageDependencyDescription with "scm" and "local" cases, this reflects better the true meaning and associated data with the two options and prepares us to adding a third option for registry
  • create new abstraction IdentityResolver, with default implementation that follows existing identity resolution logic
  • move mirror logic into IdentityResolver, and simplify code that used mirrors
  • move all logic to generate identity, apply mirrors to PackageDependencyDescription so it is handles as soon as possible in the call stack
  • adjust call-sites
  • adjust and add tests for mirror

builds on #3239 and #3240 so lets merge those first

@tomerd tomerd force-pushed the refactor/identity04 branch 2 times, most recently from eea65aa to ad5a33c Compare February 8, 2021 04:36
@tomerd
Copy link
Contributor Author

tomerd commented Feb 8, 2021

@swift-ci please smoke test

import TSCBasic
import PackageModel

// TODO: refactor this when adding registry support
Copy link
Contributor Author

Choose a reason for hiding this comment

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

👀

let isBaseURLRemote = URL.scheme(packageLocation) != nil

func fixLocation(_ location: String, requirement: Requirement) throws -> String {
fileprivate init(
Copy link
Contributor Author

@tomerd tomerd Feb 8, 2021

Choose a reason for hiding this comment

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

👀 this is the key change, the logic to address identity resolution d location remapping (aka mirrors) moved to the constructor of the PackageDependencyDescription which is the earliest time and makes the rest of the code simpler can it assume the dependency identity and location is correct

@@ -11,15 +11,33 @@
import TSCBasic

/// Represents a package dependency.
public struct PackageDependencyDescription: Equatable, Codable, Hashable {
public enum PackageDependencyDescription: Equatable {
Copy link
Contributor Author

@tomerd tomerd Feb 8, 2021

Choose a reason for hiding this comment

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

👀 this is the other key change: PackageDependencyDescription is now and enum with two cases: local and git. the idea is to model the data more accurately instead of the a struct that has fields that are reused with different meaning and make reasoning in downstream harder. As we get closer with the registry, we will add a 3rd option registry with its own payload.

Copy link
Contributor

Choose a reason for hiding this comment

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

The one drawback (since enums can't have stored properties) is that common properties have to be replicated across the payloads. I don't think this is a problem but another way that might make sense would be to separate out the reference type as an enum (path, git repo, registry), which would also make clear what is common to all packages (e.g. identity and filter) but leaving the specifics of the reference type to the enum. Just a thought.

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, this is the tradeoff here. i went with creating computed properties for the shared properties since its not a big price to pay, and the price is paid only once in PackageDependencyDescription itself, keeping the call-sites nice and clean. if we split the properties across the associated values and and some "type" enum, the call-sites would have to know how to access the properties so the code in PackageDependencyDescription would be cleaner but the call-sites "uglier"

Copy link
Contributor

@abertelrud abertelrud Feb 9, 2021

Choose a reason for hiding this comment

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

Agreed. Overall it's a good tradeoff. I expect it to be very rare to have to add enum cases here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

my thoughts exactly

public let name: String
// FIXME: we should simplify target based dependencies such that this is no longer required
// A name to be used *only* for target dependencies resolution
public var nameForTargetDependencyResolutionOnly: String {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

renamed this so its obvious what its only fo


/// The dependency requirement.
public enum Requirement: Equatable, Hashable {
case exact(Version)
case range(Range<Version>)
case revision(String)
case branch(String)
case localPackage
Copy link
Contributor Author

Choose a reason for hiding this comment

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

a nice side effect of the move to enum is that we can get rid of localPackage as kind of requirement which seems unnatural

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed, that was always odd.

@@ -1309,6 +1309,7 @@ extension Workspace {
/// This will load the manifests for the root package as well as all the
/// current dependencies from the working checkouts.
// @testable internal
// FIXME: this logic should be changed to use identity instead of location once identity is unique
Copy link
Contributor Author

@tomerd tomerd Feb 8, 2021

Choose a reason for hiding this comment

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

this is the next step in the identity cleanup journey, but before its unique we need to keep using locations here :(

@@ -65,4 +65,62 @@ class DependencyResolutionTests: XCTestCase {
XCTAssertEqual(output, "♣︎K\n♣︎Q\n♣︎J\n♣︎10\n♣︎9\n♣︎8\n♣︎7\n♣︎6\n♣︎5\n♣︎4\n")
}
}

func testMirrors() {
Copy link
Contributor Author

@tomerd tomerd Feb 8, 2021

Choose a reason for hiding this comment

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

😅

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, was there no test at all before?!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

there was a test that uses all mocks, no end-to-end test

@tomerd
Copy link
Contributor Author

tomerd commented Feb 8, 2021

@swift-ci please smoke test

@tomerd tomerd self-assigned this Feb 8, 2021
Copy link
Contributor

@abertelrud abertelrud left a comment

Choose a reason for hiding this comment

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

This is great! Just had a question/suggestion for PackageDependencyDescription but this looks good.

public protocol IdentityResolver {
func resolveIdentity(for location: String) -> PackageIdentity
func resolveIdentity(for path: AbsolutePath) -> PackageIdentity
func resolveLocation(from location: String) -> String
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this String because it could be either path or URL or identity?

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, I was contemplating moving to URL as well but wanted to minimize changes so kept String for now. We could/should revisiting this in follow-up PRs

Copy link
Contributor

Choose a reason for hiding this comment

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

Great, that seems like a good choice (keeping PRs incremental)

// If the dependency URL starts with '~/', try to expand it.
return fileSystem.homeDirectory.appending(RelativePath(String(dependencyLocation.dropFirst(2)))).pathString
} else if dependencyLocation.hasPrefix(filePrefix) {
// FIXME: SwiftPM can't handle file locations with file:// scheme so we need to
Copy link
Contributor

Choose a reason for hiding this comment

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

Right, in particular, file:// is treated as a remote package whose repo just happens to be in the local file system.

public struct Git: Equatable, Codable {
public let identity: PackageIdentity
public let name: String?
public let location: String
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this always a URL in this case? Would it make sense to use URL, or rather keep as String?


/// The dependency requirement.
public enum Requirement: Equatable, Hashable {
case exact(Version)
case range(Range<Version>)
case revision(String)
case branch(String)
case localPackage
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed, that was always odd.

@@ -11,15 +11,33 @@
import TSCBasic

/// Represents a package dependency.
public struct PackageDependencyDescription: Equatable, Codable, Hashable {
public enum PackageDependencyDescription: Equatable {
Copy link
Contributor

Choose a reason for hiding this comment

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

The one drawback (since enums can't have stored properties) is that common properties have to be replicated across the payloads. I don't think this is a problem but another way that might make sense would be to separate out the reference type as an enum (path, git repo, registry), which would also make clear what is common to all packages (e.g. identity and filter) but leaving the specifics of the reference type to the enum. Just a thought.

/// - SeeAlso: `explicitName`
/// - SeeAlso: `url`
public let name: String
// FIXME: we should simplify target based dependencies such that this is no longer required
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed.

@@ -65,4 +65,62 @@ class DependencyResolutionTests: XCTestCase {
XCTAssertEqual(output, "♣︎K\n♣︎Q\n♣︎J\n♣︎10\n♣︎9\n♣︎8\n♣︎7\n♣︎6\n♣︎5\n♣︎4\n")
}
}

func testMirrors() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, was there no test at all before?!

@tomerd
Copy link
Contributor Author

tomerd commented Feb 9, 2021

@swift-ci please smoke test

@tomerd tomerd force-pushed the refactor/identity04 branch from c613001 to 5965575 Compare February 9, 2021 02:13
@tomerd tomerd changed the title Refactor/identity04 improve correctness by using identity more broadly throughout the code Feb 9, 2021
@tomerd
Copy link
Contributor Author

tomerd commented Feb 9, 2021

@swift-ci please smoke test

@tomerd
Copy link
Contributor Author

tomerd commented Feb 9, 2021

@neonichu lmk what you think

@tomerd tomerd changed the title improve correctness by using identity more broadly throughout the code improve correctness by using identity more broadly throughout the code Feb 9, 2021
@tomerd tomerd force-pushed the refactor/identity04 branch from 5965575 to 9aef406 Compare February 11, 2021 21:31
motivation: improve correctness by using identity more broadly throughout the code, prepare to package registry

changes:
* refector as PackageDependencyDescription with "scm" and "local" cases, this reflects better the true meaning and associated data with the two options and prepares us to adding a third option for registry
* create new abstraction IdentityResolver, with default implementation that follows existing identity resolution logic
* move mirror logic into IdentityResolver, and simplify code that used mirrors
* move all logic to generate identity, apply mirrors to PackageDependencyDescription so it is handles as soon as possible in the call stack
* adjust call-sites
* adjust and add tests for mirror
@tomerd tomerd force-pushed the refactor/identity04 branch from 9aef406 to e77f4ae Compare February 11, 2021 21:33
@tomerd
Copy link
Contributor Author

tomerd commented Feb 11, 2021

@swift-ci please smoke test

@tomerd
Copy link
Contributor Author

tomerd commented Feb 11, 2021

@neonichu renamed git to scm as per your feedback

@tomerd
Copy link
Contributor Author

tomerd commented Feb 11, 2021

@swift-ci please smoke test macOS

1 similar comment
@tomerd
Copy link
Contributor Author

tomerd commented Feb 12, 2021

@swift-ci please smoke test macOS

@tomerd tomerd merged commit 5667965 into swiftlang:main Feb 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants