Skip to content

Commit 53b795d

Browse files
authored
"Virtual" (in-memory) project file (#4)
1 parent c35b577 commit 53b795d

File tree

7 files changed

+56
-39
lines changed

7 files changed

+56
-39
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# CHANGELOG
22

3+
## 1.0.5
4+
5+
### changed
6+
7+
* "Virtual" (in-memory) project file
8+
39
## 1.0.4
410

511
### changed

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,11 @@ Main learnings
5858
- A small compiler change is needed to allow for the directive format.
5959
- The most important missing piece is editor support.
6060

61-
Open items
62-
- I did not succeed yet in replicating the "virtual project file" approach. If I use the msbuild API's `BuildManager`, it doesn't find the sdk, probably because I am missing the right global build properties that `dotnet run` has available internally. I am not sure if there is a workaround. For now, I settled for a less nice file-based approach. Less nice because the script location must be writable.
63-
- Not sure yet if the "compile only" shortcut can easily be replicated for F#.
64-
6561
## TODOs
6662

6763
Runfs
68-
- investigate the open items: virtual project file, optimize the build step (cache core compile input beyond restore)
69-
- add more tests, automate publishing, possibly Rid-package, fix case sensitivity issue in Directives.fs
64+
- investigate if the "compile only" shortcut can be replicated for F#
65+
- add more tests, possibly Rid-package, fix case sensitivity issue in Directives.fs
7066
- implement the #project, #source and #dll directives and `--convert`
7167

7268
Elsewhere

src/Runfs/Build.fs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ let createProject verbose projectFilePath (projectFileText: string) : Project =
2727
let loggerArgs = [|$"-verbosity:{verbosity}"; "-tl:off"; "NoSummary"|]
2828
let consoleLogger = TerminalLogger.CreateTerminalOrConsoleLogger loggerArgs
2929
let loggers = [|consoleLogger|]
30-
let globalProperties =
31-
dict [
32-
]
30+
let globalProperties = dict []
3331
let projectCollection = new ProjectCollection(
3432
globalProperties,
3533
loggers,
@@ -38,24 +36,17 @@ let createProject verbose projectFilePath (projectFileText: string) : Project =
3836
options.ProjectCollection <- projectCollection
3937
options.GlobalProperties <- globalProperties
4038

41-
// let reader = new StringReader(projectFileText)
42-
// let xmlReader = XmlReader.Create reader
43-
// let projectRoot = ProjectRootElement.Create(xmlReader, projectCollection)
44-
// projectRoot.FullPath <- projectFilePath
45-
// let projectInstance = ProjectInstance.FromProjectRootElement(projectRoot, options)
46-
47-
File.WriteAllText(projectFilePath, projectFileText)
48-
try
49-
let projectInstance = ProjectInstance.FromFile(projectFilePath, options)
50-
let parameters = BuildParameters projectCollection
51-
parameters.Loggers <- loggers
52-
parameters.LogTaskInputs <- false
53-
let buildManager = BuildManager.DefaultBuildManager
54-
buildManager.BeginBuild parameters
55-
{buildManager = buildManager; projectInstance = projectInstance}
56-
with ex ->
57-
File.Delete projectFilePath
58-
reraise()
39+
let reader = new StringReader(projectFileText)
40+
let xmlReader = XmlReader.Create reader
41+
let projectRoot = ProjectRootElement.Create(xmlReader, projectCollection)
42+
projectRoot.FullPath <- projectFilePath
43+
let projectInstance = ProjectInstance.FromProjectRootElement(projectRoot, options)
44+
let parameters = BuildParameters projectCollection
45+
parameters.Loggers <- loggers
46+
parameters.LogTaskInputs <- false
47+
let buildManager = BuildManager.DefaultBuildManager
48+
buildManager.BeginBuild parameters
49+
{buildManager = buildManager; projectInstance = projectInstance}
5950

6051
let build target project =
6152
let flags =

src/Runfs/ProjectFile.fs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,31 @@ let createProjectFileLines directives entryPointSourceFullPath artifactsPath ass
5959
$""" <Compile Include="{escape entryPointSourceFullPath}" />"""
6060
" </ItemGroup>"
6161
yield! sdks |> List.map (sdkLine "Sdk.targets")
62+
63+
$""" <!-- Override targets which don't work with project files that are not present on disk. --> """
64+
$""" <!-- Hopefully we can remove this once net10 has landed. --> """
65+
66+
$""" <Target Name="_FilterRestoreGraphProjectInputItems" """
67+
$""" DependsOnTargets="_LoadRestoreGraphEntryPoints" """
68+
$""" Returns="@(FilteredRestoreGraphProjectInputItems)"> """
69+
$""" <ItemGroup> """
70+
$""" <FilteredRestoreGraphProjectInputItems Include="@(RestoreGraphProjectInputItems)" /> """
71+
$""" </ItemGroup> """
72+
$""" </Target> """
73+
74+
$""" <Target Name="_GetAllRestoreProjectPathItems" """
75+
$""" DependsOnTargets="_FilterRestoreGraphProjectInputItems" """
76+
$""" Returns="@(_RestoreProjectPathItems)"> """
77+
$""" <ItemGroup> """
78+
$""" <_RestoreProjectPathItems Include="@(FilteredRestoreGraphProjectInputItems)" /> """
79+
$""" </ItemGroup> """
80+
$""" </Target> """
81+
82+
$""" <Target Name="_GenerateRestoreGraph" """
83+
$""" DependsOnTargets="_FilterRestoreGraphProjectInputItems;_GetAllRestoreProjectPathItems;_GenerateRestoreGraphProjectEntry;_GenerateProjectRestoreGraph" """
84+
$""" Returns="@(_RestoreGraphEntry)"> """
85+
$""" <!-- Output from dependency _GenerateRestoreGraphProjectEntry and _GenerateProjectRestoreGraph --> """
86+
$""" </Target> """
87+
6288
"</Project>"
6389
]

src/Runfs/Runfs.fs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ let run (options, sourcePath, args) =
107107
return computeDependenciesHash (string fullSourceDir) directives
108108
}
109109

110-
let! dependenciesChanged, sourceChanged, noExecutable = guardAndTime "computing build level" <| fun () ->
110+
let! needsRestore, needsBuild = guardAndTime "computing build level" <| fun () ->
111111
let dependenciesChanged =
112112
if noDependencyCheck then
113113
false
@@ -118,34 +118,34 @@ let run (options, sourcePath, args) =
118118
let readPreviousSourceHash() = File.ReadAllText sourceHashPath
119119
not (File.Exists sourceHashPath && readPreviousSourceHash() = sourceHash)
120120
let noDll = not (File.Exists dllPath)
121-
Ok (dependenciesChanged, sourceChanged, noDll)
121+
Ok (dependenciesChanged || noDll, sourceChanged)
122122

123-
if dependenciesChanged || noExecutable then
123+
if needsRestore then
124124
do! guardAndTime "creating and writing project file" <| fun () ->
125125
let projectFileLines = createProjectFileLines directives fullSourcePath artifactsDir AssemblyName
126126
File.WriteAllLines(savedProjectFilePath, projectFileLines) |> Ok
127127

128-
if dependenciesChanged || sourceChanged || noExecutable then
128+
if needsRestore || needsBuild then
129129
use! project = guardAndTime "creating msbuild project instance" <| fun () ->
130130
let projectFileText = File.ReadAllText savedProjectFilePath
131131
createProject verbose virtualProjectFilePath projectFileText |> Ok
132132

133-
if dependenciesChanged || noExecutable then
133+
if needsRestore then
134134
do! guardAndTime "running msbuild restore" <| fun () -> result {
135135
File.Delete dependenciesHashPath
136136
do! build "restore" project |> Result.mapError BuildError
137137
}
138-
138+
139139
do! guardAndTime "running dotnet build" <| fun () -> result {
140140
File.Delete sourceHash
141141
do! build "build" project |> Result.mapError BuildError
142142
}
143143

144-
if dependenciesChanged then
144+
if needsRestore then
145145
do! guardAndTime "saving dependencies hash" <| fun () ->
146146
File.WriteAllText(dependenciesHashPath, dependenciesHash) |> Ok
147147

148-
if sourceChanged then
148+
if needsBuild then
149149
do! guardAndTime "saving source hash" <| fun () ->
150150
File.WriteAllText(sourceHashPath, sourceHash) |> Ok
151151

src/Runfs/Runfs.fsproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<!-- General -->
44
<AssemblyName>Runfs</AssemblyName>
5-
<Version>1.0.4</Version>
5+
<Version>1.0.5</Version>
66
<Description>"dotnet run app.cs" functionality for F#.</Description>
77
<Copyright>Copyright 2025 by Martin521</Copyright>
88
<Authors>Martin521 and contributors</Authors>
@@ -19,7 +19,7 @@
1919
<PackageIcon>
2020
</PackageIcon>
2121
<PackageLicenseExpression>MIT</PackageLicenseExpression>
22-
<!-- <PackageReadmeFile>README.md</PackageReadmeFile> -->
22+
<PackageReadmeFile>README.md</PackageReadmeFile>
2323
</PropertyGroup>
2424
<ItemGroup>
2525
<None Include="../../README.md" Pack="true" PackagePath="" />

tests/Runfs.Tests/TestFiles/test1.fs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,3 @@ printfn $"args: {args}"
1313

1414
// let RuntimeVersion = Environment.Version
1515
// printfn $"Runtime version: {RuntimeVersion}"
16-
17-

0 commit comments

Comments
 (0)