1 #region Copyright notice and license
2 
3 // Copyright 2018 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #endregion
18 
19 using System;
20 using System.IO;
21 using System.Runtime.CompilerServices;
22 using System.Runtime.InteropServices;
23 using System.Security;
24 
25 namespace Grpc.Tools
26 {
27     // Metadata names (MSBuild item attributes) that we refer to often.
28     static class Metadata
29     {
30         // On output dependency lists.
31         public static string Source = "Source";
32         // On Protobuf items.
33         public static string ProtoRoot = "ProtoRoot";
34         public static string OutputDir = "OutputDir";
35         public static string GrpcServices = "GrpcServices";
36         public static string GrpcOutputDir = "GrpcOutputDir";
37     };
38 
39     // A few flags used to control the behavior under various platforms.
40     internal static class Platform
41     {
42         public enum OsKind { Unknown, Windows, Linux, MacOsX };
43         public static readonly OsKind Os;
44 
45         public enum CpuKind { Unknown, X86, X64 };
46         public static readonly CpuKind Cpu;
47 
48         // This is not necessarily true, but good enough. BCL lacks a per-FS
49         // API to determine file case sensitivity.
50         public static bool IsFsCaseInsensitive => Os == OsKind.Windows;
51         public static bool IsWindows => Os == OsKind.Windows;
52 
Platform()53         static Platform()
54         {
55 #if NETCORE
56             Os = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OsKind.Windows
57                : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? OsKind.Linux
58                : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OsKind.MacOsX
59                : OsKind.Unknown;
60 
61             switch (RuntimeInformation.ProcessArchitecture)
62             {
63                 case Architecture.X86: Cpu = CpuKind.X86; break;
64                 case Architecture.X64: Cpu = CpuKind.X64; break;
65                 // We do not have build tools for other architectures.
66                 default: Cpu = CpuKind.Unknown; break;
67             }
68 #else
69             // Using the same best-effort detection logic as Grpc.Core/PlatformApis.cs
70             var platform = Environment.OSVersion.Platform;
71             if (platform == PlatformID.Win32NT || platform == PlatformID.Win32S || platform == PlatformID.Win32Windows)
72             {
73                 Os = OsKind.Windows;
74             }
75             else if (platform == PlatformID.Unix && GetUname() == "Darwin")
76             {
77                 Os = OsKind.MacOsX;
78             }
79             else
80             {
81                 Os = OsKind.Linux;
82             }
83 
84             // Hope we are not building on ARM under Xamarin!
85             Cpu = Environment.Is64BitProcess ? CpuKind.X64 : CpuKind.X86;
86 #endif
87         }
88 
89         [DllImport("libc")]
uname(IntPtr buf)90         static extern int uname(IntPtr buf);
91 
92         // This code is copied from Grpc.Core/PlatformApis.cs
GetUname()93         static string GetUname()
94         {
95             var buffer = Marshal.AllocHGlobal(8192);
96             try
97             {
98                 if (uname(buffer) == 0)
99                 {
100                     return Marshal.PtrToStringAnsi(buffer);
101                 }
102                 return string.Empty;
103             }
104             catch
105             {
106                 return string.Empty;
107             }
108             finally
109             {
110                 if (buffer != IntPtr.Zero)
111                 {
112                     Marshal.FreeHGlobal(buffer);
113                 }
114             }
115         }
116     };
117 
118     // Exception handling helpers.
119     static class Exceptions
120     {
121         // Returns true iff the exception indicates an error from an I/O call. See
122         // https://github.com/Microsoft/msbuild/blob/v15.4.8.50001/src/Shared/ExceptionHandling.cs#L101
123         static public bool IsIoRelated(Exception ex) =>
124             ex is IOException ||
125             (ex is ArgumentException && !(ex is ArgumentNullException)) ||
126             ex is SecurityException ||
127             ex is UnauthorizedAccessException ||
128             ex is NotSupportedException;
129     };
130 
131     // String helpers.
132     static class Strings
133     {
134         // Compare string to argument using OrdinalIgnoreCase comparison.
EqualNoCase(this string a, string b)135         public static bool EqualNoCase(this string a, string b) =>
136             string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
137     }
138 }
139