Skip to content

Commit 65281d7

Browse files
authored
Filter out non-design time capable projects (#225)
* fantomas livves * add failing tests * Build design time projects only
1 parent a6d01ee commit 65281d7

File tree

10 files changed

+189
-52
lines changed

10 files changed

+189
-52
lines changed

.config/dotnet-tools.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
{
2-
"version": 1,
3-
"isRoot": true,
4-
"tools": {}
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"fantomas": {
6+
"version": "7.0.0",
7+
"commands": [
8+
"fantomas"
9+
],
10+
"rollForward": false
11+
}
12+
}
513
}

src/Ionide.ProjInfo/Library.fs

Lines changed: 69 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,14 @@ module SdkDiscovery =
4545
|> Seq.toArray
4646

4747
p.WaitForExit()
48+
4849
if p.ExitCode = 0 then
4950
output
5051
elif failOnError then
51-
let output = output |> String.concat "\n"
52+
let output =
53+
output
54+
|> String.concat "\n"
55+
5256
failwith $"`{binaryFullPath.FullName} {args}` failed with exit code %i{p.ExitCode}. Output: %s{output}"
5357
else
5458
// for the legacy VS flow, whose behaviour is harder to test, we maintain compatibility with how proj-info
@@ -340,6 +344,20 @@ module ProjectLoader =
340344
internal
341345
| StandardProject of ProjectInstance
342346
| TraversalProject of ProjectInstance
347+
/// This could be things like shproj files, or other things that aren't standard projects
348+
| Other of ProjectInstance
349+
350+
let (|IsTraversal|_|) (p: ProjectInstance) =
351+
match p.GetProperty "IsTraversal" with
352+
| null -> None
353+
| p when Boolean.TryParse(p.EvaluatedValue) = (true, false) -> None
354+
| _ -> Some()
355+
356+
let (|DesignTimeCapable|_|) (targets: string seq) (p: ProjectInstance) =
357+
if Seq.forall p.Targets.ContainsKey targets then
358+
Some()
359+
else
360+
None
343361

344362
let internal projectLoaderLogger = lazy (LogProvider.getLoggerByName "ProjectLoader")
345363

@@ -411,11 +429,12 @@ module ProjectLoader =
411429
match _message with
412430
| null ->
413431
// if the project is already loaded throw a nicer message
414-
let message = System.Text.StringBuilder()
432+
let message = Text.StringBuilder()
433+
let appendLine (t: string) (sb: Text.StringBuilder) = sb.AppendLine t
415434

416435
message
417-
.AppendLine($"The project '{projectPath}' already exists in the project collection with the same global properties.")
418-
.AppendLine("The global properties requested were:")
436+
|> appendLine $"The project '{projectPath}' already exists in the project collection with the same global properties."
437+
|> appendLine "The global properties requested were:"
419438
|> ignore
420439

421440
for (KeyValue(k, v)) in properties do
@@ -617,7 +636,7 @@ module ProjectLoader =
617636
let lines: seq<string> = File.ReadLines path
618637

619638
(Seq.tryFind (fun (line: string) -> line.Contains legacyProjFormatXmlns) lines)
620-
.IsSome
639+
|> Option.isSome
621640
else
622641
false
623642

@@ -639,22 +658,20 @@ module ProjectLoader =
639658
let loggers = createLoggers [ path ] binaryLogs sw
640659

641660
let pi = project.CreateProjectInstance()
661+
let designTimeTargets = designTimeBuildTargets isLegacyFrameworkProjFile
642662

643663
let doDesignTimeBuild () =
644-
let build = pi.Build(designTimeBuildTargets isLegacyFrameworkProjFile, loggers)
664+
let build = pi.Build(designTimeTargets, loggers)
645665

646666
if build then
647667
Ok(StandardProject pi)
648668
else
649669
Error(sw.ToString())
650670

651-
let yieldTraversalProject () = Ok(TraversalProject pi)
652-
653-
// do traversal project detection here
654-
match pi.GetProperty "IsTraversal" with
655-
| null -> doDesignTimeBuild ()
656-
| p when Boolean.Parse(p.EvaluatedValue) = false -> doDesignTimeBuild ()
657-
| _ -> yieldTraversalProject ()
671+
match pi with
672+
| IsTraversal -> Ok(TraversalProject pi)
673+
| DesignTimeCapable designTimeTargets -> doDesignTimeBuild ()
674+
| _ -> Ok(Other pi)
658675

659676
with exc ->
660677
projectLoaderLogger.Value.error (
@@ -723,6 +740,7 @@ module ProjectLoader =
723740
}
724741
)
725742
|> Seq.toList
743+
| Other(_) -> List.empty
726744

727745
let getCompileItems (p: ProjectInstance) =
728746
p.Items
@@ -945,6 +963,7 @@ module ProjectLoader =
945963
type LoadedProjectInfo =
946964
| StandardProjectInfo of ProjectOptions
947965
| TraversalProjectInfo of ProjectReference list
966+
| OtherProjectInfo of ProjectInstance
948967

949968
let getLoadedProjectInfo (path: string) customProperties project : Result<LoadedProjectInfo, string> =
950969
// let (LoadedProject p) = project
@@ -1001,6 +1020,7 @@ module ProjectLoader =
10011020
else
10021021
let proj = mapToProject path commandLineArgs p2pRefs compileItems nuGetRefs sdkInfo props customProps
10031022
Ok(LoadedProjectInfo.StandardProjectInfo proj)
1023+
| LoadedProject.Other p -> Ok(LoadedProjectInfo.OtherProjectInfo p)
10041024

10051025
/// A type that turns project files or solution files into deconstructed options.
10061026
/// Use this in conjunction with the other ProjInfo libraries to turn these options into
@@ -1105,42 +1125,32 @@ type WorkspaceLoaderViaProjectGraph private (toolsPath, ?globalProperties: (stri
11051125
paths
11061126
|> Seq.iter (fun p -> loadingNotification.Trigger(WorkspaceProjectState.Loading p))
11071127

1128+
let designTimeTargets = ProjectLoader.designTimeBuildTargets false
1129+
11081130
let graph =
1109-
match
1131+
let entryPoints =
11101132
paths
1133+
|> Seq.map ProjectGraphEntryPoint
11111134
|> List.ofSeq
1112-
with
1113-
| [ x ] ->
1114-
let g: ProjectGraph =
1115-
ProjectGraph(x, projectCollection = per_request_collection, projectInstanceFactory = projectInstanceFactory)
1116-
// When giving ProjectGraph a singular project, g.EntryPointNodes only contains that project.
1117-
// To get it to build the Graph with all the dependencies we need to look at all the ProjectNodes
1118-
// and tell the graph to use all as potentially an entrypoint
1119-
let nodes =
1120-
g.ProjectNodes
1121-
|> Seq.choose (fun pn ->
1122-
match pn.ProjectInstance.GetProperty("IsTraversal") with
1123-
| null ->
1124-
ProjectGraphEntryPoint pn.ProjectInstance.FullPath
1125-
|> Some
1126-
| p ->
1127-
match bool.TryParse(p.EvaluatedValue) with
1128-
| true, true -> None
1129-
| true, false ->
1130-
ProjectGraphEntryPoint pn.ProjectInstance.FullPath
1131-
|> Some
1132-
| false, _ -> None
1133-
)
1134-
1135-
ProjectGraph(nodes, projectCollection = per_request_collection, projectInstanceFactory = projectInstanceFactory)
1136-
1137-
| xs ->
1138-
let entryPoints =
1139-
paths
1140-
|> Seq.map ProjectGraphEntryPoint
1141-
|> List.ofSeq
11421135

1136+
let g: ProjectGraph =
11431137
ProjectGraph(entryPoints, projectCollection = per_request_collection, projectInstanceFactory = projectInstanceFactory)
1138+
// When giving ProjectGraph a singular project, g.EntryPointNodes only contains that project.
1139+
// To get it to build the Graph with all the dependencies we need to look at all the ProjectNodes
1140+
// and tell the graph to use all as potentially an entrypoint
1141+
// Additionally, we need to filter out any projects that are not design time capable
1142+
let nodes =
1143+
g.ProjectNodes
1144+
|> Seq.choose (fun pn ->
1145+
match pn.ProjectInstance with
1146+
| ProjectLoader.DesignTimeCapable designTimeTargets ->
1147+
1148+
ProjectGraphEntryPoint pn.ProjectInstance.FullPath
1149+
|> Some
1150+
| _ -> None
1151+
)
1152+
1153+
ProjectGraph(nodes, projectCollection = per_request_collection, projectInstanceFactory = projectInstanceFactory)
11441154

11451155
graph
11461156

@@ -1205,9 +1215,11 @@ type WorkspaceLoaderViaProjectGraph private (toolsPath, ?globalProperties: (stri
12051215
let gbr =
12061216
GraphBuildRequestData(
12071217
projectGraph = projects,
1208-
targetsToBuild=ProjectLoader.designTimeBuildTargets false,
1209-
hostServices=null,
1210-
flags= (BuildRequestDataFlags.ReplaceExistingProjectInstance ||| BuildRequestDataFlags.ClearCachesAfterBuild)
1218+
targetsToBuild = ProjectLoader.designTimeBuildTargets false,
1219+
hostServices = null,
1220+
flags =
1221+
(BuildRequestDataFlags.ReplaceExistingProjectInstance
1222+
||| BuildRequestDataFlags.ClearCachesAfterBuild)
12111223
)
12121224

12131225
let bm = BuildManager.DefaultBuildManager
@@ -1260,7 +1272,6 @@ type WorkspaceLoaderViaProjectGraph private (toolsPath, ?globalProperties: (stri
12601272
let projects =
12611273
builtProjects
12621274
|> Seq.map (fun p -> p.FullPath, ProjectLoader.getLoadedProjectInfo p.FullPath customProperties (ProjectLoader.StandardProject p))
1263-
12641275
|> Seq.choose (fun (projectPath, projectOptionResult) ->
12651276
match projectOptionResult with
12661277
| Ok projectOptions ->
@@ -1303,6 +1314,12 @@ type WorkspaceLoaderViaProjectGraph private (toolsPath, ?globalProperties: (stri
13031314
)
13041315

13051316
loadingNotification.Trigger(WorkspaceProjectState.Loaded(po, allStandardProjects, false))
1317+
| ProjectLoader.LoadedProjectInfo.OtherProjectInfo p ->
1318+
logger.info (
1319+
Log.setMessage "Other project loaded {project}"
1320+
>> Log.addContextDestructured "project" p.FullPath
1321+
)
1322+
13061323
)
13071324

13081325
allStandardProjects :> seq<_>
@@ -1417,6 +1434,7 @@ type WorkspaceLoader private (toolsPath: ToolsPath, ?globalProperties: (string *
14171434
match project with
14181435
| ProjectLoader.LoadedProjectInfo.StandardProjectInfo p -> p.ReferencedProjects
14191436
| ProjectLoader.LoadedProjectInfo.TraversalProjectInfo p -> p
1437+
| ProjectLoader.LoadedProjectInfo.OtherProjectInfo p -> []
14201438

14211439
let lst =
14221440
referencedProjects
@@ -1432,6 +1450,7 @@ type WorkspaceLoader private (toolsPath: ToolsPath, ?globalProperties: (string *
14321450
match project with
14331451
| ProjectLoader.LoadedProjectInfo.StandardProjectInfo p -> Some p
14341452
| ProjectLoader.LoadedProjectInfo.TraversalProjectInfo p -> None
1453+
| ProjectLoader.LoadedProjectInfo.OtherProjectInfo p -> None
14351454

14361455
lst, info
14371456
| Error msg ->
@@ -1446,13 +1465,14 @@ type WorkspaceLoader private (toolsPath: ToolsPath, ?globalProperties: (string *
14461465

14471466
match project with
14481467
| ProjectLoader.LoadedProjectInfo.StandardProjectInfo p -> loadingNotification.Trigger(WorkspaceProjectState.Loaded(p, getAllKnown (), true))
1449-
14501468
| ProjectLoader.LoadedProjectInfo.TraversalProjectInfo p -> ()
1469+
| ProjectLoader.LoadedProjectInfo.OtherProjectInfo p -> ()
14511470

14521471
let referencedProjects =
14531472
match project with
14541473
| ProjectLoader.LoadedProjectInfo.StandardProjectInfo p -> p.ReferencedProjects
14551474
| ProjectLoader.LoadedProjectInfo.TraversalProjectInfo p -> p
1475+
| ProjectLoader.LoadedProjectInfo.OtherProjectInfo p -> []
14561476

14571477
let lst =
14581478
referencedProjects

test/Ionide.ProjInfo.Tests/TestAssets.fs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,11 @@ let ``traversal project`` = {
321321
yield! ``sample3 Netsdk projs``.ProjectReferences
322322
]
323323
}
324+
325+
let ``sample 11 sln with other project types`` = {
326+
ProjDir = "sample11-solution-with-other-projects"
327+
AssemblyName = ""
328+
ProjectFile = "sample11-solution-with-other-projects.sln"
329+
TargetFrameworks = Map.empty
330+
ProjectReferences = []
331+
}

test/Ionide.ProjInfo.Tests/Tests.fs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ let implAssemblyForProject (test: TestAssetProjInfo) = $"{test.AssemblyName}.dll
4343
let refAssemblyForProject (test: TestAssetProjInfo) =
4444
Path.Combine("ref", implAssemblyForProject test)
4545

46+
let getResult (r: Result<_, _>) =
47+
match r with
48+
| Ok x -> x
49+
| Result.Error e -> failwithf "%A" e
50+
4651
let TestRunDir =
4752
RepoDir
4853
/ "test"
@@ -1999,6 +2004,7 @@ let debugTests toolsPath workspaceLoader (workspaceFactory: ToolsPath -> IWorksp
19992004
(fun logger fs ->
20002005

20012006
let loader = workspaceFactory toolsPath
2007+
20022008
let slnPath =
20032009
@"C:\Users\JimmyByrd\Documents\Repositories\public\TheAngryByrd\FsToolkit.ErrorHandling\FsToolkit.ErrorHandling.sln"
20042010

@@ -2245,6 +2251,28 @@ let traversalProjectTest toolsPath loaderType workspaceFactory =
22452251

22462252
)
22472253

2254+
let sample11OtherProjectsTest toolsPath loaderType workspaceFactory =
2255+
testCase
2256+
$"Can load sample11 with other projects like shproj in sln - {loaderType}"
2257+
(fun () ->
2258+
2259+
let projPath = pathForProject ``sample 11 sln with other project types``
2260+
2261+
let projPaths =
2262+
// using Inspectsln emulates what we do in FsAutocomplete for gathering projects to load
2263+
InspectSln.tryParseSln projPath
2264+
|> getResult
2265+
|> InspectSln.loadingBuildOrder
2266+
2267+
let loader: IWorkspaceLoader = workspaceFactory toolsPath
2268+
2269+
let parsed =
2270+
loader.LoadProjects projPaths
2271+
|> Seq.toList
2272+
2273+
Expect.hasLength parsed 1 "Should have fsproj"
2274+
)
2275+
22482276
let tests toolsPath =
22492277
let testSample3WorkspaceLoaderExpected = [
22502278
ExpectNotification.loading "c1.fsproj"
@@ -2371,4 +2399,7 @@ let tests toolsPath =
23712399

23722400
traversalProjectTest toolsPath (nameof (WorkspaceLoader)) WorkspaceLoader.Create
23732401
traversalProjectTest toolsPath (nameof (WorkspaceLoaderViaProjectGraph)) WorkspaceLoaderViaProjectGraph.Create
2402+
2403+
sample11OtherProjectsTest toolsPath (nameof (WorkspaceLoader)) WorkspaceLoader.Create
2404+
sample11OtherProjectsTest toolsPath (nameof (WorkspaceLoaderViaProjectGraph)) WorkspaceLoaderViaProjectGraph.Create
23742405
]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace classlibf1
2+
3+
module Say =
4+
let hello name =
5+
printfn "Hello %s" name
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<Compile Include="Library.fs" />
10+
</ItemGroup>
11+
12+
</Project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "classlibf1", "classlibf1\classlibf1.fsproj", "{DEB2A50A-745D-4BB4-9DB5-D688F1FE8D7E}"
7+
EndProject
8+
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "shared", "shared.shproj", "{AA1DD2E8-1CDE-4D1A-896C-8212C6D061A7}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(SolutionProperties) = preSolution
16+
HideSolutionNode = FALSE
17+
EndGlobalSection
18+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
19+
{DEB2A50A-745D-4BB4-9DB5-D688F1FE8D7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20+
{DEB2A50A-745D-4BB4-9DB5-D688F1FE8D7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
21+
{DEB2A50A-745D-4BB4-9DB5-D688F1FE8D7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
22+
{DEB2A50A-745D-4BB4-9DB5-D688F1FE8D7E}.Release|Any CPU.Build.0 = Release|Any CPU
23+
EndGlobalSection
24+
EndGlobal
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
open System
2+
let lol = ()
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
5+
<HasSharedItems>true</HasSharedItems>
6+
<SharedGUID>aa1dd2e8-1cde-4d1a-896c-8212c6d061a7</SharedGUID>
7+
</PropertyGroup>
8+
<PropertyGroup Label="Configuration">
9+
<Import_RootNamespace>Scripts</Import_RootNamespace>
10+
</PropertyGroup>
11+
<ItemGroup>
12+
<None Include="$(MSBuildThisFileDirectory)\scripts\*.fsx" />
13+
</ItemGroup>
14+
</Project>

0 commit comments

Comments
 (0)