@@ -323,17 +323,26 @@ extension Workspace {
323
323
}
324
324
}
325
325
326
- /// Ends the edit mode of a dependency which is in edit mode.
326
+ /// Ends the edit mode of an edited dependency.
327
+ ///
328
+ /// This will re-resolve the dependencies after ending edit as the original
329
+ /// checkout may be outdated.
327
330
///
328
331
/// - Parameters:
329
332
/// - packageName: The name of the package to edit.
330
- /// - forceRemove: If true, the dependency will be unedited even if has
331
- /// unpushed and uncommited changes. Otherwise will throw respective errors.
332
- ///
333
- /// - throws: WorkspaceError
334
- public func unedit( packageName: String , forceRemove: Bool ) throws {
333
+ /// - forceRemove: If true, the dependency will be unedited even if has unpushed
334
+ /// or uncommited changes. Otherwise will throw respective errors.
335
+ /// - root: The workspace root. This is used to resolve the dependencies post unediting.
336
+ /// - diagnostics: The diagnostics engine that reports errors, warnings
337
+ /// and notes.
338
+ public func unedit(
339
+ packageName: String ,
340
+ forceRemove: Bool ,
341
+ root: WorkspaceRoot ,
342
+ diagnostics: DiagnosticsEngine
343
+ ) throws {
335
344
let dependency = try managedDependencies. dependency ( forName: packageName)
336
- try unedit ( dependency: dependency, forceRemove: forceRemove)
345
+ try unedit ( dependency: dependency, forceRemove: forceRemove, root : root , diagnostics : diagnostics )
337
346
}
338
347
339
348
/// Resolve a package at the given state.
@@ -367,27 +376,22 @@ extension Workspace {
367
376
return diagnostics. emit ( error)
368
377
}
369
378
370
- // Compute the checkout state.
371
- //
372
- // We use a dummy revision in case of version and branch because we
373
- // might not know the needed revision at this point.
374
- let checkoutState : CheckoutState
379
+ // Compute the custom or extra constraint we need to impose.
380
+ let requirement : RepositoryPackageConstraint . Requirement
375
381
if let version = version {
376
- checkoutState = CheckoutState ( revision : Revision ( identifier : " " ) , version: version )
382
+ requirement = . versionSet ( . exact ( version) )
377
383
} else if let branch = branch {
378
- checkoutState = CheckoutState ( revision: Revision ( identifier : " " ) , branch : branch)
384
+ requirement = . revision( branch)
379
385
} else if let revision = revision {
380
- checkoutState = CheckoutState ( revision: Revision ( identifier : revision) )
386
+ requirement = . revision( revision)
381
387
} else {
382
- checkoutState = currentState
388
+ requirement = currentState. requirement ( )
383
389
}
384
-
385
- // Create a pin with above checkout state.
386
- let pin = PinsStore . Pin (
387
- package : dependency. name, repository: dependency. repository, state: checkoutState)
390
+ let constraint = RepositoryPackageConstraint (
391
+ container: dependency. repository, requirement: requirement)
388
392
389
393
// Run the resolution.
390
- _resolve ( root: root, extraPins : [ pin ] , diagnostics: diagnostics)
394
+ _resolve ( root: root, extraConstraints : [ constraint ] , diagnostics: diagnostics)
391
395
}
392
396
393
397
/// Cleans the build artefacts from workspace data.
@@ -666,7 +670,12 @@ extension Workspace {
666
670
}
667
671
668
672
/// Unedit a managed dependency. See public API unedit(packageName:forceRemove:).
669
- fileprivate func unedit( dependency: ManagedDependency , forceRemove: Bool ) throws {
673
+ fileprivate func unedit(
674
+ dependency: ManagedDependency ,
675
+ forceRemove: Bool ,
676
+ root: WorkspaceRoot ? = nil ,
677
+ diagnostics: DiagnosticsEngine
678
+ ) throws {
670
679
671
680
// Compute if we need to force remove.
672
681
var forceRemove = forceRemove
@@ -709,6 +718,12 @@ extension Workspace {
709
718
managedDependencies [ dependency. repository] = dependency. basedOn
710
719
// Save the state.
711
720
try managedDependencies. saveState ( )
721
+
722
+ // Resolve the dependencies if workspace root is provided. We do this to
723
+ // ensure the unedited version of this dependency is resolved properly.
724
+ if let root = root {
725
+ resolve ( root: root, diagnostics: diagnostics)
726
+ }
712
727
}
713
728
714
729
}
@@ -866,14 +881,14 @@ extension Workspace {
866
881
867
882
/// Implementation of resolve(root:diagnostics:).
868
883
///
869
- /// The extra pins will override the pin of the same package in the
870
- /// pinsStore. It is useful in situations where a requirement is being
884
+ /// The extra constraints will be added to the main requirements.
885
+ /// It is useful in situations where a requirement is being
871
886
/// imposed outside of manifest and pins file. E.g., when using a command
872
887
/// like `$ swift package resolve foo --version 1.0.0`.
873
888
@discardableResult
874
889
fileprivate func _resolve(
875
890
root: WorkspaceRoot ,
876
- extraPins : [ PinsStore . Pin ] = [ ] ,
891
+ extraConstraints : [ RepositoryPackageConstraint ] = [ ] ,
877
892
diagnostics: DiagnosticsEngine
878
893
) -> DependencyManifests {
879
894
@@ -898,17 +913,18 @@ extension Workspace {
898
913
// The pins to use in case we need to run the resolution.
899
914
var validPins = pinsStore. createConstraints ( )
900
915
901
- // Compute if we need to run the resolver.
916
+ // Compute if we need to run the resolver. We always run the resolver if
917
+ // there are extra constraints.
902
918
if missingURLs. isEmpty {
903
919
// Use root constraints, dependency manifest constraints and extra
904
- // pins to compute if a new resolution is required.
905
- let dependencies = graphRoot. constraints + currentManifests. dependencyConstraints ( )
906
- extraPins. forEach ( pinsStore. add)
920
+ // constraints to compute if a new resolution is required.
921
+ let dependencies = graphRoot. constraints + currentManifests. dependencyConstraints ( ) + extraConstraints
907
922
908
923
let result = isResolutionRequired ( dependencies: dependencies, pinsStore: pinsStore)
909
924
910
- // If we don't need resolution, just validate pinsStore and return.
911
- if !result. resolve {
925
+ // If we don't need resolution and there are no extra constraints,
926
+ // just validate pinsStore and return.
927
+ if !result. resolve && extraConstraints. isEmpty {
912
928
validatePinsStore ( with: diagnostics)
913
929
return currentManifests
914
930
}
@@ -918,13 +934,23 @@ extension Workspace {
918
934
919
935
// Create the constraints.
920
936
var constraints = [ RepositoryPackageConstraint] ( )
921
- constraints += graphRoot. constraints
937
+ constraints += graphRoot. constraints + extraConstraints
922
938
constraints += currentManifests. editedPackagesConstraints ( )
923
939
924
940
// Perform dependency resolution.
925
- let result = resolveDependencies ( dependencies: constraints, pins: validPins, diagnostics: diagnostics)
926
- guard !diagnostics. hasErrors else {
927
- return currentManifests
941
+ let resolverDiagnostics = DiagnosticsEngine ( )
942
+ var result = resolveDependencies ( dependencies: constraints, pins: validPins, diagnostics: resolverDiagnostics)
943
+
944
+ // If we fail, we just try again without any pins because the pins might
945
+ // be completely incompatible.
946
+ //
947
+ // FIXME: We should only do this if resolver emits "unresolvable" error.
948
+ // FIXME: We should merge the engine in case we get no errors but warnings or notes.
949
+ if resolverDiagnostics. hasErrors {
950
+ result = resolveDependencies ( dependencies: constraints, pins: [ ] , diagnostics: diagnostics)
951
+ guard !diagnostics. hasErrors else {
952
+ return currentManifests
953
+ }
928
954
}
929
955
930
956
// Update the checkouts with dependency resolution result.
@@ -1171,18 +1197,26 @@ extension Workspace {
1171
1197
fileprivate func fixManagedDependencies( with diagnostics: DiagnosticsEngine ) {
1172
1198
for dependency in managedDependencies. values {
1173
1199
diagnostics. wrap {
1200
+
1201
+ // If the dependency is present, we're done.
1174
1202
let dependencyPath = path ( for: dependency)
1175
- if !fileSystem. isDirectory ( dependencyPath) {
1176
- switch dependency. state {
1177
- case . checkout( let checkoutState) :
1178
- // If some checkout dependency has been removed, clone it again.
1179
- _ = try clone ( repository: dependency. repository, at: checkoutState)
1180
- diagnostics. emit ( WorkspaceDiagnostics . CheckedOutDependencyMissing ( packageName: dependency. name) )
1181
- case . edited:
1182
- // If some edited dependency has been removed, mark it as unedited.
1183
- try unedit ( dependency: dependency, forceRemove: true )
1184
- diagnostics. emit ( WorkspaceDiagnostics . EditedDependencyMissing ( packageName: dependency. name) )
1185
- }
1203
+ guard !fileSystem. isDirectory ( dependencyPath) else { return }
1204
+
1205
+ switch dependency. state {
1206
+ case . checkout( let checkoutState) :
1207
+ // If some checkout dependency has been removed, clone it again.
1208
+ _ = try clone ( repository: dependency. repository, at: checkoutState)
1209
+ diagnostics. emit ( WorkspaceDiagnostics . CheckedOutDependencyMissing ( packageName: dependency. name) )
1210
+
1211
+ case . edited:
1212
+ // If some edited dependency has been removed, mark it as unedited.
1213
+ //
1214
+ // Note: We don't resolve the dependencies when unediting
1215
+ // here because we expect this method to be called as part
1216
+ // of some other resolve operation (i.e. resolve, update, etc).
1217
+ try unedit ( dependency: dependency, forceRemove: true , diagnostics: diagnostics)
1218
+
1219
+ diagnostics. emit ( WorkspaceDiagnostics . EditedDependencyMissing ( packageName: dependency. name) )
1186
1220
}
1187
1221
}
1188
1222
}
0 commit comments