/// <summary>
		/// The only entry point in the class. This method (plus its private methods) does the work of the class.
		/// </summary>
		/// <param name="pathname">Pathname of the split up file that contains <paramref name="element"/>.</param>
		/// <param name="sortedData">All of the data being collected that will end up as CmObject elments in the rebuilt fwdata file. These are sorted by guid order.</param>
		/// <param name="element">The xml element to check for a duplicate guid.</param>
		/// <param name="isOwnSeqNode">Out paramenter that is used by caller.</param>
		/// <param name="className">The class of <paramref name="element"/>.</param>
		/// <returns></returns>
		internal static string CheckForDuplicateGuid(string pathname, SortedDictionary<string, XElement> sortedData, XElement element, out bool isOwnSeqNode, out string className)
		{
			var mdc = MetadataCache.MdCache;
			FdoClassInfo classInfo;
			isOwnSeqNode = GetClassInfoFromElement(mdc, element, out classInfo, out className);
			var elementGuid = element.Attribute(SharedConstants.GuidStr).Value.ToLowerInvariant();

			if (!sortedData.ContainsKey(elementGuid))
				return elementGuid;

			// Does LT-12524 "Handle merge in case of conflicting move object to different destination".
			// This need will manifest itself in the guid already being in 'sortedData' and an exception being thrown.
			// At this point element has not been flattened, so stuff it owns will still be in it.
			// That is good, if we go with JohnT's idea of using a new guid for guids that are already in 'sortedData'.
			// By changing it before flattening, then the owned stuff will get the new one for their ownerguid attrs.
			// The owned stuff will also be dup, so the idea is to also change their guids right now. [ChangeGuids is recursive down the owning tree.]
			// Just be sure to change 'elementGuid' to the new one. :-)
			// The first item added to sortedData has been flattened by this point, but not any following ones.
			var oldGuid = elementGuid;
			elementGuid = ChangeGuids(mdc, classInfo, element);
			using (var listener = new ChorusNotesMergeEventListener(ChorusNotesMergeEventListener.GetChorusNotesFilePath(pathname)))
			{
				// Don't try to use something like this:
				// var contextGenerator = new FieldWorkObjectContextGenerator();
				// contextGenerator.GenerateContextDescriptor(element.ToString(), pathname)
				// it will fail for elements in an owning sequence because in the unflattened form
				// the object representing a sequence item has element name <ownseq> which won't generate a useful label.
				var context = FieldWorksMergeServices.GenerateContextDescriptor(pathname, elementGuid, className);
				listener.EnteringContext(context);
				// Adding the conflict to the listener, will result in the ChorusNotes file being updated (created if need be.)
				var conflict = new IncompatibleMoveConflict(className, CmObjectFlatteningService.GetXmlNode(element)) { Situation = new NullMergeSituation() };
				// The order of the next three lines is critical. Each prepares state that the following lines use.
				listener.RecordContextInConflict(conflict);
				conflict.HtmlDetails = MakeHtmlForIncompatibleMove(conflict, oldGuid, elementGuid, element);
				listener.ConflictOccurred(conflict);
				File.WriteAllText(pathname + "." + SharedConstants.dupid, "");
			}
			return elementGuid;
		}
 public void FileOutput_WithContent_UsesCanonicalXmlSettings()
 {
     string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
         + "<notes\r\n"
         + "\tversion=\"0\">\r\n"
         + "\t<annotation>Dummy</annotation>\r\n"
         + "</notes>";
     using (var logFile = TempFile.CreateAndGetPathButDontMakeTheFile())
     {
         using (var log = new ChorusNotesMergeEventListener(logFile.Path))
         {
             log.ConflictOccurred(new DummyConflict());
         }
         string result = File.ReadAllText(logFile.Path);
         Assert.AreEqual(expected, result);
     }
 }
 public void FileDidNotExist_CreatesCorrectFile()
 {
     using (TempFile logFile = TempFile.CreateAndGetPathButDontMakeTheFile())
     {
         using (ChorusNotesMergeEventListener log = new ChorusNotesMergeEventListener(logFile.Path))
         {
             log.ConflictOccurred(new DummyConflict());
             log.ConflictOccurred(new DummyConflict());
         }
         XmlDocument doc = new XmlDocument();
         doc.Load(logFile.Path);
         Assert.AreEqual(2, doc.SelectNodes("notes/annotation").Count);
     }
 }
Esempio n. 4
0
        /// <summary>
        /// This method will detect changed vs deleted file conflicts in the output coming from mercurial.
        /// It produces a conflict for that situation and tells mercurial to keep the changed file.
        /// <note>The default response for mercurial is to keep the changed, but on some user systems (Windows 8?)
        /// mercurial will pause waiting for input instead of using the default answer.</note>
        /// </summary>
        private bool HandleChangedVsDeletedFiles(string line, StreamWriter standardInput)
        {
            // The two situations we are dealing with are:
            //
            // local changed [filename] which remote deleted
            // use (c)hanged version or (d)elete?
            //		and
            // remote changed [filename] which local deleted
            // use (c)hanged version or leave (d)eleted?

            string changedVsDeletedFile = null;
            var match = Regex.Match(line, @"local changed (.*) which remote deleted");
            if(match.Captures.Count > 0)
            {
                changedVsDeletedFile = match.Groups[1].Value;
            }
            else
            {
                match = Regex.Match(line, @"remote changed (.*) which local deleted");
                if(match.Captures.Count > 0)
                {
                    changedVsDeletedFile = match.Groups[1].Value;
                }
            }
            if(changedVsDeletedFile != null)
            {
                var conflictPath = Path.Combine(_rootDirectory, changedVsDeletedFile);
                var conflictReport = new FileChangedVsFileDeletedConflict(conflictPath);
                using(var chorusNoteCreator = new ChorusNotesMergeEventListener(ChorusNotesMergeEventListener.GetChorusNotesFilePath(conflictPath)))
                {
                    chorusNoteCreator.ConflictOccurred(conflictReport);
                }
                return true;
            }
            // Send hg the response it might be waiting for:
            if(line.Contains(@"(c)hanged") && line.Contains(@"(d)elete"))
            {
                standardInput.WriteLine('c');
                return true;
            }
            // This input line was not related to a Changed vs Deleted File situation
            return false;
        }