private static int ProcessSuccessfulUpdates(AssemblyUpdaterUpdateTask[] tasks) { var assembliesToUpdate = GetAssembliesToBeUpdated(); var succeededUpdates = tasks.Where(t => t.Result == APIUpdaterAssemblyHelper.UpdatesApplied); if (!succeededUpdates.Any()) { assembliesToUpdate.Clear(); return(0); } if (AskForConsent(false) != APIUpdaterStatus.Accepted) { APIUpdaterLogger.WriteToFile(L10n.Tr("User declined to run APIUpdater")); return(0); } var assemblyPaths2 = succeededUpdates.Select(u => u.Candidate.Path).ToArray(); APIUpdaterHelper.HandleFilesInPackagesVirtualFolder(assemblyPaths2); if (!APIUpdaterHelper.CheckReadOnlyFiles(assemblyPaths2)) { return(0); } foreach (var succeedd in succeededUpdates) { APIUpdaterLogger.WriteToFile("{0}{1}", Environment.NewLine, succeedd.StdOut); FileUtil.MoveFileIfExists(succeedd.OutputPath, succeedd.Candidate.Path); } assembliesToUpdate.Clear(); return(succeededUpdates.Count()); }
private static bool HandleAssemblyUpdaterErrors(IEnumerable <AssemblyUpdaterUpdateTask> allTasks) { var tasksWithErrors = allTasks.Where(t => APIUpdaterAssemblyHelper.IsError(t.Result) || t.Exception != null); if (!tasksWithErrors.Any()) { return(false); } var sb = new StringBuilder(L10n.Tr("Unable to update following assemblies:")); foreach (var updaterTask in tasksWithErrors) { sb.AppendFormat("{1} (Name = {2}, Error = {3}) (Output: {4}){0}{5}{0}{6}{0}", Environment.NewLine, updaterTask.Candidate.Path, updaterTask.Candidate.Name, updaterTask.Result, updaterTask.OutputPath, updaterTask.StdOut, updaterTask.StdErr); if (updaterTask.Exception != null) { sb.AppendFormat("\tException: {0}{1}", updaterTask.Exception, Environment.NewLine); } } ReportIgnoredAssembliesDueToPreviousErrors(sb, allTasks.Except(tasksWithErrors)); APIUpdaterLogger.WriteErrorToConsole(sb.ToString()); return(true); }
private static void LogTimeoutError(AssemblyUpdaterCheckAssemblyPublishConfigsTask[] tasks, TimeSpan waitedTime) { var timedOut = tasks.Where(t => !t.Event.WaitOne(0)); var sb = new StringBuilder(L10n.Tr("Timeout while checking assemblies:")); foreach (var task in timedOut) { sb.AppendFormat("{1}{0}", Environment.NewLine, task.Candidate.Path); } sb.AppendFormat(L10n.Tr("{0}Timeout: {1} ms"), Environment.NewLine, waitedTime.Milliseconds); sb.AppendFormat(L10n.Tr("{0}Update configurations from those assemblies may have not been applied."), Environment.NewLine); APIUpdaterLogger.WriteErrorToConsole(sb.ToString()); }
private static void LogTimeoutError(AssemblyUpdaterUpdateTask[] tasks) { var completedSuccessfully = tasks.Where(t => t.Event.WaitOne(0)); var timedout = tasks.Where(t => !t.Event.WaitOne(0)); var sb = new StringBuilder(L10n.Tr("Timeout while updating assemblies:")); foreach (var updaterTask in timedout) { sb.AppendFormat("{1} (Output: {2}){0}", Environment.NewLine, updaterTask.Candidate.Path, updaterTask.OutputPath); } ReportIgnoredAssembliesDueToPreviousErrors(sb, completedSuccessfully); APIUpdaterLogger.WriteErrorToConsole(sb.ToString()); }
internal static void UpdateAssemblies() { var assembliesToUpdate = GetAssembliesToBeUpdated(); if (assembliesToUpdate.Count == 0) { return; } var assemblyPaths = assembliesToUpdate.Select(c => c.Path); var anyAssemblyInAssetsFolder = assemblyPaths.Any(path => path.IndexOf("Assets/", StringComparison.OrdinalIgnoreCase) != -1); var sw = Stopwatch.StartNew(); var updatedCount = 0; var assembliesToCheckCount = assembliesToUpdate.Count; var tasks = assembliesToUpdate.Select(a => new AssemblyUpdaterUpdateTask(a)).ToArray(); foreach (var task in tasks) { ThreadPool.QueueUserWorkItem(RunAssemblyUpdaterTask, task); } var finishOk = false; var waitEvents = tasks.Select(t => t.Event).ToArray(); var timeout = TimeSpan.FromSeconds(30); if (WaitOnManyEvents(waitEvents, timeout)) { if (!HandleAssemblyUpdaterErrors(tasks)) { updatedCount = ProcessSuccessfulUpdates(tasks); finishOk = updatedCount >= 0; } } else { LogTimeoutError(tasks); } sw.Stop(); APIUpdaterLogger.WriteToFile(L10n.Tr("Update finished with {0} in {1} ms ({2}/{3} assembly(ies) updated)."), finishOk ? L10n.Tr("success") : L10n.Tr("error"), sw.ElapsedMilliseconds, updatedCount >= 0 ? updatedCount : 0, assembliesToCheckCount); PersistListOfAssembliesToUpdate(); }
private static string ResolveAssemblyPath(string assemblyName) { //find the assembly in Data/Managed or Data/Managed/UnityEngine var assemblyFileName = assemblyName + ".dll"; var managedPath = GetUnityEditorManagedPath(); var pathInManagedFolder = Path.Combine(managedPath, assemblyFileName); if (File.Exists(pathInManagedFolder)) { return(pathInManagedFolder); } var pathInUnityEngineFolder = Path.Combine(Path.Combine(managedPath, "UnityEngine"), assemblyFileName); if (File.Exists(pathInUnityEngineFolder)) { return(pathInUnityEngineFolder); } var assetsAssemblies = new HashSet <string>(AssetDatabase.GetAllAssetPaths().Where(assetPath => Path.GetExtension(assetPath) == ".dll").ToArray()); // If the same assembly exist in multiple folders, choose the shortest path one. This ensures that for UnityExtensions we always pick the one at the root of // the extention folder. var resolvedList = assetsAssemblies.Where(a => CompareIgnoreCase(AssemblyNameFromPath(a), assemblyName)).ToArray(); var assemblyPathInAssetsFolder = resolvedList.OrderBy(path => path.Length).FirstOrDefault(); if (resolvedList.Length > 1 && !resolvedList.All(a => a.IsUnityExtension())) { APIUpdaterLogger.WriteToFile("Warning : Multiple matches found for assembly name '{0}'. Shortest path one ({1}) choosen as the source of updates. Full list: {2}", assemblyName, assemblyPathInAssetsFolder, string.Join(Environment.NewLine, resolvedList)); } if (assemblyPathInAssetsFolder != null && (assemblyPathInAssetsFolder.IsInPackage() || assemblyPathInAssetsFolder.IsInAssetsFolder())) { return(assemblyPathInAssetsFolder); } //TODO: In order to support *pre-built* assemblies referencing assemblies (PA) built out of // packages deployed as source code we need to find PA which is located in Library/ScriptAssemblies folder // In this case, we need to look at the mono islands (editorComp.GetAllMonoIslands(EditorScriptCompilationOptions.BuildingForEditor)) // and consider the ones which have its source in packages: // var isInPackage = i._files.Any(path => editorComp.IsPathInPackageDirectory(path)); return(null); }
private static AssemblyDependencyGraph ReadOrCreateAssemblyDependencyGraph(string assemblyDependencyGraphFilePath) { try { if (File.Exists(assemblyDependencyGraphFilePath)) { using (var stream = File.OpenRead(assemblyDependencyGraphFilePath)) { return(AssemblyDependencyGraph.LoadFrom(stream)); } } } catch (IOException e) { APIUpdaterLogger.WriteToFile(string.Format(L10n.Tr("Failed to read assembly dependency graph ({0}). Exception: {1}")), assemblyDependencyGraphFilePath, e); } return(new AssemblyDependencyGraph()); }
internal static void ProcessImportedAssemblies(string[] assemblies) { var sw = Stopwatch.StartNew(); var depGraph = UpdateDependencyGraph(assemblies); var sortedCandidatesForUpdating = FindCandidatesForUpdatingSortedByDependency(assemblies, depGraph); var assembliesToUpdate = GetAssembliesToBeUpdated(); CollectImportedAssembliesToBeUpdated(assembliesToUpdate, sortedCandidatesForUpdating); UpdatePublishUpdaterConfigStatusAndAddDependents(assembliesToUpdate, sortedCandidatesForUpdating, depGraph); SaveDependencyGraph(depGraph, k_AssemblyDependencyGraphFilePath); sw.Stop(); APIUpdaterLogger.WriteToFile(L10n.Tr("Processing imported assemblies took {0} ms ({1}/{2} assemblie(s))."), sw.ElapsedMilliseconds, assembliesToUpdate.Count, sortedCandidatesForUpdating.Count()); UpdateAssemblies(); }
private static bool HandleCheckAssemblyPublishUpdaterConfigErrors(AssemblyUpdaterCheckAssemblyPublishConfigsTask[] nonTimedOutTasks) { var withErrors = nonTimedOutTasks.Where(t => APIUpdaterAssemblyHelper.IsError(t.Result) || t.Exception != null); if (!withErrors.Any()) { return(false); } var sb = new StringBuilder(L10n.Tr("Failed to check following assemblies for updater configurations:\r\n")); foreach (var failledAssemblyInfo in withErrors) { sb.AppendFormat(L10n.Tr("{0} (ret = {1}):\r\n{2}\r\n{3}\r\n"), failledAssemblyInfo.Candidate.Path, failledAssemblyInfo.Result, failledAssemblyInfo.StdOut, failledAssemblyInfo.StdErr); } sb.Append("\r\n--------------"); APIUpdaterLogger.WriteErrorToConsole(sb.ToString()); return(true); }
private static bool HandleAssemblyUpdaterErrors(IEnumerable <AssemblyUpdaterUpdateTask> allTasks) { var tasksWithErrors = allTasks.Where(t => APIUpdaterAssemblyHelper.IsError(t.Result) || APIUpdaterAssemblyHelper.IsUnknown(t.Result) || t.Exception != null); if (!tasksWithErrors.Any()) { return(false); } var sb = new StringBuilder(L10n.Tr("Unable to update following assemblies:")); foreach (var updaterTask in tasksWithErrors) { sb.Append(FormatErrorFromTask(updaterTask)); } ReportIgnoredAssembliesDueToPreviousErrors(sb, allTasks.Except(tasksWithErrors)); APIUpdaterLogger.WriteErrorToConsole(sb.ToString()); return(true); }
private static string ResolveAssemblyPath(string assemblyName) { //find the assembly in Data/Managed or Data/Managed/UnityEngine var assemblyFileName = assemblyName + ".dll"; var managedPath = GetUnityEditorManagedPath(); var pathInManagedFolder = Path.Combine(managedPath, assemblyFileName); if (File.Exists(pathInManagedFolder)) { return(pathInManagedFolder); } var pathInUnityEngineFolder = Path.Combine(Path.Combine(managedPath, "UnityEngine"), assemblyFileName); if (File.Exists(pathInUnityEngineFolder)) { return(pathInUnityEngineFolder); } var assetsAssemblies = new HashSet <string>(AssetDatabase.GetAllAssetPaths().Where(assetPath => Path.GetExtension(assetPath) == ".dll").ToArray()); // If the same assembly exist in multiple folders, choose the shortest path one. var resolvedList = assetsAssemblies.Where(a => CompareIgnoreCase(AssemblyNameFromPath(a), assemblyName)).ToArray(); var assemblyPathInAssetsFolder = resolvedList.OrderBy(path => path.Length).FirstOrDefault(); if (resolvedList.Length > 1) { APIUpdaterLogger.WriteToFile(L10n.Tr("Warning : Multiple matches found for assembly name '{0}'. Shortest path one ({1}) chosen as the source of updates. Full list: {2}"), assemblyName, assemblyPathInAssetsFolder, string.Join(Environment.NewLine, resolvedList)); } if (assemblyPathInAssetsFolder != null && (assemblyPathInAssetsFolder.IsInPackage() || assemblyPathInAssetsFolder.IsInAssetsFolder())) { return(assemblyPathInAssetsFolder); } return(null); }
private static void SaveDependencyGraph(AssemblyDependencyGraph dependencyGraph, string path) { try { var targetDir = Path.GetDirectoryName(path); if (!Directory.Exists(targetDir)) { Directory.CreateDirectory(targetDir); } using (var file = File.Open(path, System.IO.FileMode.Create)) { dependencyGraph.SaveTo(file); } } catch (UnauthorizedAccessException ex) { APIUpdaterLogger.WriteToFile(string.Format(L10n.Tr("Failed to save assembly dependency graph ({0}). Exception: {1}")), path, ex); } catch (IOException ex) { APIUpdaterLogger.WriteToFile(string.Format(L10n.Tr("Failed to save assembly dependency graph ({0}). Exception: {1}")), path, ex); } }
internal static void UpdateAssemblies() { var assembliesToUpdate = GetAssembliesToBeUpdated(); if (assembliesToUpdate.Count == 0) { return; } var assemblyPaths = assembliesToUpdate.Select(c => c.Path); var anyAssemblyInAssetsFolder = assemblyPaths.Any(path => path.IndexOf("Assets/", StringComparison.OrdinalIgnoreCase) != -1); // Only try to connect to VCS if there are files under VCS that need to be updated if (anyAssemblyInAssetsFolder) { var failedToConnectToVcs = false; if (WaitForVCSServerConnection(true)) { failedToConnectToVcs = Provider.enabled && !APIUpdaterHelper.CheckoutAndValidateVCSFiles(assemblyPaths); } if (failedToConnectToVcs) { assembliesToUpdate.Clear(); return; } } var sw = Stopwatch.StartNew(); var updatedCount = 0; var assembliesToCheckCount = assembliesToUpdate.Count; var tasks = assembliesToUpdate.Select(a => new AssemblyUpdaterUpdateTask(a)).ToArray(); foreach (var task in tasks) { CollectAssemblyObsoleteAPIUsage(task.Candidate.Path); ThreadPool.QueueUserWorkItem(RunAssemblyUpdaterTask, task); } var finishOk = false; var waitEvents = tasks.Select(t => t.Event).ToArray(); var timeout = TimeSpan.FromSeconds(30); if (WaitHandle.WaitAll(waitEvents, timeout)) { if (!HandleAssemblyUpdaterErrors(tasks)) { updatedCount = ProcessSuccessfulUpdates(tasks); finishOk = true; } } else { LogTimeoutError(tasks); } sw.Stop(); APIUpdaterLogger.WriteToFile(L10n.Tr("Update finished with {0} in {1} ms ({2}/{3} assemblie(s) updated)."), finishOk ? L10n.Tr("success") : L10n.Tr("error"), sw.ElapsedMilliseconds, updatedCount, assembliesToCheckCount); if (updatedCount > 0 && !EditorCompilationInterface.Instance.DoesProjectFolderHaveAnyScripts()) { ReportPossibleUpdateFinished(false); } PersistListOfAssembliesToUpdate(); }
private static int ProcessSuccessfulUpdates(AssemblyUpdaterUpdateTask[] tasks) { var assembliesToUpdate = GetAssembliesToBeUpdated(); var succeededUpdates = tasks.Where(t => t.Result == APIUpdaterAssemblyHelper.UpdatesApplied); if (!succeededUpdates.Any()) { assembliesToUpdate.Clear(); return(0); } var assembliesRequiringConsent = FilterOutLocalAndEmbeddedPackagesWhenAskingForConsent(assembliesToUpdate.Select(a => a.Path)).ToArray(); if (assembliesRequiringConsent.Length > 0 && !AskForConsent(assembliesRequiringConsent)) { APIUpdaterLogger.WriteToFile(L10n.Tr("User declined to run APIUpdater")); return(0); } var updatedAssemblyPaths = succeededUpdates.Select(u => u.Candidate.Path).ToArray(); if (!CheckoutFromVCSIfNeeded(updatedAssemblyPaths)) { return(-1); } APIUpdaterHelper.HandleFilesInPackagesVirtualFolder(updatedAssemblyPaths); if (!APIUpdaterHelper.CheckReadOnlyFiles(updatedAssemblyPaths)) { return(0); } foreach (var succeed in succeededUpdates) { APIUpdaterLogger.WriteToFile("{0}{1}", Environment.NewLine, succeed.StdOut); FileUtil.MoveFileIfExists(succeed.OutputPath, succeed.Candidate.Path); } assembliesToUpdate.Clear(); return(succeededUpdates.Count()); bool CheckoutFromVCSIfNeeded(string[] assemblyPathsToCheck) { // Only try to connect to VCS if there are files under VCS that need to be updated var assembliesInAssetsFolder = assemblyPathsToCheck.Where(path => path.IndexOf("Assets/", StringComparison.OrdinalIgnoreCase) != -1).ToArray(); if (!assembliesInAssetsFolder.Any()) { return(true); } if (!WaitForVCSServerConnection()) { return(false); } var failedToCheckoutFiles = !APIUpdaterHelper.MakeEditable(assembliesInAssetsFolder); if (failedToCheckoutFiles) { assembliesToUpdate.Clear(); return(false); } return(true); } IEnumerable <string> FilterOutLocalAndEmbeddedPackagesWhenAskingForConsent(IEnumerable <string> ass) { foreach (var path in ass.Select(path => path.Replace("\\", "/"))) // package manager paths are always separated by / { var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(path); if (packageInfo == null || packageInfo.source == PackageSource.Local || packageInfo.source == PackageSource.Embedded) { yield return(path); } } } }