private void CreateSubmoduleNodes(SubmoduleInfoResult result, GitModule threadModule, ref List <SubmoduleNode> nodes) { // result.OurSubmodules/AllSubmodules contain a recursive list of submodules, but don't provide info about the super // project path. So we deduce these by substring matching paths against an ordered list of all paths. var modulePaths = result.AllSubmodules.Select(info => info.Path).ToList(); // Add current and parent module paths var parentModule = threadModule; while (parentModule is not null) { modulePaths.Add(parentModule.WorkingDir); parentModule = parentModule.SuperprojectModule; } // Sort descending so we find the nearest outer folder first modulePaths = modulePaths.OrderByDescending(path => path).ToList(); foreach (var submoduleInfo in result.AllSubmodules) { string superPath = GetSubmoduleSuperPath(submoduleInfo.Path); string localPath = Path.GetDirectoryName(submoduleInfo.Path.Substring(superPath.Length)).ToPosixPath(); var isCurrent = submoduleInfo.Bold; nodes.Add(new SubmoduleNode(this, submoduleInfo, isCurrent, isCurrent ? result.CurrentSubmoduleStatus : null, localPath, superPath)); } return; string GetSubmoduleSuperPath(string submodulePath) { var superPath = modulePaths.Find(path => submodulePath != path && submodulePath.Contains(path)); Validates.NotNull(superPath); return(superPath); } }
/// <summary> /// Removes the specified remote from .git/config file. /// </summary> /// <param name="remote">Remote to remove.</param> /// <returns>Output of <see cref="IGitModule.RemoveRemote"/> operation, if the remote is active; otherwise <see cref="string.Empty"/>.</returns> public string RemoveRemote(ConfigFileRemote remote) { if (remote is null) { throw new ArgumentNullException(nameof(remote)); } var module = GetModule(); if (!remote.Disabled) { Validates.NotNull(remote.Name); return(module.RemoveRemote(remote.Name)); } var sectionName = $"{DisabledSectionPrefix}{SectionRemote}.{remote.Name}"; module.LocalConfigFile.RemoveConfigSection(sectionName, true); return(string.Empty); }
protected override void SettingsToPage() { ThreadHelper.JoinableTaskFactory.RunAsync( async() => { Validates.NotNull(_populateBuildServerTypeTask); await _populateBuildServerTypeTask.JoinAsync(); await this.SwitchToMainThreadAsync(); IBuildServerSettings buildServerSettings = GetCurrentSettings() .BuildServer(); checkBoxEnableBuildServerIntegration.SetNullableChecked(buildServerSettings.EnableIntegration); checkBoxShowBuildResultPage.SetNullableChecked(buildServerSettings.ShowBuildResultPage); BuildServerType.SelectedItem = buildServerSettings.Type ?? _noneItem.Text; }); }
/// <summary> /// Loads all persisted external link definitions across all setting layers. /// </summary> public IReadOnlyList <ExternalLinkDefinition> Get(RepoDistSettings settings) { if (settings is null) { throw new ArgumentNullException(nameof(settings)); } var cachedSettings = new RepoDistSettings(null, settings.SettingsCache, SettingLevel.Unknown); IEnumerable <ExternalLinkDefinition>?effective = _externalLinksStorage.Load(cachedSettings); Validates.NotNull(effective); if (settings.LowerPriority is not null) { var lowerPriorityLoader = new ConfiguredLinkDefinitionsProvider(_externalLinksStorage); effective = effective.Union(lowerPriorityLoader.Get(settings.LowerPriority)); } return(effective.ToList()); }
private void ActivateBuildServerSettingsControl() { Validates.NotNull(CurrentSettings); var controls = buildServerSettingsPanel.Controls.OfType <IBuildServerSettingsUserControl>().Cast <Control>(); var previousControl = controls.SingleOrDefault(); previousControl?.Dispose(); var control = CreateBuildServerSettingsUserControl(); buildServerSettingsPanel.Controls.Clear(); if (control is not null) { control.LoadSettings(CurrentSettings.BuildServer.TypeSettings); buildServerSettingsPanel.Controls.Add((Control)control); ((Control)control).Dock = DockStyle.Fill; } }
private void LoadReportContent(GitRevision revision, bool isFavIconMissing) { Validates.NotNull(_buildReportWebBrowser); try { if (revision.BuildStatus?.ShowInBuildReportTab == true) { _buildReportWebBrowser.Navigate(revision.BuildStatus.Url); } if (isFavIconMissing) { _buildReportWebBrowser.Navigated += BuildReportWebBrowserOnNavigated; } } catch { // No propagation to the user if the report fails } }
private string GetPullRequestBody() { Validates.NotNull(_info.SourceRepo); Validates.NotNull(_info.SourceRepo.ProjectKey); Validates.NotNull(_info.SourceRepo.RepoName); Validates.NotNull(_info.SourceBranch); Validates.NotNull(_info.TargetRepo); Validates.NotNull(_info.TargetRepo.ProjectKey); Validates.NotNull(_info.TargetRepo.RepoName); Validates.NotNull(_info.TargetBranch); Validates.NotNull(_info.Reviewers); JObject resource = new(); resource["title"] = _info.Title; resource["description"] = _info.Description; resource["fromRef"] = CreatePullRequestRef( _info.SourceRepo.ProjectKey, _info.SourceRepo.RepoName, _info.SourceBranch); resource["toRef"] = CreatePullRequestRef( _info.TargetRepo.ProjectKey, _info.TargetRepo.RepoName, _info.TargetBranch); JArray reviewers = new(); foreach (var reviewer in _info.Reviewers) { JObject r = new(); r["user"] = new JObject(); r["user"]["name"] = reviewer.Slug; reviewers.Add(r); } resource["reviewers"] = reviewers; return(resource.ToString()); }
private void BuildReportWebBrowserOnNavigated(object sender, WebBrowserNavigatedEventArgs webBrowserNavigatedEventArgs) { Validates.NotNull(_buildReportWebBrowser); Validates.NotNull(_buildReportTabPage); _buildReportWebBrowser.Navigated -= BuildReportWebBrowserOnNavigated; var favIconUrl = DetermineFavIconUrl(_buildReportWebBrowser.Document); if (favIconUrl is not null) { ThreadHelper.JoinableTaskFactory.RunAsync( async() => { using var imageStream = await DownloadRemoteImageFileAsync(favIconUrl); if (imageStream is not null) { await _tabControl.SwitchToMainThreadAsync(); var favIconImage = Image.FromStream(imageStream) .GetThumbnailImage(16, 16, null, IntPtr.Zero); var imageCollection = _tabControl.ImageList.Images; var imageIndex = _buildReportTabPage.ImageIndex; if (imageIndex < 0) { _buildReportTabPage.ImageIndex = imageCollection.Count; imageCollection.Add(favIconImage); } else { imageCollection[imageIndex] = favIconImage; } _tabControl.Invalidate(false); } }); } }
public ExternalLink Apply(Match?remoteMatch, Match?revisionMatch, GitRevision revision) { List <string> groups = new(); AddGroupsFromMatches(remoteMatch); AddGroupsFromMatches(revisionMatch); var groupsArray = groups.ToArray <object>(); string?caption = null; string?uri; try { caption = string.Format(Caption, groupsArray); Validates.NotNull(Format); uri = Format.Replace("%COMMIT_HASH%", revision.Guid); uri = string.Format(uri, groupsArray); IsValid = true; } catch (Exception e) { uri = e.Message + ": " + Format + " " + groupsArray; IsValid = false; } return(new ExternalLink(caption, uri)); void AddGroupsFromMatches(Match?match) { if (match is not null) { for (int i = match.Groups.Count > 1 ? 1 : 0; i < match.Groups.Count; i++) { groups.Add(match.Groups[i].Value); } } } }
public static void LoadThemeData() { Validates.NotNull(_renderers); Validates.NotNull(_scrollBarRenderer); Validates.NotNull(_headerRenderer); Validates.NotNull(_listViewRenderer); Validates.NotNull(_treeViewRenderer); foreach (ThemeRenderer renderer in _renderers) { renderer.AddThemeData(IntPtr.Zero); } var editorHandle = new ICSharpCode.TextEditor.TextEditorControl().Handle; var listViewHandle = new NativeListView().Handle; var treeViewHandle = new NativeTreeView().Handle; _scrollBarRenderer.AddThemeData(editorHandle); _scrollBarRenderer.AddThemeData(listViewHandle); _headerRenderer.AddThemeData(listViewHandle); _listViewRenderer.AddThemeData(listViewHandle); _treeViewRenderer.AddThemeData(treeViewHandle); }
private static IEnumerable <string> ReadOrInitializeAutoCompleteRegexes() { string?appDataPath = AppSettings.ApplicationDataPath.Value; Validates.NotNull(appDataPath); var path = PathUtil.Combine(appDataPath, "AutoCompleteRegexes.txt"); if (File.Exists(path)) { return(File.ReadLines(path)); } Stream?s = Assembly.GetEntryAssembly()?.GetManifestResourceStream("GitExtensions.AutoCompleteRegexes.txt"); if (s is null) { throw new NotImplementedException("Please add AutoCompleteRegexes.txt file into .csproj"); } using var sr = new StreamReader(s); return(sr.ReadToEnd().Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)); }
private static bool MigrateSettings(IList <Current.Repository> history, IEnumerable <RepositoryCategory> categorised) { var changed = false; foreach (var category in categorised.Where(c => c.CategoryType == "Repositories")) { Validates.NotNull(category.Repositories); foreach (var repository in category.Repositories) { var repo = history.FirstOrDefault(hr => hr.Path == repository.Path); if (repo is null) { repo = new Current.Repository(repository.Path !); history.Add(repo); } Validates.NotNull(repository.Anchor); repo.Anchor = GetAnchor(repository.Anchor); repo.Category = category.Description; changed = true; } } return(changed); Current.Repository.RepositoryAnchor GetAnchor(string anchor) { if (!Enum.TryParse <Current.Repository.RepositoryAnchor>(anchor, out var repositoryAnchor)) { return(Current.Repository.RepositoryAnchor.None); } return(repositoryAnchor); } }
protected override ISettingsSource GetCurrentSettings() { Validates.NotNull(CurrentSettings); return(CurrentSettings); }
public override void KillProcess() { Validates.NotNull(_terminal); KillProcess(_terminal); }
private async Task <Nodes> FillBranchTreeAsync(IReadOnlyList <IGitRef> branches, CancellationToken token) { var nodes = new Nodes(this); var pathToNodes = new Dictionary <string, BaseBranchNode>(); var enabledRemoteRepoNodes = new List <RemoteRepoNode>(); var remoteByName = (await Module.GetRemotesAsync().ConfigureAwaitRunInline()).ToDictionary(r => r.Name); var remotesManager = new ConfigFileRemoteSettingsManager(() => Module); // Create nodes for enabled remotes with branches foreach (IGitRef branch in branches) { token.ThrowIfCancellationRequested(); Validates.NotNull(branch.ObjectId); bool isVisible = !IsFiltering.Value || _refsSource.Contains(branch.ObjectId); var remoteName = branch.Name.SubstringUntil('/'); if (remoteByName.TryGetValue(remoteName, out Remote remote)) { var remoteBranchNode = new RemoteBranchNode(this, branch.ObjectId, branch.Name, isVisible); var parent = remoteBranchNode.CreateRootNode( pathToNodes, (tree, parentPath) => CreateRemoteBranchPathNode(tree, parentPath, remote)); if (parent is not null) { enabledRemoteRepoNodes.Add((RemoteRepoNode)parent); } } } // Create nodes for enabled remotes without branches var enabledRemotesNoBranches = remotesManager.GetEnabledRemoteNamesWithoutBranches(); foreach (var remoteName in enabledRemotesNoBranches) { if (remoteByName.TryGetValue(remoteName, out var remote)) { var node = new RemoteRepoNode(this, remoteName, remotesManager, remote, true); enabledRemoteRepoNodes.Add(node); } } // Add enabled remote nodes in order enabledRemoteRepoNodes .OrderBy(node => node.FullPath) .ForEach(node => nodes.AddNode(node)); // Add disabled remotes, if any var disabledRemotes = remotesManager.GetDisabledRemotes(); if (disabledRemotes.Count > 0) { var disabledRemoteRepoNodes = new List <RemoteRepoNode>(); foreach (var remote in disabledRemotes.OrderBy(remote => remote.Name)) { var node = new RemoteRepoNode(this, remote.Name, remotesManager, remote, false); disabledRemoteRepoNodes.Add(node); } var disabledFolderNode = new RemoteRepoFolderNode(this, Strings.Inactive); disabledRemoteRepoNodes .OrderBy(node => node.FullPath) .ForEach(node => disabledFolderNode.Nodes.AddNode(node)); nodes.AddNode(disabledFolderNode); } return(nodes); BaseBranchNode CreateRemoteBranchPathNode(Tree tree, string parentPath, Remote remote) { if (parentPath == remote.Name) { return(new RemoteRepoNode(tree, parentPath, remotesManager, remote, true)); } return(new BasePathNode(tree, parentPath)); } }
public ConsoleEmulatorOutputControl() { InitializeComponent(); Validates.NotNull(_panel); }
public override void AppendMessageFreeThreaded(string text) { Validates.NotNull(_terminal); _terminal.RunningSession?.WriteOutputTextAsync(text); }
/// <summary> /// Saves the remote details by creating a new or updating an existing remote entry in .git/config file. /// </summary> /// <param name="remote">An existing remote instance or <see langword="null"/> if creating a new entry.</param> /// <param name="remoteName"> /// <para>The remote name.</para> /// <para>If updating an existing remote and the name changed, it will result in remote name change and prompt for "remote update".</para> /// </param> /// <param name="remoteUrl"> /// <para>The remote URL.</para> /// <para>If updating an existing remote and the URL changed, it will result in remote URL change and prompt for "remote update".</para> /// </param> /// <param name="remotePushUrl">An optional alternative remote push URL.</param> /// <param name="remotePuttySshKey">An optional Putty SSH key.</param> /// <returns>Result of the operation.</returns> public ConfigFileRemoteSaveResult SaveRemote(ConfigFileRemote?remote, string remoteName, string remoteUrl, string?remotePushUrl, string remotePuttySshKey) { if (string.IsNullOrWhiteSpace(remoteName)) { throw new ArgumentNullException(nameof(remoteName)); } remoteName = remoteName.Trim(); // if create a new remote or updated the url - we may need to perform "update remote" bool updateRemoteRequired = false; // if operation return anything back, relay that to the user var output = string.Empty; var module = GetModule(); bool remoteDisabled = false; if (remote is null) { output = module.AddRemote(remoteName, remoteUrl); // If output was returned, something went wrong if (!string.IsNullOrWhiteSpace(output)) { return(new ConfigFileRemoteSaveResult(output, false)); } updateRemoteRequired = true; } else { if (remote.Disabled) { // disabled branches can't updated as it poses to many problems, i.e. // - verify that the branch name is valid, and // - it does not duplicate an active branch name etc. return(new ConfigFileRemoteSaveResult(null, false)); } remoteDisabled = remote.Disabled; if (!string.Equals(remote.Name, remoteName, StringComparison.Ordinal)) { Validates.NotNull(remote.Name); // the name of the remote changed - perform rename output = module.RenameRemote(remote.Name, remoteName); } if (!string.Equals(remote.Url, remoteUrl, StringComparison.Ordinal)) { // the remote url changed - we may need to update remote updateRemoteRequired = true; } } UpdateSettings(module, remoteName, remoteDisabled, SettingKeyString.RemoteUrl, remoteUrl); UpdateSettings(module, remoteName, remoteDisabled, SettingKeyString.RemotePushUrl, remotePushUrl); UpdateSettings(module, remoteName, remoteDisabled, SettingKeyString.RemotePuttySshKey, remotePuttySshKey); return(new ConfigFileRemoteSaveResult(output, updateRemoteRequired)); }
private static CommandStatus RunScriptInternal(IWin32Window owner, IGitModule module, string?scriptKey, IGitUICommands uiCommands, RevisionGridControl?revisionGrid) { if (Strings.IsNullOrEmpty(scriptKey)) { return(false); } ScriptInfo?scriptInfo = ScriptManager.GetScript(scriptKey); if (scriptInfo is null) { ThreadHelper.AssertOnUIThread(); throw new UserExternalOperationException($"{TranslatedStrings.ScriptErrorCantFind}: '{scriptKey}'", new ExternalOperationException(command: null, arguments: null, module.WorkingDir, innerException: null)); } if (Strings.IsNullOrEmpty(scriptInfo.Command)) { return(false); } string?arguments = scriptInfo.Arguments; if (!Strings.IsNullOrEmpty(arguments) && revisionGrid is null) { string?optionDependingOnSelectedRevision = ScriptOptionsParser.Options.FirstOrDefault(option => ScriptOptionsParser.DependsOnSelectedRevision(option) && ScriptOptionsParser.Contains(arguments, option)); if (optionDependingOnSelectedRevision is not null) { ThreadHelper.AssertOnUIThread(); throw new UserExternalOperationException($"{TranslatedStrings.ScriptText}: '{scriptKey}'{Environment.NewLine}'{optionDependingOnSelectedRevision}' {TranslatedStrings.ScriptErrorOptionWithoutRevisionGridText}", new ExternalOperationException(scriptInfo.Command, arguments, module.WorkingDir, innerException: null)); } } if (scriptInfo.AskConfirmation && MessageBox.Show(owner, $"{TranslatedStrings.ScriptConfirmExecute}: '{scriptInfo.Name}'?", TranslatedStrings.ScriptText, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) { return(false); } string?originalCommand = scriptInfo.Command; (string?argument, bool abort) = ScriptOptionsParser.Parse(scriptInfo.Arguments, module, owner, revisionGrid); if (abort) { ThreadHelper.AssertOnUIThread(); throw new UserExternalOperationException($"{TranslatedStrings.ScriptText}: '{scriptKey}'{Environment.NewLine}{TranslatedStrings.ScriptErrorOptionWithoutRevisionText}", new ExternalOperationException(scriptInfo.Command, arguments, module.WorkingDir, innerException: null)); } Validates.NotNull(argument); string command = OverrideCommandWhenNecessary(originalCommand); command = ExpandCommandVariables(command, module); if (scriptInfo.IsPowerShell) { PowerShellHelper.RunPowerShell(command, argument, module.WorkingDir, scriptInfo.RunInBackground); // 'RunPowerShell' always runs the script detached (yet). // Hence currently, it does not make sense to set 'needsGridRefresh' to '!scriptInfo.RunInBackground'. return(new CommandStatus(executed: true, needsGridRefresh: false)); } if (command.StartsWith(PluginPrefix)) { command = command.Replace(PluginPrefix, string.Empty); lock (PluginRegistry.Plugins) { foreach (var plugin in PluginRegistry.Plugins) { if (string.Equals(plugin.Name, command, StringComparison.CurrentCultureIgnoreCase)) { var eventArgs = new GitUIEventArgs(owner, uiCommands); return(new CommandStatus(executed: true, needsGridRefresh: plugin.Execute(eventArgs))); } } } return(false); } if (command.StartsWith(NavigateToPrefix)) { if (revisionGrid is null) { return(false); } command = command.Replace(NavigateToPrefix, string.Empty); if (!Strings.IsNullOrEmpty(command)) { var revisionRef = new Executable(command, module.WorkingDir).GetOutputLines(argument).FirstOrDefault(); if (revisionRef is not null) { revisionGrid.GoToRef(revisionRef, true); } } return(new CommandStatus(executed: true, needsGridRefresh: false)); } if (!scriptInfo.RunInBackground) { bool success = FormProcess.ShowDialog(owner, command, argument, module.WorkingDir, null, true); if (!success) { return(false); } } else { if (originalCommand.Equals("{openurl}", StringComparison.CurrentCultureIgnoreCase)) { OsShellUtil.OpenUrlInDefaultBrowser(argument); } else { // It is totally valid to have a command without an argument, e.g.: // Command : myscript.cmd // Arguments: <blank> new Executable(command, module.WorkingDir).Start(argument ?? string.Empty); } } return(new CommandStatus(executed: true, needsGridRefresh: !scriptInfo.RunInBackground)); }
public override void SetValue <T>(string name, T value, Func <T, string?> encode) { Validates.NotNull(_parent); _parent.SetValue(PathFor(name), value, encode); }
private void buttonBrowse_Click(object sender, EventArgs e) { Validates.NotNull(PathShowingControl); ShowFolderBrowserDialogWithPreselectedPath(() => PathShowingControl.Text, path => PathShowingControl.Text = path); }
public static GitSubmoduleStatus?ParseSubmoduleStatus(string?text, GitModule module, string?fileName) { if (string.IsNullOrEmpty(text)) { return(null); } string?name = null; string? oldName = null; bool isDirty = false; ObjectId?commitId = null; ObjectId?oldCommitId = null; int? addedCommits = null; int? removedCommits = null; using (var reader = new StringReader(text)) { string?line = reader.ReadLine(); if (line is not null) { var match = Regex.Match(line, @"diff --git [abic]/(.+)\s[abwi]/(.+)"); if (match.Groups.Count > 1) { name = match.Groups[1].Value; oldName = match.Groups[2].Value; } else { match = Regex.Match(line, @"diff --cc (.+)"); if (match.Groups.Count > 1) { name = match.Groups[1].Value; oldName = match.Groups[1].Value; } } } while ((line = reader.ReadLine()) is not null) { // We are looking for lines resembling: // // -Subproject commit bfef4454fc51e345051ee5bf66686dc28deed627 // +Subproject commit 8b20498b954609770205c2cc794b868b4ac3ee69-dirty if (!line.Contains("Subproject")) { continue; } char c = line[0]; const string commitStr = "commit "; string hash = ""; int pos = line.IndexOf(commitStr); if (pos >= 0) { hash = line.Substring(pos + commitStr.Length); } bool endsWithDirty = hash.EndsWith("-dirty"); hash = hash.Replace("-dirty", ""); if (c == '-') { oldCommitId = ObjectId.Parse(hash); } else if (c == '+') { commitId = ObjectId.Parse(hash); isDirty = endsWithDirty; } // TODO: Support combined merge } } if (oldCommitId is not null && commitId is not null) { if (oldCommitId == commitId) { addedCommits = 0; removedCommits = 0; } else { var submodule = module.GetSubmodule(fileName); if (submodule.IsValidGitWorkingDir()) { addedCommits = submodule.GetCommitCount(commitId.ToString(), oldCommitId.ToString(), cache: true, throwOnErrorExit: false); removedCommits = submodule.GetCommitCount(oldCommitId.ToString(), commitId.ToString(), cache: true, throwOnErrorExit: false); } } } Validates.NotNull(name); return(new GitSubmoduleStatus(name, oldName, isDirty, commitId, oldCommitId, addedCommits, removedCommits)); }
public override T GetValue <T>(string name, T defaultValue, Func <string, T> decode) { Validates.NotNull(_parent); return(_parent.GetValue(PathFor(name), defaultValue, decode)); }
private void ObserveBuilds(IObserver <BuildInfo> observer, CancellationToken cancellationToken) { try { var allBuildInfos = new List <JoinableTask <ResponseInfo> >(); var latestBuildInfos = new List <JoinableTask <ResponseInfo> >(); foreach (var projectUrl in _lastProjectBuildTime.Keys) { if (_lastProjectBuildTime[projectUrl] <= 0) { // This project must be updated, no need to to check the latest builds allBuildInfos.Add(ThreadHelper.JoinableTaskFactory.RunAsync(() => GetBuildInfoTaskAsync(projectUrl, true, cancellationToken))); } else { latestBuildInfos.Add(ThreadHelper.JoinableTaskFactory.RunAsync(() => GetBuildInfoTaskAsync(projectUrl, false, cancellationToken))); } } // Check the latest build on the server to the existing build timestamp // The simple request will limit the load on the Jenkins server // To fetch just new builds is possible too, but it will make the solution more complicated // Similar, the build results could be cached so they are available when switching repos foreach (var info in latestBuildInfos.Where(info => !info.Task.IsFaulted)) { ResponseInfo responseInfo = info.Join(); Validates.NotNull(responseInfo.Url); if (responseInfo.Timestamp > _lastProjectBuildTime[responseInfo.Url]) { // The info has at least one newer job, query the status allBuildInfos.Add(ThreadHelper.JoinableTaskFactory.RunAsync(() => GetBuildInfoTaskAsync(responseInfo.Url, true, cancellationToken))); } } if (allBuildInfos.All(t => t.Task.IsCanceled)) { observer.OnCompleted(); return; } var builds = new Dictionary <ObjectId, BuildInfo.BuildStatus>(); foreach (var build in allBuildInfos) { if (build.Task.IsFaulted) { Debug.Assert(build.Task.Exception is not null, "build.Task.Exception is not null"); observer.OnError(build.Task.Exception); continue; } var buildResponse = build.Join(cancellationToken); if (build.Task.IsCanceled || buildResponse.Timestamp <= 0) { // No valid information received for the build continue; } Validates.NotNull(buildResponse.Url); Validates.NotNull(buildResponse.JobDescription); _lastProjectBuildTime[buildResponse.Url] = buildResponse.Timestamp; foreach (var buildDetails in buildResponse.JobDescription) { if (cancellationToken.IsCancellationRequested) { return; } try { var buildInfo = CreateBuildInfo((JObject)buildDetails); if (buildInfo is null) { continue; } if (buildInfo.Status == BuildInfo.BuildStatus.InProgress) { // Need to make a full request next time _lastProjectBuildTime[buildResponse.Url] = 0; } // Normally, there is only one commit per Jenkins build // builds listed with latest first, likely most interesting // Update the observer if at least one of them is better (cannot be selective) var isBetter = false; foreach (var commit in buildInfo.CommitHashList) { if (!StatusIsBetter(buildInfo.Status, commit, builds)) { continue; } isBetter = true; builds[commit] = buildInfo.Status; } if (isBetter) { observer.OnNext(buildInfo); } } catch { // Ignore unexpected responses } } } // Complete the job, it will be run again with Observe.Retry() (every 10th sec) observer.OnCompleted(); } catch (OperationCanceledException) { // Do nothing, the observer is already stopped } catch (Exception ex) { // Cancelling a sub-task is similar to cancelling this task if (!(ex.InnerException is OperationCanceledException)) { observer.OnError(ex); } } return;
public void SaveSettings() { Validates.NotNull(Settings); HotkeySettingsManager.SaveSettings(Settings); }
private void OnStatusUpdated(SubmoduleStatusEventArgs e) { ThreadHelper.JoinableTaskFactory.RunAsync(async() => { CancellationTokenSource?cts = null; Task <Nodes>?loadNodesTask = null; if (e.StructureUpdated) { _currentNodes = null; } if (_currentNodes is not null) { // Structure is up-to-date, update status var infos = e.Info.AllSubmodules.ToDictionary(info => info.Path, info => info); Validates.NotNull(e.Info.TopProject); infos[e.Info.TopProject.Path] = e.Info.TopProject; var nodes = _currentNodes.DepthEnumerator <SubmoduleNode>().ToList(); foreach (var node in nodes) { if (infos.ContainsKey(node.Info.Path)) { node.Info = infos[node.Info.Path]; infos.Remove(node.Info.Path); } else { // structure no longer matching Debug.Assert(true, $"Status info with {1 + e.Info.AllSubmodules.Count} records do not match current nodes ({nodes.Count})"); _currentNodes = null; break; } } if (infos.Count > 0) { Debug.Fail($"{infos.Count} status info records remains after matching current nodes, structure seem to mismatch ({nodes.Count}/{e.Info.AllSubmodules.Count})"); _currentNodes = null; } } if (_currentNodes is null) { await ReloadNodesAsync(token => { cts = CancellationTokenSource.CreateLinkedTokenSource(e.Token, token); loadNodesTask = LoadNodesAsync(e.Info, cts.Token); return(loadNodesTask); }).ConfigureAwait(false); } if (cts is not null && loadNodesTask is not null) { _currentNodes = await loadNodesTask; } if (_currentNodes is not null) { var token = cts?.Token ?? e.Token; await LoadNodeDetailsAsync(_currentNodes, token).ConfigureAwaitRunInline(); LoadNodeToolTips(_currentNodes, token); } Interlocked.CompareExchange(ref _currentSubmoduleInfo, null, e); }).FileAndForget(); }
public async Task <TextRange?> FindNextAsync(bool viaF3, bool searchBackward, string?messageIfNotFound) { if (string.IsNullOrEmpty(txtLookFor.Text)) { MessageBox.Show(this, _noSearchString.Text, Text, MessageBoxButtons.OK, MessageBoxIcon.Information); return(null); } Validates.NotNull(_editor); _lastSearchWasBackward = searchBackward; _search.LookFor = txtLookFor.Text; _search.MatchCase = chkMatchCase.Checked; _search.MatchWholeWordOnly = chkMatchWholeWord.Checked; int startIdx = -1; int currentIdx = -1; TextRange?range; do { Caret caret = _editor.ActiveTextAreaControl.Caret; if (viaF3 && _search.HasScanRegion && !Globals.IsInRange(caret.Offset, _search.BeginOffset, _search.EndOffset)) { // user moved outside of the originally selected region _search.ClearScanRegion(); } int startFrom = caret.Offset - (searchBackward ? 1 : 0); if (startFrom == -1) { startFrom = _search.EndOffset; } var isMultiFileSearch = _fileLoader is not null && !_search.HasScanRegion; range = _search.FindNext(startFrom, searchBackward, out _lastSearchLoopedAround); if (range is not null && (!_lastSearchLoopedAround || !isMultiFileSearch)) { SelectResult(range); } else if (isMultiFileSearch) { range = null; if (currentIdx != -1 && startIdx == -1) { startIdx = currentIdx; } Validates.NotNull(_fileLoader); if (_fileLoader(searchBackward, true, out var fileIndex, out var loadFileContent)) { currentIdx = fileIndex; try { await loadFileContent; } catch (OperationCanceledException) { break; } } else { break; } }
public override Control CreateControl() { Validates.NotNull(_textBoxCreator); Setting.CustomControl = _textBoxCreator(); return(Setting.CustomControl); }
private void AddTopAndNodesToTree( ref Nodes nodes, List <SubmoduleNode> submoduleNodes, GitModule threadModule, SubmoduleInfoResult result) { // Create tree of SubmoduleFolderNode for each path directory and add input SubmoduleNodes as leaves. // Example of (SuperPath + LocalPath).ToPosixPath() for all nodes: // // C:/code/gitextensions2/Externals/conemu-inside // C:/code/gitextensions2/Externals/Git.hub // C:/code/gitextensions2/Externals/ICSharpCode.TextEditor // C:/code/gitextensions2/Externals/ICSharpCode.TextEditor/gitextensions // C:/code/gitextensions2/Externals/ICSharpCode.TextEditor/gitextensions/Externals/conemu-inside // C:/code/gitextensions2/Externals/ICSharpCode.TextEditor/gitextensions/Externals/Git.hub // C:/code/gitextensions2/Externals/ICSharpCode.TextEditor/gitextensions/Externals/ICSharpCode.TextEditor // C:/code/gitextensions2/Externals/ICSharpCode.TextEditor/gitextensions/Externals/NBug // C:/code/gitextensions2/Externals/ICSharpCode.TextEditor/gitextensions/GitExtensionsDoc // C:/code/gitextensions2/Externals/NBug // C:/code/gitextensions2/GitExtensionsDoc // // What we want to do is first remove the topModule portion, "C:/code/gitextensions2/", and // then build our tree by breaking up each path into parts, separated by '/'. // // Note that when we break up the paths, some parts are just directories, the others are submodule nodes: // // Externals / ICSharpCode.TextEditor / gitextensions / Externals / Git.hub // folder submodule submodule folder submodule // // Input 'nodes' is an array of SubmoduleNodes for all the submodules; now we need to create SubmoduleFolderNodes // and insert everything into a tree. var topModule = threadModule.GetTopModule(); // Build a mapping of top-module-relative path to node var pathToNodes = new Dictionary <string, Node>(); // Add existing SubmoduleNodes foreach (var node in submoduleNodes) { pathToNodes[GetNodeRelativePath(topModule, node)] = node; } // Create and add missing SubmoduleFolderNodes foreach (var node in submoduleNodes) { var parts = GetNodeRelativePath(topModule, node).Split(Delimiters.ForwardSlash); for (int i = 0; i < parts.Length - 1; ++i) { var path = string.Join("/", parts.Take(i + 1)); if (!pathToNodes.ContainsKey(path)) { pathToNodes[path] = new SubmoduleFolderNode(this, parts[i]); } } } // Now build the tree var rootNode = new DummyNode(); var nodesInTree = new HashSet <Node>(); foreach (var node in submoduleNodes) { Node parentNode = rootNode; var parts = GetNodeRelativePath(topModule, node).Split(Delimiters.ForwardSlash); for (int i = 0; i < parts.Length; ++i) { var path = string.Join("/", parts.Take(i + 1)); var nodeToAdd = pathToNodes[path]; // If node is not already in the tree, add it if (!nodesInTree.Contains(nodeToAdd)) { parentNode.Nodes.AddNode(nodeToAdd); nodesInTree.Add(nodeToAdd); } parentNode = nodeToAdd; } } Validates.NotNull(result.TopProject); // Add top-module node, and move children of root to it var topModuleNode = new SubmoduleNode( this, result.TopProject, result.TopProject.Bold, result.TopProject.Bold ? result.CurrentSubmoduleStatus : null, "", result.TopProject.Path); topModuleNode.Nodes.AddNodes(rootNode.Nodes); nodes.AddNode(topModuleNode); }
/// <summary> /// Draws visible end side. /// </summary> /// <param name = "graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> internal void DrawVisibleEndSide(Graphics graphics) { Validates.NotNull(Pen); Validates.NotNull(BrushEndSide); EndSide.Draw(graphics, Pen, BrushEndSide); }