@@ -111,8 +111,6 @@ Override targets which don't work with project files that are not present on dis
111
111
</Target>
112
112
""" ;
113
113
114
- private ImmutableArray < CSharpDirective > _directives ;
115
-
116
114
public VirtualProjectBuildingCommand (
117
115
string entryPointFileFullPath ,
118
116
MSBuildArgs msbuildArgs )
@@ -136,6 +134,23 @@ public VirtualProjectBuildingCommand(
136
134
/// </summary>
137
135
public bool NoBuildMarkers { get ; init ; }
138
136
137
+ public ImmutableArray < CSharpDirective > Directives
138
+ {
139
+ get
140
+ {
141
+ if ( field . IsDefault )
142
+ {
143
+ var sourceFile = LoadSourceFile ( EntryPointFileFullPath ) ;
144
+ field = FindDirectives ( sourceFile , reportAllErrors : false , errors : null ) ;
145
+ Debug . Assert ( ! field . IsDefault ) ;
146
+ }
147
+
148
+ return field ;
149
+ }
150
+
151
+ init ;
152
+ }
153
+
139
154
public override int Execute ( )
140
155
{
141
156
Debug . Assert ( ! ( NoRestore && NoBuild ) ) ;
@@ -157,8 +172,6 @@ public override int Execute()
157
172
Reporter . Output . WriteLine ( CliCommandStrings . NoBinaryLogBecauseUpToDate . Yellow ( ) ) ;
158
173
}
159
174
160
- PrepareProjectInstance ( ) ;
161
-
162
175
return 0 ;
163
176
}
164
177
@@ -188,8 +201,6 @@ public override int Execute()
188
201
LogTaskInputs = binaryLoggers . Length != 0 ,
189
202
} ;
190
203
191
- PrepareProjectInstance ( ) ;
192
-
193
204
// Do a restore first (equivalent to MSBuild's "implicit restore", i.e., `/restore`).
194
205
// See https://github.com/dotnet/msbuild/blob/a1c2e7402ef0abe36bf493e395b04dd2cb1b3540/src/MSBuild/XMake.cs#L1838
195
206
// and https://github.com/dotnet/msbuild/issues/11519.
@@ -445,17 +456,7 @@ private void MarkBuildStart()
445
456
446
457
string directory = GetArtifactsPath ( ) ;
447
458
448
- if ( OperatingSystem . IsWindows ( ) )
449
- {
450
- Directory . CreateDirectory ( directory ) ;
451
- }
452
- else
453
- {
454
- // Ensure only the current user has access to the directory to avoid leaking the program to other users.
455
- // We don't mind that permissions might be different if the directory already exists,
456
- // since it's under user's local directory and its path should be unique.
457
- Directory . CreateDirectory ( directory , UnixFileMode . UserRead | UnixFileMode . UserWrite | UnixFileMode . UserExecute ) ;
458
- }
459
+ CreateTempSubdirectory ( directory ) ;
459
460
460
461
File . WriteAllText ( Path . Join ( directory , BuildStartCacheFileName ) , EntryPointFileFullPath ) ;
461
462
}
@@ -472,19 +473,6 @@ private void MarkBuildSuccess(RunFileBuildCacheEntry cacheEntry)
472
473
JsonSerializer . Serialize ( stream , cacheEntry , RunFileJsonSerializerContext . Default . RunFileBuildCacheEntry ) ;
473
474
}
474
475
475
- /// <summary>
476
- /// Needs to be called before the first call to <see cref="CreateProjectInstance(ProjectCollection)"/>.
477
- /// </summary>
478
- public VirtualProjectBuildingCommand PrepareProjectInstance ( )
479
- {
480
- Debug . Assert ( _directives . IsDefault , $ "{ nameof ( PrepareProjectInstance ) } should not be called multiple times.") ;
481
-
482
- var sourceFile = LoadSourceFile ( EntryPointFileFullPath ) ;
483
- _directives = FindDirectives ( sourceFile , reportAllErrors : false , errors : null ) ;
484
-
485
- return this ;
486
- }
487
-
488
476
public ProjectInstance CreateProjectInstance ( ProjectCollection projectCollection )
489
477
{
490
478
return CreateProjectInstance ( projectCollection , addGlobalProperties : null ) ;
@@ -511,13 +499,11 @@ private ProjectInstance CreateProjectInstance(
511
499
512
500
ProjectRootElement CreateProjectRootElement ( ProjectCollection projectCollection )
513
501
{
514
- Debug . Assert ( ! _directives . IsDefault , $ "{ nameof ( PrepareProjectInstance ) } should have been called first.") ;
515
-
516
502
var projectFileFullPath = Path . ChangeExtension ( EntryPointFileFullPath , ".csproj" ) ;
517
503
var projectFileWriter = new StringWriter ( ) ;
518
504
WriteProjectFile (
519
505
projectFileWriter ,
520
- _directives ,
506
+ Directives ,
521
507
isVirtualProject : true ,
522
508
targetFilePath : EntryPointFileFullPath ,
523
509
artifactsPath : GetArtifactsPath ( ) ,
@@ -534,20 +520,46 @@ ProjectRootElement CreateProjectRootElement(ProjectCollection projectCollection)
534
520
535
521
private string GetArtifactsPath ( ) => CustomArtifactsPath ?? GetArtifactsPath ( EntryPointFileFullPath ) ;
536
522
537
- // internal for testing
538
- internal static string GetArtifactsPath ( string entryPointFileFullPath )
523
+ public static string GetArtifactsPath ( string entryPointFileFullPath )
524
+ {
525
+ // Include entry point file name so the directory name is not completely opaque.
526
+ string fileName = Path . GetFileNameWithoutExtension ( entryPointFileFullPath ) ;
527
+ string hash = Sha256Hasher . HashWithNormalizedCasing ( entryPointFileFullPath ) ;
528
+ string directoryName = $ "{ fileName } -{ hash } ";
529
+
530
+ return GetTempSubdirectory ( directoryName ) ;
531
+ }
532
+
533
+ /// <summary>
534
+ /// Obtains a temporary subdirectory for file-based apps.
535
+ /// </summary>
536
+ public static string GetTempSubdirectory ( string name )
539
537
{
540
538
// We want a location where permissions are expected to be restricted to the current user.
541
539
string directory = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows )
542
540
? Path . GetTempPath ( )
543
541
: Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) ;
544
542
545
- // Include entry point file name so the directory name is not completely opaque.
546
- string fileName = Path . GetFileNameWithoutExtension ( entryPointFileFullPath ) ;
547
- string hash = Sha256Hasher . HashWithNormalizedCasing ( entryPointFileFullPath ) ;
548
- string directoryName = $ "{ fileName } -{ hash } ";
543
+ return Path . Join ( directory , "dotnet" , "runfile" , name ) ;
544
+ }
549
545
550
- return Path . Join ( directory , "dotnet" , "runfile" , directoryName ) ;
546
+ /// <summary>
547
+ /// Creates a temporary subdirectory for file-based apps.
548
+ /// Use <see cref="GetTempSubdirectory"/> to obtain the path.
549
+ /// </summary>
550
+ public static void CreateTempSubdirectory ( string path )
551
+ {
552
+ if ( OperatingSystem . IsWindows ( ) )
553
+ {
554
+ Directory . CreateDirectory ( path ) ;
555
+ }
556
+ else
557
+ {
558
+ // Ensure only the current user has access to the directory to avoid leaking the program to other users.
559
+ // We don't mind that permissions might be different if the directory already exists,
560
+ // since it's under user's local directory and its path should be unique.
561
+ Directory . CreateDirectory ( path , UnixFileMode . UserRead | UnixFileMode . UserWrite | UnixFileMode . UserExecute ) ;
562
+ }
551
563
}
552
564
553
565
public static void WriteProjectFile (
@@ -648,7 +660,7 @@ public static void WriteProjectFile(
648
660
writer . WriteLine ( """
649
661
650
662
<PropertyGroup>
651
- <EnableDefaultItems >false</EnableDefaultItems >
663
+ <EnableDefaultCompileItems >false</EnableDefaultCompileItems >
652
664
</PropertyGroup>
653
665
""" ) ;
654
666
}
0 commit comments