The description of the changed text file.
Example #1
0
        /// <summary>
        /// Gets the change from the repository
        /// Returns null if any error occurs, or the change is not pending.
        /// </summary>
        /// <param name="changeId"> shelveset identifier. </param>
        /// <param name="includeBranchedFiles"> Include full text for branched and integrated files. </param>
        /// <returns> The change. </returns>
        public Change GetChange(string changeId, bool includeBranchedFiles)
        {
            if (!File.Exists(diffFromSvnBatFilename))
            {
                Console.WriteLine("difffromsvn.bat does not exist in the same directory as review.exe.");
                Console.WriteLine(" This batch file must run 'diff.exe %6 %7'");
                return null;
            }

            // first get the list of all files (including paths):
            // svn status --changelist xxx
            string result = RunClient(@"status --changelist """ + changeId + "\" \"" + localRoot + "\" ", false);

            StringReader sr = new StringReader(result);
            string line = null;

            bool seenDash = false;

            Regex fileAfterSpaceRegEx = new Regex(@"^(?<changetype>.).......(?<filename>(\S)+)$");

            List<ChangeFile> files = new List<ChangeFile>();

            // Results look like this:
            //--- Changelist 'mine':
            //        util\VisitorPrefsGetter.java
            //M       util\VisitorPrefsEidMigrator.java

            // Rules:
            // skip past first line that begins with "-"
            // then for each line, get the filename by finding the first non-whitespace after a white-space
            while ((line = sr.ReadLine()) != null)
            {
                if (!seenDash)
                {
                    if ((line.Length > 0) && (line[0] == '-'))
                    {
                        seenDash = true;
                    }
                    continue;
                }

                Match match = fileAfterSpaceRegEx.Match(line);
                if (!match.Success)
                {
                    Console.WriteLine("Could not interpret svn status output: " + line);
                    return null;
                }

                // what type of change is it?
                string typeOfChange = match.Groups[2].Value;
                if (typeOfChange.Length == 0)
                {
                    // no change, skip this
                    continue;
                }
                ChangeFile.SourceControlAction action = ChangeFile.SourceControlAction.EDIT;

                switch (typeOfChange)
                {
                    case "C":   // conflicted
                    case "M":   // modified
                    case "R":   // replaced
                    case " ":   // no change but added to the changelist
                        action = ChangeFile.SourceControlAction.EDIT;
                        break;
                    case "D":   // deleted
                    case "!":
                        action = ChangeFile.SourceControlAction.DELETE;
                        break;
                    case "I":   // ignored
                    case "A":   // added
                        action = ChangeFile.SourceControlAction.ADD;
                        break;
                    case "?":   // not under version control
                        break;
                    default:
                        // unexpected
                        Console.WriteLine("Unexpected change type: " + typeOfChange);
                        return null;
                }

                // this is the filename
                string filename = match.Groups[3].Value;

                bool isText = false;
                // get the mime-type to see if it's text
                string mimetype = RunClient("propget svn:mime-type " + "\"" + filename + "\"", false);
                if (mimetype == null || mimetype.StartsWith("text") || mimetype.Length == 0)
                {
                    isText = true;
                }

                // get the current revision
                string serverFilename = null;
                int revisionId = GetRevisionFromFile(filename, ref serverFilename);

                ChangeFile cf = new ChangeFile(serverFilename, action, revisionId, isText);
                cf.LocalFileName = filename;
                files.Add(cf);
            }

            if (!seenDash)
                return null;

            if (files.Count > 0)
            {
                // TODO: figure out name of client and description
                Change change = new Change(SourceControl, Client, changeId,
                    DateTime.Now.ToUniversalTime(), changeId, files.ToArray());

                FillInFileData(change);
                return change;
            }

            return null;
        }
Example #2
0
        /// <summary>
        /// Gets the change from the shelveset.
        /// Returns null if any error occurs, or the change is not pending.
        /// </summary>
        /// <param name="changeId"> shelveset identifier. </param>
        /// <param name="includeBranchedFiles"> Include full text for branched and integrated files. </param>
        /// <returns> The change. </returns>
        Change ISourceControl.GetChange(string changeId, bool includeBranchedFiles)
        {
            bool getFilesFromShelveSet = Tfs.GetFilesFromShelveSet;
            Debug.Assert(Tfs.GetFilesFromShelveSet || Workspace != null);

            string shelvesetName = changeId;
            string shelvesetOwner = TfsServer.AuthenticatedUserName;

            Shelveset shelveset = null;
            PendingSet[] sets = null;

            {
                var nameAndOwner = changeId.Split(new char[] { ';' });
                if (nameAndOwner.Length == 2)
                {
                    shelvesetName = nameAndOwner[0];
                    shelvesetOwner = nameAndOwner[1];
                }

                Shelveset[] shelvesets = VcsServer.QueryShelvesets(shelvesetName, shelvesetOwner);
                if (shelvesets.Length != 1)
                {
                    if (shelvesets.Count() == 0)
                        Console.WriteLine("Change not found.");
                    else
                        Console.WriteLine("Ambiguous change name.");

                    return null;
                }

                shelveset = shelvesets.First();

                if (getFilesFromShelveSet)
                    sets = VcsServer.QueryShelvedChanges(shelvesetName, shelvesetOwner, null, true);
                else
                    sets = VcsServer.QueryShelvedChanges(shelveset);
            }

            List<ChangeFile> files = new List<ChangeFile>();
            foreach (PendingSet set in sets)
            {
                PendingChange[] changes = set.PendingChanges;
                foreach (PendingChange change in changes)
                {
                    ChangeFile.SourceControlAction action;
                    string originalFileName = null;
                    if (change.ChangeTypeName.Equals("edit"))
                    {
                        action = ChangeFile.SourceControlAction.EDIT;
                    }
                    else if (change.ChangeTypeName.Equals("add"))
                    {
                        action = ChangeFile.SourceControlAction.ADD;
                    }
                    else if (change.ChangeTypeName.Equals("delete") || change.ChangeTypeName.Equals("merge, delete"))
                    {
                        action = ChangeFile.SourceControlAction.DELETE;
                    }
                    else if (change.ChangeTypeName.Equals("branch") || change.ChangeTypeName.Equals("merge, branch"))
                    {
                        action = ChangeFile.SourceControlAction.BRANCH;
                    }
                    else if (change.ChangeTypeName.Equals("merge, edit"))
                    {
                        action = ChangeFile.SourceControlAction.INTEGRATE;
                    }
                    else if (change.ChangeTypeName.Equals("rename"))
                    {
                        action = ChangeFile.SourceControlAction.RENAME;
                    }
                    else if (change.ChangeTypeName.Equals("rename, edit"))
                    {
                        action = ChangeFile.SourceControlAction.EDIT;

                        originalFileName = change.SourceServerItem;
                    }
                    else
                    {
                        Console.WriteLine("Unsupported action for file " + change.LocalItem + " : " +
                            change.ChangeTypeName);

                        return null;
                    }

                    ChangeFile file = new ChangeFile(change.ServerItem, action, change.Version,
                        (change.ItemType == ItemType.File) && IsTextEncoding(change.Encoding));

                    files.Add(file);

                    file.LocalFileName = Workspace.GetLocalItemForServerItem(change.ServerItem);

                    file.OriginalServerFileName = originalFileName;

                    if (getFilesFromShelveSet)
                    {
                        if (action != ChangeFile.SourceControlAction.DELETE)
                        {
                            file.LastModifiedTime = shelveset.CreationDate.ToUniversalTime();
                        }
                    }
                    else if (File.Exists(file.LocalFileName))
                    {
                        file.LastModifiedTime = File.GetLastWriteTimeUtc(file.LocalFileName);
                    }

                    if (!file.IsText)
                        continue;

                    // Store the entire file.
                    if (action == ChangeFile.SourceControlAction.ADD ||
                        (action == ChangeFile.SourceControlAction.BRANCH && includeBranchedFiles))
                    {
                        if (getFilesFromShelveSet)
                        {
                            using (Malevich.Util.TempFile tempFile = new Malevich.Util.TempFile())
                            {
                                change.DownloadShelvedFile(tempFile.FullName);
                                file.Data = File.ReadAllText(tempFile.FullName);
                            }
                        }
                        else
                        {
                            file.Data = File.ReadAllText(file.LocalFileName);
                        }
                    }

                    // Store the diff.
                    else if (action == ChangeFile.SourceControlAction.EDIT ||
                             (action == ChangeFile.SourceControlAction.INTEGRATE && includeBranchedFiles))
                    {
#if USE_DIFF_TOOL
                        using (var baseFile = new TempFile())
                        using (var changedFile = new TempFile())
                        {
                            change.DownloadBaseFile(baseFile.FullName);
                            change.DownloadShelvedFile(changedFile.FullName);

                            string args = baseFile.FullName + " " + changedFile.FullName;

                            using (Process diff = new Process())
                            {
                                diff.StartInfo.UseShellExecute = false;
                                diff.StartInfo.RedirectStandardError = true;
                                diff.StartInfo.RedirectStandardOutput = true;
                                diff.StartInfo.CreateNoWindow = true;
                                diff.StartInfo.FileName = @"bin\diff.exe";
                                diff.StartInfo.Arguments = args;
                                diff.Start();

                                string stderr;
                                file.Data = Malevich.Util.CommonUtils.ReadProcessOutput(diff, false, out stderr);
                            }
                        }
#else
                        IDiffItem changedFile = getFilesFromShelveSet ?
                            (IDiffItem)new DiffItemShelvedChange(shelveset.Name, change) :
                            (IDiffItem)new DiffItemLocalFile(file.LocalFileName, change.Encoding,
                                file.LastModifiedTime.Value, false);
                        DiffItemPendingChangeBase baseFile = new DiffItemPendingChangeBase(change);

                        // Generate the diffs
                        DiffOptions options = new DiffOptions();
                        options.OutputType = DiffOutputType.UnixNormal;
                        options.UseThirdPartyTool = false;


                        using (var memStream = new MemoryStream())
                        {
                            options.StreamWriter = new StreamWriter(memStream);
                            {
                                // DiffFiles closes options.StreamWriter.
                                Difference.DiffFiles(VcsServer, baseFile, changedFile, options, null, true);
                                memStream.Seek(0, SeekOrigin.Begin);

                                // Remove TFS-specific delimiters.
                                using (StreamReader reader = new StreamReader(memStream))
                                {
                                    StringBuilder sb = new StringBuilder();
                                    for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
                                    {
                                        if (line.Equals(""))
                                            continue;

                                        if (line.StartsWith("="))
                                            continue;

                                        sb.Append(line);
                                        sb.Append('\n');
                                    }
                                    file.Data = sb.ToString();
                                }
                            }
                        }
#endif
                    }
                }
            }

            if (files.Count() == 0)
            {
                Console.WriteLine("The shelveset does not contain any files!");
                return null;
            }

            // Iterate the workitems associated with the bug and store the IDs.
            var bugIds = new List<string>();
            foreach (WorkItemCheckinInfo workItemInfo in shelveset.WorkItemInfo)
            {
                var workItem = workItemInfo.WorkItem;
                bugIds.Add(workItem.Id.ToString());
            }

            return new Change(
                Tfs,
                Tfs.Workspace,
                shelveset.Name,
                shelveset.OwnerName,
                shelveset.CreationDate.ToUniversalTime(),
                shelveset.Comment,
                bugIds,
                files) { ChangeListFriendlyName = shelveset.DisplayName.Split(new char[] { ';' })[0] };
        }
Example #3
0
        /// <summary>
        /// Gets the change from the source control system. The change must be pending.
        /// Returns null if any error occurs, or the change is not pending.
        /// </summary>
        /// <param name="changeNo"> CL identifier. </param>
        /// <param name="changeListId"> Incude the text of branched and integrated files. </param>
        /// <returns> The change. </returns>
        public Change GetChange(string changeListId, bool includeBranchedFiles)
        {
            int changeNo;
            if (!Int32.TryParse(changeListId, out changeNo))
            {
                Console.WriteLine("Change List number is not a number!");
                return null;
            }

            string description = RunClient("describe " + changeNo, false);
            if (description == null)
                return null;

            StringReader reader = new StringReader(description);
            string firstLine = reader.ReadLine();
            if (firstLine == null)
            {
                Console.WriteLine("The description is empty. Cannot proceed.");
                return null;
            }

            Match firstLineMatch = ClientDescribeTitleParser.Match(firstLine);
            if (!firstLineMatch.Success)
            {
                Console.WriteLine("This change is not pending!");
                return null;
            }

            string clientName = firstLineMatch.Groups[1].Value;

            DateTime timeStamp;

            if (!DateTime.TryParse(firstLineMatch.Groups[2].Value, out timeStamp))
                BugOut(description + "\n\n[Could not parse the time stamp]");

            timeStamp = timeStamp.ToUniversalTime();

            if (!"".Equals(reader.ReadLine()))
                BugOut(description + "\n\n[No newline before change description]");

            StringBuilder changeDescription = new StringBuilder();
            for (; ; )
            {
                string line = reader.ReadLine();
                if (line == null)
                    BugOut(description + "\n\n[Unexpected EOL]");

                if (line.Equals("Affected files ..."))
                    break;

                changeDescription.Append(line.Trim());
                changeDescription.Append('\n');
            }

            if (!"".Equals(reader.ReadLine()))
                BugOut(description + "\n\n[No newline before the list of files]");

            List<ChangeFile> files = new List<ChangeFile>();
            for (; ; )
            {
                string fileString = reader.ReadLine();
                if (fileString == null || "".Equals(fileString))
                    break;

                Match match = ClientDescribeFileParser.Match(fileString);
                if (!match.Success)
                    BugOut(description + "\n\n[Could not match " + fileString + "]");

                string fileName = match.Groups[1].Value;
                string rev = match.Groups[2].Value;
                string action = match.Groups[3].Value;

                int revision = -1;
                if (!Int32.TryParse(rev, out revision))
                    BugOut(description + "\n\n[Could not parse revision in " + fileString + "]");

                // Make sure the file is text.
                string openedFile = RunClient("opened \"" + fileName + "\"", false);
                if (openedFile == null)
                    BugOut("opened \"" + fileName + "\"");

                // Ignore binary files
                bool isText = ClientOpenedIsText.IsMatch(openedFile);

                ChangeFile.SourceControlAction a = ChangeFile.SourceControlAction.ADD;
                if ("edit".Equals(action))
                    a = ChangeFile.SourceControlAction.EDIT;
                else if ("add".Equals(action))
                    a = ChangeFile.SourceControlAction.ADD;
                else if ("delete".Equals(action))
                    a = ChangeFile.SourceControlAction.DELETE;
                else if ("branch".Equals(action))
                    a = ChangeFile.SourceControlAction.BRANCH;
                else if ("integrate".Equals(action))
                    a = ChangeFile.SourceControlAction.INTEGRATE;
                else
                    BugOut(description + "\n\n[Unknown file action: " + action + "]");

                ChangeFile file = new ChangeFile(fileName, a, revision, isText);
                files.Add(file);
            }

            if (files.Count > 0)
            {
                Change change = new Change(SourceControl, clientName, changeListId, timeStamp,
                    changeDescription.ToString(), files.ToArray());
                FillInFileData(change, includeBranchedFiles);
                return change;
            }

            return null;
        }
        /// <summary>
        /// Gets the change from the source control system. The change must be pending.
        /// Returns null if any error occurs, or the change is not pending.
        /// </summary>
        /// <param name="changeNo"> CL identifier. </param>
        /// <param name="changeListId"> Incude the text of branched and integrated files. </param>
        /// <param name="skipFiles"> True to skip files when not needed - faster. </param>
        /// <returns> The change. </returns>
        public Change GetChange(string changeListId, bool includeBranchedFiles, bool skipFile = false)
        {
            bool shelved = false;
            int changeNo;
            if (!Int32.TryParse(changeListId, out changeNo))
            {
                Log.Error("Change List number is not a number!");
                return null;
            }

            // Use -S for shelved changelists
            string description = RunClient("describe -s -S " + changeNo, false);
            if (string.IsNullOrEmpty(description))
                return null;

            StringReader reader = new StringReader(description);
            string firstLine = reader.ReadLine();
            if (firstLine == null)
            {
                Log.Error("The description is empty. Cannot proceed.");
                return null;
            }

            Match firstLineMatch = ClientDescribeTitleParser.Match(firstLine);
            if (!firstLineMatch.Success)
            {
                Log.Error("This change is not pending!");
                return null;
            }

            string clientName = firstLineMatch.Groups[1].Value;

            DateTime timeStamp;

            if (!DateTime.TryParse(firstLineMatch.Groups[2].Value, out timeStamp))
                BugOut(description + "\n\n[Could not parse the time stamp]");

            timeStamp = timeStamp.ToUniversalTime();

            if (!"".Equals(reader.ReadLine()))
                BugOut(description + "\n\n[No newline before change description]");

            StringBuilder changeDescription = new StringBuilder();
            for (; ; )
            {
                string line = reader.ReadLine();
                if (line == null)
                    BugOut(description + "\n\n[Unexpected EOL]");

                if (line.Equals("Affected files ..."))
                    break;

                if (line.Equals("Shelved files ...")) {
                    shelved = true;
                    break;
                }

                changeDescription.Append(line.Trim());
                changeDescription.Append('\n');
            }

            if (!"".Equals(reader.ReadLine()))
                BugOut(description + "\n\n[No newline before the list of files]");

            List<ChangeFile> files = new List<ChangeFile>();
            if (!skipFile)
            {
                for (; ; )
                {
                    string fileString = reader.ReadLine();
                    if (fileString == null || "".Equals(fileString))
                        break;

                    Match match = ClientDescribeFileParser.Match(fileString);
                    if (!match.Success)
                        BugOut(description + "\n\n[Could not match " + fileString + "]");

                    string fileName = match.Groups[1].Value;
                    string rev = match.Groups[2].Value;
                    string action = match.Groups[3].Value;

                    int revision = -1;
                    if (rev != "none" && !Int32.TryParse(rev, out revision))
                        BugOut(description + "\n\n[Could not parse revision in " + fileString + "]");

                    // Make sure the file is text.
                    bool isText = false;
                    if (!shelved)
                    {
                        var openedFile = RunClient("opened \"" + fileName + "\"", false);
                        if (string.IsNullOrEmpty(openedFile) && !shelved)
                            BugOut("opened \"" + fileName + "\"");

                        // Ignore binary files
                        isText = ClientOpenedIsText.IsMatch(openedFile);
                    }
                    else
                    {
                        var stats = RunClient(string.Format("fstat \"{0}@={1}\"", fileName, changeListId), false);
                        if (string.IsNullOrEmpty(stats) && !shelved)
                            BugOut("opened \"" + fileName + "\"");

                        // Ignore binary files
                        isText = stats.Contains("... headType text") ? true : false;
                    }

                    ChangeFile.SourceControlAction a = ChangeFile.SourceControlAction.ADD;
                    if ("edit".Equals(action))
                        a = ChangeFile.SourceControlAction.EDIT;
                    else if ("add".Equals(action) || "move/add".Equals(action))
                        a = ChangeFile.SourceControlAction.ADD;
                    else if ("delete".Equals(action) || "move/delete".Equals(action))
                        a = ChangeFile.SourceControlAction.DELETE;
                    else if ("branch".Equals(action))
                        a = ChangeFile.SourceControlAction.BRANCH;
                    else if ("integrate".Equals(action))
                        a = ChangeFile.SourceControlAction.INTEGRATE;
                    else if ("move/add".Equals(action))
                        a = ChangeFile.SourceControlAction.RENAME;
                    else
                        BugOut(description + "\n\n[Unknown file action: " + action + "]");

                    ChangeFile file = new ChangeFile(fileName, a, revision, isText, shelved);
                    files.Add(file);
                }
            }

            if (files.Count > 0 || skipFile)
            {
                Change change = new Change(SourceControl, clientName, changeListId, timeStamp,
                    description, files.ToArray());
                FillInFileData(change, includeBranchedFiles);
                return change;
            }

            return null;
        }