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);
                }
            }
コード例 #2
0
        /// <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);
        }
コード例 #3
0
        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;
            });
        }
コード例 #4
0
        /// <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());
        }
コード例 #5
0
        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;
            }
        }
コード例 #6
0
        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
            }
        }
コード例 #7
0
        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());
        }
コード例 #8
0
        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);
                    }
                });
            }
        }
コード例 #9
0
        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);
                    }
                }
            }
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        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));
        }
コード例 #12
0
        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);
            }
        }
コード例 #13
0
 protected override ISettingsSource GetCurrentSettings()
 {
     Validates.NotNull(CurrentSettings);
     return(CurrentSettings);
 }
コード例 #14
0
 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));
                }
            }
コード例 #16
0
        public ConsoleEmulatorOutputControl()
        {
            InitializeComponent();

            Validates.NotNull(_panel);
        }
コード例 #17
0
 public override void AppendMessageFreeThreaded(string text)
 {
     Validates.NotNull(_terminal);
     _terminal.RunningSession?.WriteOutputTextAsync(text);
 }
コード例 #18
0
        /// <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));
        }
コード例 #19
0
ファイル: ScriptRunner.cs プロジェクト: zjwmyl/gitextensions
        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));
        }
コード例 #20
0
 public override void SetValue <T>(string name, T value, Func <T, string?> encode)
 {
     Validates.NotNull(_parent);
     _parent.SetValue(PathFor(name), value, encode);
 }
コード例 #21
0
        private void buttonBrowse_Click(object sender, EventArgs e)
        {
            Validates.NotNull(PathShowingControl);

            ShowFolderBrowserDialogWithPreselectedPath(() => PathShowingControl.Text, path => PathShowingControl.Text = path);
        }
コード例 #22
0
        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));
        }
コード例 #23
0
 public override T GetValue <T>(string name, T defaultValue, Func <string, T> decode)
 {
     Validates.NotNull(_parent);
     return(_parent.GetValue(PathFor(name), defaultValue, decode));
 }
コード例 #24
0
        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;
コード例 #25
0
 public void SaveSettings()
 {
     Validates.NotNull(Settings);
     HotkeySettingsManager.SaveSettings(Settings);
 }
コード例 #26
0
            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();
            }
コード例 #27
0
        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;
                    }
                }
コード例 #28
0
 public override Control CreateControl()
 {
     Validates.NotNull(_textBoxCreator);
     Setting.CustomControl = _textBoxCreator();
     return(Setting.CustomControl);
 }
コード例 #29
0
            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);
            }
コード例 #30
0
 /// <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);
 }