private void SetTopProjectSubmoduleInfo(SubmoduleInfoResult result, string noBranchText, IGitModule topProject, bool isCurrentTopProject) { string path = topProject.WorkingDir; string name = Directory.Exists(path) ? Path.GetFileName(Path.GetDirectoryName(path)) : path; name += GetBranchNameSuffix(path, noBranchText); result.TopProject = new SubmoduleInfo { Text = name, Path = path, Bold = isCurrentTopProject }; }
private void SetTopProjectSubmoduleInfo(SubmoduleInfoResult result, string noBranchText, IGitModule topProject, bool isParentTopProject) { if (isParentTopProject) { result.TopProject = result.SuperProject; } else { string path = topProject.WorkingDir; string name = Path.GetFileName(Path.GetDirectoryName(topProject.WorkingDir)) + GetBranchNameSuffix(path, noBranchText); result.TopProject = new SubmoduleInfo { Text = name, Path = topProject.WorkingDir }; } }
private async Task SetTopProjectSubmoduleInfoAsync(bool updateStatus, SubmoduleInfoResult result, GitModule module, CancellationToken cancelToken, string noBranchText, IGitModule topProject, bool isParentTopProject) { if (isParentTopProject) { result.TopProject = result.SuperProject; } else { string path = topProject.WorkingDir; string name = Path.GetFileName(Path.GetDirectoryName(topProject.WorkingDir)) + GetBranchNameSuffix(path, noBranchText); result.TopProject = new SubmoduleInfo { Text = name, Path = topProject.WorkingDir }; await GetSubmoduleStatusAsync(updateStatus, result.TopProject, cancelToken); } }
private void SetSubmoduleData(GitModule currentModule, SubmoduleInfoResult result, string noBranchText, IGitModule topProject) { var submodules = topProject.GetSubmodulesLocalPaths().OrderBy(submoduleName => submoduleName).ToArray(); if (!submodules.Any()) { return; } var superWorkDir = currentModule.SuperprojectModule?.WorkingDir; var currentWorkDir = currentModule.WorkingDir; var localPath = currentWorkDir.Substring(topProject.WorkingDir.Length); if (string.IsNullOrWhiteSpace(localPath)) { localPath = "."; } localPath = Path.GetDirectoryName(localPath).ToPosixPath(); foreach (var submodule in submodules) { string path = topProject.GetSubmoduleFullPath(submodule); string name = submodule + GetBranchNameSuffix(path, noBranchText); bool bold = false; if (submodule == localPath) { result.CurrentSubmoduleName = currentModule.GetCurrentSubmoduleLocalPath(); bold = true; } var smi = new SubmoduleInfo { Text = name, Path = path, Bold = bold }; result.AllSubmodules.Add(smi); if (path == superWorkDir) { result.SuperProject = smi; } if (path != currentWorkDir && path.StartsWith(currentWorkDir)) { result.OurSubmodules.Add(smi); } } }
private void GetRepositorySubmodulesStructure(SubmoduleInfoResult result, string noBranchText) { foreach (var submodule in result.Module.GetSubmodulesLocalPaths().OrderBy(submoduleName => submoduleName)) { var name = submodule; string path = result.Module.GetSubmoduleFullPath(submodule); if (AppSettings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path)) { name = name + " " + GetModuleBranch(path, noBranchText); } var smi = new SubmoduleInfo { Text = name, Path = path }; result.OurSubmodules.Add(smi); } }
private void GetRepositorySubmodulesStatus(SubmoduleInfoResult result, IGitModule module, CancellationToken cancelToken, string noBranchText) { foreach (var submodule in module.GetSubmodulesLocalPaths().OrderBy(submoduleName => submoduleName)) { cancelToken.ThrowIfCancellationRequested(); var name = submodule; string path = module.GetSubmoduleFullPath(submodule); if (AppSettings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path)) { name = name + " " + GetModuleBranch(path, noBranchText); } var smi = new SubmoduleInfo { Text = name, Path = path }; result.OurSubmodules.Add(smi); GetSubmoduleStatusAsync(smi, cancelToken).FileAndForget(); } }
private void SetTopProjectSubmoduleInfo(SubmoduleInfoResult result, string noBranchText, IVsrModule topProject, bool isParentTopProject, bool isCurrentTopProject) { if (isParentTopProject && !isCurrentTopProject) { result.TopProject = result.SuperProject; } else { string path = topProject.WorkingDir; string name = Directory.Exists(path) ? Path.GetFileName(Path.GetDirectoryName(path)) + GetBranchNameSuffix(path, noBranchText) : path; result.TopProject = new SubmoduleInfo { Text = name, Path = path, Bold = isCurrentTopProject }; } }
/// <summary> /// Get the result submodule structure /// </summary> /// <param name="currentModule">The current module</param> /// <param name="noBranchText">text with no branches</param> private SubmoduleInfoResult GetSuperProjectRepositorySubmodulesStructure(GitModule currentModule, string noBranchText) { var result = new SubmoduleInfoResult { Module = currentModule }; IGitModule topProject = currentModule.GetTopModule(); bool isCurrentTopProject = currentModule.SuperprojectModule is null; SetTopProjectSubmoduleInfo(result, noBranchText, topProject, isCurrentTopProject); bool isParentTopProject = currentModule.SuperprojectModule?.WorkingDir == topProject.WorkingDir; if (isParentTopProject) { result.SuperProject = result.TopProject; } // Set result.CurrentSubmoduleName and populate result.AllSubmodules SetSubmoduleData(currentModule, result, noBranchText, topProject); return(result); }
private void SetSuperProjectSubmoduleInfo(GitModule superprojectModule, SubmoduleInfoResult result, string noBranchText, IGitModule topProject, bool isParentTopProject) { string name; if (isParentTopProject) { name = Path.GetFileName(Path.GetDirectoryName(topProject.WorkingDir)); } else { var localPath = superprojectModule.WorkingDir.Substring(topProject.WorkingDir.Length); localPath = PathUtil.GetDirectoryName(localPath.ToPosixPath()); name = localPath; } string path = superprojectModule.WorkingDir; name += GetBranchNameSuffix(path, noBranchText); result.SuperProject = new SubmoduleInfo { Text = name, Path = superprojectModule.WorkingDir }; }
private async Task SetSuperProjectSubmoduleInfoAsync(bool updateStatus, SubmoduleInfoResult result, GitModule module, CancellationToken cancelToken, string noBranchText, IGitModule topProject, bool isParentTopProject) { string name; if (isParentTopProject) { name = Path.GetFileName(Path.GetDirectoryName(topProject.WorkingDir)); } else { var localPath = module.SuperprojectModule.WorkingDir.Substring(topProject.WorkingDir.Length); localPath = PathUtil.GetDirectoryName(localPath.ToPosixPath()); name = localPath; } string path = module.SuperprojectModule.WorkingDir; name += GetBranchNameSuffix(path, noBranchText); result.SuperProject = new SubmoduleInfo { Text = name, Path = module.SuperprojectModule.WorkingDir }; await GetSubmoduleStatusAsync(updateStatus, result.SuperProject, cancelToken); }
private async Task GetRepositorySubmodulesStatusAsync(SubmoduleInfoResult result, IGitModule module, CancellationToken cancelToken, string noBranchText) { List <Task> tasks = new List <Task>(); foreach (var submodule in module.GetSubmodulesLocalPaths().OrderBy(submoduleName => submoduleName)) { cancelToken.ThrowIfCancellationRequested(); var name = submodule; string path = module.GetSubmoduleFullPath(submodule); if (AppSettings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path)) { name = name + " " + GetModuleBranch(path, noBranchText); } var smi = new SubmoduleInfo { Text = name, Path = path }; result.OurSubmodules.Add(smi); tasks.Add(GetSubmoduleStatusAsync(smi, cancelToken)); } await Task.WhenAll(tasks); }
public void UpdateSubmodulesStatus(bool updateStatus, string workingDirectory, string noBranchText) { ThreadHelper.JoinableTaskFactory.RunAsync(async() => { // Cancel any previous async activities: var cancelToken = _submodulesStatusSequence.Next(); // If not updating the status, allow a 'quick' update _previousSubmoduleUpdateTime = updateStatus ? DateTime.Now : DateTime.MinValue; OnStatusUpdating(); await TaskScheduler.Default; // Start gathering new submodule information asynchronously. This makes a significant difference in UI // responsiveness if there are numerous submodules (e.g. > 100). // First task: Gather list of submodules on a background thread. // Don't access Module directly because it's not thread-safe. Use a thread-local version: var threadModule = new GitModule(workingDirectory); var result = new SubmoduleInfoResult { Module = threadModule }; // Add all submodules inside the current repository: var submodulesTask = GetRepositorySubmodulesStatusAsync(updateStatus, result, threadModule, cancelToken, noBranchText); var superTask = GetSuperProjectRepositorySubmodulesStatusAsync(updateStatus, result, threadModule, cancelToken, noBranchText); await Task.WhenAll(submodulesTask, superTask); OnStatusUpdated(result, cancelToken); _previousSubmoduleUpdateTime = updateStatus ? DateTime.Now : DateTime.MinValue; }).FileAndForget(); }
public void UpdateSubmodulesStatus(string workingDirectory, string noBranchText, Action onUpdateBegin, Func <SubmoduleInfoResult, CancellationToken, Task> onUpdateCompleteAsync) { // Cancel any previous async activities: var cancelToken = _submodulesStatusSequence.Next(); _previousSubmoduleUpdateTime = DateTime.Now; onUpdateBegin(); // Start gathering new submodule information asynchronously. This makes a significant difference in UI // responsiveness if there are numerous submodules (e.g. > 100). ThreadHelper.JoinableTaskFactory.RunAsync(async() => { // First task: Gather list of submodules on a background thread. // Add a short delay to prio log first await Task.Delay(100, cancelToken); // Don't access Module directly because it's not thread-safe. Use a thread-local version: var threadModule = new GitModule(workingDirectory); var result = new SubmoduleInfoResult(); // Add all submodules inside the current repository: var submodulesTask = GetRepositorySubmodulesStatusAsync(result, threadModule, cancelToken, noBranchText); var superTask = GetSuperProjectRepositorySubmodulesStatusAsync(result, threadModule, cancelToken, noBranchText); await Task.WhenAll(submodulesTask, superTask); await onUpdateCompleteAsync(result, cancelToken); _previousSubmoduleUpdateTime = DateTime.Now; }).FileAndForget(); }
/// <inheritdoc /> public async Task UpdateSubmodulesStructureAsync(string workingDirectory, string noBranchText, bool updateStatus) { _submoduleInfoResult = null; _gitStatusWhileUpdatingStructure = null; _submoduleInfos.Clear(); // Cancel any previous async activities: var cancelToken = _submodulesStatusSequence.Next(); // Do not throttle next status update _previousSubmoduleUpdateTime = DateTime.MinValue; OnStatusUpdating(); await TaskScheduler.Default; // Start gathering new submodule structure asynchronously. var currentModule = new GitModule(workingDirectory); var result = new SubmoduleInfoResult { Module = currentModule }; // Add all submodules inside the current repository: GetRepositorySubmodulesStructure(result, noBranchText); GetSuperProjectRepositorySubmodulesStructure(currentModule, result, noBranchText); // Structure is updated OnStatusUpdated(result, cancelToken); // Prepare info for status updates (normally triggered by StatusMonitor) foreach (var info in result.OurSubmodules) { _submoduleInfos[info.Path] = info; } foreach (var info in result.SuperSubmodules) { _submoduleInfos[info.Path] = info; } if (!_submoduleInfos.ContainsKey(result.TopProject.Path)) { _submoduleInfos.Add(result.TopProject.Path, result.TopProject); } // Start update status for the submodules if (updateStatus) { if (result.SuperProject != null) { // For the topmodule, use git-status information to update the status // If a submodule is current, update once from top module to give an overview // The structure _below_ the current module could have been updated from git-status but the current module // must be updated from its super project to set the ahead/behind information await GetSubmoduleDetailedStatusAsync(currentModule.GetTopModule(), cancelToken); // Ignore if possible or at least delay the pending git-status trigger _gitStatusWhileUpdatingStructure = null; _previousSubmoduleUpdateTime = DateTime.Now; } else if (_gitStatusWhileUpdatingStructure != null) { await UpdateSubmodulesStatusAsync(currentModule, _gitStatusWhileUpdatingStructure, cancelToken); // Ignore if possible or at least delay the pending git-status trigger _gitStatusWhileUpdatingStructure = null; _previousSubmoduleUpdateTime = DateTime.Now; } OnStatusUpdated(result, cancelToken); } _submoduleInfoResult = result; }
public SubmoduleStatusEventArgs(SubmoduleInfoResult info, bool structureUpdated, CancellationToken token) { Info = info; Token = token; StructureUpdated = structureUpdated; }
private async Task GetSuperProjectRepositorySubmodulesStatusAsync(SubmoduleInfoResult result, GitModule module, CancellationToken cancelToken, string noBranchText) { if (module.SuperprojectModule == null) { return; } string name, path; GitModule supersuperproject = FindTopProjectModule(module.SuperprojectModule); if (module.SuperprojectModule.WorkingDir != supersuperproject.WorkingDir) { name = Path.GetFileName(Path.GetDirectoryName(supersuperproject.WorkingDir)); path = supersuperproject.WorkingDir; if (AppSettings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path)) { name = name + " " + GetModuleBranch(path, noBranchText); } result.TopProject = new SubmoduleInfo { Text = name, Path = supersuperproject.WorkingDir }; await GetSubmoduleStatusAsync(result.TopProject, cancelToken); } if (module.SuperprojectModule.WorkingDir != supersuperproject.WorkingDir) { var localPath = module.SuperprojectModule.WorkingDir.Substring(supersuperproject.WorkingDir.Length); localPath = PathUtil.GetDirectoryName(localPath.ToPosixPath()); name = localPath; } else { name = Path.GetFileName(Path.GetDirectoryName(supersuperproject.WorkingDir)); } path = module.SuperprojectModule.WorkingDir; if (AppSettings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path)) { name = name + " " + GetModuleBranch(path, noBranchText); } result.SuperProject = new SubmoduleInfo { Text = name, Path = module.SuperprojectModule.WorkingDir }; await GetSubmoduleStatusAsync(result.SuperProject, cancelToken); var submodules = supersuperproject.GetSubmodulesLocalPaths().OrderBy(submoduleName => submoduleName).ToArray(); if (submodules.Any()) { string localPath = module.WorkingDir.Substring(supersuperproject.WorkingDir.Length); localPath = PathUtil.GetDirectoryName(localPath.ToPosixPath()); List <Task> subTasks = new List <Task>(); foreach (var submodule in submodules) { cancelToken.ThrowIfCancellationRequested(); name = submodule; path = supersuperproject.GetSubmoduleFullPath(submodule); if (AppSettings.DashboardShowCurrentBranch && !GitModule.IsBareRepository(path)) { name = name + " " + GetModuleBranch(path, noBranchText); } bool bold = false; if (submodule == localPath) { result.CurrentSubmoduleName = module.GetCurrentSubmoduleLocalPath(); bold = true; } var smi = new SubmoduleInfo { Text = name, Path = path, Bold = bold }; result.SuperSubmodules.Add(smi); subTasks.Add(GetSubmoduleStatusAsync(smi, cancelToken)); } await Task.WhenAll(subTasks); } }
/// <summary> /// This function always at least sets result.TopProject /// </summary> /// <param name="result">submodule info</param> /// <param name="noBranchText">text with no branches</param> private void GetSuperProjectRepositorySubmodulesStructure(GitModule currentModule, SubmoduleInfoResult result, string noBranchText) { bool isCurrentTopProject = currentModule.SuperprojectModule == null; if (isCurrentTopProject) { SetTopProjectSubmoduleInfo(result, noBranchText, result.Module, false, isCurrentTopProject); return; } IGitModule topProject = currentModule.SuperprojectModule.GetTopModule(); bool isParentTopProject = currentModule.SuperprojectModule.WorkingDir == topProject.WorkingDir; // Set result.SuperProject SetSuperProjectSubmoduleInfo(currentModule.SuperprojectModule, result, noBranchText, topProject, isParentTopProject); // Set result.TopProject SetTopProjectSubmoduleInfo(result, noBranchText, topProject, isParentTopProject, isCurrentTopProject); // Set result.CurrentSubmoduleName and populate result.SuperSubmodules SetSubmoduleData(currentModule, result, noBranchText, topProject); }
/// <inheritdoc /> public void UpdateSubmodulesStructure(string workingDirectory, string noBranchText, bool updateStatus) { _submoduleInfoResult = null; _gitStatusWhileUpdatingStructure = null; _submoduleInfos.Clear(); ThreadHelper.JoinableTaskFactory.RunAsync(async() => { // Cancel any previous async activities: var cancelToken = _submodulesStatusSequence.Next(); // Do not throttle next status update _previousSubmoduleUpdateTime = DateTime.MinValue; OnStatusUpdating(); await TaskScheduler.Default; // Start gathering new submodule structure asynchronously. var currentModule = new GitModule(workingDirectory); var result = new SubmoduleInfoResult { Module = currentModule }; // Add all submodules inside the current repository: GetRepositorySubmodulesStructure(result, noBranchText); GetSuperProjectRepositorySubmodulesStructure(currentModule, result, noBranchText); // Structure is updated OnStatusUpdated(result, cancelToken); // Prepare info for status updates (normally triggered by StatusMonitor) foreach (var info in result.OurSubmodules) { _submoduleInfos[info.Path] = info; } foreach (var info in result.SuperSubmodules) { _submoduleInfos[info.Path] = info; } if (!_submoduleInfos.ContainsKey(result.TopProject.Path)) { _submoduleInfos.Add(result.TopProject.Path, result.TopProject); } // Start update status for the submodules if (updateStatus) { if (result.SuperProject != null) { // Update from top module (will stop at current) await GetSubmoduleDetailedStatusAsync(currentModule.GetTopModule(), cancelToken); } if (_gitStatusWhileUpdatingStructure != null) { // Current module must be updated separately (not in _submoduleInfos) await UpdateSubmodulesStatusAsync(currentModule, _gitStatusWhileUpdatingStructure, cancelToken); } OnStatusUpdated(result, cancelToken); } _submoduleInfoResult = result; }).FileAndForget(); }
private async Task GetSuperProjectRepositorySubmodulesStatusAsync(bool updateStatus, SubmoduleInfoResult result, GitModule module, CancellationToken cancelToken, string noBranchText) { // This function always at least sets result.TopProject bool isCurrentTopProject = module.SuperprojectModule == null; if (isCurrentTopProject) { string path = module.WorkingDir; string name = Path.GetFileName(Path.GetDirectoryName(module.WorkingDir)) + GetBranchNameSuffix(path, noBranchText); result.TopProject = new SubmoduleInfo { Text = name, Path = module.WorkingDir, Bold = true }; return; } IGitModule topProject = module.SuperprojectModule.GetTopModule(); bool isParentTopProject = module.SuperprojectModule.WorkingDir == topProject.WorkingDir; // Set result.SuperProject SetSuperProjectSubmoduleInfo(updateStatus, result, module, cancelToken, noBranchText, topProject, isParentTopProject); // Set result.TopProject await SetTopProjectSubmoduleInfoAsync(updateStatus, result, module, cancelToken, noBranchText, topProject, isParentTopProject); // Set result.CurrentSubmoduleName and populate result.SuperSubmodules await SetSubmoduleDataAsync(updateStatus, result, module, cancelToken, noBranchText, topProject); }
private void OnStatusUpdated(SubmoduleInfoResult info, CancellationToken token) { token.ThrowIfCancellationRequested(); StatusUpdated?.Invoke(this, new SubmoduleStatusEventArgs(info, token)); }
public SubmoduleStatusEventArgs(SubmoduleInfoResult info, CancellationToken token) { Info = info; Token = token; }
/// <inheritdoc /> public async Task UpdateSubmodulesStructureAsync(string workingDirectory, string noBranchText, bool updateStatus) { _submoduleInfoResult = null; _submoduleInfos.Clear(); // Cancel previous structure and status updates var cancelToken = _submodulesStructureSequence.Next(); _submodulesStatusSequence.Next(); // Do not throttle next status update _previousSubmoduleUpdateTime = DateTime.MinValue; OnStatusUpdating(); await TaskScheduler.Default; // Start gathering new submodule structure asynchronously. var currentModule = new GitModule(workingDirectory); var result = GetSuperProjectRepositorySubmodulesStructure(currentModule, noBranchText); // Prepare info for status updates _submoduleInfos[result.TopProject.Path] = result.TopProject; foreach (var info in result.AllSubmodules) { _submoduleInfos[info.Path] = info; } // Structure is updated OnStatusUpdated(result, cancelToken); if (updateStatus && currentModule.SuperprojectModule is not null) { // For the top module, use git-status information to update the status // If a submodule is current, update once from top module to give an overview // (The structure below the current module could have been updated from git-status but the current module // must be updated from its super project to set the ahead/behind information) // Further git-status updates only the current module and below var topModule = currentModule.GetTopModule(); await GetSubmoduleDetailedStatusAsync(topModule, cancelToken); // Set status for top module from submodules foreach (var name in topModule.GetSubmodulesLocalPaths(false)) { var path = topModule.GetSubmoduleFullPath(name); if (_submoduleInfos.ContainsKey(path) && _submoduleInfos[path].Detailed is not null) { SetModuleAsDirtyUpwards(topModule); break; } } // Ignore if possible or at least delay the pending git-status trigger _previousSubmoduleUpdateTime = DateTime.Now; _submodulesStatusSequence.Next(); OnStatusUpdated(result, cancelToken); } _submoduleInfoResult = result; }
/// <summary> /// This function always at least sets result.TopProject /// </summary> /// <param name="result">submodule info</param> /// <param name="noBranchText">text with no branches</param> private void GetSuperProjectRepositorySubmodulesStructure(GitModule currentModule, SubmoduleInfoResult result, string noBranchText) { bool isCurrentTopProject = currentModule.SuperprojectModule == null; if (isCurrentTopProject) { string path = result.Module.WorkingDir; string name = Path.GetFileName(Path.GetDirectoryName(result.Module.WorkingDir)) + GetBranchNameSuffix(path, noBranchText); result.TopProject = new SubmoduleInfo { Text = name, Path = result.Module.WorkingDir, Bold = true }; return; } IGitModule topProject = currentModule.SuperprojectModule.GetTopModule(); bool isParentTopProject = currentModule.SuperprojectModule.WorkingDir == topProject.WorkingDir; // Set result.SuperProject SetSuperProjectSubmoduleInfo(currentModule.SuperprojectModule, result, noBranchText, topProject, isParentTopProject); // Set result.TopProject SetTopProjectSubmoduleInfo(result, noBranchText, topProject, isParentTopProject); // Set result.CurrentSubmoduleName and populate result.SuperSubmodules SetSubmoduleData(currentModule, result, noBranchText, topProject); }