From 3ebbd23f27561e2a312aaceccdcc14d195bf1adb Mon Sep 17 00:00:00 2001
From: Kamalpreet Kaur <kmlkaur73@gmail.com>
Date: Mon, 23 Dec 2024 23:14:41 +0530
Subject: [PATCH] add: linux specific binary download

---
 .../BrowserStackLocal.csproj                  |  4 +-
 .../BrowserStackLocal/BrowserStackTunnel.cs   | 72 +++++++++----------
 BrowserStackLocal/BrowserStackLocal/Util.cs   | 26 +++++++
 3 files changed, 63 insertions(+), 39 deletions(-)
 create mode 100644 BrowserStackLocal/BrowserStackLocal/Util.cs

diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj
index 2fd4d10..db178a6 100644
--- a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj
+++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj
@@ -2,7 +2,7 @@
   <PropertyGroup>
     <RootNamespace>BrowserStack</RootNamespace>
     <AssemblyName>BrowserStackLocal</AssemblyName>
-    <TargetFrameworks>net20;netstandard2.0</TargetFrameworks>
+    <TargetFrameworks>net48;netstandard2.0</TargetFrameworks>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <Title>BrowserStackLocal</Title>
     <Product>BrowserStackLocal</Product>
@@ -31,4 +31,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
\ No newline at end of file
+</Project>
diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs
index 9b98e9d..f3cd6bc 100644
--- a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs
+++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs
@@ -15,12 +15,9 @@ public enum LocalState { Idle, Connecting, Connected, Error, Disconnected };
 
   public class BrowserStackTunnel : IDisposable
   {
-    // Need to get rid of this variable, instead use getBinaryName()
-    static readonly string binaryName = isDarwin() ? "BrowserStackLocal-darwin-x64" : "BrowserStackLocal.exe";
-    static readonly string downloadURL = isDarwin() ?
-                                        "https://www.browserstack.com/local-testing/downloads/binaries/BrowserStackLocal-darwin-x64" :
-                                        "https://www.browserstack.com/local-testing/downloads/binaries/BrowserStackLocal.exe";
-    static readonly string homepath = isDarwin() ?
+    static string binaryName = GetBinaryName();
+    static readonly string downloadURL = "https://www.browserstack.com/local-testing/downloads/binaries/" + binaryName;
+    static readonly string homepath = IsDarwin() || IsLinux() ?
                                         Environment.GetFolderPath(Environment.SpecialFolder.Personal) :
                                         Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
     public static readonly string[] basePaths = new string[] {
@@ -39,79 +36,80 @@ public class BrowserStackTunnel : IDisposable
 
     Process process = null;
 
-    static Boolean isDarwin()
+    static bool IsDarwin()
     {
       if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
       {
         return true;
       }
+      return false;
     }
+    
 
-    static Boolean isWindows()
+    static bool IsWindows()
     {
       if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
       {
         return true;
       }
+      return false;
     }
 
-    static Boolean isLinux()
+    static bool IsLinux()
     {
-      if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+      if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
       {
         return true;
       }
+      return false;
     }
 
-    static Boolean isAlpine()
+    static bool IsAlpine()
     {
-      const string osReleaseFile = "/etc/os-release";
-
-      if (File.Exists(osReleaseFile))
+      try
       {
-        string[] lines = File.ReadAllLines(osReleaseFile);
-        foreach (string line in lines)
+        string[] output = Util.RunShellCommand("grep -w 'NAME' /etc/os-release");
+        if (string.IsNullOrEmpty(output[0]) && output[0].Contains("Alpine"))
         {
-          if (line.StartsWith("ID="))
-          {
-            string id = line.Substring(3).Trim('"'); // Remove 'ID=' and quotes
-            if (id.Equals("alpine", StringComparison.OrdinalIgnoreCase))
-            {
-              return true;
-            }
-          }
+          return true;
         }
       }
+      catch (System.Exception)
+      {
+        return false;
+      }
+      return false;
     }
-    static staring getBinaryName()
+
+    static string GetBinaryName()
     {
-      if isDarwin()
+      if (IsDarwin())
       {
-        binaryName = "BrowserStackLocal-darwin-x64"
+        return "BrowserStackLocal-darwin-x64";
       }
-      else if isWindows()
+      else if (IsWindows())
       {
-        binaryName = "BrowserStackLocal.exe"
+        return "BrowserStackLocal.exe";
       }
-      else if isLinux()
+      else if (IsLinux())
       {
-        if (RuntimeInformation.OSArchitecture == Architecture.X64
-                           || RuntimeInformation.OSArchitecture == Architecture.Arm64)
+        if (Environment.Is64BitOperatingSystem)
         {
-          if isAlpine()
+          if (IsAlpine())
           {
-            binaryName = "BrowserStackLocal-alpine"
+            return "BrowserStackLocal-alpine";
           }
           else
           {
-            binaryName = "BrowserStackLocal-linux-x64"
+            return "BrowserStackLocal-linux-x64";
           }
         }
         else
         {
-          binaryName = "BrowserStackLocal-linux-ia32"
+          return "BrowserStackLocal-linux-ia32";
         }
       }
+      return "BrowserStackLocal.exe";
     }
 
     public virtual void addBinaryPath(string binaryAbsolute)
@@ -150,7 +148,7 @@ public virtual void fallbackPaths()
 
     public void modifyBinaryPermission()
     {
-      if (isDarwin())
+      if (IsDarwin() || IsLinux())
        {
         try
         {
diff --git a/BrowserStackLocal/BrowserStackLocal/Util.cs b/BrowserStackLocal/BrowserStackLocal/Util.cs
new file mode 100644
index 0000000..cbd114a
--- /dev/null
+++ b/BrowserStackLocal/BrowserStackLocal/Util.cs
@@ -0,0 +1,26 @@
+using System.Diagnostics;
+
+namespace BrowserStack
+{
+    public class Util {
+
+        // Only Unix Support
+        public static string[] RunShellCommand(string command) {
+            ProcessStartInfo psi = new ProcessStartInfo("bash", $"-c \"{command}\"") {
+                RedirectStandardOutput = true,
+                RedirectStandardError = true,
+                UseShellExecute = false,
+                CreateNoWindow = true
+            };
+
+            Process process = new Process { StartInfo = psi };
+            process.Start();
+            string output = process.StandardOutput.ReadToEnd();
+            string error = process.StandardError.ReadToEnd();
+            process.WaitForExit();
+            return new string[]{output, error};
+        }
+        
+    }
+}
+