// Merges the fetched changes private void Rebase() { if (HasLocalChanges) { Add(); string commit_message = FormatCommitMessage(); Commit(commit_message); } SparkleGit git = new SparkleGit(LocalPath, "rebase FETCH_HEAD"); git.StartInfo.RedirectStandardOutput = false; git.Start(); git.WaitForExit(); if (git.ExitCode != 0) { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Conflict detected, trying to get out..."); while (HasLocalChanges) { ResolveConflict(); } SparkleHelpers.DebugInfo("Git", "[" + Name + "] Conflict resolved"); OnConflictResolved(); } }
private List <SparkleChange> ParseStatus() { List <SparkleChange> changes = new List <SparkleChange> (); SparkleGit git_status = new SparkleGit(LocalPath, "status --porcelain"); git_status.Start(); while (!git_status.StandardOutput.EndOfStream) { string line = git_status.StandardOutput.ReadLine(); line = line.Trim(); if (line.EndsWith(".empty") || line.EndsWith(".empty\"")) { line = line.Replace(".empty", ""); } SparkleChange change; if (line.StartsWith("R")) { string path = line.Substring(3, line.IndexOf(" -> ") - 3).Trim("\" ".ToCharArray()); string moved_to_path = line.Substring(line.IndexOf(" -> ") + 4).Trim("\" ".ToCharArray()); change = new SparkleChange() { Type = SparkleChangeType.Moved, Path = EnsureSpecialCharacters(path), MovedToPath = EnsureSpecialCharacters(moved_to_path) }; } else { string path = line.Substring(2).Trim("\" ".ToCharArray()); change = new SparkleChange() { Path = EnsureSpecialCharacters(path) }; change.Type = SparkleChangeType.Added; if (line.StartsWith("M")) { change.Type = SparkleChangeType.Edited; } else if (line.StartsWith("D")) { change.Type = SparkleChangeType.Deleted; } } changes.Add(change); } git_status.StandardOutput.ReadToEnd(); git_status.WaitForExit(); return(changes); }
// Creates a pretty commit message based on what has changed private string FormatCommitMessage() { int count = 0; string message = ""; SparkleGit git_status = new SparkleGit(LocalPath, "status --porcelain"); git_status.Start(); while (!git_status.StandardOutput.EndOfStream) { string line = git_status.StandardOutput.ReadLine(); if (line.EndsWith(".empty") || line.EndsWith(".empty\"")) { line = line.Replace(".empty", ""); } if (line.StartsWith("R")) { string path = line.Substring(3, line.IndexOf(" -> ") - 3).Trim("\"".ToCharArray()); string moved_to_path = line.Substring(line.IndexOf(" -> ") + 4).Trim("\"".ToCharArray()); message += "< ‘" + EnsureSpecialCharacters(path) + "’\n"; message += "> ‘" + EnsureSpecialCharacters(moved_to_path) + "’\n"; } else { if (line.StartsWith("M")) { message += "/"; } else if (line.StartsWith("D")) { message += "-"; } else { message += "+"; } string path = line.Substring(3).Trim("\"".ToCharArray()); message += " ‘" + EnsureSpecialCharacters(path) + "’\n"; } count++; if (count == 10) { message += "...\n"; break; } } git_status.StandardOutput.ReadToEnd(); git_status.WaitForExit(); return(message); }
// Stages the made changes private void Add() { SparkleGit git = new SparkleGit(LocalPath, "add --all"); git.Start(); git.WaitForExit(); SparkleHelpers.DebugInfo("Git", "[" + Name + "] Changes staged"); }
public override void RestoreFile(string path, string revision, string target_file_path) { if (path == null) { throw new ArgumentNullException("path"); } if (revision == null) { throw new ArgumentNullException("revision"); } SparkleLogger.LogInfo("Git", Name + " | Restoring \"" + path + "\" (revision " + revision + ")"); // FIXME: git-show doesn't decrypt objects, so we can't use it to retrieve // files from the index. This is a suboptimal workaround but it does the job if (this.is_encrypted) { // Restore the older file... SparkleGit git = new SparkleGit(LocalPath, "checkout " + revision + " \"" + path + "\""); git.StartAndWaitForExit(); string local_file_path = Path.Combine(LocalPath, path); // ...move it... try { File.Move(local_file_path, target_file_path); } catch { SparkleLogger.LogInfo("Git", Name + " | Could not move \"" + local_file_path + "\" to \"" + target_file_path + "\""); } // ...and restore the most recent revision git = new SparkleGit(LocalPath, "checkout " + CurrentRevision + " \"" + path + "\""); git.StartAndWaitForExit(); // The correct way } else { path = path.Replace("\"", "\\\""); SparkleGit git = new SparkleGit(LocalPath, "show " + revision + ":\"" + path + "\""); git.Start(); FileStream stream = File.OpenWrite(target_file_path); git.StandardOutput.BaseStream.CopyTo(stream); stream.Close(); git.WaitForExit(); } if (target_file_path.StartsWith(LocalPath)) { new Thread(() => OnFileActivity(null)).Start(); } }
public override bool IsFetchedRepoPasswordCorrect(string password) { string password_check_file_path = Path.Combine(TargetFolder, ".sparkleshare"); if (!File.Exists(password_check_file_path)) { SparkleGit git = new SparkleGit(TargetFolder, "show HEAD:.sparkleshare"); git.Start(); // Reading the standard output HAS to go before // WaitForExit, or it will hang forever on output > 4096 bytes string output = git.StandardOutput.ReadToEnd(); git.WaitForExit(); if (git.ExitCode != 0) { return(false); } else { File.WriteAllText(password_check_file_path, output); } } Process process = new Process() { EnableRaisingEvents = true }; process.StartInfo.WorkingDirectory = TargetFolder; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.CreateNoWindow = true; process.StartInfo.FileName = "openssl"; process.StartInfo.Arguments = "enc -d -aes-256-cbc -base64 -S " + this.crypto_salt + " -pass pass:\"" + password + "\" -in " + password_check_file_path; process.Start(); // Reading the standard output HAS to go before // WaitForExit, or it will hang forever on output > 4096 bytes process.StandardOutput.ReadToEnd(); process.WaitForExit(); if (process.ExitCode == 0) { File.Delete(password_check_file_path); return(true); } else { return(false); } }
// Commits the made changes private void Commit(string message) { SparkleGit git = new SparkleGit(LocalPath, "commit -m \"" + message + "\" " + "--author=\"" + SparkleConfig.DefaultConfig.User.Name + " <" + SparkleConfig.DefaultConfig.User.Email + ">\""); git.Start(); git.StandardOutput.ReadToEnd(); git.WaitForExit(); SparkleHelpers.DebugInfo("Commit", "[" + Name + "] " + message); }
public override void Complete() { if (IsFetchedRepoEmpty) { return; } SparkleGit git = new SparkleGit(TargetFolder, "checkout HEAD"); git.Start(); // Reading the standard output HAS to go before // WaitForExit, or it will hang forever on output > 4096 bytes git.StandardOutput.ReadToEnd(); git.WaitForExit(); }
public SparkleRepo(string path, SparkleConfig config) : base(path, config) { SparkleGit git = new SparkleGit(LocalPath, "config --get filter.bin.clean"); git.Start(); git.WaitForExit(); this.use_git_bin = (git.ExitCode == 0); string rebase_apply_path = new string [] { LocalPath, ".git", "rebase-apply" }.Combine(); if (Directory.Exists(rebase_apply_path)) { git = new SparkleGit(LocalPath, "rebase --abort"); git.StartAndWaitForExit(); } }
private void ResolveConflict() { // This is a list of conflict status codes that Git uses, their // meaning, and how SparkleShare should handle them. // // DD unmerged, both deleted -> Do nothing // AU unmerged, added by us -> Use theirs, save ours as a timestamped copy // UD unmerged, deleted by them -> Use ours // UA unmerged, added by them -> Use theirs, save ours as a timestamped copy // DU unmerged, deleted by us -> Use theirs // AA unmerged, both added -> Use theirs, save ours as a timestamped copy // UU unmerged, both modified -> Use theirs, save ours as a timestamped copy // ?? unmerged, new files -> Stage the new files // // Note that a rebase merge works by replaying each commit from the working branch on // top of the upstream branch. Because of this, when a merge conflict happens the // side reported as 'ours' is the so-far rebased series, starting with upstream, // and 'theirs' is the working branch. In other words, the sides are swapped. // // So: 'ours' means the 'server's version' and 'theirs' means the 'local version' SparkleGit git_status = new SparkleGit(LocalPath, "status --porcelain"); git_status.Start(); // Reading the standard output HAS to go before // WaitForExit, or it will hang forever on output > 4096 bytes string output = git_status.StandardOutput.ReadToEnd().TrimEnd(); git_status.WaitForExit(); string [] lines = output.Split("\n".ToCharArray()); foreach (string line in lines) { string conflicting_path = line.Substring(3); conflicting_path = conflicting_path.Trim("\"".ToCharArray()); SparkleHelpers.DebugInfo("Git", "[" + Name + "] Conflict type: " + line); // Both the local and server version have been modified if (line.StartsWith("UU") || line.StartsWith("AA") || line.StartsWith("AU") || line.StartsWith("UA")) { // Recover local version SparkleGit git_theirs = new SparkleGit(LocalPath, "checkout --theirs \"" + conflicting_path + "\""); git_theirs.Start(); git_theirs.WaitForExit(); // Append a timestamp to local version. // Windows doesn't allow colons in the file name, so // we use "h" between the hours and minutes instead. string timestamp = DateTime.Now.ToString("MMM d H\\hmm"); string their_path = Path.GetFileNameWithoutExtension(conflicting_path) + " (" + SparkleConfig.DefaultConfig.User.Name + ", " + timestamp + ")" + Path.GetExtension(conflicting_path); string abs_conflicting_path = Path.Combine(LocalPath, conflicting_path); string abs_their_path = Path.Combine(LocalPath, their_path); File.Move(abs_conflicting_path, abs_their_path); // Recover server version SparkleGit git_ours = new SparkleGit(LocalPath, "checkout --ours \"" + conflicting_path + "\""); git_ours.Start(); git_ours.WaitForExit(); Add(); SparkleGit git_rebase_continue = new SparkleGit(LocalPath, "rebase --continue"); git_rebase_continue.Start(); git_rebase_continue.WaitForExit(); // The local version has been modified, but the server version was removed } else if (line.StartsWith("DU")) { // The modified local version is already in the // checkout, so it just needs to be added. // // We need to specifically mention the file, so // we can't reuse the Add () method SparkleGit git_add = new SparkleGit(LocalPath, "add \"" + conflicting_path + "\""); git_add.Start(); git_add.WaitForExit(); SparkleGit git_rebase_continue = new SparkleGit(LocalPath, "rebase --continue"); git_rebase_continue.Start(); git_rebase_continue.WaitForExit(); // The server version has been modified, but the local version was removed } else if (line.StartsWith("UD")) { // We can just skip here, the server version is // already in the checkout SparkleGit git_rebase_skip = new SparkleGit(LocalPath, "rebase --skip"); git_rebase_skip.Start(); git_rebase_skip.WaitForExit(); // New local files } else { Add(); SparkleGit git_rebase_continue = new SparkleGit(LocalPath, "rebase --continue"); git_rebase_continue.Start(); git_rebase_continue.WaitForExit(); } } }
public override bool SyncDown() { SparkleGit git = new SparkleGit(LocalPath, "fetch --progress \"" + RemoteUrl + "\" master"); git.StartInfo.RedirectStandardError = true; git.Start(); double percentage = 1.0; Regex progress_regex = new Regex(@"([0-9]+)%", RegexOptions.Compiled); while (!git.StandardError.EndOfStream) { string line = git.StandardError.ReadLine(); Match match = progress_regex.Match(line); string speed = ""; double number = 0.0; if (match.Success) { number = double.Parse(match.Groups [1].Value); // The fetching progress consists of two stages: the "Compressing // objects" stage which we count as 20% of the total progress, and // the "Receiving objects" stage which we count as the last 80% if (line.StartsWith("Compressing")) { // "Compressing objects" stage number = (number / 100 * 20); } else { // "Writing objects" stage number = (number / 100 * 80 + 20); if (line.Contains("|")) { speed = line.Substring(line.IndexOf("|") + 1).Trim(); speed = speed.Replace(", done.", "").Trim(); speed = speed.Replace("i", ""); speed = speed.Replace("KB/s", "ᴋʙ/s"); speed = speed.Replace("MB/s", "ᴍʙ/s"); } } } else { SparkleHelpers.DebugInfo("Git", "[" + Name + "] " + line); } if (number >= percentage) { percentage = number; base.OnProgressChanged(percentage, speed); } } git.WaitForExit(); UpdateSizes(); if (git.ExitCode == 0) { Rebase(); File.SetAttributes( Path.Combine(LocalPath, ".sparkleshare"), FileAttributes.Hidden ); ChangeSets = GetChangeSets(); return(true); } else { ChangeSets = GetChangeSets(); return(false); } }
public override bool SyncUp() { if (HasLocalChanges) { Add(); string message = FormatCommitMessage(); Commit(message); } SparkleGit git = new SparkleGit(LocalPath, "push --progress " + // Redirects progress stats to standarderror "\"" + RemoteUrl + "\" master"); git.StartInfo.RedirectStandardError = true; git.Start(); double percentage = 1.0; Regex progress_regex = new Regex(@"([0-9]+)%", RegexOptions.Compiled); while (!git.StandardError.EndOfStream) { string line = git.StandardError.ReadLine(); Match match = progress_regex.Match(line); string speed = ""; double number = 0.0; if (match.Success) { number = double.Parse(match.Groups [1].Value); // The pushing progress consists of two stages: the "Compressing // objects" stage which we count as 20% of the total progress, and // the "Writing objects" stage which we count as the last 80% if (line.StartsWith("Compressing")) { // "Compressing objects" stage number = (number / 100 * 20); } else { if (line.StartsWith("ERROR: QUOTA EXCEEDED")) { int quota_limit = int.Parse(line.Substring(21).Trim()); throw new QuotaExceededException("Quota exceeded", quota_limit); } // "Writing objects" stage number = (number / 100 * 80 + 20); if (line.Contains("|")) { speed = line.Substring(line.IndexOf("|") + 1).Trim(); speed = speed.Replace(", done.", "").Trim(); speed = speed.Replace("i", ""); speed = speed.Replace("KB/s", "ᴋʙ/s"); speed = speed.Replace("MB/s", "ᴍʙ/s"); } } } else { SparkleHelpers.DebugInfo("Git", "[" + Name + "] " + line); } if (number >= percentage) { percentage = number; base.OnProgressChanged(percentage, speed); } } git.WaitForExit(); UpdateSizes(); ChangeSets = GetChangeSets(); if (git.ExitCode == 0) { return(true); } else { return(false); } }
public override bool SyncDown() { SparkleGit git = new SparkleGit(LocalPath, "fetch --progress \"" + RemoteUrl + "\" " + this.branch); git.StartInfo.RedirectStandardError = true; git.Start(); double percentage = 1.0; while (!git.StandardError.EndOfStream) { string line = git.StandardError.ReadLine(); Match match = this.progress_regex.Match(line); double speed = 0.0; double number = 0.0; if (match.Success) { number = double.Parse(match.Groups [1].Value); // The fetching progress consists of two stages: the "Compressing // objects" stage which we count as 20% of the total progress, and // the "Receiving objects" stage which we count as the last 80% if (line.StartsWith("Compressing")) { // "Compressing objects" stage number = (number / 100 * 20); } else { // "Writing objects" stage number = (number / 100 * 80 + 20); Match speed_match = this.speed_regex.Match(line); if (speed_match.Success) { speed = double.Parse(speed_match.Groups [1].Value) * 1024; if (speed_match.Groups [2].Value.Equals("M")) { speed = speed * 1024; } } } } else { SparkleLogger.LogInfo("Git", Name + " | " + line); if (FindError(line)) { return(false); } } if (number >= percentage) { percentage = number; base.OnProgressChanged(percentage, speed); } } git.WaitForExit(); UpdateSizes(); if (git.ExitCode == 0) { if (Rebase()) { ClearCache(); return(true); } else { return(false); } } else { Error = ErrorStatus.HostUnreachable; return(false); } }
public override bool SyncUp() { if (HasLocalChanges) { Add(); string message = FormatCommitMessage(); Commit(message); } SparkleGit git; if (this.use_git_bin) { SparkleGitBin git_bin = new SparkleGitBin(LocalPath, "push"); git_bin.StartAndWaitForExit(); // TODO: Progress } git = new SparkleGit(LocalPath, "push --progress \"" + RemoteUrl + "\" " + this.branch); git.StartInfo.RedirectStandardError = true; git.Start(); double percentage = 1.0; while (!git.StandardError.EndOfStream) { string line = git.StandardError.ReadLine(); Match match = this.progress_regex.Match(line); double speed = 0.0; double number = 0.0; if (match.Success) { number = double.Parse(match.Groups [1].Value); // The pushing progress consists of two stages: the "Compressing // objects" stage which we count as 20% of the total progress, and // the "Writing objects" stage which we count as the last 80% if (line.StartsWith("Compressing")) { // "Compressing objects" stage number = (number / 100 * 20); } else { // "Writing objects" stage number = (number / 100 * 80 + 20); Match speed_match = this.speed_regex.Match(line); if (speed_match.Success) { speed = double.Parse(speed_match.Groups [1].Value) * 1024; if (speed_match.Groups [2].Value.Equals("M")) { speed = speed * 1024; } } } } else { SparkleLogger.LogInfo("Git", Name + " | " + line); if (FindError(line)) { return(false); } } if (number >= percentage) { percentage = number; base.OnProgressChanged(percentage, speed); } } git.WaitForExit(); UpdateSizes(); if (git.ExitCode == 0) { ClearCache(); string salt_file_path = new string [] { LocalPath, ".git", "salt" }.Combine(); // If the repo is encrypted, create a branch to // store the salt in and push it to the host if (File.Exists(salt_file_path)) { string salt = File.ReadAllText(salt_file_path).Trim(); SparkleGit git_salt = new SparkleGit(LocalPath, "branch salt-" + salt); git_salt.StartAndWaitForExit(); git_salt = new SparkleGit(LocalPath, "push origin salt-" + salt); git_salt.StartAndWaitForExit(); File.Delete(salt_file_path); } return(true); } else { Error = ErrorStatus.HostUnreachable; return(false); } }
// Returns a list of the latest change sets public override List <SparkleChangeSet> GetChangeSets(int count) { if (count < 1) { count = 30; } count = 150; List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> (); SparkleGit git_log = new SparkleGit(LocalPath, "log -" + count + " --raw -M --date=iso --format=medium --no-color --no-merges"); git_log.Start(); // Reading the standard output HAS to go before // WaitForExit, or it will hang forever on output > 4096 bytes string output = git_log.StandardOutput.ReadToEnd(); git_log.WaitForExit(); string [] lines = output.Split("\n".ToCharArray()); List <string> entries = new List <string> (); int line_number = 0; bool first_pass = true; string entry = "", last_entry = ""; foreach (string line in lines) { if (line.StartsWith("commit") && !first_pass) { entries.Add(entry); entry = ""; line_number = 0; } else { first_pass = false; } // Only parse 250 files to prevent memory issues if (line_number < 254) { entry += line + "\n"; line_number++; } last_entry = entry; } entries.Add(last_entry); Regex merge_regex = new Regex(@"commit ([a-z0-9]{40})\n" + "Merge: .+ .+\n" + "Author: (.+) <(.+)>\n" + "Date: ([0-9]{4})-([0-9]{2})-([0-9]{2}) " + "([0-9]{2}):([0-9]{2}):([0-9]{2}) .([0-9]{4})\n" + "*", RegexOptions.Compiled); Regex non_merge_regex = new Regex(@"commit ([a-z0-9]{40})\n" + "Author: (.+) <(.+)>\n" + "Date: ([0-9]{4})-([0-9]{2})-([0-9]{2}) " + "([0-9]{2}):([0-9]{2}):([0-9]{2}) (.[0-9]{4})\n" + "*", RegexOptions.Compiled); foreach (string log_entry in entries) { Regex regex; bool is_merge_commit = false; if (log_entry.Contains("\nMerge: ")) { regex = merge_regex; is_merge_commit = true; } else { regex = non_merge_regex; } Match match = regex.Match(log_entry); if (match.Success) { SparkleChangeSet change_set = new SparkleChangeSet(); change_set.Folder = new SparkleFolder(Name); change_set.Revision = match.Groups [1].Value; change_set.User = new SparkleUser(match.Groups [2].Value, match.Groups [3].Value); change_set.IsMagical = is_merge_commit; change_set.RemoteUrl = RemoteUrl; change_set.Timestamp = new DateTime(int.Parse(match.Groups [4].Value), int.Parse(match.Groups [5].Value), int.Parse(match.Groups [6].Value), int.Parse(match.Groups [7].Value), int.Parse(match.Groups [8].Value), int.Parse(match.Groups [9].Value)); string time_zone = match.Groups [10].Value; int our_offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Hours; int their_offset = int.Parse(time_zone.Substring(0, 3)); change_set.Timestamp = change_set.Timestamp.AddHours(their_offset * -1); change_set.Timestamp = change_set.Timestamp.AddHours(our_offset); string [] entry_lines = log_entry.Split("\n".ToCharArray()); foreach (string entry_line in entry_lines) { if (entry_line.StartsWith(":")) { string change_type = entry_line [37].ToString(); string file_path = entry_line.Substring(39); string to_file_path; if (file_path.EndsWith(".empty")) { file_path = file_path.Substring(0, file_path.Length - ".empty".Length); } if (file_path.Equals(".sparkleshare")) { continue; } if (change_type.Equals("A")) { change_set.Changes.Add( new SparkleChange() { Path = file_path, Timestamp = change_set.Timestamp, Type = SparkleChangeType.Added } ); } else if (change_type.Equals("M")) { change_set.Changes.Add( new SparkleChange() { Path = file_path, Timestamp = change_set.Timestamp, Type = SparkleChangeType.Edited } ); } else if (change_type.Equals("D")) { change_set.Changes.Add( new SparkleChange() { Path = file_path, Timestamp = change_set.Timestamp, Type = SparkleChangeType.Deleted } ); } else if (change_type.Equals("R")) { int tab_pos = entry_line.LastIndexOf("\t"); file_path = entry_line.Substring(42, tab_pos - 42); to_file_path = entry_line.Substring(tab_pos + 1); if (file_path.EndsWith(".empty")) { file_path = file_path.Substring(0, file_path.Length - 6); } if (to_file_path.EndsWith(".empty")) { to_file_path = to_file_path.Substring(0, to_file_path.Length - 6); } change_set.Changes.Add( new SparkleChange() { Path = file_path, MovedPath = to_file_path, Timestamp = change_set.Timestamp, Type = SparkleChangeType.Moved } ); } } } if (change_set.Changes.Count > 0) { if (change_sets.Count > 0) { SparkleChangeSet last_change_set = change_sets [change_sets.Count - 1]; if (change_set.Timestamp.Year == last_change_set.Timestamp.Year && change_set.Timestamp.Month == last_change_set.Timestamp.Month && change_set.Timestamp.Day == last_change_set.Timestamp.Day && change_set.User.Name.Equals(last_change_set.User.Name)) { last_change_set.Changes.AddRange(change_set.Changes); if (DateTime.Compare(last_change_set.Timestamp, change_set.Timestamp) < 1) { last_change_set.FirstTimestamp = last_change_set.Timestamp; last_change_set.Timestamp = change_set.Timestamp; last_change_set.Revision = change_set.Revision; } else { last_change_set.FirstTimestamp = change_set.Timestamp; } } else { change_sets.Add(change_set); } } else { change_sets.Add(change_set); } } } } return(change_sets); }
// Creates a pretty commit message based on what has changed private string FormatCommitMessage() { List <string> Added = new List <string> (); List <string> Modified = new List <string> (); List <string> Removed = new List <string> (); string file_name = ""; string message = ""; SparkleGit git_status = new SparkleGit(LocalPath, "status --porcelain"); git_status.Start(); // Reading the standard output HAS to go before // WaitForExit, or it will hang forever on output > 4096 bytes string output = git_status.StandardOutput.ReadToEnd().Trim("\n".ToCharArray()); git_status.WaitForExit(); string [] lines = output.Split("\n".ToCharArray()); foreach (string line in lines) { if (line.StartsWith("A")) { Added.Add(line.Substring(3)); } else if (line.StartsWith("M")) { Modified.Add(line.Substring(3)); } else if (line.StartsWith("D")) { Removed.Add(line.Substring(3)); } else if (line.StartsWith("R")) { Removed.Add(line.Substring(3, (line.IndexOf(" -> ") - 3))); Added.Add(line.Substring(line.IndexOf(" -> ") + 4)); } } int count = 0; int max_count = 20; string n = Environment.NewLine; foreach (string added in Added) { file_name = added.Trim("\"".ToCharArray()); if (file_name.EndsWith(".empty")) { file_name = file_name.Substring(0, file_name.Length - 6); } message += "+ ‘" + file_name + "’" + n; count++; if (count == max_count) { return(message + "..."); } } foreach (string modified in Modified) { file_name = modified.Trim("\"".ToCharArray()); if (file_name.EndsWith(".empty")) { continue; } message += "/ ‘" + file_name + "’" + n; count++; if (count == max_count) { return(message + "..."); } } foreach (string removed in Removed) { file_name = removed.Trim("\"".ToCharArray()); if (file_name.EndsWith(".empty")) { file_name = file_name.Substring(0, file_name.Length - 6); } message += "- ‘" + file_name + "’" + n; count++; if (count == max_count) { return(message + "..." + n); } } message = message.Replace("\"", ""); return(message.TrimEnd()); }
public override bool SyncUp() { if (HasLocalChanges) { Add(); string message = FormatCommitMessage(); Commit(message); } SparkleGit git; if (this.use_git_bin) { SparkleGitBin git_bin = new SparkleGitBin(LocalPath, "push"); git_bin.StartAndWaitForExit(); // TODO: Progress } git = new SparkleGit(LocalPath, "push --progress " + // Redirects progress stats to standarderror "\"" + RemoteUrl + "\" master"); git.StartInfo.RedirectStandardError = true; git.Start(); double percentage = 1.0; Regex progress_regex = new Regex(@"([0-9]+)%", RegexOptions.Compiled); while (!git.StandardError.EndOfStream) { string line = git.StandardError.ReadLine(); Match match = progress_regex.Match(line); string speed = ""; double number = 0.0; if (match.Success) { number = double.Parse(match.Groups [1].Value); // The pushing progress consists of two stages: the "Compressing // objects" stage which we count as 20% of the total progress, and // the "Writing objects" stage which we count as the last 80% if (line.StartsWith("Compressing")) { // "Compressing objects" stage number = (number / 100 * 20); } else { // "Writing objects" stage number = (number / 100 * 80 + 20); if (line.Contains("|")) { speed = line.Substring(line.IndexOf("|") + 1).Trim(); speed = speed.Replace(", done.", "").Trim(); speed = speed.Replace("i", ""); speed = speed.Replace("KB/s", "ᴋʙ/s"); speed = speed.Replace("MB/s", "ᴍʙ/s"); } } } else { SparkleLogger.LogInfo("Git", Name + " | " + line); if (FindError(line)) { return(false); } } if (number >= percentage) { percentage = number; base.OnProgressChanged(percentage, speed); } } git.WaitForExit(); UpdateSizes(); if (git.ExitCode == 0) { ClearCache(); return(true); } else { Error = ErrorStatus.HostUnreachable; return(false); } }