From 7def79624912afd6fe09da88a09a33eb9af2921a Mon Sep 17 00:00:00 2001 From: "Aaron (Qilong)" <173288704@qq.com> Date: Mon, 4 Dec 2023 05:06:02 -0500 Subject: [PATCH] DYN-5873 Removal of Update Manager (#14632) * Removal of Update Manager * Remove UpdateManager CleanUp * Update * Clean Up * Update to rely on PathResolver so integrators can implement GetDynamoUserDataLocations() differently * Null check for PathResolver * Comments --- src/DynamoApplications/PathResolvers.cs | 38 +- src/DynamoApplications/StartupUtils.cs | 59 - src/DynamoCore/Configuration/IPathResolver.cs | 15 + src/DynamoCore/Configuration/PathManager.cs | 21 + src/DynamoCore/Core/DynamoMigrator.cs | 47 +- src/DynamoCore/Models/DynamoModel.cs | 43 +- src/DynamoCore/Updates/UpdateManager.cs | 1386 ----------------- .../GraphUpdateNotificationControl.xaml | 60 - .../GraphUpdateNotificationControl.xaml.cs | 36 - src/DynamoCoreWpf/DynamoCoreWpf.csproj | 7 - src/DynamoCoreWpf/UI/Converters.cs | 42 - .../Themes/Modern/DynamoColorsAndBrushes.xaml | 4 - .../UI/Themes/Modern/DynamoConverters.xaml | 2 - .../ViewModels/Core/DynamoViewModel.cs | 37 +- .../Views/About/AboutWindow.xaml | 13 +- test/DynamoCoreTests/UpdateManagerTests.cs | 465 ------ test/DynamoCoreTests/Updates/UpdatesTests.cs | 238 --- .../DynamoCoreTests/UserDataMigrationTests.cs | 42 +- .../UpdateManagerUITests.cs | 31 - .../SystemTestServices/SystemTestBase.cs | 3 - .../TestServices/TestPathResolver.cs | 9 +- .../HelixWatch3DViewModelTests.cs | 1 - 22 files changed, 143 insertions(+), 2456 deletions(-) delete mode 100644 src/DynamoCore/Updates/UpdateManager.cs delete mode 100644 src/DynamoCoreWpf/Controls/GraphUpdateNotificationControl.xaml delete mode 100644 src/DynamoCoreWpf/Controls/GraphUpdateNotificationControl.xaml.cs delete mode 100644 test/DynamoCoreTests/UpdateManagerTests.cs delete mode 100644 test/DynamoCoreTests/Updates/UpdatesTests.cs delete mode 100644 test/DynamoCoreWpfTests/UpdateManagerUITests.cs diff --git a/src/DynamoApplications/PathResolvers.cs b/src/DynamoApplications/PathResolvers.cs index fa2502df346..fc8bf9b835f 100644 --- a/src/DynamoApplications/PathResolvers.cs +++ b/src/DynamoApplications/PathResolvers.cs @@ -1,5 +1,7 @@ +using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Dynamo.Interfaces; namespace Dynamo.Applications @@ -58,13 +60,41 @@ public IEnumerable PreloadedLibraryPaths public string UserDataRootFolder { - get { return string.Empty; } + get { return Path.Combine(Environment.GetFolderPath( + Environment.SpecialFolder.ApplicationData), + "Dynamo", "Dynamo Core").ToString(); } } public string CommonDataRootFolder { get { return string.Empty; } } + + /// + /// Returns the full path of user data location of all version of this + /// Dynamo product installed on this system. The default implementation + /// returns list of all subfolders in %appdata%\Dynamo as well as + /// %appdata%\Dynamo\Dynamo Core\ folders. + /// + /// + public IEnumerable GetDynamoUserDataLocations() + { + var appDatafolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var dynamoFolder = Path.Combine(appDatafolder, "Dynamo"); + if (!Directory.Exists(dynamoFolder)) return Enumerable.Empty(); + + var paths = new List(); + var coreFolder = new FileInfo(UserDataRootFolder).FullName; + //Dynamo Core folder has to be enumerated first to cater migration from + //Dynamo 1.0 to Dynamo Core 1.0 + if (Directory.Exists(coreFolder)) + { + paths.AddRange(Directory.EnumerateDirectories(coreFolder)); + } + + paths.AddRange(Directory.EnumerateDirectories(dynamoFolder)); + return paths; + } } internal class CLIPathResolver : IPathResolver @@ -125,5 +155,11 @@ public IEnumerable PreloadedLibraryPaths public string UserDataRootFolder { get; private set; } public string CommonDataRootFolder { get; private set; } + + public IEnumerable GetDynamoUserDataLocations() + { + // Do nothing for now. + return Enumerable.Empty(); + } } } diff --git a/src/DynamoApplications/StartupUtils.cs b/src/DynamoApplications/StartupUtils.cs index c53b4144de0..d45ba8928e0 100644 --- a/src/DynamoApplications/StartupUtils.cs +++ b/src/DynamoApplications/StartupUtils.cs @@ -75,48 +75,6 @@ public static class StartupUtils /// public static event Action ASMPreloadFailure; -#if NET6_0_OR_GREATER - [System.Runtime.Versioning.SupportedOSPlatform("windows")] -#endif - internal class SandboxLookUp : DynamoLookUp - { - public override IEnumerable GetDynamoInstallLocations() - { - const string regKey64 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"; - //Open HKLM for 64bit registry - var regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); - //Open Windows/CurrentVersion/Uninstall registry key - regKey = regKey.OpenSubKey(regKey64); - - //Get "InstallLocation" value as string for all the subkey that starts with "Dynamo" - return regKey.GetSubKeyNames().Where(s => s.StartsWith("Dynamo")).Select( - (s) => regKey.OpenSubKey(s).GetValue("InstallLocation") as string); - } - } - - /// - ///this class is left unimplemented,unclear how to - ///lookup installation locations on nix/mac - /// - internal class CLILookUp : DynamoLookUp - { - public override IEnumerable GetDynamoInstallLocations() - { - throw new NotImplementedException(); - int p = (int)Environment.OSVersion.Platform; - if ((p == 4) || (p == 6) || (p == 128)) - { - Console.WriteLine("Running on Unix"); - } - else - { - Console.WriteLine("NOT running on Unix"); - } - - return null; - } - } - public struct CommandLineArguments { public static CommandLineArguments Parse(string[] args) @@ -211,22 +169,6 @@ public static void PreloadShapeManager(ref string geometryFactoryPath, ref strin preloaderLocation = preloader.PreloaderLocation; } - /// - ///if we are building a model for CLI mode, then we don't want to start an updateManager - ///for now, building an updatemanager instance requires finding Dynamo install location - ///which if we are running on mac os or *nix will use different logic then SandboxLookup - /// -#if NET6_0_OR_GREATER - [System.Runtime.Versioning.SupportedOSPlatform("windows")] -#endif - private static IUpdateManager InitializeUpdateManager() - { - var cfg = UpdateManagerConfiguration.GetSettings(new SandboxLookUp()); - var um = new Dynamo.Updates.UpdateManager(cfg); - Debug.Assert(cfg.DynamoLookUp != null); - return um; - } - /// /// Use this overload to construct a DynamoModel in CLI context when the location of ASM to use is known, host analytics info is known and you want to set data paths. /// @@ -391,7 +333,6 @@ private static DynamoModel StartDynamoWithDefaultConfig(bool CLImode, HostAnalyticsInfo = info, CLIMode = CLImode, AuthProvider = CLImode || noNetworkMode ? null : new Core.IDSDKManager(), - UpdateManager = CLImode ? null : OSHelper.IsWindows() ? InitializeUpdateManager() : null, StartInTestMode = CLImode, PathResolver = CreatePathResolver(CLImode, preloaderLocation, userDataFolder, commonDataFolder), IsServiceMode = isServiceMode, diff --git a/src/DynamoCore/Configuration/IPathResolver.cs b/src/DynamoCore/Configuration/IPathResolver.cs index cb0aabaed44..2a28ec40a0d 100644 --- a/src/DynamoCore/Configuration/IPathResolver.cs +++ b/src/DynamoCore/Configuration/IPathResolver.cs @@ -58,6 +58,16 @@ public interface IPathResolver /// as it will be appended by PathManager. /// string CommonDataRootFolder { get; } + + /// + /// Returns a list of user data folders on this system. + /// + /// + /// The implementation of this interface method should return a list of user + /// data folders, one for each of Dynamo product installed on the system. When + /// there is no Dynamo product installed, this method returns an empty list. + /// + IEnumerable GetDynamoUserDataLocations(); } /// @@ -189,6 +199,11 @@ public interface IPathManager /// int MinorFileVersion { get; } + /// + /// Integration specific PathResolver + /// + IPathResolver PathResolver { get; } + /// /// Call this method to add additional path for consideration when path /// resolution take place. diff --git a/src/DynamoCore/Configuration/PathManager.cs b/src/DynamoCore/Configuration/PathManager.cs index 059bc121bd4..a05e97f7f1c 100644 --- a/src/DynamoCore/Configuration/PathManager.cs +++ b/src/DynamoCore/Configuration/PathManager.cs @@ -76,6 +76,7 @@ internal static Lazy private readonly int majorFileVersion; private readonly int minorFileVersion; + private Updates.BinaryVersion productVersion; private readonly string dynamoCoreDir; private string hostApplicationDirectory; private string userDataDir; @@ -102,6 +103,14 @@ internal static Lazy internal IPreferences Preferences { get; set; } + /// + /// PathResolver is used to resolve paths for custom nodes, packages, and preloaded libraries. + /// + public IPathResolver PathResolver + { + get { return pathResolver; } + } + private IEnumerable RootDirectories { get @@ -631,6 +640,18 @@ internal string GetUserDataFolder() return GetDynamoDataFolder(Path.Combine(folder, "Dynamo", "Dynamo Core")); } + /// + /// Returns the current Dynamo product version. + /// + /// + public Updates.BinaryVersion GetProductVersion() + { + if (null != productVersion) return productVersion; + var executingAssemblyName = Assembly.GetExecutingAssembly().GetName(); + productVersion = Updates.BinaryVersion.FromString(executingAssemblyName.Version.ToString()); + return productVersion; + } + private string GetCommonDataFolder() { if (pathResolver != null && !string.IsNullOrEmpty(pathResolver.CommonDataRootFolder)) diff --git a/src/DynamoCore/Core/DynamoMigrator.cs b/src/DynamoCore/Core/DynamoMigrator.cs index 87b5fb484cd..85f87cf4299 100644 --- a/src/DynamoCore/Core/DynamoMigrator.cs +++ b/src/DynamoCore/Core/DynamoMigrator.cs @@ -183,13 +183,12 @@ protected virtual DynamoMigratorBase MigrateFrom(DynamoMigratorBase sourceMigrat /// definitions from the last but one version to the currently installed Dynamo version /// /// - /// /// new migrator instance after migration - public static DynamoMigratorBase MigrateBetweenDynamoVersions(IPathManager pathManager, IDynamoLookUp dynamoLookup = null) + public static DynamoMigratorBase MigrateBetweenDynamoVersions(IPathManager pathManager) { //Get the current version from the current path manager user data directory. var currentVersion = GetInstallVersionFromUserDataFolder(pathManager.UserDataDirectory); - var previousVersion = GetLatestVersionToMigrate(pathManager, dynamoLookup, currentVersion); + var previousVersion = GetLatestVersionToMigrate(pathManager, currentVersion); if (!previousVersion.HasValue || previousVersion.Value.UserDataRoot == null) return null; //Don't have previous version for migration @@ -201,12 +200,11 @@ public static DynamoMigratorBase MigrateBetweenDynamoVersions(IPathManager pathM /// Returns the most recent version to migrate to the given current version. /// /// - /// /// /// FileVersion? - public static FileVersion? GetLatestVersionToMigrate(IPathManager pathManager, IDynamoLookUp dynamoLookup, FileVersion currentVersion) + public static FileVersion? GetLatestVersionToMigrate(IPathManager pathManager, FileVersion currentVersion) { - var versions = GetInstalledVersions(pathManager, dynamoLookup); + var versions = GetInstalledVersions(pathManager); if (versions.Count() < 2) return null; // No need for migration @@ -265,17 +263,14 @@ public static IEnumerable GetInstalledVersions(string rootFolder) } /// - /// Returns list of FileVersion objects, given the IPathManager and - /// IDynamoLookUp objects. If a valid IDynamoLookUp interface object - /// is passed, this method uses the lookup to get Dynamo user data locations. + /// Returns list of FileVersion objects, given the IPathManager. /// /// - /// /// - public static IEnumerable GetInstalledVersions(IPathManager pathManager, IDynamoLookUp dynamoLookup) + public static IEnumerable GetInstalledVersions(IPathManager pathManager) { - return dynamoLookup != null - ? GetInstalledVersionsCore(() => dynamoLookup.GetDynamoUserDataLocations()) + var installedVersions = GetInstalledVersionsCore(() => pathManager.PathResolver != null? pathManager.PathResolver.GetDynamoUserDataLocations() : Enumerable.Empty()); + return installedVersions.Any() ? installedVersions : GetInstalledVersions(Path.GetDirectoryName(pathManager.UserDataDirectory)); } @@ -403,6 +398,32 @@ public string CommonDataRootFolder { get { return string.Empty; } } + + /// + /// Returns the full path of user data location of all version of this + /// Dynamo product installed on this system. The default implementation + /// returns list of all subfolders in %appdata%\Dynamo as well as + /// %appdata%\Dynamo\Dynamo Core\ folders. + /// + /// + public IEnumerable GetDynamoUserDataLocations() + { + var appDatafolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var dynamoFolder = Path.Combine(appDatafolder, "Dynamo"); + if (!Directory.Exists(dynamoFolder)) return Enumerable.Empty(); + + var paths = new List(); + var coreFolder = new FileInfo(UserDataRootFolder).FullName; + //Dynamo Core folder has to be enumerated first to cater migration from + //Dynamo 1.0 to Dynamo Core 1.0 + if (Directory.Exists(coreFolder)) + { + paths.AddRange(Directory.EnumerateDirectories(coreFolder)); + } + + paths.AddRange(Directory.EnumerateDirectories(dynamoFolder)); + return paths; + } } } diff --git a/src/DynamoCore/Models/DynamoModel.cs b/src/DynamoCore/Models/DynamoModel.cs index 996e074533b..4bca507d88a 100644 --- a/src/DynamoCore/Models/DynamoModel.cs +++ b/src/DynamoCore/Models/DynamoModel.cs @@ -34,7 +34,6 @@ using Dynamo.Search; using Dynamo.Search.SearchElements; using Dynamo.Selection; -using Dynamo.Updates; using Dynamo.Utilities; using DynamoServices; using Greg; @@ -46,7 +45,6 @@ using ProtoCore.Runtime; using Compiler = ProtoAssociative.Compiler; // Dynamo package manager -using DefaultUpdateManager = Dynamo.Updates.UpdateManager; using FunctionGroup = Dynamo.Engine.FunctionGroup; using Symbol = Dynamo.Graph.Nodes.CustomNodes.Symbol; using Utils = Dynamo.Graph.Nodes.Utilities; @@ -98,11 +96,13 @@ public static DynamoPreferencesData Default() /// public struct HostAnalyticsInfo { - /// Dynamo variation identified by host. + // Dynamo variation identified by host. public string HostName; - /// Dynamo host parent id for analytics purpose. + // Dynamo variation version specific to host + public Version HostVersion; + // Dynamo host parent id for analytics purpose. public string ParentId; - /// Dynamo host session id for analytics purpose. + // Dynamo host session id for analytics purpose. public string SessionId; } @@ -200,7 +200,7 @@ internal LuceneSearchUtility LuceneUtility /// public static string Version { - get { return DefaultUpdateManager.GetProductVersion().ToString(); } + get { return Core.PathManager.Instance.GetProductVersion().ToString(); } } /// @@ -229,11 +229,6 @@ public static string Version /// internal bool NoNetworkMode { get; } - /// - /// UpdateManager to handle automatic upgrade to higher version. - /// - public IUpdateManager UpdateManager { get; private set; } - /// /// The path manager that configures path information required for /// Dynamo to function properly. See IPathManager interface for more @@ -292,7 +287,7 @@ internal static string AppVersion get { return Process.GetCurrentProcess().ProcessName + "-" - + DefaultUpdateManager.GetProductVersion(); + + Core.PathManager.Instance.GetProductVersion(); } } @@ -517,7 +512,6 @@ public interface IStartConfiguration IPreferences Preferences { get; set; } IPathResolver PathResolver { get; set; } bool StartInTestMode { get; set; } - IUpdateManager UpdateManager { get; set; } ISchedulerThread SchedulerThread { get; set; } string GeometryFactoryPath { get; set; } IAuthProvider AuthProvider { get; set; } @@ -575,7 +569,6 @@ public struct DefaultStartConfiguration : IStartConfiguration public IPreferences Preferences { get; set; } public IPathResolver PathResolver { get; set; } public bool StartInTestMode { get; set; } - public IUpdateManager UpdateManager { get; set; } public ISchedulerThread SchedulerThread { get; set; } public string GeometryFactoryPath { get; set; } public IAuthProvider AuthProvider { get; set; } @@ -699,14 +692,8 @@ protected DynamoModel(IStartConfiguration config) PreferenceSettings.MessageLogged += LogMessage; } - UpdateManager = config.UpdateManager ?? new DefaultUpdateManager(null); - - if (UpdateManager != null) - { - // For API compatibility now in Dynamo 2.0, integrators can set HostName in both ways - HostName = string.IsNullOrEmpty(UpdateManager.HostName) ? HostAnalyticsInfo.HostName : UpdateManager.HostName; - HostVersion = UpdateManager.HostVersion?.ToString(); - } + HostName = HostAnalyticsInfo.HostName; + HostVersion = HostAnalyticsInfo.HostVersion?.ToString(); bool areAnalyticsDisabledFromConfig = false; if (!IsServiceMode) @@ -766,10 +753,7 @@ protected DynamoModel(IStartConfiguration config) try { - var dynamoLookup = config.UpdateManager != null && config.UpdateManager.Configuration != null - ? config.UpdateManager.Configuration.DynamoLookUp : null; - - migrator = DynamoMigratorBase.MigrateBetweenDynamoVersions(pathManager, dynamoLookup); + migrator = DynamoMigratorBase.MigrateBetweenDynamoVersions(pathManager); } catch (Exception e) { @@ -932,12 +916,6 @@ protected DynamoModel(IStartConfiguration config) AuthenticationManager = new AuthenticationManager(config.AuthProvider); } - UpdateManager.Log += UpdateManager_Log; - if (!IsTestMode && !IsHeadless && !IsServiceMode && !config.NoNetworkMode) - { - DefaultUpdateManager.CheckForProductUpdate(UpdateManager); - } - Logger.Log(string.Format("Dynamo -- Build {0}", Assembly.GetExecutingAssembly().GetName().Version)); @@ -1410,7 +1388,6 @@ public void Dispose() EngineController.VMLibrariesReset -= ReloadDummyNodes; - UpdateManager.Log -= UpdateManager_Log; Logger.Dispose(); EngineController.Dispose(); diff --git a/src/DynamoCore/Updates/UpdateManager.cs b/src/DynamoCore/Updates/UpdateManager.cs deleted file mode 100644 index c78d25e132b..00000000000 --- a/src/DynamoCore/Updates/UpdateManager.cs +++ /dev/null @@ -1,1386 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Xml.Linq; -using System.Xml.Serialization; -using Autodesk.Analytics.Core; -using Dynamo.Core; -using Dynamo.Logging; - -namespace Dynamo.Updates -{ - /// - /// Represents the method that will handle events. - /// - /// The object where the event handler is attached. - /// The event data. - public delegate void UpdateDownloadedEventHandler(object sender, UpdateDownloadedEventArgs e); - - /// - /// A delegate used to handle shutdown request - /// - public delegate void ShutdownRequestedEventHandler(IUpdateManager updateManager); - - /// - /// Provides data for events. - /// - public class UpdateDownloadedEventArgs : EventArgs - { - /// - /// Initializes a new instance of the class - /// with the error and the update location - /// - /// The exception thrown during downloading update. - /// Null if update is downloaded successfully. - /// Location where the update has been downloaded to. - public UpdateDownloadedEventArgs(Exception error, string fileLocation) - { - Error = error; - UpdateFileLocation = fileLocation; - UpdateAvailable = !string.IsNullOrEmpty(fileLocation); - } - - /// - /// Returns flag which indicates if update has been downloaded. - /// - public bool UpdateAvailable { get; private set; } - - /// - /// Returns location where the update has been downloaded to. - /// - public string UpdateFileLocation { get; private set; } - - /// - /// Returns exception thrown during downloading update. - /// Null if update is downloaded successfully. - /// - public Exception Error { get; private set; } - } - - /// - /// An interface which describes properties and methods for - /// updating the application. - /// - public interface IUpdateManager - { - /// - /// Returns current product version. - /// - BinaryVersion ProductVersion { get; } - - /// - /// Returns available product version. - /// - BinaryVersion AvailableVersion { get; } - - /// - /// Returns information, where version can be updated. - /// - IAppVersionInfo UpdateInfo { get; set; } - - /// - /// Bool value indicates if new version is available. - /// - bool IsUpdateAvailable { get; } - - /// - /// Event is fired when an update is downloaded. - /// - event UpdateDownloadedEventHandler UpdateDownloaded; - - /// - /// Event is fired when Dynamo needs to be restarted. - /// - event ShutdownRequestedEventHandler ShutdownRequested; - - /// - /// Checks for product updates in background thread. - /// - /// Asynchronous web request for update data - void CheckForProductUpdate(IAsynchronousRequest request); - - /// - /// Quits and installs new version. - /// - void QuitAndInstallUpdate(); - - /// - /// This function is called when a Dynamo Model is shutting down. - /// - void HostApplicationBeginQuit(); - - /// - /// Reads the request's data, and parses for available versions. - /// If a more recent version is available, the UpdateInfo object - /// will be set. - /// - /// Asynchronous request - void UpdateDataAvailable(IAsynchronousRequest request); - - /// - /// This flag is available via the debug menu to - /// allow the update manager to check for newer daily builds. - /// - bool CheckNewerDailyBuilds { get; set; } - - /// - /// Specifies whether to force update. - /// - bool ForceUpdate { get; set; } - - /// - /// Returns a reference to Update Manager Configuration settings. - /// - IUpdateManagerConfiguration Configuration { get; } - - /// - /// Event fires, when something should be logged. - /// - event LogEventHandler Log; - - /// - /// This function logs a message. - /// - /// LogEventArgs - void OnLog(LogEventArgs args); - - /// - /// Sets application process id. It's used for logging. - /// - /// int - void RegisterExternalApplicationProcessId(int id); - - /// - /// Get the current version of the Host - /// - Version HostVersion { get; set; } - - /// - /// Get the current name of the Host - /// - String HostName { get; set; } - } - - /// - /// Interface provides methods, that get installed Dynamo paths and the last Dynamo version. - /// - public interface IDynamoLookUp - { - /// - /// Returns installation path for all version of this Dynamo Product - /// installed on this system. - /// - IEnumerable GetDynamoInstallLocations(); - - /// - /// Returns a list of user data folders on this system. - /// - /// - /// The implementation of this interface method should return a list of user - /// data folders, one for each of Dynamo product installed on the system. When - /// there is no Dynamo product installed, this method returns an empty list. - /// - IEnumerable GetDynamoUserDataLocations(); - - /// - /// Returns the version of latest installed product - /// - BinaryVersion LatestProduct { get; } - } - - /// - /// This interface represents configuration properties for Update manager. - /// - public interface IUpdateManagerConfiguration - { - /// - /// Specifies download location for new installer - /// - string DownloadSourcePath { get; set; } - - /// - /// Specifies location for signature file to validate the new installer. - /// - string SignatureSourcePath { get; set; } - - /// - /// Specifies whether to consider daily builds for update, default is false. - /// - bool CheckNewerDailyBuild { get; set; } - - /// - /// Specifies whether to force update, default value is false. - /// - bool ForceUpdate { get; set; } - - /// - /// Returns the base name of the installer to be used for upgrade. - /// - string InstallerNameBase { get; set; } - - /// - /// Returns IDynamoLookUp interface to search Dynamo installations on the system. - /// - IDynamoLookUp DynamoLookUp { get; set; } - } - - /// - /// This interface represents configuration properties for Disable Update. - /// - public interface IDisableUpdateConfig - { - /// - /// Specifies whether to disable update, default value is false. - /// - Boolean DisableUpdates { get; set; } - } - - /// - /// An interface to describe available - /// application update info. - /// - public interface IAppVersionInfo - { - BinaryVersion Version { get; set; } - string VersionInfoURL { get; set; } - string InstallerURL { get; set; } - string SignatureURL { get; set; } - } - - /// - /// An interface to describe an asynchronous web - /// request for updating data. - /// - public interface IAsynchronousRequest - { - /// - /// The data returned from the request. - /// - string Data { get; set; } - - /// - /// Any error information returned from the request. - /// - string Error { get; set; } - - /// - /// Represents the send request link. - /// - Uri Path { get; set; } - - /// - /// An action to be invoked upon completion of the request. - /// This action is invoked regardless of the success of the request. - /// - Action OnRequestCompleted { get; set; } - } - - /// - /// This class returns of Dynamo - /// - public class AppVersionInfo : IAppVersionInfo - { - /// - /// Returns current Dynamo version - /// - public BinaryVersion Version { get; set; } - - /// - /// Returns URL where one can get information about - /// current Dynamo version - /// - public string VersionInfoURL { get; set; } - - /// - /// Returns URL where Dynamo installer can be downloaded from - /// - public string InstallerURL { get; set; } - - /// - /// Returns URL where signature file to validate the new installer can be downloaded from - /// - public string SignatureURL { get; set; } - } - - /// - /// The UpdateRequest class encapsulates a request for - /// getting update information from the web. - /// - internal class UpdateRequest : IAsynchronousRequest - { - /// - /// An action to be invoked upon completion of the request. - /// This action is invoked regardless of the success of the request. - /// - public Action OnRequestCompleted { get; set; } - - /// - /// The data returned from the request. - /// - public string Data { get; set; } - - /// - /// Any error information returned from the request. - /// - public string Error { get; set; } - - public Uri Path { get; set; } - - /// - /// UpdateManager instance that created this request. - /// - private readonly IUpdateManager manager = null; - - /// - /// The constructor. - /// - /// Uri that needs to be read to get the update information. - /// The update manager which is making this request. - public UpdateRequest(Uri path, IUpdateManager manager) - { - OnRequestCompleted = manager.UpdateDataAvailable; - this.manager = manager; - - Error = string.Empty; - Data = string.Empty; - Path = path; - - var client = new WebClient(); - client.OpenReadAsync(path); - client.OpenReadCompleted += ReadResult; - } - - /// - /// Event handler for the web client's requestion completed event. Reads - /// the request result information and subsequently triggers - /// the UpdateDataAvailable event. - /// - /// - /// - private void ReadResult(object sender, OpenReadCompletedEventArgs e) - { - try - { - if (null == e || e.Error != null) - { - Error = "Unspecified error"; - if (null != e && (null != e.Error)) - Error = e.Error.Message; - } - - using (var sr = new StreamReader(e.Result)) - { - Data = sr.ReadToEnd(); - } - } - catch (Exception ex) - { - Error = string.Empty; - Data = string.Empty; - - manager.OnLog(new LogEventArgs("The update request could not be completed.", LogLevel.File)); - manager.OnLog(new LogEventArgs(ex, LogLevel.File)); - } - - //regardless of the success of the above logic - //invoke the completion callback - OnRequestCompleted.Invoke(this); - } - } - - /// - /// Specifies Update Manager Configuration settings. - /// - public class UpdateManagerConfiguration : IUpdateManagerConfiguration,IDisableUpdateConfig - { - private const string PRODUCTION_SOURCE_PATH_S = "http://dyn-builds-data.s3.amazonaws.com/"; - private const string PRODUCTION_SIG_SOURCE_PATH_S = "http://dyn-builds-data-sig.s3.amazonaws.com/"; - private const string DEFAULT_CONFIG_FILE_S = "UpdateManagerConfig.xml"; - private const string INSTALL_NAME_BASE = "DynamoInstall"; - - /// - /// Specifies download location for new installer - /// - public string DownloadSourcePath { get; set; } - - /// - /// Specifies location for signature file to validate the new installer. - /// - public string SignatureSourcePath { get; set; } - - /// - /// Specifies whether to consider daily builds for update, default is false. - /// - public bool CheckNewerDailyBuild { get; set; } - - /// - /// Specifies whether to force update, default value is false. - /// - public bool ForceUpdate { get; set; } - - /// - /// Returns the base name of the installer to be used for upgrade. - /// - public string InstallerNameBase { get; set; } - - /// - /// Return file path for the overriding config file. - /// - [XmlIgnore] - public string ConfigFilePath { get; set; } - - /// - /// Specifies whether to disable update, default value is false. - /// - public Boolean DisableUpdates { get; set; } - - /// - /// Default constructor - /// - public UpdateManagerConfiguration() - { - DownloadSourcePath = PRODUCTION_SOURCE_PATH_S; - SignatureSourcePath = PRODUCTION_SIG_SOURCE_PATH_S; - CheckNewerDailyBuild = false; - ForceUpdate = false; - InstallerNameBase = INSTALL_NAME_BASE; - DisableUpdates = false; - } - - /// - /// Loads the configurations from given xml file. - /// - /// Xml file path that contains configuration details. - /// IUpdateManager object which can log errors during loading. - /// Loaded UpdateManagerConfiguration. - public static UpdateManagerConfiguration Load(string filePath, IUpdateManager updateManager) - { - if(string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) - return null; - - try - { - var serializer = new XmlSerializer(typeof(UpdateManagerConfiguration)); - using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) - { - var config = serializer.Deserialize(fs) as UpdateManagerConfiguration; - if(null != config) - config.ConfigFilePath = filePath; - return config; - } - } - catch (Exception ex) - { - if (null != updateManager) - updateManager.OnLog( - new LogEventArgs( - string.Format( - Properties.Resources.FailedToLoad, - filePath, - ex.Message), - LogLevel.Console)); - else throw; - } - return null; - } - - /// - /// Saves this configuration to a given file in xml format. - /// - /// File path to save this configuration. - /// IUpdateManager object which can log errors during saving. - public void Save(string filePath, IUpdateManager updateManager) - { - try - { - var serializer = new XmlSerializer(typeof(UpdateManagerConfiguration)); - using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) - { - serializer.Serialize(fs, this); - } - } - catch (Exception ex) - { - if (null != updateManager) - updateManager.OnLog( - new LogEventArgs( - string.Format( - Properties.Resources.FailedToSave, - filePath, - ex.Message), - LogLevel.Console)); - else throw; - } - } - - /// - /// Utility method to get the settings - /// - /// IDynamoLookUp instance - /// IUpdateManager object which can log errors during saving. - /// Update Manager Configuration settings object - public static UpdateManagerConfiguration GetSettings(IDynamoLookUp lookUp, IUpdateManager updateManager = null) - { - string filePath; - var exists = TryGetConfigFilePath(out filePath); -#if DEBUG - //This code is just to create the default config file to - //save the default settings, which later on can be modified - //to re-direct it to other download target for testing. - if (!exists) - { - var umConfig = new UpdateManagerConfiguration(); - umConfig.Save(filePath, updateManager); - } -#endif - if (!exists) - return new UpdateManagerConfiguration() { DynamoLookUp = lookUp }; - - var config = Load(filePath, updateManager); - if (null != config) - config.DynamoLookUp = lookUp; - - return config; - } - - /// - /// Returns the update manager config file path. - /// - /// Full path for the config file - /// True if file exists. - public static bool TryGetConfigFilePath(out string filePath) - { - string location = Assembly.GetExecutingAssembly().Location; - // ReSharper disable once AssignNullToNotNullAttribute, location is always available - filePath = Path.Combine(Path.GetDirectoryName(location), DEFAULT_CONFIG_FILE_S); - return File.Exists(filePath); - } - - /// - /// IDynamoLookUp object to get installed Dynamo versions - /// - [XmlIgnore] - public IDynamoLookUp DynamoLookUp { get; set; } - } - - /// - /// This class provides services for product update management. - /// - [Obsolete("UpdateManager is deprecated and will be removed in a future Dynamo version.")] - internal sealed class UpdateManager : NotificationObject, IUpdateManager - { - #region Private Class Data Members - - private bool versionCheckInProgress; - private static BinaryVersion productVersion; - private IAppVersionInfo updateInfo; - private const string OLD_DAILY_INSTALL_NAME_BASE = "DynamoDailyInstall"; - // TODO: InstallUpdate tool has been removed. - // Remove UpdateManager and code that's dependent on it: https://jira.autodesk.com/browse/DYN-5873 - private const string INSTALLUPDATE_EXE = "InstallUpdate.exe"; - private string updateFileLocation; - private int currentDownloadProgress = -1; - private IAppVersionInfo downloadedUpdateInfo; - private IUpdateManagerConfiguration configuration = null; - private int hostApplicationProcessId = -1; - - #endregion - - #region Public Event Handlers - - /// - /// Occurs when RequestUpdateDownload operation completes. - /// - public event UpdateDownloadedEventHandler UpdateDownloaded; - public event ShutdownRequestedEventHandler ShutdownRequested; - public event LogEventHandler Log; - - #endregion - - #region Public Class Properties - - /// - /// Obtains product version string - /// - public BinaryVersion ProductVersion - { - get - { - return GetProductVersion(); - } - } - - public static BinaryVersion GetProductVersion() - { - if (null != productVersion) return productVersion; - - var executingAssemblyName = Assembly.GetExecutingAssembly().GetName(); - productVersion = BinaryVersion.FromString(executingAssemblyName.Version.ToString()); - - return productVersion; - } - - public Version HostVersion { get; set; } - - public string HostName { get; set; } - - /// - /// BaseVersion is a method which compares the current Dynamo Core Version and the HostVersion - /// (DynamoRevit/DynamoStudio etc.) and returns the earlier (lower) Version. - /// This allows subsequent methods to do a single check and if there is an updated version (to either Core/Host - /// versions), the subsequent methods will poll the server for an update. - /// - private BinaryVersion BaseVersion() - { - if (HostVersion == null) return ProductVersion; - - var binaryHostVersion = BinaryVersion.FromString(HostVersion.ToString()); - - if (ProductVersion < binaryHostVersion) return ProductVersion; - else return binaryHostVersion; - } - - /// - /// Obtains available update version string - /// - public BinaryVersion AvailableVersion - { - get - { - // Dirty patch: A version is available only when the update has been downloaded. - // This causes the UI to display the update button only after the download has - // completed. - return downloadedUpdateInfo == null - ? BaseVersion() : updateInfo.Version; - } - } - - /// - /// Obtains downloaded update file location. - /// - public string UpdateFileLocation - { - get { return updateFileLocation; } - private set - { - updateFileLocation = value; - RaisePropertyChanged("UpdateFileLocation"); - } - } - - public IAppVersionInfo UpdateInfo - { - get { return updateInfo; } - set - { - if (value != null) - { - OnLog(new LogEventArgs(string.Format(Properties.Resources.UpdateAvailable, value.Version), LogLevel.Console)); - } - - updateInfo = value; - RaisePropertyChanged("UpdateInfo"); - } - } - - /// - /// Dirty patch: Set to the value of UpdateInfo once the new update installer has been - /// downloaded. - /// - public IAppVersionInfo DownloadedUpdateInfo - { - get { return downloadedUpdateInfo; } - set - { - downloadedUpdateInfo = value; - RaisePropertyChanged("DownloadedUpdateInfo"); - } - } - - /// - /// Returns true if a new version is available. - /// - public bool IsUpdateAvailable - { - get - { - //Update is not available until it's downloaded - if (DownloadedUpdateInfo == null) - return false; - - return ForceUpdate || AvailableVersion > BaseVersion(); - } - } - - /// - /// This flag is available via the debug menu to - /// allow the update manager to check for newer daily - /// builds as well. - /// - public bool CheckNewerDailyBuilds - { - get { return Configuration.CheckNewerDailyBuild; } - set - { - if (!Configuration.CheckNewerDailyBuild && value) - { - CheckForProductUpdate(new UpdateRequest(new Uri(Configuration.DownloadSourcePath), this)); - } - Configuration.CheckNewerDailyBuild = value; - RaisePropertyChanged("CheckNewerDailyBuilds"); - } - } - - /// - /// Apply the most recent update, regardless - /// of whether it is newer than the current version. - /// - public bool ForceUpdate - { - get { return Configuration.ForceUpdate; } - set - { - if (!Configuration.ForceUpdate && value) - { - // do a check - CheckForProductUpdate(new UpdateRequest(new Uri(Configuration.DownloadSourcePath), this)); - } - Configuration.ForceUpdate = value; - RaisePropertyChanged("ForceUpdate"); - } - } - - /// - /// Returns the configuration settings. - /// - public IUpdateManagerConfiguration Configuration - { - get - { - return configuration ?? (configuration = UpdateManagerConfiguration.GetSettings(null, this)); - } - } - - #endregion - - public UpdateManager(IUpdateManagerConfiguration configuration) - { - this.configuration = configuration; - PropertyChanged += UpdateManager_PropertyChanged; - HostVersion = null; - HostName = string.Empty; - } - - void UpdateManager_PropertyChanged(object sender, PropertyChangedEventArgs e) - { - switch (e.PropertyName) - { - case "UpdateInfo": - if (updateInfo != null) - { - //When the UpdateInfo property changes, this will be reflected in the UI - //by the vsisibility of the download cloud. The most up to date version will - //be downloaded asynchronously. - OnLog(new LogEventArgs(Properties.Resources.UpdateDownloadStarted, LogLevel.Console)); - - var tempPath = Path.GetTempPath(); - DownloadUpdatePackageAsynchronously(updateInfo.InstallerURL, updateInfo.Version, tempPath); - DownloadSignatureFileAsynchronously(updateInfo.SignatureURL, tempPath); - } - break; - } - } - - #region Public Class Operational Methods - - /// - /// Async call to request the update version info from the web. - /// This call raises UpdateFound event notification, if an update is - /// found. - /// - public void CheckForProductUpdate(IAsynchronousRequest request) - { - OnLog(new LogEventArgs("RequestUpdateVersionInfo", LogLevel.File)); - OnLog(new LogEventArgs(Properties.Resources.RequestingVersionUpdate, LogLevel.Console)); - - if (versionCheckInProgress) - return; - - versionCheckInProgress = true; - } - - /// - /// Callback for the UpdateRequest's UpdateDataAvailable event. - /// Reads the request data, and parses for available versions. - /// If a more recent version is available, the UpdateInfo object - /// will be set. - /// - /// An instance of an update request. - public void UpdateDataAvailable(IAsynchronousRequest request) - { - UpdateInfo = null; - - //If there is error data or the request data is empty - //bail out. - if (!string.IsNullOrEmpty(request.Error) || - string.IsNullOrEmpty(request.Data)) - { - OnLog(new LogEventArgs(String.Format(Properties.Resources.CouldNotGetUpdateData, request.Path), LogLevel.Console)); - versionCheckInProgress = false; - return; - } - - var latestBuildFilePath = GetLatestBuildFromS3(request, CheckNewerDailyBuilds); - if (string.IsNullOrEmpty(latestBuildFilePath)) - { - OnLog(new LogEventArgs(Properties.Resources.CouldNotGetLatestBuild, LogLevel.Console)); - versionCheckInProgress = false; - return; - } - - // Strip the build number from the file name. - // DynamoInstall0.7.0 becomes 0.7.0. Build a version - // and compare it with the current product version. - - var latestBuildDownloadUrl = Path.Combine(Configuration.DownloadSourcePath, latestBuildFilePath); - var latestBuildSignatureUrl = Path.Combine( - Configuration.SignatureSourcePath, - Path.GetFileNameWithoutExtension(latestBuildFilePath) + ".sig"); - - BinaryVersion latestBuildVersion; - var latestBuildTime = new DateTime(); - - bool useStable = false; - if (IsStableBuild(Configuration.InstallerNameBase, latestBuildFilePath)) - { - useStable = true; - latestBuildVersion = GetBinaryVersionFromFilePath(Configuration.InstallerNameBase, latestBuildFilePath); - } - else if (IsDailyBuild(Configuration.InstallerNameBase, latestBuildFilePath) || IsDailyBuild(OLD_DAILY_INSTALL_NAME_BASE, latestBuildFilePath)) - { - latestBuildTime = GetBuildTimeFromFilePath(Configuration.InstallerNameBase, latestBuildFilePath); - latestBuildVersion = GetCurrentBinaryVersion(); - } - else - { - OnLog(new LogEventArgs(Properties.Resources.PathNotRegconizableAsStableOrDailyBuild, LogLevel.Console)); - versionCheckInProgress = false; - return; - } - - // Check the last downloaded update. If it's the same or newer as the - // one found on S3, then just set the update information to that one - // and bounce. - - //if (ExistingUpdateIsNewer()) - //{ - // logger.Log(string.Format("Using previously updated download {0}", dynamoModel.PreferenceSettings.LastUpdateDownloadPath)); - // UpdateDownloaded(this, new UpdateDownloadedEventArgs(null, UpdateFileLocation)); - // versionCheckInProgress = false; - // return; - //} - - // Install the latest update regardless of whether it - // is newer than the current build. - if (ForceUpdate) - { - SetUpdateInfo(latestBuildVersion, latestBuildDownloadUrl, latestBuildSignatureUrl); - } - else - { - if (useStable) //Check stables - { - if (latestBuildVersion > BaseVersion()) - { - SetUpdateInfo(latestBuildVersion, latestBuildDownloadUrl, latestBuildSignatureUrl); - } - else - { - OnLog(new LogEventArgs(Properties.Resources.DynamoUpToDate, LogLevel.Console)); - } - } - else // Check dailies - { - if (latestBuildTime > DateTime.Now) - { - SetUpdateInfo(GetCurrentBinaryVersion(), latestBuildDownloadUrl, latestBuildSignatureUrl); - } - else - { - OnLog(new LogEventArgs(Properties.Resources.DynamoUpToDate, LogLevel.Console)); - } - } - } - - versionCheckInProgress = false; - } - - public void QuitAndInstallUpdate() - { - OnLog(new LogEventArgs("UpdateManager.QuitAndInstallUpdate-Invoked", LogLevel.File)); - - if (ShutdownRequested != null) - ShutdownRequested(this); - } - - public void HostApplicationBeginQuit() - { - // Double check that the updater path is not null and that there - // exists a file at that location on disk. - // Although this updater is stored in a temp directory, - // and the user wouldn't have come across it, there's the - // outside chance that it was deleted. Update cannot - // continue without this file. - - if (string.IsNullOrEmpty(UpdateFileLocation) || !File.Exists(UpdateFileLocation)) - return; - - var currDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var updater = Path.Combine(currDir, INSTALLUPDATE_EXE); - - // Double check that that the updater program exists. - // This program lives in the users' base Dynamo directory. If - // it doesn't exist, we can't run the update. - - if (!File.Exists(updater)) - return; - - var p = new Process - { - StartInfo = - { - FileName = updater, - Arguments = UpdateFileLocation, - UseShellExecute = false, - CreateNoWindow = true - } - }; - - if (hostApplicationProcessId != -1) - { - p.StartInfo.Arguments += " " + hostApplicationProcessId; - } - p.Start(); - Dynamo.Logging.Analytics.TrackEvent(Actions.Installed, Categories.Upgrade, AvailableVersion.ToString()); - } - - public void RegisterExternalApplicationProcessId(int id) - { - hostApplicationProcessId = id; - } - - #endregion - - #region Private Event Handlers - - private void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e) - { - versionCheckInProgress = false; - - if (e == null) - return; - - string errorMessage = ((null == e.Error) ? "Successful" : e.Error.Message); - OnLog(new LogEventArgs(Properties.Resources.UpdateDownloadComplete, LogLevel.Console)); - OnLog(new LogEventArgs(errorMessage, LogLevel.File)); - - UpdateFileLocation = string.Empty; - - if (e.Error != null) - return; - - // Dirty patch: this ensures that we have a property that reflects the update status - // only after the update has been downloaded. - DownloadedUpdateInfo = UpdateInfo; - - UpdateFileLocation = (string)e.UserState; - OnLog(new LogEventArgs("Update download complete.", LogLevel.Console)); - Dynamo.Logging.Analytics.TrackEvent(Actions.Downloaded, Categories.Upgrade, AvailableVersion.ToString()); - - if (null != UpdateDownloaded) - UpdateDownloaded(this, new UpdateDownloadedEventArgs(e.Error, UpdateFileLocation)); - } - - public void OnLog(LogEventArgs args) - { - if (Log != null) - { - Log(args); - } - } - - #endregion - - #region Private Class Helper Methods - - /// - /// Returns the file name of the latest build on S3 - /// - /// - /// - /// - private string GetLatestBuildFromS3(IAsynchronousRequest request, bool checkDailyBuilds) - { - XNamespace ns = "http://s3.amazonaws.com/doc/2006-03-01/"; - - XDocument doc = null; - using (TextReader td = new StringReader(request.Data)) - { - try - { - doc = XDocument.Load(td); - } - catch (Exception e) - { - OnLog(new LogEventArgs(e, LogLevel.Console)); - return null; - } - } - - // Reads filenames from S3, and pulls out those which include - // DynamoInstall, and optionally, those that include DynamoDailyInstall. - // Order the results according to their LastUpdated field. - - var bucketresult = doc.Element(ns + "ListBucketResult"); - - if (bucketresult == null) - { - return null; - } - - var builds = bucketresult.Descendants(ns + "LastModified"). - OrderByDescending(x => DateTime.Parse(x.Value)). - Where(x => x.Parent.Value.Contains(Configuration.InstallerNameBase) || x.Parent.Value.Contains(OLD_DAILY_INSTALL_NAME_BASE)). - Select(x => x.Parent); - - - var xElements = builds as XElement[] ?? builds.ToArray(); - if (!xElements.Any()) - { - return null; - } - - var fileNames = xElements.Select(x => x.Element(ns + "Key").Value); - - string latestBuild = string.Empty; - latestBuild = checkDailyBuilds ? - fileNames.FirstOrDefault(x => IsDailyBuild(Configuration.InstallerNameBase, x) || IsDailyBuild(OLD_DAILY_INSTALL_NAME_BASE, x)) : - fileNames.FirstOrDefault(x => IsStableBuild(Configuration.InstallerNameBase, x)); - - return latestBuild; - } - - /// - /// Returns a build time from a file path. - /// - /// - /// - /// A DateTime or the DateTime MinValue. - internal static DateTime GetBuildTimeFromFilePath(string installNameBase, string filePath) - { - var version = GetVersionString(installNameBase, filePath); - var dtStr = version.Split('.').LastOrDefault(); - - DateTime dt; - return DateTime.TryParseExact( - dtStr, - "yyyyMMddTHHmm", - CultureInfo.InvariantCulture, - DateTimeStyles.None, - out dt) ? dt : DateTime.MinValue; - } - - /// - /// Find the version string within a file name - /// by removing the base install name. - /// - /// - /// - /// A version string like "x.x.x.x" or null if one cannot be found. - private static string GetVersionString(string installNameBase, string filePath) - { - if (!filePath.Contains(installNameBase)) - { - return null; - } - - var fileName = Path.GetFileNameWithoutExtension(filePath); - return fileName.Replace(installNameBase, ""); - } - - /// - /// Returns a binary version for the executing assembly - /// - /// A BinaryVersion - internal static BinaryVersion GetCurrentBinaryVersion() - { - // If we're looking at dailies, latest build version will simply be - // the current build version without a build or revision, ex. 0.6 - var v = Assembly.GetExecutingAssembly().GetName().Version; - return BinaryVersion.FromString(string.Format("{0}.{1}.{2}", v.Major, v.Minor, v.Build)); - } - - /// - /// Returns a BinaryVersion from a file path. - /// - /// The base install name. - /// The path name of the file. - /// A BinaryVersion or null if one can not be parse from the file path. - internal static BinaryVersion GetBinaryVersionFromFilePath(string installNameBase, string filePath) - { - // Filename format is DynamoInstall0.7.1.YYYYMMDDT0000.exe - var index = filePath.IndexOf(installNameBase, StringComparison.Ordinal); - if (index < 0) - return null; - - // Skip past the 'installNameBase' since we are only interested - // in getting the version numbers that come after the base name. - var fileName = Path.GetFileNameWithoutExtension(filePath); - var version = fileName.Substring(index + installNameBase.Length); - - var splits = version.Split(new [] { "." }, StringSplitOptions.RemoveEmptyEntries); - if (splits.Count() < 3) // This can be 4 if it includes revision number. - return null; - - ushort major, minor, build; - if (!ushort.TryParse(splits[0], out major)) - return null; - if (!ushort.TryParse(splits[1], out minor)) - return null; - if (!ushort.TryParse(splits[2], out build)) - return null; - - return BinaryVersion.FromString(string.Format("{0}.{1}.{2}.0", major, minor, build)); - } - - private void SetUpdateInfo(BinaryVersion latestBuildVersion, string latestBuildDownloadUrl, string signatureUrl) - { - UpdateInfo = new AppVersionInfo() - { - Version = latestBuildVersion, - VersionInfoURL = Configuration.DownloadSourcePath, - InstallerURL = latestBuildDownloadUrl, - SignatureURL = signatureUrl - }; - } - - /// - /// Check if a file name is a daily build. - /// - /// - /// - /// True if this is a daily build, otherwise false. - internal static bool IsDailyBuild(string installNameBase, string fileName) - { - if (!fileName.Contains(installNameBase)) - { - return false; - } - - var versionStr = GetVersionString(installNameBase, fileName); - var splits = versionStr.Split('.'); - - DateTime dt; - return DateTime.TryParseExact( - splits.Last(), - "yyyyMMddTHHmm", - CultureInfo.InvariantCulture, - DateTimeStyles.None, - out dt); - } - - /// - /// Check if a file name is a stable build. - /// - /// - /// - /// True if this is a stable build, otherwise false. - internal static bool IsStableBuild(string installNameBase, string fileName) - { - if (!fileName.Contains(installNameBase)) - { - return false; - } - return !IsDailyBuild(installNameBase, fileName); - } - - /// - /// Async call to request downloading a file from web. - /// This call raises UpdateDownloaded event notification. - /// - /// Web URL for file to download. - /// The version of package that is to be downloaded. - /// Temp folder path where the update package - /// to be downloaded. - /// Request status, it may return false if invalid URL was passed. - private bool DownloadUpdatePackageAsynchronously(string url, BinaryVersion version, string tempPath) - { - currentDownloadProgress = -1; - - if (string.IsNullOrEmpty(url) || (null == version)) - { - versionCheckInProgress = false; - return false; - } - - UpdateFileLocation = string.Empty; - string downloadedFileName = string.Empty; - string downloadedFilePath = string.Empty; - - try - { - downloadedFileName = Path.GetFileName(url); - downloadedFilePath = Path.Combine(tempPath, downloadedFileName); - - if (File.Exists(downloadedFilePath)) - File.Delete(downloadedFilePath); - } - catch (Exception) - { - versionCheckInProgress = false; - return false; - } - - var client = new WebClient(); - client.DownloadProgressChanged += client_DownloadProgressChanged; - client.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadFileCompleted); - client.DownloadFileAsync(new Uri(url), downloadedFilePath, downloadedFilePath); - return true; - } - - /// - /// Async call to download the signature file. - /// - /// Signature file url for download. - /// Temp folder path where the signature file - /// to be downloaded. - /// - private bool DownloadSignatureFileAsynchronously(string url, string tempPath) - { - string downloadedFileName = string.Empty; - string downloadedFilePath = string.Empty; - - try - { - downloadedFileName = Path.GetFileName(url); - downloadedFilePath = Path.Combine(tempPath, downloadedFileName); - - if (File.Exists(downloadedFilePath)) - File.Delete(downloadedFilePath); - } - catch (Exception) - { - versionCheckInProgress = false; - return false; - } - - var client = new WebClient(); - client.DownloadFileAsync(new Uri(url), downloadedFilePath, downloadedFilePath); - return true; - } - - void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { - if (e.ProgressPercentage % 10 == 0 && - e.ProgressPercentage > currentDownloadProgress) - { - OnLog(new LogEventArgs(string.Format(Properties.Resources.UpdateDownloadProgress, e.ProgressPercentage), LogLevel.Console)); - currentDownloadProgress = e.ProgressPercentage; - } - } - - #endregion - - /// - /// Checks for the product update by requesting for update version info - /// from configured download source path. This method will skip the - /// update check if a newer version of the product is already installed. - /// - /// Update manager instance using which product - /// update check needs to be done. - internal static void CheckForProductUpdate(IUpdateManager manager) - { - //If we already have higher version installed, don't look for product update. - if(manager.Configuration.DynamoLookUp != null && manager.Configuration.DynamoLookUp.LatestProduct > manager.ProductVersion) - return; - if((manager.Configuration is IDisableUpdateConfig) && (manager.Configuration as IDisableUpdateConfig).DisableUpdates) - return; - var downloadUri = new Uri(manager.Configuration.DownloadSourcePath); - manager.CheckForProductUpdate(new UpdateRequest(downloadUri, manager)); - } - } - - /// - /// Lookup for installed products - /// - internal abstract class DynamoLookUp : IDynamoLookUp - { - /// - /// Returns the version of latest product - /// - public BinaryVersion LatestProduct { get { return GetLatestInstallVersion(); } } - - /// - /// Locates DynamoCore.dll at given install path and gets file version - /// - /// Dynamo install path - /// Dynamo version if valid Dynamo exists else null - public virtual Version GetDynamoVersion(string installPath) - { - if(!Directory.Exists(installPath))//null or empty installPath will return false - return null; - - var filePath = Directory.GetFiles(installPath, "*DynamoCore.dll").FirstOrDefault(); - return String.IsNullOrEmpty(filePath) ? null : Version.Parse(FileVersionInfo.GetVersionInfo(filePath).FileVersion); - } - - /// - /// Returns all dynamo install path on the system by looking into the Windows registry. - /// - /// List of Dynamo install path - public abstract IEnumerable GetDynamoInstallLocations(); - - /// - /// Returns the full path of user data location of all version of this - /// Dynamo product installed on this system. The default implementation - /// returns list of all subfolders in %appdata%\Dynamo as well as - /// %appdata%\Dynamo\Dynamo Core\ folders. - /// - /// - public virtual IEnumerable GetDynamoUserDataLocations() - { - var appDatafolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - var dynamoFolder = Path.Combine(appDatafolder, "Dynamo"); - if (!Directory.Exists(dynamoFolder)) return Enumerable.Empty(); - - var paths = new List(); - var coreFolder = Path.Combine(dynamoFolder, "Dynamo Core"); - //Dynamo Core folder has to be enumerated first to cater migration from - //Dynamo 1.0 to Dynamo Core 1.0 - if (Directory.Exists(coreFolder)) - { - paths.AddRange(Directory.EnumerateDirectories(coreFolder)); - } - - paths.AddRange(Directory.EnumerateDirectories(dynamoFolder)); - return paths; - } - - private BinaryVersion GetLatestInstallVersion() - { - var dynamoInstallations = GetDynamoInstallLocations(); - if(null == dynamoInstallations) - return null; - - var latestVersion = - dynamoInstallations.Select(GetDynamoVersion).OrderBy(s => s).LastOrDefault(); - return latestVersion == null ? null : BinaryVersion.FromString(latestVersion.ToString()); - } - } -} diff --git a/src/DynamoCoreWpf/Controls/GraphUpdateNotificationControl.xaml b/src/DynamoCoreWpf/Controls/GraphUpdateNotificationControl.xaml deleted file mode 100644 index 18704b951d0..00000000000 --- a/src/DynamoCoreWpf/Controls/GraphUpdateNotificationControl.xaml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/DynamoCoreWpf/Controls/GraphUpdateNotificationControl.xaml.cs b/src/DynamoCoreWpf/Controls/GraphUpdateNotificationControl.xaml.cs deleted file mode 100644 index 48a41467509..00000000000 --- a/src/DynamoCoreWpf/Controls/GraphUpdateNotificationControl.xaml.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Windows; -using System.Windows.Controls; - -using Dynamo.Updates; -using Dynamo.Wpf.Utilities; - -namespace DynamoCore.UI.Controls -{ - /// - /// Interaction logic for GraphUpdateNotificationControl.xaml - /// - public partial class GraphUpdateNotificationControl : UserControl - { - public GraphUpdateNotificationControl() - { - InitializeComponent(); - InstallButton.Click += OnInstallButtonClicked; - } - - private void OnInstallButtonClicked(object sender, RoutedEventArgs e) - { - var um = DataContext as IUpdateManager; - if (um == null) return; - - var result = MessageBoxService.Show(Dynamo.Wpf.Properties.Resources.UpdateMessage, - Dynamo.Wpf.Properties.Resources.InstallMessageCaption, - MessageBoxButton.OKCancel, - MessageBoxImage.None); - - if (result == MessageBoxResult.OK) - { - um.QuitAndInstallUpdate(); - } - } - } -} \ No newline at end of file diff --git a/src/DynamoCoreWpf/DynamoCoreWpf.csproj b/src/DynamoCoreWpf/DynamoCoreWpf.csproj index a75c9236d12..bb5c06ad00f 100644 --- a/src/DynamoCoreWpf/DynamoCoreWpf.csproj +++ b/src/DynamoCoreWpf/DynamoCoreWpf.csproj @@ -319,9 +319,6 @@ - - GraphUpdateNotificationControl.xaml - ShortcutToolbar.xaml @@ -569,10 +566,6 @@ Designer MSBuild:Compile - - MSBuild:Compile - Designer - Designer Always diff --git a/src/DynamoCoreWpf/UI/Converters.cs b/src/DynamoCoreWpf/UI/Converters.cs index 56df2b6627b..6028ffb653e 100644 --- a/src/DynamoCoreWpf/UI/Converters.cs +++ b/src/DynamoCoreWpf/UI/Converters.cs @@ -2239,48 +2239,6 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu } } - public class IsUpdateAvailableToTextConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - var um = value as IUpdateManager; - if (um == null) - return Resources.AboutWindowCannotGetVersion; - - if (!um.IsUpdateAvailable) - return Resources.AboutWindowUpToDate; - - var latest = um.AvailableVersion; - - return latest != null ? latest.ToString() : Resources.AboutWindowCannotGetVersion; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return null; - } - } - - public class IsUpdateAvailableBrushConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - SolidColorBrush brush; - - brush = (bool)value - ? (SolidColorBrush) - SharedDictionaryManager.DynamoColorsAndBrushesDictionary["UpdateManagerUpdateAvailableBrush"] - : (SolidColorBrush)SharedDictionaryManager.DynamoColorsAndBrushesDictionary["UpdateManagerUpToDateBrush"]; - - return brush; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return null; - } - } - public class BinaryRadioButtonCheckedConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, diff --git a/src/DynamoCoreWpf/UI/Themes/Modern/DynamoColorsAndBrushes.xaml b/src/DynamoCoreWpf/UI/Themes/Modern/DynamoColorsAndBrushes.xaml index 105ccbd5240..18edd8b4296 100644 --- a/src/DynamoCoreWpf/UI/Themes/Modern/DynamoColorsAndBrushes.xaml +++ b/src/DynamoCoreWpf/UI/Themes/Modern/DynamoColorsAndBrushes.xaml @@ -116,10 +116,6 @@ - - - - #000000 #000000 diff --git a/src/DynamoCoreWpf/UI/Themes/Modern/DynamoConverters.xaml b/src/DynamoCoreWpf/UI/Themes/Modern/DynamoConverters.xaml index 9b750dff15b..e244a6dea74 100644 --- a/src/DynamoCoreWpf/UI/Themes/Modern/DynamoConverters.xaml +++ b/src/DynamoCoreWpf/UI/Themes/Modern/DynamoConverters.xaml @@ -106,8 +106,6 @@ - - diff --git a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs index 0583d55b413..5adaa99dbba 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs @@ -492,15 +492,6 @@ public string HostName get { return model.HostName; } } - public bool IsUpdateAvailable - { - get - { - var um = model.UpdateManager; - return um.IsUpdateAvailable; - } - } - public string LicenseFile { get @@ -728,7 +719,6 @@ protected DynamoViewModel(StartConfiguration startConfiguration) SubscribeModelUiEvents(); SubscribeModelChangedHandlers(); SubscribeModelBackupFileSaveEvent(); - SubscribeUpdateManagerHandlers(); InitializeAutomationSettings(startConfiguration.CommandFilePath); @@ -857,7 +847,6 @@ protected virtual void UnsubscribeAllEvents() UnsubscribeDispatcherEvents(); UnsubscribeModelUiEvents(); UnsubscribeModelChangedEvents(); - UnsubscribeUpdateManagerEvents(); UnsubscribeLoggerEvents(); UnsubscribeModelCleaningUpEvent(); UnsubscribeModelBackupFileSaveEvent(); @@ -892,16 +881,9 @@ private void UnsubscribeLoggerEvents() model.Logger.PropertyChanged -= Instance_PropertyChanged; } - private void SubscribeUpdateManagerHandlers() - { - model.UpdateManager.UpdateDownloaded += Instance_UpdateDownloaded; - model.UpdateManager.ShutdownRequested += UpdateManager_ShutdownRequested; - } - private void UnsubscribeUpdateManagerEvents() { - model.UpdateManager.UpdateDownloaded -= Instance_UpdateDownloaded; - model.UpdateManager.ShutdownRequested -= UpdateManager_ShutdownRequested; + } private void SubscribeModelUiEvents() @@ -1085,18 +1067,6 @@ internal bool CanClearLog(object parameter) return true; } - void Instance_UpdateDownloaded(object sender, UpdateDownloadedEventArgs e) - { - RaisePropertyChanged("Version"); - RaisePropertyChanged("IsUpdateAvailable"); - } - - void UpdateManager_ShutdownRequested(IUpdateManager updateManager) - { - PerformShutdownSequence(new ShutdownParams( - shutdownHost: true, allowCancellation: true)); - } - void CollectInfoManager_PropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) @@ -3475,11 +3445,6 @@ public bool PerformShutdownSequence(ShutdownParams shutdownParams) MainGuideManager?.CloseRealTimeInfoWindow(); model.ShutDown(shutdownParams.ShutdownHost); - if (shutdownParams.ShutdownHost) - { - model.UpdateManager.HostApplicationBeginQuit(); - } - UsageReportingManager.DestroyInstance(); this.model.CommandStarting -= OnModelCommandStarting; this.model.CommandCompleted -= OnModelCommandCompleted; diff --git a/src/DynamoCoreWpf/Views/About/AboutWindow.xaml b/src/DynamoCoreWpf/Views/About/AboutWindow.xaml index 9ff7236c0cf..008f85fb37e 100644 --- a/src/DynamoCoreWpf/Views/About/AboutWindow.xaml +++ b/src/DynamoCoreWpf/Views/About/AboutWindow.xaml @@ -1,4 +1,4 @@ - - - - - public class UpdateManagerTestNotUpToDate - { - private const string DOWNLOAD_SOURCE_PATH_S = "http://downloadsourcepath/"; - private const string SIGNATURE_SOURCE_PATH_S = "http://SignatureSourcePath/"; - - static UpdateManagerConfiguration NewConfiguration(bool checkNewerDailyBuild =false, bool forceUpdate =false, IDynamoLookUp lookup = null) - { - return new UpdateManagerConfiguration() - { - DownloadSourcePath = DOWNLOAD_SOURCE_PATH_S, - SignatureSourcePath = SIGNATURE_SOURCE_PATH_S, - CheckNewerDailyBuild = checkNewerDailyBuild, - ForceUpdate = forceUpdate, - DynamoLookUp = lookup, - }; - } - - [Test] - [Category("UnitTests")] - public void UpdateCheckReturnsInfoWhenNewerVersionAvaialable() - { - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.updateAvailableData); - - var updateManager = new DynUpdateManager(NewConfiguration()); - updateManager.UpdateDataAvailable(updateRequest.Object); - Assert.NotNull(updateManager.UpdateInfo); - } - - [Test] - [Category("UnitTests")] - public void UpdateCheckReturnsInfoWhenNewerDailyBuildAvailable() - { - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.dailyBuildAvailableData); - - var updateManager = new DynUpdateManager(NewConfiguration(checkNewerDailyBuild: true)); - updateManager.UpdateDataAvailable(updateRequest.Object); - Assert.NotNull(updateManager.UpdateInfo); - } - - [Test, Category("UnitTests")] - public void IsUpdateAvailableWhenNewerVersionAvaialable() - { - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.updateAvailableData); - - var updateManager = new DynUpdateManager(NewConfiguration()); - updateManager.UpdateDataAvailable(updateRequest.Object); - updateManager.DownloadedUpdateInfo = updateManager.UpdateInfo; - - Assert.IsTrue(updateManager.IsUpdateAvailable); - } - - [Test, Category("UnitTests")] - public void IsUpdateAvailableWhenForceUpdateIsTrue() - { - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.noUpdateAvailableData); - - var updateManager = new DynUpdateManager(NewConfiguration(forceUpdate:true)); - updateManager.UpdateDataAvailable(updateRequest.Object); - updateManager.DownloadedUpdateInfo = updateManager.UpdateInfo; - - Assert.IsTrue(updateManager.IsUpdateAvailable); - } - - [Test, Category("UnitTests")] - public void NoUpdateAvailableWhenUpToDate() - { - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.noUpdateAvailableData); - - var updateManager = new DynUpdateManager(NewConfiguration()); - updateManager.UpdateDataAvailable(updateRequest.Object); - updateManager.DownloadedUpdateInfo = updateManager.UpdateInfo; - - Assert.IsFalse(updateManager.IsUpdateAvailable); - } - - [Test, Category("UnitTests")] - public void NoUpdateIsAvailableWhenHigherVersionDynamoIsInstalled() - { - var lookup = new Mock(); - lookup.Setup(l => l.GetDynamoInstallLocations()).Returns(new[] { "A" }); - lookup.Setup(l => l.GetDynamoVersion(It.IsAny())) - .Returns(s => Version.Parse("9.9.9.0")); - - var um = new DynUpdateManager(NewConfiguration(false, false, lookup.Object)); - Assert.IsNotNull(um); - - DynUpdateManager.CheckForProductUpdate(um); - um.DownloadedUpdateInfo = um.UpdateInfo; - - Assert.IsNull(um.UpdateInfo); - Assert.IsFalse(um.IsUpdateAvailable); - } - - [Test, Category("UnitTests")] - public void DisableUpdateWhenLowerVersionDynamoIsInstalled() - { - var lookup = new Mock(); - lookup.Setup(l => l.GetDynamoInstallLocations()).Returns(new[] { "A" }); - lookup.Setup(l => l.GetDynamoVersion(It.IsAny())) - .Returns(s => Version.Parse("1.2.0.0")); - - var um = new DynUpdateManager(NewConfiguration(false,false,lookup.Object)); - (um.Configuration as IDisableUpdateConfig).DisableUpdates=true; - Assert.IsNotNull(um); - - DynUpdateManager.CheckForProductUpdate(um); - Assert.IsNull(um.UpdateInfo); - Assert.IsFalse(um.IsUpdateAvailable); - } - - [Test, Category("UnitTests")] - public void NoUpdateAvailableWhenUpdateInfoIsNotYetDownloaded() - { - var updateManager = new DynUpdateManager(NewConfiguration()); - - Assert.IsFalse(updateManager.IsUpdateAvailable); - } - - [Test, Category("UnitTests")] - public void UpdateCheckReturnsCorrectVersionWhenAvailable() - { - var um = new DynUpdateManager(NewConfiguration()); - Assert.IsNotNull(um); - - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.updateAvailableData); - um.UpdateDataAvailable(updateRequest.Object); - - // Spoof a download completion by setting the downloaded update info to the update info - um.DownloadedUpdateInfo = um.UpdateInfo; - Assert.NotNull(um.UpdateInfo); - Assert.AreEqual(um.AvailableVersion.ToString(), "9.9.9.0"); - } - - [Test, Category("UnitTests")] - public void ConfigurationSerialization() - { - var config = new UpdateManagerConfiguration() - { - DownloadSourcePath = DOWNLOAD_SOURCE_PATH_S, - SignatureSourcePath = SIGNATURE_SOURCE_PATH_S - }; - - //save to a temp file. - var tempFile = Path.GetTempFileName(); - Assert.DoesNotThrow(() => config.Save(tempFile, null)); - - //read from a temp file. - UpdateManagerConfiguration savedConfig = null; - Assert.DoesNotThrow(() => savedConfig = UpdateManagerConfiguration.Load(tempFile, null)); - - //Compare parameters. - Assert.IsNotNull(savedConfig); - Assert.AreEqual(config.CheckNewerDailyBuild, savedConfig.CheckNewerDailyBuild); - Assert.AreEqual(config.SignatureSourcePath, savedConfig.SignatureSourcePath); - Assert.AreEqual(config.DownloadSourcePath, savedConfig.DownloadSourcePath); - Assert.AreEqual(config.ForceUpdate, savedConfig.ForceUpdate); - Assert.AreEqual(config.DisableUpdates, savedConfig.DisableUpdates); - } - - [Test] - [Category("UnitTests")] - public void ConfigurationRedirection() - { - //Inject test config to UpdateManager instance, using reflection. - var config = new UpdateManagerConfiguration() - { - DownloadSourcePath = DOWNLOAD_SOURCE_PATH_S, - SignatureSourcePath = SIGNATURE_SOURCE_PATH_S - }; - - var um = new DynUpdateManager(config); - Assert.IsNotNull(um); - - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data) - .Returns(UpdateManagerTestHelpers.updateAvailableData); - um.UpdateDataAvailable(updateRequest.Object); - - // Spoof a download completion by setting the downloaded update info to the update info - um.DownloadedUpdateInfo = um.UpdateInfo; - Assert.NotNull(um.UpdateInfo); - Assert.AreEqual("9.9.9.0", um.AvailableVersion.ToString()); - Assert.AreEqual(DOWNLOAD_SOURCE_PATH_S, um.UpdateInfo.VersionInfoURL); - Assert.AreEqual( - SIGNATURE_SOURCE_PATH_S + @"DynamoInstall9.9.9.sig", - um.UpdateInfo.SignatureURL); - } - - [Test] - [Category("UnitTests")] - public void UpdateCheckReturnsNothingWhenNoNewerVersionAvailable() - { - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.noUpdateAvailableData); - var um = new DynUpdateManager(NewConfiguration()); - um.UpdateDataAvailable(updateRequest.Object); - - Assert.Null(um.UpdateInfo); - } - - [Test] - [Category("UnitTests")] - public void UpdateCheckReturnsNothingWhenNoVersionsAvailable() - { - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.noData); - var um = new DynUpdateManager(NewConfiguration()); - um.UpdateDataAvailable(updateRequest.Object); - - Assert.Null(um.UpdateInfo); - } - - [Test] - [Category("UnitTests")] - public void UpdateCheckReturnsNothingWhenNotConnected() - { - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(string.Empty); - - var um = new DynUpdateManager(NewConfiguration()); - um.UpdateDataAvailable(updateRequest.Object); - - Assert.Null(um.UpdateInfo); - } - - [Test] - [Category("UnitTests")] - public void ShouldRecognizeStableInstallerWithProperName() - { - var test = - Updates.UpdateManager.IsStableBuild("DynamoInstall", "DynamoInstall0.7.1.exe"); - Assert.True(test); - } - - [Test] - [Category("UnitTests")] - public void ShouldRecognizeOldDailyBuilds() - { - var test = - Updates.UpdateManager.IsDailyBuild("DynamoDailyInstall", "DynamoDailyInstall20140625T0009.exe"); - Assert.True(test); - } - - [Test] - [Category("UnitTests")] - public void ShouldRecognizeDailyInstallerWithProperName() - { - var test = - Updates.UpdateManager.IsStableBuild("DynamoInstall", "DynamoInstall0.7.1.20140625T0009.exe"); - Assert.False(test); - - test = Updates.UpdateManager.IsDailyBuild("DynamoInstall", "DynamoInstall0.7.1.20140625T0009.exe"); - Assert.True(test); - } - - [Test] - [Category("UnitTests")] - public void ShouldGetBinaryVersionFromInstaller() - { - var version = Updates.UpdateManager.GetBinaryVersionFromFilePath("DynamoInstall", "DynamoInstall0.7.1.exe"); - Assert.AreEqual("0.7.1.0", version.ToString()); - - version = Updates.UpdateManager.GetBinaryVersionFromFilePath("DynamoInstall", "DynamoInstall0.7.1.20140625T0009.exe"); - Assert.AreEqual("0.7.1.0", version.ToString()); - - version = Updates.UpdateManager.GetBinaryVersionFromFilePath("DynamoInstall", "Blah.exe"); - Assert.IsNull(version); - } - - [Test] - [Category("UnitTests")] - public void ShouldGetDateTimeFromDailyInstaller() - { - var dateTime = Updates.UpdateManager.GetBuildTimeFromFilePath("DynamoInstall", "DynamoInstall0.7.1.20140625T0009.exe"); - Assert.AreEqual(dateTime.Year, 2014); - Assert.AreEqual(dateTime.Month, 6); - Assert.AreEqual(dateTime.Day, 25); - Assert.AreEqual(dateTime.Minute, 9); - Assert.AreEqual(dateTime.Hour, 0); - - dateTime = Updates.UpdateManager.GetBuildTimeFromFilePath("DynamoInstall", "DynamoInstall0.7.1.exe"); - Assert.AreEqual(dateTime, DateTime.MinValue); - } - - [Test, Category("UnitTests")] - public void UpdateCheckReturnsNothingWhenGivenBadData() - { - // Here we simulate some xml that is returned that is well-formed - // but not what we are looking for. This is the case often when you - // are logging into a network that requires an additional login, like - // hotel wi-fi. In this case, the ListBucketResult element will not - // be found in the xml and we'll get null UpdateInfo. - - var updateRequest = new Mock(); - updateRequest.Setup(ur => ur.Data).Returns(UpdateManagerTestHelpers.badData); - - var um = new DynUpdateManager(NewConfiguration()); - um.UpdateDataAvailable(updateRequest.Object); - - Assert.Null(um.UpdateInfo); - } - - [Test, Category("UnitTests")] - public void GetLatestProductFromGoodData() - { - var products = new Dictionary - { - { "A", new Version(0, 1, 2, 3) }, - { "B", new Version(0, 1, 2, 3) }, - { "C", new Version(1, 2, 0, 0) }, - { "D", new Version(0, 1, 3, 3) }, - }; - - var lookup = new Mock(); - lookup.Setup(l => l.GetDynamoInstallLocations()).Returns(products.Keys); - lookup.Setup(l => l.GetDynamoVersion(It.IsAny())) - .Returns(s => products[s]); - - var latest = lookup.Object.LatestProduct; - Assert.AreEqual("1.2.0.0", latest.ToString()); - } - - [Test, Category("UnitTests")] - public void NoLatestProductVersion() - { - var lookup = new Mock(); - lookup.Setup(l => l.GetDynamoInstallLocations()).Returns(new[] { "A" }); - lookup.Setup(l => l.GetDynamoVersion(It.IsAny())) - .Returns(null); - - var latest = lookup.Object.LatestProduct; - Assert.AreEqual(null, latest); - } - - [Test, Category("UnitTests")] - public void GetLatestProductVersion() - { - var products = new Dictionary - { - { "A", new Version() }, - { "B", new Version(0, 1, 2, 3) }, - { "C", new Version(1, 2, 0, 0) }, - { "D", null }, - }; - - var lookup = new Mock(); - lookup.Setup(l => l.GetDynamoInstallLocations()).Returns(products.Keys); - lookup.Setup(l => l.GetDynamoVersion(It.IsAny())) - .Returns(s => products[s]); - var latest = lookup.Object.LatestProduct; - Assert.AreEqual("1.2.0.0", latest.ToString()); - } - } - - internal static class UpdateManagerTestHelpers - { - public const string updateAvailableData = - "" + - "dyn-builds-data" + - "" + - "" + - "1000" + - "true" + - "" + - "DynamoInstall0.1.0.exe" + - "2013-11-01T17:02:59.000Z" + - "" + - "" + - "DynamoInstall1.0.0.exe" + - "2013-11-02T17:02:59.000Z" + - "" + - "" + - "DynamoInstall9.9.9.exe" + - "2013-11-03T17:02:59.000Z" + - "" + - ""; - - // Daily build data for the year 2099 :) - public const string dailyBuildAvailableData = - "" + - "dyn-builds-data" + - "" + - "" + - "1000" + - "true" + - "" + - "DynamoInstall0.1.0.exe" + - "2013-11-01T17:02:59.000Z" + - "" + - "" + - "DynamoInstall0.1.0.20990101T0001.exe" + - "2099-11-02T17:02:59.000Z" + - "" + - "" + - "DynamoInstall0.1.0.20990101T0002.exe" + - "2099-11-03T17:02:59.000Z" + - "" + - ""; - - public const string noUpdateAvailableData = - "" + - "dyn-builds-data" + - "" + - "" + - "1000" + - "true" + - "" + - "DynamoInstall0.1.0.exe" + - "2013-11-01T17:02:59.000Z" + - "" + - "" + - "DynamoInstall0.1.1.exe" + - "2013-11-02T17:02:59.000Z" + - "" + - "" + - "DynamoInstall0.1.2.exe" + - "2013-11-03T17:02:59.000Z" + - "" + - ""; - - public const string noData = - "" + - "dyn-builds-data" + - "" + - "" + - "1000" + - "true" + - ""; - - public const string badData = - "" + - "" + - " Foo" + - "Bar" + - "Reminder" + - "This is some bad xml!" + - ""; - - public static void DoNothing() - { - Debug.WriteLine("Doing nothing."); - } - } -} diff --git a/test/DynamoCoreTests/Updates/UpdatesTests.cs b/test/DynamoCoreTests/Updates/UpdatesTests.cs deleted file mode 100644 index ed2581e4fa5..00000000000 --- a/test/DynamoCoreTests/Updates/UpdatesTests.cs +++ /dev/null @@ -1,238 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Dynamo.Logging; -using Dynamo.Updates; -using NUnit.Framework; - -namespace Dynamo.Tests -{ - /// - /// Test class to test the UpdateManager class and its related classes - /// - [TestFixture] - public class UpdatesTests - { - private UpdateManager updateManager; - - [SetUp] - public void Init() - { - //Create an instance of the UpdateManager class to be used in the tests. - var config = UpdateManagerConfiguration.GetSettings(null); - updateManager = new UpdateManager(config); - } - - #region UpdateDownloadedEventArgs - [Test] - [Category("UnitTests")] - public void UpdateDownloadedEventArgsConstructorTest() - { - Exception e = new Exception("Error"); - string fileLocation = "FileLocation"; - - var eventArgs = new UpdateDownloadedEventArgs(e, fileLocation); - - Assert.AreEqual(e, eventArgs.Error); - Assert.AreEqual(fileLocation, eventArgs.UpdateFileLocation); - - //UpdateAvailable depends on FileLocation. If it's null, it will be false, else it is true. - Assert.IsTrue(eventArgs.UpdateAvailable); - - eventArgs = new UpdateDownloadedEventArgs(e, null); - Assert.IsFalse(eventArgs.UpdateAvailable); - } - #endregion - - #region UpdateManagerConfiguration - [Test] - [Category("UnitTests")] - public void UpdateManagerConfigurationLoadTest() - { - //Testing all the calls for Load that return null - Assert.IsNull(UpdateManagerConfiguration.Load(null, updateManager)); - Assert.IsNull(UpdateManagerConfiguration.Load("", updateManager)); - Assert.IsNull(UpdateManagerConfiguration.Load("filePath", updateManager)); - Assert.IsNull(UpdateManagerConfiguration.Load(Path.GetTempFileName(), updateManager)); - } - - [Test] - [Category("UnitTests")] - public void UpdateManagerConfigurationSaveTest() - { - var config = new UpdateManagerConfiguration(); - var goodPath = Path.GetTempFileName(); - var badPath = "W:\\PathThatDoesntExist"; - - //Happy path - Assert.DoesNotThrow(() => config.Save(goodPath, updateManager)); - - //if statement in the catch block - Assert.DoesNotThrow(() => config.Save(badPath, updateManager)); - - //else statement in the catch block - Assert.Throws(() => config.Save(badPath, null)); - } - - [Test] - [Category("UnitTests")] - public void UpdateManagerConfigurationPropertiesTest() - { - var config = (UpdateManagerConfiguration)updateManager.Configuration; - - //CheckNewerDailyBuild - //Set to false and then true to trigger if statement. - config.CheckNewerDailyBuild = false; - config.CheckNewerDailyBuild = true; - - Assert.AreEqual(true, config.CheckNewerDailyBuild); - - //ForceUpdate - //Set to false and then true to trigger if statement. - config.ForceUpdate = false; - config.ForceUpdate = true; - - Assert.AreEqual(true, config.ForceUpdate); - } - #endregion - - #region UpdateManager - [Test] - [Category("UnitTests")] - public void QuitAndInstallUpdateTest() - { - //This handler is used to cover the if statement - updateManager.ShutdownRequested += TestShutdownRequestedHandler; - Assert.DoesNotThrow(() => updateManager.QuitAndInstallUpdate()); - updateManager.ShutdownRequested -= TestShutdownRequestedHandler; - } - - private void TestShutdownRequestedHandler(IUpdateManager updateManager) { } - - [Test] - [Category("UnitTests")] - public void BaseVersionTest() - { - updateManager.DownloadedUpdateInfo = new AppVersionInfo() { Version = BinaryVersion.FromString("5.5.5.5") }; - updateManager.UpdateInfo = new AppVersionInfo() { Version = BinaryVersion.FromString("5.5.5.5") }; - - //These two cases are to cover both routes in the BaseVersion if statement. - //ProductVersion < HostVersion - updateManager.HostVersion = new Version(9, 9, 9, 9); - Assert.IsTrue(updateManager.IsUpdateAvailable); - - //ProductVersion > HostVersion - updateManager.HostVersion = new Version(1, 1, 1, 1); - Assert.IsTrue(updateManager.IsUpdateAvailable); - } - - [Test] - [Category("UnitTests")] - public void UpdateManagerPropertiesTest() - { - //CheckNewerDailyBuild - //Set to false and then true to trigger if statement. - updateManager.CheckNewerDailyBuilds = false; - updateManager.CheckNewerDailyBuilds = true; - - Assert.AreEqual(true, updateManager.CheckNewerDailyBuilds); - - //ForceUpdate - //Set to false and then true to trigger if statement. - updateManager.ForceUpdate = false; - updateManager.ForceUpdate = true; - - Assert.AreEqual(true, updateManager.ForceUpdate); - - // HostName - updateManager.HostName = "Host Name"; - Assert.AreEqual("Host Name", updateManager.HostName); - - //UpdateFileLocation - _ = new UpdateManager(new UpdateManagerConfiguration()); - // For a new UpdateManager, the UpdateFileLocation property is not initialized. - Assert.That(updateManager.UpdateFileLocation, Is.Null.Or.Empty); - } - - [Test] - [Category("UnitTests")] - public void IsStableBuildTest() - { - //If fileName does not contain installNameBase, returns false. - Assert.IsFalse(UpdateManager.IsStableBuild("InstallNameBase", "FileName")); - } - - [Test] - [Category("UnitTests")] - public void IsDailyBuildTest() - { - //If fileName does not contain installNameBase, returns false. - Assert.IsFalse(UpdateManager.IsDailyBuild("InstallNameBase", "FileName")); - } - - [Test] - [Category("UnitTests")] - public void RegisterExternalApplicationProcessIdTest() - { - //This is a void method that sets a private attribute. There is no way to validate whether the - //value was changed or not, but this covers the code and makes sure no exceptions are thrown. - Assert.DoesNotThrow(() => updateManager.RegisterExternalApplicationProcessId(1)); - } - - [Test] - [Category("UnitTests")] - public void OnLogTest() - { - //Create and validate the LogEventArgs - var logEventArgs = new LogEventArgs("Test", LogLevel.Console); - - Assert.AreEqual(LogLevel.Console, logEventArgs.Level); - Assert.AreEqual("Test", logEventArgs.Message); - - //Bind the handler and call OnLog - updateManager.Log += TestLogHandler; - updateManager.OnLog(logEventArgs); - updateManager.Log -= TestLogHandler; - } - - private void TestLogHandler(LogEventArgs args) { } - #endregion - - #region DynamoLookup - private class DynamoLookupChildTest : DynamoLookUp - { - public override IEnumerable GetDynamoInstallLocations() - { - return new List(); - } - } - - [Test] - [Category("UnitTests")] - public void DynamoLookupTests() - { - var lookup = new DynamoLookupChildTest(); - - //LatestProduct will be null in this case because in DynamoLookupChildTest, the implementation of GetDynamoInstallLocations returns an empty list. - Assert.IsNull(lookup.LatestProduct); - Assert.IsNull(lookup.GetDynamoVersion(Path.GetTempPath())); - Assert.IsNotNull(lookup.GetDynamoUserDataLocations()); - } - #endregion - - #region UpdateRequest - [Test] - [Category("UnitTests")] - public void UpdateRequestConstructorTest() - { - var path = new Uri(Path.GetTempPath()); - var updateRequest = new UpdateRequest(path, updateManager); - - Assert.IsNotNull(updateRequest.OnRequestCompleted); - Assert.IsNotNull(updateRequest.Data); - Assert.IsNotNull(updateRequest.Error); - Assert.IsNotNull(updateRequest.Path); - } - #endregion - } -} diff --git a/test/DynamoCoreTests/UserDataMigrationTests.cs b/test/DynamoCoreTests/UserDataMigrationTests.cs index e2fadd586f7..9b9ed5776ef 100644 --- a/test/DynamoCoreTests/UserDataMigrationTests.cs +++ b/test/DynamoCoreTests/UserDataMigrationTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -183,25 +183,15 @@ public void GetSortedInstalledVersions_FromDirectoryInspection() { Assert.IsTrue(e.ParamName == "rootFolder"); } - - try - { - DynamoMigratorBase.GetInstalledVersions(null); - } - catch (ArgumentNullException e) - { - Assert.IsTrue(e.ParamName == "rootFolder"); - } - } [Test, Category("UnitTests")] public void GetSortedInstallVersion_FromDynamoLookUp() { - var mockLookup = new Mock(); - mockLookup.Setup(x=>x.GetDynamoUserDataLocations()).Returns(MockUserDirectories); + var mockLookup = new Mock(); + mockLookup.Setup(x=>x.PathResolver.GetDynamoUserDataLocations()).Returns(MockUserDirectories); - var versionList = DynamoMigratorBase.GetInstalledVersions(null, mockLookup.Object).ToList(); + var versionList = DynamoMigratorBase.GetInstalledVersions(mockLookup.Object).ToList(); VerifySortedOrder(versionList); Assert.AreEqual(5, versionList.Count); Assert.AreEqual(TempFolder, versionList[0].UserDataRoot); @@ -212,11 +202,11 @@ public void GetSortedInstallVersion_FromDynamoLookUp() [Test, Category("UnitTests")] public void GetLatestVersionToMigrate() { - var mockLookup = new Mock(); - mockLookup.Setup(x => x.GetDynamoUserDataLocations()).Returns(MockUserDirectories); + var mockLookup = new Mock(); + mockLookup.Setup(x => x.PathResolver.GetDynamoUserDataLocations()).Returns(MockUserDirectories); var current = new FileVersion(1, 0, Path.Combine(TempFolder, "Test")); - var latest = DynamoMigratorBase.GetLatestVersionToMigrate(null, mockLookup.Object, current); + var latest = DynamoMigratorBase.GetLatestVersionToMigrate(mockLookup.Object, current); Assert.IsTrue(latest.HasValue); Assert.AreEqual(1, latest.Value.MajorPart); Assert.AreEqual(0, latest.Value.MinorPart); @@ -226,11 +216,11 @@ public void GetLatestVersionToMigrate() [Test, Category("UnitTests")] public void GetLatestVersionToMigrate_10() { - var mockLookup = new Mock(); - mockLookup.Setup(x => x.GetDynamoUserDataLocations()).Returns(MockUserDirectories); + var mockLookup = new Mock(); + mockLookup.Setup(x => x.PathResolver.GetDynamoUserDataLocations()).Returns(MockUserDirectories); var current = new FileVersion(1, 0, TempFolder); - var latest = DynamoMigratorBase.GetLatestVersionToMigrate(null, mockLookup.Object, current); + var latest = DynamoMigratorBase.GetLatestVersionToMigrate(mockLookup.Object, current); Assert.IsTrue(latest.HasValue); Assert.AreEqual(1, latest.Value.MajorPart); Assert.AreEqual(0, latest.Value.MinorPart); @@ -241,11 +231,11 @@ public void GetLatestVersionToMigrate_10() [Test, Category("UnitTests")] public void GetLatestVersionToMigrate_PartiallyValidData() { - var mockLookup = new Mock(); - mockLookup.Setup(x => x.GetDynamoUserDataLocations()).Returns(MockUserDirectories); + var mockLookup = new Mock(); + mockLookup.Setup(x => x.PathResolver.GetDynamoUserDataLocations()).Returns(MockUserDirectories); var current = new FileVersion(0, 9, TempFolder); - var latest = DynamoMigratorBase.GetLatestVersionToMigrate(null, mockLookup.Object, current); + var latest = DynamoMigratorBase.GetLatestVersionToMigrate(mockLookup.Object, current); Assert.IsTrue(latest.HasValue); Assert.AreEqual(0, latest.Value.MajorPart); Assert.AreEqual(8, latest.Value.MinorPart); @@ -255,11 +245,11 @@ public void GetLatestVersionToMigrate_PartiallyValidData() [Test, Category("UnitTests")] public void GetLatestVersionToMigrate_AllInvalidData() { - var mockLookup = new Mock(); - mockLookup.Setup(x => x.GetDynamoUserDataLocations()).Returns(new[] { "x", "y", "z" }); + var mockLookup = new Mock(); + mockLookup.Setup(x => x.PathResolver.GetDynamoUserDataLocations()).Returns(new[] { "x", "y", "z" }); var current = new FileVersion(1, 0, "a"); - var latest = DynamoMigratorBase.GetLatestVersionToMigrate(null, mockLookup.Object, current); + var latest = DynamoMigratorBase.GetLatestVersionToMigrate(mockLookup.Object, current); Assert.IsTrue(!latest.HasValue || latest.Value.UserDataRoot == null); } diff --git a/test/DynamoCoreWpfTests/UpdateManagerUITests.cs b/test/DynamoCoreWpfTests/UpdateManagerUITests.cs deleted file mode 100644 index febc9476796..00000000000 --- a/test/DynamoCoreWpfTests/UpdateManagerUITests.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Windows; -using Dynamo.UI.Controls; -using Dynamo.Updates; -using Moq; -using NUnit.Framework; -using SystemTestServices; -using DynamoCoreWpfTests.Utility; - -namespace DynamoCoreWpfTests -{ - [TestFixture] - public class UpdateManagerUITests : SystemTestBase - { - private const string DOWNLOAD_SOURCE_PATH_S = "http://downloadsourcepath/"; - private const string SIGNATURE_SOURCE_PATH_S = "http://SignatureSourcePath/"; - - private void MockUpdateManager(bool isUpToDate) - { - var umMock = new Mock(); - umMock.Setup(um => um.IsUpdateAvailable).Returns(!isUpToDate); - - UpdateManager = umMock.Object; - } - - [SetUp] - public override void Setup() - { - //override this to avoid the typical startup behavior - } - } -} diff --git a/test/Libraries/SystemTestServices/SystemTestBase.cs b/test/Libraries/SystemTestServices/SystemTestBase.cs index 9d7a3be1dea..d7eada732b5 100644 --- a/test/Libraries/SystemTestServices/SystemTestBase.cs +++ b/test/Libraries/SystemTestServices/SystemTestBase.cs @@ -46,8 +46,6 @@ public abstract class SystemTestBase protected DynamoModel Model { get; set; } - protected IUpdateManager UpdateManager { get; set; } - protected string ExecutingDirectory { get { return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } @@ -193,7 +191,6 @@ protected virtual void StartDynamo(TestSessionConfiguration testConfig) StartInTestMode = true, PathResolver = pathResolver, GeometryFactoryPath = preloader.GeometryFactoryPath, - UpdateManager = this.UpdateManager, ProcessMode = TaskProcessMode.Synchronous }); diff --git a/test/Libraries/TestServices/TestPathResolver.cs b/test/Libraries/TestServices/TestPathResolver.cs index 53703582d5f..ae697deca31 100644 --- a/test/Libraries/TestServices/TestPathResolver.cs +++ b/test/Libraries/TestServices/TestPathResolver.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using System.Linq; using Dynamo.Interfaces; namespace TestServices @@ -81,5 +82,11 @@ public string CommonDataRootFolder { get { return commonDataRootFolder; } } + + public IEnumerable GetDynamoUserDataLocations() + { + // Do nothing for now. + return Enumerable.Empty(); + } } } diff --git a/test/VisualizationTests/HelixWatch3DViewModelTests.cs b/test/VisualizationTests/HelixWatch3DViewModelTests.cs index b140dd269eb..83dda4484af 100644 --- a/test/VisualizationTests/HelixWatch3DViewModelTests.cs +++ b/test/VisualizationTests/HelixWatch3DViewModelTests.cs @@ -99,7 +99,6 @@ protected override void StartDynamo(TestSessionConfiguration testConfig) StartInTestMode = true, PathResolver = pathResolver, GeometryFactoryPath = preloader.GeometryFactoryPath, - UpdateManager = this.UpdateManager, ProcessMode = TaskProcessMode.Synchronous, Preferences = PreferenceSettings.Instance });