[siminstaller] Adjust according to recent Xcode changes. (#15449)
The url to download the list of simulators that are available has changed, and the format changed slightly as well.
This commit is contained in:
Родитель
5b3c844ba9
Коммит
4c53f68d8d
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
@ -83,7 +84,7 @@ namespace xsiminstaller {
|
|||
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) },
|
||||
|
@ -134,22 +135,49 @@ namespace xsiminstaller {
|
|||
|
||||
xcodeVersion = xcodeVersion.Insert (xcodeVersion.Length - 2, ".");
|
||||
xcodeVersion = xcodeVersion.Insert (xcodeVersion.Length - 1, ".");
|
||||
var url = $"https://devimages-cdn.apple.com/downloads/xcode/simulators/index-{xcodeVersion}-{xcodeUuid}.dvtdownloadableindex";
|
||||
var uri = new Uri (url);
|
||||
var tmpfile = Path.Combine (TempDirectory, Path.GetFileName (uri.LocalPath));
|
||||
|
||||
var indexName = $"index-{xcodeVersion}-{xcodeUuid}.dvtdownloadableindex";
|
||||
var tmpfile = Path.Combine (TempDirectory, indexName);
|
||||
if (!File.Exists (tmpfile)) {
|
||||
var wc = new WebClient ();
|
||||
try {
|
||||
if (verbose > 0)
|
||||
Console.WriteLine ($"Downloading '{uri}'");
|
||||
wc.DownloadFile (uri, tmpfile);
|
||||
} catch (Exception ex) {
|
||||
// 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}");
|
||||
// Try multiple urls
|
||||
var urls = new string [] {
|
||||
$"https://devimages-cdn.apple.com/downloads/xcode/simulators/{indexName}",
|
||||
/*
|
||||
* 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;
|
||||
foreach (var url in urls) {
|
||||
var uri = new Uri (url);
|
||||
var wc = new WebClient ();
|
||||
try {
|
||||
if (verbose > 0)
|
||||
Console.WriteLine ($"Downloading '{uri}'");
|
||||
else if (anyFailures)
|
||||
Console.WriteLine ($"Attempting fallback url '{uri}'");
|
||||
wc.DownloadFile (uri, tmpfile);
|
||||
} 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) {
|
||||
|
@ -169,13 +197,14 @@ namespace xsiminstaller {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
if (!TryExecuteAndCapture ("plutil", $"-convert xml1 -o - '{tmpfile}'", out var xml))
|
||||
|
||||
if (!TryExecuteAndCapture ("plutil", $"-convert xml1 -o - '{tmpfile}'", out var xml))
|
||||
return 1;
|
||||
|
||||
var doc = new XmlDocument ();
|
||||
doc.LoadXml (xml);
|
||||
|
||||
var downloadables = doc.SelectNodes ("//plist/dict/key[text()='downloadables']/following-sibling::array/dict");
|
||||
var downloadables = doc.SelectNodes ("//plist/dict/key[text()='downloadables']/following-sibling::array[1]/dict");
|
||||
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");
|
||||
|
@ -200,7 +229,14 @@ namespace xsiminstaller {
|
|||
|
||||
var name = Replace (nameNode.InnerText, dict);
|
||||
var source = Replace (sourceNode.InnerText, dict);
|
||||
var installPrefix = Replace (installPrefixNode.InnerText, dict);
|
||||
var installPrefix = Replace (installPrefixNode?.InnerText, dict);
|
||||
|
||||
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;
|
||||
|
||||
|
@ -405,11 +441,28 @@ namespace xsiminstaller {
|
|||
return true;
|
||||
}
|
||||
|
||||
static string Replace (string value, Dictionary<string, string> replacements)
|
||||
[return: NotNullIfNotNull ("value")]
|
||||
static string? Replace ( string? value, Dictionary<string, string> replacements)
|
||||
{
|
||||
if (value is null)
|
||||
return null;
|
||||
foreach (var kvp in replacements)
|
||||
value = value.Replace ($"$({kvp.Key})", kvp.Value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET // the below attributes are no longer needed once we switch to .NET
|
||||
namespace System.Diagnostics.CodeAnalysis {
|
||||
[AttributeUsage (AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
|
||||
internal sealed class NotNullIfNotNullAttribute : Attribute {
|
||||
public string ParameterName { get; }
|
||||
|
||||
public NotNullIfNotNullAttribute (string parameterName)
|
||||
{
|
||||
ParameterName = parameterName;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !NET
|
||||
|
|
Загрузка…
Ссылка в новой задаче