1
1
using System ;
2
+ using System . Collections . Generic ;
2
3
using System . Diagnostics ;
3
4
using System . IO ;
5
+ using System . Linq ;
4
6
using System . Runtime . InteropServices ;
5
7
using GitCredentialManager . Interop . Posix . Native ;
6
8
@@ -349,6 +351,8 @@ private static string GetOSType()
349
351
return "Unknown" ;
350
352
}
351
353
354
+ private static string _linuxDistroVersion ;
355
+
352
356
private static string GetOSVersion ( ITrace2 trace2 )
353
357
{
354
358
//
@@ -373,22 +377,80 @@ private static string GetOSVersion(ITrace2 trace2)
373
377
374
378
if ( IsLinux ( ) )
375
379
{
376
- var psi = new ProcessStartInfo
377
- {
378
- FileName = "uname" ,
379
- Arguments = "-a" ,
380
- RedirectStandardOutput = true
381
- } ;
380
+ return _linuxDistroVersion ??= GetLinuxDistroVersion ( ) ;
382
381
383
- using ( var uname = new ChildProcess ( trace2 , psi ) )
382
+ string GetLinuxDistroVersion ( )
384
383
{
385
- uname . Start ( Trace2ProcessClass . Other ) ;
386
- uname . Process . WaitForExit ( ) ;
384
+ // Let's first try to get the distribution information from /etc/os-release
385
+ // (or /usr/lib/os-release) which is required in systemd distributions.
386
+ // https://www.freedesktop.org/software/systemd/man/os-release.html
387
+ foreach ( string osReleasePath in new [ ] { "/etc/os-release" , "/usr/lib/os-release" } )
388
+ {
389
+ if ( ! File . Exists ( osReleasePath ) )
390
+ {
391
+ continue ;
392
+ }
393
+
394
+ var props = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
395
+ char [ ] split = { '=' } ;
396
+ string [ ] lines = File . ReadAllLines ( osReleasePath ) ;
397
+ foreach ( string line in lines )
398
+ {
399
+ // Each line is a key="value" pair
400
+ string [ ] kvp = line . Split ( split , count : 2 ) ;
401
+ if ( kvp . Length != 2 )
402
+ {
403
+ continue ;
404
+ }
405
+
406
+ props [ kvp [ 0 ] ] = kvp [ 1 ] . Trim ( '"' ) ;
407
+ }
408
+
409
+ // Try to get the PRETTY_NAME first which is a user-friendly description
410
+ // including the distro name and version.
411
+ if ( props . TryGetValue ( "PRETTY_NAME" , out string prettyName ) )
412
+ {
413
+ return prettyName ;
414
+ }
415
+
416
+ // Fall-back to (NAME || ID) + (VERSION || VERSION_ID || VERSION_CODENAME)?
417
+ if ( props . TryGetValue ( "NAME" , out string distro ) ||
418
+ props . TryGetValue ( "ID" , out distro ) )
419
+ {
420
+ if ( props . TryGetValue ( "VERSION" , out string version ) ||
421
+ props . TryGetValue ( "VERSION_ID" , out version ) ||
422
+ props . TryGetValue ( "VERSION_CODENAME" , out version ) )
423
+ {
424
+ return $ "{ distro } { version } ";
425
+ }
426
+
427
+ // Return just the distro name if we don't have a version
428
+ return distro ;
429
+ }
430
+ }
387
431
388
- if ( uname . ExitCode == 0 )
432
+ // If we couldn't get the distribution information from /etc/os-release
433
+ // (for example if we're running on a non-systemd distribution), then let's
434
+ // use `uname -a` to get at least some information.
435
+ var psi = new ProcessStartInfo
389
436
{
390
- return uname . StandardOutput . ReadToEnd ( ) . Trim ( ) ;
437
+ FileName = "uname" ,
438
+ Arguments = "-a" ,
439
+ RedirectStandardOutput = true
440
+ } ;
441
+
442
+ using ( var uname = new ChildProcess ( trace2 , psi ) )
443
+ {
444
+ uname . Start ( Trace2ProcessClass . Other ) ;
445
+ uname . Process . WaitForExit ( ) ;
446
+
447
+ if ( uname . ExitCode == 0 )
448
+ {
449
+ return uname . StandardOutput . ReadToEnd ( ) . Trim ( ) ;
450
+ }
391
451
}
452
+
453
+ return "Unknown-Linux" ;
392
454
}
393
455
}
394
456
0 commit comments