Forge
csharpdeeb25a2
1namespace CascadeIDE.Features.Workspace.Application;
2
3/// <summary>
4/// Создание пустого файла решения через <c>dotnet new sln</c> (без шаблонов из NuGet — только встроенный шаблон SDK).
5/// </summary>
6public static class BlankSolutionCreator
7{
8 /// <param name="solutionFilePath">Полный путь к будущему <c>.sln</c> (файл ещё не должен существовать).</param>
9 public static async Task<BlankSolutionCreateResult> TryCreateAsync(
10 string solutionFilePath,
11 IDotnetCommandRunner dotnetRunner,
12 CancellationToken cancellationToken = default)
13 {
14 ArgumentNullException.ThrowIfNull(dotnetRunner);
15
16 if (string.IsNullOrWhiteSpace(solutionFilePath))
17 return BlankSolutionCreateResult.Failure("Путь к решению пустой.");
18
19 string fullPath;
20 try
21 {
22 fullPath = CanonicalFilePath.Normalize(solutionFilePath.Trim());
23 }
24 catch (Exception ex)
25 {
26 return BlankSolutionCreateResult.Failure("Некорректный путь: " + ex.Message);
27 }
28
29 if (!fullPath.EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
30 return BlankSolutionCreateResult.Failure("Нужен путь к файлу с расширением .sln.");
31
32 if (File.Exists(fullPath))
33 return BlankSolutionCreateResult.Failure("Файл решения уже существует: " + fullPath);
34
35 var solutionName = Path.GetFileNameWithoutExtension(fullPath);
36 if (string.IsNullOrWhiteSpace(solutionName))
37 return BlankSolutionCreateResult.Failure("Имя решения пустое.");
38
39 var outputDir = Path.GetDirectoryName(fullPath);
40 if (string.IsNullOrWhiteSpace(outputDir))
41 return BlankSolutionCreateResult.Failure("Не удалось определить каталог для решения.");
42
43 try
44 {
45 Directory.CreateDirectory(outputDir);
46 }
47 catch (Exception ex)
48 {
49 return BlankSolutionCreateResult.Failure("Не удалось создать каталог: " + ex.Message);
50 }
51
52 IReadOnlyList<string> args = ["new", "sln", "-n", solutionName, "-o", outputDir];
53 var (ok, exitCode, output) = await dotnetRunner
54 .RunAsync(args, workingDirectory: outputDir, cancellationToken)
55 .ConfigureAwait(false);
56
57 if (!ok)
58 {
59 var tail = string.IsNullOrWhiteSpace(output) ? "" : "\r\n" + output.Trim();
60 return BlankSolutionCreateResult.Failure($"dotnet new sln завершился с кодом {exitCode}.{tail}");
61 }
62
63 if (!File.Exists(fullPath))
64 return BlankSolutionCreateResult.Failure(
65 "Команда выполнилась, но файл решения не найден. Вывод dotnet:\r\n" + output.Trim());
66
67 return BlankSolutionCreateResult.Success(fullPath);
68 }
69}
70
71/// <summary>Исход <see cref="BlankSolutionCreator.TryCreateAsync"/>.</summary>
72public readonly record struct BlankSolutionCreateResult(bool Ok, string? SolutionPath, string? ErrorMessage)
73{
74 public static BlankSolutionCreateResult Success(string solutionPath) => new(true, solutionPath, null);
75
76 public static BlankSolutionCreateResult Failure(string message) => new(false, null, message);
77}
78
View only · write via MCP/CIDE