コード例 #1
0
ファイル: SvnExporter.cs プロジェクト: mathewng/vss2svn
        private bool ReplayChangeset(VssPathMapper pathMapper, Changeset changeset,
                                     SvnWrapper svn, LinkedList <Revision> labels)
        {
            var needCommit = false;

            foreach (Revision revision in changeset.Revisions)
            {
                if (workQueue.IsAborting)
                {
                    break;
                }

                AbortRetryIgnore(delegate
                {
                    needCommit |= ReplayRevision(pathMapper, revision, svn, labels);
                });
            }
            return(needCommit);
        }
コード例 #2
0
ファイル: ChangesetBuilder.cs プロジェクト: mathewng/vss2svn
        private void DumpChangeset(Changeset changeset, int changesetId)
        {
            var firstRevTime   = changeset.Revisions.First.Value.DateTime;
            var changeDuration = changeset.DateTime - firstRevTime;

            logger.WriteSectionSeparator();
            logger.WriteLine("Changeset {0} - {1} ({2} secs) {3} {4} files",
                             changesetId, changeset.DateTime, changeDuration.TotalSeconds, changeset.User,
                             changeset.Revisions.Count);
            if (!string.IsNullOrEmpty(changeset.Comment))
            {
                logger.WriteLine(changeset.Comment);
            }
            logger.WriteLine();
            foreach (var revision in changeset.Revisions)
            {
                logger.WriteLine("  {0} {1}@{2} {3}",
                                 revision.DateTime, revision.Item, revision.Version, revision.Action);
            }
        }
コード例 #3
0
ファイル: GitExporter.cs プロジェクト: mathewng/vss2svn
        private bool ReplayChangeset(VssPathMapper pathMapper, Changeset changeset,
            GitWrapper git, LinkedList<Revision> labels)
        {
            var needCommit = false;
            foreach (Revision revision in changeset.Revisions)
            {
                if (workQueue.IsAborting)
                {
                    break;
                }

                AbortRetryIgnore(delegate
                {
                    needCommit |= ReplayRevision(pathMapper, revision, git, labels);
                });
            }
            return needCommit;
        }
コード例 #4
0
ファイル: GitExporter.cs プロジェクト: mathewng/vss2svn
 private bool CommitChangeset(GitWrapper git, Changeset changeset)
 {
     var result = false;
     AbortRetryIgnore(delegate
     {
         result = git.AddAll() &&
             git.Commit(changeset.User, GetEmail(changeset.User),
             changeset.Comment ?? DefaultComment, changeset.DateTime);
     });
     return result;
 }
コード例 #5
0
ファイル: ChangesetBuilder.cs プロジェクト: mathewng/vss2svn
        public void BuildChangesets()
        {
            workQueue.AddLast(delegate(object work)
            {
                logger.WriteSectionSeparator();
                LogStatus(work, "Building changesets");

                var unnamedLabelCount = 0ul;

                var stopwatch            = Stopwatch.StartNew();
                var pendingChangesByUser = new Dictionary <string, Changeset>();
                foreach (var dateEntry in revisionAnalyzer.SortedRevisions)
                {
                    var dateTime = dateEntry.Key;

                    //foreach (Revision revision in dateEntry.Value)
                    for (var node = dateEntry.Value.First; node != dateEntry.Value.Last.Next; node = node.Next)
                    {
                        var revision = node.Value;

                        // VSS Destroyed Items: skip all. This will enable merging revisions separated by destroyed items.
                        if (excludeAllDestroyedItems)
                        {
                            if ((revision.Action as VssNamedAction)?.Name?.PhysicalName != null &&
                                revisionAnalyzer.IsDestroyed((revision.Action as VssNamedAction).Name.PhysicalName) &&
                                !revisionAnalyzer.Database.ItemExists((revision.Action as VssNamedAction).Name.PhysicalName))
                            {
                                continue;
                            }
                        }



                        // VSS Adds: fill in comments for add from create action
                        if (revision.Action.Type == VssActionType.Add && revision.Comment == null)
                        {
                            node.Value = revision = new Revision(revision.DateTime, revision.User, revision.Item, revision.Version, FindCorrespondingAction(revision, VssActionType.Create)?.Comment, revision.Action);
                        }

                        // VSS Labels: fill in empty label names as svn cannot have empty tag path.
                        if (revision.Action.Type == VssActionType.Label && string.IsNullOrEmpty(((VssLabelAction)revision.Action).Label))
                        {
                            node.Value = revision = new Revision(revision.DateTime, revision.User, revision.Item, revision.Version, revision.Comment, new VssLabelAction(string.Format(unnamedLabelFormat, revision.DateTime, ++unnamedLabelCount)));
                        }

                        // VSS Creates: skip all and exclude from changeset as it increases history complexity unnecessarily and the info is not useful at all. not used in exporter
                        if (revision.Action.Type == VssActionType.Create)
                        {
                            continue;
                        }

                        // determine target of project revisions
                        var actionType  = revision.Action.Type;
                        var namedAction = revision.Action as VssNamedAction;
                        var targetFile  = revision.Item.PhysicalName;
                        if (namedAction != null)
                        {
                            targetFile = namedAction.Name.PhysicalName;
                        }

                        // Create actions are only used to obtain initial item comments;
                        // items are actually created when added to a project
                        var creating = (actionType == VssActionType.Create ||
                                        (actionType == VssActionType.Branch && !revision.Item.IsProject));

                        // Share actions are never conflict (which is important,
                        // since Share always precedes Branch)
                        var nonconflicting = creating || (actionType == VssActionType.Share);


                        // look up the pending change for user of this revision
                        // and flush changes past time threshold
                        var pendingUser                  = revision.User;
                        Changeset pendingChange          = null;
                        LinkedList <string> flushedUsers = new LinkedList <string>();
                        foreach (var userEntry in pendingChangesByUser)
                        {
                            var user   = userEntry.Key;
                            var change = userEntry.Value;

                            // flush change if file conflict or past time threshold
                            var flush    = false;
                            var timeDiff = revision.DateTime - change.DateTime;

                            if (user == pendingUser)
                            {
                                // VSS Label: make labels on their own changeset
                                if ((revision.Action.Type == VssActionType.Label && change.Revisions.Last.Value.Action.Type != VssActionType.Label) ||
                                    (revision.Action.Type != VssActionType.Label && change.Revisions.Last.Value.Action.Type == VssActionType.Label))
                                {
                                    logger.WriteLine("NOTE: Splitting changeset due to label: {0}", change.Revisions.Last.Value.Action);
                                    flush = true;
                                }
                                // Cannot combine due to file conflict. must be recorded as separate changes
                                else if (!nonconflicting && change.TargetFiles.Contains(targetFile))
                                {
                                    logger.WriteLine("NOTE: Splitting changeset due to file conflict on {0}:", targetFile);
                                    flush = true;
                                }
                            }
                            else
                            {
                            }

                            /*
                             * if (!mergeAcrossDifferentUser && !HasSameUser(revision, change.Revisions.Last.Value))
                             * {
                             *  logger.WriteLine("NOTE: Splitting changeset due to different user: {0} != {1}", change.Revisions.Last.Value.User, revision.User);
                             *  flush = true;
                             * }
                             */

                            // additional check if not flushed above
                            if (!flush)
                            {
                                if ((TimeSpan.Zero == anyCommentThreshold ? TimeSpan.FromSeconds(1) : TimeSpan.Zero) + timeDiff > anyCommentThreshold)
                                {
                                    var lastRevision = FindLastRevisionWithNonEmptyComment(change);
                                    //if (HasSameComment(revision, change.Revisions.Last.Value))
                                    if (HasSameComment(revision, lastRevision))
                                    {
                                        string message;
                                        if ((TimeSpan.Zero == sameCommentThreshold ? TimeSpan.FromSeconds(1) : TimeSpan.Zero) + timeDiff < sameCommentThreshold)
                                        {
                                            message = "Using same-comment threshold";
                                        }
                                        else
                                        {
                                            message = "Splitting changeset due to same comment but exceeded threshold";
                                            logger.WriteLine("NOTE: {0} ({1} second gap):", message, timeDiff.TotalSeconds);
                                            flush = true;
                                        }
                                    }
                                    else
                                    {
                                        //logger.WriteLine("NOTE: Splitting changeset due to different comment: {0} != {1}:", change.Revisions.Last.Value.Comment, revision.Comment);
                                        logger.WriteLine("NOTE: Splitting changeset due to different comment: {0} != {1}:", lastRevision.Comment ?? "null", revision.Comment ?? "null");
                                        flush = true;
                                    }
                                }
                            }



                            if (flush)
                            {
                                AddChangeset(change);
                                flushedUsers.AddLast(user);
                            }
                            else if (user == pendingUser)
                            {
                                pendingChange = change;
                            }
                        }

                        foreach (string user in flushedUsers)
                        {
                            pendingChangesByUser.Remove(user);
                        }

                        // if no pending change for user, create a new one
                        if (pendingChange == null)
                        {
                            pendingChange      = new Changeset();
                            pendingChange.User = pendingUser;
                            pendingChangesByUser[pendingUser] = pendingChange;
                        }

                        // update the time of the change based on the last revision
                        pendingChange.DateTime = revision.DateTime;

                        // add the revision to the change
                        pendingChange.Revisions.AddLast(revision);

                        // track target files in changeset to detect conflicting actions
                        if (!nonconflicting)
                        {
                            pendingChange.TargetFiles.Add(targetFile);
                        }

                        // build up a concatenation of unique revision comments
                        var revComment = revision.Comment;
                        if (revComment != null)
                        {
                            revComment = revComment.Trim();
                            if (revComment.Length > 0)
                            {
                                if (string.IsNullOrEmpty(pendingChange.Comment))
                                {
                                    pendingChange.Comment = revComment;
                                }
                                else if (!pendingChange.Comment.Contains(revComment))
                                {
                                    pendingChange.Comment += "\n" + revComment;
                                }
                            }
                        }
                    }
                }

                // flush all remaining changes
                foreach (var change in pendingChangesByUser.Values)
                {
                    AddChangeset(change);
                }
                stopwatch.Stop();

                logger.WriteSectionSeparator();
                logger.WriteLine("Found {0} changesets in {1:HH:mm:ss}",
                                 changesets.Count, new DateTime(stopwatch.ElapsedTicks));
            });
        }
コード例 #6
0
ファイル: ChangesetBuilder.cs プロジェクト: mathewng/vss2svn
        public void BuildChangesets()
        {
            workQueue.AddLast(delegate (object work)
            {
                logger.WriteSectionSeparator();
                LogStatus(work, "Building changesets");

                var unnamedLabelCount = 0ul;

                var stopwatch = Stopwatch.StartNew();
                var pendingChangesByUser = new Dictionary<string, Changeset>();
                foreach (var dateEntry in revisionAnalyzer.SortedRevisions)
                {
                    var dateTime = dateEntry.Key;

                    //foreach (Revision revision in dateEntry.Value)
                    for (var node = dateEntry.Value.First; node != dateEntry.Value.Last.Next; node = node.Next)
                    {
                        var revision = node.Value;

                        // VSS Destroyed Items: skip all. This will enable merging revisions separated by destroyed items.
                        if (excludeAllDestroyedItems)
                        {
                            if ((revision.Action as VssNamedAction)?.Name?.PhysicalName != null
                                                    && revisionAnalyzer.IsDestroyed((revision.Action as VssNamedAction).Name.PhysicalName)
                                                    && !revisionAnalyzer.Database.ItemExists((revision.Action as VssNamedAction).Name.PhysicalName))
                            {
                                continue;
                            }
                        }

                        // VSS Adds: fill in comments for add from create action
                        if (revision.Action.Type == VssActionType.Add && revision.Comment == null)
                            node.Value = revision = new Revision(revision.DateTime, revision.User, revision.Item, revision.Version, FindCorrespondingAction(revision, VssActionType.Create)?.Comment, revision.Action);

                        // VSS Labels: fill in empty label names as svn cannot have empty tag path.
                        if (revision.Action.Type == VssActionType.Label && string.IsNullOrEmpty(((VssLabelAction)revision.Action).Label))
                            node.Value = revision = new Revision(revision.DateTime, revision.User, revision.Item, revision.Version, revision.Comment, new VssLabelAction(string.Format(unnamedLabelFormat, revision.DateTime, ++unnamedLabelCount)));

                        // VSS Creates: skip all and exclude from changeset as it increases history complexity unnecessarily and the info is not useful at all. not used in exporter
                        if (revision.Action.Type == VssActionType.Create)
                            continue;

                        // determine target of project revisions
                        var actionType = revision.Action.Type;
                        var namedAction = revision.Action as VssNamedAction;
                        var targetFile = revision.Item.PhysicalName;
                        if (namedAction != null)
                        {
                            targetFile = namedAction.Name.PhysicalName;
                        }

                        // Create actions are only used to obtain initial item comments;
                        // items are actually created when added to a project
                        var creating = (actionType == VssActionType.Create ||
                            (actionType == VssActionType.Branch && !revision.Item.IsProject));

                        // Share actions are never conflict (which is important,
                        // since Share always precedes Branch)
                        var nonconflicting = creating || (actionType == VssActionType.Share);

                        // look up the pending change for user of this revision
                        // and flush changes past time threshold
                        var pendingUser = revision.User;
                        Changeset pendingChange = null;
                        LinkedList<string> flushedUsers = new LinkedList<string>();
                        foreach (var userEntry in pendingChangesByUser)
                        {
                            var user = userEntry.Key;
                            var change = userEntry.Value;

                            // flush change if file conflict or past time threshold
                            var flush = false;
                            var timeDiff = revision.DateTime - change.DateTime;

                            if (user == pendingUser)
                            {
                                // VSS Label: make labels on their own changeset
                                if ((revision.Action.Type == VssActionType.Label && change.Revisions.Last.Value.Action.Type != VssActionType.Label)
                                || (revision.Action.Type != VssActionType.Label && change.Revisions.Last.Value.Action.Type == VssActionType.Label))
                                {
                                    logger.WriteLine("NOTE: Splitting changeset due to label: {0}", change.Revisions.Last.Value.Action);
                                    flush = true;
                                }
                                // Cannot combine due to file conflict. must be recorded as separate changes
                                else if (!nonconflicting && change.TargetFiles.Contains(targetFile))
                                {
                                    logger.WriteLine("NOTE: Splitting changeset due to file conflict on {0}:", targetFile);
                                    flush = true;
                                }

                            }
                            else
                            {

                            }
                            /*
                            if (!mergeAcrossDifferentUser && !HasSameUser(revision, change.Revisions.Last.Value))
                            {
                                logger.WriteLine("NOTE: Splitting changeset due to different user: {0} != {1}", change.Revisions.Last.Value.User, revision.User);
                                flush = true;
                            }
                            */

                            // additional check if not flushed above
                            if (!flush)
                            {
                                if ((TimeSpan.Zero == anyCommentThreshold ? TimeSpan.FromSeconds(1) : TimeSpan.Zero) + timeDiff > anyCommentThreshold)
                                {
                                    var lastRevision = FindLastRevisionWithNonEmptyComment(change);
                                    //if (HasSameComment(revision, change.Revisions.Last.Value))
                                    if (HasSameComment(revision, lastRevision))
                                    {
                                        string message;
                                        if ((TimeSpan.Zero == sameCommentThreshold ? TimeSpan.FromSeconds(1) : TimeSpan.Zero) + timeDiff < sameCommentThreshold)
                                        {
                                            message = "Using same-comment threshold";
                                        }
                                        else
                                        {
                                            message = "Splitting changeset due to same comment but exceeded threshold";
                                            logger.WriteLine("NOTE: {0} ({1} second gap):", message, timeDiff.TotalSeconds);
                                            flush = true;
                                        }
                                    }
                                    else
                                    {
                                        //logger.WriteLine("NOTE: Splitting changeset due to different comment: {0} != {1}:", change.Revisions.Last.Value.Comment, revision.Comment);
                                        logger.WriteLine("NOTE: Splitting changeset due to different comment: {0} != {1}:", lastRevision.Comment ?? "null", revision.Comment ?? "null");
                                        flush = true;
                                    }
                                }
                            }

                            if (flush)
                            {
                                AddChangeset(change);
                                flushedUsers.AddLast(user);
                            }
                            else if (user == pendingUser)
                            {
                                pendingChange = change;
                            }
                        }

                        foreach (string user in flushedUsers)
                            pendingChangesByUser.Remove(user);

                        // if no pending change for user, create a new one
                        if (pendingChange == null)
                        {
                            pendingChange = new Changeset();
                            pendingChange.User = pendingUser;
                            pendingChangesByUser[pendingUser] = pendingChange;
                        }

                        // update the time of the change based on the last revision
                        pendingChange.DateTime = revision.DateTime;

                        // add the revision to the change
                        pendingChange.Revisions.AddLast(revision);

                        // track target files in changeset to detect conflicting actions
                        if (!nonconflicting)
                        {
                            pendingChange.TargetFiles.Add(targetFile);
                        }

                        // build up a concatenation of unique revision comments
                        var revComment = revision.Comment;
                        if (revComment != null)
                        {
                            revComment = revComment.Trim();
                            if (revComment.Length > 0)
                            {
                                if (string.IsNullOrEmpty(pendingChange.Comment))
                                {
                                    pendingChange.Comment = revComment;
                                }
                                else if (!pendingChange.Comment.Contains(revComment))
                                {
                                    pendingChange.Comment += "\n" + revComment;
                                }
                            }
                        }
                    }
                }

                // flush all remaining changes
                foreach (var change in pendingChangesByUser.Values)
                {
                    AddChangeset(change);
                }
                stopwatch.Stop();

                logger.WriteSectionSeparator();
                logger.WriteLine("Found {0} changesets in {1:HH:mm:ss}",
                    changesets.Count, new DateTime(stopwatch.ElapsedTicks));
            });
        }
コード例 #7
0
ファイル: ChangesetBuilder.cs プロジェクト: mathewng/vss2svn
 private Revision FindLastRevisionWithNonEmptyComment(Changeset change)
 {
     var node = (LinkedListNode<Revision>)null;
     for (node = change.Revisions.Last; node != change.Revisions.First.Previous && string.IsNullOrEmpty(node.Value.Comment); node = node.Previous)
         ;
     return node?.Value??change.Revisions.Last.Value;
 }
コード例 #8
0
ファイル: ChangesetBuilder.cs プロジェクト: mathewng/vss2svn
 private void DumpChangeset(Changeset changeset, int changesetId)
 {
     var firstRevTime = changeset.Revisions.First.Value.DateTime;
     var changeDuration = changeset.DateTime - firstRevTime;
     logger.WriteSectionSeparator();
     logger.WriteLine("Changeset {0} - {1} ({2} secs) {3} {4} files",
         changesetId, changeset.DateTime, changeDuration.TotalSeconds, changeset.User,
         changeset.Revisions.Count);
     if (!string.IsNullOrEmpty(changeset.Comment))
     {
         logger.WriteLine(changeset.Comment);
     }
     logger.WriteLine();
     foreach (var revision in changeset.Revisions)
     {
         logger.WriteLine("  {0} {1}@{2} {3}",
             revision.DateTime, revision.Item, revision.Version, revision.Action);
     }
 }
コード例 #9
0
ファイル: ChangesetBuilder.cs プロジェクト: mathewng/vss2svn
 private void AddChangeset(Changeset change)
 {
     changesets.AddLast(change);
     int changesetId = changesets.Count;
     DumpChangeset(change, changesetId);
 }
コード例 #10
0
ファイル: SvnExporter.cs プロジェクト: mathewng/vss2svn
 private bool CommitChangeset(SvnWrapper svn, Changeset changeset)
 {
     var result = false;
     AbortRetryIgnore(delegate
     {
         result = svn.AddAll() &&
             svn.Commit(changeset.User, GetSvnUserFromVssUser(changeset.User),
             changeset.Comment ?? DefaultComment, changeset.DateTime);
     });
     return result;
 }