summaryrefslogtreecommitdiff
path: root/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
blob: 7bce53308c3ce7250cecedb41392c3a514bd1a6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using JetBrains.Annotations;
using OS = GodotTools.Utils.OS;

namespace GodotTools.Build
{
    public static class DotNetFinder
    {
        [CanBeNull]
        public static string FindDotNetExe()
        {
            // In the future, this method may do more than just search in PATH. We could look in
            // known locations or use Godot's linked nethost to search from the hostfxr location.

            return OS.PathWhich("dotnet");
        }

        public static bool TryFindDotNetSdk(
            Version expectedVersion,
            [NotNullWhen(true)] out Version version,
            [NotNullWhen(true)] out string path
        )
        {
            version = null;
            path = null;

            string dotNetExe = FindDotNetExe();

            if (string.IsNullOrEmpty(dotNetExe))
                return false;

            using Process process = new Process();
            process.StartInfo = new ProcessStartInfo(dotNetExe, "--list-sdks")
            {
                UseShellExecute = false,
                RedirectStandardOutput = true
            };

            process.StartInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"] = "en-US";

            var lines = new List<string>();

            process.OutputDataReceived += (_, e) =>
            {
                if (!string.IsNullOrWhiteSpace(e.Data))
                    lines.Add(e.Data);
            };

            try
            {
                process.Start();
            }
            catch
            {
                return false;
            }

            process.BeginOutputReadLine();
            process.WaitForExit();

            Version latestVersionMatch = null;
            string matchPath = null;

            foreach (var line in lines)
            {
                string[] sdkLineParts = line.Trim()
                    .Split(' ', 2, StringSplitOptions.TrimEntries);

                if (sdkLineParts.Length < 2)
                    continue;

                if (!Version.TryParse(sdkLineParts[0], out var lineVersion))
                    continue;

                // We're looking for the exact same major version
                if (lineVersion.Major != expectedVersion.Major)
                    continue;

                if (latestVersionMatch != null && lineVersion < latestVersionMatch)
                    continue;

                latestVersionMatch = lineVersion;
                matchPath = sdkLineParts[1].TrimStart('[').TrimEnd(']');
            }

            if (latestVersionMatch == null)
                return false;

            version = latestVersionMatch;
            path = Path.Combine(matchPath!, version.ToString());

            return true;
        }
    }
}