2019-07-03 09:44:53 +02:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Diagnostics;
|
2019-11-10 17:10:38 +01:00
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2019-07-03 09:44:53 +02:00
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Runtime.CompilerServices;
|
2020-03-18 17:40:04 +01:00
|
|
|
using JetBrains.Annotations;
|
2019-07-03 09:44:53 +02:00
|
|
|
|
|
|
|
namespace GodotTools.Utils
|
|
|
|
{
|
2019-11-10 17:10:38 +01:00
|
|
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
2019-07-03 09:44:53 +02:00
|
|
|
public static class OS
|
|
|
|
{
|
|
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
2019-11-10 17:10:38 +01:00
|
|
|
static extern string GetPlatformName();
|
2019-07-03 09:44:53 +02:00
|
|
|
|
2019-12-17 13:10:01 +01:00
|
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
|
|
static extern bool UnixFileHasExecutableAccess(string filePath);
|
|
|
|
|
2019-11-10 17:10:38 +01:00
|
|
|
public static class Names
|
2019-07-03 09:44:53 +02:00
|
|
|
{
|
2019-11-10 17:10:38 +01:00
|
|
|
public const string Windows = "Windows";
|
|
|
|
public const string OSX = "OSX";
|
2020-05-09 20:55:50 +02:00
|
|
|
public const string Linux = "Linux";
|
|
|
|
public const string FreeBSD = "FreeBSD";
|
|
|
|
public const string NetBSD = "NetBSD";
|
|
|
|
public const string BSD = "BSD";
|
2019-11-10 17:10:38 +01:00
|
|
|
public const string Server = "Server";
|
|
|
|
public const string UWP = "UWP";
|
|
|
|
public const string Haiku = "Haiku";
|
|
|
|
public const string Android = "Android";
|
2020-03-18 17:40:04 +01:00
|
|
|
public const string iOS = "iOS";
|
2019-11-10 17:10:38 +01:00
|
|
|
public const string HTML5 = "HTML5";
|
2019-07-03 09:44:53 +02:00
|
|
|
}
|
|
|
|
|
2019-11-10 17:10:38 +01:00
|
|
|
public static class Platforms
|
2019-07-03 09:44:53 +02:00
|
|
|
{
|
2019-11-10 17:10:38 +01:00
|
|
|
public const string Windows = "windows";
|
|
|
|
public const string OSX = "osx";
|
2020-05-09 20:55:50 +02:00
|
|
|
public const string LinuxBSD = "linuxbsd";
|
2019-11-10 17:10:38 +01:00
|
|
|
public const string Server = "server";
|
|
|
|
public const string UWP = "uwp";
|
|
|
|
public const string Haiku = "haiku";
|
|
|
|
public const string Android = "android";
|
2020-03-18 17:40:04 +01:00
|
|
|
public const string iOS = "iphone";
|
2019-11-10 17:10:38 +01:00
|
|
|
public const string HTML5 = "javascript";
|
2019-07-03 09:44:53 +02:00
|
|
|
}
|
|
|
|
|
2019-11-10 17:10:38 +01:00
|
|
|
public static readonly Dictionary<string, string> PlatformNameMap = new Dictionary<string, string>
|
2019-07-03 09:44:53 +02:00
|
|
|
{
|
2019-11-10 17:10:38 +01:00
|
|
|
[Names.Windows] = Platforms.Windows,
|
|
|
|
[Names.OSX] = Platforms.OSX,
|
2020-05-09 20:55:50 +02:00
|
|
|
[Names.Linux] = Platforms.LinuxBSD,
|
|
|
|
[Names.FreeBSD] = Platforms.LinuxBSD,
|
|
|
|
[Names.NetBSD] = Platforms.LinuxBSD,
|
|
|
|
[Names.BSD] = Platforms.LinuxBSD,
|
2019-11-10 17:10:38 +01:00
|
|
|
[Names.Server] = Platforms.Server,
|
|
|
|
[Names.UWP] = Platforms.UWP,
|
|
|
|
[Names.Haiku] = Platforms.Haiku,
|
|
|
|
[Names.Android] = Platforms.Android,
|
2020-03-18 17:40:04 +01:00
|
|
|
[Names.iOS] = Platforms.iOS,
|
2019-11-10 17:10:38 +01:00
|
|
|
[Names.HTML5] = Platforms.HTML5
|
|
|
|
};
|
2019-07-03 09:44:53 +02:00
|
|
|
|
2019-11-10 17:10:38 +01:00
|
|
|
private static bool IsOS(string name)
|
2019-07-03 09:44:53 +02:00
|
|
|
{
|
2019-11-10 17:10:38 +01:00
|
|
|
return name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
|
2019-07-03 09:44:53 +02:00
|
|
|
}
|
|
|
|
|
2020-05-09 20:55:50 +02:00
|
|
|
private static bool IsAnyOS(IEnumerable<string> names)
|
|
|
|
{
|
|
|
|
return names.Any(p => p.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase));
|
|
|
|
}
|
|
|
|
|
|
|
|
private static readonly IEnumerable<string> LinuxBSDPlatforms =
|
|
|
|
new[] {Names.Linux, Names.FreeBSD, Names.NetBSD, Names.BSD};
|
|
|
|
|
|
|
|
private static readonly IEnumerable<string> UnixLikePlatforms =
|
|
|
|
new[] {Names.OSX, Names.Server, Names.Haiku, Names.Android, Names.iOS}
|
|
|
|
.Concat(LinuxBSDPlatforms).ToArray();
|
|
|
|
|
2019-11-21 15:08:52 +01:00
|
|
|
private static readonly Lazy<bool> _isWindows = new Lazy<bool>(() => IsOS(Names.Windows));
|
|
|
|
private static readonly Lazy<bool> _isOSX = new Lazy<bool>(() => IsOS(Names.OSX));
|
2020-05-09 20:55:50 +02:00
|
|
|
private static readonly Lazy<bool> _isLinuxBSD = new Lazy<bool>(() => IsAnyOS(LinuxBSDPlatforms));
|
2019-11-21 15:08:52 +01:00
|
|
|
private static readonly Lazy<bool> _isServer = new Lazy<bool>(() => IsOS(Names.Server));
|
|
|
|
private static readonly Lazy<bool> _isUWP = new Lazy<bool>(() => IsOS(Names.UWP));
|
|
|
|
private static readonly Lazy<bool> _isHaiku = new Lazy<bool>(() => IsOS(Names.Haiku));
|
|
|
|
private static readonly Lazy<bool> _isAndroid = new Lazy<bool>(() => IsOS(Names.Android));
|
2020-03-18 17:40:04 +01:00
|
|
|
private static readonly Lazy<bool> _isiOS = new Lazy<bool>(() => IsOS(Names.iOS));
|
2019-11-21 15:08:52 +01:00
|
|
|
private static readonly Lazy<bool> _isHTML5 = new Lazy<bool>(() => IsOS(Names.HTML5));
|
2020-05-09 20:55:50 +02:00
|
|
|
private static readonly Lazy<bool> _isUnixLike = new Lazy<bool>(() => IsAnyOS(UnixLikePlatforms));
|
2019-11-21 15:08:52 +01:00
|
|
|
|
2019-12-04 15:07:00 +01:00
|
|
|
public static bool IsWindows => _isWindows.Value || IsUWP;
|
2019-11-21 15:08:52 +01:00
|
|
|
public static bool IsOSX => _isOSX.Value;
|
2020-05-09 20:55:50 +02:00
|
|
|
public static bool IsLinuxBSD => _isLinuxBSD.Value;
|
2019-11-21 15:08:52 +01:00
|
|
|
public static bool IsServer => _isServer.Value;
|
|
|
|
public static bool IsUWP => _isUWP.Value;
|
|
|
|
public static bool IsHaiku => _isHaiku.Value;
|
|
|
|
public static bool IsAndroid => _isAndroid.Value;
|
2020-03-18 17:40:04 +01:00
|
|
|
public static bool IsiOS => _isiOS.Value;
|
2019-11-21 15:08:52 +01:00
|
|
|
public static bool IsHTML5 => _isHTML5.Value;
|
2020-05-09 20:55:50 +02:00
|
|
|
public static bool IsUnixLike => _isUnixLike.Value;
|
2019-07-03 09:44:53 +02:00
|
|
|
|
2019-11-13 20:12:36 +01:00
|
|
|
public static char PathSep => IsWindows ? ';' : ':';
|
2019-07-03 09:44:53 +02:00
|
|
|
|
2020-03-18 17:40:04 +01:00
|
|
|
public static string PathWhich([NotNull] string name)
|
2019-07-03 09:44:53 +02:00
|
|
|
{
|
2019-11-21 15:08:52 +01:00
|
|
|
return IsWindows ? PathWhichWindows(name) : PathWhichUnix(name);
|
|
|
|
}
|
|
|
|
|
2020-03-18 17:40:04 +01:00
|
|
|
private static string PathWhichWindows([NotNull] string name)
|
2019-11-21 15:08:52 +01:00
|
|
|
{
|
|
|
|
string[] windowsExts = Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? new string[] { };
|
|
|
|
string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
|
|
|
|
|
|
|
|
var searchDirs = new List<string>();
|
|
|
|
|
|
|
|
if (pathDirs != null)
|
|
|
|
searchDirs.AddRange(pathDirs);
|
|
|
|
|
|
|
|
string nameExt = Path.GetExtension(name);
|
2019-12-21 19:26:29 +01:00
|
|
|
bool hasPathExt = !string.IsNullOrEmpty(nameExt) && windowsExts.Contains(nameExt, StringComparer.OrdinalIgnoreCase);
|
2019-11-21 15:08:52 +01:00
|
|
|
|
|
|
|
searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list
|
|
|
|
|
|
|
|
if (hasPathExt)
|
|
|
|
return searchDirs.Select(dir => Path.Combine(dir, name)).FirstOrDefault(File.Exists);
|
|
|
|
|
|
|
|
return (from dir in searchDirs
|
2020-05-09 20:55:50 +02:00
|
|
|
select Path.Combine(dir, name)
|
2019-11-21 15:08:52 +01:00
|
|
|
into path
|
2020-05-09 20:55:50 +02:00
|
|
|
from ext in windowsExts
|
|
|
|
select path + ext).FirstOrDefault(File.Exists);
|
2019-11-21 15:08:52 +01:00
|
|
|
}
|
|
|
|
|
2020-03-18 17:40:04 +01:00
|
|
|
private static string PathWhichUnix([NotNull] string name)
|
2019-11-21 15:08:52 +01:00
|
|
|
{
|
2019-07-03 09:44:53 +02:00
|
|
|
string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
|
|
|
|
|
|
|
|
var searchDirs = new List<string>();
|
|
|
|
|
|
|
|
if (pathDirs != null)
|
|
|
|
searchDirs.AddRange(pathDirs);
|
|
|
|
|
|
|
|
searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list
|
|
|
|
|
2019-11-21 15:08:52 +01:00
|
|
|
return searchDirs.Select(dir => Path.Combine(dir, name))
|
2019-12-17 13:10:01 +01:00
|
|
|
.FirstOrDefault(path => File.Exists(path) && UnixFileHasExecutableAccess(path));
|
2019-07-03 09:44:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void RunProcess(string command, IEnumerable<string> arguments)
|
|
|
|
{
|
2019-11-13 20:12:36 +01:00
|
|
|
// TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead
|
2019-07-03 09:44:53 +02:00
|
|
|
string CmdLineArgsToString(IEnumerable<string> args)
|
|
|
|
{
|
2019-11-13 20:12:36 +01:00
|
|
|
// Not perfect, but as long as we are careful...
|
2019-07-03 09:44:53 +02:00
|
|
|
return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg));
|
|
|
|
}
|
|
|
|
|
2019-11-13 20:12:36 +01:00
|
|
|
var startInfo = new ProcessStartInfo(command, CmdLineArgsToString(arguments))
|
2019-07-03 09:44:53 +02:00
|
|
|
{
|
|
|
|
RedirectStandardOutput = true,
|
|
|
|
RedirectStandardError = true,
|
|
|
|
UseShellExecute = false
|
|
|
|
};
|
|
|
|
|
|
|
|
using (Process process = Process.Start(startInfo))
|
|
|
|
{
|
|
|
|
if (process == null)
|
|
|
|
throw new Exception("No process was started");
|
|
|
|
|
|
|
|
process.BeginOutputReadLine();
|
|
|
|
process.BeginErrorReadLine();
|
2019-12-11 14:46:28 +01:00
|
|
|
if (IsWindows && process.Id > 0)
|
2019-12-06 11:30:49 +01:00
|
|
|
User32Dll.AllowSetForegroundWindow(process.Id); // allows application to focus itself
|
2019-07-03 09:44:53 +02:00
|
|
|
}
|
|
|
|
}
|
2020-03-18 17:40:04 +01:00
|
|
|
|
|
|
|
public static int ExecuteCommand(string command, IEnumerable<string> arguments)
|
|
|
|
{
|
|
|
|
// TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead
|
|
|
|
string CmdLineArgsToString(IEnumerable<string> args)
|
|
|
|
{
|
|
|
|
// Not perfect, but as long as we are careful...
|
|
|
|
return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg));
|
|
|
|
}
|
|
|
|
|
|
|
|
var startInfo = new ProcessStartInfo(command, CmdLineArgsToString(arguments));
|
|
|
|
|
|
|
|
Console.WriteLine($"Executing: \"{startInfo.FileName}\" {startInfo.Arguments}");
|
|
|
|
|
|
|
|
// Print the output
|
|
|
|
startInfo.RedirectStandardOutput = false;
|
|
|
|
startInfo.RedirectStandardError = false;
|
|
|
|
|
|
|
|
startInfo.UseShellExecute = false;
|
|
|
|
|
2020-05-09 20:55:50 +02:00
|
|
|
using (var process = new Process {StartInfo = startInfo})
|
2020-03-18 17:40:04 +01:00
|
|
|
{
|
|
|
|
process.Start();
|
|
|
|
process.WaitForExit();
|
|
|
|
|
|
|
|
return process.ExitCode;
|
|
|
|
}
|
|
|
|
}
|
2019-07-03 09:44:53 +02:00
|
|
|
}
|
|
|
|
}
|