diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 7982232165e..568399ac561 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -217,9 +217,17 @@ internal unsafe static char[] GetEnvironmentCharArray() /// internal static Dictionary GetEnvironmentVariables() { + Dictionary table = new Dictionary(200, StringComparer.OrdinalIgnoreCase); // Razzle has 150 environment variables + if (PlatformUtilities.IsUnix){ + // Mono does have expensive security checks + foreach (DictionaryEntry ke in Environment.GetEnvironmentVariables ()){ + table.Add ((string)ke.Key, (string)ke.Value); + } + return table; + } char[] block = GetEnvironmentCharArray(); - Dictionary table = new Dictionary(200, StringComparer.OrdinalIgnoreCase); // Razzle has 150 environment variables + // Copy strings out, parsing into pairs and inserting into the table. // The first few environment variable entries start with an '='! diff --git a/src/Shared/EncodingUtilities.cs b/src/Shared/EncodingUtilities.cs index b4bc885eda7..54d0f7d633a 100644 --- a/src/Shared/EncodingUtilities.cs +++ b/src/Shared/EncodingUtilities.cs @@ -27,6 +27,10 @@ static internal Encoding CurrentSystemOemEncoding // fall back to default ANSI encoding if we have problems s_currentOemEncoding = Encoding.Default; + if (PlatformUtilities.IsUnix){ + // The Mono default encoding is already the system encoding. + return s_currentOemEncoding; + } try { // get the current OEM code page diff --git a/src/Shared/FileUtilities.cs b/src/Shared/FileUtilities.cs index 1c6da527b4b..6f77a3dc3f0 100644 --- a/src/Shared/FileUtilities.cs +++ b/src/Shared/FileUtilities.cs @@ -309,6 +309,9 @@ private unsafe static bool AreStringsEqual(char* buffer, int len, string s) /// internal unsafe static string NormalizePath(string path) { + if (PlatformUtilities.IsUnix) + return Path.GetFullPath (path); + ErrorUtilities.VerifyThrowArgumentLength(path, "path"); int errorCode = 0; // 0 == success in Win32 @@ -740,6 +743,9 @@ internal static bool DirectoryExistsNoThrow(string fullPath) { fullPath = AttemptToShortenPath(fullPath); + if (PlatformUtilities.IsUnix) + return Directory.Exists (fullPath); + NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA data = new NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA(); bool success = false; @@ -762,6 +768,9 @@ internal static bool FileExistsNoThrow(string fullPath) { fullPath = AttemptToShortenPath(fullPath); + if (PlatformUtilities.IsUnix) + return File.Exists (fullPath); + NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA data = new NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA(); bool success = false; @@ -784,6 +793,9 @@ internal static bool FileOrDirectoryExistsNoThrow(string fullPath) { fullPath = AttemptToShortenPath(fullPath); + if (PlatformUtilities.IsUnix) + return Directory.Exists (fullPath) || File.Exists (fullPath); + NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA data = new NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA(); bool success = false; diff --git a/src/Shared/MSBuildNameIgnoreCaseComparer.cs b/src/Shared/MSBuildNameIgnoreCaseComparer.cs index d7ac19d60e6..1f3d113d5d1 100644 --- a/src/Shared/MSBuildNameIgnoreCaseComparer.cs +++ b/src/Shared/MSBuildNameIgnoreCaseComparer.cs @@ -76,13 +76,22 @@ internal class MSBuildNameIgnoreCaseComparer : EqualityComparer, IEquali /// We need a static contructor to retrieve the running ProcessorArchitecture that way we can /// Avoid using optimized code that will not run correctly on IA64 due to alignment issues /// + + // + // The side effect of this is to set s_runningProcessorArchitecture, which is not used + // in any of the code that has been released, so we skip it for Unix. + // static MSBuildNameIgnoreCaseComparer() { - NativeMethodsShared.SYSTEM_INFO systemInfo = new NativeMethodsShared.SYSTEM_INFO(); - - NativeMethodsShared.GetSystemInfo(ref systemInfo); - - s_runningProcessorArchitecture = systemInfo.wProcessorArchitecture; + if (PlatformUtilities.IsUnix){ + return; + } else { + NativeMethodsShared.SYSTEM_INFO systemInfo = new NativeMethodsShared.SYSTEM_INFO(); + + NativeMethodsShared.GetSystemInfo(ref systemInfo); + + s_runningProcessorArchitecture = systemInfo.wProcessorArchitecture; + } } /// diff --git a/src/Shared/NativeMethodsShared.cs b/src/Shared/NativeMethodsShared.cs index e5abf312a30..5875fdfbf27 100644 --- a/src/Shared/NativeMethodsShared.cs +++ b/src/Shared/NativeMethodsShared.cs @@ -163,7 +163,7 @@ internal struct SYSTEM_INFO internal ushort wProcessorRevision; } - + /// /// Wrap the intptr returned by OpenProcess in a safe handle. /// @@ -370,6 +370,15 @@ internal static bool GetLastWriteDirectoryUtcTime(string fullPath, out DateTime // there fileModifiedTimeUtc = DateTime.MinValue; + + if (PlatformUtilities.IsUnix){ + if (Directory.Exists (fullPath)){ + fileModifiedTimeUtc = File.GetLastWriteTimeUtc (fullPath); + return true; + } + return false; + } + WIN32_FILE_ATTRIBUTE_DATA data = new WIN32_FILE_ATTRIBUTE_DATA(); bool success = false; @@ -481,6 +490,14 @@ internal static MemoryStatus GetMemoryStatus() internal static DateTime GetLastWriteFileUtcTime(string fullPath) { DateTime fileModifiedTime = DateTime.MinValue; + if (PlatformUtilities.IsUnix){ + if (File.Exists (fullPath)) + return File.GetLastWriteTimeUtc (fullPath); + if (Directory.Exists (fullPath)) + return Directory.GetLastWriteTimeUtc (fullPath); + return fileModifiedTime; + } + WIN32_FILE_ATTRIBUTE_DATA data = new WIN32_FILE_ATTRIBUTE_DATA(); bool success = false; @@ -529,6 +546,7 @@ public static void ThrowExceptionForErrorCode(int errorCode) Marshal.ThrowExceptionForHR(errorCode); } + static string []paths; /// /// Looks for the given file in the system path i.e. all locations in /// the %PATH% environment variable. @@ -537,6 +555,17 @@ public static void ThrowExceptionForErrorCode(int errorCode) /// The location of the file, or null if file not found. internal static string FindOnPath(string filename) { + if (PlatformUtilities.IsUnix){ + if (paths == null) + paths = Environment.GetEnvironmentVariable ("PATH").Split (':'); + foreach (var p in paths){ + var full = Path.Combine (p, filename); + // TODO: not only it needs to exist, but it also should be executable + if (File.Exists (full)) + return full; + } + return null; + } StringBuilder pathBuilder = new StringBuilder(MAX_PATH + 1); string pathToFile = null; @@ -747,6 +776,9 @@ internal static List> GetChildProcessIds(in /// internal static string GetCurrentDirectory() { + if (PlatformUtilities.IsUnix) + return Environment.CurrentDirectory; + StringBuilder sb = new StringBuilder(MAX_PATH); int pathLength = GetCurrentDirectory(MAX_PATH, sb); @@ -838,11 +870,22 @@ internal static extern uint GetRequestedRuntimeInfo(String pExe, [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern int GetCurrentDirectory(int nBufferLength, [Out] StringBuilder lpBuffer); + [DllImport("libc", SetLastError = true)] + internal static extern int chdir (string path); + [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")] [SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api", Justification = "Using unmanaged equivalent for performance reasons")] - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport("kernel32.dll", EntryPoint="SetCurrentDirectory", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool SetCurrentDirectory(string path); + static extern bool _SetCurrentDirectory(string path); + internal static bool SetCurrentDirectory (string path) + { + if (PlatformUtilities.IsUnix) + return chdir (path) == 0; + else + return _SetCurrentDirectory (path); + } + [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")] [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] @@ -927,4 +970,22 @@ internal static bool MsgWaitOne(this WaitHandle handle, int timeout) #endregion } + internal class PlatformUtilities { + static int platform; + + internal static bool IsUnix { + get { + if (platform == 0){ + int p = (int) Environment.OSVersion.Platform; + + if ((p == 4) || (p == 6) || (p == 128)) { + platform = 1; + } else { + platform = 2; + } + } + return platform == 1; + } + } + } } diff --git a/src/XMakeBuildEngine/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/XMakeBuildEngine/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index 6b47c562b94..001a2c8e906 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -828,6 +828,9 @@ private void EvaluateRequestStates() [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect", Justification = "We're trying to get rid of memory because we're running low, so we need to collect NOW in order to free it up ASAP")] private void CheckMemoryUsage() { + if (PlatformUtilities.IsUnix) + return; + // Jeffrey Richter suggests that when the memory load in the system exceeds 80% it is a good // idea to start finding ways to unload unnecessary data to prevent memory starvation. We use this metric in // our calculations below. diff --git a/src/XMakeBuildEngine/Logging/BaseConsoleLogger.cs b/src/XMakeBuildEngine/Logging/BaseConsoleLogger.cs index 34187689126..8be8599b388 100644 --- a/src/XMakeBuildEngine/Logging/BaseConsoleLogger.cs +++ b/src/XMakeBuildEngine/Logging/BaseConsoleLogger.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -342,19 +342,23 @@ internal void WriteLinePretty(int indentLevel, string formattedString) /// internal void IsRunningWithCharacterFileType() { - // Get the std out handle - IntPtr stdHandle = NativeMethodsShared.GetStdHandle(NativeMethodsShared.STD_OUTPUT_HANDLE); - - if (stdHandle != Microsoft.Build.BackEnd.NativeMethods.InvalidHandle) - { - uint fileType = NativeMethodsShared.GetFileType(stdHandle); - - // The std out is a char type(LPT or Console) - runningWithCharacterFileType = (fileType == NativeMethodsShared.FILE_TYPE_CHAR); - } - else - { - runningWithCharacterFileType = false; + if (PlatformUtilities.IsRunningOnUnix){ + runningWithCharacterFileType = !Console.IsInputRedirected && !Console.IsOutputRedirected; + } else { + // Get the std out handle + IntPtr stdHandle = NativeMethodsShared.GetStdHandle(NativeMethodsShared.STD_OUTPUT_HANDLE); + + if (stdHandle != Microsoft.Build.BackEnd.NativeMethods.InvalidHandle) + { + uint fileType = NativeMethodsShared.GetFileType(stdHandle); + + // The std out is a char type(LPT or Console) + runningWithCharacterFileType = (fileType == NativeMethodsShared.FILE_TYPE_CHAR); + } + else + { + runningWithCharacterFileType = false; + } } } diff --git a/src/XMakeTasks/Exec.cs b/src/XMakeTasks/Exec.cs index aa9dd6db5be..6012de1b6f4 100644 --- a/src/XMakeTasks/Exec.cs +++ b/src/XMakeTasks/Exec.cs @@ -539,7 +539,10 @@ internal bool ValidateParametersAccessor() protected override string GenerateFullPathToTool() { // Get the fully qualified path to cmd.exe - return ToolLocationHelper.GetPathToSystemFile("cmd.exe"); + if (PlatformUtilities.IsUnix) + return "sh"; + else + return ToolLocationHelper.GetPathToSystemFile("cmd.exe"); } ///