public List<Commit> Load() { Commit commit = null; var commits = new List<Commit>(); var commitRx = new Regex(@"^Commit:(?<at>[0-9]+)\t\tUser:(?<user>.+)\t\tComment:(?<comment>.*)$"); using(var r = File.OpenText(DataFileName)) { string line; while((line = r.ReadLine())!=null) { if(line.StartsWith(" ")) { var arr = line.Substring(1).Split(':'); Debug.Assert(arr.Length == 3); Debug.Assert(commit != null); commit.AddRevision(new FileRevisionLite { FileSpec = arr[2], VssVersion = Int32.Parse(arr[0]), At = new DateTime(Int64.Parse(arr[1]), DateTimeKind.Utc) }); } else { var m = commitRx.Match(line); if(m.Success) { commit = new Commit { At = new DateTime(long.Parse(m.Groups["at"].Value), DateTimeKind.Utc), User = m.Groups["user"].Value, Comment = DeserializeMultilineText(m.Groups["comment"].Value) }; commits.Add(commit); } } } } return commits; }
void LoadRevision(IDestinationDriver driver, Commit commit, StreamWriter log) { var added = new List<string>(); foreach (var file in commit.Files) { var filePath = _cache.GetFilePath(file.FileSpec, file.VssVersion); if(filePath == null) { Debugger.Break(); log.WriteLine("File {0}@{1} absent in cache. Rerun 'VssSvnConverter build-cache'", file.FileSpec, file.VssVersion); Console.Error.WriteLine("File {0}@{1} absent in cache. Rerun 'VssSvnConverter build-cache'", file.FileSpec, file.VssVersion); Environment.Exit(1); } var relPath = file.FileSpec.TrimStart('$', '/', '\\'); // mangle path if (_opts.MangleImportPath.Count > 0) { foreach (var manglePair in _opts.MangleImportPath) { relPath = manglePair.Item1.Replace(relPath, manglePair.Item2); } } // special mode for check unimportant differenrces if (_opts.ImportUnimportantOnly && !_unimportants.Any(t => t.Item1.IsMatch(relPath.ToLowerInvariant().Replace('\\', '/').Trim('/')))) continue; log.WriteLine("Load: {0} -> {1}", file, relPath); var dstPath = Path.Combine(driver.WorkingCopy, relPath); var dstDir = Path.GetDirectoryName(dstPath); Debug.Assert(dstDir != null); if(!Directory.Exists(dstDir)) driver.AddDirectory(dstDir); var addToVcs = !File.Exists(dstPath); if(File.Exists(dstPath)) { File.Delete(dstPath); log.WriteLine("Deleted: {0}", dstPath); } if(_useHardLink) { _useHardLink = CreateHardLink(dstPath, filePath, IntPtr.Zero); log.WriteLine("CreateHl: {0} -> {1} result: {2}", filePath, dstPath, _useHardLink); } if(!_useHardLink) { File.Copy(filePath, dstPath, true); log.WriteLine("Copy: {0} -> {1}", filePath, dstPath); } // git can not detect modifications if MTime not updated File.SetLastWriteTimeUtc(filePath, DateTime.UtcNow); if(addToVcs) added.Add(dstPath); // file can be modified in place if it is not hardlink var canBeModifiedInplace = !_useHardLink; Action<bool> prepareForModifyInplace = recuireContent => { if (canBeModifiedInplace) return; // make copy of file instead of hardlink File.Delete(dstPath); if (recuireContent) { File.Copy(filePath, dstPath, true); log.WriteLine("Copy: {0} -> {1}", filePath, dstPath); } canBeModifiedInplace = true; }; DoCensoring(driver.WorkingCopy, dstPath, _censors, prepareForModifyInplace); if (!addToVcs && _unimportants.Count > 0) RevertUnimportant(driver, dstPath, relPath, prepareForModifyInplace); } if(added.Count > 0) driver.AddFiles(added.ToArray()); }
void BuildCommitComment(int commitIndex, Commit cmt, IEnumerable<string> comments) { var sb = new StringBuilder(); if(comments != null) { foreach (var c in comments) { if (sb.Length > 0) sb.AppendLine("---"); sb.AppendLine(c); } } if (_opts.CommentAddVssFilesInfo && cmt.Files.Count() > 1) { if (sb.Length > 0) sb.AppendLine("==="); sb.AppendFormat("@Files:"); foreach (var file in cmt.Files) sb.AppendFormat("\n\t{0} {1}@{2}", file.At, file.FileSpec, file.VssVersion); } if(_opts.CommentAddUserTime) { var commitInfo = string.Format("{{{1} by {0}}}", cmt.User4Comment ?? cmt.User, cmt.At.ToString("yyyy-MMM-dd HH:ss:mm", CultureInfo.InvariantCulture)); if (sb.Length > 0) { if (sb.ToString().Trim().IndexOf('\n') != -1) sb.Insert(0, "\n"); else sb.Insert(0, " "); sb.Insert(0, ":"); } sb.Insert(0, commitInfo); } if(_opts.CommentAddCommitNumber) { sb.Insert(0, string.Format("Commit#{0}\n", commitIndex + 1)); } cmt.Comment = sb.ToString().Trim(); }
List<Commit> SliceToCommits(IEnumerable<FileRevision> revs) { var currentUserCommits = new Dictionary<string, Commit>(); var returnCommits = new List<Commit>(); var commitComments = new Dictionary<Commit, List<string>>(); foreach (var rev in revs) { // commits flushing var forRemove = new List<string>(); foreach (var kvp in currentUserCommits) { var commit = kvp.Value; // out of silence period ? if((rev.At - commit.LastChangeAt) > _opts.SilentSpan) { forRemove.Add(kvp.Key); continue; } // file already in one of commit if(commit.ContainsFile(rev.FileSpec)) { // flush commit if merge changes disallowd or if file participate in other user commit if(!_opts.MergeChanges || commit.User != rev.User) { forRemove.Add(kvp.Key); continue; } } // if overlapping not allowed - flush all users, except current revision user if(!_opts.OverlapCommits && commit.User != rev.User) { forRemove.Add(kvp.Key); continue; } } forRemove.ForEach(k => currentUserCommits.Remove(k)); // get/create current commit Commit cmt; if(!currentUserCommits.TryGetValue(rev.User, out cmt)) { cmt = new Commit { At = rev.At, User = rev.User, User4Comment = rev.User4Comment }; currentUserCommits.Add(rev.User, cmt); returnCommits.Add(cmt); } // add file revision cmt.AddRevision(new FileRevisionLite { FileSpec = rev.FileSpec, VssVersion = rev.VssVersion, At = rev.At }); if(!string.IsNullOrWhiteSpace(rev.Comment)) { List<string> comments; if (!commitComments.TryGetValue(cmt, out comments)) { commitComments[cmt] = comments = new List<string>(); } if(!string.IsNullOrWhiteSpace(rev.Comment)) { var comment = rev.Comment.Trim(); if (!comments.Contains(comment)) comments.Add(comment); } } } // build commit comments for (int i = 0; i < returnCommits.Count; i++) { var cmt = returnCommits[i]; List<string> comments; commitComments.TryGetValue(cmt, out comments); BuildCommitComment(i, cmt, comments); } return returnCommits; }