diff --git a/Make.config b/Make.config index 0e7edc1cca26..79ec8941f5ad 100644 --- a/Make.config +++ b/Make.config @@ -278,10 +278,10 @@ DOTNET_MIN_MACCATALYST_SDK_VERSION=15.0 DOTNET_MIN_MACOS_SDK_VERSION=12.0 # The min simulator version available in the Xcode we're using -MIN_IOS_SIMULATOR_VERSION=15.0 -MIN_TVOS_SIMULATOR_VERSION=15.0 +MIN_IOS_SIMULATOR_VERSION=16.0 +MIN_TVOS_SIMULATOR_VERSION=16.0 # These are the simulator package ids for the versions above -EXTRA_SIMULATORS=com.apple.pkg.iPhoneSimulatorSDK15_0 com.apple.pkg.AppleTVSimulatorSDK15_0 +EXTRA_SIMULATORS=iOS:MIN_IOS_SIMULATOR_VERSION tvOS:MIN_TVOS_SIMULATOR_VERSION INCLUDE_IOS=1 INCLUDE_MAC=1 diff --git a/src/StoreKit/Enums.cs b/src/StoreKit/Enums.cs index 1b9f9aded092..4e82dd9fedfc 100644 --- a/src/StoreKit/Enums.cs +++ b/src/StoreKit/Enums.cs @@ -153,7 +153,7 @@ public enum SKOverlayPosition : long { Raised = 1, } - [NoMac, iOS (16, 0), MacCatalyst (16, 0), NoTV] + [NoMac, iOS (16, 1), MacCatalyst (16, 1), NoTV] public enum SKAdNetworkCoarseConversionValue { [Field ("SKAdNetworkCoarseConversionValueHigh")] High, diff --git a/src/storekit.cs b/src/storekit.cs index 1f273c0191f4..d40f1b66cc86 100644 --- a/src/storekit.cs +++ b/src/storekit.cs @@ -817,7 +817,7 @@ interface SKStoreProductParameterKey { [Field ("SKStoreProductParameterAdNetworkCampaignIdentifier")] NSString AdNetworkCampaignIdentifier { get; } - [NoMac, iOS (16, 0), MacCatalyst (16, 0), TV (17, 0)] + [NoMac, iOS (16, 1), MacCatalyst (16, 1), TV (16, 1)] [Field ("SKStoreProductParameterAdNetworkSourceIdentifier")] NSString AdNetworkSourceIdentifier { get; } @@ -1488,7 +1488,7 @@ interface SKAdImpression { [Export ("adCampaignIdentifier", ArgumentSemantic.Strong)] NSNumber AdCampaignIdentifier { get; set; } - [NoMac, iOS (16, 0), MacCatalyst (16, 0), NoTV] + [NoMac, iOS (16, 1), MacCatalyst (16, 1), NoTV] [Export ("sourceIdentifier", ArgumentSemantic.Strong)] NSNumber SourceIdentifier { get; set; } diff --git a/system-dependencies.sh b/system-dependencies.sh index 5c48d3cc66be..1f29f05a2bf0 100755 --- a/system-dependencies.sh +++ b/system-dependencies.sh @@ -174,6 +174,10 @@ while ! test -z $1; do IGNORE_SIMULATORS=1 shift ;; + --ignore-old-simulators) + IGNORE_OLD_SIMULATORS=1 + shift + ;; --enforce-simulators) unset IGNORE_SIMULATORS unset OPTIONAL_SIMULATORS @@ -901,14 +905,12 @@ function check_old_simulators () local EXTRA_SIMULATORS local XCODE + local XCODE_DEVELOPER_ROOT - EXTRA_SIMULATORS=$(grep ^EXTRA_SIMULATORS= Make.config | sed 's/.*=//') - XCODE=$(dirname "$(dirname "$(grep ^XCODE_DEVELOPER_ROOT= Make.config | sed 's/.*=//')")") + XCODE_DEVELOPER_ROOT=$(grep XCODE$1_DEVELOPER_ROOT= Make.config | sed 's/.*=//') - if ! make -C tools/siminstaller >/dev/null; then - warn "Can't check if simulators are available, because siminstaller failed to build." - return - fi + IFS=' ' read -r -a EXTRA_SIMULATORS <<< "$(grep ^EXTRA_SIMULATORS= Make.config | sed 's/.*=//')" + XCODE=$(dirname "$(dirname "$XCODE_DEVELOPER_ROOT")") if ! test -d "$XCODE"; then # can't test unless Xcode is present @@ -916,38 +918,39 @@ function check_old_simulators () return fi - IFS=', ' read -r -a SIMS <<< "$EXTRA_SIMULATORS" - arraylength=${#SIMS[@]} - INSTALL_SIMULATORS= - for (( i=1; i/dev/null); then - local action=warn - if test -z $OPTIONAL_OLD_SIMULATORS; then - action=fail - fi - if [[ "$FAILED_SIMULATORS" =~ "Unknown simulators:" ]]; then - $action "${FAILED_SIMULATORS}" - $action " If you just updated the Xcode version, it's possible Apple stopped shipping these simulators with the new version of Xcode." - $action " If that's the case, you can list the available simulators with ${COLOR_MAGENTA}make -C tools/siminstaller print-simulators --xcode $XCODE${COLOR_RESET}," - $action " and then update the ${COLOR_MAGENTA}MIN__SIMULATOR_VERSION${COLOR_RESET} and ${COLOR_MAGENTA}EXTRA_SIMULATORS${COLOR_RESET} variables in Make.config to the earliest available simulators." - $action " Another possibility is that Apple is not shipping any simulators (yet?) for the new version of Xcode (if the previous list shows no simulators)." + local action=warn + if test -z $OPTIONAL_OLD_SIMULATORS; then + action=fail + fi + + local os + local versionName + local version + + for spec in "${EXTRA_SIMULATORS[@]}"; do + os=${spec/:*/} + versionName=${spec/*:/} + version=$(grep "^${versionName}=" Make.config | sed 's/.*=//') + + OS_TMP_FILE=$SD_TMP_DIR/$os-$version.json + jq ".runtimes[] | select(.platform == \"$os\" and .version == \"$version\" and .isAvailable == true and .isInternal == false) | [ { \"version\":.version, \"name\":.name, \"identifier\":.identifier } ]" < "$TMP_FILE" > "$OS_TMP_FILE" + #echo $OS_TMP_FILE + LENGTH=$(jq length < "$OS_TMP_FILE") + if [[ "$LENGTH" != "" && "$LENGTH" -gt 0 ]]; then + ok "Found the $os $version simulator." + elif test -z "$PROVISION_OLD_SIMULATORS"; then + $action "The $os $version simulator is not installed. Execute ${COLOR_MAGENTA}xcodebuild -downloadPlatform $os -buildVersion $version${COLOR_RESET} to install." else - if ! test -z $PROVISION_OLD_SIMULATORS; then - if ! make -C tools/siminstaller install-simulators INSTALL_SIMULATORS="$INSTALL_SIMULATORS"; then - $action "Failed to install extra simulators." - else - ok "Extra simulators installed successfully: '${FAILED_SIMULATORS//$'\n'/', '}'" - fi - else - $action "The simulators '${FAILED_SIMULATORS//$'\n'/', '}' are not installed or need to be upgraded." - fi + warn "The $os $version simulator is not installed. Now executing ${COLOR_BLUE}"$XCODE_DEVELOPER_ROOT/usr/bin/xcodebuild" -downloadPlatform $os -buildVersion $version${COLOR_RESET} to install..." + "$XCODE_DEVELOPER_ROOT/usr/bin/xcodebuild" -downloadPlatform "$os" -buildVersion "$version" + warn "Successfully executed ${COLOR_BLUE}"$XCODE_DEVELOPER_ROOT/usr/bin/xcodebuild" -downloadPlatform $os -buildVersion $version${COLOR_RESET}." fi - else - ok "Found all extra simulators: ${EXTRA_SIMULATORS// /, }" - fi + done } echo "Checking system..." diff --git a/tests/introspection/ApiCtorInitTest.cs b/tests/introspection/ApiCtorInitTest.cs index 33176dc530ea..680adc465150 100644 --- a/tests/introspection/ApiCtorInitTest.cs +++ b/tests/introspection/ApiCtorInitTest.cs @@ -153,6 +153,28 @@ protected virtual bool Skip (Type type) return true; case "ASAccountAuthenticationModificationController": return true; // started failing in Xcode 16.3 beta 1 for unknown reasons (it works in an Xcode project). +#if __TVOS__ + case "MTLAccelerationStructureDescriptor": + case "MTLAccelerationStructureGeometryDescriptor": + case "MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor": + case "MTLAccelerationStructureMotionTriangleGeometryDescriptor": + case "MTLAccelerationStructurePassDescriptor": + case "MTLAccelerationStructurePassSampleBufferAttachmentDescriptor": + case "MTLAccelerationStructurePassSampleBufferAttachmentDescriptorArray": + case "MTLAccelerationStructureTriangleGeometryDescriptor": + case "MTLMeshRenderPipelineDescriptor": + case "MTLMotionKeyframeData": + case "MTLRasterizationRateLayerArray": + case "MTLRasterizationRateMapDescriptor": + case "MTLRasterizationRateSampleArray": + case "MTLRenderPipelineFunctionsDescriptor": + case "MTLResourceStatePassSampleBufferAttachmentDescriptor": + case "MTLResourceStatePassSampleBufferAttachmentDescriptorArray": + // The initial tvOS 16.0 simulator doesn't have these classes, but the tvOS 16.1 simulator doess + if (TestRuntime.IsSimulator && !TestRuntime.CheckXcodeVersion (14, 1)) + return true; + break; +#endif } switch (type.Namespace) { diff --git a/tests/introspection/ApiFieldTest.cs b/tests/introspection/ApiFieldTest.cs index c20ffda42add..e85e6c442531 100644 --- a/tests/introspection/ApiFieldTest.cs +++ b/tests/introspection/ApiFieldTest.cs @@ -76,6 +76,14 @@ protected virtual bool Skip (PropertyInfo property) default: return false; } + case "CMSampleAttachmentKey": // kCMSampleAttachmentKey_HDR10PlusPerFrameData": + switch (property.Name) { + case "Hdr10PlusPerFrameDataKey": + if (TestRuntime.IsSimulator) + return !TestRuntime.CheckXcodeVersion (14, 1); // not available in the iOS 16.0 simulator, but it is in the iOS 16.1 simulator + break; + } + break; } return SkipDueToAttribute (property); } diff --git a/tests/introspection/ApiProtocolTest.cs b/tests/introspection/ApiProtocolTest.cs index df21861b1697..098e811c9d95 100644 --- a/tests/introspection/ApiProtocolTest.cs +++ b/tests/introspection/ApiProtocolTest.cs @@ -45,6 +45,10 @@ protected virtual bool Skip (Type type) if (TestRuntime.IsSimulatorOrDesktop) return true; break; + case "SafetyKit": + if (TestRuntime.IsSimulator) + return !TestRuntime.CheckXcodeVersion (15, 0); // doesn't seem to be available in the iOS simulator until iOS 17+ + break; } switch (type.Name) { @@ -73,6 +77,36 @@ protected virtual bool Skip (Type type) case "GKHybridStrategist": // We removed the bindings for this type. return true; +#endif +#if __TVOS__ + case "MTLAccelerationStructureBoundingBoxGeometryDescriptor": + case "MTLAccelerationStructureDescriptor": + case "MTLAccelerationStructureGeometryDescriptor": + case "MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor": + case "MTLAccelerationStructureMotionTriangleGeometryDescriptor": + case "MTLAccelerationStructurePassDescriptor": + case "MTLAccelerationStructurePassSampleBufferAttachmentDescriptor": + case "MTLAccelerationStructurePassSampleBufferAttachmentDescriptorArray": + case "MTLAccelerationStructureTriangleGeometryDescriptor": + case "MTLInstanceAccelerationStructureDescriptor": + case "MTLIntersectionFunctionDescriptor": + case "MTLIntersectionFunctionTableDescriptor": + case "MTLMeshRenderPipelineDescriptor": + case "MTLMotionKeyframeData": + case "MTLPrimitiveAccelerationStructureDescriptor": + case "MTLRasterizationRateLayerArray": + case "MTLRasterizationRateLayerDescriptor": + case "MTLRasterizationRateMapDescriptor": + case "MTLRasterizationRateSampleArray": + case "MTLRenderPipelineFunctionsDescriptor": + case "MTLResourceStatePassDescriptor": + case "MTLResourceStatePassSampleBufferAttachmentDescriptor": + case "MTLResourceStatePassSampleBufferAttachmentDescriptorArray": + case "MTLVisibleFunctionTableDescriptor": + // The initial tvOS 16.0 simulator doesn't have these classes, but the tvOS 16.1 simulator doess + if (TestRuntime.IsSimulator && !TestRuntime.CheckXcodeVersion (14, 1)) + return true; + goto default; #endif default: return SkipDueToAttribute (type); diff --git a/tests/introspection/ApiSelectorTest.cs b/tests/introspection/ApiSelectorTest.cs index ae69391e6950..fb5c5494c452 100644 --- a/tests/introspection/ApiSelectorTest.cs +++ b/tests/introspection/ApiSelectorTest.cs @@ -51,6 +51,13 @@ protected virtual bool Skip (Type type) return true; } + switch (type.Namespace) { + case "SafetyKit": + if (TestRuntime.IsSimulator) + return !TestRuntime.CheckXcodeVersion (15, 0); // doesn't seem to be available in the iOS simulator until iOS 17+ + break; + } + switch (type.FullName) { case "MetalPerformanceShaders.MPSCommandBuffer": // The reflectable type metadata contains no selectors. @@ -663,12 +670,20 @@ protected virtual bool Skip (Type type, string selectorName) case "functionCount": case "setFunctionCount:": return true; +#if __TVOS__ + case "intersectionFunctionTableDescriptor": + return !TestRuntime.CheckXcodeVersion (14, 1); +#endif } break; case "MTLResourceStatePassDescriptor": switch (selectorName) { case "sampleBufferAttachments": return true; +#if __TVOS__ + case "resourceStatePassDescriptor": + return !TestRuntime.CheckXcodeVersion (14, 1); +#endif } break; case "MTLResourceStatePassSampleBufferAttachmentDescriptor": @@ -687,8 +702,44 @@ protected virtual bool Skip (Type type, string selectorName) case "functionCount": case "setFunctionCount:": return true; +#if __TVOS__ + case "visibleFunctionTableDescriptor": + return !TestRuntime.CheckXcodeVersion (14, 1); +#endif + } + break; +#if __TVOS__ + case "MTLRenderPipelineReflection": + switch (selectorName) { + case "meshBindings": + case "objectBindings": + return !TestRuntime.CheckXcodeVersion (14, 1); + } + break; + case "MTLAccelerationStructureBoundingBoxGeometryDescriptor": + case "MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor": + case "MTLAccelerationStructureMotionTriangleGeometryDescriptor": + case "MTLAccelerationStructureTriangleGeometryDescriptor": + case "MTLInstanceAccelerationStructureDescriptor": + case "MTLPrimitiveAccelerationStructureDescriptor": + switch (selectorName) { + case "descriptor": + return !TestRuntime.CheckXcodeVersion (14, 1); + } + break; + case "MTLAccelerationStructurePassDescriptor": + switch (selectorName) { + case "accelerationStructurePassDescriptor": + return !TestRuntime.CheckXcodeVersion (14, 1); } break; + case "MTLMotionKeyframeData": + switch (selectorName) { + case "data": + return !TestRuntime.CheckXcodeVersion (14, 1); + } + break; +#endif case "AVPlayerLooper": // This API got introduced in Xcode 8.0 binding but is not currently present nor in Xcode 8.3 or Xcode 9.0 needs research switch (selectorName) { case "isLoopingEnabled": @@ -1068,6 +1119,12 @@ protected virtual bool Skip (Type type, string selectorName) } break; #endif + case "CMWaterSubmersionManager": + switch (selectorName) { + case "maximumDepth": + return !TestRuntime.CheckXcodeVersion (15, 0); // it's not in iOS 16, but maybe iOS 17? + } + break; } // old binding mistake diff --git a/tests/introspection/iOSApiFieldTest.cs b/tests/introspection/iOSApiFieldTest.cs index eadc207576ad..e9487979aa4f 100644 --- a/tests/introspection/iOSApiFieldTest.cs +++ b/tests/introspection/iOSApiFieldTest.cs @@ -172,6 +172,10 @@ protected override bool Skip (string constantName, string libraryName) // Xcode 12.2 Beta 1 does not ship this but it is available in Xcode 12.0... case "HKMetadataKeyBarometricPressure": return true; + case "kCMSampleAttachmentKey_HDR10PlusPerFrameData": + if (TestRuntime.IsSimulator) + return !TestRuntime.CheckXcodeVersion (14, 1); // not available in the iOS 16.0 simulator, but it is in the iOS 16.1 simulator + goto default; default: return false; } diff --git a/tests/test-dependencies.sh b/tests/test-dependencies.sh index 844befe448df..cd45663575e4 100755 --- a/tests/test-dependencies.sh +++ b/tests/test-dependencies.sh @@ -1,4 +1,4 @@ #!/bin/bash -ex cd "$(dirname "$0")" -./system-dependencies.sh --provision-mono --ignore-xamarin-studio --ignore-xcode --ignore-osx --ignore-dotnet --ignore-shellcheck --ignore-yamllint +./system-dependencies.sh --provision-mono --ignore-xamarin-studio --ignore-xcode --ignore-osx --ignore-dotnet --ignore-shellcheck --ignore-yamllint --ignore-old-simulators diff --git a/tools/Makefile b/tools/Makefile index 223e358b08bf..16687fc8fa91 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -22,6 +22,6 @@ ifdef INCLUDE_MTOUCH SUBDIRS += mtouch endif -SUBDIRS+=mlaunch siminstaller +SUBDIRS+=mlaunch SUBDIRS += dotnet-linker diff --git a/tools/autoformat.sh b/tools/autoformat.sh index b2e6dd5aa20b..9b785edccd9c 100755 --- a/tools/autoformat.sh +++ b/tools/autoformat.sh @@ -48,7 +48,6 @@ dotnet format whitespace "$SRC_DIR/tools/dotnet-linker/dotnet-linker.csproj" dotnet format whitespace "$SRC_DIR/tools/mmp/mmp.csproj" dotnet format whitespace "$SRC_DIR/tools/mtouch/mtouch.csproj" dotnet format whitespace "$SRC_DIR/tests/xharness/xharness.sln" -dotnet format whitespace "$SRC_DIR/tools/siminstaller/siminstaller.csproj" dotnet format whitespace "$SRC_DIR/tests/introspection/dotnet/iOS/introspection.csproj" dotnet format whitespace "$SRC_DIR/tests/introspection/dotnet/MacCatalyst/introspection.csproj" dotnet format whitespace "$SRC_DIR/tests/introspection/dotnet/macOS/introspection.csproj" diff --git a/tools/common/SdkVersions.cs b/tools/common/SdkVersions.cs index 357757a33c2f..4e4155fe0a61 100644 --- a/tools/common/SdkVersions.cs +++ b/tools/common/SdkVersions.cs @@ -29,8 +29,8 @@ static class SdkVersions { public const string DotNetMinTVOS = "12.2"; public const string DotNetMinMacCatalyst = "15.0"; - public const string MiniOSSimulator = "15.0"; - public const string MinTVOSSimulator = "15.0"; + public const string MiniOSSimulator = "16.0"; + public const string MinTVOSSimulator = "16.0"; public const string MaxiOSSimulator = "18.4"; public const string MaxTVOSSimulator = "18.4"; diff --git a/tools/siminstaller/Makefile b/tools/siminstaller/Makefile deleted file mode 100644 index fba14035a60c..000000000000 --- a/tools/siminstaller/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -TOP=../.. -include $(TOP)/Make.config - -EXECUTABLE=bin/Debug/siminstaller.dll - -all-local:: $(EXECUTABLE) - -install-local:: all-local - -# we build using the system .NET, because we might execute before we've downloaded our own version of .NET (i.e. while provisioning dependencies) -$(EXECUTABLE): $(wildcard *.cs) $(wildcard *.csproj) Makefile - $(Q_BUILD) cd $(HOME) && dotnet build $(abspath $(CURDIR))/*.csproj "/bl:$(abspath $@.binlog)" /p:UseSharedCompilation=false $(DOTNET_BUILD_VERBOSITY) - $(Q) touch $@ - -print-simulators: $(EXECUTABLE) - $(Q) cd $(HOME) && dotnet exec $(abspath $<) --xcode=$(abspath $(XCODE_DEVELOPER_ROOT)/../..) --print-simulators - -only-check: $(EXECUTABLE) - $(Q) cd $(HOME) && dotnet exec $(abspath $<) --xcode=$(abspath $(XCODE_DEVELOPER_ROOT)/../..) -q $(INSTALL_SIMULATORS) --only-check - -install-simulators: $(EXECUTABLE) - $(Q) cd $(HOME) && dotnet exec $(abspath $<) --xcode=$(abspath $(XCODE_DEVELOPER_ROOT)/../..) -q $(INSTALL_SIMULATORS) diff --git a/tools/siminstaller/Program.cs b/tools/siminstaller/Program.cs deleted file mode 100644 index a6f8ef947484..000000000000 --- a/tools/siminstaller/Program.cs +++ /dev/null @@ -1,489 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; -using System.Xml; -using Mono.Options; - -namespace xsiminstaller { - class MainClass { - static bool print_simulators; - static int verbose; - - static string TempDirectory { - get { - var rv = Path.Combine (Path.GetTempPath (), "x-provisioning"); - Directory.CreateDirectory (rv); - return rv; - } - } - - static bool TryExecuteAndCapture (out string stdout, string filename, params string [] arguments) - { - var rv = TryExecuteAndCapture (out stdout, out var stderr, filename, arguments); - if (!rv) - Console.WriteLine (stderr); - return rv; - } - - static bool TryExecuteAndCapture (out string stdout, out string stderr, string filename, params string [] arguments) - { - using (var p = new Process ()) { - p.StartInfo.FileName = filename; - foreach (var arg in arguments) - p.StartInfo.ArgumentList.Add (arg); - p.StartInfo.RedirectStandardOutput = true; - p.StartInfo.RedirectStandardError = true; - p.StartInfo.UseShellExecute = false; - var quotedArguments = Xamarin.Utils.StringUtils.FormatArguments (arguments); - if (verbose > 0) - Console.WriteLine ($"{filename} {quotedArguments}"); - var output = new StringBuilder (); - var error = new StringBuilder (); - var outputDone = new ManualResetEvent (false); - var errorDone = new ManualResetEvent (false); - p.OutputDataReceived += (sender, args) => { - if (args.Data is null) { - outputDone.Set (); - } else { - output.AppendLine (args.Data); - } - }; - p.ErrorDataReceived += (sender, args) => { - if (args.Data is null) { - errorDone.Set (); - } else { - error.AppendLine (args.Data); - } - }; - p.Start (); - p.BeginErrorReadLine (); - p.BeginOutputReadLine (); - p.WaitForExit (); - outputDone.WaitOne (); - errorDone.WaitOne (); - stdout = output.ToString (); - stderr = error.ToString (); - if (verbose > 0 && p.ExitCode != 0) - Console.WriteLine ($"Failed to execute '{filename} {quotedArguments}', exit code: {p.ExitCode}\n{stdout}\n{stderr}"); - return p.ExitCode == 0; - } - } - - public async static Task Main (string [] args) - { - var exit_code = 0; - string? xcode_app = null; - var install = new List (); - var only_check = false; - var force = false; - var printHelp = false; - - var os = new OptionSet { - { "xcode=", "The Xcode.app to use", (v) => xcode_app = v }, - { "install=", "ID of simulator to install. Can be repeated multiple times.", (v) => install.Add (v) }, - { "only-check", "Only check if the simulators are installed or not. Prints the name of any missing simulators, and returns 1 if any non-installed simulators were found.", (v) => only_check = true }, - { "print-simulators", "Print all detected simulators.", (v) => print_simulators = true }, - { "f|force", "Install again even if already installed.", (v) => force = true }, - { "v|verbose", "Increase verbosity", (v) => verbose++ }, - { "q|quiet", "Decrease verbosity", (v) => verbose-- }, - { "h|help", "Print this help message", (v) => printHelp = true }, - }; - - var others = os.Parse (args); - if (others.Any ()) { - Console.WriteLine ("Unexpected arguments:"); - foreach (var arg in others) - Console.WriteLine ("\t{0}", arg); - Console.WriteLine ("Expected arguments are:"); - os.WriteOptionDescriptions (Console.Out); - return 1; - } - - if (printHelp) { - os.WriteOptionDescriptions (Console.Out); - return 0; - } - - if (string.IsNullOrEmpty (xcode_app)) { - Console.WriteLine ("--xcode is required."); - return 1; - } else if (!Directory.Exists (xcode_app)) { - Console.WriteLine ("The Xcode directory {0} does not exist.", xcode_app); - return 1; - } - - var plist = Path.Combine (xcode_app, "Contents", "Info.plist"); - if (!File.Exists (plist)) { - Console.WriteLine ($"The Info.plist '{plist}' does not exist."); - return 1; - } - - if (!TryExecuteAndCapture (out var xcodeVersion, "/usr/libexec/PlistBuddy", $"-c", "Print :DTXcode", plist)) - return 1; - xcodeVersion = xcodeVersion.Trim (); - xcodeVersion = xcodeVersion.Insert (xcodeVersion.Length - 2, "."); - xcodeVersion = xcodeVersion.Insert (xcodeVersion.Length - 1, "."); - - var indexName = $"index-{xcodeVersion}.dvtdownloadableindex"; - var tmpfile = Path.Combine (TempDirectory, indexName); - if (!File.Exists (tmpfile)) { - var urls = new string [] { - /* - * The following url was found while debugging Xcode, the "index2" part is actually hardcoded: - * - * DVTFoundation`-[DVTDownloadableIndexSource identifier]: - * 0x103db478d <+0>: pushq %rbp - * 0x103db478e <+1>: movq %rsp, %rbp - * 0x103db4791 <+4>: leaq 0x53f008(%rip), %rax ; @"index2" - * 0x103db4798 <+11>: popq %rbp - * 0x103db4799 <+12>: retq - * - */ - "https://devimages-cdn.apple.com/downloads/xcode/simulators/index2.dvtdownloadableindex", - }; - var anyFailures = false; - var wc = new HttpClient (); - foreach (var url in urls) { - var uri = new Uri (url); - try { - if (verbose > 0) - Console.WriteLine ($"Downloading '{uri}'"); - else if (anyFailures) - Console.WriteLine ($"Attempting fallback url '{uri}'"); - - var response = await wc.GetAsync (uri); - using var file = new FileStream (tmpfile, FileMode.Create, FileAccess.Write, FileShare.None); - await response.Content.CopyToAsync (file); - } catch (Exception ex) { - File.Delete (tmpfile); // Make sure there are no downloaded remnants - // 403 means 404 - if (ex is WebException we && (we.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.Forbidden) { - Console.WriteLine ($"Failed to download {url}: Not found"); // Apple's servers return a 403 if the file doesn't exist, which can be quite confusing, so show a better error. - } else { - Console.WriteLine ($"Failed to download {url}: {ex}"); - } - anyFailures = true; - } - } - - if (!File.Exists (tmpfile)) { - // We couldn't download the list of simulators, but the simulator(s) we were requested to install might already be installed. - // Don't fail in that case (we'd miss any potential updates, but that's probably not too bad). - if (install.Count > 0) { - if (verbose > 0) - Console.WriteLine ("Checking if all the requested simulators are already installed"); - foreach (var name in install) { - if (!IsInstalled (name, out var _)) { - Console.WriteLine (verbose > 0 ? $"The simulator '{name}' is not installed." : name); - exit_code = 1; - } else if (verbose > 0) { - Console.WriteLine ($"The simulator '{name}' is installed."); - } - } - // We can't install any missing simulators, because we don't have the download url (since we couldn't download the .dvtdownloadableindex file), so just exit. - return exit_code; - } - return 1; - } - } - - if (!TryExecuteAndCapture (out var xml, "plutil", "-convert", "xml1", "-o", "-", tmpfile)) - return 1; - - var doc = new XmlDocument (); - doc.LoadXml (xml); - - var downloadables = doc.SelectNodes ("//plist/dict/key[text()='downloadables']/following-sibling::array[1]/dict"); - if (downloadables is not null) { - foreach (XmlNode downloadable in downloadables) { - var nameNode = downloadable.SelectSingleNode ("key[text()='name']/following-sibling::string"); - var versionNode = downloadable.SelectSingleNode ("key[text()='version']/following-sibling::string"); - var sourceNode = downloadable.SelectSingleNode ("key[text()='source']/following-sibling::string"); - var identifierNode = downloadable.SelectSingleNode ("key[text()='identifier']/following-sibling::string"); - var fileSizeNode = downloadable.SelectSingleNode ("key[text()='fileSize']/following-sibling::integer|key[text()='fileSize']/following-sibling::real"); - var installPrefixNode = downloadable.SelectSingleNode ("key[text()='userInfo']/following-sibling::dict/key[text()='InstallPrefix']/following-sibling::string"); - - var version = versionNode?.InnerText ?? string.Empty; - var versions = version.Split ('.'); - var versionMajor = versions [0]; - var versionMinor = versions [1]; - var dict = new Dictionary () { - { "DOWNLOADABLE_VERSION_MAJOR", versionMajor }, - { "DOWNLOADABLE_VERSION_MINOR", versionMinor }, - { "DOWNLOADABLE_VERSION", version }, - }; - - var identifier = Replace (identifierNode?.InnerText, dict); - - var name = Replace (nameNode?.InnerText, dict) ?? string.Empty; - var source = Replace (sourceNode?.InnerText, dict); - var installPrefix = Replace (installPrefixNode?.InnerText, dict); - - if (string.IsNullOrEmpty (identifier)) { - if (verbose >= 0) - Console.WriteLine ($"No identifier found for {name}"); - continue; - } - - dict.Add ("DOWNLOADABLE_IDENTIFIER", identifier); - - if (installPrefix is null) { - // This is just guesswork - var simRuntimeName = name.Replace (" Simulator", ".simruntime"); - installPrefix = $"/Library/Developer/CoreSimulator/Profiles/Runtimes/{simRuntimeName}"; - } - - double.TryParse (fileSizeNode?.InnerText, out var parsedFileSize); - var fileSize = (long) parsedFileSize; - - var installed = false; - var updateAvailable = false; - - if (only_check && !install.Contains (identifier)) - continue; - - if (IsInstalled (identifier, out var installedVersion)) { - if (installedVersion >= Version.Parse (version)) { - installed = true; - } else { - updateAvailable = true; - } - } - - var doInstall = false; - if (install.Contains (identifier)) { - if (force) { - doInstall = true; - if (!only_check && verbose >= 0 && installed) - Console.WriteLine ($"The simulator '{identifier}' is already installed, but will be installed again because --force was specified."); - } else if (installed) { - if (!only_check && verbose >= 0) - Console.WriteLine ($"Not installing '{identifier}' because it's already installed and up-to-date."); - } else { - doInstall = true; - } - install.Remove (identifier); - } - - if (print_simulators) { - Console.WriteLine (name); - Console.Write ($" Version: {version}"); - if (updateAvailable) - Console.WriteLine ($" (an earlier version is installed: {installedVersion}"); - else if (!installed) - Console.WriteLine ($" (not installed)"); - else - Console.WriteLine ($" (installed)"); - Console.WriteLine ($" Source: {source}"); - Console.WriteLine ($" Identifier: {identifier}"); - Console.WriteLine ($" InstallPrefix: {installPrefix}"); - } - - if (only_check) { - if (doInstall) { - if (updateAvailable) { - Console.WriteLine (verbose > 0 ? $"The simulator '{name}' is installed, but an update is available." : name); - } else { - Console.WriteLine (verbose > 0 ? $"The simulator '{name}' is not installed." : name); - } - exit_code = 1; - } else if (verbose > 0) { - Console.WriteLine ($"The simulator '{name}' is installed."); - } - } - if (doInstall && !only_check) { - Console.WriteLine ($"Installing {name}..."); - if (await InstallAsync (source, fileSize, installPrefix)) { - Console.WriteLine ($"Installed {name} successfully."); - } else { - Console.WriteLine ($"Failed to install {name}."); - return 1; - } - } - } - } - - if (install.Count > 0) { - Console.WriteLine ("Unknown simulators: {0}", string.Join (", ", install)); - return 1; - } - - return exit_code; - } - - static bool IsInstalled (string identifier, out Version? installedVersion) - { - if (TryExecuteAndCapture (out var pkgInfo, out _, $"pkgutil", "--pkg-info", identifier)) { - var lines = pkgInfo.Split ('\n'); - var version = lines.First ((v) => v.StartsWith ("version: ", StringComparison.Ordinal)).Substring ("version: ".Length); - installedVersion = Version.Parse (version); - return true; - } - - installedVersion = null; - return false; - } - - static async Task InstallAsync (string? source, long fileSize, string installPrefix) - { - if (string.IsNullOrEmpty (source)) { - Console.WriteLine ($"Failed to install, no source provided."); - return false; - } - - var download_dir = TempDirectory; - var filename = Path.GetFileName (source); - var download_path = Path.Combine (download_dir, filename); - var download = true; - - if (!File.Exists (download_path)) { - Console.WriteLine ($"Downloading '{source}' to '{download_path}' (size: {fileSize} bytes = {fileSize / 1024.0 / 1024.0:N2} MB)..."); - } else if (new FileInfo (download_path).Length != fileSize) { - Console.WriteLine ($"Downloading '{source}' to '{download_path}' because the existing file's size {new FileInfo (download_path).Length} does not match the expected size {fileSize}..."); - } else { - download = false; - } - if (download) { - var downloadDone = new ManualResetEvent (false); - var wc = new HttpClient (); - long lastProgress = 0; - var watch = Stopwatch.StartNew (); - var downloadProgressChanged = (DownloadProgressChangedEventArgs progress_args) => { - var progress = progress_args.BytesReceived * 100 / fileSize; - if (progress > lastProgress) { - lastProgress = progress; - var duration = watch.Elapsed.TotalSeconds; - var speed = progress_args.BytesReceived / duration; - var timeLeft = TimeSpan.FromSeconds ((long) ((progress_args.TotalBytesToReceive - progress_args.BytesReceived) / speed)); - Console.WriteLine ($"Downloaded {progress_args.BytesReceived:N0}/{fileSize:N0} bytes = {progress}% in {duration:N1}s ({speed / 1024.0 / 1024.0:N1} MB/s; approximately {timeLeft} left)"); - } - }; - var downloadFileCompleted = (AsyncCompletedEventArgs download_args) => { - Console.WriteLine ($"Download completed in {watch.Elapsed.TotalSeconds}s"); - if (download_args.Error is not null) { - Console.WriteLine ($" with error: {download_args.Error}"); - } - downloadDone.Set (); - }; - - using var file = new FileStream (download_path, FileMode.Create, FileAccess.Write, FileShare.None); - var response = await wc.GetAsync (new Uri (source), HttpCompletionOption.ResponseHeadersRead); - var contentLength = response.Content.Headers.ContentLength; - - using var responseStream = await response.Content.ReadAsStreamAsync (); - - var buffer = new byte [40960]; - long totalBytesRead = 0; - int bytesRead; - while ((bytesRead = await responseStream.ReadAsync (buffer, 0, buffer.Length)) > 0) { - file.Write (buffer, 0, bytesRead); - totalBytesRead += bytesRead; - downloadProgressChanged (new DownloadProgressChangedEventArgs () { BytesReceived = totalBytesRead, TotalBytesToReceive = contentLength ?? -1 }); - } - downloadFileCompleted (new AsyncCompletedEventArgs (null, false, null)); - downloadDone.WaitOne (); - } - var mount_point = Path.Combine (download_dir, filename + "-mount"); - Directory.CreateDirectory (mount_point); - try { - Console.WriteLine ($"Mounting '{download_path}' into '{mount_point}'..."); - if (!TryExecuteAndCapture (out _, "hdiutil", "attach", download_path, "-mountpoint", mount_point, "-quiet", "-nobrowse")) { - Console.WriteLine ("Mount failure!"); - return false; - } - - try { - var packages = Directory.GetFiles (mount_point, "*.pkg"); - if (packages.Length == 0) { - Console.WriteLine ("Found no *.pkg files in the dmg."); - return false; - } else if (packages.Length > 1) { - Console.WriteLine ("Found more than one *.pkg file in the dmg:\n\t{0}", string.Join ("\n\t", packages)); - return false; - } - - // According to the package manifest, the package's install location is /. - // That's obviously not where it's installed, but I have no idea how Apple does it - // So instead decompress the package, modify the package manifest, re-create the package, and then install it. - var expanded_path = Path.Combine (download_dir + "-expanded-pkg"); - if (Directory.Exists (expanded_path)) - Directory.Delete (expanded_path, true); - Console.WriteLine ($"Expanding '{packages [0]}' into '{expanded_path}'..."); - if (!TryExecuteAndCapture (out _, "pkgutil", "--expand", packages [0], expanded_path)) { - Console.WriteLine ($"Failed to expand {packages [0]}"); - return false; - } - - try { - var packageInfoPath = Path.Combine (expanded_path, "PackageInfo"); - var packageInfoDoc = new XmlDocument (); - packageInfoDoc.Load (packageInfoPath); - // Add the install-location attribute to the pkg-info node - var attr = packageInfoDoc.CreateAttribute ("install-location"); - attr.Value = installPrefix; - packageInfoDoc.SelectSingleNode ("/pkg-info")!.Attributes!.Append (attr); - packageInfoDoc.Save (packageInfoPath); - - var fixed_path = Path.Combine (Path.GetDirectoryName (download_path)!, Path.GetFileNameWithoutExtension (download_path) + "-fixed.pkg"); - if (File.Exists (fixed_path)) - File.Delete (fixed_path); - try { - Console.WriteLine ($"Creating fixed package '{fixed_path}' from '{expanded_path}'..."); - if (!TryExecuteAndCapture (out _, "pkgutil", "--flatten", expanded_path, fixed_path)) { - Console.WriteLine ("Failed to create fixed package."); - return false; - } - - Console.WriteLine ($"Installing '{fixed_path}'..."); - if (!TryExecuteAndCapture (out _, "sudo", "installer", "-pkg", fixed_path, "-target", "/", "-verbose", "-dumplog")) { - Console.WriteLine ("Failed to install package."); - return false; - } - } finally { - if (File.Exists (fixed_path)) - File.Delete (fixed_path); - } - } finally { - Directory.Delete (expanded_path, true); - } - } finally { - if (!TryExecuteAndCapture (out _, "hdiutil", "detach", mount_point, "-quiet", "-force")) - Console.WriteLine ($"Failed to detach {mount_point}"); - } - } finally { - try { - Directory.Delete (mount_point, true); - } catch (IOException ioex) { - Console.WriteLine ($"Unable to remove: {mount_point}"); - Console.WriteLine ($" with error: {ioex}"); - } - } - - File.Delete (download_path); - - return true; - } - - [return: NotNullIfNotNull ("value")] - static string? Replace (string? value, Dictionary replacements) - { - if (value is null) - return null; - foreach (var kvp in replacements) - value = value.Replace ($"$({kvp.Key})", kvp.Value); - return value; - } - } -} - -class DownloadProgressChangedEventArgs { - public long TotalBytesToReceive; - public long BytesReceived; -} diff --git a/tools/siminstaller/README.md b/tools/siminstaller/README.md deleted file mode 100644 index f25c8a938258..000000000000 --- a/tools/siminstaller/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# SimInstaller - -This is a simple tool that can install old simulator versions for Xcode from the command line. diff --git a/tools/siminstaller/siminstaller.csproj b/tools/siminstaller/siminstaller.csproj deleted file mode 100644 index 05c5a87b8c79..000000000000 --- a/tools/siminstaller/siminstaller.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - Exe - net$(BundledNETCoreAppTargetFrameworkVersion) - enable - enable - latest - false - - - - - - - diff --git a/tools/siminstaller/siminstaller.sln b/tools/siminstaller/siminstaller.sln deleted file mode 100644 index 24fba93d49ae..000000000000 --- a/tools/siminstaller/siminstaller.sln +++ /dev/null @@ -1,17 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "siminstaller", "siminstaller.csproj", "{DA71C0E6-7A4F-430D-B7D2-D134F4E4DD98}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DA71C0E6-7A4F-430D-B7D2-D134F4E4DD98}.Debug|x86.ActiveCfg = Debug|x86 - {DA71C0E6-7A4F-430D-B7D2-D134F4E4DD98}.Debug|x86.Build.0 = Debug|x86 - {DA71C0E6-7A4F-430D-B7D2-D134F4E4DD98}.Release|x86.ActiveCfg = Release|x86 - {DA71C0E6-7A4F-430D-B7D2-D134F4E4DD98}.Release|x86.Build.0 = Release|x86 - EndGlobalSection -EndGlobal