/// <summary> /// Parses the changes into change objects. /// </summary> /// <param name="text">The text to parse change objects from.</param> /// <returns>A list of change objects. NOTE: If no items have been deleted, index = 0 will be null. If no items have been created, index = 1 will be null</returns> public static IList<AbstractChange> ParseChanges(String[] text) { if (text.Any(s => s == null)) throw new ArgumentNullException("text"); if (!text.Any()) throw new ArgumentException("Argument was empty"); IList<AbstractChange> parsedChanges = new List<AbstractChange>(); ItemsCreatedChange itemsCreated = null; ItemsDeletedChange itemsDeleted = null; parsedChanges.Add(itemsDeleted); parsedChanges.Add(itemsCreated); int pointer = 0; while (pointer < text.Length) { if (text[pointer].StartsWith(AbstractChange.ItemCreationMark)) { // An item has been created if (parsedChanges[1] == null) { parsedChanges[1] = new ItemsCreatedChange(); } // The item is a folder if (text[pointer].EndsWith(FileSystem.PathSeparator)) { if (parsedChanges[1] is ItemsCreatedChange) { ((ItemsCreatedChange)parsedChanges[1]).CreateItem(new FolderCreation(text[pointer].Substring(AbstractChange.ItemCreationMark.Length))); } pointer++; } else { IList<String> fileContents = new List<string>(); String createdFilePath = text[pointer].Substring(AbstractChange.ItemCreationMark.Length); pointer++; while (pointer < text.Length) { // No more modifications for this file if (text[pointer].Equals(AbstractChange.BlockSeparatorMark)) break; // Line insertion if (text[pointer].StartsWith(AbstractChange.LineInsertionMark)) { String lineNumber = text[pointer].Substring(AbstractChange.LineInsertionMark.Length); int tmp = lineNumber.IndexOf(AbstractChange.LineInsertionMark); String line = lineNumber.Substring(tmp + AbstractChange.LineInsertionMark.Length); fileContents.Add(line); pointer++; } } if (parsedChanges[1] is ItemsCreatedChange) { ((ItemsCreatedChange)parsedChanges[1]).CreateItem(new FileCreation(createdFilePath, fileContents.ToArray())); } } } else if (text[pointer].StartsWith(AbstractChange.ItemDeletionMark)) { // An item has been deleted String path = text[pointer].Substring(AbstractChange.ItemDeletionMark.Length); if (parsedChanges[0] == null) { parsedChanges[0] = new ItemsDeletedChange(); } if (parsedChanges[0] is ItemsDeletedChange) { ((ItemsDeletedChange)parsedChanges[0]).DeleteItem(path); } pointer++; } else if (text[pointer].StartsWith(AbstractChange.ItemModificationMark)) { // A file has been modified String path = text[pointer].Substring(AbstractChange.ItemModificationMark.Length); FileModifiedChange modified = new FileModifiedChange(path); pointer++; // Iterate through the file modifications until there are no more (end of file or linebreak) while (pointer < text.Length) { // No more modifications for this file if (text[pointer].Equals(AbstractChange.BlockSeparatorMark)) break; // Line insertion if (text[pointer].StartsWith(AbstractChange.LineInsertionMark)) { String lineNumber = text[pointer].Substring(AbstractChange.LineInsertionMark.Length); int tmp = lineNumber.IndexOf(AbstractChange.LineInsertionMark); int number = int.Parse(lineNumber.Substring(0, tmp)); String line = lineNumber.Substring(tmp + AbstractChange.LineInsertionMark.Length); modified.AddInsertion(number, line); pointer++; } // Line deletion if (text[pointer].StartsWith(AbstractChange.LineDeletionMark)) { String lineNumber = text[pointer].Substring(AbstractChange.LineDeletionMark.Length); int tmp = lineNumber.IndexOf(AbstractChange.LineDeletionMark); int number = int.Parse(lineNumber.Substring(0, tmp)); String line = lineNumber.Substring(tmp + AbstractChange.LineDeletionMark.Length); modified.AddDeletion(number, line); pointer++; } } parsedChanges.Add(modified); } if (pointer < text.Length && text[pointer].Equals(AbstractChange.BlockSeparatorMark)) { // Current line is empty pointer++; } } return parsedChanges; }
/// <summary> /// Compares the file modifications. /// </summary> /// <param name="relativePath">The relative path to the original file with respect to this version control system.</param> /// <param name="originalText">The original text.</param> /// <param name="latestText">The latest text.</param> /// <returns></returns> public static FileModifiedChange CompareFileModifications(String relativePath, string[] originalText, string[] latestText) { FileModifiedChange fileModified = new FileModifiedChange(relativePath); Contract.Requires(originalText != null && latestText != null); Contract.Requires(originalText.Length > 0 || latestText.Length > 0); int o = 0; int n = 0; while (o <= originalText.Length && n <= latestText.Length) { if (o == originalText.Length && n == latestText.Length) { // Both o and n point beyond their respective arrays. No more to merge break; } else if (o == originalText.Length && n != latestText.Length) { // All remaining lines in latestText are new for (int i = n; i < latestText.Length; i++) { fileModified.AddInsertion(i, latestText[i]); } break; } else if (o != originalText.Length && n == latestText.Length) { // The rest of lines in originalText have been removed for (; o < originalText.Length; o++) { fileModified.AddDeletion(o, originalText[o]); } break; } else if (originalText[o].Equals(latestText[n])) { // No changes have occured at this line o++; n++; } else if (!originalText[o].Equals(latestText[n])) { // A line has changed bool found = false; // Search all lines in latestText[t..end] for originalText[o] int t = n + 1; for (; t < latestText.Length; t++) { // Search was successfull if (originalText[o].Equals(latestText[t])) { found = true; break; } } if (!found) { // Line has been deleted fileModified.AddDeletion(o, originalText[o]); o++; } else { // Lines in latestText[n..t] was added for (; n < t; n++) { fileModified.AddInsertion(n, latestText[n]); } n++; o++; } } } return fileModified; }
/// <summary> /// Tries to save the folder according to the info shown in the view. /// If the folder can't be renamed or moved the change wont take effect. /// And the user is sent back to the info.aspx page /// </summary> protected void SaveChanges(object sender, EventArgs e) { string oldFolderName = _path.Substring(0, _path.LastIndexOf(@"\")); string newName = NameTextBox.Text; bool hasBeenMoved = !oldFolderName.Equals(FolderDropDown.SelectedItem.ToString()); bool hasBeenRenamed = !_name.Equals(newName); var vsc = VersionSystemFacade.GetVersionControlSystem(_path.Substring(4)); if (hasBeenRenamed) { FileModifiedChange modification = new FileModifiedChange(VersionSystemFacade.GetPathRelativeToRepository(_absolutPath)); modification.Rename(newName + "\\"); if (vsc.Save(modification) != null) { base.ShowWarning(); Response.Redirect("Info.aspx?path=" + _path); } } // respond URI is the orignal path (but might be with a new name) _responeUri = "info.aspx?path=Pie\\" + newName; if (hasBeenMoved) { string newFolder = FolderDropDown.SelectedItem.ToString().Substring(3) + @"\"; List<AbstractChange> fileMovedChanges = new List<AbstractChange>(); ICollection<AbstractChange> moveChanges = base.MoveFolder(_path.Substring(3), (newFolder + newName)); fileMovedChanges.AddRange(moveChanges); // Adds the move-changes to the version control system. // Sets the respond URI. if (vsc.Save(fileMovedChanges).Any()) { // If there was any errors while moving (returned a not-empty collction), // respond URI is the orignal path (but might be with a new name). _responeUri = "info.aspx?path=Pie\\" + newName; } else { // Else the respond URI is the new path. _responeUri = "info.aspx?path=Pie\\" + newFolder + newName; } } // Redirect to view the info.aspx page, for the current file. Response.Redirect(_responeUri); }