Skip to content

Commit

Permalink
platformutils: avoid procstart to get Linux distro info
Browse files Browse the repository at this point in the history
Try using the /etc/os-release file, for systemd distros, in favour of
calling out to `uname` which can add extra overhead in the form of
process startup. Direct file I/O and parsing should be faster.
  • Loading branch information
mjcheetham committed May 4, 2023
1 parent 39504ac commit b7aeb3a
Showing 1 changed file with 64 additions and 11 deletions.
75 changes: 64 additions & 11 deletions src/shared/Core/PlatformUtils.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using GitCredentialManager.Interop.Posix.Native;

Expand Down Expand Up @@ -349,6 +351,8 @@ private static string GetOSType()
return "Unknown";
}

private static string _linuxDistroVersion;

private static string GetOSVersion(ITrace2 trace2)
{
//
Expand All @@ -373,22 +377,71 @@ private static string GetOSVersion(ITrace2 trace2)

if (IsLinux())
{
var psi = new ProcessStartInfo
{
FileName = "uname",
Arguments = "-a",
RedirectStandardOutput = true
};
return _linuxDistroVersion ??= GetLinuxDistroVersion();

using (var uname = new ChildProcess(trace2, psi))
string GetLinuxDistroVersion()
{
uname.Start(Trace2ProcessClass.Other);
uname.Process.WaitForExit();
// Let's first try to get the distribution information from /etc/os-release
// (or /usr/lib/os-release) which is required in systemd distributions.
// https://www.freedesktop.org/software/systemd/man/os-release.html
foreach (string osReleasePath in new[] { "/etc/os-release", "/usr/lib/os-release" })
{
if (!File.Exists(osReleasePath))
{
continue;
}

// Each line is a key=value pair
char[] split = { '=' };
IDictionary<string, string> props = File.ReadAllLines(osReleasePath)
.Select(x => x.Split(split, count: 2))
.ToDictionary(x => x[0].Trim(), x => x[1].Trim(), StringComparer.OrdinalIgnoreCase);

// Try to get the PRETTY_NAME first which is a user-friendly description
// including the distro name and version.
if (props.TryGetValue("PRETTY_NAME", out string prettyName))
{
return prettyName;
}

// Fall-back to (NAME || ID) + (VERSION || VERSION_ID || VERSION_CODENAME)?
if (props.TryGetValue("NAME", out string distro) ||
props.TryGetValue("ID", out distro))
{
if (props.TryGetValue("VERSION", out string version) ||
props.TryGetValue("VERSION_ID", out version) ||
props.TryGetValue("VERSION_CODENAME", out version))
{
return $"{distro} {version}";
}

// Return just the distro name if we don't have a version
return distro;
}
}

if (uname.ExitCode == 0)
// If we couldn't get the distribution information from /etc/os-release
// (for example if we're running on a non-systemd distribution), then let's
// use `uname -a` to get at least some information.
var psi = new ProcessStartInfo
{
return uname.StandardOutput.ReadToEnd().Trim();
FileName = "uname",
Arguments = "-a",
RedirectStandardOutput = true
};

using (var uname = new ChildProcess(trace2, psi))
{
uname.Start(Trace2ProcessClass.Other);
uname.Process.WaitForExit();

if (uname.ExitCode == 0)
{
return uname.StandardOutput.ReadToEnd().Trim();
}
}

return "Unknown-Linux";
}
}

Expand Down

0 comments on commit b7aeb3a

Please sign in to comment.