From f4f68e47051ede0587d01bd431e0b28f79817bf2 Mon Sep 17 00:00:00 2001 From: Fyodor Soikin Date: Tue, 11 Jul 2017 13:26:55 -0400 Subject: [PATCH] Carefuly handle cases when the .paket folder is present in .sln file, not present, or is empty. Fixes #2512. --- .../ConvertFromNuGetSpecs.fs | 33 +++++++++++----- .../before/{2161.sln => sln.sln} | 0 .../before/proj.fsproj | 10 +++++ .../before/sln.sln | 34 ++++++++++++++++ .../before/proj.fsproj | 10 +++++ .../before/sln.sln | 39 +++++++++++++++++++ .../PaketConfigFiles/SolutionFile.fs | 27 ++++++++++--- 7 files changed, 139 insertions(+), 14 deletions(-) rename integrationtests/scenarios/i002161-convert-existing-paket-folder/before/{2161.sln => sln.sln} (100%) create mode 100644 integrationtests/scenarios/i002512-convert-absent-paket-folder/before/proj.fsproj create mode 100644 integrationtests/scenarios/i002512-convert-absent-paket-folder/before/sln.sln create mode 100644 integrationtests/scenarios/i002512-convert-paket-folder-with-files/before/proj.fsproj create mode 100644 integrationtests/scenarios/i002512-convert-paket-folder-with-files/before/sln.sln diff --git a/integrationtests/Paket.IntegrationTests/ConvertFromNuGetSpecs.fs b/integrationtests/Paket.IntegrationTests/ConvertFromNuGetSpecs.fs index 696609bd46..ad2557917d 100644 --- a/integrationtests/Paket.IntegrationTests/ConvertFromNuGetSpecs.fs +++ b/integrationtests/Paket.IntegrationTests/ConvertFromNuGetSpecs.fs @@ -90,15 +90,30 @@ let ``#1922 should remove references to moved analyzers``() = StringAssert.Contains(@"", projectXml) StringAssert.Contains(@"", projectXml) -[] -let ``#2161 should put paket.dependencies inside the .paket folder when it's already present in the sln file``() = - let scenario = "i002161-convert-existing-paket-folder" +let testPaketDependenciesFileInSolution scenario expectedFiles = paket "convert-from-nuget" scenario |> ignore + + let expectedLines = + [ yield "Project\\(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\"\\) = \"\\.paket\", \"\\.paket\", \"{[^}]+}\"" + yield "\s*ProjectSection\\(SolutionItems\\) = preProject" + for f in expectedFiles do yield sprintf "\s*%s = %s" f f + yield "\s*EndProjectSection" + yield "EndProject" ] + |> String.concat Environment.NewLine + + let slnFileText = File.ReadAllText(Path.Combine(scenarioTempPath scenario, "sln.sln")) - let slnLines = File.ReadAllLines(Path.Combine(scenarioTempPath scenario, "2161.sln")) - let sectionOpenLine = slnLines |> Array.findIndex (fun line -> line.StartsWith "Project" && line.Contains "\".paket\"") - let sectionEndLine = sectionOpenLine + (slnLines |> Seq.skip sectionOpenLine |> Seq.findIndex (fun line -> line.StartsWith "EndProject")) - let depsFileLine = slnLines |> Array.findIndex (fun line -> line.Contains "paket.dependencies") + System.Text.RegularExpressions.Regex.IsMatch(slnFileText, expectedLines) + |> shouldEqual true + +[] +let ``#2161 should put paket.dependencies inside the .paket folder when it's already present in the sln file``() = + testPaketDependenciesFileInSolution "i002161-convert-existing-paket-folder" ["paket.dependencies"] - sectionOpenLine |> shouldBeSmallerThan depsFileLine - sectionEndLine |> shouldBeGreaterThan depsFileLine \ No newline at end of file +[] +let ``#2512 should put paket.dependencies inside the .paket folder when it's absent in the sln file``() = + testPaketDependenciesFileInSolution "i002512-convert-absent-paket-folder" ["paket.dependencies"] + +[] +let ``#2512 should put paket.dependencies inside the .paket folder that already has files in it``() = + testPaketDependenciesFileInSolution "i002512-convert-paket-folder-with-files" ["paket.dependencies"; "SomeFile"] \ No newline at end of file diff --git a/integrationtests/scenarios/i002161-convert-existing-paket-folder/before/2161.sln b/integrationtests/scenarios/i002161-convert-existing-paket-folder/before/sln.sln similarity index 100% rename from integrationtests/scenarios/i002161-convert-existing-paket-folder/before/2161.sln rename to integrationtests/scenarios/i002161-convert-existing-paket-folder/before/sln.sln diff --git a/integrationtests/scenarios/i002512-convert-absent-paket-folder/before/proj.fsproj b/integrationtests/scenarios/i002512-convert-absent-paket-folder/before/proj.fsproj new file mode 100644 index 0000000000..7ac825999a --- /dev/null +++ b/integrationtests/scenarios/i002512-convert-absent-paket-folder/before/proj.fsproj @@ -0,0 +1,10 @@ + + + Exe + netcoreapp1.1 + + + + + + \ No newline at end of file diff --git a/integrationtests/scenarios/i002512-convert-absent-paket-folder/before/sln.sln b/integrationtests/scenarios/i002512-convert-absent-paket-folder/before/sln.sln new file mode 100644 index 0000000000..2834665b05 --- /dev/null +++ b/integrationtests/scenarios/i002512-convert-absent-paket-folder/before/sln.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "proj", "proj.fsproj", "{5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|x64.ActiveCfg = Debug|x64 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|x64.Build.0 = Debug|x64 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|x86.ActiveCfg = Debug|x86 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|x86.Build.0 = Debug|x86 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|Any CPU.Build.0 = Release|Any CPU + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|x64.ActiveCfg = Release|x64 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|x64.Build.0 = Release|x64 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|x86.ActiveCfg = Release|x86 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|x86.Build.0 = Release|x86 + EndGlobalSection +EndGlobal diff --git a/integrationtests/scenarios/i002512-convert-paket-folder-with-files/before/proj.fsproj b/integrationtests/scenarios/i002512-convert-paket-folder-with-files/before/proj.fsproj new file mode 100644 index 0000000000..7ac825999a --- /dev/null +++ b/integrationtests/scenarios/i002512-convert-paket-folder-with-files/before/proj.fsproj @@ -0,0 +1,10 @@ + + + Exe + netcoreapp1.1 + + + + + + \ No newline at end of file diff --git a/integrationtests/scenarios/i002512-convert-paket-folder-with-files/before/sln.sln b/integrationtests/scenarios/i002512-convert-paket-folder-with-files/before/sln.sln new file mode 100644 index 0000000000..8de292167b --- /dev/null +++ b/integrationtests/scenarios/i002512-convert-paket-folder-with-files/before/sln.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "proj", "proj.fsproj", "{5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{75DC0F05-EDD7-4CAD-B88E-9BA4DFCDDAE2}" + ProjectSection(SolutionItems) = preProject + SomeFile = SomeFile + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|x64.ActiveCfg = Debug|x64 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|x64.Build.0 = Debug|x64 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|x86.ActiveCfg = Debug|x86 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Debug|x86.Build.0 = Debug|x86 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|Any CPU.Build.0 = Release|Any CPU + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|x64.ActiveCfg = Release|x64 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|x64.Build.0 = Release|x64 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|x86.ActiveCfg = Release|x86 + {5AB9014A-86E7-4A3C-8731-AC5220ABB7F8}.Release|x86.Build.0 = Release|x86 + EndGlobalSection +EndGlobal diff --git a/src/Paket.Core/PaketConfigFiles/SolutionFile.fs b/src/Paket.Core/PaketConfigFiles/SolutionFile.fs index 3e13d0b32a..03b8533cfb 100644 --- a/src/Paket.Core/PaketConfigFiles/SolutionFile.fs +++ b/src/Paket.Core/PaketConfigFiles/SolutionFile.fs @@ -22,12 +22,15 @@ type SolutionFile(fileName: string) = content.RemoveRange(index, 4) | None -> () + let projectSectionLines = + [ "\tProjectSection(SolutionItems) = preProject"; + "\tEndProjectSection" ] + let addPaketFolder () = let lines = - [sprintf "Project(\"{%s}\") = \".paket\", \".paket\", \"{%s}\"" Constants.SolutionFolderProjectGuid (Guid.NewGuid().ToString("D").ToUpper()); - " ProjectSection(SolutionItems) = preProject"; - " EndProjectSection"; - "EndProject"] + [sprintf "Project(\"{%s}\") = \".paket\", \".paket\", \"{%s}\"" Constants.SolutionFolderProjectGuid (Guid.NewGuid().ToString("D").ToUpper())] + @ projectSectionLines + @ [ "EndProject" ] let index = match content |> Seq.tryFindIndex (fun line -> line.StartsWith("Project")) with @@ -46,10 +49,24 @@ type SolutionFile(fileName: string) = let addPaketFiles(paketProjectIndex, length, dependenciesFile, lockFile) = let projectLines = content.GetRange(paketProjectIndex, length) + + // This here is ad-hoc hacky solution to sln ambiguity. + // The problen is that the .sln file may or may not contain a "ProjectSection" within the ".paket" "Project" (see #2161 and #2512). + // When the "ProjectSection" is not there, we need to add it, and then add new files within it. + // A better solution would be to have a proper parser for the .sln file, but that would take too long, and would probably be a waste anyway. + let firstLineInPaketProject = if paketProjectIndex < content.Count-1 then content.[paketProjectIndex+1] else "" + if not (firstLineInPaketProject.Contains "ProjectSection") then + if firstLineInPaketProject.Contains "EndProject" then + // The "Project" is empty => insert "ProjectSection" + content.InsertRange( paketProjectIndex+1, projectSectionLines ) + else + // The "Project" is not empty, but also doesn't contain a "ProjectSection" => no idea what this means, + // so just fall back to old behavior and insert new lines at +2 after "Project" start. + () let add s = if not <| Seq.exists (fun line -> line = s) projectLines - then content.Insert(paketProjectIndex + 1, s) + then content.Insert(paketProjectIndex + 2, s) Option.iter (fun lockFile -> add (sprintf" %s = %s" lockFile lockFile)) lockFile