/// <summary> /// This handles merging the revisions in the event that a single check-in spans a window of time rather than an exact /// second in time. /// </summary> /// <returns></returns> private static bool MergeRevisions() { //Merge from the back of the list to move items forward //This could potentially merge everything into a single revision with a time of the //first revision if there are no comments and every version is within the mergedrevision_seconds of each other //however, a single person is not likely to be making that many changes on a regular basis if (revisions.Count <= 1 || MergeRevisionWindow == 0) { mergeLog.WarnFormat("Skipping revision merge because there is nothing to do"); return(true); } mergeLog.InfoFormat("Starting to merge revisions with count of {0}", revisions.Count); //No point in checking the last revision with nothing //Start with the most recent files and move backward through the list //By moving the files to an earlier point in time (if within the window), we can keep moving them to an earlier //point in time thereby allowing more revisions to get merged as the time of the earliest revision for (int i = revisions.Keys.Count - 2; i >= 0; i--) { int j = i; VssRevProps key = revisions.Keys[i]; while (++j < revisions.Keys.Count && revisions.Keys[j].Time.Subtract(key.Time).TotalSeconds <= MergeRevisionWindow) { //Make sure we don't have any duplicate files before checking the author and/or comments. //If we have a duplicate file, we can't even proceed with merging to the past bool bDuplicate = false; //the i is "later" (older) than the j which is "newer" (more recent) foreach (VssFileVersion laterfile in revisions[key].Values) { foreach (VssFileVersion newerfile in revisions[revisions.Keys[j]].Values) { if (string.Compare(laterfile.Spec, newerfile.Spec, true) == 0) { bDuplicate = true; break; } } if (bDuplicate) { break; } } //We must stop if we have encountered a duplicate file because we cannot merge anything beyond this point if (bDuplicate) { break; } //No duplicates; now make sure we have other matching properties for the revision if (string.Compare(key.Author, revisions.Keys[j].Author, true) == 0 && string.Compare(key.Comment, revisions.Keys[j].Comment, true) == 0) { mergeLog.DebugFormat("Merging revision {0}\n\tinto\t{1}", revisions.Keys[j], key); //Merge the more recent revisions into the older revision foreach (var laterfile in revisions[revisions.Keys[j]]) { revisions[key].Add(laterfile.Key, laterfile.Value); } revisions.Remove(revisions.Keys[j]); break; } } } mergeLog.InfoFormat("Merge completed with a final revision count of {0}", revisions.Count); return(true); }
private static void GetAndAddRevision(VssRevProps properties, Dictionary <string, VssFileVersion> files, SvnClient svnClient) { string dir = Path.Combine(repoDIR, vssPROJ.Substring(2).Replace("/", "\\")); string filePath = string.Empty; var delkeys = new List <string>(); foreach (string key in files.Keys) { try { //take care of the rare case of an item both file and label if (!String.IsNullOrEmpty(files[key].Version.Label)) { if (files[key].Version.VSSItem.Type != 0) { GetFileVersion(files[key].Version.VSSItem, files[key].Version, svnClient); var commitArgs = new SvnCommitArgs { LogMessage = properties.Comment }; svnClient.Commit(dir, commitArgs); filePath = Path.Combine( Path.GetDirectoryName( string.Format("{0}{1}", repoDIR, files[key].Spec.Substring(1)).Replace("/", "\\")), files[key].Version.VSSItem.Name); var uri = new Uri(string.Format("{0}{1}", svnURL, svnPROJ)); //svnClient.GetInfo(SvnTarget.FromString(filePath), out infoEventArgs); CounterfeitRevProps(svnClient, SvnTarget.FromUri(uri), files[key].Version); } TagSourceUrl = String.Empty; var tag = new Tag { fromUrlString = GenerateSourceUrl(files[key].Version.VSSItem), tagString = String.Format("{0}/{1}/{2}_{3}", svnURL, svnTAG, files[key].Version.VSSItem.Name, sanitizeLabel(files[key].Version.Label)), label = files[key].Version.Label }; ApplyTag(files[key].Version.VSSItem, svnClient, files[key].Version, tag); return; } //rare case end GetFileVersion(files[key].Version.VSSItem, files[key].Version, svnClient); //Only need one file to get the revision information from if (string.IsNullOrEmpty(filePath)) { filePath = Path.Combine( Path.GetDirectoryName( string.Format("{0}{1}", repoDIR, files[key].Spec.Substring(1)).Replace("/", "\\")), files[key].Version.VSSItem.Name); } if (files[key].Deleted) { delkeys.Add(filePath); } } catch (COMException ex) { switch ((uint)ex.ErrorCode) { case 0x8004D838: //version is corrupted and unavailable migrateLog.WarnFormat("Skipping version due to corruption in file {1}:{0}", files[key].VersionNumber, files[key].Spec); continue; default: if (IgnoreExceptions) { migrateLog.ErrorFormat("Error processing file {1}:{0}", files[key].VersionNumber, files[key].Spec); migrateLog.ErrorFormat(ex.ToString()); continue; } throw; } } } //Only commit if we actually have a file that has been updated as a result of the get if (!string.IsNullOrEmpty(filePath)) { var commitArgs = new SvnCommitArgs { LogMessage = properties.Comment }; migrateLog.DebugFormat("Committing revision ..."); //SLOW!!!, change to ICollection of FilePaths (only verify updated files!) svnClient.Commit(dir, commitArgs); //delete files which are marked as deleted in vss foreach (string delFilePath in delkeys) { svnClient.Delete(delFilePath); migrateLog.Info(String.Format("Deleted: {0}", delFilePath)); } delkeys.Clear(); SvnInfoEventArgs infoEventArgs; //Use one of the committed files to determine the revision we just committed var uri = new Uri(string.Format("{0}{1}", svnURL, svnPROJ)); //svnClient.GetInfo(SvnTarget.FromString(filePath), out infoEventArgs); svnClient.GetInfo(SvnTarget.FromUri(uri), out infoEventArgs); svnClient.SetRevisionProperty(new Uri(svnURL), infoEventArgs.Revision, SvnPropertyNames.SvnAuthor, properties.Author); string strCfgTime; string[] strSplit, strSplit2; strSplit = properties.Time.ToString().Split(' '); strSplit2 = strSplit[0].Split('/'); strCfgTime = strSplit2[2] + '-' + strSplit2[1] + '-' + strSplit2[0] + 'T' + strSplit[1] + ".000000Z"; svnClient.SetRevisionProperty(new Uri(svnURL), infoEventArgs.Revision, SvnPropertyNames.SvnDate, strCfgTime); } }
private static void AddRevision(IVSSVersion version, bool deleted) { var key = new VssRevProps { Author = version.Username, Comment = version.Comment.Replace("\n", "").Replace("\t", "").Trim(), Time = version.Date }; var file = new VssFileVersion { Spec = version.VSSItem.Spec, VersionNumber = version.VersionNumber, Version = version, Action = version.Action, Deleted = deleted }; //Ignore branches and the root directory if (version.Action.Contains("Branched at version") || version.Action.ToLower().Contains("verzweigt bei version") || string.Compare("$/", file.Spec, true) == 0) { return; } //if pinned add to a special (and always last) revision if (version.VSSItem.IsPinned) { if (!revisions.ContainsKey(pinProps)) //if there is no pinprop revision, add one ... { revisions.Add(pinProps, new Dictionary <string, VssFileVersion>(StringComparer.CurrentCultureIgnoreCase) { { file.Spec, file } }); } else //else add file to pinprop revision { revisions[pinProps].Add(file.Spec, file); } } //filter duplicate labels if (!string.IsNullOrEmpty(version.Label)) { if (labellist.Contains(version.VSSItem.Spec)) { if (tagslist.Contains(version.Label)) { return; } tagslist.Add(version.Label); } else { labellist.Add(version.VSSItem.Spec); tagslist.Add(version.Label); } } //if revision is the same but file was not added yet, then ... if (revisions.Keys.Contains(key) && (!revisions[key].ContainsKey(file.Spec)))// || version.VSSItem.Type == (int) VSSItemType.VSSITEM_PROJECT)) { //Add the file to the existing revision if it exists searchLog.DebugFormat("Adding {0}:{1} to {2}", file.Spec, file.VersionNumber, key); revisions[key].Add(file.Spec, file); return; } if (revisions.Keys.Contains(key) && (revisions[key].ContainsKey(file.Spec))) { return; } //else revision has not been added yet, so ... var files = new Dictionary <string, VssFileVersion>(StringComparer.CurrentCultureIgnoreCase) { { file.Spec, file } }; searchLog.DebugFormat("New revision {0} {1}:{2}", key, file.Spec, file.VersionNumber); revisions.Add(key, files); return; }