diff --git a/src/Paket.Core/DependenciesFile.fs b/src/Paket.Core/DependenciesFile.fs index d09dec2644..356f921d08 100644 --- a/src/Paket.Core/DependenciesFile.fs +++ b/src/Paket.Core/DependenciesFile.fs @@ -308,12 +308,21 @@ type DependenciesFile(fileName,options,sources,packages : PackageRequirement lis member __.FileName = fileName member __.Lines = textRepresentation member __.Sources = sources - member this.Resolve(force) = + + member this.Resolve(force,packages) = let getSha1 origin owner repo branch = RemoteDownload.getSHA1OfBranch origin owner repo branch |> Async.RunSynchronously let root = Path.GetDirectoryName this.FileName - this.Resolve(getSha1,NuGetV2.GetVersions root,NuGetV2.GetPackageDetails root force) + this.Resolve(getSha1,NuGetV2.GetVersions root,NuGetV2.GetPackageDetails root force,packages) + + member this.Resolve(force) = + this.Resolve(force,Some packages) + + member __.Resolve(getSha1,getVersionF, getPackageDetailsF,rootDependencies) = + let rootDependencies = + match rootDependencies with + | None -> packages + | Some d -> d - member __.Resolve(getSha1,getVersionF, getPackageDetailsF) = let resolveSourceFile(file:ResolvedSourceFile) : PackageRequirement list = let parserF text = try @@ -339,9 +348,12 @@ type DependenciesFile(fileName,options,sources,packages : PackageRequirement lis VersionRequirement = v }) |> Seq.toList - { ResolvedPackages = PackageResolver.Resolve(getVersionF, getPackageDetailsF, options.Settings.FrameworkRestrictions, remoteDependencies @ packages) + { ResolvedPackages = PackageResolver.Resolve(getVersionF, getPackageDetailsF, options.Settings.FrameworkRestrictions, remoteDependencies @ rootDependencies, Set.ofList packages) ResolvedSourceFiles = remoteFiles } + member __.Resolve(getSha1,getVersionF, getPackageDetailsF) = + __.Resolve(getSha1,getVersionF,getPackageDetailsF,Some packages) + member __.AddAdditionalPackage(packageName:PackageName,versionRequirement,resolverStrategy,settings,?pinDown) = let pinDown = defaultArg pinDown false let packageString = DependenciesFileSerializer.packageString packageName versionRequirement resolverStrategy settings diff --git a/src/Paket.Core/LockFile.fs b/src/Paket.Core/LockFile.fs index de00f27a9d..92ea35ab30 100644 --- a/src/Paket.Core/LockFile.fs +++ b/src/Paket.Core/LockFile.fs @@ -206,13 +206,15 @@ module LockFileParser = Settings = InstallSettings.Parse(optionsString) Version = SemVer.Parse version } :: state.Packages } | None -> failwith "no source has been specified." - | NugetDependency (name, _) -> + | NugetDependency (name, v) -> + let parts = v.Split([|" - "|],StringSplitOptions.None) + let version = parts.[0] if state.LastWasPackage then match state.Packages with | currentPackage :: otherPackages -> { state with Packages = { currentPackage with - Dependencies = Set.add (PackageName name, VersionRequirement.AllReleases, []) currentPackage.Dependencies + Dependencies = Set.add (PackageName name, DependenciesFileParser.parseVersionRequirement version, []) currentPackage.Dependencies } :: otherPackages } | [] -> failwith "cannot set a dependency - no package has been specified." else diff --git a/src/Paket.Core/PackageResolver.fs b/src/Paket.Core/PackageResolver.fs index 4756c2f92a..b32c4385db 100644 --- a/src/Paket.Core/PackageResolver.fs +++ b/src/Paket.Core/PackageResolver.fs @@ -151,7 +151,7 @@ type Resolved = { ResolvedSourceFiles : ModuleResolver.ResolvedSourceFile list } /// Resolves all direct and transitive dependencies -let Resolve(getVersionsF, getPackageDetailsF, globalFrameworkRestrictions, rootDependencies:PackageRequirement list) = +let Resolve(getVersionsF, getPackageDetailsF, globalFrameworkRestrictions, rootDependencies, (requirements : Set)) = tracefn "Resolving packages:" let exploredPackages = Dictionary() let allVersions = Dictionary() @@ -244,8 +244,19 @@ let Resolve(getVersionsF, getPackageDetailsF, globalFrameworkRestrictions, rootD match Map.tryFind currentRequirement.Name filteredVersions with | None -> // we didn't select a version yet so all versions are possible + + let requirement = + requirements + |> Seq.tryFind (fun r -> NormalizedPackageName currentRequirement.Name = NormalizedPackageName r.Name) + + let isInRange ver = + let inRange = currentRequirement.VersionRequirement.IsInRange(ver) + match requirement with + | None -> inRange + | Some requirement -> inRange && requirement.VersionRequirement.IsInRange(ver) + availableVersions := getAllVersions(currentRequirement.Sources,currentRequirement.Name,currentRequirement.VersionRequirement.Range) - compatibleVersions := List.filter currentRequirement.VersionRequirement.IsInRange (!availableVersions) + compatibleVersions := List.filter isInRange (!availableVersions) if currentRequirement.VersionRequirement.Range.IsGlobalOverride then globalOverride := true else diff --git a/src/Paket.Core/UpdateProcess.fs b/src/Paket.Core/UpdateProcess.fs index ccc5a179bf..f9f3cdf885 100644 --- a/src/Paket.Core/UpdateProcess.fs +++ b/src/Paket.Core/UpdateProcess.fs @@ -1,4 +1,4 @@ -/// Contains methods for the update process. +/// Contains methods for the update process. module Paket.UpdateProcess open Paket @@ -46,25 +46,67 @@ let addPackagesFromReferenceFiles projects (dependenciesFile : DependenciesFile) newDependenciesFile.Save() newDependenciesFile -let SelectiveUpdate(dependenciesFile : DependenciesFile, updateAll, exclude, force) = - let lockFileName = DependenciesFile.FindLockfile dependenciesFile.FileName +let selectiveUpdate resolve lockFile dependenciesFile updateAll package = + let install () = + let changedDependencies = DependencyChangeDetection.findChangesInDependenciesFile(dependenciesFile,lockFile) + let dependenciesFile = DependencyChangeDetection.PinUnchangedDependencies dependenciesFile lockFile Set.empty + resolve dependenciesFile None + + let selectiveUpdate package = + let selectiveResolution = + dependenciesFile.Packages + |> List.filter (fun p -> package = NormalizedPackageName p.Name) + |> Some + |> resolve dependenciesFile + + let merge destination source = + Map.fold (fun acc key value -> Map.add key value acc) destination source + + let resolution = + let resolvedPackages = + selectiveResolution.ResolvedPackages.GetModelOrFail() + |> merge lockFile.ResolvedPackages + + let dependencies = + resolvedPackages + |> Seq.map (fun d -> d.Value.Dependencies |> Seq.map (fun (n,_,_) -> n)) + |> Seq.concat + |> Set.ofSeq + + let isDirectDependency package = + dependenciesFile.DirectDependencies + |> Map.exists (fun p _ -> NormalizedPackageName p = package) + + let isTransitiveDependency package = + dependencies + |> Set.exists (fun p -> NormalizedPackageName p = package) + + resolvedPackages + |> Map.filter (fun p _ -> isDirectDependency p || isTransitiveDependency p) + + { ResolvedPackages = Resolution.Ok(resolution); ResolvedSourceFiles = lockFile.SourceFiles } let resolution = - if not lockFileName.Exists || updateAll then - dependenciesFile.Resolve(force) + if updateAll then + resolve dependenciesFile None else - let oldLockFile = LockFile.LoadFrom(lockFileName.FullName) - let changedDependencies = DependencyChangeDetection.findChangesInDependenciesFile(dependenciesFile,oldLockFile) + match package with + | None -> install () + | Some package -> selectiveUpdate package - let changed = - match exclude with - | None -> changedDependencies - | Some package -> Set.add package changedDependencies + LockFile(lockFile.FileName, dependenciesFile.Options, resolution.ResolvedPackages.GetModelOrFail(), resolution.ResolvedSourceFiles) - let dependenciesFile = DependencyChangeDetection.PinUnchangedDependencies dependenciesFile oldLockFile changed +let SelectiveUpdate(dependenciesFile : DependenciesFile, updateAll, exclude, force) = + let lockFileName = DependenciesFile.FindLockfile dependenciesFile.FileName + let oldLockFile = + if not lockFileName.Exists then + LockFile.Parse(lockFileName.FullName, [||]) + else + LockFile.LoadFrom lockFileName.FullName - dependenciesFile.Resolve(force) - LockFile.Create(lockFileName.FullName, dependenciesFile.Options, resolution.ResolvedPackages, resolution.ResolvedSourceFiles) + let lockFile = selectiveUpdate (fun d p -> d.Resolve(force, p)) oldLockFile dependenciesFile updateAll exclude + lockFile.Save() + lockFile /// Smart install command let SmartInstall(dependenciesFileName, updateAll, exclude, options : UpdaterOptions) = diff --git a/tests/Paket.Tests/Lockfile/ParserSpecs.fs b/tests/Paket.Tests/Lockfile/ParserSpecs.fs index bf8c516ab0..08ce7fc739 100644 --- a/tests/Paket.Tests/Lockfile/ParserSpecs.fs +++ b/tests/Paket.Tests/Lockfile/ParserSpecs.fs @@ -47,12 +47,12 @@ let ``should parse lock file``() = packages.[1].Source |> shouldEqual PackageSources.DefaultNugetSource packages.[1].Name |> shouldEqual (PackageName "Castle.Windsor-log4net") packages.[1].Version |> shouldEqual (SemVer.Parse "3.3") - packages.[1].Dependencies |> shouldEqual (Set.ofList [PackageName "Castle.Windsor", VersionRequirement.AllReleases, []; PackageName "log4net", VersionRequirement.AllReleases, []]) + packages.[1].Dependencies |> shouldEqual (Set.ofList [PackageName "Castle.Windsor", VersionRequirement(Minimum(SemVer.Parse "2.0"), PreReleaseStatus.No), []; PackageName "log4net", VersionRequirement(Minimum(SemVer.Parse "1.0"), PreReleaseStatus.No), []]) packages.[5].Source |> shouldEqual PackageSources.DefaultNugetSource packages.[5].Name |> shouldEqual (PackageName "log4net") packages.[5].Version |> shouldEqual (SemVer.Parse "1.1") - packages.[5].Dependencies |> shouldEqual (Set.ofList [PackageName "log", VersionRequirement.AllReleases, []]) + packages.[5].Dependencies |> shouldEqual (Set.ofList [PackageName "log", VersionRequirement(Minimum(SemVer.Parse "1.0"), PreReleaseStatus.No), []]) let sourceFiles = List.rev lockFile.SourceFiles sourceFiles|> shouldEqual @@ -103,7 +103,7 @@ let ``should parse strict lock file``() = packages.[5].Source |> shouldEqual PackageSources.DefaultNugetSource packages.[5].Name |> shouldEqual (PackageName "log4net") packages.[5].Version |> shouldEqual (SemVer.Parse "1.1") - packages.[5].Dependencies |> shouldEqual (Set.ofList [PackageName "log", VersionRequirement.AllReleases, []]) + packages.[5].Dependencies |> shouldEqual (Set.ofList [PackageName "log", VersionRequirement(Minimum(SemVer.Parse "1.0"), PreReleaseStatus.No), []]) let redirectsLockFile = """REDIRECTS: ON IMPORT-TARGETS: TRUE diff --git a/tests/Paket.Tests/Paket.Tests.fsproj b/tests/Paket.Tests/Paket.Tests.fsproj index cad8e4a5e8..de20c6e09e 100644 --- a/tests/Paket.Tests/Paket.Tests.fsproj +++ b/tests/Paket.Tests/Paket.Tests.fsproj @@ -94,6 +94,7 @@ + Always diff --git a/tests/Paket.Tests/TestHelpers.fs b/tests/Paket.Tests/TestHelpers.fs index f896a76f57..ef5812bb9b 100644 --- a/tests/Paket.Tests/TestHelpers.fs +++ b/tests/Paket.Tests/TestHelpers.fs @@ -38,7 +38,7 @@ let safeResolve graph (dependencies : (string * VersionRange) list) = Parent = PackageRequirementSource.DependenciesFile "" Settings = InstallSettings.Default ResolverStrategy = ResolverStrategy.Max }) - PackageResolver.Resolve(VersionsFromGraph graph, PackageDetailsFromGraph graph, [], packages) + PackageResolver.Resolve(VersionsFromGraph graph, PackageDetailsFromGraph graph, [], packages, Set.empty) let resolve graph dependencies = (safeResolve graph dependencies).GetModelOrFail() diff --git a/tests/Paket.Tests/UpdateProcessSpecs.fs b/tests/Paket.Tests/UpdateProcessSpecs.fs new file mode 100644 index 0000000000..9f1040c280 --- /dev/null +++ b/tests/Paket.Tests/UpdateProcessSpecs.fs @@ -0,0 +1,429 @@ +module Paket.UpdateProcess.Test + +open Paket +open Paket.Domain +open Paket.PackageSources +open Paket.PackageResolver +open Paket.TestHelpers +open NUnit.Framework +open FsUnit +open System + +let lockFileData = """NUGET + remote: http://nuget.org/api/v2 + specs: + Castle.Core (3.2.0) + Castle.Core-log4net (3.2.0) + Castle.Core (>= 3.2.0) + log4net (1.2.10) + FAKE (4.0.0) + log4net (1.2.10) +""" + +let graph = + [ "Castle.Core-log4net", "3.2.0", + [ "Castle.Core", VersionRequirement(VersionRange.AtLeast "3.2.0",PreReleaseStatus.No) + "log4net", VersionRequirement(VersionRange.AtLeast "1.2.10",PreReleaseStatus.No) ] + "Castle.Core-log4net", "3.3.3", + [ "Castle.Core", VersionRequirement(VersionRange.AtLeast "3.3.3",PreReleaseStatus.No) + "log4net", VersionRequirement(VersionRange.AtLeast "1.2.10",PreReleaseStatus.No) ] + "Castle.Core-log4net", "4.0.0", + [ "Castle.Core", VersionRequirement(VersionRange.AtLeast "4.0.0",PreReleaseStatus.No) ] + "Castle.Core", "3.2.0", [] + "Castle.Core", "3.3.3", [] + "Castle.Core", "4.0.0", [] + "FAKE", "4.0.0", [] + "FAKE", "4.0.1", [] + "log4net", "1.2.10", [] + "Newtonsoft.Json", "7.0.1", [] + "Newtonsoft.Json", "6.0.8", [] ] + +let getVersions = VersionsFromGraph graph +let getPackageDetails = PackageDetailsFromGraph graph + +let lockFile = LockFile.Parse("",toLines lockFileData) +let resolve (dependenciesFile : DependenciesFile) packages = dependenciesFile.Resolve(noSha1, getVersions, getPackageDetails, packages) + +[] +let ``SelectiveUpdate does not update any package when it is neither updating all nor selective updating``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net ~> 3.2 + nuget FAKE""") + + let updateAll = false + let lockFile = selectiveUpdate resolve lockFile dependenciesFile updateAll None + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.2.0"); + ("Castle.Core","3.2.0"); + ("FAKE","4.0.0"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate updates all packages not constraining version``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net ~> 3.2 + nuget FAKE""") + + let updateAll = true + let lockFile = selectiveUpdate resolve lockFile dependenciesFile updateAll None + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.3.3"); + ("Castle.Core","4.0.0"); + ("FAKE","4.0.1"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate updates all packages constraining version``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net < 4.0 + nuget Castle.Core ~> 3.2 + nuget FAKE = 4.0.0""") + + let updateAll = true + let lockFile = selectiveUpdate resolve lockFile dependenciesFile updateAll None + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.3.3"); + ("Castle.Core","3.3.3"); + ("FAKE","4.0.0"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate removes a dependency when it is updated to a version that does not depend on a library``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget FAKE""") + + let updateAll = true + let lockFile = selectiveUpdate resolve lockFile dependenciesFile updateAll None + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","4.0.0"); + ("Castle.Core","4.0.0"); + ("FAKE","4.0.1")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate updates a single package``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget FAKE""") + + let updateAll = false + let lockFile = + Some(NormalizedPackageName(PackageName "FAKE")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.2.0"); + ("Castle.Core","3.2.0"); + ("FAKE","4.0.1"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate updates a single constrained package``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net ~> 3.2 + nuget FAKE""") + + let updateAll = false + let lockFile = + Some(NormalizedPackageName(PackageName "Castle.Core-log4net")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.3.3"); + ("Castle.Core","4.0.0"); + ("FAKE","4.0.0"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate updates a single package with constrained dependency in dependencies file``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net ~> 3.2 + nuget Castle.Core ~> 3.2 + nuget FAKE""") + + let updateAll = false + let lockFile = + Some(NormalizedPackageName(PackageName "Castle.Core-log4net")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.3.3"); + ("Castle.Core","3.3.3"); + ("FAKE","4.0.0"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate installs new packages``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget FAKE + nuget Newtonsoft.Json""") + + let updateAll = false + let lockFile = selectiveUpdate resolve lockFile dependenciesFile updateAll None + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.2.0"); + ("Castle.Core","3.2.0"); + ("FAKE","4.0.0"); + ("log4net", "1.2.10"); + ("Newtonsoft.Json", "7.0.1")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate removes a dependency when it updates a single package and it is updated to a version that does not depend on a library``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget FAKE""") + + let updateAll = false + let lockFile = + Some(NormalizedPackageName(PackageName "Castle.Core-log4net")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","4.0.0"); + ("Castle.Core","4.0.0"); + ("FAKE","4.0.0")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate does not update when a dependency constrain is not met``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget Castle.Core = 3.2.0 + nuget FAKE""") + + let updateAll = false + let lockFile = + Some(NormalizedPackageName(PackageName "Castle.Core-log4net")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.2.0"); + ("Castle.Core","3.2.0"); + ("FAKE","4.0.0"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate considers package name case difference``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget castle.core = 3.2.0 + nuget FAKE""") + + let updateAll = false + let lockFile = + Some(NormalizedPackageName(PackageName "Castle.Core-log4net")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.2.0"); + ("Castle.Core","3.2.0"); + ("FAKE","4.0.0"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate conflicts when a dependency is contrained``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget Castle.Core = 3.2.0 + nuget log4net > 1.2.10 + nuget FAKE""") + + let updateAll = false + + (fun () -> + Some(NormalizedPackageName(PackageName "Castle.Core-log4net")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + |> ignore) + |> shouldFail + +[] +let ``SelectiveUpdate does not update any package when package does not exist``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget FAKE""") + + let updateAll = false + let lockFile = + Some(NormalizedPackageName(PackageName "package")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + + let result = + lockFile.ResolvedPackages + |> Seq.map (fun (KeyValue (_,resolved)) -> (string resolved.Name, string resolved.Version)) + + let expected = + [("Castle.Core-log4net","3.2.0"); + ("Castle.Core","3.2.0"); + ("FAKE","4.0.0"); + ("log4net","1.2.10")] + |> Seq.sortBy (fun (key,_) -> key) + + result + |> Seq.sortBy (fun (key,_) -> key) + |> shouldEqual expected + +[] +let ``SelectiveUpdate generates paket.lock correctly``() = + + let dependenciesFile = DependenciesFile.FromCode("""source http://nuget.org/api/v2 + + nuget Castle.Core-log4net + nuget Castle.Core + nuget FAKE""") + + let updateAll = false + let lockFile = + Some(NormalizedPackageName(PackageName "Castle.Core")) + |> selectiveUpdate resolve lockFile dependenciesFile updateAll + + let result = + String.Join + (Environment.NewLine, + LockFileSerializer.serializePackages InstallOptions.Default lockFile.ResolvedPackages, + LockFileSerializer.serializeSourceFiles lockFile.SourceFiles) + + + let expected = """NUGET + remote: http://nuget.org/api/v2 + specs: + Castle.Core (4.0.0) + Castle.Core-log4net (3.2.0) + Castle.Core (>= 3.2.0) + log4net (1.2.10) + FAKE (4.0.0) + log4net (1.2.10) +""" + + result + |> shouldEqual (normalizeLineEndings expected) + \ No newline at end of file