Skip to content
Open
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
28 changes: 24 additions & 4 deletions src/Paket.Core/PaketConfigFiles/ProjectFile.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,20 @@ module ProjectFile =
|> Array.map (fun x -> x.Trim())
|> Array.toList

// Same as getTargetFramework/getTargetFrameworksParsed above but evaluates conditional
// PropertyGroups (e.g. `Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"`)
// using the given Configuration/Platform, instead of an empty property map.
let getTargetFrameworkWithDefaults defaultProperties (project:ProjectFile) =
getPropertyWithDefaults "TargetFramework" defaultProperties project

let getTargetFrameworksParsedWithDefaults defaultProperties (project:ProjectFile) =
getPropertyWithDefaults "TargetFrameworks" defaultProperties project
|> Option.map (fun x -> x.Split([|';'|],StringSplitOptions.RemoveEmptyEntries))
|> Option.toArray
|> Array.concat
|> Array.map (fun x -> x.Trim())
|> Array.toList

let getToolsVersion (project:ProjectFile) =
let adjustIfWeHaveSDK v =
try
Expand Down Expand Up @@ -1622,22 +1636,28 @@ module ProjectFile =
sprintf "%s.%s" assemblyName ending

let getOutputDirectory buildConfiguration buildPlatform (targetProfile : TargetProfile option) (project:ProjectFile) =
// Some projects put TargetFramework(s) inside a conditional PropertyGroup keyed on
// Configuration/Platform (e.g. `Condition="'$(Configuration)'=='Release'"`), so we must
// evaluate the property map with the requested Configuration/Platform, not an empty one,
// or the frameworks won't be found at all (see issue #3799).
let defaultProperties =
Map.ofList [("Configuration", buildConfiguration); ("Platform", buildPlatform)]
let targetFramework =
match targetProfile with
| Some targetProfile ->
let targetProfile = targetProfile.ToString()
match getTargetFramework project with
match getTargetFrameworkWithDefaults defaultProperties project with
| Some x -> if x = targetProfile then x else ""
| None ->
let parsedTargetFrameworks = getTargetFrameworksParsed project
let parsedTargetFrameworks = getTargetFrameworksParsedWithDefaults defaultProperties project
match List.tryFind ((=) targetProfile) parsedTargetFrameworks with
| Some x -> x
| None -> ""
| None ->
match getTargetFramework project with
match getTargetFrameworkWithDefaults defaultProperties project with
| Some x -> x
| None ->
match getTargetFrameworksParsed project with
match getTargetFrameworksParsedWithDefaults defaultProperties project with
| fwk :: _ -> fwk
| [] -> ""

Expand Down
2 changes: 2 additions & 0 deletions tests/Paket.Tests/Paket.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@
<Compile Include="LocalFile\LocalFileSpecs.fs" />
<Compile Include="Simplifier\BasicScenarioSpecs.fs" />
<TestAsset Include="ProjectFile\TestData\MicrosoftNetSdkWithTargetFrameworkAndOutputPath.csprojtest" />
<TestAsset Include="ProjectFile\TestData\MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest" />
<TestAsset Include="ProjectFile\TestData\MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest" />
<TestAsset Include="ProjectFile\TestData\EmptyFsharpGuid.fsprojtest" />
<TestAsset Include="ProjectFile\TestData\EmptyVbGuid.vbprojtest" />
<TestAsset Include="ProjectFile\TestData\EmptyPyGuid.pyprojtest" />
Expand Down
42 changes: 42 additions & 0 deletions tests/Paket.Tests/ProjectFile/OutputSpecs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,48 @@ let ``should detect output path for netsdk with outputPath and appendTargetFrame
let expected = (System.IO.Path.Combine(@"bin", configuration,"netstandard1.4_bin") |> normalizePath)
outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())

[<Test>]
let ``should detect output path for netsdk with conditional target frameworks csproj file``
([<Values("Debug", "Release", "dEbUg", "rElEaSe")>] configuration) =
ensureDir ()
let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworks.csprojtest").Value
// Should not throw "Unable to find <configuration> output path node" (see issue #3799)
let outPath = projectFile.GetOutputDirectory configuration "" None
outPath |> shouldNotEqual ""

[<Test>]
let ``should detect output path for netsdk with only conditional target frameworks (no unconditional fallback) csproj file``
([<Values("Debug", "Release")>] configuration) =
ensureDir ()
// Reproduces the exact shape from issue #3799: no unconditional TargetFramework/TargetFrameworks
// element exists at all, only Configuration-conditioned PropertyGroups.
let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
let outPath = projectFile.GetOutputDirectory configuration "" None
outPath |> shouldNotEqual ""

[<Test>]
let ``should pick the conditional target frameworks matching the requested configuration for netsdk csproj file``
([<Values("Debug", "Release")>] configuration) =
ensureDir ()
let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
let outPath = projectFile.GetOutputDirectory configuration "" None
// Debug config only lists netstandard2.0;net45, Release additionally lists net47;
// the first framework in each list is netstandard2.0, and it should be selected as the default.
let expected = (System.IO.Path.Combine(@"bin", configuration, "netstandard2.0") |> normalizePath)
outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())

[<Test>]
let ``should detect output path for a specific target profile in a conditional target frameworks csproj file``
([<Values("Debug", "Release")>] configuration) =
ensureDir ()
let projectFile = ProjectFile.TryLoad("./ProjectFile/TestData/MicrosoftNetSdkWithConditionalTargetFrameworksOnly.csprojtest").Value
let targetProfile =
FrameworkDetection.internalExtract "net45"
|> Option.map TargetProfile.SinglePlatform
let outPath = projectFile.GetOutputDirectory configuration "" targetProfile
let expected = (System.IO.Path.Combine(@"bin", configuration, "net45") |> normalizePath)
outPath.ToLowerInvariant() |> shouldEqual (expected.ToLowerInvariant())

[<Test>]
let ``should detect framework profile for ProjectWithConditions file`` () =
ensureDir ()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<AssemblyName>TestPaket</AssemblyName>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<TargetFrameworks>netstandard2.0;net45</TargetFrameworks>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)'=='Release'">
<TargetFrameworks>netstandard2.0;net45;net47</TargetFrameworks>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<TargetFrameworks>netstandard2.0;net45</TargetFrameworks>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)'=='Release'">
<TargetFrameworks>netstandard2.0;net45;net47</TargetFrameworks>
</PropertyGroup>
</Project>