/// <summary> /// Delete downloaded data, checking to only delte expected files. /// </summary> /// <param name="downloadPath">Where downloads were stored.</param> /// <param name="metadata">The Unity version downloaded</param> /// <param name="packageIds">Downloaded packages.</param> public void CleanUpDownloads(VersionMetadata metadata, string downloadPath, IEnumerable <PackageMetadata> packages) { if (!Directory.Exists(downloadPath)) { return; } foreach (var directory in Directory.GetDirectories(downloadPath)) { throw new Exception("Unexpected directory in downloads folder: " + directory); } var packageFileNames = packages .Select(p => p.GetFileName()) .ToList(); foreach (var path in Directory.GetFiles(downloadPath)) { var fileName = Path.GetFileName(path); if (fileName == ".DS_Store" || fileName == "thumbs.db" || fileName == "desktop.ini") { continue; } if (!packageFileNames.Contains(fileName)) { throw new Exception("Unexpected file in downloads folder: " + path); } } Directory.Delete(downloadPath, true); }
/// <summary> /// Get the default package IDs for the given version. /// </summary> /// <param name="metadata">Unity version</param> /// <param name="cachePlatform">Name of platform</param> public IEnumerable <string> GetDefaultPackages(VersionMetadata metadata, CachePlatform cachePlatform) { var platform = metadata.GetPlatform(cachePlatform); if (platform.packages == null) { throw new ArgumentException("Unity version contains no packages."); } return(platform.packages.Where(p => p.install).Select(p => p.name)); }
/// <summary> /// Extract the versions and the base URLs from the html string. /// </summary> Dictionary <UnityVersion, VersionMetadata> ExtractFromHtml(string html, Dictionary <UnityVersion, VersionMetadata> results = null) { var matches = UNIT_DOWNLOADS_RE.Matches(html); results = results ?? new Dictionary <UnityVersion, VersionMetadata>(); foreach (Match match in matches) { var version = new UnityVersion(match.Groups[4].Value); version.hash = match.Groups[2].Value; var iniUrl = match.Groups[1].Value; var componentName = match.Groups[3].Value; CachePlatform cachePlatform; if (componentName.Contains("Mac")) { cachePlatform = CachePlatform.macOS; } else if (componentName.Contains("Windows")) { cachePlatform = CachePlatform.Windows; } else if (componentName.Contains("Linux")) { cachePlatform = CachePlatform.Linux; } else { Logger.LogDebug("Platform name not found in component name: " + componentName); continue; } VersionMetadata metadata = default; if (!results.TryGetValue(version, out metadata)) { metadata.version = version; } var platform = metadata.GetPlatform(cachePlatform); platform.iniUrl = iniUrl; metadata.SetPlatform(cachePlatform, platform); results[version] = metadata; } return(results); }
void ParseVersions(CachePlatform cachePlatform, HubUnityVersion[] versions, List <VersionMetadata> results) { foreach (var version in versions) { var metadata = new VersionMetadata(); metadata.version = new UnityVersion(version.version); var platform = new VersionPlatformMetadata(); platform.packages = new PackageMetadata[version.modules.Length + 1]; platform.packages[0] = new PackageMetadata() { name = "Unity ", title = "Unity " + version.version, description = "Unity Editor", url = version.downloadUrl, install = true, mandatory = false, size = long.Parse(version.downloadSize), installedsize = long.Parse(version.installedSize), version = version.version, md5 = version.checksum }; var i = 1; foreach (var module in version.modules) { platform.packages[i++] = new PackageMetadata() { name = module.id, title = module.name, description = module.description, url = module.downloadUrl, install = module.selected, mandatory = false, size = long.Parse(module.downloadSize), installedsize = long.Parse(module.installedSize), version = version.version, md5 = module.checksum }; } Logger.LogDebug($"Found version {metadata.version} with {platform.packages.Length} packages"); metadata.SetPlatform(cachePlatform, platform); results.Add(metadata); } }
/// <summary> /// Create a download and install queue from the given version and packages. /// </summary> /// <param name="metadata">The Unity version</param> /// <param name="cachePlatform">Name of platform</param> /// <param name="downloadPath">Location of the downloaded the packages</param> /// <param name="packageIds">Packages to download and/or install</param> /// <returns>The queue list with the created queue items</returns> public Queue CreateQueue(VersionMetadata metadata, CachePlatform cachePlatform, string downloadPath, IEnumerable <PackageMetadata> packages) { if (!metadata.version.IsFullVersion) { throw new ArgumentException("VersionMetadata.version needs to contain a full Unity version", nameof(metadata)); } var platform = metadata.GetPlatform(cachePlatform); if (platform.packages == null || platform.packages.Length == 0) { throw new ArgumentException("VersionMetadata.packages cannot be null or empty", nameof(metadata)); } var items = new List <QueueItem>(); foreach (var package in packages) { var fullUrl = package.url; if (platform.iniUrl != null && !fullUrl.StartsWith("http")) { fullUrl = platform.iniUrl + package.url; } var fileName = package.GetFileName(); Logger.LogDebug($"{package.name}: Using file name '{fileName}' for url '{fullUrl}'"); var outputPath = Path.Combine(downloadPath, fileName); items.Add(new QueueItem() { package = package, downloadUrl = new Uri(fullUrl), filePath = outputPath, retries = Configuration.retryCount }); } return(new Queue() { metadata = metadata, items = items }); }
/// <summary> /// Convert a UnityHub URL to a VersionMetadata struct. /// </summary> /// <remarks> /// Conversion is completely offline, no http lookup is made. /// </remarks> public VersionMetadata UnityHubUrlToVersion(string url) { var match = UNITYHUB_RE.Match(url); if (!match.Success) { return(default(VersionMetadata)); } var version = new UnityVersion(match.Groups[1].Value); version.hash = match.Groups[2].Value; var metadata = new VersionMetadata(); metadata.version = version; metadata.baseUrl = GetIniBaseUrl(version.type) + version.hash + "/"; return(metadata); }
/// <summary> /// Extract the versions and the base URLs from the html string. /// </summary> Dictionary <UnityVersion, VersionMetadata> ExtractFromHtml(string html, bool prerelease = false, Dictionary <UnityVersion, VersionMetadata> results = null) { var matches = UNITYHUB_RE.Matches(html); results = results ?? new Dictionary <UnityVersion, VersionMetadata>(); foreach (Match match in matches) { var version = new UnityVersion(match.Groups[1].Value); version.hash = match.Groups[2].Value; VersionMetadata metadata = default; if (!results.TryGetValue(version, out metadata)) { metadata.version = version; } metadata.baseUrl = GetIniBaseUrl(version.type) + version.hash + "/"; metadata.prerelease = prerelease; results[version] = metadata; } matches = UNITY_DOWNLOAD_RE.Matches(html); foreach (Match match in matches) { var version = new UnityVersion(match.Groups[2].Value); version.hash = match.Groups[1].Value; VersionMetadata metadata = default; if (!results.TryGetValue(version, out metadata)) { metadata.version = version; } metadata.baseUrl = GetIniBaseUrl(version.type) + version.hash + "/"; metadata.prerelease = prerelease; results[version] = metadata; } return(results); }
/// <summary> /// Resolve package patterns to package metadata. /// This method also adds package dependencies. /// </summary> public IEnumerable <PackageMetadata> ResolvePackages( VersionMetadata metadata, CachePlatform cachePlatform, IEnumerable <string> packages, IList <string> notFound = null, bool addDependencies = true ) { var platform = metadata.GetPlatform(cachePlatform); var metas = new List <PackageMetadata>(); foreach (var id in packages) { PackageMetadata resolved = default; if (id.StartsWith('~')) { // Contains lookup var str = id.Substring(1); foreach (var package in platform.packages) { if (package.name.Contains(str, StringComparison.OrdinalIgnoreCase)) { if (resolved.name == null) { Logger.LogDebug($"Fuzzy lookup '{id}' matched package '{resolved.name}'"); resolved = package; } else { throw new Exception($"Fuzzy package match '{id}' is ambiguous between '{package.name}' and '{resolved.name}'"); } } } } else { // Exact lookup resolved = platform.GetPackage(id); } if (resolved.name != null) { if (addDependencies) { foreach (var package in platform.packages) { if (package.sync == resolved.name && !metas.Any(p => p.name == package.name)) { Logger.LogInformation($"Adding '{package.name}' which '{resolved.name}' is synced with"); metas.Add(package); } } } metas.Add(resolved); } else if (notFound != null) { notFound.Add(id); } } return(metas); }
/// <summary> /// Get the path to the download directory (determined by DataPath or platform). /// </summary> public string GetDownloadDirectory(VersionMetadata metadata) { var downloadPath = DataPath ?? Platform.GetDownloadDirectory(); return(Path.Combine(downloadPath, string.Format(Configuration.downloadSubdirectory, metadata.version))); }
/// <summary> /// Resolve package patterns to package metadata. /// This method also adds package dependencies. /// </summary> public IEnumerable <PackageMetadata> ResolvePackages( VersionMetadata metadata, CachePlatform cachePlatform, IEnumerable <string> packages, IList <string> notFound = null ) { var packageMetadata = metadata.GetPackages(cachePlatform); var metas = new List <PackageMetadata>(); foreach (var pattern in packages) { var id = pattern; bool fuzzy = false, addDependencies = true; while (id.StartsWith("~") || id.StartsWith("=")) { if (id.StartsWith("~")) { fuzzy = true; id = id.Substring(1); } else if (id.StartsWith("=")) { addDependencies = false; id = id.Substring(1); } } PackageMetadata resolved = default; if (fuzzy) { // Contains lookup foreach (var package in packageMetadata) { if (package.name.IndexOf(id, StringComparison.OrdinalIgnoreCase) >= 0) { if (resolved.name == null) { Logger.LogDebug($"Fuzzy lookup '{pattern}' matched package '{resolved.name}'"); resolved = package; } else { throw new Exception($"Fuzzy package match '{pattern}' is ambiguous between '{package.name}' and '{resolved.name}'"); } } } } else { // Exact lookup resolved = metadata.GetPackage(cachePlatform, id); } if (resolved.name != null) { AddPackageWithDependencies(packageMetadata, metas, resolved, addDependencies); } else if (notFound != null) { notFound.Add(id); } } return(metas); }
static IEnumerable <PackageMetadata> Generator(VersionMetadata version, CachePlatform platform) { var v = version.version; // Documentation if (v.major >= 2018 && version.GetRawPackage(platform, "Documentation").name == null) { yield return(new PackageMetadata() { name = "Documentation", description = "Offline Documentation", url = $"https://storage.googleapis.com/docscloudstorage/{v.major}.{v.minor}/UnityDocumentation.zip", install = true, destination = "{UNITY_PATH}", size = 350 * 1024 * 1024, // Conservative estimate based on 2019.2 installedsize = 650 * 1024 * 1024, // " }); } // Language packs if (v.major >= 2018) { string[] localizations; if (v.major == 2018 && v.minor == 1) { localizations = Localizations_2018_1; } else if (v.major == 2018) { localizations = Localizations_2018_2; } else { localizations = Localizations_2019_1; } foreach (var loc in localizations) { yield return(new PackageMetadata() { name = LanguageNames[loc], description = $"{LanguageNames[loc]} Language Pack", url = $"https://new-translate.unity3d.jp/v1/live/54/{v.major}.{v.minor}/{loc}", fileName = $"{loc}.po", destination = "{UNITY_PATH}/Unity.app/Contents/Localization", size = 2 * 1024 * 1024, // Conservative estimate based on 2019.2 installedsize = 2 * 1024 * 1024, // " }); } } // Android dependencies if (v.major >= 2019 && version.GetRawPackage(platform, "Android").name != null) { // Android SDK & NDK & stuff yield return(new PackageMetadata() { name = "Android SDK & NDK Tools", description = "Android SDK & NDK Tools 26.1.1", url = $"https://dl.google.com/android/repository/sdk-tools-darwin-4333796.zip", destination = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/SDK", size = 148 * 1024 * 1024, installedsize = 174 * 1024 * 1024, sync = "Android", eulaurl1 = "https://dl.google.com/dl/android/repository/repository2-1.xml", eulalabel1 = "Android SDK and NDK License Terms from Google", eulamessage = "Please review and accept the license terms before downloading and installing Android\'s SDK and NDK.", }); yield return(new PackageMetadata() { name = "Android SDK Platform Tools", description = "Android SDK Platform Tools 28.0.1", url = $"https://dl.google.com/android/repository/platform-tools_r28.0.1-darwin.zip", destination = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/SDK", size = 5 * 1024 * 1024, installedsize = 16 * 1024 * 1024, hidden = true, sync = "Android SDK & NDK Tools", }); yield return(new PackageMetadata() { name = "Android SDK Build Tools", description = "Android SDK Build Tools 28.0.3", url = $"https://dl.google.com/android/repository/build-tools_r28.0.3-macosx.zip", destination = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/SDK/build-tools", size = 53 * 1024 * 1024, installedsize = 120 * 1024 * 1024, hidden = true, sync = "Android SDK & NDK Tools", renameFrom = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/SDK/build-tools/android-9", renameTo = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/SDK/build-tools/28.0.3" }); yield return(new PackageMetadata() { name = "Android SDK Platforms", description = "Android SDK Platforms 28 r06", url = $"https://dl.google.com/android/repository/platform-28_r06.zip", destination = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/SDK/platforms", size = 61 * 1024 * 1024, installedsize = 121 * 1024 * 1024, hidden = true, sync = "Android SDK & NDK Tools", renameFrom = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/SDK/platforms/android-9", renameTo = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/SDK/platforms/android-28" }); if (v.major == 2019 && v.minor <= 2) { yield return(new PackageMetadata() { name = "Android NDK 16b", description = "Android NDK r16b", url = $"https://dl.google.com/android/repository/android-ndk-r16b-darwin-x86_64.zip", destination = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer", size = 770 * 1024 * 1024, installedsize = 2700L * 1024 * 1024, hidden = true, sync = "Android SDK & NDK Tools", renameFrom = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/android-ndk-r16b", renameTo = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/NDK" }); } else { yield return(new PackageMetadata() { name = "Android NDK 19", description = "Android NDK r19", url = $"https://dl.google.com/android/repository/android-ndk-r19-darwin-x86_64.zip", destination = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer", size = 770 * 1024 * 1024, installedsize = 2700L * 1024 * 1024, hidden = true, sync = "Android SDK & NDK Tools", renameFrom = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/android-ndk-r19", renameTo = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/NDK" }); } // Android JDK if (v.major > 2019 || v.minor >= 2) { yield return(new PackageMetadata() { name = "OpenJDK", description = "Android Open JDK 8u172-b11", url = $"http://download.unity3d.com/download_unity/open-jdk/open-jdk-mac-x64/jdk8u172-b11_4be8440cc514099cfe1b50cbc74128f6955cd90fd5afe15ea7be60f832de67b4.zip", destination = "{UNITY_PATH}/PlaybackEngines/AndroidPlayer/OpenJDK", size = 73 * 1024 * 1024, installedsize = 165 * 1024 * 1024, sync = "Android", }); } } }
static IEnumerable <PackageMetadata> GeneratePackages(VersionMetadata version, CachePlatform platform) { return(Generator(version, platform).ToList()); }