private IVcsWrapper CreateVcsWrapper(Encoding commitEncoding) { Invoke((MethodInvoker) delegate { if (transcodeCheckBox.Checked) { commitEncoding = Encoding.UTF8; } }); string repoPath = outDirTextBox.Text; string vcsType = vcsSetttingsTabs.SelectedTab.Text; if (vcsType.Equals(vcsTypeGit)) { GitWrapper wrapper = new GitWrapper(repoPath, logger, commitEncoding, forceAnnotatedCheckBox.Checked); wrapper.GitIgnoreInfo = $"{ignoreFile.Text}|{attributesFile.Text}|{userName.Text}|{userEmail.Text}|{initialComment.Text}"; return(wrapper); } else if (vcsType.Equals(vcsTypeSvn)) { bool stdLayout = svnStandardLayoutCheckBox.Checked; string trunk = stdLayout ? SvnWrapper.stdTrunk : svnTrunkTextBox.Text; string tags = stdLayout ? SvnWrapper.stdTags : svnTagsTextBox.Text; string branches = stdLayout ? SvnWrapper.stdBranches : svnBranchesTextBox.Text; var wrapper = new SvnWrapper(repoPath, svnRepoTextBox.Text, svnProjectPathTextBox.Text, trunk, tags, branches, logger); wrapper.SetCredentials(svnUserTextBox.Text, svnPasswordTextBox.Text); return(wrapper); } throw new ArgumentOutOfRangeException("vcsType", vcsType, "Undefined VCS Type"); }
private bool ReplayRevisionAlt(Revision revision, GitWrapper git, LinkedList <Revision> labels) { var needCommit = false; var actionType = revision.Action.Type; // We don't worry about projects! <smile> if ( (!revision.Item.IsProject) && (actionType == VssActionType.Create) || (actionType == VssActionType.Edit) ) { FileLocation fileLocation; if (fileAnalyzer.SortedFileLocations.TryGetValue(revision.Item.PhysicalName, out fileLocation)) { var path = VssPathMapper.GetWorkingPath(repoPath, fileLocation.Path, inheritProjectDir ? "" : fileAnalyzer.vssRootProjectPath); logger.WriteLine("{0}: {1} revision {2}", fileLocation.Path, actionType, revision.Version); if (WriteRevisionTo(revision.Item.PhysicalName, revision.Version, path)) { // add file explicitly, so it is visible to subsequent git operations git.Add(path); needCommit = true; } } } return(needCommit); }
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 { if (fileAnalyzer == null) { needCommit |= ReplayRevision(pathMapper, revision, git, labels); } else { needCommit |= ReplayRevisionAlt(revision, git, labels); } }); } return(needCommit); }
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); }
private bool CommitChangeset(GitWrapper git, Changeset changeset) { string comment = changeset.Comment ?? this.DefaultComment; if (string.IsNullOrEmpty(comment)) { comment = "** " + GetComment(changeset, 155); } var result = false; AbortRetryIgnore(delegate { result = git.AddAll() && git.Commit(changeset.User, GetEmail(changeset.User), comment ?? DefaultComment, changeset.DateTime); }); return(result); }
public void ExportToGit(string repoPath) { workQueue.AddLast(delegate(object work) { var stopwatch = Stopwatch.StartNew(); logger.WriteSectionSeparator(); LogStatus(work, "Initializing Git repository"); // create repository directory if it does not exist if (!Directory.Exists(repoPath)) { Directory.CreateDirectory(repoPath); } var git = new GitWrapper(repoPath, logger); git.CommitEncoding = commitEncoding; while (!git.FindExecutable()) { var button = MessageBox.Show("Git not found in PATH. " + "If you need to modify your PATH variable, please " + "restart the program for the changes to take effect.", "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); if (button == DialogResult.Cancel) { workQueue.Abort(); return; } } if (!RetryCancel(delegate { git.Init(); })) { return; } if (commitEncoding.WebName != "utf-8") { AbortRetryIgnore(delegate { git.SetConfig("i18n.commitencoding", commitEncoding.WebName); }); } var pathMapper = new VssPathMapper(); // create mappings for root projects foreach (var rootProject in revisionAnalyzer.RootProjects) { var rootPath = VssPathMapper.GetWorkingPath(repoPath, rootProject.Path); pathMapper.SetProjectPath(rootProject.PhysicalName, rootPath, rootProject.Path); } // replay each changeset var changesetId = 1; var changesets = changesetBuilder.Changesets; var commitCount = 0; var tagCount = 0; var replayStopwatch = new Stopwatch(); var labels = new LinkedList <Revision>(); tagsUsed.Clear(); foreach (var changeset in changesets) { var changesetDesc = string.Format(CultureInfo.InvariantCulture, "changeset {0} from {1}", changesetId, changeset.DateTime); // replay each revision in changeset LogStatus(work, "Replaying " + changesetDesc); labels.Clear(); replayStopwatch.Start(); bool needCommit; try { needCommit = ReplayChangeset(pathMapper, changeset, git, labels); } finally { replayStopwatch.Stop(); } if (workQueue.IsAborting) { return; } // commit changes if (needCommit) { LogStatus(work, "Committing " + changesetDesc); if (CommitChangeset(git, changeset)) { ++commitCount; } } if (workQueue.IsAborting) { return; } // create tags for any labels in the changeset if (labels.Count > 0) { foreach (Revision label in labels) { var labelName = ((VssLabelAction)label.Action).Label; if (string.IsNullOrEmpty(labelName)) { logger.WriteLine("NOTE: Ignoring empty label"); } else if (commitCount == 0) { logger.WriteLine("NOTE: Ignoring label '{0}' before initial commit", labelName); } else { var tagName = GetTagFromLabel(labelName); var tagMessage = "Creating tag " + tagName; if (tagName != labelName) { tagMessage += " for label '" + labelName + "'"; } LogStatus(work, tagMessage); // annotated tags require (and are implied by) a tag message; // tools like Mercurial's git converter only import annotated tags var tagComment = label.Comment; if (string.IsNullOrEmpty(tagComment) && forceAnnotatedTags) { // use the original VSS label as the tag message if none was provided tagComment = labelName; } if (AbortRetryIgnore( delegate { git.Tag(tagName, label.User, GetEmail(label.User), tagComment, label.DateTime); })) { ++tagCount; } } } } ++changesetId; } stopwatch.Stop(); logger.WriteSectionSeparator(); logger.WriteLine("Git export complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks)); logger.WriteLine("Replay time: {0:HH:mm:ss}", new DateTime(replayStopwatch.ElapsedTicks)); logger.WriteLine("Git time: {0:HH:mm:ss}", new DateTime(git.ElapsedTime.Ticks)); logger.WriteLine("Git commits: {0}", commitCount); logger.WriteLine("Git tags: {0}", tagCount); }); }
private bool WriteRevision(VssPathMapper pathMapper, VssActionType actionType, string physicalName, int version, string underProject, GitWrapper git) { var needCommit = false; var paths = pathMapper.GetFilePaths(physicalName, underProject); foreach (string path in paths) { logger.WriteLine("{0}: {1} revision {2}", path, actionType, version); if (WriteRevisionTo(physicalName, version, path)) { // add file explicitly, so it is visible to subsequent git operations git.Add(path); needCommit = true; } } return(needCommit); }
private bool ReplayRevision(VssPathMapper pathMapper, Revision revision, GitWrapper git, LinkedList <Revision> labels) { var needCommit = false; var actionType = revision.Action.Type; if (revision.Item.IsProject) { // note that project path (and therefore target path) can be // null if a project was moved and its original location was // subsequently destroyed var project = revision.Item; var projectName = project.LogicalName; var projectPath = pathMapper.GetProjectPath(project.PhysicalName); var projectDesc = projectPath; if (projectPath == null) { projectDesc = revision.Item.ToString(); logger.WriteLine("NOTE: {0} is currently unmapped", project); } VssItemName target = null; string targetPath = null; var namedAction = revision.Action as VssNamedAction; if (namedAction != null) { target = namedAction.Name; if (projectPath != null) { targetPath = Path.Combine(projectPath, target.LogicalName); } } bool isAddAction = false; bool writeFile = false; string writeProjectPhysicalName = null; VssItemInfo itemInfo = null; switch (actionType) { case VssActionType.Label: // defer tagging until after commit labels.AddLast(revision); break; case VssActionType.Create: // ignored; items are actually created when added to a project break; case VssActionType.Add: case VssActionType.Share: logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.AddItem(project, target); isAddAction = true; break; case VssActionType.Recover: logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.RecoverItem(project, target); isAddAction = true; break; case VssActionType.Delete: case VssActionType.Destroy: { logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.DeleteItem(project, target); if (targetPath != null && !itemInfo.Destroyed) { if (target.IsProject) { if (Directory.Exists(targetPath)) { string successor = pathMapper.TryToGetPhysicalNameContainedInProject(project, target); if (successor != null) { // we already have another project with the same logical name logger.WriteLine("NOTE: {0} contains another directory named {1}; not deleting directory", projectDesc, target.LogicalName); writeProjectPhysicalName = successor; // rewrite this project because it gets deleted below } if (((VssProjectInfo)itemInfo).ContainsFiles()) { git.Remove(targetPath, true); needCommit = true; } else { // git doesn't care about directories with no files Directory.Delete(targetPath, true); } } } else { if (File.Exists(targetPath)) { // not sure how it can happen, but a project can evidently // contain another file with the same logical name, so check // that this is not the case before deleting the file if (pathMapper.TryToGetPhysicalNameContainedInProject(project, target) != null) { logger.WriteLine("NOTE: {0} contains another file named {1}; not deleting file", projectDesc, target.LogicalName); } else { File.Delete(targetPath); needCommit = true; } } } } } break; case VssActionType.Rename: { var renameAction = (VssRenameAction)revision.Action; logger.WriteLine("{0}: {1} {2} to {3}", projectDesc, actionType, renameAction.OriginalName, target.LogicalName); itemInfo = pathMapper.RenameItem(target); if (targetPath != null && !itemInfo.Destroyed) { var sourcePath = Path.Combine(projectPath, renameAction.OriginalName); if (target.IsProject ? Directory.Exists(sourcePath) : File.Exists(sourcePath)) { // renaming a file or a project that contains files? var projectInfo = itemInfo as VssProjectInfo; if (projectInfo == null || projectInfo.ContainsFiles()) { CaseSensitiveRename(sourcePath, targetPath, git.Move); needCommit = true; } else { // git doesn't care about directories with no files CaseSensitiveRename(sourcePath, targetPath, Directory.Move); } } else { logger.WriteLine("NOTE: Skipping rename because {0} does not exist", sourcePath); } } } break; case VssActionType.MoveFrom: // if both MoveFrom & MoveTo are present (e.g. // one of them has not been destroyed), only one // can succeed, so check that the source exists { var moveFromAction = (VssMoveFromAction)revision.Action; logger.WriteLine("{0}: Move from {1} to {2}", projectDesc, moveFromAction.OriginalProject, targetPath ?? target.LogicalName); var sourcePath = pathMapper.GetProjectPath(target.PhysicalName); var projectInfo = pathMapper.MoveProjectFrom( project, target, moveFromAction.OriginalProject); if (targetPath != null && !projectInfo.Destroyed) { if (sourcePath != null && Directory.Exists(sourcePath)) { if (projectInfo.ContainsFiles()) { git.Move(sourcePath, targetPath); needCommit = true; } else { // git doesn't care about directories with no files Directory.Move(sourcePath, targetPath); } } else { // project was moved from a now-destroyed project writeProjectPhysicalName = target.PhysicalName; } } } break; case VssActionType.MoveTo: { // handle actual moves in MoveFrom; this just does cleanup of destroyed projects var moveToAction = (VssMoveToAction)revision.Action; logger.WriteLine("{0}: Move to {1} from {2}", projectDesc, moveToAction.NewProject, targetPath ?? target.LogicalName); var projectInfo = pathMapper.MoveProjectTo( project, target, moveToAction.NewProject); if (projectInfo.Destroyed && targetPath != null && Directory.Exists(targetPath)) { // project was moved to a now-destroyed project; remove empty directory Directory.Delete(targetPath, true); } } break; case VssActionType.Pin: { var pinAction = (VssPinAction)revision.Action; if (pinAction.Pinned) { logger.WriteLine("{0}: Pin {1}", projectDesc, target.LogicalName); itemInfo = pathMapper.PinItem(project, target); } else { logger.WriteLine("{0}: Unpin {1}", projectDesc, target.LogicalName); itemInfo = pathMapper.UnpinItem(project, target); writeFile = !itemInfo.Destroyed; } } break; case VssActionType.Branch: { var branchAction = (VssBranchAction)revision.Action; logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.BranchFile(project, target, branchAction.Source); // branching within the project might happen after branching of the file writeFile = true; } break; case VssActionType.Archive: // currently ignored { var archiveAction = (VssArchiveAction)revision.Action; logger.WriteLine("{0}: Archive {1} to {2} (ignored)", projectDesc, target.LogicalName, archiveAction.ArchivePath); } break; case VssActionType.Restore: { var restoreAction = (VssRestoreAction)revision.Action; logger.WriteLine("{0}: Restore {1} from archive {2}", projectDesc, target.LogicalName, restoreAction.ArchivePath); itemInfo = pathMapper.AddItem(project, target); isAddAction = true; } break; } if (targetPath != null) { if (isAddAction) { if (revisionAnalyzer.IsDestroyed(target.PhysicalName) && !database.ItemExists(target.PhysicalName)) { logger.WriteLine("NOTE: Skipping destroyed file: {0}", targetPath); itemInfo.Destroyed = true; } else if (target.IsProject) { Directory.CreateDirectory(targetPath); writeProjectPhysicalName = target.PhysicalName; } else { writeFile = true; } } if (writeProjectPhysicalName != null && pathMapper.IsProjectRooted(writeProjectPhysicalName)) { // create all contained subdirectories foreach (var projectInfo in pathMapper.GetAllProjects(writeProjectPhysicalName)) { logger.WriteLine("{0}: Creating subdirectory {1}", projectDesc, projectInfo.LogicalName); Directory.CreateDirectory(projectInfo.GetPath()); } // write current rev of all contained files foreach (var fileInfo in pathMapper.GetAllFiles(writeProjectPhysicalName)) { if (WriteRevision(pathMapper, actionType, fileInfo.PhysicalName, fileInfo.Version, writeProjectPhysicalName, git)) { // one or more files were written needCommit = true; } } } else if (writeFile) { // write current rev to working path int version = pathMapper.GetFileVersion(target.PhysicalName); if (WriteRevisionTo(target.PhysicalName, version, targetPath)) { // add file explicitly, so it is visible to subsequent git operations git.Add(targetPath); needCommit = true; } } } } // item is a file, not a project else if (actionType == VssActionType.Edit || actionType == VssActionType.Branch) { // if the action is Branch, the following code is necessary only if the item // was branched from a file that is not part of the migration subset; it will // make sure we start with the correct revision instead of the first revision var target = revision.Item; // update current rev pathMapper.SetFileVersion(target, revision.Version); // write current rev to all sharing projects WriteRevision(pathMapper, actionType, target.PhysicalName, revision.Version, null, git); needCommit = true; } return(needCommit); }
public void ExportToGit(string repoPath) { workQueue.AddLast(delegate(object work) { var stopwatch = Stopwatch.StartNew(); logger.WriteSectionSeparator(); LogStatus(work, "Initializing Git repository"); // create repository directory if it does not exist if (!Directory.Exists(repoPath)) { Directory.CreateDirectory(repoPath); } var git = new GitWrapper(repoPath, logger); git.CommitEncoding = commitEncoding; while (!git.FindExecutable()) { var button = MessageBox.Show("Git not found in PATH. " + "If you need to modify your PATH variable, please " + "restart the program for the changes to take effect.", "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); if (button == DialogResult.Cancel) { workQueue.Abort(); return; } } if (!RetryCancel(delegate { git.Init(); })) { return; } if (commitEncoding.WebName != "utf-8") { AbortRetryIgnore(delegate { git.SetConfig("i18n.commitencoding", commitEncoding.WebName); }); } var pathMapper = new VssPathMapper(); // create mappings for root projects foreach (var rootProject in revisionAnalyzer.RootProjects) { var rootPath = VssPathMapper.GetWorkingPath(repoPath, rootProject.Path); pathMapper.SetProjectPath(rootProject.PhysicalName, rootPath, rootProject.Path); } // replay each changeset var changesetId = 1; var changesets = changesetBuilder.Changesets; var commitCount = 0; var tagCount = 0; var replayStopwatch = new Stopwatch(); var labels = new LinkedList<Revision>(); tagsUsed.Clear(); foreach (var changeset in changesets) { var changesetDesc = string.Format(CultureInfo.InvariantCulture, "changeset {0} from {1}", changesetId, changeset.DateTime); // replay each revision in changeset LogStatus(work, "Replaying " + changesetDesc); labels.Clear(); replayStopwatch.Start(); bool needCommit; try { needCommit = ReplayChangeset(pathMapper, changeset, git, labels); } finally { replayStopwatch.Stop(); } if (workQueue.IsAborting) { return; } // commit changes if (needCommit) { LogStatus(work, "Committing " + changesetDesc); if (CommitChangeset(git, changeset)) { ++commitCount; } } if (workQueue.IsAborting) { return; } // create tags for any labels in the changeset if (labels.Count > 0) { foreach (Revision label in labels) { var labelName = ((VssLabelAction)label.Action).Label; if (string.IsNullOrEmpty(labelName)) { logger.WriteLine("NOTE: Ignoring empty label"); } else if (commitCount == 0) { logger.WriteLine("NOTE: Ignoring label '{0}' before initial commit", labelName); } else { var tagName = GetTagFromLabel(labelName); var tagMessage = "Creating tag " + tagName; if (tagName != labelName) { tagMessage += " for label '" + labelName + "'"; } LogStatus(work, tagMessage); // annotated tags require (and are implied by) a tag message; // tools like Mercurial's git converter only import annotated tags var tagComment = label.Comment; if (string.IsNullOrEmpty(tagComment) && forceAnnotatedTags) { // use the original VSS label as the tag message if none was provided tagComment = labelName; } if (AbortRetryIgnore( delegate { git.Tag(tagName, label.User, GetEmail(label.User), tagComment, label.DateTime); })) { ++tagCount; } } } } ++changesetId; } stopwatch.Stop(); logger.WriteSectionSeparator(); logger.WriteLine("Git export complete in {0:HH:mm:ss}", new DateTime(stopwatch.ElapsedTicks)); logger.WriteLine("Replay time: {0:HH:mm:ss}", new DateTime(replayStopwatch.ElapsedTicks)); logger.WriteLine("Git time: {0:HH:mm:ss}", new DateTime(git.ElapsedTime.Ticks)); logger.WriteLine("Git commits: {0}", commitCount); logger.WriteLine("Git tags: {0}", tagCount); }); }
private bool WriteRevision(VssPathMapper pathMapper, VssActionType actionType, string physicalName, int version, string underProject, GitWrapper git) { var needCommit = false; var paths = pathMapper.GetFilePaths(physicalName, underProject); foreach (string path in paths) { logger.WriteLine("{0}: {1} revision {2}", path, actionType, version); if (WriteRevisionTo(physicalName, version, path)) { // add file explicitly, so it is visible to subsequent git operations git.Add(path); needCommit = true; } } return needCommit; }
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; }
private bool ReplayRevision(VssPathMapper pathMapper, Revision revision, GitWrapper git, LinkedList<Revision> labels) { var needCommit = false; var actionType = revision.Action.Type; if (revision.Item.IsProject) { // note that project path (and therefore target path) can be // null if a project was moved and its original location was // subsequently destroyed var project = revision.Item; var projectName = project.LogicalName; var projectPath = pathMapper.GetProjectPath(project.PhysicalName); var projectDesc = projectPath; if (projectPath == null) { projectDesc = revision.Item.ToString(); logger.WriteLine("NOTE: {0} is currently unmapped", project); } VssItemName target = null; string targetPath = null; var namedAction = revision.Action as VssNamedAction; if (namedAction != null) { target = namedAction.Name; if (projectPath != null) { targetPath = Path.Combine(projectPath, target.LogicalName); } } bool isAddAction = false; bool writeProject = false; bool writeFile = false; VssItemInfo itemInfo = null; switch (actionType) { case VssActionType.Label: // defer tagging until after commit labels.AddLast(revision); break; case VssActionType.Create: // ignored; items are actually created when added to a project break; case VssActionType.Add: case VssActionType.Share: logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.AddItem(project, target); isAddAction = true; break; case VssActionType.Recover: logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.RecoverItem(project, target); isAddAction = true; break; case VssActionType.Delete: case VssActionType.Destroy: { logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.DeleteItem(project, target); if (targetPath != null && !itemInfo.Destroyed) { if (target.IsProject) { if (Directory.Exists(targetPath)) { if (((VssProjectInfo)itemInfo).ContainsFiles()) { git.Remove(targetPath, true); needCommit = true; } else { // git doesn't care about directories with no files Directory.Delete(targetPath, true); } } } else { if (File.Exists(targetPath)) { // not sure how it can happen, but a project can evidently // contain another file with the same logical name, so check // that this is not the case before deleting the file if (pathMapper.ProjectContainsLogicalName(project, target)) { logger.WriteLine("NOTE: {0} contains another file named {1}; not deleting file", projectDesc, target.LogicalName); } else { File.Delete(targetPath); needCommit = true; } } } } } break; case VssActionType.Rename: { var renameAction = (VssRenameAction)revision.Action; logger.WriteLine("{0}: {1} {2} to {3}", projectDesc, actionType, renameAction.OriginalName, target.LogicalName); itemInfo = pathMapper.RenameItem(target); if (targetPath != null && !itemInfo.Destroyed) { var sourcePath = Path.Combine(projectPath, renameAction.OriginalName); if (target.IsProject ? Directory.Exists(sourcePath) : File.Exists(sourcePath)) { // renaming a file or a project that contains files? var projectInfo = itemInfo as VssProjectInfo; if (projectInfo == null || projectInfo.ContainsFiles()) { CaseSensitiveRename(sourcePath, targetPath, git.Move); needCommit = true; } else { // git doesn't care about directories with no files CaseSensitiveRename(sourcePath, targetPath, Directory.Move); } } else { logger.WriteLine("NOTE: Skipping rename because {0} does not exist", sourcePath); } } } break; case VssActionType.MoveFrom: // if both MoveFrom & MoveTo are present (e.g. // one of them has not been destroyed), only one // can succeed, so check that the source exists { var moveFromAction = (VssMoveFromAction)revision.Action; logger.WriteLine("{0}: Move from {1} to {2}", projectDesc, moveFromAction.OriginalProject, targetPath ?? target.LogicalName); var sourcePath = pathMapper.GetProjectPath(target.PhysicalName); var projectInfo = pathMapper.MoveProjectFrom( project, target, moveFromAction.OriginalProject); if (targetPath != null && !projectInfo.Destroyed) { if (sourcePath != null && Directory.Exists(sourcePath)) { if (projectInfo.ContainsFiles()) { git.Move(sourcePath, targetPath); needCommit = true; } else { // git doesn't care about directories with no files Directory.Move(sourcePath, targetPath); } } else { // project was moved from a now-destroyed project writeProject = true; } } } break; case VssActionType.MoveTo: { // handle actual moves in MoveFrom; this just does cleanup of destroyed projects var moveToAction = (VssMoveToAction)revision.Action; logger.WriteLine("{0}: Move to {1} from {2}", projectDesc, moveToAction.NewProject, targetPath ?? target.LogicalName); var projectInfo = pathMapper.MoveProjectTo( project, target, moveToAction.NewProject); if (projectInfo.Destroyed && targetPath != null && Directory.Exists(targetPath)) { // project was moved to a now-destroyed project; remove empty directory Directory.Delete(targetPath, true); } } break; case VssActionType.Pin: { var pinAction = (VssPinAction)revision.Action; if (pinAction.Pinned) { logger.WriteLine("{0}: Pin {1}", projectDesc, target.LogicalName); itemInfo = pathMapper.PinItem(project, target); } else { logger.WriteLine("{0}: Unpin {1}", projectDesc, target.LogicalName); itemInfo = pathMapper.UnpinItem(project, target); writeFile = !itemInfo.Destroyed; } } break; case VssActionType.Branch: { var branchAction = (VssBranchAction)revision.Action; logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.BranchFile(project, target, branchAction.Source); // branching within the project might happen after branching of the file writeFile = true; } break; case VssActionType.Archive: // currently ignored { var archiveAction = (VssArchiveAction)revision.Action; logger.WriteLine("{0}: Archive {1} to {2} (ignored)", projectDesc, target.LogicalName, archiveAction.ArchivePath); } break; case VssActionType.Restore: { var restoreAction = (VssRestoreAction)revision.Action; logger.WriteLine("{0}: Restore {1} from archive {2}", projectDesc, target.LogicalName, restoreAction.ArchivePath); itemInfo = pathMapper.AddItem(project, target); isAddAction = true; } break; } if (targetPath != null) { if (isAddAction) { if (revisionAnalyzer.IsDestroyed(target.PhysicalName) && !database.ItemExists(target.PhysicalName)) { logger.WriteLine("NOTE: Skipping destroyed file: {0}", targetPath); itemInfo.Destroyed = true; } else if (target.IsProject) { Directory.CreateDirectory(targetPath); writeProject = true; } else { writeFile = true; } } if (writeProject && pathMapper.IsProjectRooted(target.PhysicalName)) { // create all contained subdirectories foreach (var projectInfo in pathMapper.GetAllProjects(target.PhysicalName)) { logger.WriteLine("{0}: Creating subdirectory {1}", projectDesc, projectInfo.LogicalName); Directory.CreateDirectory(projectInfo.GetPath()); } // write current rev of all contained files foreach (var fileInfo in pathMapper.GetAllFiles(target.PhysicalName)) { if (WriteRevision(pathMapper, actionType, fileInfo.PhysicalName, fileInfo.Version, target.PhysicalName, git)) { // one or more files were written needCommit = true; } } } else if (writeFile) { // write current rev to working path int version = pathMapper.GetFileVersion(target.PhysicalName); if (WriteRevisionTo(target.PhysicalName, version, targetPath)) { // add file explicitly, so it is visible to subsequent git operations git.Add(targetPath); needCommit = true; } } } } // item is a file, not a project else if (actionType == VssActionType.Edit || actionType == VssActionType.Branch) { // if the action is Branch, the following code is necessary only if the item // was branched from a file that is not part of the migration subset; it will // make sure we start with the correct revision instead of the first revision var target = revision.Item; // update current rev pathMapper.SetFileVersion(target, revision.Version); // write current rev to all sharing projects WriteRevision(pathMapper, actionType, target.PhysicalName, revision.Version, null, git); needCommit = true; } return needCommit; }
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; }
private void AddNewItems(GitWrapper git) { int counter = 0; if (pathsToAdd.Count > 0) { while (true) { //make sure we do not make the path so long it will not run. var itemsToAdd = pathsToAdd.Skip(counter * 100).Take(100).ToList(); if (itemsToAdd.Count == 0) { return; } git.Add(itemsToAdd); counter++; } } }
private bool ReplayRevisionAlt(Revision revision, GitWrapper git, LinkedList<Revision> labels) { var needCommit = false; var actionType = revision.Action.Type; // We don't worry about projects! <smile> if ( (!revision.Item.IsProject) && (actionType == VssActionType.Create) || (actionType == VssActionType.Edit) ) { FileLocation fileLocation; if (fileAnalyzer.SortedFileLocations.TryGetValue(revision.Item.PhysicalName, out fileLocation)) { var path = VssPathMapper.GetWorkingPath(repoPath, fileLocation.Path, inheritProjectDir ? "" : fileAnalyzer.vssRootProjectPath); logger.WriteLine("{0}: {1} revision {2}", fileLocation.Path, actionType, revision.Version); if (WriteRevisionTo(revision.Item.PhysicalName, revision.Version, path)) { // add file explicitly, so it is visible to subsequent git operations git.Add(path); needCommit = true; } } } return needCommit; }
private bool ReplayRevision(VssPathMapper pathMapper, Revision revision, GitWrapper git, LinkedList <Revision> labels) { var needCommit = false; var actionType = revision.Action.Type; if (revision.Item.IsProject) { // note that project path (and therefore target path) can be // null if a project was moved and its original location was // subsequently destroyed var project = revision.Item; var projectPath = pathMapper.GetProjectPath(project.PhysicalName); var projectDesc = projectPath; if (projectPath == null) { projectDesc = revision.Item.ToString(); logger.WriteLine("NOTE: {0} is currently unmapped", project); } VssItemName target = null; string targetPath = null; if (revision.Action is VssNamedAction namedAction) { target = namedAction.Name; if (projectPath != null) { targetPath = Path.Combine(projectPath, target.LogicalName); } } var isAddAction = false; var writeProject = false; var writeFile = false; VssItemInfo itemInfo = null; switch (actionType) { case VssActionType.Label: // defer tagging until after commit labels.AddLast(revision); break; case VssActionType.Create: // ignored; items are actually created when added to a project break; case VssActionType.Add: case VssActionType.Share: logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.AddItem(project, target); isAddAction = true; break; case VssActionType.Recover: logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.RecoverItem(project, target); isAddAction = true; break; case VssActionType.Delete: case VssActionType.Destroy: { logger.WriteLine("{0}: {1} {2}", projectDesc, actionType, target.LogicalName); itemInfo = pathMapper.DeleteItem(project, target); if (targetPath != null && !itemInfo.Destroyed) { if (target.IsProject) { if (Directory.Exists(targetPath)) { if (((VssProjectInfo)itemInfo).ContainsFiles()) { git.Remove(targetPath, true); needCommit = true; } else { // git doesn't care about directories with no files Directory.Delete(targetPath, true); } } } else { if (File.Exists(targetPath)) { // not sure how it can happen, but a project can evidently // contain another file with the same logical name, so check // that this is not the case before deleting the file if (pathMapper.ProjectContainsLogicalName(project, target)) { logger.WriteLine("NOTE: {0} contains another file named {1}; not deleting file", projectDesc, target.LogicalName); } else { File.Delete(targetPath); needCommit = true; } } } } } break; case VssActionType.Rename: { var renameAction = (VssRenameAction)revision.Action; logger.WriteLine("{0}: {1} {2} to {3}", projectDesc, actionType, renameAction.OriginalName, target.LogicalName); itemInfo = pathMapper.RenameItem(target); if (targetPath != null && !itemInfo.Destroyed) { var sourcePath = Path.Combine(projectPath, renameAction.OriginalName); if (target.IsProject ? Directory.Exists(sourcePath) : File.Exists(sourcePath)) { // renaming a file or a project that contains files? if (!(itemInfo is VssProjectInfo projectInfo) || (projectInfo.ContainsFiles() && projectInfo.Items.All(x => !x.Destroyed))) { CaseSensitiveRename(sourcePath, targetPath, git.Move); needCommit = true; } else { // git doesn't care about directories with no files CaseSensitiveRename(sourcePath, targetPath, CaseSensitiveDirectoryMove); } } else { logger.WriteLine("NOTE: Skipping rename because {0} does not exist", sourcePath); } } } break;