Example #1
0
        private string FormatMessage(SparkleChangeSet change_set)
        {
            string message = "added ‘{0}’";

            switch (change_set.Changes [0].Type)
            {
            case SparkleChangeType.Edited:  message = "edited ‘{0}’"; break;

            case SparkleChangeType.Deleted: message = "deleted ‘{0}’"; break;

            case SparkleChangeType.Moved:   message = "moved ‘{0}’"; break;
            }

            if (change_set.Changes.Count == 1)
            {
                return(message = string.Format(message, change_set.Changes [0].Path));
            }
            else if (change_set.Changes.Count > 1)
            {
                message = string.Format(message, change_set.Changes [0].Path);
                return(string.Format(message + " and {0} more", change_set.Changes.Count - 1));
            }
            else
            {
                return("did something magical");
            }
        }
        private string FormatMessage(SparkleChangeSet change_set)
        {
            string file_name = "";
            string message   = "";

            if (change_set.Added.Count > 0)
            {
                file_name = change_set.Added [0];
                message   = String.Format("added ‘{0}’", file_name);
            }

            if (change_set.MovedFrom.Count > 0)
            {
                file_name = change_set.MovedFrom [0];
                message   = String.Format("moved ‘{0}’", file_name);
            }

            if (change_set.Edited.Count > 0)
            {
                file_name = change_set.Edited [0];
                message   = String.Format("edited ‘{0}’", file_name);
            }

            if (change_set.Deleted.Count > 0)
            {
                file_name = change_set.Deleted [0];
                message   = String.Format("deleted ‘{0}’", file_name);
            }

            int changes_count = (change_set.Added.Count +
                                 change_set.Edited.Count +
                                 change_set.Deleted.Count +
                                 change_set.MovedFrom.Count) - 1;

            if (changes_count > 0)
            {
                string msg = string.Format("and {0} more", changes_count);
                message += " " + String.Format(msg, changes_count);
            }
            else if (changes_count < 0)
            {
                message += "did something magical";
            }

            return(message);
        }
        private string FormatMessage(SparkleChangeSet change_set)
        {
            string message = "";

            if (change_set.Changes [0].Type == SparkleChangeType.Deleted)
            {
                message = string.Format("moved ‘{0}’", change_set.Changes [0].Path);
            }

            if (change_set.Changes [0].Type == SparkleChangeType.Moved)
            {
                message = string.Format("moved ‘{0}’", change_set.Changes [0].Path);
            }

            if (change_set.Changes [0].Type == SparkleChangeType.Added)
            {
                message = string.Format("added ‘{0}’", change_set.Changes [0].Path);
            }

            if (change_set.Changes [0].Type == SparkleChangeType.Edited)
            {
                message = string.Format("moved ‘{0}’", change_set.Changes [0].Path);
            }

            if (change_set.Changes.Count > 0)
            {
                string msg = string.Format("and {0} more", change_set.Changes.Count);
                message = message + " " + string.Format(msg, change_set.Changes.Count);
            }
            else
            {
                message = "did something magical";
            }

            return(message);
        }
Example #4
0
        // 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);
        }
Example #5
0
        private List <SparkleChangeSet> GetChangeSetsInternal(string path)
        {
            List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> ();
            SparkleGit git;

            if (path == null)
            {
                git = new SparkleGit(LocalPath, "log --since=1.month --raw --find-renames --date=iso " +
                                     "--format=medium --no-color --no-merges");
            }
            else
            {
                path = path.Replace("\\", "/");

                git = new SparkleGit(LocalPath, "log --raw --find-renames --date=iso " +
                                     "--format=medium --no-color --no-merges -- \"" + path + "\"");
            }

            string output = git.StartAndReadStandardOutput();

            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);


            foreach (string log_entry in entries)
            {
                Match match = this.log_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.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 type_letter      = entry_line [37].ToString();
                            string file_path        = entry_line.Substring(39);
                            bool   change_is_folder = false;

                            if (file_path.Equals(".sparkleshare"))
                            {
                                continue;
                            }

                            if (file_path.EndsWith(".empty"))
                            {
                                file_path        = file_path.Substring(0, file_path.Length - ".empty".Length);
                                change_is_folder = true;
                            }

                            file_path = EnsureSpecialCharacters(file_path);
                            file_path = file_path.Replace("\\\"", "\"");

                            if (type_letter.Equals("R"))
                            {
                                int tab_pos = entry_line.LastIndexOf("\t");
                                file_path = entry_line.Substring(42, tab_pos - 42);
                                string to_file_path = entry_line.Substring(tab_pos + 1);

                                file_path    = EnsureSpecialCharacters(file_path);
                                to_file_path = EnsureSpecialCharacters(to_file_path);

                                file_path    = file_path.Replace("\\\"", "\"");
                                to_file_path = to_file_path.Replace("\\\"", "\"");

                                if (file_path.EndsWith(".empty"))
                                {
                                    file_path        = file_path.Substring(0, file_path.Length - 6);
                                    change_is_folder = true;
                                }

                                if (to_file_path.EndsWith(".empty"))
                                {
                                    to_file_path     = to_file_path.Substring(0, to_file_path.Length - 6);
                                    change_is_folder = true;
                                }

                                change_set.Changes.Add(
                                    new SparkleChange()
                                {
                                    Path        = file_path,
                                    IsFolder    = change_is_folder,
                                    MovedToPath = to_file_path,
                                    Timestamp   = change_set.Timestamp,
                                    Type        = SparkleChangeType.Moved
                                }
                                    );
                            }
                            else
                            {
                                SparkleChangeType change_type = SparkleChangeType.Added;

                                if (type_letter.Equals("M"))
                                {
                                    change_type = SparkleChangeType.Edited;
                                }
                                else if (type_letter.Equals("D"))
                                {
                                    change_type = SparkleChangeType.Deleted;
                                }

                                change_set.Changes.Add(
                                    new SparkleChange()
                                {
                                    Path      = file_path,
                                    IsFolder  = change_is_folder,
                                    Timestamp = change_set.Timestamp,
                                    Type      = change_type
                                }
                                    );
                            }
                        }
                    }

                    if (change_sets.Count > 0 && path == null)
                    {
                        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
                    {
                        if (path != null)
                        {
                            bool skip_change_set = false;;

                            foreach (SparkleChange change in change_set.Changes)
                            {
                                if ((change.Type == SparkleChangeType.Deleted ||
                                     change.Type == SparkleChangeType.Moved) && change.Path.Equals(path))
                                {
                                    skip_change_set = true;
                                }
                            }

                            if (skip_change_set)
                            {
                                continue;
                            }
                        }

                        change_sets.Add(change_set);
                    }
                }
            }

            return(change_sets);
        }
        private List <SparkleChangeSet> GetChangeSetsInternal(string path)
        {
            List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> ();
            SparkleGit git;

            if (path == null)
            {
                git = new SparkleGit(LocalPath, "log --since=1.month --raw --find-renames --date=iso " +
                                     "--format=medium --no-color -m --first-parent");
            }
            else
            {
                path = path.Replace("\\", "/");

                git = new SparkleGit(LocalPath, "log --raw --find-renames --date=iso " +
                                     "--format=medium --no-color --no-merges -- \"" + path + "\"");
            }

            string output = git.StartAndReadStandardOutput();

            if (path == null && string.IsNullOrWhiteSpace(output))
            {
                git = new SparkleGit(LocalPath, "log -n 75 --raw --find-renames --date=iso " +
                                     "--format=medium --no-color -m --first-parent");

                output = git.StartAndReadStandardOutput();
            }

            string []     lines   = output.Split("\n".ToCharArray());
            List <string> entries = new List <string> ();

            // Split up commit entries
            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 first 250 files to prevent memory issues
                if (line_number < 250)
                {
                    entry += line + "\n";
                    line_number++;
                }

                last_entry = entry;
            }

            entries.Add(last_entry);

            // Parse commit entries
            foreach (string log_entry in entries)
            {
                Match match = this.log_regex.Match(log_entry);

                if (!match.Success)
                {
                    match = this.merge_regex.Match(log_entry);

                    if (!match.Success)
                    {
                        continue;
                    }
                }

                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.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());

                // Parse file list. Lines containing file changes start with ":"
                foreach (string entry_line in entry_lines)
                {
                    // Skip lines containing backspace characters
                    if (!entry_line.StartsWith(":") || entry_line.Contains("\\177"))
                    {
                        continue;
                    }

                    string file_path = entry_line.Substring(39);

                    if (file_path.Equals(".sparkleshare"))
                    {
                        continue;
                    }

                    string type_letter      = entry_line [37].ToString();
                    bool   change_is_folder = false;

                    if (file_path.EndsWith(".empty"))
                    {
                        file_path        = file_path.Substring(0, file_path.Length - ".empty".Length);
                        change_is_folder = true;
                    }

                    try {
                        file_path = EnsureSpecialCharacters(file_path);
                    } catch (Exception e) {
                        SparkleLogger.LogInfo("Local", "Error parsing file name '" + file_path + "'", e);
                        continue;
                    }

                    file_path = file_path.Replace("\\\"", "\"");

                    SparkleChange change = new SparkleChange()
                    {
                        Path      = file_path,
                        IsFolder  = change_is_folder,
                        Timestamp = change_set.Timestamp,
                        Type      = SparkleChangeType.Added
                    };

                    if (type_letter.Equals("R"))
                    {
                        int tab_pos = entry_line.LastIndexOf("\t");
                        file_path = entry_line.Substring(42, tab_pos - 42);
                        string to_file_path = entry_line.Substring(tab_pos + 1);

                        try {
                            file_path = EnsureSpecialCharacters(file_path);
                        } catch (Exception e) {
                            SparkleLogger.LogInfo("Local", "Error parsing file name '" + file_path + "'", e);
                            continue;
                        }

                        try {
                            to_file_path = EnsureSpecialCharacters(to_file_path);
                        } catch (Exception e) {
                            SparkleLogger.LogInfo("Local", "Error parsing file name '" + to_file_path + "'", e);
                            continue;
                        }

                        file_path    = file_path.Replace("\\\"", "\"");
                        to_file_path = to_file_path.Replace("\\\"", "\"");

                        if (file_path.EndsWith(".empty"))
                        {
                            file_path        = file_path.Substring(0, file_path.Length - 6);
                            change_is_folder = true;
                        }

                        if (to_file_path.EndsWith(".empty"))
                        {
                            to_file_path     = to_file_path.Substring(0, to_file_path.Length - 6);
                            change_is_folder = true;
                        }

                        change.Path        = file_path;
                        change.MovedToPath = to_file_path;
                        change.Type        = SparkleChangeType.Moved;
                    }
                    else if (type_letter.Equals("M"))
                    {
                        change.Type = SparkleChangeType.Edited;
                    }
                    else if (type_letter.Equals("D"))
                    {
                        change.Type = SparkleChangeType.Deleted;
                    }

                    change_set.Changes.Add(change);
                }

                // Group commits per user, per day
                if (change_sets.Count > 0 && path == null)
                {
                    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
                {
                    // Don't show removals or moves in the revision list of a file
                    if (path != null)
                    {
                        List <SparkleChange> changes_to_skip = new List <SparkleChange> ();

                        foreach (SparkleChange change in change_set.Changes)
                        {
                            if ((change.Type == SparkleChangeType.Deleted || change.Type == SparkleChangeType.Moved) &&
                                change.Path.Equals(path))
                            {
                                changes_to_skip.Add(change);
                            }
                        }

                        foreach (SparkleChange change_to_skip in changes_to_skip)
                        {
                            change_set.Changes.Remove(change_to_skip);
                        }
                    }

                    change_sets.Add(change_set);
                }
            }

            return(change_sets);
        }
Example #7
0
        // Returns a list of the latest change sets
        public override List<SparkleChangeSet> GetChangeSets(int count)
        {
            if (count < 1)
                count = 30;

            List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> ();

            // Console.InputEncoding  = System.Text.Encoding.Unicode;
            Console.OutputEncoding = System.Text.Encoding.Unicode;

            SparkleGut gut_log = new SparkleGut (LocalPath, "get-change-sets --count=" + count);
            gut_log.Start ();

            // Reading the standard output HAS to go before
            // WaitForExit, or it will hang forever on output > 4096 bytes
            string output = gut_log.StandardOutput.ReadToEnd ();
            string [] lines = output.Split ("\n".ToCharArray ());
            gut_log.WaitForExit ();

            SparkleChangeSet change_set = null;
            foreach (string line in lines) {
                if (line.StartsWith ("revision")) {
                    change_set = new SparkleChangeSet ();
                    change_set.Folder = Name;
                    change_set.Url = Url;
                    change_sets.Add (change_set);
                }
                if(change_set == null)
                    continue;

                string[] kv = line.Split (":".ToCharArray (), 2);
                if(kv.Length != 2)
                    continue;

                string key = kv[0];
                string val = kv[1];

                if(key.Equals("revision")) {
                    change_set.Revision = val;
                }
                if(key.Equals("user")) {
                    Regex regex = new Regex (@"(.+) <(.+)>");
                    Match match = regex.Match (val);
                    change_set.User = new SparkleUser (match.Groups [1].Value, match.Groups [2].Value);
                }
                if(key.Equals("magical")) {
                    change_set.IsMagical = val.Equals("true");
                }
                if(key.Equals("timestamp")) {
                    Regex regex = new Regex (@"([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) (.[0-9]{4})");
                    Match match = regex.Match (val);
                    change_set.Timestamp = new DateTime (int.Parse (match.Groups [1].Value),
                        int.Parse (match.Groups [2].Value), int.Parse (match.Groups [3].Value),
                        int.Parse (match.Groups [4].Value), int.Parse (match.Groups [5].Value),
                        int.Parse (match.Groups [6].Value));
                    string time_zone     = match.Groups [7].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);
                }
                if(key.Equals("added")) {
                    change_set.Added.Add(val);
                }
                if(key.Equals("edited")) {
                    change_set.Edited.Add(val);
                }
                if(key.Equals("deleted")) {
                    change_set.Deleted.Add(val);
                }
            }

            return change_sets;
        }