diff --git a/src/Paket.Core/Installation/DependencyChangeDetection.fs b/src/Paket.Core/Installation/DependencyChangeDetection.fs index d63c6764f6..94c6f4a049 100644 --- a/src/Paket.Core/Installation/DependencyChangeDetection.fs +++ b/src/Paket.Core/Installation/DependencyChangeDetection.fs @@ -1,5 +1,6 @@ module Paket.DependencyChangeDetection +open Paket.Domain open Paket.Requirements open Paket.PackageResolver @@ -10,6 +11,8 @@ type DependencyChangeType = | SettingsChanged /// The Version in the LockFile doesn't match the spec in the dependencies file. | VersionNotValid + /// The Version in the LockFile is a prerelease, but the dependencies file does not allow prereleases for this package. + | PrereleaseVersionNotAllowed /// Package from dependencies file was not found in lockfile | PackageNotFoundInLockFile /// Group from dependencies file was not found in lockfile @@ -17,6 +20,16 @@ type DependencyChangeType = /// Package from lock file was not found in dependencies file | PackageNotFoundInDependenciesFile + override this.ToString() = + match this with + | RestrictionsChanged -> "Framework restrictions have changed" + | SettingsChanged -> "Settings have changed" + | VersionNotValid -> "Installed version is not valid" + | PrereleaseVersionNotAllowed -> "Prerelease version installed, but not allowed" + | PackageNotFoundInLockFile -> "Package was not found in lock file" + | GroupNotFoundInLockFile -> "Group was not found in lock file" + | PackageNotFoundInDependenciesFile -> "Package was not found in dependencies file" + let findNuGetChangesInDependenciesFile(dependenciesFile:DependenciesFile,lockFile:LockFile,strict) = let allTransitives groupName = lockFile.GetTransitiveDependencies groupName let getChanges groupName transitives (newRequirement:PackageRequirement) (originalPackage:PackageInfo) = @@ -37,13 +50,19 @@ let findNuGetChangesInDependenciesFile(dependenciesFile:DependenciesFile,lockFil else [] let requirementOk = - let isInRange = + let requirement = if strict then - newRequirement.VersionRequirement.IsInRange originalPackage.Version + newRequirement.VersionRequirement else - newRequirement.IncludingPrereleases().VersionRequirement.IsInRange originalPackage.Version + newRequirement.IncludingPrereleases().VersionRequirement + + let isInRange = requirement.IsInRange originalPackage.Version + if not isInRange then - [VersionNotValid] + if originalPackage.Version.PreRelease.IsSome && requirement.PreReleases = No then + [PrereleaseVersionNotAllowed] + else + [VersionNotValid] else [] requirementOk @ settingsChanged() @@ -218,6 +237,11 @@ let GetPreferredNuGetVersions (dependenciesFile:DependenciesFile,lockFile:LockFi | None -> kv.Key, (kv.Value.Version, kv.Value.Source)) |> Map.ofSeq +type ResolutionTriggeringChange = + | NuGetChange of PackageName * DependencyChangeType + | RemoteChange of projectName:string * fileName:string + | SettingsChange + let GetChanges(dependenciesFile,lockFile,strict) = let nuGetChanges = findNuGetChangesInDependenciesFile(dependenciesFile,lockFile,strict) let nuGetChangesPerGroup = @@ -231,37 +255,49 @@ let GetChanges(dependenciesFile,lockFile,strict) = |> Seq.groupBy fst |> Map.ofSeq - let hasNuGetChanges groupName = + let getNuGetChanges groupName = match nuGetChangesPerGroup |> Map.tryFind groupName with - | None -> false - | Some x -> Seq.isEmpty x |> not - - let hasRemoteFileChanges groupName = + | None -> [] + | Some x -> + x + |> Seq.collect (fun (_, package, changes) -> + changes + |> List.map (fun change -> NuGetChange (package, change))) + |> Seq.toList + + let getRemoteFileChanges groupName = match remoteFileChangesPerGroup |> Map.tryFind groupName with - | None -> false - | Some x -> Seq.isEmpty x |> not + | None -> [] + | Some x -> + x + |> Seq.map (fun (_, change) -> RemoteChange (change.Project, change.Name)) + |> Seq.toList - let hasChangedSettings groupName = + let getChangedSettings groupName = match dependenciesFile.Groups |> Map.tryFind groupName with - | None -> true + | None -> [ SettingsChange ] | Some dependenciesFileGroup -> match lockFile.Groups |> Map.tryFind groupName with - | None -> true + | None -> [ SettingsChange ] | Some lockFileGroup -> let lockFileGroupOptions = if dependenciesFileGroup.Options.Settings.FrameworkRestrictions = AutoDetectFramework then { lockFileGroup.Options with Settings = { lockFileGroup.Options.Settings with FrameworkRestrictions = AutoDetectFramework } } else lockFileGroup.Options - dependenciesFileGroup.Options <> lockFileGroupOptions + + if dependenciesFileGroup.Options <> lockFileGroupOptions then + [ SettingsChange ] + else [] - let hasChanges groupName _ = - hasChangedSettings groupName || hasNuGetChanges groupName || hasRemoteFileChanges groupName + let getChanges groupName _ = + [ getChangedSettings groupName; getNuGetChanges groupName; getRemoteFileChanges groupName ] + |> List.concat let hasAnyChanges = dependenciesFile.Groups - |> Map.filter hasChanges + |> Map.filter (fun groupName group -> getChanges groupName group |> List.isEmpty |> not) |> Map.isEmpty |> not - hasAnyChanges,nuGetChanges,remoteFileChanges,hasChanges \ No newline at end of file + hasAnyChanges,nuGetChanges,remoteFileChanges,getChanges \ No newline at end of file diff --git a/src/Paket.Core/Installation/UpdateProcess.fs b/src/Paket.Core/Installation/UpdateProcess.fs index 2ccdaba262..2514e396f9 100644 --- a/src/Paket.Core/Installation/UpdateProcess.fs +++ b/src/Paket.Core/Installation/UpdateProcess.fs @@ -10,6 +10,8 @@ open Chessie.ErrorHandling open Paket.Logging open InstallProcess +type RTC = DependencyChangeDetection.ResolutionTriggeringChange + let selectiveUpdate force getSha1 getVersionsF getPackageDetailsF getRuntimeGraphFromPackage (lockFile:LockFile) (dependenciesFile:DependenciesFile) updateMode semVerUpdateMode = let dependenciesFile = let processFile createRequirementF = @@ -42,6 +44,42 @@ let selectiveUpdate force getSha1 getVersionsF getPackageDetailsF getRuntimeGrap let getPreferredVersionsF,getPackageDetailsF,groupsToUpdate = let changes,groups = + let install groupName = + let hasAnyChanges,nuGetChanges,remoteFileChanges,getChanges = DependencyChangeDetection.GetChanges(dependenciesFile,lockFile,true) + + let hasChanges groupName x = + match getChanges groupName x with + | [] -> + tracefn "Skipping resolver for group %O since it is already up-to-date" groupName + false + | changes -> + tracefn "Resolving group %O because of changes:" groupName + + changes + |> List.map (function + | RTC.NuGetChange (packageName, change) -> + sprintf "Package %O: %O" packageName change + | RTC.RemoteChange (project, file) -> + sprintf "Remote file %s changed in project %s" file project + | RTC.SettingsChange -> "Group has settings changes") + |> List.iter (tracefn "- %s") + + true + + let groupFilter = + match groupName with + | Some groupName -> fun g -> g = groupName + | None -> fun _ -> true + + let groups = + dependenciesFile.Groups + |> Map.filter (fun g _ -> groupFilter g) + |> Map.filter hasChanges + + nuGetChanges + |> Set.map (fun (f,s,_) -> f,s) + |> Set.filter (fst >> groupFilter), groups + match updateMode with | UpdateAll -> let changes = @@ -78,38 +116,8 @@ let selectiveUpdate force getSha1 getVersionsF getPackageDetailsF getRuntimeGrap |> Map.filter (fun k _ -> k = groupName || changes |> Seq.exists (fun (g,_) -> g = k)) changes,groups - | InstallGroup groupName -> - let hasAnyChanges,nuGetChanges,remoteFileChanges,hasChanges = DependencyChangeDetection.GetChanges(dependenciesFile,lockFile,true) - - let hasChanges groupName x = - let hasChanges = hasChanges groupName x - if not hasChanges then - tracefn "Skipping resolver for group %O since it is already up-to-date" groupName - hasChanges - - let groups = - dependenciesFile.Groups - |> Map.filter (fun k _ -> k = groupName) - |> Map.filter hasChanges - - nuGetChanges - |> Set.map (fun (f,s,_) -> f,s) - |> Set.filter (fun (g,_) -> g = groupName), groups - | Install -> - let hasAnyChanges,nuGetChanges,remoteFileChanges,hasChanges = DependencyChangeDetection.GetChanges(dependenciesFile,lockFile,true) - - let hasChanges groupName x = - let hasChanges = hasChanges groupName x - if not hasChanges then - tracefn "Skipping resolver for group %O since it is already up-to-date" groupName - hasChanges - - let groups = - dependenciesFile.Groups - |> Map.filter hasChanges - - nuGetChanges - |> Set.map (fun (f,s,_) -> f,s), groups + | InstallGroup groupName -> install (Some groupName) + | Install -> install None let preferredVersions = match updateMode with diff --git a/src/Paket.Core/Paket.Core.fsproj b/src/Paket.Core/Paket.Core.fsproj index 0d52a9c654..b930ea610d 100644 --- a/src/Paket.Core/Paket.Core.fsproj +++ b/src/Paket.Core/Paket.Core.fsproj @@ -23,12 +23,12 @@ ..\..\bin TRACE;DEBUG;USE_WEB_CLIENT_FOR_UPLOAD 3 - update + install Project paket.exe - C:\proj\testing\testpaketfailure\ + D:\Development\Staging\Paket\3008_prerelease_resolution_message\Paket3008\.paket\ true diff --git a/src/Paket/Paket.fsproj b/src/Paket/Paket.fsproj index a5154de506..8577694016 100644 --- a/src/Paket/Paket.fsproj +++ b/src/Paket/Paket.fsproj @@ -23,7 +23,7 @@ true false false - ..\..\bin\ + D:\Development\Staging\Paket\3008_prerelease_resolution_message\Paket3008\.paket DEBUG;TRACE 3 @@ -34,14 +34,14 @@ install C:\temp\Gu.Reactive update - add -g Foo Newtonsoft.Json + install C:\proj\Paket D:\temp\PaketTargetFrameworkRepro\ D:\code\bookstore C:\temp\paket-conflict\paket.conflict.app D:\temp\i3032 C:\code\Paket\integrationtests\scenarios\i003062-external-lock\before - C:\temp\flip + D:\Development\Staging\Paket\3008_prerelease_resolution_message\Paket3008 true diff --git a/src/Paket/Program.fs b/src/Paket/Program.fs index 7e3bc771d1..d9144ffe1b 100644 --- a/src/Paket/Program.fs +++ b/src/Paket/Program.fs @@ -918,3 +918,5 @@ let main() = else printError exn main() + +ignore ()