* Simple case: execute one command: Run() returns when the command completes return structure including the stdout safety built-in: self-terminate if there is no response within some time * More complex case: AsyncRun() command takes more time: asynchronous execution with a completion callback callbacks for stdout and stderr can terminate execution from another thread: Terminate()
Пример #1
0
        /// <summary>
        /// Create a git file of a specific version. Use a temp file since the file
        /// content needs to be created from the git history.
        /// </summary>
        private string GetTempFile(string file, string sha)
        {
            // git show commands needs '/' as file path separator
            string gitpath = file.Replace(Path.DirectorySeparatorChar, '/');
            string cmd     = string.Format("show {1}:\"{0}\"", gitpath, sha);

            ExecResult result = App.Repos.Current.Run(cmd);

            if (result.Success() == false)
            {
                return(string.Empty);
            }
            string response = result.stdout;

            // Create a temp file based on a version of our file and write its content to it
            string rev = listRev.Items.Find(sha, false)[0].Text.Trim();

            file = Path.GetFileName(file);
            file = string.Format("ReadOnly-{0}-Rev-{1}-{2}", tmpFileCounter, rev, file);
            tmpFileCounter++;
            string tempFile = Path.Combine(Path.GetTempPath(), file);

            try
            {
                File.WriteAllText(tempFile, response);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            // Add the temp file to the global list of temp files to be removed at the app exit time
            ClassGlobals.TempFiles.Add(tempFile);
            return(tempFile);
        }
Пример #2
0
        /// <summary>
        /// User clicked on a log item. Fetch its full description.
        /// </summary>
        private void ListRevSelectedIndexChanged(object sender, EventArgs e)
        {
            // Set the menu enables according to the number of items selected
            viewMenuItem.Enabled          = syncMenuItem.Enabled = diffVsClientFileMenuItem.Enabled = listRev.SelectedIndices.Count == 1;
            diffRevisionsMenuItem.Enabled = listRev.SelectedIndices.Count == 2;

            // Set up for 2 SHA checkins: the one in the [0] spot being the most recently selected
            if (listRev.SelectedIndices.Count == 1)
            {
                lruSha[0] = lruSha[1] = listRev.SelectedItems[0].Name;
            }
            if (listRev.SelectedIndices.Count > 1)
            {
                if (listRev.SelectedItems[0].Name == lruSha[0])
                {
                    lruSha[1] = listRev.SelectedItems[1].Name;
                }
                else
                {
                    lruSha[1] = listRev.SelectedItems[0].Name;
                }
            }
            // Fill in the description of a selected checkin if a single one is selected
            if (listRev.SelectedIndices.Count == 1)
            {
                string     sha    = lruSha[1];
                string     cmd    = string.Format("show -s {0}", sha);
                ExecResult result = App.Repos.Current.Run(cmd);
                textDescription.Text = result.Success() ? result.stdout : result.stderr;
            }
        }
Пример #3
0
        /// <summary>
        /// Reload status fields in the context of a status class
        /// </summary>
        private void Status()
        {
            XY.Clear();
            AltFile.Clear();
            ExecResult result = Repo.Run("status --porcelain -uall -z");

            if (!result.Success())
            {
                return;
            }
            string[] response = result.stdout
                                .Replace('/', Path.DirectorySeparatorChar) // Correct the path slash on Windows
                                .Split(("\0")
                                       .ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < response.Length; i++)
            {
                string s    = response[i].Substring(3);
                string code = response[i].Substring(0, 2);
                XY[s] = code;
                if ("RC".Contains(response[i][0]))
                {
                    i++;
                    AltFile[s] = response[i];
                }
            }
        }
Пример #4
0
        public ExecResult Run(string args, bool async)
        {
            ExecResult output = new ExecResult();

            try
            {
                Directory.SetCurrentDirectory(Root);

                // Set the HTTPS password
                string password = Remotes.GetPassword("");
                ClassUtils.AddEnvar("PASSWORD", password);

                // The Windows limit to the command line argument length is about 8K
                // We may hit that limit when doing operations on a large number of files.
                //
                // However, when sending a long list of files, git was hanging unless
                // the total length was much less than that, so I set it to about 2000 chars
                // which seemed to work fine.

                if (args.Length < 2000)
                {
                    return(ClassGit.Run(args, async));
                }

                // Partition the args into "[command] -- [set of file chunks < 2000 chars]"
                // Basically we have to rebuild the command into multiple instances with
                // same command but with file lists not larger than about 2K
                int    i   = args.IndexOf(" -- ") + 3;
                string cmd = args.Substring(0, i + 1);
                args = args.Substring(i);       // We separate git command up to and until the list of files

                App.PrintLogMessage("Processing large amount of files: please wait...", MessageType.General);

                // Add files individually up to the length limit using the starting " file delimiter
                string[] files = args.Split(new [] { " \"" }, StringSplitOptions.RemoveEmptyEntries);
                // Note: files in the list are now stripped from their initial " character!
                i = 0;
                do
                {
                    StringBuilder batch = new StringBuilder(2100);
                    while (batch.Length < 2000 && i < files.Length)
                    {
                        batch.Append("\"" + files[i++] + " ");
                    }

                    output = ClassGit.Run(cmd + batch, async);
                    if (output.Success() == false)
                    {
                        break;
                    }
                } while (i < files.Length);
            }
            catch (Exception ex)
            {
                App.PrintLogMessage(ex.Message, MessageType.Error);
            }

            return(output);
        }
Пример #5
0
        /// <summary>
        /// Refresh the list of remotes for the given repo while keeping the
        /// existing passwords and push commands
        /// </summary>
        public void Refresh(ClassRepo repo)
        {
            // Build the new list while picking up password fields from the existing list
            Dictionary <string, Remote> newlist = new Dictionary <string, Remote>();

            string[]   response = new[] { string.Empty };
            ExecResult result   = repo.Run("remote -v");

            if (result.Success())
            {
                response = result.stdout.Split((Environment.NewLine).ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

                foreach (string s in response)
                {
                    Remote r = new Remote();

                    // Split the resulting remote repo name/url into separate strings
                    string[] url  = s.Split("\t ".ToCharArray());
                    string   name = url[0];

                    // Find if the name exists in the main list and save off the password from it
                    if (newlist.ContainsKey(name))
                    {
                        r = newlist[name];
                    }

                    if (remotes.ContainsKey(name))
                    {
                        r.Password = remotes[name].Password;
                        r.PushCmd  = remotes[name].PushCmd;
                    }

                    // Set all other fields that we refresh every time
                    r.Name = name;

                    if (url[2] == "(fetch)")
                    {
                        r.UrlFetch = url[1];
                    }
                    if (url[2] == "(push)")
                    {
                        r.UrlPush = url[1];
                    }

                    // Add it to the new list
                    newlist[name] = r;
                }
            }

            // Set the newly built list to be the master list
            remotes = newlist;

            // Fixup the new current string name
            if (!remotes.ContainsKey(Current))
            {
                Current = remotes.Count > 0 ? remotes.ElementAt(0).Key : "";
            }
        }
Пример #6
0
 /// <summary>
 /// Switch to a named branch
 /// </summary>
 public bool SwitchTo(string name)
 {
     // Make sure the given branch name is a valid local branch
     if (!string.IsNullOrEmpty(name) && Local.IndexOf(name) >= 0)
     {
         ExecResult result = App.Repos.Current.RunCmd("checkout " + name);
         return(result.Success());
     }
     return(false);
 }
Пример #7
0
        /// <summary>
        /// Returns a value of a global git configuration key
        /// </summary>
        public static string GetGlobal(string key)
        {
            ExecResult result = ClassGit.Run("config --global --get " + key);

            if (result.Success())
            {
                return(result.stdout);
            }

            App.PrintLogMessage("Error getting global git config parameter!", MessageType.Error);
            return(String.Empty);
        }
Пример #8
0
        /// <summary>
        /// Returns a value of a local git configuration key
        /// </summary>
        public static string GetLocal(ClassRepo repo, string key)
        {
            ExecResult result = repo.Run("config --local --get " + key);

            if (result.Success())
            {
                return(result.stdout);
            }

            App.PrintLogMessage("Error getting local git config parameter!", MessageType.Error);
            return(string.Empty);
        }
Пример #9
0
        /// <summary>
        /// Initializes SSH connection by running the PLINK using the specified
        /// connection parameters. This function blocks until the PLINK returns.
        /// </summary>
        public void ImportRemoteSshKey(ClassUrl.Url url)
        {
            // Build the arguments to the PLINK process: port number, user and the host
            // Use the default SSH values if the url did not provide them
            string args = " -P " + (url.Port > 0 ? url.Port.ToString() : "22") +
                          " -l " + (string.IsNullOrEmpty(url.User) ? "anonymous" : url.User) +
                          " " + url.Host;

            // plink does everything through its stderr stream
            ExecResult result = Exec.Run(pathPlink, args);

            App.PrintLogMessage(result.stderr, MessageType.Error);
        }
Пример #10
0
 /// <summary>
 /// Sync file to the selected revision
 /// </summary>
 private void SyncMenuItemClick(object sender, EventArgs e)
 {
     if (MessageBox.Show("This will sync file to a previous version. Continue?", "Revision Sync",
                         MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
     {
         string     cmd    = string.Format("checkout {1} -- {0}", file, lruSha[0]);
         ExecResult result = App.Repos.Current.RunCmd(cmd);
         if (result.Success())
         {
             App.PrintStatusMessage("File checked out at a previous revision " + lruSha[0] + ": " + file, MessageType.General);
             App.DoRefresh();
         }
         else
         {
             App.PrintStatusMessage("Sync error: " + result.stderr, MessageType.Error);
             MessageBox.Show(result.stderr, "Sync error", MessageBoxButtons.OK, MessageBoxIcon.Error);
         }
     }
 }
Пример #11
0
        /// <summary>
        /// User clicked on the Install button.. We need to find the latest msysgit build,
        /// download it and run it
        /// </summary>
        private void BtInstallClick(object sender, EventArgs e)
        {
            string installerFile = Path.GetTempFileName(); // Junk name so we can safely call 'Delete'

            try
            {
                // msysgit is hosted at https://github.com/msysgit/msysgit/releases
                // and the files can be downloaded at the subfolder 'download':

                FormDownload msysgit = new FormDownload("Download msysgit",
                                                        @"https://github.com/msysgit/msysgit/releases",
                                                        @"(?<file>Git-[1-2]+.[0-9]+.[0-9]+-\S+.exe)", "/download/");

                // If the download succeeded, run the installer file
                if (msysgit.ShowDialog() == DialogResult.OK)
                {
                    installerFile = msysgit.TargetFile;
                    ExecResult ret = Exec.Run(installerFile, String.Empty);
                    if (ret.retcode == 0)
                    {
                        // Check if the git executable is at the expected location now
                        if (File.Exists(gitPath))
                        {
                            PathToGit = textBoxPath.Text = gitPath;
                        }
                    }
                    DialogResult = DialogResult.OK;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
            }
            finally
            {
                // Make sure we don't leave temporary files around
                File.Delete(installerFile);
            }
        }
Пример #12
0
        /// <summary>
        /// The form is loading. Get the file log information and fill it in.
        /// </summary>
        private void FormRevisionHistoryLoad(object sender, EventArgs e)
        {
            // Get the list of revisions by running a git command
            StringBuilder cmd = new StringBuilder("log ");

            cmd.Append(" --pretty=format:");        // Start formatting section
            cmd.Append("%h%x09");                   // Abbreviated commit hash
            cmd.Append("%ct%x09");                  // Committing time, UNIX-style
            cmd.Append("%an%x09");                  // Author name
            cmd.Append("%s");                       // Subject

            // Limit the number of commits to show
            if (Properties.Settings.Default.commitsRetrieveAll == false)
            {
                cmd.Append(" -" + Properties.Settings.Default.commitsRetrieveLast);
            }

            // Get the log of a single file only
            cmd.Append(" -- \"" + file + "\"");

            ExecResult result = App.Repos.Current.Run(cmd.ToString());

            if (result.Success())
            {
                PanelRevlist.UpdateList(listRev, result.stdout, true, string.Empty);
            }
            if (listRev.Items.Count > 0)
            {
                // Activate the given SHA item or the first one if none given
                int index = listRev.Items.IndexOfKey(Sha);
                if (index < 0)
                {
                    index = 0;
                }
                listRev.SelectedIndices.Add(index);
                listRev.Items[index].EnsureVisible();
            }
        }
Пример #13
0
 /// <summary>
 /// Callback that handles process completion event
 /// </summary>
 private void PComplete(ExecResult result)
 {
     UseWaitCursor = false;
     this.result   = result;
     if (result.Success())
     {
         toolStripStatus.Text = "Git command completed successfully.";
         textStdout.AppendText("Git command completed successfully.", Color.Green);
         // On success, auto-close the dialog if the user's preference was checked
         // This behavior can be skipped if the user holds down the Control key
         if (Properties.Settings.Default.AutoCloseGitOnSuccess && Control.ModifierKeys != Keys.Control)
         {
             DialogResult = DialogResult.OK;
         }
     }
     else
     {
         toolStripStatus.Text = "Git command failed!";
         textStdout.AppendText("Git command failed!", Color.Red);
     }
     btCancel.Text = "Done";
     StopProgress();
 }
Пример #14
0
        /// <summary>
        /// Add new remote repository
        /// </summary>
        private void BtAddClick(object sender, EventArgs e)
        {
            ClassRemotes.Remote remote        = new ClassRemotes.Remote();
            FormRemoteAddEdit   remoteAddEdit = new FormRemoteAddEdit();

            remoteAddEdit.Prepare(FormRemoteAddEdit.Function.Add, remote);

            if (remoteAddEdit.ShowDialog() == DialogResult.OK)
            {
                remote = remoteAddEdit.Get();
                ExecResult result = _repo.Run("remote add " + remote.Name + " " + remote.UrlFetch);
                if (result.Success())
                {
                    _repo.Remotes.SetPassword(remote.Name, remote.Password);
                    _repo.Remotes.SetPushCmd(remote.Name, remote.PushCmd);
                    SetRepo(_repo);
                }
                else
                {
                    MessageBox.Show("Git is unable to add this remote repository.", "Add remote repository", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    App.PrintStatusMessage(result.stderr, MessageType.Error);
                }
            }
        }
Пример #15
0
        public ExecResult RunCmd(string args, bool async)
        {
            // Print the actual command line to the status window only if user selected that setting
            if (Properties.Settings.Default.logCommands)
            {
                App.PrintStatusMessage("git " + args, MessageType.Command);
            }

            // Run the command and print the response to the status window in any case
            ExecResult result = Run(args, async);

            if (result.stdout.Length > 0)
            {
                App.PrintStatusMessage(result.stdout, MessageType.Output);
            }

            // If the command caused an error, print it also
            if (result.Success() == false)
            {
                App.PrintStatusMessage(result.stderr, MessageType.Error);
            }

            return(result);
        }
Пример #16
0
        /// <summary>
        /// Populate list with existing stashes
        /// </summary>
        private void PopulateStashList()
        {
            listStashes.Items.Clear();
            ExecResult result = App.Repos.Current.Run("stash list");

            if (result.Success())
            {
                string[] response = result.stdout.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var stash in response)
                {
                    listStashes.Items.Add(stash);
                }
            }
            // Disable buttons (in the case the stash list was empty)
            // but re-enable them once we have a stash to select (select the top one by default)
            btApply.Enabled = btRemove.Enabled = btShow.Enabled = false;
            if (listStashes.Items.Count > 0)
            {
                string s = listStashes.Items[0].ToString();
                stash = s.Substring(0, s.IndexOf(':'));
                listStashes.SelectedIndex = 0;
                btApply.Enabled           = btRemove.Enabled = btShow.Enabled = true;
            }
        }
Пример #17
0
        /// <summary>
        /// Button clicked to delete a selected branch.
        /// This method is called only if a branch has been selected (otherwise the Delete button was disabled)
        /// </summary>
        private void DeleteClick(object sender, EventArgs e)
        {
            string cmd;
            string selectedBranch = listBranches.SelectedItem.ToString();

            // Depending on the branch (local or remote), use a different way to delete it
            if (radioLocalBranch.Checked)
            {
                cmd = String.Format("branch {0} {1}", checkForce.Checked ? "-D" : "-d", selectedBranch);
            }
            else
            {
                // Remote branch
                string repoName   = selectedBranch.Split('/')[0];
                string branchName = selectedBranch.Split('/')[1];
                if (checkTracking.Checked)
                {
                    cmd = String.Format("branch -rd {0}", branchName); // Remove a reference to a remote branch
                }
                else
                {
                    cmd = String.Format("push {0} :{1}", repoName, branchName);
                }
            }

            // Execute the final branch command and if fail, show the dialog box asking to retry
            ExecResult result = App.Repos.Current.RunCmd(cmd);

            if (result.Success() == false)
            {
                if (MessageBox.Show(result.stderr, "Error deleting branch", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Retry)
                {
                    DialogResult = DialogResult.None;
                }
            }
        }
Пример #18
0
        /// <summary>
        /// Called on a change of radio button selection for the branch origin
        /// </summary>
        private void RadioBranchSourceCheckedChanged(object sender, EventArgs e)
        {
            RadioButton rb = sender as RadioButton;

            if (rb.Checked == false)
            {
                switch (rb.Tag.ToString())
                {
                case "SHA1":
                    textSHA1.Enabled = false;
                    break;

                default:
                    listBranches.Enabled   = false;
                    listBranches.BackColor = SystemColors.Control;
                    break;
                }
                origin = null;
            }
            else
            {
                switch (rb.Tag.ToString())
                {
                case "Head":
                    break;

                case "SHA1":
                    textSHA1.Enabled = true;
                    break;

                case "Local":
                    listBranches.Items.Clear();
                    foreach (var branch in branches.Local)
                    {
                        listBranches.Items.Add(branch);
                    }
                    listBranches.Enabled   = true;
                    listBranches.BackColor = SystemColors.Window;
                    break;

                case "Remote":
                    listBranches.Items.Clear();
                    foreach (var branch in branches.Remote)
                    {
                        listBranches.Items.Add(branch);
                    }
                    listBranches.Enabled   = true;
                    listBranches.BackColor = SystemColors.Window;
                    break;

                case "Tag":
                    listBranches.Items.Clear();
                    ExecResult result = App.Repos.Current.Run("tag");
                    if (result.Success())
                    {
                        string[] tags = result.stdout.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var tag in tags)
                        {
                            listBranches.Items.Add(tag);
                        }
                        listBranches.Enabled = true;
                    }
                    listBranches.BackColor = SystemColors.Window;
                    break;

                default:
                    break;
                }
            }
        }
Пример #19
0
 /// <summary>
 /// Callback that handles process completion event
 /// </summary>
 private void PComplete(ExecResult result)
 {
     _result = result;
     if (result.Success())
     {
         toolStripStatus.Text = "Git command completed successfully.";
         textStdout.AppendText("Git command completed successfully.", Color.Green);
     }
     else
     {
         toolStripStatus.Text = "Git command failed!";
         textStdout.AppendText("Git command failed!", Color.Red);
     }
     btCancel.Text = "Done";
     StopProgress();
 }
Пример #20
0
        public ExecResult Run(string args, bool async)
        {
            ExecResult output = new ExecResult();
            try
            {
                Directory.SetCurrentDirectory(Root);

                // Set the HTTPS password
                string password = Remotes.GetPassword("");
                ClassUtils.AddEnvar("PASSWORD", password);

                // The Windows limit to the command line argument length is about 8K
                // We may hit that limit when doing operations on a large number of files.
                //
                // However, when sending a long list of files, git was hanging unless
                // the total length was much less than that, so I set it to about 2000 chars
                // which seemed to work fine.

                if (args.Length < 2000)
                    return ClassGit.Run(args, async);

                // Partition the args into "[command] -- [set of file chunks < 2000 chars]"
                // Basically we have to rebuild the command into multiple instances with
                // same command but with file lists not larger than about 2K
                int i = args.IndexOf(" -- ") + 3;
                string cmd = args.Substring(0, i + 1);
                args = args.Substring(i);

                // Add files individually up to the length limit
                string[] files = args.Split(' ');
                i = 0;
                do
                {
                    StringBuilder batch = new StringBuilder(2100);
                    while (batch.Length < 2000 && i < files.Length)
                        batch.Append(files[i++] + " ");

                    output = ClassGit.Run(cmd + batch, async);
                    if (output.Success() == false)
                        break;
                } while (i < files.Length);
            }
            catch (Exception ex)
            {
                App.PrintLogMessage(ex.Message);
            }

            return output;
        }
Пример #21
0
        /// <summary>
        /// Given a Sha string, loads that commit into the form.
        /// </summary>
        public void LoadChangelist(string sha)
        {
            Tag = sha;      // Store the SHA of a current commit in the Tag field of this form

            // Issuing "show" command can take _very_ long time with a commit full of files
            // Run a much faster 'whatchanged' command first to get the list of files
            string     cmd    = "whatchanged " + sha + " -n 1 --format=medium";
            ExecResult result = App.Repos.Current.Run(cmd);

            string[] response = new[] { string.Empty };
            if (result.Success())
            {
                response = result.stdout.Split(new[] { cr }, StringSplitOptions.None);
            }

            // Go over the resulting list and add to our text box
            textChangelist.Text = "";       // Clear the rich text box

            // Get the list of lines that describe individual files vs the rest (checkin comment)
            List <string> files   = response.Where(s => s.StartsWith(":")).ToList();
            List <string> comment = response.Where(s => !s.StartsWith(":")).ToList();

            // ---------------- Print the comment section ----------------
            foreach (string s in comment)
            {
                textChangelist.AppendText(s + cr);
            }

            // ---------------- Print the files section ----------------
            textChangelist.AppendText(cr + "Files:" + cr + cr, Color.Red);

            foreach (string s in files)
            {
                // Parse the file name indicator following this template:
                // :100644 000000 ed81075... 0000000... D  file0
                // [attributes]   [prev]     [next]        [file]
                // 0       1      2          3          4                   (preamble[])
                // Starting with git 2.10, new output is added for copy-edit and rename-edit (https://git-scm.com/docs/git-diff-tree)
                // :100644 000000 ed81075... 0000000... C68 file1 file2     (copy-edit with a similarity "score")
                //                                         ^tab  ^tab

                string[] parts    = s.Split(new[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
                string[] preamble = parts[0].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                if ((parts.Length == 2 || parts.Length == 3) && preamble.Length == 5)
                {
                    // In the tag of the link, we will send file name and related SHA keys (stripped of ".")
                    string tag = string.Format("{0}#{1}#{2}", parts[1], preamble[2].Replace(".", ""), preamble[3].Replace(".", ""));
                    textChangelist.AppendText(s[37] + "\t");

                    if (parts.Length == 3) // Two files are listed
                    {
                        textChangelist.AppendText(parts[1] + " -> ");
                        textChangelist.InsertLink(parts[2], tag);
                    }
                    else
                    {
                        textChangelist.InsertLink(parts[1], tag);
                    }
                }
                else
                {
                    textChangelist.AppendText(s);
                }
                textChangelist.AppendText(cr);
            }

            // Now optionally run the detailed show command, but if the number of files is large,
            // ask the user to confirm for any more than, say, 30 files
            if (comboShow.SelectedIndex == 0)
            {
                return;
            }

            if (files.Count > 30)
            {
                string q =
                    "The number of files changed in this commit is very large and it may take considerable time" +
                    " to display their detailed difference. Do you still want to proceed?\n\n(To skip this message in the future, select " +
                    "(none) in the details option)";

                if (MessageBox.Show(q, "Detailed difference of " + files.Count + " files", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.No)
                {
                    return;
                }
            }

            cmd    = "show -t " + sha + " --format=" + comboShow.SelectedItem;
            result = App.Repos.Current.Run(cmd);
            if (result.Success())
            {
                response = result.stdout.Split(new[] { cr }, StringSplitOptions.None);
            }

            textChangelist.AppendText(cr + "Details" + cr + cr, Color.Red);

            // Write out the complete response text containing all files' differences
            foreach (string s in response)
            {
                textChangelist.SelectedText = s + cr;
            }

            textChangelist.Select(0, 0);
        }
Пример #22
0
 /// <summary>
 /// Callback that handles process completion event
 /// </summary>
 private void PComplete(ExecResult result)
 {
     textStdout.Cursor = Cursors.IBeam;  // Default cursor for the text box
     this.result = result;
     if (result.Success())
     {
         toolStripStatus.Text = "Git command completed successfully.";
         textStdout.AppendText("Git command completed successfully.", Color.Green);
         // On success, auto-close the dialog if the user's preference was checked
         // This behavior can be skipped if the user holds down the Control key
         if (Properties.Settings.Default.AutoCloseGitOnSuccess && Control.ModifierKeys != Keys.Control)
             DialogResult = DialogResult.OK;
     }
     else
     {
         toolStripStatus.Text = "Git command failed!";
         textStdout.AppendText("Git command failed!", Color.Red);
     }
     btCancel.Text = "Done";
     StopProgress();
 }
Пример #23
0
        /// <summary>
        /// Given a Sha string, loads that commit into the form.
        /// </summary>
        public void LoadChangelist(string sha)
        {
            Tag = sha;      // Store the SHA of a current commit in the Tag field of this form

            // Issuing "show" command can take _very_ long time with a commit full of files
            // Run a much faster 'whatchanged' command first to get the list of files
            string     cmd    = "whatchanged " + sha + " -n 1 --format=medium";
            ExecResult result = App.Repos.Current.Run(cmd);

            string[] response = new[] { string.Empty };
            if (result.Success())
            {
                response = result.stdout.Split(new[] { cr }, StringSplitOptions.None);
            }

            // Go over the resulting list and add to our text box
            textChangelist.Text = "";       // Clear the rich text box

            // Get the list of lines that describe individual files vs the rest (checkin comment)
            List <string> files   = response.Where(s => s.StartsWith(":")).ToList();
            List <string> comment = response.Where(s => !s.StartsWith(":")).ToList();

            // ---------------- Print the comment section ----------------
            foreach (string s in comment)
            {
                textChangelist.AppendText(s + cr);
            }

            // ---------------- Print the files section ----------------
            textChangelist.AppendText(cr + "Files:" + cr + cr, Color.Red);

            foreach (string s in files)
            {
                // Parse the file name indicator following this template:
                // :100644 000000 ed81075... 0000000... D  Build/Help.SED
                // [attributes]   [prev]     [next]        [file]           (meaning)
                // 0       1      2          3          4  5                (chunk)

                // We strip tabs and '.' characters which are part of SHA keys in the line
                string[] chunk = s.Replace('.', ' ').Split(new[] { ' ', '\t', '.' }, StringSplitOptions.RemoveEmptyEntries);

                if (s.Length >= 39)    // Hard-coded value! Depends on the git output.
                {
                    // In the tag of the link, we will send file name and related SHA keys
                    string tag = string.Format("{0}#{1}#{2}", s.Substring(39), chunk[2], chunk[3]);
                    textChangelist.AppendText(s.Substring(37, 2));
                    textChangelist.InsertLink(s.Substring(39), tag);
                    textChangelist.AppendText(cr);
                }
                else
                {
                    textChangelist.AppendText(s + cr);
                }
            }

            // Now optionally run the detailed show command, but if the number of files is large,
            // ask the user to confirm for any more than, say, 30 files
            if (comboShow.SelectedIndex == 0)
            {
                return;
            }

            if (files.Count > 30)
            {
                string q =
                    "The number of files changed in this commit is very large and it may take considerable time" +
                    " to display their detailed difference. Do you still want to proceed?\n\n(To skip this message in the future, select " +
                    "(none) in the details option)";

                if (MessageBox.Show(q, "Detailed difference of " + files.Count + " files", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.No)
                {
                    return;
                }
            }

            cmd    = "show -t " + sha + " --format=" + comboShow.SelectedItem;
            result = App.Repos.Current.Run(cmd);
            if (result.Success())
            {
                response = result.stdout.Split(new[] { cr }, StringSplitOptions.None);
            }

            textChangelist.AppendText(cr + "Details" + cr + cr, Color.Red);

            // Write out the complete response text containing all files' differences
            foreach (string s in response)
            {
                textChangelist.SelectedText = s + cr;
            }

            textChangelist.Select(0, 0);
        }