using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using OpenTap.Cli; namespace OpenTap.Package { /// /// Checks packages for updates /// [Browsable(false)] [Display("check-updates", "Checks for update for installed packages.", "package")] internal class UpdateCheck : ICliAction { /// /// Used to specify if PackageManagerSettings.CheckForUpdates should be checked before executing. /// [Browsable(false)] [CommandLineArgument("startup")] public bool Startup { get; set; } static readonly TraceSource Log = OpenTap.Log.CreateSource("UpdateCheck"); private void CheckForUpdatesAsync(CancellationToken cancellationToken) { string noUpdateCheckEnv = Environment.GetEnvironmentVariable("OPENTAP_NO_UPDATE_CHECK"); bool noUpdateCheck = noUpdateCheckEnv == "true" || noUpdateCheckEnv == "1"; if (Startup && (PackageManagerSettings.Current.CheckForUpdates == false || noUpdateCheck)) return; // Since we are deciding to do the update check for the parent process there is no reason to also // do it for the child processes. Environment.SetEnvironmentVariable("OPENTAP_NO_UPDATE_CHECK", "true"); string noUpdateMessageEnv = Environment.GetEnvironmentVariable("OPENTAP_NO_UPDATE_MESSAGE"); bool noUpdateMessage = noUpdateMessageEnv == "true" || noUpdateMessageEnv == "1"; var timer = Stopwatch.StartNew(); List updates = new List(); var installation = new Installation(ExecutorClient.ExeDir); IPackageIdentifier[] installedPackages = installation.GetPackages().ToArray(); Parallel.ForEach(PackageManagerSettings.Current.GetEnabledRepositories(null), repo => { try { updates.AddRange(repo.CheckForUpdates(installedPackages, cancellationToken)); } catch (Exception ex) { if (noUpdateMessage) Log.Debug("Update check against {0} failed. See debug messages for details.", repo.Url); else Log.Warning("Update check against {0} failed. See debug messages for details.", repo.Url); Log.Debug(ex); } }); if (noUpdateMessage) return; using var _ = CliUserInputInterface.AcquireUserInputLock(); if (updates.Any()) { Log.Info("Updates available for:"); foreach (var update in updates.GroupBy(p => p.Name)) { var currentPackage = installedPackages.FirstOrDefault(p => p.Name == update.Key); var updatedPackage = update.OrderByDescending(p => p.Version).FirstOrDefault(); Log.Info($" - {update.Key}: {currentPackage?.Version} -> {updatedPackage?.Version}"); } } else { Log.Debug(timer, "Update check completed."); if (!Startup) Log.Info("All installed packages are up to date."); } } /// /// Runs the check for updates action. /// /// /// public int Execute(CancellationToken cancellationToken) { CheckForUpdatesAsync(cancellationToken); return (int) ExitCodes.Success; } } }