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

Handle silverlight framework identifiers comparison #1130

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 2 additions & 20 deletions src/Paket.Core/InstallModel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -288,25 +288,7 @@ type InstallModel =
| [] -> this
| restrictions ->
let applRestriction folder =
{ folder with
Targets =
folder.Targets
|> List.filter
(function
| SinglePlatform pf ->
restrictions
|> List.exists (fun restriction ->
match restriction with
| FrameworkRestriction.Exactly fw -> pf = fw
| FrameworkRestriction.Portable r -> false
| FrameworkRestriction.AtLeast fw -> pf >= fw
| FrameworkRestriction.Between(min,max) -> pf >= min && pf < max)
| _ ->
restrictions
|> List.exists (fun restriction ->
match restriction with
| FrameworkRestriction.Portable r -> true
| _ -> false))}
{ folder with Targets = applyRestrictionsToTargets restrictions folder.Targets}

{this with
ReferenceFileFolders =
Expand All @@ -317,7 +299,7 @@ type InstallModel =
TargetsFileFolders =
this.TargetsFileFolders
|> List.map applRestriction
|> List.filter (fun folder -> folder.Targets <> []) }
|> List.filter (fun folder -> folder.Targets <> []) }

member this.GetFrameworkAssembliesLazy =
lazy ([ for lib in this.ReferenceFileFolders do
Expand Down
12 changes: 7 additions & 5 deletions src/Paket.Core/PublicAPI.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type Dependencies(dependenciesFileName: string) =
let listPackages (packages: System.Collections.Generic.KeyValuePair<GroupName*PackageName, PackageResolver.ResolvedPackage> seq) =
packages
|> Seq.map (fun kv ->
let groupName,packageName = kv.Key
let groupName,packageName = kv.Key
groupName.ToString(),packageName.ToString(),kv.Value.Version.ToString())
|> Seq.toList

Expand All @@ -33,13 +33,13 @@ type Dependencies(dependenciesFileName: string) =
path
else
let parent = dir.Parent
if parent = null then
match parent with
| null ->
if withError then
failwithf "Could not find '%s'. To use Paket with this solution, please run 'paket init' first." Constants.DependenciesFileName
else
Constants.DependenciesFileName
else
findInPath(parent, withError)
| _ -> findInPath(parent, withError)

let dependenciesFileName = findInPath(DirectoryInfo path,true)
verbosefn "found: %s" dependenciesFileName
Expand Down Expand Up @@ -404,7 +404,9 @@ type Dependencies(dependenciesFileName: string) =
let cancellationToken = defaultArg cancellationToken (System.Threading.CancellationToken())
let maxResults = defaultArg maxResults 1000
let sources = this.GetSources() |> Seq.map (fun kv -> kv.Value) |> List.concat |> List.distinct
if sources = [] then [PackageSources.DefaultNugetSource] else sources
match sources with
| [] -> [PackageSources.DefaultNugetSource]
| _ -> sources
|> List.choose (fun x -> match x with | Nuget s -> Some s.Url | _ -> None)
|> Seq.distinct
|> Seq.map (fun url ->
Expand Down
126 changes: 79 additions & 47 deletions src/Paket.Core/Requirements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type FrameworkRestriction =
| Between of FrameworkIdentifier * FrameworkIdentifier

override this.ToString() =
match this with
match this with
| FrameworkRestriction.Exactly r -> r.ToString()
| FrameworkRestriction.Portable r -> r
| FrameworkRestriction.AtLeast r -> ">= " + r.ToString()
Expand Down Expand Up @@ -72,7 +72,7 @@ let rec optimizeRestrictions restrictions =
let newRestrictions' =
restrictions
|> List.distinct
|> List.sort
|> List.sort

let newRestrictions =
match newRestrictions' |> Seq.tryFind (function | FrameworkRestriction.AtLeast r -> true | _ -> false) with
Expand All @@ -81,14 +81,15 @@ let rec optimizeRestrictions restrictions =
let currentVersion =
match r with
| FrameworkRestriction.AtLeast(DotNetFramework(x)) -> x
| x -> failwithf "Unknown .NET moniker %O" x
| x -> failwithf "Unknown .NET moniker %O" x

let isLowerVersion x =
let isMatching x =
if x = FrameworkVersion.V3_5 && currentVersion = FrameworkVersion.V4 then true else
if x = FrameworkVersion.V4_Client && currentVersion = FrameworkVersion.V4_5 then true else
let hasFrameworksBetween = KnownTargetProfiles.DotNetFrameworkVersions |> Seq.exists (fun p -> p > x && p < currentVersion)
not hasFrameworksBetween
KnownTargetProfiles.DotNetFrameworkVersions
|> Seq.exists (fun p -> p > x && p < currentVersion)
|> not

match x with
| FrameworkRestriction.Exactly(DotNetFramework(x)) -> isMatching x
Expand All @@ -102,7 +103,7 @@ let rec optimizeRestrictions restrictions =
match n with
| FrameworkRestriction.Exactly(DotNetFramework(x)) -> x
| FrameworkRestriction.AtLeast(DotNetFramework(x)) -> x
| x -> failwithf "Unknown .NET moniker %O" x
| x -> failwithf "Unknown .NET moniker %O" x

(newRestrictions'
|> List.filter (fun x -> x <> r && x <> n)) @ [FrameworkRestriction.AtLeast(DotNetFramework(newLowest))]
Expand All @@ -111,8 +112,6 @@ let rec optimizeRestrictions restrictions =


let optimizeDependencies packages =
let grouped = packages |> List.groupBy (fun (n,v,_) -> n,v)

let invertedRestrictions =
let expanded =
[for (n,vr,r:FrameworkRestrictions) in packages do
Expand All @@ -136,71 +135,66 @@ let optimizeDependencies packages =

let emptyRestrictions =
[for (n,vr,r:FrameworkRestrictions) in packages do
if r = [] then
if List.isEmpty r then
yield n,vr]
|> Set.ofList

let grouped = packages |> List.filter (fun (name,_,_) -> name <> PackageName "") |> List.groupBy (fun (n,v,_) -> n,v)
[for (name,versionRequirement:VersionRequirement),group in grouped do
if name <> PackageName "" then
if not (Set.isEmpty emptyRestrictions) && Set.contains (name,versionRequirement) emptyRestrictions then
yield name,versionRequirement,[]
else
let plain =
group
|> List.map (fun (_,_,res) -> res)
|> List.concat
|> List.distinct
|> List.sort

let localMaxDotNetRestriction = findMaxDotNetRestriction plain
let globalMax = defaultArg globalMax localMaxDotNetRestriction
if not (Set.isEmpty emptyRestrictions) && Set.contains (name,versionRequirement) emptyRestrictions then
yield name,versionRequirement,[]
else
let plain =
group
|> List.map (fun (_,_,res) -> res)
|> List.concat
|> List.distinct
|> List.sort

let dotnetRestrictions,others = List.partition (function | FrameworkRestriction.Exactly(DotNetFramework(_)) -> true | FrameworkRestriction.AtLeast(DotNetFramework(_)) -> true | _ -> false) plain
let localMaxDotNetRestriction = findMaxDotNetRestriction plain
let globalMax = defaultArg globalMax localMaxDotNetRestriction

let restrictions' =
dotnetRestrictions
|> List.map (fun restriction ->
match restriction with
| FrameworkRestriction.Exactly r ->
if r = localMaxDotNetRestriction && r = globalMax then
FrameworkRestriction.AtLeast r
else
restriction
| _ -> restriction)
let dotnetRestrictions,others = List.partition (function | FrameworkRestriction.Exactly(DotNetFramework(_)) -> true | FrameworkRestriction.AtLeast(DotNetFramework(_)) -> true | _ -> false) plain

let restrictions = optimizeRestrictions restrictions'
let restrictions' =
dotnetRestrictions
|> List.map (fun restriction ->
match restriction with
| FrameworkRestriction.Exactly r when r = localMaxDotNetRestriction && r = globalMax ->
FrameworkRestriction.AtLeast r
| _ -> restriction)

yield name,versionRequirement,others @ restrictions]
yield name,versionRequirement,others @ optimizeRestrictions restrictions']

let combineRestrictions x y =
match x with
| FrameworkRestriction.Exactly r ->
match y with
| FrameworkRestriction.Exactly r' -> if r = r' then [FrameworkRestriction.Exactly r] else []
| FrameworkRestriction.Portable _ -> []
| FrameworkRestriction.AtLeast r' -> if r' <= r then [FrameworkRestriction.Exactly r] else []
| FrameworkRestriction.Between(min,max) -> if min <= r && r <= max then [FrameworkRestriction.Exactly r] else []
| FrameworkRestriction.Exactly r' when r = r' -> [FrameworkRestriction.Exactly r]
| FrameworkRestriction.AtLeast r' when r' <= r -> [FrameworkRestriction.Exactly r]
| FrameworkRestriction.Between(min,max) when min <= r && r <= max -> [FrameworkRestriction.Exactly r]
| _ -> []
| FrameworkRestriction.Portable r ->
match y with
| FrameworkRestriction.Portable r' -> if r = r' then [FrameworkRestriction.Portable r] else []
| FrameworkRestriction.Portable r' when r = r' ->[FrameworkRestriction.Portable r]
| _ -> []
| FrameworkRestriction.AtLeast r ->
match y with
| FrameworkRestriction.Exactly r' -> if r <= r' then [FrameworkRestriction.Exactly r'] else []
| FrameworkRestriction.Portable _ -> []
| FrameworkRestriction.Exactly r' when r <= r' -> [FrameworkRestriction.Exactly r']
| FrameworkRestriction.AtLeast r' -> [FrameworkRestriction.AtLeast (max r r')]
| FrameworkRestriction.Between(min,max) -> if min <= r && r <= max then [FrameworkRestriction.Between(r,max)] else []
| FrameworkRestriction.Between(min,max) when min <= r && r <= max -> [FrameworkRestriction.Between(r,max)]
| _ -> []
| FrameworkRestriction.Between(min1,max1) ->
match y with
| FrameworkRestriction.Exactly r -> if min1 <= r && r <= max1 then [FrameworkRestriction.Exactly r] else []
| FrameworkRestriction.Portable _ -> []
| FrameworkRestriction.AtLeast r -> if min1 <= r && r <= max1 then [FrameworkRestriction.Between(r,max1)] else []
| FrameworkRestriction.Between(min2,max2) ->
| FrameworkRestriction.Exactly r when min1 <= r && r <= max1 -> [FrameworkRestriction.Exactly r]
| FrameworkRestriction.AtLeast r when min1 <= r && r <= max1 -> [FrameworkRestriction.Between(r,max1)]
| FrameworkRestriction.Between(min2,max2) ->
let min' = max min1 min2
let max' = min max1 max2
if min' < max' then [FrameworkRestriction.Between(min',max')] else
if min' = max' then [FrameworkRestriction.Exactly(min')] else
[]
| _ -> []

let filterRestrictions (list1:FrameworkRestrictions) (list2:FrameworkRestrictions) =
match list1,list2 with
Expand All @@ -213,6 +207,44 @@ let filterRestrictions (list1:FrameworkRestrictions) (list2:FrameworkRestriction
if c <> [] then yield! c]
|> optimizeRestrictions

let inline frameworkCategory (fw:FrameworkIdentifier) =
match fw with
| DotNetFramework _ -> ".NET"
| Silverlight _ -> "Silverlight"
| DNX _ -> "DNX"
| DNXCore _ -> "DNXCore"
| MonoAndroid _ -> "MonoAndroid"
| MonoMac _ -> "MonoMac"
| MonoTouch _ -> "MonoTouch"
| Windows _ -> "Windows"
| WindowsPhoneApp _ -> "WindowsPhoneApp"
| WindowsPhoneSilverlight _ -> "WindowsPhoneSilverlight"
| XamarinMac _ -> "XamarinMac"
| XamariniOS _ -> "XamariniOS"


/// Get if a target should be considered with the specified restrictions
let isTargetMatchingRestrictions (restrictions:FrameworkRestrictions) = function
| SinglePlatform pf ->
restrictions
|> List.exists (fun restriction ->
match restriction with
| FrameworkRestriction.Exactly fw -> pf = fw
| FrameworkRestriction.Portable _ -> false
| FrameworkRestriction.AtLeast fw -> pf >= fw && frameworkCategory pf = frameworkCategory fw
| FrameworkRestriction.Between(min,max) -> pf >= min && pf < max && frameworkCategory pf = frameworkCategory min)
| PortableProfile(_) ->
restrictions
|> List.exists (fun restriction ->
match restriction with
| FrameworkRestriction.Portable _ -> true
| _ -> false)

/// Get all targets that should be considered with the specified restrictions
let applyRestrictionsToTargets (restrictions:FrameworkRestrictions) (targets: TargetProfile list) =
let result = targets |> List.filter (isTargetMatchingRestrictions restrictions)
result

type ContentCopySettings =
| Omit
| Overwrite
Expand Down
3 changes: 2 additions & 1 deletion tests/Paket.Tests/Paket.Tests.fsproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -308,6 +308,7 @@
<Compile Include="InstallModel\Penalty\FrameworkConditionsSpecs.fs" />
<Compile Include="InstallModel\AnalyzerSpecs.fs" />
<Compile Include="DependencyModel\ProjectDependencySpecs.fs" />
<Compile Include="Requirements\RestrictionApplicationSpecs.fs" />
<None Include="paket.references" />
</ItemGroup>
<ItemGroup>
Expand Down
83 changes: 83 additions & 0 deletions tests/Paket.Tests/Requirements/RestrictionApplicationSpecs.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
module Paket.Requirements.RestrictionApplicationSpecs

open Paket
open FsUnit
open NUnit.Framework
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")
]

[<Test>]
let ``>= net10 contains all but only dotnet versions (#1124)`` () =
/// https://github.com/fsprojects/Paket/issues/1124
let restrictions = [FrameworkRestriction.AtLeast(DotNetFramework(FrameworkVersion.V1))]
let restricted = applyRestrictionsToTargets restrictions TestTargetProfiles.AllProfiles

restricted |> shouldEqual TestTargetProfiles.DotNetFrameworkProfiles

[<Test>]
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

[<Test>]
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

[<Test>]
let ``>= sl30 contains all but only silverlight versions`` () =
let restrictions = [FrameworkRestriction.AtLeast(Silverlight "v3.0")]
let restricted = applyRestrictionsToTargets restrictions TestTargetProfiles.AllProfiles

restricted |> shouldEqual TestTargetProfiles.SilverlightProfiles