/// <summary> /// Tries to open a <see cref="ProjectItem" /> such that content modification operations are possible. /// </summary> /// <param name="item">The <see cref="ProjectItem" /> to be opened.</param> /// <param name="extension"> /// The <see cref="ILicenseHeaderExtension" /> instance used to access the currently configured /// language definitions. /// </param> /// <returns> /// Returns <see langword="true" /> if opening <paramref name="item" /> succeeded or was not necessary, otherwise /// <see langword="false" />. /// </returns> public static bool TryOpenDocument(ProjectItem item, ILicenseHeaderExtension extension) { try { ThreadHelper.ThrowIfNotOnUIThread(); // Opening files potentially having non-text content (.png, .snk) might result in a Visual Studio error "Some bytes have been replaced with the // Unicode substitution character while loading file ...". In order to avoid this, files with unknown extensions are not opened. However, in order // to keep such files eligible as Core input, still return true var languageForExtension = extension.LicenseHeaderReplacer.GetLanguageFromExtension(Path.GetExtension(item.FileNames[1])); if (languageForExtension == null) { return(true); } item.Open(Constants.vsViewKindTextView); return(true); } catch (COMException) { return(false); } catch (IOException) { return(false); } }
/// <summary> /// Adds the license header text for the specified extension to the given project item. /// </summary> /// <param name="item">Specifies the project item in which the license header text is to be inserted.</param> /// <param name="extension">Specifies the extension of the language whose content should be added to the project item.</param> /// <param name="calledByUser">Specifies whether this method was called explicitly by the user or by the program.</param> /// <returns></returns> public static async Task AddLicenseHeaderToItemAsync( this ProjectItem item, ILicenseHeaderExtension extension, bool calledByUser) { if (item == null || ProjectItemInspection.IsLicenseHeader(item)) { return; } await extension.JoinableTaskFactory.SwitchToMainThreadAsync(); var headers = LicenseHeaderFinder.GetHeaderDefinitionForItem(item); if (headers != null) { var content = item.GetContent(out var wasAlreadyOpen, extension); if (content == null) { return; } var result = await extension.LicenseHeaderReplacer.RemoveOrReplaceHeader( new LicenseHeaderContentInput (content, item.FileNames[1], headers, item.GetAdditionalProperties())); await CoreHelpers.HandleResultAsync(result, extension, wasAlreadyOpen, calledByUser); return; } if (calledByUser && LicenseHeaderDefinitionFileHelper.ShowQuestionForAddingLicenseHeaderFile(item.ContainingProject, extension.DefaultLicenseHeaderPageModel)) { await AddLicenseHeaderToItemAsync(item, extension, true); } }
public void TestNoLicenseHeaderFile() { ILicenseHeaderExtension extension = MockRepository.GenerateStub <ILicenseHeaderExtension> (); ProjectItem projectItem = MockRepository.GenerateMock <ProjectItem>(); projectItem.Expect(x => x.Name).Return("projectItem.cs"); ILinkedFileFilter linkedFileFilter = MockRepository.GenerateMock <ILinkedFileFilter> (); LicenseHeaderReplacer licenseHeaderReplacer = MockRepository.GenerateStrictMock <LicenseHeaderReplacer> (extension); linkedFileFilter.Expect(x => x.NoLicenseHeaderFile).Return(new List <ProjectItem> { projectItem }); linkedFileFilter.Expect(x => x.ToBeProgressed).Return(new List <ProjectItem> ()); linkedFileFilter.Expect(x => x.NotInSolution).Return(new List <ProjectItem> ()); LinkedFileHandler linkedFileHandler = new LinkedFileHandler(); linkedFileHandler.Handle(licenseHeaderReplacer, linkedFileFilter); string expectedMessage = string.Format(Resources.LinkedFileUpdateInformation, "projectItem.cs") .Replace(@"\n", "\n"); Assert.AreEqual(expectedMessage, linkedFileHandler.Message); }
public static void AddExistingLicenseHeaderDefinitionFile(ILicenseHeaderExtension serviceProvider) { ThreadHelper.ThrowIfNotOnUIThread(); var project = serviceProvider.GetSolutionExplorerItem() as Project; var projectItem = serviceProvider.GetSolutionExplorerItem() as ProjectItem; string fileName; if (project != null) { fileName = project.FileName; } else if (projectItem != null) { fileName = projectItem.Name; } else { return; } ProjectItems projectItems = null; if (project != null) { projectItems = project.ProjectItems; } else if (projectItem != null) { projectItems = projectItem.ProjectItems; } ExistingLicenseHeaderDefinitionFileAdder.AddDefinitionFileToOneProject(fileName, projectItems); }
public static void AddNewLicenseHeaderDefinitionFile(ILicenseHeaderExtension serviceProvider) { ThreadHelper.ThrowIfNotOnUIThread(); var page = serviceProvider.DefaultLicenseHeaderPageModel; var solutionItem = serviceProvider.GetSolutionExplorerItem(); var project = solutionItem as Project; if (project == null) { if (solutionItem is ProjectItem projectItem) { LicenseHeaderDefinitionFileHelper.AddLicenseHeaderDefinitionFile(projectItem, page); } } if (project == null) { return; } var licenseHeaderDefinitionFile = LicenseHeaderDefinitionFileHelper.AddHeaderDefinitionFile(project, page); licenseHeaderDefinitionFile.Open(Constants.vsViewKindCode).Activate(); }
public AddLicenseHeaderToAllFilesInProjectHelper( CancellationToken cancellationToken, ILicenseHeaderExtension licenseHeaderExtension, BaseUpdateViewModel baseUpdateViewModel) { _cancellationToken = cancellationToken; _licenseHeaderExtension = licenseHeaderExtension; _baseUpdateViewModel = baseUpdateViewModel; }
/// <summary> /// Processes a range of <see cref="ReplacerResult{TSuccess,TError}" /> objects, including possible error handling. /// </summary> /// <param name="result">Specifies the replacer result. Indicates whether the specific operation succeeded or failed.</param> /// <param name="licenseHeaderExtension"> /// A <see cref="ILicenseHeaderExtension" /> instance used to access members exposed /// by the LHM Extension Package. /// </param> /// <param name="viewModel"> /// A <see cref="BaseUpdateViewModel" /> instance used to update progress indicator properties if a /// <see cref="LicenseHeaderReplacer" /> newly needs to be invoked. /// </param> /// <param name="projectName"> /// The name of the project the files updated by a <see cref="LicenseHeaderReplacer" /> operation /// belong to. /// </param> /// <param name="fileOpenedStatus"> /// Provides information on which files (full path, dictionary key) are currently opened /// (values). /// </param> /// <param name="cancellationToken"> /// A <see cref="CancellationToken" /> that can be used to cancel pending Core operations /// if they have not been started yet. /// </param> public static async Task HandleResultAsync( IEnumerable <ReplacerResult <ReplacerSuccess, ReplacerError <LicenseHeaderContentInput> > > result, ILicenseHeaderExtension licenseHeaderExtension, BaseUpdateViewModel viewModel, string projectName, IDictionary <string, bool> fileOpenedStatus, CancellationToken cancellationToken) { // collect NonCommentText-errors and ask if license header should still be inserted var errors = result.Where(replacerResult => !replacerResult.IsSuccess).Select(replacerResult => replacerResult.Error).ToList(); var nonCommentTextErrorsByExtension = errors.Where(x => x.Type == ReplacerErrorType.NonCommentText).GroupBy(x => Path.GetExtension(x.Input.DocumentPath)); var inputIgnoringNonCommentText = new List <LicenseHeaderContentInput>(); foreach (var extension in nonCommentTextErrorsByExtension) { var message = string.Format(Resources.Warning_InvalidLicenseHeader, extension.Key).ReplaceNewLines(); if (!MessageBoxHelper.AskYesNo(message, Resources.Warning, true)) { continue; } foreach (var failedFile in extension) { failedFile.Input.IgnoreNonCommentText = true; inputIgnoringNonCommentText.Add(failedFile.Input); } } // collect other errors and the ones that occurred while "force-inserting" headers with non-comment-text var overallErrors = errors.Where(x => x.Type != ReplacerErrorType.NonCommentText && x.Type != ReplacerErrorType.LicenseHeaderDocument).ToList(); if (inputIgnoringNonCommentText.Count > 0) { viewModel.FileCountCurrentProject = inputIgnoringNonCommentText.Count; var resultIgnoringNonCommentText = await licenseHeaderExtension.LicenseHeaderReplacer.RemoveOrReplaceHeader( inputIgnoringNonCommentText, CreateProgress (viewModel, projectName, fileOpenedStatus, cancellationToken), cancellationToken); overallErrors.AddRange(resultIgnoringNonCommentText.Where(replacerResult => !replacerResult.IsSuccess).Select(replacerResult => replacerResult.Error)); } // display all errors collected from "first attempt" and "force-insertion" if (overallErrors.Count == 0) { return; } MessageBoxHelper.ShowError($"{overallErrors.Count} unexpected errors have occurred. See output window or log file for more details"); foreach (var otherError in overallErrors) { s_log.Error($"File '{otherError.Input.DocumentPath}' failed: {otherError.Description}"); } }
private static void ProcessSuccess(ReplacerSuccess replacerSuccess, ILicenseHeaderExtension extension, bool isOpen) { ThreadHelper.ThrowIfNotOnUIThread(); if (!File.Exists(replacerSuccess.FilePath) || TrySetContent(replacerSuccess.FilePath, extension.Dte2.Solution, replacerSuccess.NewContent, isOpen, extension)) { return; } s_log.Error($"Updating license header for file {replacerSuccess.FilePath} failed."); MessageBoxHelper.ShowError($"Updating license header for file {replacerSuccess.FilePath} failed."); }
/// <summary> /// Processes the given <see cref="ReplacerResult{TSuccess,TError}" /> object, including handling errors that possibly /// occurred. /// </summary> /// <param name="result">Specifies the replacer result. Indicates whether the specific operation succeeded or failed.</param> /// <param name="extension"> /// A <see cref="ILicenseHeaderExtension" /> instance used to access members exposed by the LHM /// Extension Package. /// </param> /// <param name="isOpen">Specifies if the current file is currently open.</param> /// <param name="calledByUser"> /// Specifies whether this method was called explicitly by the user or implicitly by the /// program. /// </param> public static async Task HandleResultAsync( ReplacerResult <ReplacerSuccess, ReplacerError <LicenseHeaderContentInput> > result, ILicenseHeaderExtension extension, bool isOpen, bool calledByUser) { if (result.IsSuccess) { await extension.JoinableTaskFactory.SwitchToMainThreadAsync(); ProcessSuccess(result.Success, extension, isOpen); return; } if (!calledByUser) { return; } var error = result.Error; switch (error.Type) { case ReplacerErrorType.NonCommentText: error.Input.IgnoreNonCommentText = true; if (!MessageBoxHelper.AskYesNo(error.Description, Resources.Warning, true)) { return; } var resultIgnoringNonCommentText = await extension.LicenseHeaderReplacer.RemoveOrReplaceHeader(error.Input); if (resultIgnoringNonCommentText.IsSuccess) { ProcessSuccess(resultIgnoringNonCommentText.Success, extension, isOpen); return; } error = resultIgnoringNonCommentText.Error; ProcessError(error); break; case ReplacerErrorType.LanguageNotFound: return; // ignore such an error (i. e. do not propagate to user) case ReplacerErrorType.LicenseHeaderDocument: return; // ignore such an error (i. e. do not propagate to user) default: ProcessError(error); break; } }
public void SetUp () { _extensionMock = MockRepository.GenerateMock<ILicenseHeaderExtension> (); _optionsPage = MockRepository.GenerateMock<IOptionsPage>(); _replacer = new LicenseHeaderReplacer (_extensionMock); _projectItem = MockRepository.GenerateMock<ProjectItem> (); _languagesPage = MockRepository.GenerateMock<ILanguagesPage>(); _extensionMock.Expect (x => x.LanguagesPage).Return (_languagesPage); _extensionMock.Expect (x => x.OptionsPage).Return (_optionsPage); _optionsPage.Expect (x => x.UseRequiredKeywords).Return (true); _optionsPage.Expect (x => x.RequiredKeywords).Return (""); _projectItem.Stub(x => x.Open(Constants.vsViewKindTextView)).Return(MockRepository.GenerateMock<Window>()); }
public void SetUp() { _extensionMock = MockRepository.GenerateMock <ILicenseHeaderExtension>(); _optionsPage = MockRepository.GenerateMock <IOptionsPage>(); _replacer = new LicenseHeaderReplacer(_extensionMock); _projectItem = MockRepository.GenerateMock <ProjectItem>(); _languagesPage = MockRepository.GenerateMock <ILanguagesPage>(); _extensionMock.Expect(x => x.LanguagesPage).Return(_languagesPage); _extensionMock.Expect(x => x.OptionsPage).Return(_optionsPage); _optionsPage.Expect(x => x.UseRequiredKeywords).Return(true); _optionsPage.Expect(x => x.RequiredKeywords).Return(""); _projectItem.Stub(x => x.Open(Constants.vsViewKindTextView)).Return(MockRepository.GenerateMock <Window>()); }
private static async Task HandleLinkedFilesAndShowMessageBoxAsync(ILicenseHeaderExtension serviceProvider, IEnumerable <ProjectItem> linkedItems) { ILinkedFileFilter linkedFileFilter = new LinkedFileFilter(serviceProvider.Dte2.Solution); linkedFileFilter.Filter(linkedItems); var linkedFileHandler = new LinkedFileHandler(serviceProvider); await linkedFileHandler.HandleAsync(linkedFileFilter); if (linkedFileHandler.Message != string.Empty) { MessageBoxHelper.ShowMessage(linkedFileHandler.Message); } }
public void TestNoProjectItems() { Solution solution = MockRepository.GenerateStub <Solution>(); ILicenseHeaderExtension extension = MockRepository.GenerateStub <ILicenseHeaderExtension>(); LinkedFileFilter linkedFileFilter = MockRepository.GenerateStrictMock <LinkedFileFilter>(solution); LicenseHeaderReplacer licenseHeaderReplacer = MockRepository.GenerateStrictMock <LicenseHeaderReplacer>(extension); LinkedFileHandler linkedFileHandler = new LinkedFileHandler(); linkedFileHandler.Handle(licenseHeaderReplacer, linkedFileFilter); Assert.AreEqual(string.Empty, linkedFileHandler.Message); }
private static async Task HandleAddLicenseHeaderToAllFilesInProjectResultAsync( CancellationToken cancellationToken, ILicenseHeaderExtension serviceProvider, object obj, AddLicenseHeaderToAllFilesResult addResult, BaseUpdateViewModel baseUpdateViewModel) { await serviceProvider.JoinableTaskFactory.SwitchToMainThreadAsync(); var project = obj as Project; var projectItem = obj as ProjectItem; if (project == null && projectItem == null) { return; } var currentProject = project; if (projectItem != null) { currentProject = projectItem.ContainingProject; } if (addResult.NoHeaderFound) { // No license header found... var solutionSearcher = new AllSolutionProjectsSearcher(); var projects = solutionSearcher.GetAllProjects(serviceProvider.Dte2.Solution); if (projects.Any(projectInSolution => LicenseHeaderFinder.GetHeaderDefinitionForProjectWithoutFallback(projectInSolution) != null)) { baseUpdateViewModel.ProcessedFilesCountCurrentProject = 0; // If another project has a license header, offer to add a link to the existing one. if (MessageBoxHelper.AskYesNo(Resources.Question_AddExistingDefinitionFileToProject.ReplaceNewLines())) { ExistingLicenseHeaderDefinitionFileAdder.AddDefinitionFileToOneProject(currentProject.FileName, currentProject.ProjectItems); await AddLicenseHeaderToAllFilesAsync(cancellationToken, serviceProvider, baseUpdateViewModel); } } else { // If no project has a license header, offer to add one for the solution. if (MessageBoxHelper.AskYesNo(Resources.Question_AddNewLicenseHeaderDefinitionForSolution.ReplaceNewLines())) { AddNewSolutionLicenseHeaderDefinitionFileCommand.Instance.Invoke(serviceProvider.Dte2.Solution); } } } }
public static async Task AddLicenseHeaderToAllFilesAsync( CancellationToken cancellationToken, ILicenseHeaderExtension serviceProvider, BaseUpdateViewModel folderProjectUpdateViewModel) { await serviceProvider.JoinableTaskFactory.SwitchToMainThreadAsync(); var obj = serviceProvider.GetSolutionExplorerItem(); var addLicenseHeaderToAllFilesCommand = new AddLicenseHeaderToAllFilesInProjectHelper( cancellationToken, serviceProvider, folderProjectUpdateViewModel); var addLicenseHeaderToAllFilesResult = await addLicenseHeaderToAllFilesCommand.RemoveOrReplaceHeadersAsync(obj); await HandleLinkedFilesAndShowMessageBoxAsync(serviceProvider, addLicenseHeaderToAllFilesResult.LinkedItems); await HandleAddLicenseHeaderToAllFilesInProjectResultAsync( cancellationToken, serviceProvider, obj, addLicenseHeaderToAllFilesResult, folderProjectUpdateViewModel); }
public LicenseHeaderReplacer(ILicenseHeaderExtension licenseHeaderExtension) { _licenseHeaderExtension = licenseHeaderExtension; }
/// <summary> /// Returns the document content of the given project item that has the language of the given extension and returns it as /// string. /// </summary> /// <param name="item">Specifies the project item whose specific content should be returned.</param> /// <param name="wasAlreadyOpen">Specifies whether the project item was already open before this method was called.</param> /// <param name="extension">Specifies the extension of the language whose content should be returned.</param> /// <returns></returns> public static string GetContent(this ProjectItem item, out bool wasAlreadyOpen, ILicenseHeaderExtension extension) { ThreadHelper.ThrowIfNotOnUIThread(); wasAlreadyOpen = item.IsOpen(); if (!wasAlreadyOpen && !CoreHelpers.TryOpenDocument(item, extension)) { return(null); } // Referring to the comment in the TryOpenDocument method: files with unknown extensions that were precautiously not opened are still fed as input to the // Core - with empty content, though, as the Core will return ReplacerErrorType.LanguageNotFound anyway (i. e. content is not relevant, only the extension) // (returning false from TryOpenDocument or null from this method would mean skipping the file entirely, which we do not want since we want to be able to // react to a ReplacerErrorType.LanguageNotFound) var languageForExtension = extension.LicenseHeaderReplacer.GetLanguageFromExtension(Path.GetExtension(item.FileNames[1])); if (languageForExtension == null) { return(""); } try { if (!(item.Document?.Object("TextDocument") is TextDocument textDocument)) { return(null); } var wasSaved = item.Document.Saved; var content = textDocument.CreateEditPoint(textDocument.StartPoint).GetText(textDocument.EndPoint); CoreHelpers.SaveAndCloseIfNecessary(item, wasAlreadyOpen, wasSaved); return(content); } catch (Exception) { return(null); } }
public AddLicenseHeaderToAllFilesInSolutionImplementation(ILicenseHeaderExtension licenseHeaderExtension) { _licenseHeaderExtension = licenseHeaderExtension; }
public AddLicenseHeaderToAllFilesInFolderProjectImplementation(ILicenseHeaderExtension licenseHeaderExtension) { _licenseHeaderExtension = licenseHeaderExtension; }
public LinkedFileHandler(ILicenseHeaderExtension licenseHeaderExtension) { _licenseHeaderExtension = licenseHeaderExtension; Message = string.Empty; }
public ButtonHandlerFactory(ILicenseHeaderExtension licenseHeadersPackage, LicenseHeaderReplacer licenseHeaderReplacer) { _licenseHeadersPackage = licenseHeadersPackage; _licenseHeaderReplacer = licenseHeaderReplacer; }
private static bool TrySetContent(string itemPath, Solution solution, string content, bool wasOpen, ILicenseHeaderExtension extension) { ThreadHelper.ThrowIfNotOnUIThread(); var item = solution.FindProjectItem(itemPath); if (item == null) { return(false); } if (!wasOpen && !TryOpenDocument(item, extension)) { return(false); } // returning false from this method would signify an error, which we do not want since this circumstance is expected to occur with unknown file extensions var languageForExtension = extension.LicenseHeaderReplacer.GetLanguageFromExtension(Path.GetExtension(item.FileNames[1])); if (languageForExtension == null) { return(true); } if (!(item.Document.Object("TextDocument") is TextDocument textDocument)) { return(false); } var wasSaved = item.Document.Saved; textDocument.CreateEditPoint(textDocument.StartPoint).Delete(textDocument.EndPoint); textDocument.CreateEditPoint(textDocument.StartPoint).Insert(content); SaveAndCloseIfNecessary(item, wasOpen, wasSaved); return(true); }
/// <summary> /// Creates an instance of the type implementing the <see cref="IMenuItemButtonHandler" /> interface that fits the given /// parameters. /// </summary> /// <param name="level">The level the <see cref="IMenuItemButtonHandler" /> instance to be created should operate on.</param> /// <param name="mode"> /// The license header insertion mode to be used by the <see cref="IMenuItemButtonHandler" /> instance /// to be created. /// </param> /// <param name="licenseHeadersPackage"> /// The <see cref="ILicenseHeaderExtension" /> instance the /// <see cref="IMenuItemButtonHandler" /> instance to be created may use for its operations. /// </param> /// <returns> /// Returns a´n <see cref="IMenuItemButtonHandler" /> instance operating on the level specified by /// <paramref name="level" /> and executing operations of the mode specified by <paramref name="mode" />. /// </returns> public static IMenuItemButtonHandler CreateHandler(MenuItemButtonLevel level, MenuItemButtonOperation mode, ILicenseHeaderExtension licenseHeadersPackage) { return(level switch { MenuItemButtonLevel.Solution => CreateSolutionHandler(licenseHeadersPackage, mode), MenuItemButtonLevel.Folder => CreateFolderHandler(licenseHeadersPackage, mode), MenuItemButtonLevel.Project => CreateProjectHandler(licenseHeadersPackage, mode), _ => throw new ArgumentOutOfRangeException(nameof(level), level, null) });
public RemoveLicenseHeaderFromAllFilesInSolutionImplementation(ILicenseHeaderExtension licenseHeaderExtension) { _licenseHeaderExtension = licenseHeaderExtension; }