22// The .NET Foundation licenses this file to you under the MIT license.
33
44using System . CommandLine ;
5+ using System . Diagnostics . CodeAnalysis ;
56using Microsoft . Build . Evaluation ;
67using Microsoft . DotNet . Cli . Commands . Run ;
78using Microsoft . DotNet . Cli . Utils ;
@@ -17,17 +18,14 @@ internal sealed class ProjectConvertCommand(ParseResult parseResult) : CommandBa
1718
1819 public override int Execute ( )
1920 {
21+ // Check the entry point file path.
2022 string file = Path . GetFullPath ( _file ) ;
2123 if ( ! VirtualProjectBuildingCommand . IsValidEntryPointPath ( file ) )
2224 {
2325 throw new GracefulException ( CliCommandStrings . InvalidFilePath , file ) ;
2426 }
2527
26- string targetDirectory = _outputDirectory ?? Path . ChangeExtension ( file , null ) ;
27- if ( Directory . Exists ( targetDirectory ) )
28- {
29- throw new GracefulException ( CliCommandStrings . DirectoryAlreadyExists , targetDirectory ) ;
30- }
28+ string targetDirectory = DetermineOutputDirectory ( file ) ;
3129
3230 // Find directives (this can fail, so do this before creating the target directory).
3331 var sourceFile = VirtualProjectBuildingCommand . LoadSourceFile ( file ) ;
@@ -36,28 +34,37 @@ public override int Execute()
3634 // Find other items to copy over, e.g., default Content items like JSON files in Web apps.
3735 var includeItems = FindIncludedItems ( ) . ToList ( ) ;
3836
39- Directory . CreateDirectory ( targetDirectory ) ;
37+ bool dryRun = _parseResult . GetValue ( ProjectConvertCommandParser . DryRunOption ) ;
38+
39+ CreateDirectory ( targetDirectory ) ;
4040
4141 var targetFile = Path . Join ( targetDirectory , Path . GetFileName ( file ) ) ;
4242
43- // If there were any directives, remove them from the file.
44- if ( directives . Length != 0 )
43+ // Process the entry point file.
44+ if ( dryRun )
4545 {
46- VirtualProjectBuildingCommand . RemoveDirectivesFromFile ( directives , sourceFile . Text , targetFile ) ;
47- File . Delete ( file ) ;
46+ Reporter . Output . WriteLine ( CliCommandStrings . ProjectConvertWouldCopyFile , file , targetFile ) ;
47+ Reporter . Output . WriteLine ( CliCommandStrings . ProjectConvertWouldConvertFile , targetFile ) ;
4848 }
4949 else
5050 {
51- File . Move ( file , targetFile ) ;
51+ VirtualProjectBuildingCommand . RemoveDirectivesFromFile ( directives , sourceFile . Text , targetFile ) ;
5252 }
5353
5454 // Create project file.
5555 string projectFile = Path . Join ( targetDirectory , Path . GetFileNameWithoutExtension ( file ) + ".csproj" ) ;
56- using var stream = File . Open ( projectFile , FileMode . Create , FileAccess . Write ) ;
57- using var writer = new StreamWriter ( stream , Encoding . UTF8 ) ;
58- VirtualProjectBuildingCommand . WriteProjectFile ( writer , directives , isVirtualProject : false ) ;
56+ if ( dryRun )
57+ {
58+ Reporter . Output . WriteLine ( CliCommandStrings . ProjectConvertWouldCreateFile , projectFile ) ;
59+ }
60+ else
61+ {
62+ using var stream = File . Open ( projectFile , FileMode . Create , FileAccess . Write ) ;
63+ using var writer = new StreamWriter ( stream , Encoding . UTF8 ) ;
64+ VirtualProjectBuildingCommand . WriteProjectFile ( writer , directives , isVirtualProject : false ) ;
65+ }
5966
60- // Copy over included items.
67+ // Copy or move over included items.
6168 foreach ( var item in includeItems )
6269 {
6370 string targetItemFullPath = Path . Combine ( targetDirectory , item . RelativePath ) ;
@@ -69,12 +76,39 @@ public override int Execute()
6976 }
7077
7178 string targetItemDirectory = Path . GetDirectoryName ( targetItemFullPath ) ! ;
72- Directory . CreateDirectory ( targetItemDirectory ) ;
73- File . Copy ( item . FullPath , targetItemFullPath ) ;
79+ CreateDirectory ( targetItemDirectory ) ;
80+ CopyFile ( item . FullPath , targetItemFullPath ) ;
7481 }
7582
7683 return 0 ;
7784
85+ void CreateDirectory ( string path )
86+ {
87+ if ( dryRun )
88+ {
89+ if ( ! Directory . Exists ( path ) )
90+ {
91+ Reporter . Output . WriteLine ( CliCommandStrings . ProjectConvertWouldCreateDirectory , path ) ;
92+ }
93+ }
94+ else
95+ {
96+ Directory . CreateDirectory ( path ) ;
97+ }
98+ }
99+
100+ void CopyFile ( string source , string target )
101+ {
102+ if ( dryRun )
103+ {
104+ Reporter . Output . WriteLine ( CliCommandStrings . ProjectConvertWouldCopyFile , source , target ) ;
105+ }
106+ else
107+ {
108+ File . Copy ( source , target ) ;
109+ }
110+ }
111+
78112 IEnumerable < ( string FullPath , string RelativePath ) > FindIncludedItems ( )
79113 {
80114 string entryPointFileDirectory = PathUtility . EnsureTrailingSlash ( Path . GetDirectoryName ( file ) ! ) ;
@@ -118,4 +152,42 @@ public override int Execute()
118152 }
119153 }
120154 }
155+
156+ private string DetermineOutputDirectory ( string file )
157+ {
158+ string defaultValue = Path . ChangeExtension ( file , null ) ;
159+ string defaultValueRelative = Path . GetRelativePath ( relativeTo : Environment . CurrentDirectory , defaultValue ) ;
160+ string targetDirectory = _outputDirectory
161+ ?? TryAskForOutputDirectory ( defaultValueRelative )
162+ ?? defaultValue ;
163+ if ( Directory . Exists ( targetDirectory ) )
164+ {
165+ throw new GracefulException ( CliCommandStrings . DirectoryAlreadyExists , targetDirectory ) ;
166+ }
167+
168+ return targetDirectory ;
169+ }
170+
171+ private string ? TryAskForOutputDirectory ( string defaultValueRelative )
172+ {
173+ return InteractiveConsole . Ask < string ? > (
174+ string . Format ( CliCommandStrings . ProjectConvertAskForOutputDirectory , defaultValueRelative ) ,
175+ _parseResult ,
176+ ( path , out result , [ NotNullWhen ( returnValue : false ) ] out error) =>
177+ {
178+ if ( Directory . Exists ( path ) )
179+ {
180+ result = null ;
181+ error = string . Format ( CliCommandStrings . DirectoryAlreadyExists , Path . GetFullPath ( path ) ) ;
182+ return false ;
183+ }
184+
185+ result = path is null ? null : Path . GetFullPath ( path ) ;
186+ error = null ;
187+ return true ;
188+ } ,
189+ out var result )
190+ ? result
191+ : null ;
192+ }
121193}
0 commit comments