diff --git a/DeviceTests/DeviceTests.Android/DeviceTests.Android.csproj b/DeviceTests/DeviceTests.Android/DeviceTests.Android.csproj index 6ea4d3e..9b81f49 100644 --- a/DeviceTests/DeviceTests.Android/DeviceTests.Android.csproj +++ b/DeviceTests/DeviceTests.Android/DeviceTests.Android.csproj @@ -7,7 +7,7 @@ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Library DeviceTests.Droid - XamarinEssentialsDeviceTestsAndroid + DeviceTestsAndroid v10.0 True true diff --git a/DeviceTests/DeviceTests.UWP/AppBundleFile.txt b/DeviceTests/DeviceTests.UWP/AppBundleFile.txt deleted file mode 100644 index 0ca24c9..0000000 --- a/DeviceTests/DeviceTests.UWP/AppBundleFile.txt +++ /dev/null @@ -1 +0,0 @@ -This file was in the app bundle. \ No newline at end of file diff --git a/DeviceTests/DeviceTests.UWP/AppBundleFile_NoExtension b/DeviceTests/DeviceTests.UWP/AppBundleFile_NoExtension deleted file mode 100644 index 0ca24c9..0000000 --- a/DeviceTests/DeviceTests.UWP/AppBundleFile_NoExtension +++ /dev/null @@ -1 +0,0 @@ -This file was in the app bundle. \ No newline at end of file diff --git a/DeviceTests/DeviceTests.UWP/DeviceTests.UWP.csproj b/DeviceTests/DeviceTests.UWP/DeviceTests.UWP.csproj index c544faa..3768eb7 100644 --- a/DeviceTests/DeviceTests.UWP/DeviceTests.UWP.csproj +++ b/DeviceTests/DeviceTests.UWP/DeviceTests.UWP.csproj @@ -8,7 +8,7 @@ AppContainerExe Properties DeviceTests.UWP - XamarinEssentialsDeviceTestsUWP + DeviceTestsUWP en-US UAP 10.0.16299.0 @@ -17,7 +17,9 @@ true 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - false + True + 7301D596D36DC7AD797E01BBF93CC2789AEA96C0 + DeviceTests.UWP_TemporaryKey.pfx true @@ -113,25 +115,14 @@ true - - - - Windows Mobile Extensions for the UWP - - - - - {63a4f6a1-48bf-4d32-aed7-82f605edb042} - Xamarin.Essentials - - {be0de9a3-d92c-47c5-9ec4-dfb546bbdf77} + {E049A504-C168-41DC-80DF-0C4C6F363761} DeviceTests @@ -153,9 +144,6 @@ - - - @@ -190,10 +178,10 @@ - + - + 14.0 diff --git a/DeviceTests/DeviceTests.UWP/Folder/AppBundleFile_Nested.txt b/DeviceTests/DeviceTests.UWP/Folder/AppBundleFile_Nested.txt deleted file mode 100644 index 0ca24c9..0000000 --- a/DeviceTests/DeviceTests.UWP/Folder/AppBundleFile_Nested.txt +++ /dev/null @@ -1 +0,0 @@ -This file was in the app bundle. \ No newline at end of file diff --git a/DeviceTests/DeviceTests.UWP/Package.appxmanifest b/DeviceTests/DeviceTests.UWP/Package.appxmanifest index f0a33b6..f217b49 100644 --- a/DeviceTests/DeviceTests.UWP/Package.appxmanifest +++ b/DeviceTests/DeviceTests.UWP/Package.appxmanifest @@ -1,10 +1,10 @@  - + Tests - Microsoft + dotnet-devices Assets\StoreLogo.png @@ -31,8 +31,5 @@ - - - \ No newline at end of file diff --git a/DeviceTests/DeviceTests/DeviceTests.csproj b/DeviceTests/DeviceTests/DeviceTests.csproj index bdcb1d3..c8844c1 100644 --- a/DeviceTests/DeviceTests/DeviceTests.csproj +++ b/DeviceTests/DeviceTests/DeviceTests.csproj @@ -10,9 +10,4 @@ - - - - - \ No newline at end of file diff --git a/dotnet-devices.sln b/dotnet-devices.sln index 9545cf3..bcba215 100644 --- a/dotnet-devices.sln +++ b/dotnet-devices.sln @@ -1,92 +1,246 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-devices", "dotnet-devices\dotnet-devices.csproj", "{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}" +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30523.141 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-devices", "dotnet-devices\dotnet-devices.csproj", "{09DD6E17-FEEC-4E1E-8823-7D6046D735F5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-devices.Tests", "dotnet-devices.Tests\dotnet-devices.Tests.csproj", "{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-devices.Tests", "dotnet-devices.Tests\dotnet-devices.Tests.csproj", "{1F459FB5-8D2D-4649-90EF-5CC54FB10A88}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DeviceTests", "DeviceTests", "{BDAAACF1-1483-412C-A14C-A7976D0FBF3D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests", "DeviceTests\DeviceTests\DeviceTests.csproj", "{E049A504-C168-41DC-80DF-0C4C6F363761}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeviceTests", "DeviceTests\DeviceTests\DeviceTests.csproj", "{E049A504-C168-41DC-80DF-0C4C6F363761}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests.iOS", "DeviceTests\DeviceTests.iOS\DeviceTests.iOS.csproj", "{EE8FC716-27FC-405B-BD27-AF17E01A6671}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests.Android", "DeviceTests\DeviceTests.Android\DeviceTests.Android.csproj", "{CB2072E0-A437-4811-AE17-16CAE0DDA1B1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceTests.UWP", "DeviceTests\DeviceTests.UWP\DeviceTests.UWP.csproj", "{4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - Debug|iPhoneSimulator = Debug|iPhoneSimulator - Release|iPhoneSimulator = Release|iPhoneSimulator + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 Debug|iPhone = Debug|iPhone + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|Any CPU.Build.0 = Release|Any CPU - {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|ARM.ActiveCfg = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|ARM.Build.0 = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|ARM64.Build.0 = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhone.ActiveCfg = Debug|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhone.Build.0 = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|x64.ActiveCfg = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|x64.Build.0 = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|x86.ActiveCfg = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Debug|x86.Build.0 = Debug|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|Any CPU.Build.0 = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|ARM.ActiveCfg = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|ARM.Build.0 = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|ARM64.ActiveCfg = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|ARM64.Build.0 = Release|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhone.ActiveCfg = Release|Any CPU {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhone.Build.0 = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|x64.ActiveCfg = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|x64.Build.0 = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|x86.ActiveCfg = Release|Any CPU + {09DD6E17-FEEC-4E1E-8823-7D6046D735F5}.Release|x86.Build.0 = Release|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|Any CPU.Build.0 = Release|Any CPU - {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|ARM.ActiveCfg = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|ARM.Build.0 = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|ARM64.Build.0 = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhone.ActiveCfg = Debug|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhone.Build.0 = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|x64.ActiveCfg = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|x64.Build.0 = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|x86.ActiveCfg = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Debug|x86.Build.0 = Debug|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|Any CPU.Build.0 = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|ARM.ActiveCfg = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|ARM.Build.0 = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|ARM64.ActiveCfg = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|ARM64.Build.0 = Release|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhone.ActiveCfg = Release|Any CPU {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhone.Build.0 = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|x64.ActiveCfg = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|x64.Build.0 = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|x86.ActiveCfg = Release|Any CPU + {1F459FB5-8D2D-4649-90EF-5CC54FB10A88}.Release|x86.Build.0 = Release|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|Any CPU.Build.0 = Release|Any CPU - {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|ARM.Build.0 = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|ARM64.Build.0 = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhone.ActiveCfg = Debug|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhone.Build.0 = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|x64.ActiveCfg = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|x64.Build.0 = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|x86.ActiveCfg = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Debug|x86.Build.0 = Debug|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|Any CPU.Build.0 = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|ARM.ActiveCfg = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|ARM.Build.0 = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|ARM64.ActiveCfg = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|ARM64.Build.0 = Release|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhone.ActiveCfg = Release|Any CPU {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhone.Build.0 = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|x64.ActiveCfg = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|x64.Build.0 = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|x86.ActiveCfg = Release|Any CPU + {E049A504-C168-41DC-80DF-0C4C6F363761}.Release|x86.Build.0 = Release|Any CPU {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator - {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator - {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|Any CPU.Build.0 = Release|iPhoneSimulator - {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator - {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator - {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator - {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|ARM.ActiveCfg = Debug|iPhone + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|ARM.Build.0 = Debug|iPhone + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|ARM64.ActiveCfg = Debug|iPhone + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|ARM64.Build.0 = Debug|iPhone {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhone.ActiveCfg = Debug|iPhone {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhone.Build.0 = Debug|iPhone + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|x64.ActiveCfg = Debug|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|x64.Build.0 = Debug|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Debug|x86.Build.0 = Debug|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|Any CPU.Build.0 = Release|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|ARM.ActiveCfg = Release|iPhone + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|ARM.Build.0 = Release|iPhone + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|ARM64.ActiveCfg = Release|iPhone + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|ARM64.Build.0 = Release|iPhone {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhone.ActiveCfg = Release|iPhone {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhone.Build.0 = Release|iPhone + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|x64.ActiveCfg = Release|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|x64.Build.0 = Release|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|x86.ActiveCfg = Release|iPhoneSimulator + {EE8FC716-27FC-405B-BD27-AF17E01A6671}.Release|x86.Build.0 = Release|iPhoneSimulator {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.Build.0 = Release|Any CPU - {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM.Build.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM.Deploy.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM64.Build.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|ARM64.Deploy.0 = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhone.ActiveCfg = Debug|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhone.Build.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhone.Deploy.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x64.ActiveCfg = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x64.Build.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x64.Deploy.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x86.ActiveCfg = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x86.Build.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Debug|x86.Deploy.0 = Debug|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.Build.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|Any CPU.Deploy.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM.ActiveCfg = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM.Build.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM.Deploy.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM64.ActiveCfg = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM64.Build.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|ARM64.Deploy.0 = Release|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhone.ActiveCfg = Release|Any CPU {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhone.Build.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhone.Deploy.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x64.ActiveCfg = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x64.Build.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x64.Deploy.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x86.ActiveCfg = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x86.Build.0 = Release|Any CPU + {CB2072E0-A437-4811-AE17-16CAE0DDA1B1}.Release|x86.Deploy.0 = Release|Any CPU + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|Any CPU.ActiveCfg = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|Any CPU.Build.0 = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|Any CPU.Deploy.0 = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM.ActiveCfg = Debug|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM.Build.0 = Debug|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM.Deploy.0 = Debug|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM64.Build.0 = Debug|ARM64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhone.ActiveCfg = Debug|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhone.Build.0 = Debug|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhone.Deploy.0 = Debug|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhoneSimulator.Build.0 = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|iPhoneSimulator.Deploy.0 = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x64.ActiveCfg = Debug|x64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x64.Build.0 = Debug|x64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x64.Deploy.0 = Debug|x64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x86.ActiveCfg = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x86.Build.0 = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Debug|x86.Deploy.0 = Debug|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|Any CPU.ActiveCfg = Release|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|Any CPU.Build.0 = Release|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|Any CPU.Deploy.0 = Release|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM.ActiveCfg = Release|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM.Build.0 = Release|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM.Deploy.0 = Release|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM64.ActiveCfg = Release|ARM64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM64.Build.0 = Release|ARM64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|ARM64.Deploy.0 = Release|ARM64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhone.ActiveCfg = Release|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhone.Build.0 = Release|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhone.Deploy.0 = Release|ARM + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhoneSimulator.ActiveCfg = Release|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhoneSimulator.Build.0 = Release|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|iPhoneSimulator.Deploy.0 = Release|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x64.ActiveCfg = Release|x64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x64.Build.0 = Release|x64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x64.Deploy.0 = Release|x64 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x86.ActiveCfg = Release|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x86.Build.0 = Release|x86 + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {E049A504-C168-41DC-80DF-0C4C6F363761} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D} {EE8FC716-27FC-405B-BD27-AF17E01A6671} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D} {CB2072E0-A437-4811-AE17-16CAE0DDA1B1} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D} + {4BD0D88F-7E7A-4C3B-9E34-BF3717A8FF4B} = {BDAAACF1-1483-412C-A14C-A7976D0FBF3D} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {14623120-794D-4BBB-8509-B49876E6AF2A} EndGlobalSection EndGlobal diff --git a/dotnet-devices/Android/AndroidSDK.cs b/dotnet-devices/Android/AndroidSDK.cs index d1ec87c..d9f7f84 100644 --- a/dotnet-devices/Android/AndroidSDK.cs +++ b/dotnet-devices/Android/AndroidSDK.cs @@ -1,6 +1,6 @@ -using System; +using Microsoft.Extensions.Logging; +using System; using System.IO; -using Microsoft.Extensions.Logging; namespace DotNetDevices.Android { @@ -24,11 +24,12 @@ namespace DotNetDevices.Android return sdkRoot; var path = Path.Combine(sdkRoot, toolPath); - if (!File.Exists(path)) + var foundPath = FindFuzzyPath(path); + if (foundPath == null) throw new FileNotFoundException($"Path to tool '{toolPath}' was not found in the SDK '{sdkRoot}'.", path); // return the full path to the tool - return path; + return foundPath; } foreach (var envvar in envvars) @@ -48,17 +49,34 @@ namespace DotNetDevices.Android return varSdkRoot; var path = Path.Combine(varSdkRoot, toolPath); - if (!File.Exists(path)) + var foundPath = FindFuzzyPath(path); + if (foundPath == null) { logger?.LogWarning($"Found SDK at '{varSdkRoot}', but it did not contan the tool '{toolPath}'."); continue; } // return the full path to the tool - return path; + return foundPath; } return null; } + + private static string? FindFuzzyPath(string path) + { + if (File.Exists(path)) + return path; + + var otherPath = Path.ChangeExtension(path, ".exe"); + if (File.Exists(otherPath)) + return otherPath; + + otherPath = Path.ChangeExtension(path, ".bat"); + if (File.Exists(otherPath)) + return otherPath; + + return null; + } } } diff --git a/dotnet-devices/Android/EmulatorManager.cs b/dotnet-devices/Android/EmulatorManager.cs index 564ae6b..0906314 100644 --- a/dotnet-devices/Android/EmulatorManager.cs +++ b/dotnet-devices/Android/EmulatorManager.cs @@ -1,109 +1,109 @@ using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; using DotNetDevices.Processes; -using Microsoft.Extensions.Logging; - -namespace DotNetDevices.Android -{ - public class EmulatorManager - { - private static readonly Regex consoleListeningRegex = new Regex(@"emulator: control console listening on port (\d+), ADB on port (\d+)"); - private static readonly Regex adbConnectedRegex = new Regex(@"emulator: onGuestSendCommand: \[(.+)\] Adb connected, start proxing data"); - private static readonly Regex alreadyBootedRegex = new Regex(@"emulator: ERROR: Running multiple emulators with the same AVD is an experimental feature\."); - - private readonly ProcessRunner processRunner; - private readonly ILogger? logger; - private readonly string emulator; - - public EmulatorManager(string? sdkRoot = null, ILogger? logger = null) - { - this.logger = logger; - processRunner = new ProcessRunner(logger); - emulator = AndroidSDK.FindPath(sdkRoot, Path.Combine("emulator", "emulator"), logger) - ?? throw new ArgumentException($"Unable to locate the Android Emulator. Make sure that ANDROID_HOME or ANDROID_SDK_ROOT is set."); - } - - public async Task BootVirtualDeviceAsync(string name, BootVirtualDeviceOptions? options = null, CancellationToken cancellationToken = default) - { - if (name == null) - throw new ArgumentNullException(nameof(name)); - - logger?.LogInformation($"Booting virtual device '{name}'..."); - - var args = $"-avd {name} -verbose"; - if (options?.NoWindow == true) - args += " -no-boot-anim -no-window"; - if (options?.NoSnapshots == true) - args += " -no-snapshot"; - if (options?.WipeData == true) - args += " -wipe-data"; - - var port = -1; - try - { - await processRunner.RunAsync(emulator, args, FindComplete, cancellationToken).ConfigureAwait(false); - } - catch (ProcessResultException ex) when (IsAlreadyLaunched(ex)) - { - // no-op - } - - return port; - - bool FindComplete(ProcessOutput output) - { - if (!output.IsError && output.Data is string o) - { - if (port <= 0) - { - // first find port - var match = consoleListeningRegex.Match(o); - if (match.Success) - port = int.Parse(match.Groups[1].Value); - } - else - { - // then wait for the boot finished - var match = adbConnectedRegex.Match(o); - if (match.Success) - return false; - } - } - - return true; - } - - bool IsAlreadyLaunched(ProcessResultException ex) - { - foreach (var output in ex.ProcessResult.GetOutput()) - { - var match = alreadyBootedRegex.Match(output); - if (match.Success) - return true; - } - - return false; - } - } - - public async Task> GetVirtualDevicesAsync(CancellationToken cancellationToken = default) - { - logger?.LogInformation("Retrieving all the virtual devices..."); - - var args = $"-list-avds"; - - var result = await processRunner.RunAsync(emulator, args, null, cancellationToken).ConfigureAwait(false); - - var avd = new List(result.OutputCount); - foreach (var output in result.GetOutput()) - { - avd.Add(new VirtualDevice(output)); - } - return avd; - } - } -} +using Microsoft.Extensions.Logging; + +namespace DotNetDevices.Android +{ + public class EmulatorManager + { + private static readonly Regex consoleListeningRegex = new Regex(@"emulator: control console listening on port (\d+), ADB on port (\d+)"); + private static readonly Regex adbConnectedRegex = new Regex(@"emulator: onGuestSendCommand: \[(.+)\] Adb connected, start proxing data"); + private static readonly Regex alreadyBootedRegex = new Regex(@"emulator: ERROR: Running multiple emulators with the same AVD is an experimental feature\."); + + private readonly ProcessRunner processRunner; + private readonly ILogger? logger; + private readonly string emulator; + + public EmulatorManager(string? sdkRoot = null, ILogger? logger = null) + { + this.logger = logger; + processRunner = new ProcessRunner(logger); + emulator = AndroidSDK.FindPath(sdkRoot, Path.Combine("emulator", "emulator"), logger) + ?? throw new ArgumentException($"Unable to locate the Android Emulator. Make sure that ANDROID_HOME or ANDROID_SDK_ROOT is set."); + } + + public async Task BootVirtualDeviceAsync(string name, BootVirtualDeviceOptions? options = null, CancellationToken cancellationToken = default) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + + logger?.LogInformation($"Booting virtual device '{name}'..."); + + var args = $"-avd {name} -verbose"; + if (options?.NoWindow == true) + args += " -no-boot-anim -no-window"; + if (options?.NoSnapshots == true) + args += " -no-snapshot"; + if (options?.WipeData == true) + args += " -wipe-data"; + + var port = -1; + try + { + await processRunner.RunAsync(emulator, args, FindComplete, cancellationToken).ConfigureAwait(false); + } + catch (ProcessResultException ex) when (IsAlreadyLaunched(ex)) + { + // no-op + } + + return port; + + bool FindComplete(ProcessOutput output) + { + if (!output.IsError && output.Data is string o) + { + if (port <= 0) + { + // first find port + var match = consoleListeningRegex.Match(o); + if (match.Success) + port = int.Parse(match.Groups[1].Value); + } + else + { + // then wait for the boot finished + var match = adbConnectedRegex.Match(o); + if (match.Success) + return false; + } + } + + return true; + } + + bool IsAlreadyLaunched(ProcessResultException ex) + { + foreach (var output in ex.ProcessResult.GetOutput()) + { + var match = alreadyBootedRegex.Match(output); + if (match.Success) + return true; + } + + return false; + } + } + + public async Task> GetVirtualDevicesAsync(CancellationToken cancellationToken = default) + { + logger?.LogInformation("Retrieving all the virtual devices..."); + + var args = $"-list-avds"; + + var result = await processRunner.RunAsync(emulator, args, null, cancellationToken).ConfigureAwait(false); + + var avd = new List(result.OutputCount); + foreach (var output in result.GetOutput()) + { + avd.Add(new VirtualDevice(output)); + } + return avd; + } + } +} diff --git a/dotnet-devices/Commands/AndroidCommand.cs b/dotnet-devices/Commands/AndroidCommand.cs index 4b4bd8b..ad80501 100644 --- a/dotnet-devices/Commands/AndroidCommand.cs +++ b/dotnet-devices/Commands/AndroidCommand.cs @@ -1,214 +1,214 @@ -using System; -using System.Collections.Generic; -using System.CommandLine; -using System.CommandLine.Invocation; -using System.CommandLine.Parsing; -using System.CommandLine.Rendering; -using System.CommandLine.Rendering.Views; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using DotNetDevices.Android; -using DotNetDevices.Apple; -using DotNetDevices.Logging; -using Microsoft.Extensions.Logging; - -namespace DotNetDevices.Commands -{ - public class AndroidCommand - { - public static Command Create() - { - return new Command("android", "Work with Android virtual devices.") - { - new Command("list", "List the virtual devices.") - { - new Option(new[] { "--sdk" }, "Whether or not to only include the available simulators."), - new Option(new[] { "--available" }, "Whether or not to only include the available simulators."), - new Option(new[] { "--booted" }, "Whether or not to only include the booted simulators."), - new Option(new[] { "--runtime" }, "The runtime to use when filtering."), - new Option(new[] { "--version" }, description: "The runtime version to use when filtering. This could be in either or . version formats.", - parseArgument: CommandLine.ParseVersion), - CommandLine.CreateVerbosity(), - new Argument("TERM", "The search term to use when filtering simulators. This could be any number of properties (UDID, runtime, version, availability, or state) as well as part of the simulator name.") - { Arity = ArgumentArity.ZeroOrOne }, - }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleListAsync))!)), - new Command("create", "Create a new virtual device.") - { - new Option(new[] { "--sdk" }, "The path to the Android SDK directory."), - new Option(new[] { "--replace" }, "Replace any existing virtual devices with the same name."), - CommandLine.CreateVerbosity(), - new Argument("NAME", "The name of the new virtual device."), - new Argument("PACKAGE", "The package to use for the new virtual device."), - }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleCreateAsync))!)), - new Command("boot", "Boot a particular simulator.") - { - new Option(new[] { "--sdk" }, "Whether or not to only include the available simulators."), - CommandLine.CreateVerbosity(), - new Argument("NAME", "The UDID of the simulator to boot."), - }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleBootAsync))!)), - }; - } - - public static async Task HandleListAsync( - string? term = null, - string? sdk = null, - bool available = false, - bool booted = false, - SimulatorRuntime? runtime = null, - string? version = null, - string? verbosity = null, - IConsole console = null!, - CancellationToken cancellationToken = default) - { - var logger = console.CreateLogger(verbosity); - var avdmanager = new AVDManager(sdk, logger); - - var devices = await avdmanager.GetDevicesAsync(); - foreach (var device in devices) - { - logger?.LogInformation(" - " + device.ToString()); - } - - var targets = await avdmanager.GetTargetsAsync(); - foreach (var target in targets) - { - logger?.LogInformation(" - " + target.ToString()); - } - - var avds = await avdmanager.GetVirtualDevicesAsync(); - foreach (var avd in avds) - { - logger?.LogInformation(" - " + avd.ToString()); - } - - try - { - await avdmanager.DeleteVirtualDeviceAsync("TESTING"); - } - catch { } - - try - { - await avdmanager.DeleteVirtualDeviceAsync("TESTED"); - } - catch { } - - await avdmanager.CreateVirtualDeviceAsync("TESTING", "system-images;android-28;google_apis_playstore;x86_64"); - - await avdmanager.CreateVirtualDeviceAsync("TESTING", "system-images;android-28;google_apis_playstore;x86_64", new VirtualDeviceCreateOptions { Overwrite = true }); - - await avdmanager.RenameVirtualDeviceAsync("TESTING", "TESTED"); - await avdmanager.MoveVirtualDeviceAsync("TESTED", "/Users/matthew/.android/avd/tested.avd"); - - //await avdmanager.DeleteVirtualDeviceAsync("TESTING"); - - //term = term?.ToLowerInvariant()?.Trim(); - - //var simctl = new SimulatorControl(logger); - //var simulators = await simctl.GetSimulatorsAsync(cancellationToken); - - //var filtered = (IEnumerable)simulators; - //if (!string.IsNullOrWhiteSpace(term)) - //{ - // if (Guid.TryParse(term, out var guid)) - // filtered = filtered.Where(s => s.Udid.ToLowerInvariant() == guid.ToString("d")); - // else if (Version.TryParse(term, out var versionFull)) - // filtered = filtered.Where(s => s.Version == versionFull); - // else if (int.TryParse(term, out var versionMjor)) - // filtered = filtered.Where(s => s.Version.Major == versionMjor); - // else if (Enum.TryParse(term, true, out var r)) - // filtered = filtered.Where(s => s.Runtime == r); - // else if (Enum.TryParse(term, true, out var state)) - // filtered = filtered.Where(s => s.State == state); - // else if (Enum.TryParse(term, true, out var availability)) - // filtered = filtered.Where(s => s.Availability == availability); - // else if (Enum.TryParse(term, true, out var type)) - // filtered = filtered.Where(s => s.Type == type); - // else - // filtered = filtered.Where(s => s.Name.ToLowerInvariant().Contains(term)); - //} - //if (booted) - // filtered = filtered.Where(s => s.State == SimulatorState.Booted); - //if (available) - // filtered = filtered.Where(s => s.Availability == SimulatorAvailability.Available); - //if (runtime != null) - // filtered = filtered.Where(s => s.Runtime == runtime); - //if (version != null) - //{ - // if (Version.TryParse(version, out var versionFull)) - // filtered = filtered.Where(s => s.Version == versionFull); - // else if (int.TryParse(version, out var versionMjor)) - // filtered = filtered.Where(s => s.Version.Major == versionMjor); - //} - - //var all = filtered.ToList(); - - //logger.LogInformation($"Found {all.Count} simulator[s]."); - - //var table = new TableView(); - //table.AddColumn(s => s.Udid, "UDID"); - //table.AddColumn(s => s.Name, "Name"); - //table.AddColumn(s => s.Runtime, "Runtime"); - //table.AddColumn(s => s.Version, "Version"); - //table.AddColumn(s => s.Availability, "Availability"); - //table.AddColumn(s => s.State, "State"); - //table.Items = all; - - //console.Append(new StackLayoutView { table }); - } - - public static async Task HandleCreateAsync( - string name, - string package, - bool replace = false, - string? sdk = null, - string? verbosity = null, - IConsole console = null!, - CancellationToken cancellationToken = default) - { - var logger = console.CreateLogger(verbosity); - - var avdmanager = new AVDManager(sdk, logger); +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.CommandLine.Invocation; +using System.CommandLine.Parsing; +using System.CommandLine.Rendering; +using System.CommandLine.Rendering.Views; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DotNetDevices.Android; +using DotNetDevices.Apple; +using DotNetDevices.Logging; +using Microsoft.Extensions.Logging; + +namespace DotNetDevices.Commands +{ + public class AndroidCommand + { + public static Command Create() + { + return new Command("android", "Work with Android virtual devices.") + { + new Command("list", "List the virtual devices.") + { + new Option(new[] { "--sdk" }, "Whether or not to only include the available simulators."), + new Option(new[] { "--available" }, "Whether or not to only include the available simulators."), + new Option(new[] { "--booted" }, "Whether or not to only include the booted simulators."), + new Option(new[] { "--runtime" }, "The runtime to use when filtering."), + new Option(new[] { "--version" }, description: "The runtime version to use when filtering. This could be in either or . version formats.", + parseArgument: CommandLine.ParseVersion), + CommandLine.CreateVerbosity(), + new Argument("TERM", "The search term to use when filtering simulators. This could be any number of properties (UDID, runtime, version, availability, or state) as well as part of the simulator name.") + { Arity = ArgumentArity.ZeroOrOne }, + }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleListAsync))!)), + new Command("create", "Create a new virtual device.") + { + new Option(new[] { "--sdk" }, "The path to the Android SDK directory."), + new Option(new[] { "--replace" }, "Replace any existing virtual devices with the same name."), + CommandLine.CreateVerbosity(), + new Argument("NAME", "The name of the new virtual device."), + new Argument("PACKAGE", "The package to use for the new virtual device."), + }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleCreateAsync))!)), + new Command("boot", "Boot a particular simulator.") + { + new Option(new[] { "--sdk" }, "Whether or not to only include the available simulators."), + CommandLine.CreateVerbosity(), + new Argument("NAME", "The UDID of the simulator to boot."), + }.WithHandler(CommandHandler.Create(typeof(AndroidCommand).GetMethod(nameof(HandleBootAsync))!)), + }; + } + + public static async Task HandleListAsync( + string? term = null, + string? sdk = null, + bool available = false, + bool booted = false, + SimulatorRuntime? runtime = null, + string? version = null, + string? verbosity = null, + IConsole console = null!, + CancellationToken cancellationToken = default) + { + var logger = console.CreateLogger(verbosity); + var avdmanager = new AVDManager(sdk, logger); + + var devices = await avdmanager.GetDevicesAsync(); + foreach (var device in devices) + { + logger?.LogInformation(" - " + device.ToString()); + } + + var targets = await avdmanager.GetTargetsAsync(); + foreach (var target in targets) + { + logger?.LogInformation(" - " + target.ToString()); + } + + var avds = await avdmanager.GetVirtualDevicesAsync(); + foreach (var avd in avds) + { + logger?.LogInformation(" - " + avd.ToString()); + } + + try + { + await avdmanager.DeleteVirtualDeviceAsync("TESTING"); + } + catch { } + + try + { + await avdmanager.DeleteVirtualDeviceAsync("TESTED"); + } + catch { } + + await avdmanager.CreateVirtualDeviceAsync("TESTING", "system-images;android-28;google_apis_playstore;x86_64"); + + await avdmanager.CreateVirtualDeviceAsync("TESTING", "system-images;android-28;google_apis_playstore;x86_64", new VirtualDeviceCreateOptions { Overwrite = true }); + + await avdmanager.RenameVirtualDeviceAsync("TESTING", "TESTED"); + await avdmanager.MoveVirtualDeviceAsync("TESTED", "/Users/matthew/.android/avd/tested.avd"); + + //await avdmanager.DeleteVirtualDeviceAsync("TESTING"); + + //term = term?.ToLowerInvariant()?.Trim(); + + //var simctl = new SimulatorControl(logger); + //var simulators = await simctl.GetSimulatorsAsync(cancellationToken); + + //var filtered = (IEnumerable)simulators; + //if (!string.IsNullOrWhiteSpace(term)) + //{ + // if (Guid.TryParse(term, out var guid)) + // filtered = filtered.Where(s => s.Udid.ToLowerInvariant() == guid.ToString("d")); + // else if (Version.TryParse(term, out var versionFull)) + // filtered = filtered.Where(s => s.Version == versionFull); + // else if (int.TryParse(term, out var versionMjor)) + // filtered = filtered.Where(s => s.Version.Major == versionMjor); + // else if (Enum.TryParse(term, true, out var r)) + // filtered = filtered.Where(s => s.Runtime == r); + // else if (Enum.TryParse(term, true, out var state)) + // filtered = filtered.Where(s => s.State == state); + // else if (Enum.TryParse(term, true, out var availability)) + // filtered = filtered.Where(s => s.Availability == availability); + // else if (Enum.TryParse(term, true, out var type)) + // filtered = filtered.Where(s => s.Type == type); + // else + // filtered = filtered.Where(s => s.Name.ToLowerInvariant().Contains(term)); + //} + //if (booted) + // filtered = filtered.Where(s => s.State == SimulatorState.Booted); + //if (available) + // filtered = filtered.Where(s => s.Availability == SimulatorAvailability.Available); + //if (runtime != null) + // filtered = filtered.Where(s => s.Runtime == runtime); + //if (version != null) + //{ + // if (Version.TryParse(version, out var versionFull)) + // filtered = filtered.Where(s => s.Version == versionFull); + // else if (int.TryParse(version, out var versionMjor)) + // filtered = filtered.Where(s => s.Version.Major == versionMjor); + //} + + //var all = filtered.ToList(); + + //logger.LogInformation($"Found {all.Count} simulator[s]."); + + //var table = new TableView(); + //table.AddColumn(s => s.Udid, "UDID"); + //table.AddColumn(s => s.Name, "Name"); + //table.AddColumn(s => s.Runtime, "Runtime"); + //table.AddColumn(s => s.Version, "Version"); + //table.AddColumn(s => s.Availability, "Availability"); + //table.AddColumn(s => s.State, "State"); + //table.Items = all; + + //console.Append(new StackLayoutView { table }); + } + + public static async Task HandleCreateAsync( + string name, + string package, + bool replace = false, + string? sdk = null, + string? verbosity = null, + IConsole console = null!, + CancellationToken cancellationToken = default) + { + var logger = console.CreateLogger(verbosity); + + var avdmanager = new AVDManager(sdk, logger); var options = new VirtualDeviceCreateOptions { Overwrite = replace }; - await avdmanager.CreateVirtualDeviceAsync(name, package, options, cancellationToken); - } - - public static async Task HandleBootAsync( - string name, - string? sdk = null, - string? verbosity = null, - IConsole console = null!, - CancellationToken cancellationToken = default) - { - var logger = console.CreateLogger(verbosity); - - var emulator = new EmulatorManager(sdk, logger); - - var avds = await emulator.GetVirtualDevicesAsync(cancellationToken); - if (avds.All(a => !a.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) - { - logger.LogError($"No virtual device with name {name} was found."); - return 1; - } - - var options = new BootVirtualDeviceOptions + await avdmanager.CreateVirtualDeviceAsync(name, package, options, cancellationToken); + } + + public static async Task HandleBootAsync( + string name, + string? sdk = null, + string? verbosity = null, + IConsole console = null!, + CancellationToken cancellationToken = default) + { + var logger = console.CreateLogger(verbosity); + + var emulator = new EmulatorManager(sdk, logger); + + var avds = await emulator.GetVirtualDevicesAsync(cancellationToken); + if (avds.All(a => !a.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) { - NoSnapshots = false, - WipeData = true, + logger.LogError($"No virtual device with name {name} was found."); + return 1; + } + + var options = new BootVirtualDeviceOptions + { + NoSnapshots = false, + WipeData = true, }; - var port = await emulator.BootVirtualDeviceAsync(name, options, cancellationToken); - if (port == -1) - logger.LogInformation($"Virtual device was already booted."); - else - logger.LogInformation($"device was booted to port {port}."); - - return 0; - } - } -} + var port = await emulator.BootVirtualDeviceAsync(name, options, cancellationToken); + if (port == -1) + logger.LogInformation($"Virtual device was already booted."); + else + logger.LogInformation($"device was booted to port {port}."); + + return 0; + } + } +} diff --git a/dotnet-devices/Commands/AppleTestCommand.cs b/dotnet-devices/Commands/AppleTestCommand.cs index 600832b..f018a80 100644 --- a/dotnet-devices/Commands/AppleTestCommand.cs +++ b/dotnet-devices/Commands/AppleTestCommand.cs @@ -1,231 +1,231 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using DotNetDevices.Apple; -using DotNetDevices.Testing; -using Microsoft.Extensions.Logging; - -namespace DotNetDevices.Commands -{ - public class AppleTestCommand - { - private readonly ILogger logger; - private readonly SimulatorControl simctl; - - public AppleTestCommand(ILogger logger) - { - this.logger = logger; - - simctl = new SimulatorControl(logger); - } - - public async Task RunTestsAsync( - string app, - string? deviceResults = null, // "TestResults.trx" - string? outputResults = null, // "TestResults.trx" - string? runtimeString = null, - string? versionString = null, - bool latest = false, - string? deviceType = null, - string? deviceName = null, - bool reset = false, - bool shutdown = false, - CancellationToken cancellationToken = default) - { - // validate app / bundle - var plist = new PList(Path.Combine(app, "Info.plist"), logger); - var bundleId = await plist.GetBundleIdentifierAsync(cancellationToken); - - // validate requested OS - var simulatorType = ParseSimulatorType(deviceType); - var runtime = ParseSimulatorRuntime(runtimeString); - var runtimeVersion = await ParseVersionAsync(versionString, runtime, cancellationToken); - - logger.LogInformation($"Looking for an available {simulatorType} ({runtimeVersion}) simulator..."); - var available = await GetAvailableSimulatorsAsync(simulatorType, runtime, runtimeVersion, latest, cancellationToken); - - // first look for a booted device - var simulator = available.FirstOrDefault(s => s.State == SimulatorState.Booted) ?? available.FirstOrDefault(); - logger.LogInformation($"Using simulator {simulator.Name} ({simulator.Runtime} {simulator.Version}): {simulator.Udid}"); - - try - { - if (reset) - await simctl.EraseSimulatorAsync(simulator.Udid, true, cancellationToken); - - await simctl.InstallAppAsync(simulator.Udid, app, true, cancellationToken); - - try - { - var parser = new TestResultsParser(); - - var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - - var launched = await simctl.LaunchAppAsync(simulator.Udid, bundleId, new LaunchAppOptions - { - CaptureOutput = true, - BootSimulator = true, - HandleOutput = output => - { - parser.ParseTestOutput( - output, - line => logger?.LogWarning(line), - async () => - { - try - { - // wait a few seconds before terminating - await Task.Delay(1000, cts.Token); - - await simctl.TerminateAppAsync(simulator.Udid, bundleId, cts.Token); - } - catch (OperationCanceledException) - { - // we expected this - } - }); - }, - }, cancellationToken); - - cts.Cancel(); - - if (deviceResults != null) - { - var dest = outputResults ?? Path.GetFileName(deviceResults); - - logger.LogInformation($"Copying test results from simulator to {dest}..."); - - var dataPath = await simctl.GetDataDirectoryAsync(simulator.Udid, bundleId, cancellationToken); - var results = Path.Combine(dataPath, "Documents", deviceResults); - if (File.Exists(results)) - File.Copy(results, dest, true); - else - logger.LogInformation($"No test results found."); - } - else - { - logger.LogInformation($"Unable to determine the test results file."); - } - } - finally - { - await simctl.UninstallAppAsync(simulator.Udid, bundleId, false, cancellationToken); - } - } - finally - { - if (shutdown) - await simctl.ShutdownSimulatorAsync(simulator.Udid, cancellationToken); - } - } - - private async Task> GetAvailableSimulatorsAsync(SimulatorType type, SimulatorRuntime runtime, Version version, bool useLatest = true, CancellationToken cancellationToken = default) - { - // load all simulators - var simulators = await simctl.GetSimulatorsAsync(cancellationToken); - - // find ones that can be used - var available = simulators - .Where(s => s.Availability == SimulatorAvailability.Available) - .Where(s => s.Runtime == runtime) - .Where(s => s.Type == type); - logger.LogDebug($"Found some available simulators:"); - foreach (var sim in available) - { - logger.LogDebug($" {sim.Name} ({sim.Runtime} {sim.Version}): {sim.Udid}"); - } - - // filter by version info - string matchingPattern; - if (useLatest) - { - var min = version; - var max = new Version(min.Major + 1, 0); - available = available.Where(s => s.Version >= min && s.Version < max); - matchingPattern = $"[{min}, {max})"; - } - else - { - available = available.Where(s => s.Version == version); - matchingPattern = $"[{version}]"; - } - - var matching = available.ToList(); - if (matching.Count > 0) - { - logger.LogDebug($"Found matching simulators {matchingPattern}:"); - foreach (var sim in matching) - { - logger.LogDebug($" {sim.Name} ({sim.Runtime} {sim.Version}): {sim.Udid}"); - } - } - else - { - throw new Exception($"Unable to find any simulators that match version {matchingPattern}."); - } - - return matching; - } - - private async Task ParseVersionAsync(string? version, SimulatorRuntime os, CancellationToken cancellationToken = default) - { - var osVersion = version?.ToLowerInvariant().Trim(); - if (!Version.TryParse(osVersion, out var numberVersion)) - { - if (int.TryParse(osVersion, out var v)) - numberVersion = new Version(v, 0); - else if (string.IsNullOrEmpty(osVersion) || osVersion == "default") - numberVersion = await simctl.GetDefaultVersionAsync(os, cancellationToken); - else - throw new Exception($"Unable to determine the version for {osVersion}."); - } - - return numberVersion; - } - - private static SimulatorRuntime ParseSimulatorRuntime(string? runtime) +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DotNetDevices.Apple; +using DotNetDevices.Testing; +using Microsoft.Extensions.Logging; + +namespace DotNetDevices.Commands +{ + public class AppleTestCommand + { + private readonly ILogger logger; + private readonly SimulatorControl simctl; + + public AppleTestCommand(ILogger logger) { - var osName = runtime?.ToLowerInvariant()?.Trim(); - var os = osName switch - { - null => SimulatorRuntime.iOS, - "" => SimulatorRuntime.iOS, - "ios" => SimulatorRuntime.iOS, - "watchos" => SimulatorRuntime.watchOS, - "tvos" => SimulatorRuntime.tvOS, - _ => throw new Exception($"Unable to determine the OS for {runtime}.") - }; - return os; - } - - private static SimulatorType ParseSimulatorType(string? deviceType) - { - var deviceTypeName = deviceType?.ToLowerInvariant()?.Trim(); - var device = deviceTypeName switch - { - // iPhone - null => SimulatorType.iPhone, - "" => SimulatorType.iPhone, - "iphone" => SimulatorType.iPhone, - "phone" => SimulatorType.iPhone, - // iPad - "ipad" => SimulatorType.iPad, - "tablet" => SimulatorType.iPad, - // iPod - "ipod" => SimulatorType.iPod, - // Apple TV - "tv" => SimulatorType.AppleTV, - "appletv" => SimulatorType.AppleTV, - // Apple Watch - "watch" => SimulatorType.AppleWatch, - "applewatch" => SimulatorType.AppleWatch, - // - _ => throw new Exception($"Unable to determine the simulator type for {deviceType}.") - }; - return device; - } - } -} + this.logger = logger; + + simctl = new SimulatorControl(logger); + } + + public async Task RunTestsAsync( + string app, + string? deviceResults = null, // "TestResults.trx" + string? outputResults = null, // "TestResults.trx" + string? runtimeString = null, + string? versionString = null, + bool latest = false, + string? deviceType = null, + string? deviceName = null, + bool reset = false, + bool shutdown = false, + CancellationToken cancellationToken = default) + { + // validate app / bundle + var plist = new PList(Path.Combine(app, "Info.plist"), logger); + var bundleId = await plist.GetBundleIdentifierAsync(cancellationToken); + + // validate requested OS + var simulatorType = ParseSimulatorType(deviceType); + var runtime = ParseSimulatorRuntime(runtimeString); + var runtimeVersion = await ParseVersionAsync(versionString, runtime, cancellationToken); + + logger.LogInformation($"Looking for an available {simulatorType} ({runtimeVersion}) simulator..."); + var available = await GetAvailableSimulatorsAsync(simulatorType, runtime, runtimeVersion, latest, cancellationToken); + + // first look for a booted device + var simulator = available.FirstOrDefault(s => s.State == SimulatorState.Booted) ?? available.FirstOrDefault(); + logger.LogInformation($"Using simulator {simulator.Name} ({simulator.Runtime} {simulator.Version}): {simulator.Udid}"); + + try + { + if (reset) + await simctl.EraseSimulatorAsync(simulator.Udid, true, cancellationToken); + + await simctl.InstallAppAsync(simulator.Udid, app, true, cancellationToken); + + try + { + var parser = new TestResultsParser(); + + var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + + var launched = await simctl.LaunchAppAsync(simulator.Udid, bundleId, new LaunchAppOptions + { + CaptureOutput = true, + BootSimulator = true, + HandleOutput = output => + { + parser.ParseTestOutput( + output, + line => logger?.LogWarning(line), + async () => + { + try + { + // wait a few seconds before terminating + await Task.Delay(1000, cts.Token); + + await simctl.TerminateAppAsync(simulator.Udid, bundleId, cts.Token); + } + catch (OperationCanceledException) + { + // we expected this + } + }); + }, + }, cancellationToken); + + cts.Cancel(); + + if (deviceResults != null) + { + var dest = outputResults ?? Path.GetFileName(deviceResults); + + logger.LogInformation($"Copying test results from simulator to {dest}..."); + + var dataPath = await simctl.GetDataDirectoryAsync(simulator.Udid, bundleId, cancellationToken); + var results = Path.Combine(dataPath, "Documents", deviceResults); + if (File.Exists(results)) + File.Copy(results, dest, true); + else + logger.LogInformation($"No test results found."); + } + else + { + logger.LogInformation($"Unable to determine the test results file."); + } + } + finally + { + await simctl.UninstallAppAsync(simulator.Udid, bundleId, false, cancellationToken); + } + } + finally + { + if (shutdown) + await simctl.ShutdownSimulatorAsync(simulator.Udid, cancellationToken); + } + } + + private async Task> GetAvailableSimulatorsAsync(SimulatorType type, SimulatorRuntime runtime, Version version, bool useLatest = true, CancellationToken cancellationToken = default) + { + // load all simulators + var simulators = await simctl.GetSimulatorsAsync(cancellationToken); + + // find ones that can be used + var available = simulators + .Where(s => s.Availability == SimulatorAvailability.Available) + .Where(s => s.Runtime == runtime) + .Where(s => s.Type == type); + logger.LogDebug($"Found some available simulators:"); + foreach (var sim in available) + { + logger.LogDebug($" {sim.Name} ({sim.Runtime} {sim.Version}): {sim.Udid}"); + } + + // filter by version info + string matchingPattern; + if (useLatest) + { + var min = version; + var max = new Version(min.Major + 1, 0); + available = available.Where(s => s.Version >= min && s.Version < max); + matchingPattern = $"[{min}, {max})"; + } + else + { + available = available.Where(s => s.Version == version); + matchingPattern = $"[{version}]"; + } + + var matching = available.ToList(); + if (matching.Count > 0) + { + logger.LogDebug($"Found matching simulators {matchingPattern}:"); + foreach (var sim in matching) + { + logger.LogDebug($" {sim.Name} ({sim.Runtime} {sim.Version}): {sim.Udid}"); + } + } + else + { + throw new Exception($"Unable to find any simulators that match version {matchingPattern}."); + } + + return matching; + } + + private async Task ParseVersionAsync(string? version, SimulatorRuntime os, CancellationToken cancellationToken = default) + { + var osVersion = version?.ToLowerInvariant().Trim(); + if (!Version.TryParse(osVersion, out var numberVersion)) + { + if (int.TryParse(osVersion, out var v)) + numberVersion = new Version(v, 0); + else if (string.IsNullOrEmpty(osVersion) || osVersion == "default") + numberVersion = await simctl.GetDefaultVersionAsync(os, cancellationToken); + else + throw new Exception($"Unable to determine the version for {osVersion}."); + } + + return numberVersion; + } + + private static SimulatorRuntime ParseSimulatorRuntime(string? runtime) + { + var osName = runtime?.ToLowerInvariant()?.Trim(); + var os = osName switch + { + null => SimulatorRuntime.iOS, + "" => SimulatorRuntime.iOS, + "ios" => SimulatorRuntime.iOS, + "watchos" => SimulatorRuntime.watchOS, + "tvos" => SimulatorRuntime.tvOS, + _ => throw new Exception($"Unable to determine the OS for {runtime}.") + }; + return os; + } + + private static SimulatorType ParseSimulatorType(string? deviceType) + { + var deviceTypeName = deviceType?.ToLowerInvariant()?.Trim(); + var device = deviceTypeName switch + { + // iPhone + null => SimulatorType.iPhone, + "" => SimulatorType.iPhone, + "iphone" => SimulatorType.iPhone, + "phone" => SimulatorType.iPhone, + // iPad + "ipad" => SimulatorType.iPad, + "tablet" => SimulatorType.iPad, + // iPod + "ipod" => SimulatorType.iPod, + // Apple TV + "tv" => SimulatorType.AppleTV, + "appletv" => SimulatorType.AppleTV, + // Apple Watch + "watch" => SimulatorType.AppleWatch, + "applewatch" => SimulatorType.AppleWatch, + // + _ => throw new Exception($"Unable to determine the simulator type for {deviceType}.") + }; + return device; + } + } +}