From 001ab065cc2d606861ccd96136d4d757cf7d08ad Mon Sep 17 00:00:00 2001 From: Julien Roncaglia Date: Mon, 12 Oct 2015 18:29:16 +0200 Subject: [PATCH] Handle framework identifiers comparison FrameworkIdentifier instances were compared structurally before but it was problematic in some cases as '>= net45' matched 'sl40' that wasn't in the same framework. Fixes #1124 --- src/Paket.Core/FrameworkHandling.fs | 17 ++++ src/Paket.Core/InstallModel.fs | 8 +- src/Paket.Core/PackageResolver.fs | 2 + src/Paket.Core/Requirements.fs | 25 +++++- .../RestrictionApplicationSpecs.fs | 84 ++++++++++++++++--- 5 files changed, 119 insertions(+), 17 deletions(-) diff --git a/src/Paket.Core/FrameworkHandling.fs b/src/Paket.Core/FrameworkHandling.fs index 471ae81232..68fba3aa6d 100644 --- a/src/Paket.Core/FrameworkHandling.fs +++ b/src/Paket.Core/FrameworkHandling.fs @@ -141,6 +141,23 @@ type FrameworkIdentifier = | WindowsPhoneApp _ -> [ WindowsPhoneApp "v8.1" ] | WindowsPhoneSilverlight _ -> [ WindowsPhoneSilverlight "v8.1" ] + /// Return if the parameter is of the same framework category (dotnet, windows phone, silverlight, ...) + member x.IsSameCategoryAs y = + match (x, y) with + | DotNetFramework _, DotNetFramework _ -> true + | Silverlight _, Silverlight _ -> true + | DNX _, DNX _ -> true + | DNXCore _, DNXCore _ -> true + | MonoAndroid _, MonoAndroid _ -> true + | MonoMac _, MonoMac _ -> true + | MonoTouch _, MonoTouch _ -> true + | Windows _, Windows _ -> true + | WindowsPhoneApp _, WindowsPhoneApp _ -> true + | WindowsPhoneSilverlight _, WindowsPhoneSilverlight _ -> true + | XamarinMac _, XamarinMac _ -> true + | XamariniOS _, XamariniOS _ -> true + | _ -> false + module FrameworkDetection = let private cache = System.Collections.Concurrent.ConcurrentDictionary<_,_>() diff --git a/src/Paket.Core/InstallModel.fs b/src/Paket.Core/InstallModel.fs index 8afb16de85..383806f6cf 100644 --- a/src/Paket.Core/InstallModel.fs +++ b/src/Paket.Core/InstallModel.fs @@ -230,21 +230,21 @@ type InstallModel = restrictions |> List.exists (fun restriction -> match restriction with - | FrameworkRestriction.Portable p -> + | FrameworkRestriction.Portable _ -> folder.Targets |> List.exists (fun target -> match target with - | SinglePlatform t -> false + | SinglePlatform _ -> false | _ -> true) | FrameworkRestriction.Exactly target -> folder.GetSinglePlatforms() |> List.exists (fun t -> t = target) | FrameworkRestriction.AtLeast target -> folder.GetSinglePlatforms() - |> List.exists (fun t -> t >= target) + |> List.exists (fun t -> t >= target && t.IsSameCategoryAs(target)) | FrameworkRestriction.Between(min,max) -> folder.GetSinglePlatforms() - |> List.exists (fun t -> t >= min && t < max) ) + |> List.exists (fun t -> t >= min && t < max && t.IsSameCategoryAs(min))) this.MapFolders(fun folder -> if referenceApplies folder then diff --git a/src/Paket.Core/PackageResolver.fs b/src/Paket.Core/PackageResolver.fs index 38c9c78527..1f1ff8e75c 100644 --- a/src/Paket.Core/PackageResolver.fs +++ b/src/Paket.Core/PackageResolver.fs @@ -18,6 +18,7 @@ module DependencySetFilter = match restriction with | FrameworkRestriction.Exactly v1 -> restrictions + |> Seq.filter (fun r2 -> restriction.IsSameCategoryAs(r2) = Some(true)) |> Seq.exists (fun r2 -> match r2 with | FrameworkRestriction.Exactly v2 when v1 = v2 -> true @@ -26,6 +27,7 @@ module DependencySetFilter = | _ -> false) | FrameworkRestriction.AtLeast v1 -> restrictions + |> Seq.filter (fun r2 -> restriction.IsSameCategoryAs(r2) = Some(true)) |> Seq.exists (fun r2 -> match r2 with | FrameworkRestriction.Exactly v2 when v1 <= v2 -> true diff --git a/src/Paket.Core/Requirements.fs b/src/Paket.Core/Requirements.fs index d995724b72..a2ad3dafad 100644 --- a/src/Paket.Core/Requirements.fs +++ b/src/Paket.Core/Requirements.fs @@ -19,6 +19,19 @@ type FrameworkRestriction = | FrameworkRestriction.AtLeast r -> ">= " + r.ToString() | FrameworkRestriction.Between(min,max) -> sprintf ">= %O < %O" min max + member private x.GetOneIdentifier = + match x with + | Exactly r -> Some r + | Portable _ -> None + | AtLeast r -> Some r + | Between(r, _) -> Some r + + /// Return if the parameter is a restriction of the same framework category (dotnet, windows phone, silverlight, ...) + member x.IsSameCategoryAs (y : FrameworkRestriction) = + match (x.GetOneIdentifier, y.GetOneIdentifier) with + | Some r, Some r' -> Some(r.IsSameCategoryAs r') + | _ -> None + type FrameworkRestrictions = FrameworkRestriction list @@ -172,7 +185,7 @@ let optimizeDependencies packages = yield name,versionRequirement,others @ restrictions] -let combineRestrictions x y = +let private combineSameCategoryOrPortableRestrictions x y = match x with | FrameworkRestriction.Exactly r -> match y with @@ -202,6 +215,12 @@ let combineRestrictions x y = if min' = max' then [FrameworkRestriction.Exactly(min')] else [] +let combineRestrictions (x : FrameworkRestriction) y = + if (x.IsSameCategoryAs(y) = Some(false)) then + [] + else + combineSameCategoryOrPortableRestrictions x y + let filterRestrictions (list1:FrameworkRestrictions) (list2:FrameworkRestrictions) = match list1,list2 with | [],_ -> list2 @@ -221,8 +240,8 @@ let isTargetMatchingRestrictions (restrictions:FrameworkRestrictions) = function match restriction with | FrameworkRestriction.Exactly fw -> pf = fw | FrameworkRestriction.Portable _ -> false - | FrameworkRestriction.AtLeast fw -> pf >= fw - | FrameworkRestriction.Between(min,max) -> pf >= min && pf < max) + | FrameworkRestriction.AtLeast fw -> pf >= fw && pf.IsSameCategoryAs(fw) + | FrameworkRestriction.Between(min,max) -> pf >= min && pf < max && pf.IsSameCategoryAs(min)) | _ -> restrictions |> List.exists (fun restriction -> diff --git a/tests/Paket.Tests/RestrictionApplicationSpecs.fs b/tests/Paket.Tests/RestrictionApplicationSpecs.fs index 16fa95ca5b..50bc8e175b 100644 --- a/tests/Paket.Tests/RestrictionApplicationSpecs.fs +++ b/tests/Paket.Tests/RestrictionApplicationSpecs.fs @@ -1,19 +1,83 @@ -module Packet.RestrictionApplicationSpecs +module Paket.Requirements.RestrictionApplicationSpecs -open System.IO open Paket -open Paket.Domain -open Chessie.ErrorHandling open FsUnit open NUnit.Framework -open TestHelpers open Paket.Requirements +let dotnet x = SinglePlatform(DotNetFramework(x)) + +module TestTargetProfiles = + let DotNetFrameworkVersions = + [FrameworkVersion.V1 + FrameworkVersion.V1_1 + FrameworkVersion.V2 + FrameworkVersion.V3 + FrameworkVersion.V3_5 + FrameworkVersion.V4_Client + FrameworkVersion.V4 + FrameworkVersion.V4_5 + FrameworkVersion.V4_5_1 + FrameworkVersion.V4_5_2 + FrameworkVersion.V4_5_3 + FrameworkVersion.V4_6] + + let DotNetFrameworkProfiles = DotNetFrameworkVersions |> List.map dotnet + + let WindowsProfiles = + [SinglePlatform(Windows "v4.5") + SinglePlatform(Windows "v4.5.1")] + + let SilverlightProfiles = + [SinglePlatform(Silverlight "v3.0") + SinglePlatform(Silverlight "v4.0") + SinglePlatform(Silverlight "v5.0")] + + let WindowsPhoneSilverlightProfiles = + [SinglePlatform(WindowsPhoneSilverlight "v7.0") + SinglePlatform(WindowsPhoneSilverlight "v7.1") + SinglePlatform(WindowsPhoneSilverlight "v8.0") + SinglePlatform(WindowsPhoneSilverlight "v8.1")] + + let AllProfiles = + DotNetFrameworkProfiles @ + WindowsProfiles @ + SilverlightProfiles @ + WindowsPhoneSilverlightProfiles @ + [SinglePlatform(MonoAndroid) + SinglePlatform(MonoTouch) + SinglePlatform(XamariniOS) + SinglePlatform(XamarinMac) + SinglePlatform(WindowsPhoneApp "v8.1") + ] + [] -let ``>= net40 does not include silverlight (#1124)`` () = +let ``>= net10 contains all but only dotnet versions (#1124)`` () = /// https://github.com/fsprojects/Paket/issues/1124 - let restrictions = [FrameworkRestriction.AtLeast(DotNetFramework(FrameworkVersion.V4))] - let targets = KnownTargetProfiles.DotNetFrameworkProfiles @ KnownTargetProfiles.SilverlightProfiles - let restricted = applyRestrictionsToTargets restrictions targets + let restrictions = [FrameworkRestriction.AtLeast(DotNetFramework(FrameworkVersion.V1))] + let restricted = applyRestrictionsToTargets restrictions TestTargetProfiles.AllProfiles + + restricted |> shouldEqual TestTargetProfiles.DotNetFrameworkProfiles + +[] +let ``>= net452 contains 4.5.2 and following versions`` () = + let restrictions = [FrameworkRestriction.AtLeast(DotNetFramework(FrameworkVersion.V4_5_2))] + let restricted = applyRestrictionsToTargets restrictions TestTargetProfiles.AllProfiles + let expected = [FrameworkVersion.V4_5_2; FrameworkVersion.V4_5_3; FrameworkVersion.V4_6] |> List.map dotnet + + restricted |> shouldEqual expected + +[] +let ``>= net40 < net451 contains 4.0 and 4.5`` () = + let restrictions = [FrameworkRestriction.Between(DotNetFramework(FrameworkVersion.V4), DotNetFramework(FrameworkVersion.V4_5_1))] + let restricted = applyRestrictionsToTargets restrictions TestTargetProfiles.AllProfiles + let expected = [FrameworkVersion.V4; FrameworkVersion.V4_5] |> List.map dotnet + + restricted |> shouldEqual expected + +[] +let ``>= sl30 contains all but only silverlight versions`` () = + let restrictions = [FrameworkRestriction.AtLeast(Silverlight "v3.0")] + let restricted = applyRestrictionsToTargets restrictions TestTargetProfiles.AllProfiles - restricted |> shouldEqual KnownTargetProfiles.DotNetFrameworkProfiles \ No newline at end of file + restricted |> shouldEqual TestTargetProfiles.SilverlightProfiles \ No newline at end of file