public async Task InstallPackage(IProgress<double> progress, PackageVersionInfo package, CancellationToken cancellationToken) { // Target based on if it is an archive or single assembly // zip archives are assumed to contain directory structures relative to our ProgramDataPath var isArchive = string.Equals(Path.GetExtension(package.targetFilename), ".zip", StringComparison.OrdinalIgnoreCase); var target = Path.Combine(isArchive ? _appPaths.TempUpdatePath : _appPaths.PluginsPath, package.targetFilename); // Download to temporary file so that, if interrupted, it won't destroy the existing installation var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions { Url = package.sourceUrl, CancellationToken = cancellationToken, Progress = progress }).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Validate with a checksum if (package.checksum != Guid.Empty) // support for legacy uploads for now { using (var crypto = new MD5CryptoServiceProvider()) using (var stream = new BufferedStream(File.OpenRead(tempFile), 100000)) { var check = Guid.Parse(BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", String.Empty)); if (check != package.checksum) { throw new ApplicationException(string.Format("Download validation failed for {0}. Probably corrupted during transfer.", package.name)); } } } cancellationToken.ThrowIfCancellationRequested(); // Success - move it to the real target try { File.Copy(tempFile, target, true); //If it is an archive - write out a version file so we know what it is if (isArchive) { File.WriteAllText(target+".ver", package.versionStr); } } catch (IOException e) { _logger.ErrorException("Error attempting to move file from {0} to {1}", e, tempFile, target); throw; } try { File.Delete(tempFile); } catch (IOException e) { // Don't fail because of this _logger.ErrorException("Error deleting temp file {0]", e, tempFile); } }
/// <summary> /// Called when [plugin installed]. /// </summary> /// <param name="package">The package.</param> private void OnPluginInstalled(PackageVersionInfo package) { _logger.Info("New plugin installed: {0} {1} {2}", package.name, package.version, package.classification); EventHelper.QueueEventIfNotNull(PluginInstalled, this, new GenericEventArgs<PackageVersionInfo> { Argument = package }, _logger); ApplicationHost.NotifyPendingRestart(); }
/// <summary> /// Called when [plugin updated]. /// </summary> /// <param name="plugin">The plugin.</param> /// <param name="newVersion">The new version.</param> private void OnPluginUpdated(IPlugin plugin, PackageVersionInfo newVersion) { _logger.Info("Plugin updated: {0} {1} {2}", newVersion.name, newVersion.version, newVersion.classification); EventHelper.QueueEventIfNotNull(PluginUpdated, this, new GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>> { Argument = new Tuple<IPlugin, PackageVersionInfo>(plugin, newVersion) }, _logger); ApplicationHost.NotifyPendingRestart(); }
public async void Install(PackageVersionInfo version) { _installationManager.InstallPackage(version, new Progress<double>(), CancellationToken.None); await _nav.NavigateToSettingsPage(); _nav.RemovePagesFromHistory(3); }
/// <summary> /// Installs the package internal. /// </summary> /// <param name="package">The package.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task InstallPackageInternal(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken) { // Do the install await _packageManager.InstallPackage(progress, package, cancellationToken).ConfigureAwait(false); // Do plugin-specific processing if (!(Path.GetExtension(package.targetFilename) ?? "").Equals(".zip", StringComparison.OrdinalIgnoreCase)) { // Set last update time if we were installed before var plugin = ApplicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase)); if (plugin != null) { OnPluginUpdated(plugin, package); } else { OnPluginInstalled(package); } } }
/// <summary> /// Installs the package. /// </summary> /// <param name="package">The package.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException">package</exception> public async Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken) { if (package == null) { throw new ArgumentNullException("package"); } if (progress == null) { throw new ArgumentNullException("progress"); } if (cancellationToken == null) { throw new ArgumentNullException("cancellationToken"); } var installationInfo = new InstallationInfo { Id = Guid.NewGuid(), Name = package.name, UpdateClass = package.classification, Version = package.versionStr }; var innerCancellationTokenSource = new CancellationTokenSource(); var tuple = new Tuple<InstallationInfo, CancellationTokenSource>(installationInfo, innerCancellationTokenSource); // Add it to the in-progress list lock (CurrentInstallations) { CurrentInstallations.Add(tuple); } var innerProgress = new ActionableProgress<double>(); // Whenever the progress updates, update the outer progress object and InstallationInfo innerProgress.RegisterAction(percent => { progress.Report(percent); installationInfo.PercentComplete = percent; }); var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token; var installationEventArgs = new InstallationEventArgs { InstallationInfo = installationInfo, PackageVersionInfo = package }; EventHelper.QueueEventIfNotNull(PackageInstalling, this, installationEventArgs, _logger); try { await InstallPackageInternal(package, innerProgress, linkedToken).ConfigureAwait(false); lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } CompletedInstallations.Add(installationInfo); EventHelper.QueueEventIfNotNull(PackageInstallationCompleted, this, installationEventArgs, _logger); } catch (OperationCanceledException) { lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } _logger.Info("Package installation cancelled: {0} {1}", package.name, package.versionStr); EventHelper.QueueEventIfNotNull(PackageInstallationCancelled, this, installationEventArgs, _logger); throw; } catch (Exception ex) { _logger.ErrorException("Package installation failed", ex); lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } EventHelper.QueueEventIfNotNull(PackageInstallationFailed, this, new InstallationFailedEventArgs { InstallationInfo = installationInfo, Exception = ex }, _logger); throw; } finally { // Dispose the progress object and remove the installation from the in-progress list innerProgress.Dispose(); tuple.Item2.Dispose(); } }
/// <summary> /// Determines whether [is package version up to date] [the specified package version info]. /// </summary> /// <param name="packageVersionInfo">The package version info.</param> /// <param name="applicationVersion">The application version.</param> /// <returns><c>true</c> if [is package version up to date] [the specified package version info]; otherwise, <c>false</c>.</returns> private bool IsPackageVersionUpToDate(PackageVersionInfo packageVersionInfo, Version applicationVersion) { if (string.IsNullOrEmpty(packageVersionInfo.requiredVersionStr)) { return true; } Version requiredVersion; return Version.TryParse(packageVersionInfo.requiredVersionStr, out requiredVersion) && applicationVersion >= requiredVersion; }
/// <summary> /// Installs the package internal. /// </summary> /// <param name="package">The package.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task InstallPackageInternal(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken) { // Do the install await PerformPackageInstallation(progress, package, cancellationToken).ConfigureAwait(false); var extension = Path.GetExtension(package.targetFilename) ?? ""; // Do plugin-specific processing if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase)) { // Set last update time if we were installed before var plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase)) ?? _applicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase)); if (plugin != null) { OnPluginUpdated(plugin, package); } else { OnPluginInstalled(package); } } }
private Version GetPackageVersion(PackageVersionInfo version) { return new Version(ValueOrDefault(version.versionStr, "0.0.0.1")); }
/// <summary> /// Initializes a new instance of the <see cref="PackageInfo"/> class. /// </summary> public PackageInfo() { versions = new PackageVersionInfo[] { }; }