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;
		}
Beispiel #2
0
		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;
		}