public async Task <ILibraryOperationResult> InstallAsync(ILibraryInstallationState desiredState, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(desiredState)); } //Expand the files property if needed ILibraryOperationResult updateResult = await UpdateStateAsync(desiredState, cancellationToken); if (!updateResult.Success) { return(updateResult); } desiredState = updateResult.InstallationState; // Refresh cache if needed ILibraryOperationResult cacheUpdateResult = await RefreshCacheAsync(desiredState, cancellationToken); if (!cacheUpdateResult.Success) { return(cacheUpdateResult); } // Check if Library is already up tp date if (IsLibraryUpToDate(desiredState, cancellationToken)) { return(LibraryOperationResult.FromUpToDate(desiredState)); } // Write files to destination return(await WriteToFilesAsync(desiredState, cancellationToken)); }
/// <summary> /// Updates file set on the passed in ILibraryInstallationState in case user selected to have all files included /// </summary> /// <param name="desiredState"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task <ILibraryOperationResult> UpdateStateAsync(ILibraryInstallationState desiredState, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(desiredState)); } string libraryId = LibraryIdToNameAndVersionConverter.Instance.GetLibraryId(desiredState.Name, desiredState.Version, Id); try { ILibraryCatalog catalog = GetCatalog(); ILibrary library = await catalog.GetLibraryAsync(desiredState.Name, desiredState.Version, cancellationToken).ConfigureAwait(false); if (library == null) { return(new LibraryOperationResult(desiredState, PredefinedErrors.UnableToResolveSource(desiredState.Name, desiredState.ProviderId))); } if (desiredState.Files != null && desiredState.Files.Count > 0) { IReadOnlyList <string> invalidFiles = library.GetInvalidFiles(desiredState.Files); if (invalidFiles.Any()) { IError invalidFilesError = PredefinedErrors.InvalidFilesInLibrary(libraryId, invalidFiles, library.Files.Keys); return(new LibraryOperationResult(desiredState, invalidFilesError)); } else { return(LibraryOperationResult.FromSuccess(desiredState)); } } desiredState = new LibraryInstallationState { ProviderId = Id, Name = desiredState.Name, Version = desiredState.Version, DestinationPath = desiredState.DestinationPath, Files = library.Files.Keys.ToList(), IsUsingDefaultDestination = desiredState.IsUsingDefaultDestination, IsUsingDefaultProvider = desiredState.IsUsingDefaultProvider }; } catch (InvalidLibraryException) { return(new LibraryOperationResult(desiredState, PredefinedErrors.UnableToResolveSource(libraryId, desiredState.ProviderId))); } catch (UnauthorizedAccessException) { return(new LibraryOperationResult(desiredState, PredefinedErrors.PathOutsideWorkingDirectory())); } catch (Exception ex) { HostInteraction.Logger.Log(ex.ToString(), LogLevel.Error); return(new LibraryOperationResult(desiredState, PredefinedErrors.UnknownException())); } return(LibraryOperationResult.FromSuccess(desiredState)); }
/// <summary> /// Installs a library as specified in the <paramref name="desiredState" /> parameter. /// </summary> /// <param name="desiredState">The details about the library to install.</param> /// <param name="cancellationToken">A token that allows for the operation to be cancelled.</param> /// <returns> /// The <see cref="Microsoft.Web.LibraryManager.Contracts.ILibraryOperationResult" /> from the installation process. /// </returns> public override async Task <ILibraryOperationResult> InstallAsync(ILibraryInstallationState desiredState, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(desiredState)); } try { ILibraryOperationResult result = await UpdateStateAsync(desiredState, cancellationToken); if (!result.Success) { return(result); } desiredState = result.InstallationState; foreach (string file in desiredState.Files) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(desiredState)); } if (string.IsNullOrEmpty(file)) { return(new LibraryOperationResult(desiredState, PredefinedErrors.CouldNotWriteFile(file))); } string path = Path.Combine(desiredState.DestinationPath, file); var sourceStream = new Func <Stream>(() => GetStreamAsync(desiredState, file, cancellationToken).Result); bool writeOk = await HostInteraction.WriteFileAsync(path, sourceStream, desiredState, cancellationToken).ConfigureAwait(false); if (!writeOk) { return(new LibraryOperationResult(desiredState, PredefinedErrors.CouldNotWriteFile(file))); } } } catch (UnauthorizedAccessException) { return(new LibraryOperationResult(desiredState, PredefinedErrors.PathOutsideWorkingDirectory())); } catch (ResourceDownloadException ex) { return(new LibraryOperationResult(desiredState, PredefinedErrors.FailedToDownloadResource(ex.Url))); } catch (Exception ex) { HostInteraction.Logger.Log(ex.ToString(), LogLevel.Error); return(new LibraryOperationResult(desiredState, PredefinedErrors.UnknownException())); } return(LibraryOperationResult.FromSuccess(desiredState)); }
public void FromCancelled() { Mocks.LibraryInstallationState state = GetState(); var result = LibraryOperationResult.FromCancelled(state); Assert.AreEqual(state, result.InstallationState); Assert.AreEqual(0, result.Errors.Count); Assert.IsFalse(result.Success); Assert.IsTrue(result.Cancelled); }
private async Task UninstallLibraryAsync(string configFilePath, string libraryName, string version, string providerId, CancellationToken cancellationToken) { string libraryId = LibraryIdToNameAndVersionConverter.Instance.GetLibraryId(libraryName, version, providerId); Logger.LogEventsHeader(OperationType.Uninstall, libraryId); try { Stopwatch sw = new Stopwatch(); sw.Start(); var dependencies = _dependenciesFactory.FromConfigFile(configFilePath); Manifest manifest = await Manifest.FromFileAsync(configFilePath, dependencies, cancellationToken).ConfigureAwait(false); ILibraryOperationResult result = null; if (manifest == null) { result = LibraryOperationResult.FromError(PredefinedErrors.ManifestMalformed()); } else { IHostInteraction hostInteraction = dependencies.GetHostInteractions(); result = await manifest.UninstallAsync(libraryName, version, async (filesPaths) => await hostInteraction.DeleteFilesAsync(filesPaths, cancellationToken), cancellationToken).ConfigureAwait(false); } sw.Stop(); if (result.Errors.Any()) { Logger.LogErrorsSummary(new List <ILibraryOperationResult> { result }, OperationType.Uninstall); } else { Logger.LogEventsSummary(new List <ILibraryOperationResult> { result }, OperationType.Uninstall, sw.Elapsed); } Telemetry.LogEventsSummary(new List <ILibraryOperationResult> { result }, OperationType.Uninstall, sw.Elapsed); } catch (OperationCanceledException ex) { Logger.LogEvent(string.Format(LibraryManager.Resources.Text.Uninstall_LibraryCancelled, libraryId), LogLevel.Task); Telemetry.TrackException($@"{OperationType.Uninstall}Cancelled", ex); } }
protected virtual ILibraryOperationResult CheckForInvalidFiles(ILibraryInstallationState desiredState, string libraryId, ILibrary library) { IReadOnlyList <string> invalidFiles = library.GetInvalidFiles(desiredState.Files); if (invalidFiles.Count > 0) { IError invalidFilesError = PredefinedErrors.InvalidFilesInLibrary(libraryId, invalidFiles, library.Files.Keys); return(new LibraryOperationResult(desiredState, invalidFilesError)); } else { return(LibraryOperationResult.FromSuccess(desiredState)); } }
/// <summary> /// Copies ILibraryInstallationState files to cache /// </summary> /// <param name="state"></param> /// <param name="cancellationToken"></param> /// <returns></returns> private async Task <ILibraryOperationResult> RefreshCacheAsync(ILibraryInstallationState state, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(state)); } var tasks = new List <Task>(); try { if (!string.IsNullOrEmpty(state.Name) && !string.IsNullOrEmpty(state.Version)) { string libraryDir = Path.Combine(CacheFolder, state.Name); List <CacheServiceMetadata> librariesMetadata = new List <CacheServiceMetadata>(); foreach (string sourceFile in state.Files) { string cacheFile = Path.Combine(libraryDir, state.Version, sourceFile); string url = string.Format(_downloadUrlFormat, state.Name, state.Version, sourceFile); CacheServiceMetadata newEntry = new CacheServiceMetadata(url, cacheFile); if (!librariesMetadata.Contains(newEntry)) { librariesMetadata.Add(new CacheServiceMetadata(url, cacheFile)); } } await _cacheService.RefreshCacheAsync(librariesMetadata, cancellationToken); } } catch (ResourceDownloadException ex) { HostInteraction.Logger.Log(ex.ToString(), LogLevel.Error); return(new LibraryOperationResult(state, PredefinedErrors.FailedToDownloadResource(ex.Url))); } catch (OperationCanceledException) { return(LibraryOperationResult.FromCancelled(state)); } catch (Exception ex) { HostInteraction.Logger.Log(ex.InnerException.ToString(), LogLevel.Error); return(new LibraryOperationResult(state, PredefinedErrors.UnknownException())); } return(LibraryOperationResult.FromSuccess(state)); }
/// <summary> /// Updates file set on the passed in ILibraryInstallationState in case user selected to have all files included /// </summary> /// <param name="desiredState"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task <ILibraryOperationResult> UpdateStateAsync(ILibraryInstallationState desiredState, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(desiredState)); } try { ILibraryCatalog catalog = GetCatalog(); ILibrary library = await catalog.GetLibraryAsync(desiredState.LibraryId, cancellationToken).ConfigureAwait(false); if (library == null) { return(new LibraryOperationResult(desiredState, PredefinedErrors.UnableToResolveSource(desiredState.LibraryId, Id))); } if (desiredState.Files != null && desiredState.Files.Count > 0) { return(LibraryOperationResult.FromSuccess(desiredState)); } desiredState = new LibraryInstallationState { ProviderId = Id, LibraryId = desiredState.LibraryId, DestinationPath = desiredState.DestinationPath, Files = library.Files.Keys.ToList(), }; } catch (InvalidLibraryException) { return(new LibraryOperationResult(desiredState, PredefinedErrors.UnableToResolveSource(desiredState.LibraryId, desiredState.ProviderId))); } catch (UnauthorizedAccessException) { return(new LibraryOperationResult(desiredState, PredefinedErrors.PathOutsideWorkingDirectory())); } catch (Exception ex) { HostInteraction.Logger.Log(ex.ToString(), LogLevel.Error); return(new LibraryOperationResult(desiredState, PredefinedErrors.UnknownException())); } return(LibraryOperationResult.FromSuccess(desiredState)); }
public void Constructor() { Mocks.LibraryInstallationState state = GetState(); var ctor1 = new LibraryOperationResult(state); Assert.AreEqual(state, ctor1.InstallationState); Assert.AreEqual(0, ctor1.Errors.Count); Assert.IsTrue(ctor1.Success); Assert.IsFalse(ctor1.Cancelled); var ctor2 = new LibraryOperationResult(state, PredefinedErrors.ManifestMalformed()); Assert.AreEqual(state, ctor2.InstallationState); Assert.AreEqual(1, ctor2.Errors.Count); Assert.IsFalse(ctor2.Success); Assert.IsFalse(ctor2.Cancelled); }
/// <summary> /// Copy files from the download cache to the desired installation state /// </summary> /// <remarks>Precondition: all files must already exist in the cache</remarks> protected async Task <ILibraryOperationResult> WriteToFilesAsync(ILibraryInstallationState state, CancellationToken cancellationToken) { if (state.Files != null) { try { foreach (string file in state.Files) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(state)); } if (string.IsNullOrEmpty(file)) { string id = LibraryNamingScheme.GetLibraryId(state.Name, state.Version); return(new LibraryOperationResult(state, PredefinedErrors.FileNameMustNotBeEmpty(id))); } string sourcePath = GetCachedFileLocalPath(state, file); string destinationPath = Path.Combine(state.DestinationPath, file); bool writeOk = await HostInteraction.CopyFileAsync(sourcePath, destinationPath, cancellationToken); if (!writeOk) { return(new LibraryOperationResult(state, PredefinedErrors.CouldNotWriteFile(file))); } } } catch (UnauthorizedAccessException) { return(new LibraryOperationResult(state, PredefinedErrors.PathOutsideWorkingDirectory())); } catch (Exception ex) { HostInteraction.Logger.Log(ex.ToString(), LogLevel.Error); return(new LibraryOperationResult(state, PredefinedErrors.UnknownException())); } } return(LibraryOperationResult.FromSuccess(state)); }
private async Task <ILibraryOperationResult> WriteToFilesAsync(ILibraryInstallationState state, CancellationToken cancellationToken) { if (state.Files != null) { try { foreach (string file in state.Files) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(state)); } if (string.IsNullOrEmpty(file)) { return(new LibraryOperationResult(state, PredefinedErrors.CouldNotWriteFile(file))); } string destinationPath = Path.Combine(state.DestinationPath, file); var sourceStream = new Func <Stream>(() => GetStreamAsync(state, file, cancellationToken).Result); bool writeOk = await HostInteraction.WriteFileAsync(destinationPath, sourceStream, state, cancellationToken).ConfigureAwait(false); if (!writeOk) { return(new LibraryOperationResult(state, PredefinedErrors.CouldNotWriteFile(file))); } } } catch (UnauthorizedAccessException) { return(new LibraryOperationResult(state, PredefinedErrors.PathOutsideWorkingDirectory())); } catch (Exception ex) { HostInteraction.Logger.Log(ex.ToString(), LogLevel.Error); return(new LibraryOperationResult(state, PredefinedErrors.UnknownException())); } } return(LibraryOperationResult.FromSuccess(state)); }
/// <summary> /// Validates <see cref="ILibraryInstallationState"/> /// </summary> /// <param name="state">The <see cref="ILibraryInstallationState"/> to validate.</param> /// <param name="provider">The <see cref="IProvider"/> used to validate <see cref="ILibraryInstallationState"/></param> /// <returns><see cref="ILibraryOperationResult"/> with the result of the validation</returns> public static async Task <ILibraryOperationResult> IsValidAsync(this ILibraryInstallationState state, IProvider provider) { if (state == null) { return(new LibraryOperationResult(state, new[] { PredefinedErrors.UnknownError() })); } if (provider == null) { return(new LibraryOperationResult(state, new[] { PredefinedErrors.ProviderUnknown(provider.Id) })); } if (string.IsNullOrEmpty(state.Name)) { return(new LibraryOperationResult(state, new[] { PredefinedErrors.LibraryIdIsUndefined() })); } ILibraryCatalog catalog = provider.GetCatalog(); try { await catalog.GetLibraryAsync(state.Name, state.Version, CancellationToken.None).ConfigureAwait(false); } catch { return(new LibraryOperationResult(state, new[] { PredefinedErrors.UnableToResolveSource(state.Name, state.Version, provider.Id) })); } if (string.IsNullOrEmpty(state.DestinationPath)) { return(new LibraryOperationResult(state, new[] { PredefinedErrors.PathIsUndefined() })); } if (state.DestinationPath.IndexOfAny(Path.GetInvalidPathChars()) >= 0) { return(new LibraryOperationResult(state, new[] { PredefinedErrors.DestinationPathHasInvalidCharacters(state.DestinationPath) })); } return(LibraryOperationResult.FromSuccess(state)); }
/// <summary> /// Copies ILibraryInstallationState files to cache /// </summary> /// <param name="state"></param> /// <param name="cancellationToken"></param> /// <returns></returns> private async Task <ILibraryOperationResult> RefreshCacheAsync(ILibraryInstallationState state, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(state)); } string libraryDir = Path.Combine(CacheFolder, state.Name, state.Version); try { var librariesMetadata = new HashSet <CacheFileMetadata>(); foreach (string sourceFile in state.Files) { string cacheFile = Path.Combine(libraryDir, sourceFile); string url = GetDownloadUrl(state, sourceFile); var newEntry = new CacheFileMetadata(url, cacheFile); librariesMetadata.Add(newEntry); } await _cacheService.RefreshCacheAsync(librariesMetadata, HostInteraction.Logger, cancellationToken); } catch (ResourceDownloadException ex) { HostInteraction.Logger.Log(ex.ToString(), LogLevel.Error); return(new LibraryOperationResult(state, PredefinedErrors.FailedToDownloadResource(ex.Url))); } catch (OperationCanceledException) { return(LibraryOperationResult.FromCancelled(state)); } catch (Exception ex) { HostInteraction.Logger.Log(ex.InnerException.ToString(), LogLevel.Error); return(new LibraryOperationResult(state, PredefinedErrors.UnknownException())); } return(LibraryOperationResult.FromSuccess(state)); }
private async Task UninstallLibraryAsync(string configFilePath, string libraryId, CancellationToken cancellationToken) { Logger.LogEventsHeader(OperationType.Uninstall, libraryId); try { Stopwatch sw = new Stopwatch(); sw.Start(); var dependencies = Dependencies.FromConfigFile(configFilePath); Manifest manifest = await Manifest.FromFileAsync(configFilePath, dependencies, cancellationToken).ConfigureAwait(false); ILibraryOperationResult result = null; if (manifest == null) { result = LibraryOperationResult.FromError(PredefinedErrors.ManifestMalformed()); } else { IHostInteraction hostInteraction = dependencies.GetHostInteractions(); result = await manifest.UninstallAsync(libraryId, async (filesPaths) => await hostInteraction.DeleteFilesAsync(filesPaths, cancellationToken), cancellationToken).ConfigureAwait(false); } sw.Stop(); Logger.LogEventsSummary(new List <ILibraryOperationResult> { result }, OperationType.Uninstall, sw.Elapsed); Telemetry.TrackUserTask("libraryuninstall"); } catch (OperationCanceledException) { Logger.LogEvent(string.Format(LibraryManager.Resources.Text.Uninstall_LibraryCancelled, libraryId), LogLevel.Task); } }
/// <inheritdoc /> public virtual async Task <ILibraryOperationResult> UpdateStateAsync(ILibraryInstallationState desiredState, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(LibraryOperationResult.FromCancelled(desiredState)); } string libraryId = LibraryNamingScheme.GetLibraryId(desiredState.Name, desiredState.Version); try { ILibraryCatalog catalog = GetCatalog(); ILibrary library = await catalog.GetLibraryAsync(desiredState.Name, desiredState.Version, cancellationToken).ConfigureAwait(false); if (library == null) { return(new LibraryOperationResult(desiredState, PredefinedErrors.UnableToResolveSource(desiredState.Name, desiredState.ProviderId))); } if (desiredState.Files != null && desiredState.Files.Count > 0) { // expand any potential file patterns IEnumerable <string> updatedFiles = FileGlobbingUtility.ExpandFileGlobs(desiredState.Files, library.Files.Keys); var processedState = new LibraryInstallationState { Name = desiredState.Name, Version = desiredState.Version, ProviderId = desiredState.ProviderId, DestinationPath = desiredState.DestinationPath, IsUsingDefaultDestination = desiredState.IsUsingDefaultDestination, IsUsingDefaultProvider = desiredState.IsUsingDefaultProvider, Files = updatedFiles.ToList(), }; return(CheckForInvalidFiles(processedState, libraryId, library)); } desiredState = new LibraryInstallationState { ProviderId = Id, Name = desiredState.Name, Version = desiredState.Version, DestinationPath = desiredState.DestinationPath, Files = library.Files.Keys.ToList(), IsUsingDefaultDestination = desiredState.IsUsingDefaultDestination, IsUsingDefaultProvider = desiredState.IsUsingDefaultProvider }; } catch (InvalidLibraryException) { return(new LibraryOperationResult(desiredState, PredefinedErrors.UnableToResolveSource(libraryId, desiredState.ProviderId))); } catch (UnauthorizedAccessException) { return(new LibraryOperationResult(desiredState, PredefinedErrors.PathOutsideWorkingDirectory())); } catch (Exception ex) { HostInteraction.Logger.Log(ex.ToString(), LogLevel.Error); return(new LibraryOperationResult(desiredState, PredefinedErrors.UnknownException())); } return(LibraryOperationResult.FromSuccess(desiredState)); }
protected override ILibraryOperationResult CheckForInvalidFiles(ILibraryInstallationState desiredState, string libraryId, ILibrary library) { return(LibraryOperationResult.FromSuccess(desiredState)); }