private void InlineDiff(Objects.Record old, Objects.Record newRecord) { if (old.Size > 10 * 1024 * 1024) { return; } string tmpOld = Utilities.DiffTool.GetTempFilename(); string tmpNew = Utilities.DiffTool.GetTempFilename(); Workspace.RestoreRecord(old, DateTime.Now, Path.GetFullPath(tmpOld)); try { if (Utilities.FileClassifier.Classify(new FileInfo(tmpOld)) != Utilities.FileEncoding.Binary) { try { Workspace.RestoreRecord(newRecord, DateTime.Now, Path.GetFullPath(tmpNew)); List <string> messages = Utilities.DiffFormatter.Run(Path.GetFullPath(tmpOld), Path.GetFullPath(tmpNew), old.Name, newRecord.Name, true, true); foreach (var x in messages) { Printer.PrintMessage(x); } } finally { System.IO.File.Delete(tmpNew); } } } finally { System.IO.File.Delete(tmpOld); } }
public ResolvedAlteration(Objects.Alteration alteration, Area ws) { Alteration = alteration; if (alteration.NewRecord.HasValue) { Record = ws.GetRecord(Alteration.NewRecord.Value); } else if (alteration.PriorRecord.HasValue) { Record = ws.GetRecord(Alteration.PriorRecord.Value); } else { throw new Exception("unexpected"); } }
private void FormatLog(Tuple <Objects.Version, int> vt, IEnumerable <KeyValuePair <bool, ResolvedAlteration> > filteralt, LogVerbOptions localOptions) { Objects.Version v = vt.Item1; if (m_LoggedVersions == null) { m_LoggedVersions = new HashSet <Guid>(); } m_LoggedVersions.Add(v.ID); Objects.Branch branch = null; if (!m_Branches.TryGetValue(v.Branch, out branch)) { branch = Workspace.GetBranch(v.Branch); m_Branches[v.Branch] = branch; } if (localOptions.Xml) { Printer.PrintMessage($" <version id='{v.ID}' parent='{v.Parent}' branch='{v.Branch}' timestamp='{v.Timestamp.ToString("o")}' author='{XmlAttr(v.Author)}' published='{v.Published}'>"); Printer.PrintMessage($" <message>{XmlText(v.Message)}</message>"); foreach (var y in Workspace.GetMergeInfo(v.ID)) { var mergeParent = Workspace.GetVersion(y.SourceVersion); Printer.PrintMessage($" <merge type='{y.Type.ToString().ToLower()}' version='{mergeParent.ID}' branch='{mergeParent.Branch}' />"); } if (localOptions.Detail == LogVerbOptions.DetailMode.Full) { foreach (var y in GetAlterations(v)) { string operationName = y.Alteration.Type.ToString().ToLower(); if (y.Alteration.Type == Objects.AlterationType.Copy || y.Alteration.Type == Objects.AlterationType.Move) { Objects.Record prior = Workspace.GetRecord(y.Alteration.PriorRecord.Value); Objects.Record next = Workspace.GetRecord(y.Alteration.NewRecord.Value); bool edited = (!next.IsDirectory && prior.DataIdentifier != next.DataIdentifier); Printer.PrintMessage($" <alteration type='{operationName}' path='{XmlAttr(next.CanonicalName)}' frompath='{XmlAttr(prior.CanonicalName)}' edited='{edited}' />"); } else { Printer.PrintMessage($" <alteration type='{operationName}' path='{y.Record.CanonicalName}' />"); } } } Printer.PrintMessage(" </version>"); } else if (localOptions.Jrunting) { // list of heads var heads = Workspace.GetHeads(v.ID); bool isHead = false; string headString = ""; foreach (var y in heads) { isHead = true; if (headString.Length != 0) { headString = headString + ", "; } headString += Workspace.GetBranch(y.Branch).Name; } // message up to first newline string message = v.Message; if (message == null) { message = string.Empty; } message = message.Replace("\r\n", "\n"); var idx = message.IndexOf('\n'); if (idx == -1) { idx = message.Length; } message = message.Substring(0, idx); string mergemarker = ""; if (Workspace.GetMergeInfo(v.ID).Count() > 0) { var m = Workspace.GetMergeInfo(v.ID).First(); var heads2 = Workspace.GetHeads(m.SourceVersion); if (heads2.Count > 0) { if (isHead) { mergemarker = " <- " + Workspace.GetBranch(heads2.First().Branch).Name; } else { mergemarker = "M: " + Workspace.GetBranch(heads2.First().Branch).Name; } } } var date = new DateTime(v.Timestamp.Ticks, DateTimeKind.Utc).ToShortDateString(); string pattern = "* #U#{0}## - "; if (isHead) { pattern += "#Y#({4}{5})## "; } else if (mergemarker.Length > 0) { pattern += "#Y#({5})## "; } pattern += "{1} "; var tagList = Workspace.GetTagsForVersion(v.ID); if (tagList.Count > 0) { pattern += "#I#[" + string.Join(" ", tagList.Select(x => "\\#" + x).ToArray()) + "]## "; } pattern += "#g#({2}, {3})##"; Printer.PrintMessage(pattern, v.ShortName, message, v.Author, date, headString, mergemarker); } else if (localOptions.Concise) { if (vt.Item2 != 0 && localOptions.Indent) { Printer.Prefix = " "; } var heads = Workspace.GetHeads(v.ID); bool isHead = false; foreach (var y in heads) { if (y.Branch == branch.ID) { isHead = true; break; } } string message = v.Message; if (message == null) { message = string.Empty; } string tipmarker = " "; if (v.ID == m_Tip.ID) { tipmarker = "#w#*##"; } string mergemarker = " "; if (Workspace.GetMergeInfo(v.ID).FirstOrDefault() != null) { mergemarker = "#s#M##"; } var tagList = Workspace.GetTagsForVersion(v.ID); string tags = ""; if (tagList.Count > 0) { tags = "#s#" + string.Join(" ", tagList.Select(x => "\\#" + x).ToArray()) + "## "; } Printer.PrintMessage($"{tipmarker}#c#{v.ShortName}:##{mergemarker}({v.Revision}/{(isHead ? "#i#" : "#b#")}{branch.Name}##)" + $"{message.Replace("\r\n", " ").Replace('\n', ' ')} {tags}" + $"#q#({v.Author} {new DateTime(v.Timestamp.Ticks, DateTimeKind.Utc).ToShortDateString()})##"); Printer.Prefix = ""; } else { Printer.PrintMessage(""); if (vt.Item2 != 0 && localOptions.Indent) { Printer.Prefix = "| "; } string tipmarker = ""; if (v.ID == m_Tip.ID) { tipmarker = " #w#*<current>##"; } Printer.PrintMessage("({0}) #c#{1}## on branch #b#{2}##{3}", v.Revision, v.ID, branch.Name, tipmarker); var mergeInfo = Workspace.GetMergeInfo(v.ID); foreach (var y in mergeInfo) { var mergeParent = Workspace.GetVersion(y.SourceVersion); Objects.Branch mergeBranch = null; if (!m_Branches.TryGetValue(mergeParent.Branch, out mergeBranch)) { mergeBranch = Workspace.GetBranch(mergeParent.Branch); m_Branches[mergeParent.Branch] = mergeBranch; } Printer.PrintMessage(" <- Merged from #s#{0}## on branch #b#{1}##", mergeParent.ID, mergeBranch.Name); } var heads = Workspace.GetHeads(v.ID); foreach (var y in heads) { Objects.Branch headBranch = null; if (!m_Branches.TryGetValue(y.Branch, out headBranch)) { headBranch = Workspace.GetBranch(y.Branch); m_Branches[y.Branch] = headBranch; } string branchFlags = string.Empty; if (branch.Terminus.HasValue) { branchFlags = " #e#(deleted)##"; } Printer.PrintMessage(" ++ #i#Head## of branch #b#{0}## (#b#\"{1}\"##){2}", headBranch.ID, headBranch.Name, branchFlags); } if (branch.Terminus == v.ID) { Printer.PrintMessage(" ++ #i#Terminus## of #e#deleted branch## #b#{0}## (#b#\"{1}\"##)", branch.ID, branch.Name); } Printer.PrintMessage("#b#Author:## {0} #q# {1} ##", v.Author, v.Timestamp.ToLocalTime()); var tagList = Workspace.GetTagsForVersion(v.ID); if (tagList.Count > 0) { Printer.PrintMessage(" #s#" + string.Join(" ", tagList.Select(x => "\\#" + x).ToArray()) + "##"); } Printer.PrintMessage(""); Printer.PushIndent(); Printer.PrintMessage("{0}", string.IsNullOrWhiteSpace(v.Message) ? "<none>" : Printer.Escape(v.Message)); Printer.PopIndent(); if (localOptions.Detail == LogVerbOptions.DetailMode.Detailed || localOptions.Detail == LogVerbOptions.DetailMode.Full) { var alterations = localOptions.Detail == LogVerbOptions.DetailMode.Detailed ? filteralt.Select(z => z.Value) : GetAlterations(v); if (localOptions.Detail == LogVerbOptions.DetailMode.Full) { Printer.PrintMessage(""); Printer.PrintMessage("#b#Alterations:##"); foreach (var y in alterations.OrderBy(z => z.Alteration.Type)) { if (y.Alteration.Type == Objects.AlterationType.Move || y.Alteration.Type == Objects.AlterationType.Copy) { string operationName = y.Alteration.Type.ToString().ToLower(); Objects.Record prior = Workspace.GetRecord(y.Alteration.PriorRecord.Value); Objects.Record next = Workspace.GetRecord(y.Alteration.NewRecord.Value); bool isUpdate = false; if (y.Alteration.Type == Objects.AlterationType.Move && !next.IsDirectory && prior.DataIdentifier != next.DataIdentifier) { isUpdate = true; operationName = "refactor"; } Printer.PrintMessage("#{2}#({0})## {1}\n <- #q#{3}##", operationName, y.Record.CanonicalName, GetAlterationFormat(y.Alteration.Type), prior.CanonicalName); if (localOptions.Diff && isUpdate) { InlineDiff(prior, next); } } else { Printer.PrintMessage("#{2}#({0})## {1}", y.Alteration.Type.ToString().ToLower(), y.Record.CanonicalName, GetAlterationFormat(y.Alteration.Type)); if (localOptions.Diff && y.Alteration.Type == Objects.AlterationType.Update) { InlineDiff(Workspace.GetRecord(y.Alteration.PriorRecord.Value), Workspace.GetRecord(y.Alteration.NewRecord.Value)); } } } } else { int[] alterationCounts = new int[5]; foreach (var y in alterations) { alterationCounts[(int)y.Alteration.Type]++; } bool first = true; string formatData = ""; for (int i = 0; i < alterationCounts.Length; i++) { if (alterationCounts[i] != 0) { if (!first) { formatData += ", "; } else { formatData += " "; } first = false; formatData += string.Format("#{2}#{0}s: {1}##", ((Objects.AlterationType)i).ToString(), alterationCounts[i], GetAlterationFormat((Objects.AlterationType)i)); } } if (formatData.Length > 0) { Printer.PrintMessage(""); Printer.PrintMessage("#b#Alterations:##"); Printer.PrintMessage(formatData); } } } else if (FilterOptions.Objects.Count != 0) { Printer.PrintMessage(""); Printer.PrintMessage("#b#Alterations:##"); List <KeyValuePair <string, ResolvedAlteration> > altList = new List <KeyValuePair <string, ResolvedAlteration> >(); foreach (var y in GetAlterations(v)) { string recName = y.Record.CanonicalName; altList.Add(new KeyValuePair <string, ResolvedAlteration>(recName, y)); } if (localOptions.Diff) { var records = FilterObjects(altList) .SelectMany(x => new[] { x.Value.Alteration.PriorRecord, x.Value.Alteration.NewRecord }) .Where(x => x.HasValue) .Select(x => Workspace.GetRecord(x.Value)); Workspace.GetMissingObjects(records, null); } foreach (var y in FilterObjects(altList).Select(x => x.Value)) { if (y.Alteration.Type == Objects.AlterationType.Move || y.Alteration.Type == Objects.AlterationType.Copy) { string operationName = y.Alteration.Type.ToString().ToLower(); Objects.Record prior = Workspace.GetRecord(y.Alteration.PriorRecord.Value); Objects.Record next = Workspace.GetRecord(y.Alteration.NewRecord.Value); bool isUpdate = false; if (y.Alteration.Type == Objects.AlterationType.Move && !next.IsDirectory && prior.DataIdentifier != next.DataIdentifier) { isUpdate = true; operationName = "refactor"; } Printer.PrintMessage("#{2}#({0})## {1}\n <- #q#{3}##", operationName, y.Record.CanonicalName, GetAlterationFormat(y.Alteration.Type), prior.CanonicalName); if (localOptions.Diff && isUpdate) { InlineDiff(prior, next); } } else { Printer.PrintMessage("#{2}#({0})## {1}", y.Alteration.Type.ToString().ToLower(), y.Record.CanonicalName, GetAlterationFormat(y.Alteration.Type)); if (localOptions.Diff && y.Alteration.Type == Objects.AlterationType.Update) { InlineDiff(Workspace.GetRecord(y.Alteration.PriorRecord.Value), Workspace.GetRecord(y.Alteration.NewRecord.Value)); } } } } Printer.Prefix = ""; // Same-branch merge revisions. This only sort-of respects the limit :( //foreach (var y in mergeInfo) //{ // var mergeParent = Workspace.GetVersion(y.SourceVersion); // if (mergeParent.Branch == v.Branch) // { // Printer.PushIndent(); // Printer.PrintMessage("---- Merged versions ----"); // List<Objects.Version> mergedVersions = new List<Objects.Version>(); // var p = mergeParent; // do // { // mergedVersions.Add(p); // if (p.Parent.HasValue && !m_LoggedVersions.Contains(p.Parent.Value)) // p = Workspace.GetVersion(p.Parent.Value); // else // p = null; // } while (p != null); // foreach (var a in ApplyHistoryFilter(mergedVersions, localOptions)) // FormatLog(a.Item1, a.Item2, localOptions); // Printer.PrintMessage("-------------------------"); // Printer.PopIndent(); // } //} } }
protected override bool RunInternal(Area ws, Versionr.Status status, IList <Versionr.Status.StatusEntry> targets, FileBaseCommandVerbOptions options) { DiffVerbOptions localOptions = options as DiffVerbOptions; Objects.Version version = null; Objects.Version parent = null; if (!string.IsNullOrEmpty(localOptions.Version)) { version = Workspace.GetPartialVersion(localOptions.Version); if (version == null) { Printer.PrintError("No version found matching {0}", localOptions.Version); return(false); } if (version.Parent.HasValue) { parent = Workspace.GetVersion(version.Parent.Value); } if (parent == null) { Printer.PrintMessage("Version {0} has no parent", version.ID); return(true); } Printer.PrintMessage("Showing changes for version #c#{0}", version.ID); } bool showUnchangedObjects = localOptions.Objects.Count != 0; List <Task> tasks = new List <Task>(); List <string> tempFiles = new List <string>(); List <System.Diagnostics.Process> diffProcesses = new List <System.Diagnostics.Process>(); try { if (version == null) { foreach (var x in targets) { if (x.VersionControlRecord != null && !x.IsDirectory && x.FilesystemEntry != null && (x.Code == StatusCode.Modified || x.Code == StatusCode.Conflict)) { if (localOptions.Recorded && x.Staged == false) { continue; } if (x.Code == StatusCode.Conflict) { Printer.PrintMessage("Object: #b#{0}## is #w#conflicted##.", x.CanonicalName); } if (Utilities.FileClassifier.Classify(x.FilesystemEntry.Info) == Utilities.FileEncoding.Binary) { Printer.PrintMessage("File: #b#{0}## is binary #w#different##.", x.CanonicalName); continue; } // Displaying local modifications string tmp = Utilities.DiffTool.GetTempFilename(); if (Workspace.ExportRecord(x.CanonicalName, Workspace.Version, tmp)) { Printer.PrintMessage("Displaying changes for file: #b#{0}", x.CanonicalName); if (localOptions.External || localOptions.ExternalNonBlocking) { tempFiles.Add(tmp); bool nonblocking = Workspace.Directives.NonBlockingDiff.HasValue && Workspace.Directives.NonBlockingDiff.Value; nonblocking |= localOptions.ExternalNonBlocking; var t = GetTaskFactory(options).StartNew(() => { var diffResult = Utilities.DiffTool.Diff(tmp, x.Name + "-base", System.IO.Path.Combine(Workspace.RootDirectory.FullName, Workspace.GetLocalCanonicalName(x.VersionControlRecord)), x.Name, ws.Directives.ExternalDiff, nonblocking); if (diffResult != null) { lock (diffProcesses) { diffProcesses.Add(diffResult); } } }); if (nonblocking) { tasks.Add(t); } else { t.Wait(); } } else { try { RunInternalDiff(tmp, System.IO.Path.Combine(Workspace.RootDirectory.FullName, Workspace.GetLocalCanonicalName(x.VersionControlRecord)), !localOptions.KeepTabs, Workspace.GetLocalCanonicalName(x.VersionControlRecord)); } finally { new System.IO.FileInfo(tmp).IsReadOnly = false; System.IO.File.Delete(tmp); } } } } else if (x.Code == StatusCode.Unchanged && showUnchangedObjects && !x.IsDirectory) { var filter = Filter(new KeyValuePair <string, Objects.Record>[] { new KeyValuePair <string, Objects.Record>(x.CanonicalName, x.VersionControlRecord) }).FirstOrDefault(); if (filter.Value != null && filter.Key == true) // check if the file was really specified { Printer.PrintMessage("Object: #b#{0}## is #s#unchanged##.", x.CanonicalName); } } else if (x.VersionControlRecord == null && showUnchangedObjects) { var filter = Filter(new KeyValuePair <string, bool>[] { new KeyValuePair <string, bool>(x.CanonicalName, true) }).FirstOrDefault(); if (filter.Value != false && filter.Key == true) // check if the file was really specified { Printer.PrintMessage("Object: #b#{0}## is #c#unversioned##.", x.CanonicalName); } } } } else { if (localOptions.Local) { var records = ws.GetRecords(version); Dictionary <string, Objects.Record> recordMap = new Dictionary <string, Objects.Record>(); foreach (var x in records) { recordMap[x.CanonicalName] = x; } foreach (var x in targets) { if (localOptions.Recorded && x.Staged == false) { continue; } Objects.Record otherRecord = null; if (recordMap.TryGetValue(x.CanonicalName, out otherRecord) && !otherRecord.IsDirectory) { if (x.VersionControlRecord != null && x.VersionControlRecord.DataIdentifier == otherRecord.DataIdentifier) { continue; } if (x.FilesystemEntry != null && otherRecord.Fingerprint == x.FilesystemEntry.Hash && otherRecord.Size == x.FilesystemEntry.Length) { continue; } if (Utilities.FileClassifier.Classify(x.FilesystemEntry.Info) == Utilities.FileEncoding.Binary) { Printer.PrintMessage("File: #b#{0}## is binary #w#different##.", x.CanonicalName); continue; } string tmp = Utilities.DiffTool.GetTempFilename(); if (Workspace.ExportRecord(x.CanonicalName, version, tmp)) { Printer.PrintMessage("Displaying changes for file: #b#{0}", x.CanonicalName); if (localOptions.External || localOptions.ExternalNonBlocking) { tempFiles.Add(tmp); bool nonblocking = Workspace.Directives.NonBlockingDiff.HasValue && Workspace.Directives.NonBlockingDiff.Value; nonblocking |= localOptions.ExternalNonBlocking; var t = GetTaskFactory(options).StartNew(() => { var diffResult = Utilities.DiffTool.Diff(tmp, x.Name + "-base", Workspace.GetLocalCanonicalName(x.VersionControlRecord), x.Name, ws.Directives.ExternalDiff, nonblocking); if (diffResult != null) { lock (diffProcesses) { diffProcesses.Add(diffResult); } } }); if (nonblocking) { tasks.Add(t); } else { t.Wait(); } } else { try { RunInternalDiff(tmp, System.IO.Path.Combine(Workspace.RootDirectory.FullName, Workspace.GetLocalCanonicalName(x.VersionControlRecord)), !localOptions.KeepTabs, Workspace.GetLocalCanonicalName(x.VersionControlRecord)); } finally { System.IO.File.Delete(tmp); } } } } else { Printer.PrintMessage("File: #b#{0}## is not in other version.", x.CanonicalName); } } } else { List <KeyValuePair <string, Objects.Record> > updates = ws.GetAlterations(version) .Where(x => x.Type == Objects.AlterationType.Update) .Select(x => ws.GetRecord(x.NewRecord.Value)) .Select(x => new KeyValuePair <string, Objects.Record>(x.CanonicalName, x)).ToList(); foreach (var pair in Filter(updates)) { Objects.Record rec = pair.Value; string tmpVersion = Utilities.DiffTool.GetTempFilename(); if (!Workspace.ExportRecord(rec.CanonicalName, version, tmpVersion)) { continue; } string tmpParent = Utilities.DiffTool.GetTempFilename(); if (!Workspace.ExportRecord(rec.CanonicalName, parent, tmpParent)) { System.IO.File.Delete(tmpVersion); continue; } Printer.PrintMessage("Displaying changes for file: #b#{0}", rec.CanonicalName); if (localOptions.External || localOptions.ExternalNonBlocking) { bool nonblocking = Workspace.Directives.NonBlockingDiff.HasValue && Workspace.Directives.NonBlockingDiff.Value; nonblocking |= localOptions.ExternalNonBlocking; tempFiles.Add(tmpVersion); tempFiles.Add(tmpParent); var t = GetTaskFactory(options).StartNew(() => { var diffResult = Utilities.DiffTool.Diff(tmpParent, rec.Name + "-" + parent.ShortName, tmpVersion, rec.Name + "-" + version.ShortName, ws.Directives.ExternalDiff, nonblocking); if (diffResult != null) { lock (diffProcesses) { diffProcesses.Add(diffResult); } } }); if (nonblocking) { tasks.Add(t); } else { t.Wait(); } } else { try { RunInternalDiff(tmpParent, tmpVersion, !localOptions.KeepTabs, rec.CanonicalName); } finally { System.IO.File.Delete(tmpVersion); System.IO.File.Delete(tmpParent); } } } } } } finally { Task.WaitAll(tasks.ToArray()); foreach (var x in diffProcesses) { x.WaitForExit(); } foreach (var x in tempFiles) { System.IO.File.Delete(x); } } return(true); }
public ResolvedAlteration(Objects.Alteration alteration, Area ws) { Alteration = alteration; if (alteration.NewRecord.HasValue) Record = ws.GetRecord(Alteration.NewRecord.Value); else if (alteration.PriorRecord.HasValue) Record = ws.GetRecord(Alteration.PriorRecord.Value); else throw new Exception("unexpected"); }
public abstract bool HasData(Objects.Record recordInfo, out List <string> requestedData);
public abstract System.IO.Stream GetRecordStream(Objects.Record record);
public abstract bool RecordData(ObjectStoreTransaction transaction, Objects.Record newRecord, Objects.Record priorRecord, Entry fileEntry);