PageRenderTime 29ms CodeModel.GetById 17ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/SparkleLib/Hg/SparkleRepoHg.cs

http://github.com/hbons/SparkleShare
C# | 319 lines | 213 code | 84 blank | 22 comment | 26 complexity | dd090276f739aa789e45ca90baabcb94 MD5 | raw file
  1//   SparkleShare, a collaboration and sharing tool.
  2//   Copyright (C) 2010  Hylke Bons <hylkebons@gmail.com>
  3//
  4//   This program is free software: you can redistribute it and/or modify
  5//   it under the terms of the GNU General Public License as published by
  6//   the Free Software Foundation, either version 3 of the License, or
  7//   (at your option) any later version.
  8//
  9//   This program is distributed in the hope that it will be useful,
 10//   but WITHOUT ANY WARRANTY; without even the implied warranty of
 11//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 12//   GNU General Public License for more details.
 13//
 14//   You should have received a copy of the GNU General Public License
 15//   along with this program. If not, see <http://www.gnu.org/licenses/>.
 16
 17
 18using System;
 19using System.Collections.Generic;
 20using System.Diagnostics;
 21using System.IO;
 22using System.Text.RegularExpressions;
 23
 24namespace SparkleLib {
 25
 26    public class SparkleRepoHg : SparkleRepoBase {
 27
 28        public SparkleRepoHg (string path, SparkleBackend backend) :
 29            base (path, backend) { }
 30
 31
 32        public override string Identifier {
 33            get {
 34                SparkleHg hg = new SparkleHg (LocalPath, "log -r : --limit 1 --template \"{node}\"");
 35                hg.Start ();
 36                hg.WaitForExit ();
 37
 38                return hg.StandardOutput.ReadToEnd ();
 39            }
 40        }
 41
 42
 43        public override string CurrentRevision {
 44            get {
 45                SparkleHg hg = new SparkleHg (LocalPath, "log --limit 1 --template \"{node}\"");
 46                hg.Start ();
 47                hg.WaitForExit ();
 48
 49		string hash = hg.StandardOutput.ReadToEnd ().Trim ();
 50                if (hash.Length > 0)
 51                    return hash;
 52                else
 53                    return null;
 54            }
 55        }
 56
 57
 58        public override bool CheckForRemoteChanges ()
 59        {
 60            return true; // Mercurial doesn't have a way to check for the remote hash
 61        }
 62
 63
 64        public override bool SyncUp ()
 65        {
 66            Add ();
 67
 68            string message = FormatCommitMessage ();
 69            Commit (message);
 70
 71            SparkleHg hg = new SparkleHg (LocalPath, "push");
 72
 73            hg.Start ();
 74            hg.WaitForExit ();
 75
 76            if (hg.ExitCode == 0) {
 77                return true;
 78            } else {
 79                return false;
 80            }
 81        }
 82
 83
 84        public override bool SyncDown ()
 85        {
 86            SparkleHg hg = new SparkleHg (LocalPath, "pull");
 87
 88            hg.Start ();
 89            hg.WaitForExit ();
 90
 91            if (hg.ExitCode == 0) {
 92                Merge ();
 93                return true;
 94            } else {
 95                return false;
 96            }
 97        }
 98
 99
100        public override bool AnyDifferences {
101            get {
102                SparkleHg hg = new SparkleHg (LocalPath, "status");
103                hg.Start ();
104                hg.WaitForExit ();
105
106                string output = hg.StandardOutput.ReadToEnd ().TrimEnd ();
107                string [] lines = output.Split ("\n".ToCharArray ());
108
109                foreach (string line in lines) {
110                    if (line.Length > 1 && !line [1].Equals (" "))
111                        return true;
112                }
113
114                return false;
115            }
116        }
117
118
119        public override bool HasUnsyncedChanges {
120            get {
121                string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath,
122                    ".hg", "has_unsynced_changes");
123
124                return File.Exists (unsynced_file_path);
125            }
126
127            set {
128                string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath,
129                    ".hg", "has_unsynced_changes");
130
131                if (value) {
132                    if (!File.Exists (unsynced_file_path))
133                        File.Create (unsynced_file_path).Close ();
134                } else {
135                    File.Delete (unsynced_file_path);
136                }
137            }
138        }
139
140
141        // Stages the made changes
142        private void Add ()
143        {
144            SparkleHg hg = new SparkleHg (LocalPath, "addremove --quiet");
145            hg.Start ();
146            hg.WaitForExit ();
147
148            SparkleHelpers.DebugInfo ("Hg", "[" + Name + "] Changes staged");
149        }
150
151
152        // Commits the made changes
153        private void Commit (string message)
154        {
155            if (!AnyDifferences)
156                return;
157
158            SparkleHg hg = new SparkleHg (LocalPath, "commit -m '" + message + "'");
159            hg.Start ();
160            hg.WaitForExit ();
161
162            SparkleHelpers.DebugInfo ("Commit", "[" + Name + "] " + message);
163        }
164
165
166        // Merges the fetched changes
167        private void Merge ()
168        {
169            DisableWatching ();
170
171            if (AnyDifferences) {
172                Add ();
173
174                string commit_message = FormatCommitMessage ();
175                Commit (commit_message);
176            }
177
178            SparkleHg hg = new SparkleHg (LocalPath, "update");
179
180            hg.Start ();
181            hg.WaitForExit ();
182
183            EnableWatching ();
184        }
185
186
187        // Returns a list of the latest change sets
188        public override List<SparkleChangeSet> GetChangeSets (int count)
189        {
190            if (count < 1)
191                count = 30;
192
193            List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> ();
194
195            SparkleHg hg_log = new SparkleHg (LocalPath, "log --limit " + count + " --style changelog --verbose --stat");
196            Console.OutputEncoding = System.Text.Encoding.Unicode;
197            hg_log.Start ();
198
199            // Reading the standard output HAS to go before
200            // WaitForExit, or it will hang forever on output > 4096 bytes
201            string output = hg_log.StandardOutput.ReadToEnd ();
202            hg_log.WaitForExit ();
203
204            string [] lines       = output.Split ("\n".ToCharArray ());
205            List <string> entries = new List <string> ();
206
207            int j = 0;
208            string entry = "", last_entry = "";
209            foreach (string line in lines) {
210                if (line.StartsWith ("2") && line.EndsWith (")") && j > 0) {
211                    entries.Add (entry);
212                    entry = "";
213                }
214
215                entry += line + "\n";
216                j++;
217
218                last_entry = entry;
219            }
220
221            entries.Add (last_entry);
222
223            Regex regex = new Regex (@"([0-9]{4})-([0-9]{2})-([0-9]{2}).*([0-9]{2}):([0-9]{2}).*.([0-9]{4})" +
224                                      "(.+)<(.+)>.*.([a-z0-9]{12})", RegexOptions.Compiled);
225
226            foreach (string log_entry in entries) {
227
228                bool is_merge_commit = false;
229
230                Match match = regex.Match (log_entry);
231
232                if (!match.Success)
233                    continue;
234
235                SparkleChangeSet change_set = new SparkleChangeSet () {
236                    Revision  = match.Groups [9].Value,
237                    IsMagical   = is_merge_commit
238                };
239
240                change_set.User.Name  = match.Groups [7].Value.Trim ();
241                change_set.User.Email = match.Groups [8].Value;
242
243
244                change_set.Timestamp = new DateTime (int.Parse (match.Groups [1].Value),
245                    int.Parse (match.Groups [2].Value), int.Parse (match.Groups [3].Value),
246                    int.Parse (match.Groups [4].Value), int.Parse (match.Groups [5].Value), 0);
247
248                string [] entry_lines = log_entry.Split ("\n".ToCharArray ());
249
250                foreach (string entry_line in entry_lines) {
251                    if (!entry_line.StartsWith ("\t* "))
252                        continue;
253
254                    if (entry_line.EndsWith ("new file.")) {
255                        string files = entry_line.Substring (3, entry_line.Length - 13);
256                        string [] added_files = files.Split (",".ToCharArray ());
257
258                        foreach (string added_file in added_files) {
259                            string file = added_file.TrimEnd (": ".ToCharArray ());
260                            change_set.Added.Add (file);
261                        }
262
263                    } else if (entry_line.EndsWith ("deleted file.")) {
264                        string files = entry_line.Substring (3, entry_line.Length - 17);
265                        string [] deleted_files = files.Split (",".ToCharArray ());
266
267                        foreach (string deleted_file in deleted_files) {
268                            string file = deleted_file.TrimEnd (": ".ToCharArray ());
269                            change_set.Deleted.Add (file);
270                        }
271
272                    } else if (!"".Equals (entry_line.Trim ())){
273                        string files = entry_line.Substring (3);
274                        files = files.TrimEnd (":".ToCharArray());
275                        string [] edited_files = files.Split (",".ToCharArray ());
276
277                        foreach (string edited_file in edited_files) {
278                            if (!change_set.Added.Contains (edited_file) &&
279                                !change_set.Deleted.Contains (edited_file)) {
280
281                                change_set.Edited.Add (edited_file);
282                            }
283                        }
284                    }
285                }
286
287                change_sets.Add (change_set);
288            }
289
290            return change_sets;
291        }
292
293
294        // Creates a pretty commit message based on what has changed
295        private string FormatCommitMessage () // TODO
296        {
297            return "SparkleShare Hg";
298        }
299
300
301        public override void CreateInitialChangeSet ()
302        {
303            base.CreateInitialChangeSet ();
304            Add ();
305
306            string message = FormatCommitMessage ();
307            Commit (message);
308        }
309
310
311        public override bool UsesNotificationCenter
312        {
313            get {
314                string file_path = SparkleHelpers.CombineMore (LocalPath, ".hg", "disable_notification_center");
315                return !File.Exists (file_path);
316            }
317        }
318    }
319}