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

[SR-7836] Added swift package update --dry-run #2380

Merged
merged 3 commits into from Oct 31, 2019
Merged

[SR-7836] Added swift package update --dry-run #2380

merged 3 commits into from Oct 31, 2019

Conversation

tgymnich
Copy link
Contributor

  • Added swift package --dry-run
  • Added prettyPrinted to Requirement
  • Added test


guard !dryRun else {
let changes = diagnostics.wrap { return try computePackageStateChanges(root: graphRoot, resolvedDependencies: updateResults, updateBranches: true) } ?? []
logPackageChanges(changes: changes, pins: pinsStore)
Copy link
Member

Choose a reason for hiding this comment

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

Workspace is a high-level library so it'll be better if we return a structured object from here. Clients can then do whatever they want with the object. In this particular case, maybe you can accept an inout array to fill for dry run.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great idea! I think it looks way better than splitting updateDependencies into updateDependencies and updateDependenciesDryRun

@ankitspd
Copy link
Member

Thanks! This is great. I left some comments inline

}
stream <<< "\n"
}
stream.flush()
Copy link
Member

Choose a reason for hiding this comment

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

Can you post what an example output looks like? Just curious!

Copy link
Contributor Author

@tgymnich tgymnich Oct 16, 2019

Choose a reason for hiding this comment

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

2019-10-16 13:21:43.723885+0200 swift-package[53147:783737] [default] Starting resolution using pubgrub resolver
Updating https://github.com/attaswift/BigInt.git
Updating https://github.com/apple/swift-protobuf.git

3 dependencies have changed:
+ SwiftProtobuf 1.7.0
~ BigInt 4.0.0 -> BigInt 5.0.0
- swift-nio 2.8.0
Program ended with exit code: 0

@@ -69,6 +69,26 @@ final class PackageToolTests: XCTestCase {
XCTAssertEqual(GitRepository(path: path).tags, ["1.2.3", "1.2.4"])
}
}

func testUpdateDryRun() throws {
Copy link
Member

Choose a reason for hiding this comment

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

It would be better if you can write a unit test since they're much much faster to run. You can see WorkspaceTests.swift for examples. Don't worry about it if it's turning out to be too hard.

@ankitspd
Copy link
Member

Hey @TG908. I ended up being a bit busier than usual this week but I hope to re-review the PR early next week.

} else if let pinsStore = diagnostics.wrap({ try workspace.pinsStore.load() }),
let changes = try workspace.updateDependenciesDryRun(
root: getWorkspaceRoot(),
diagnostics: diagnostics) {
Copy link
Member

Choose a reason for hiding this comment

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

Didn't we discuss passing an inout array to get the changes? Any particular reason for switching to a new method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since I had to create a new method due to API stability anyway, I chose to use a return value instead of inout because I think the in part of inout would never be used.

Copy link
Member

@ankitspd ankitspd Oct 28, 2019

Choose a reason for hiding this comment

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

I was thinking the parameter would default to nil and we'd use the in part to determine if this is a dry run operation. Something like:

public func updateDependencies(
  root: PackageGraphRootInput,
  dryRunResults: [Result]? = nil
  diagnostics: DiagnosticsEngine
) {
...

  // Fill the dry run results array if one is provided and return without performing the actual update.
  if dryRunResults != nil {
    dryRunResults = updateResults
    return
  }
...
}

Copy link
Contributor Author

@tgymnich tgymnich Oct 28, 2019

Choose a reason for hiding this comment

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

This won't work in swift 5.1 inout parameters cannot have a default value.

Copy link
Member

Choose a reason for hiding this comment

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

Ah. What if we add a specialized method ourselves?

public func updateDependencies(
  root: PackageGraphRootInput,
  diagnostics: DiagnosticsEngine
) {
  updateDependencies(root: root, dryRunResults: nil, diagnostics: diagnostics)
}

public func updateDependencies(
  root: PackageGraphRootInput,
  dryRunResults: [Result]?,
  diagnostics: DiagnosticsEngine
) {
...
}

Copy link
Contributor Author

@tgymnich tgymnich Oct 28, 2019

Choose a reason for hiding this comment

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

Is it obvious to someone reading the code for the first time that passing a dry run array causes the actual update not to happen?

Without reading the documentation it is more obvious that the method updateDependencies performs an actual update and updateDependenciesDryRun does not.

Copy link
Member

Choose a reason for hiding this comment

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

You're right, it's not very obvious especially for API consumers. What if we always return the update result and make this method @discardableResult? Then this method could just take a simple Bool dryRun.

- Added swift package --dry-run
- Added prettyPrinted to Requirement
- Added tests
Copy link
Member

@ankitspd ankitspd left a comment

Choose a reason for hiding this comment

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

I have some very minor nits but otherwise this is ready to go. Thanks a lot for working on this!

@tgymnich
Copy link
Contributor Author

tgymnich commented Oct 31, 2019

You are welcome. Thank you for your input!

@ankitspd
Copy link
Member

@swift-ci smoke test

@ankitspd ankitspd merged commit c43b137 into apple:master Oct 31, 2019
@helje5
Copy link
Contributor

helje5 commented Nov 12, 2019

Given the output in the sample above:

2019-10-16 13:21:43.723885+0200 swift-package[53147:783737] [default] Starting resolution using pubgrub resolver
Updating https://github.com/attaswift/BigInt.git
Updating https://github.com/apple/swift-protobuf.git

3 dependencies have changed:
+ SwiftProtobuf 1.7.0
~ BigInt 4.0.0 -> BigInt 5.0.0
- swift-nio 2.8.0
Program ended with exit code: 0

This isn't a proper --dry-run, right? It'll "wet" the fetch state of the git repositories? Can we add something to avoid that (i.e. move the checkouts to a temporary location or do some form of APFS clone when available)?

@ankitspd
Copy link
Member

That fetch state is supposed to be an implementation detail. What's your use case?

@helje5
Copy link
Contributor

helje5 commented Nov 12, 2019

As part of the Catalog App I'd like to show a user projects he could update and ideally what is new (just like the Updates section in App Store). But in no way I want to modify any of his precious stuff before he clicks an actual "update" button.

Besides, the core definition of --dry-run is that it has zarro side effects.

I understand that this seems quite hard w/ just git, so I'm probably going to APFS clone projects and run a full update.

In any case I suggest that the dox to this "dry-run" explicitly documents that this is going to fetch and not be dry. It's quite unexpected and counter to the point.

@ankitspd
Copy link
Member

I don't want this behavior documented because it's an implementation detail and we'll probably want to have local shared cache at some point. But it seems fine to consider this behavior as a bug in the current --dry-run implementation.

@helje5
Copy link
Contributor

helje5 commented Nov 12, 2019

A local shared cache
😍

@tgymnich
Copy link
Contributor Author

tgymnich commented Nov 14, 2019

The best solution would be to just copy the workspace into a temporary directory. In case of a dry run a normal update would be performed on a temporary Workspace. I would also remove the dry run argument for updateDependencies again and just always print the summary of changed packages (should I keep returning the changed packages?).

@helje5
Copy link
Contributor

helje5 commented Nov 15, 2019

That is what I also plan to do for now. Unfortunately it's a little hard to clone into the same directory :-)

BTW: Something which would also be appreciated is if this would get the JSON output treatment.

@tgymnich
Copy link
Contributor Author

For getting easy to parse output you could also use the swift package manger library to get the outdated packages.

@helje5
Copy link
Contributor

helje5 commented Nov 15, 2019

I think that's too much coupling for my purpose, I just want to use the Swift the user has active.

@tgymnich
Copy link
Contributor Author

I created an issue

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.

None yet

3 participants