Skip to content

Commit

Permalink
Allow global properties to be provided to project loaders (#107)
Browse files Browse the repository at this point in the history
Co-authored-by: Don Syme <[email protected]>
Co-authored-by: Chet Husk <[email protected]>
  • Loading branch information
3 people authored Apr 16, 2021
1 parent 0db8ac2 commit d9b0b7b
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 29 deletions.
19 changes: 15 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.52.0] - 2021-04-13

### Changed

- [Allow global properties to be provided to project loaders](https://github.com/ionide/proj-info/pull/107)

## [0.51.0] - 2021-03-15

* Change the order of calls so that FSAC doesn't have a deadlock with its current usage of this library
### Changed

- Change the order of calls so that FSAC doesn't have a deadlock with its current usage of this library

## [0.50.0] - 2021-03-13

* Introduce a pluggable abstraction for creating workspaces to allow for independent experimentation
* Introduce a workspace implementation for MsBuild Graph Build mode, which should be a large performance boost for consumers
* introduce debouncing to prevent rebuilds when invoked multiple times in a short timeframe
### Changed

- Introduce a pluggable abstraction for creating workspaces to allow for independent experimentation
- Introduce a workspace implementation for MsBuild Graph Build mode, which should be a large performance boost for consumers
- introduce debouncing to prevent rebuilds when invoked multiple times in a short timeframe

## [0.49.0] - 2021-03-03

Expand Down
40 changes: 23 additions & 17 deletions src/Ionide.ProjInfo/Library.fs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ module ProjectLoader =
else
[ logger ]

let getGlobalProps (path: string) (tfm: string option) =
let getGlobalProps (path: string) (tfm: string option) (globalProperties: (string * string) list)=
dict [ "ProvideCommandLineArgs", "true"
"DesignTimeBuild", "true"
"SkipCompilerExecution", "true"
Expand All @@ -91,19 +91,20 @@ module ProjectLoader =
"TargetFramework", tfm.Value
if path.EndsWith ".csproj" then
"NonExistentFile", Path.Combine("__NonExistentSubDir__", "__NonExistentFile__")
"DotnetProjInfo", "true" ]
"DotnetProjInfo", "true"
yield! globalProperties ]


let buildArgs =
[| "ResolvePackageDependenciesDesignTime"
"_GenerateCompileDependencyCache"
"CoreCompile" |]

let loadProject (path: string) (generateBinlog: bool) (ToolsPath toolsPath) =
let loadProject (path: string) (generateBinlog: bool) (ToolsPath toolsPath) globalProperties =
try
let tfm = getTfm path

let globalProperties = getGlobalProps path tfm
let globalProperties = getGlobalProps path tfm globalProperties

match System.Environment.GetEnvironmentVariable "DOTNET_HOST_PATH" with
| null
Expand All @@ -112,7 +113,7 @@ module ProjectLoader =

use pc = new ProjectCollection(globalProperties)

let pi = pc.LoadProject(path)
let pi = pc.LoadProject(path, globalProperties, toolsVersion=null)

use sw = new StringWriter()

Expand Down Expand Up @@ -343,10 +344,11 @@ module ProjectLoader =
/// <param name="path">Full path to the `.fsproj` file</param>
/// <param name="toolsPath">Path to MsBuild obtained from `ProjectLoader.init ()`</param>
/// <param name="generateBinlog">Enable Binary Log generation</param>
/// <param name="globalProperties">The global properties to use (e.g. Configuration=Release). Some additional global properties are pre-set by the tool</param>
/// <param name="customProperties">List of additional MsBuild properties that you want to obtain.</param>
/// <returns>Returns the record instance representing the loaded project or string containing error message</returns>
let getProjectInfo (path: string) (toolsPath: ToolsPath) (generateBinlog: bool) (customProperties: string list) : Result<Types.ProjectOptions, string> =
let loadedProject = loadProject path generateBinlog toolsPath
let getProjectInfo (path: string) (toolsPath: ToolsPath) (globalProperties: (string*string) list) (generateBinlog: bool) (customProperties: string list) : Result<Types.ProjectOptions, string> =
let loadedProject = loadProject path generateBinlog toolsPath globalProperties

match loadedProject with
| Success project -> getLoadedProjectInfo path customProperties project
Expand All @@ -369,7 +371,8 @@ type IWorkspaceLoader =
[<CLIEvent>]
abstract Notifications : IEvent<WorkspaceProjectState>

type WorkspaceLoaderViaProjectGraph private (toolsPath: ToolsPath) =
type WorkspaceLoaderViaProjectGraph private (toolsPath: ToolsPath, ?globalProperties: (string*string) list) =
let globalProperties = defaultArg globalProperties []
let logger = LogProvider.getLoggerFor<WorkspaceLoaderViaProjectGraph> ()
let loadingNotification = new Event<Types.WorkspaceProjectState>()

Expand All @@ -383,17 +386,19 @@ type WorkspaceLoaderViaProjectGraph private (toolsPath: ToolsPath) =
loadingNotification.Trigger(WorkspaceProjectState.Failed(p, ProjectNotFound(p)))
None

let projectInstanceFactory projectPath globalProperties (projectCollection: ProjectCollection) =
let projectInstanceFactory projectPath (_globalProperties: IDictionary<string,string>) (projectCollection: ProjectCollection) =
let tfm = ProjectLoader.getTfm projectPath
ProjectInstance(projectPath, ProjectLoader.getGlobalProps projectPath tfm, null, projectCollection)
//let globalProperties = globalProperties |> Seq.toList |> List.map (fun (KeyValue(k,v)) -> (k,v))
let globalProperties = ProjectLoader.getGlobalProps projectPath tfm globalProperties
ProjectInstance(projectPath, globalProperties, toolsVersion=null, projectCollection=projectCollection)

let projectGraphProjs (paths: string seq) =

handleProjectGraphFailures
<| fun () ->
paths |> Seq.iter (fun p -> loadingNotification.Trigger(WorkspaceProjectState.Loading p))
let entryPoints = paths |> Seq.map ProjectGraphEntryPoint
ProjectGraph(entryPoints, ProjectCollection.GlobalProjectCollection, projectInstanceFactory)
ProjectGraph(entryPoints, projectCollection=ProjectCollection.GlobalProjectCollection, projectInstanceFactory=projectInstanceFactory)

let projectGraphSln (path: string) =
handleProjectGraphFailures
Expand Down Expand Up @@ -541,10 +546,11 @@ type WorkspaceLoaderViaProjectGraph private (toolsPath: ToolsPath) =
this.LoadSln(sln, customProperties, false)


static member Create(toolsPath: ToolsPath) =
WorkspaceLoaderViaProjectGraph(toolsPath) :> IWorkspaceLoader
static member Create(toolsPath: ToolsPath, ?globalProperties) =
WorkspaceLoaderViaProjectGraph(toolsPath, ?globalProperties=globalProperties) :> IWorkspaceLoader

type WorkspaceLoader private (toolsPath: ToolsPath) =
type WorkspaceLoader private (toolsPath: ToolsPath, ?globalProperties: (string * string) list) =
let globalProperties = defaultArg globalProperties []
let loadingNotification = new Event<Types.WorkspaceProjectState>()


Expand All @@ -561,7 +567,7 @@ type WorkspaceLoader private (toolsPath: ToolsPath) =
cache |> Seq.map (fun n -> n.Value) |> Seq.toList

let rec loadProject p =
let res = ProjectLoader.getProjectInfo p toolsPath generateBinlog customProperties
let res = ProjectLoader.getProjectInfo p toolsPath globalProperties generateBinlog customProperties

match res with
| Ok project ->
Expand Down Expand Up @@ -644,8 +650,8 @@ type WorkspaceLoader private (toolsPath: ToolsPath) =



static member Create(toolsPath: ToolsPath) =
WorkspaceLoader(toolsPath) :> IWorkspaceLoader
static member Create(toolsPath: ToolsPath, ?globalProperties) =
WorkspaceLoader(toolsPath, ?globalProperties=globalProperties) :> IWorkspaceLoader

type ProjectViewerTree =
{ Name: string
Expand Down
22 changes: 15 additions & 7 deletions test/Ionide.ProjInfo.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ open Ionide.ProjInfo
open Expecto.Logging.Message
open FSharp.Compiler.SourceCodeServices

#nowarn "25"

let RepoDir = (__SOURCE_DIRECTORY__ / ".." / "..") |> Path.GetFullPath
let ExamplesDir = RepoDir / "test" / "examples"
let TestRunDir = RepoDir / "test" / "testrun_ws"
Expand Down Expand Up @@ -140,10 +142,10 @@ module ExpectNotification =
let watchNotifications logger loader =
NotificationWatcher(loader, logNotification logger)

let testSample2 toolsPath workspaceLoader (workspaceFactory: ToolsPath -> IWorkspaceLoader) =
let testSample2 toolsPath workspaceLoader isRelease (workspaceFactory: ToolsPath * (string * string) list -> IWorkspaceLoader) =
testCase
|> withLog
(sprintf "can load sample2 - %s" workspaceLoader)
(sprintf "can load sample2 - %s - isRelease is %b" workspaceLoader isRelease)
(fun logger fs ->
let testDir = inDir fs "load_sample2"
copyDirFromAssets fs ``sample2 NetSdk library``.ProjDir testDir
Expand All @@ -153,7 +155,9 @@ let testSample2 toolsPath workspaceLoader (workspaceFactory: ToolsPath -> IWorks

dotnet fs [ "restore"; projPath ] |> checkExitCodeZero

let loader = workspaceFactory toolsPath
let config = if isRelease then "Release" else "Debug"
let props = [("Configuration", config)]
let loader = workspaceFactory (toolsPath, props)

let watcher = watchNotifications logger loader

Expand All @@ -168,8 +172,10 @@ let testSample2 toolsPath workspaceLoader (workspaceFactory: ToolsPath -> IWorks
let n1Parsed = parsed |> expectFind projPath "first is a lib"

let expectedSources =
[ projDir / "obj/Debug/netstandard2.0/n1.AssemblyInfo.fs"
projDir / "Library.fs" ]
[ projDir / ("obj/" + config + "/netstandard2.0/n1.AssemblyInfo.fs")
projDir / "Library.fs"
if isRelease then
projDir / "Other.fs" ]
|> List.map Path.GetFullPath

Expect.equal parsed.Length 1 "console and lib"
Expand Down Expand Up @@ -981,8 +987,10 @@ let tests toolsPath =
testSequenced
<| testList
"Main tests"
[ testSample2 toolsPath "WorkspaceLoader" WorkspaceLoader.Create
testSample2 toolsPath "WorkspaceLoaderViaProjectGraph" WorkspaceLoaderViaProjectGraph.Create
[ testSample2 toolsPath "WorkspaceLoader" false (fun (tools,props) -> WorkspaceLoader.Create(tools, globalProperties=props))
testSample2 toolsPath "WorkspaceLoader" true (fun (tools,props) -> WorkspaceLoader.Create(tools, globalProperties=props))
testSample2 toolsPath "WorkspaceLoaderViaProjectGraph" false (fun (tools,props) -> WorkspaceLoaderViaProjectGraph.Create(tools, globalProperties=props))
testSample2 toolsPath "WorkspaceLoaderViaProjectGraph" true (fun (tools,props) -> WorkspaceLoaderViaProjectGraph.Create(tools, globalProperties=props))
testSample3 toolsPath "WorkspaceLoader" WorkspaceLoader.Create testSample3WorkspaceLoaderExpected //- Sample 3 having issues, was also marked pending on old test suite
// testSample3 toolsPath "WorkspaceLoaderViaProjectGraph" WorkspaceLoaderViaProjectGraph.Create testSample3GraphExpected //- Sample 3 having issues, was also marked pending on old test suite
testSample4 toolsPath "WorkspaceLoader" WorkspaceLoader.Create
Expand Down
3 changes: 2 additions & 1 deletion test/examples/sample2-netsdk-lib/n1/n1.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="Library.fs" />
<Compile Include="Library.fs" />
<Compile Include="Other.fs" Condition="'$(Configuration)' == 'Release'"/>
</ItemGroup>

</Project>

0 comments on commit d9b0b7b

Please sign in to comment.