Пример #1
0
        public void GetVersionDetails(ElementVersion version, out List <Tuple <string, int> > mergesTo, out List <Tuple <string, int> > mergesFrom)
        {
            bool isDir = version.Element.IsDirectory;
            // not interested in directory merges
            string format = "%Fu" + _separator + "%u" + _separator + "%d" + _separator + "%Nc" + _separator + "%Nl" +
                            (isDir ? "" : _separator + "%[hlink:Merge]p");
            // string.Join to handle multi-line comments
            string raw = string.Join("\r\n", ExecuteCommand("desc -fmt \"" + format + "\" \"" + version + "\""));

            string[] parts = _separator.Split(raw);
            version.AuthorName  = string.Intern(parts[0]);
            version.AuthorLogin = string.Intern(parts[1]);
            version.Date        = DateTime.Parse(parts[2], null, DateTimeStyles.RoundtripKind).ToUniversalTime();
            version.Comment     = string.Intern(parts[3]);
            foreach (string label in parts[4].Split(' '))
            {
                if (!string.IsNullOrWhiteSpace(label) && _labelFilter.ShouldKeep(label))
                {
                    version.Labels.Add(string.Intern(label));
                }
            }
            mergesTo = mergesFrom = null;
            if (isDir && parts.Count() >= 6 && !string.IsNullOrEmpty(parts[5]))
            {
                Logger.TraceData(TraceEventType.Verbose, (int)TraceId.Cleartool, "Ignoring directory merge info for", version);
            }
            if (isDir || string.IsNullOrEmpty(parts[5]))
            {
                return;
            }

            Match match = _mergeRegex.Match(parts[5]);

            if (!match.Success)
            {
                Logger.TraceData(TraceEventType.Warning, (int)TraceId.Cleartool, "Failed to parse merge data '" + parts[5] + "'");
                return;
            }
            mergesTo   = new List <Tuple <string, int> >();
            mergesFrom = new List <Tuple <string, int> >();
            int count = match.Groups[1].Captures.Count;

            for (int i = 0; i < count; i++)
            {
                var addTo         = match.Groups[2].Captures[i].Value == "->" ? mergesTo : mergesFrom;
                var branch        = match.Groups[3].Captures[i].Value;
                var versionNumber = match.Groups[4].Captures[i].Value;
                if (versionNumber.StartsWith("CHECKEDOUT"))
                {
                    continue;
                }
                addTo.Add(new Tuple <string, int>(branch, int.Parse(versionNumber)));
            }
        }
Пример #2
0
        /// <summary>
        /// Semantic of the file parameter is that the "directory" part (if present) is the path relative to the global clearcase root
        /// the file itself should therefore be in the working directory
        /// (although we could cheat using '/' for the root vs '\' for the actual file path)
        /// </summary>
        /// <param name="file"></param>
        public void ReadFile(string file)
        {
            string root = "";
            int    pos  = file.LastIndexOf('/');

            if (pos != -1)
            {
                root = file.Substring(0, pos + 1).Replace('/', '\\');
                file = file.Substring(pos + 1);
            }
            Logger.TraceData(TraceEventType.Start | TraceEventType.Information, (int)TraceId.ReadExport, "Start reading export file", file);
            TextReader     reader = new StreamReader(file);
            string         line;
            string         currentElementName = null;
            Element        currentElement     = null;
            ElementBranch  currentBranch      = null;
            ElementVersion currentVersion     = null;
            List <Tuple <ElementVersion, string, int, bool> > currentElementMerges = new List <Tuple <ElementVersion, string, int, bool> >();
            Match  match;
            int    lineNb = 0;
            int    missingCommentChars = 0;
            string currentComment      = null;
            // hack around end of lines
            string eol;

            while ((line = ReadLine(reader, out eol)) != null)
            {
                lineNb++;
                if (missingCommentChars > 0)
                {
                    Debug.Assert(currentVersion != null);
                    currentComment      += line;
                    missingCommentChars -= line.Length;
                    if (missingCommentChars < 0)
                    {
                        throw new Exception(file + ", line " + lineNb + " : Unexpected comment length");
                    }
                    if (missingCommentChars > 0)
                    {
                        currentComment      += eol;
                        missingCommentChars -= eol.Length;
                    }
                    if (missingCommentChars == 0)
                    {
                        currentVersion.Comment = string.Intern(currentComment);
                        currentComment         = null;
                    }
                    continue;
                }
                if (line == "ELEMENT_BEGIN")
                {
                    currentElementName = null;
                    currentBranch      = null;
                    currentElement     = null;
                    currentVersion     = null;
                    currentElementMerges.Clear();
                    continue;
                }
                if (currentElement == null && (match = _elementNameRegex.Match(line)).Success)
                {
                    currentElementName = root + match.Groups[1].Value;
                    currentElement     = new Element(currentElementName, false); // no directories in export files
                    Elements.Add(currentElement);
                    Logger.TraceData(TraceEventType.Start | TraceEventType.Verbose, (int)TraceId.ReadExport, "Start reading element", currentElementName);
                    continue;
                }
                if (line == "ELEMENT_END")
                {
                    if (currentElement == null)
                    {
                        throw new Exception(file + ", line " + lineNb + " : Unexpected ELEMENT_END before it was named");
                    }
                    foreach (var merge in currentElementMerges)
                    {
                        var version = merge.Item1;
                        var other   = currentElement.GetVersion(merge.Item2, merge.Item3);
                        if (other == null || version.Date > _originDate)
                        {
                            // skip merges to or from skipped versions (that were too recent)
                            continue;
                        }
                        (merge.Item4 ? version.MergesTo : version.MergesFrom).Add(other);
                    }

                    Logger.TraceData(TraceEventType.Stop | TraceEventType.Verbose, (int)TraceId.ReadExport, "Stop reading element", currentElementName);
                    continue;
                }

                if (line == "VERSION_BEGIN" || line == "VERSION_END")
                {
                    currentVersion = null;
                    continue;
                }
                if (currentElement != null && currentVersion == null && (match = _versionIdRegex.Match(line)).Success)
                {
                    string[] branchPath = match.Groups[1].Value.Split('\\');
                    string   branchName = branchPath[branchPath.Length - 1];
                    if (currentBranch == null || (currentBranch.BranchName != branchName && !currentElement.Branches.TryGetValue(branchName, out currentBranch)))
                    {
                        if (branchName != "main")
                        {
                            throw new Exception(file + ", line " + lineNb + " : Unexpected branch " + branchName);
                        }
                        currentBranch = new ElementBranch(currentElement, branchName, null);
                        currentElement.Branches[branchName] = currentBranch;
                    }
                    currentVersion = new ElementVersion(currentBranch, int.Parse(match.Groups[2].Value));
                    currentBranch.Versions.Add(currentVersion);
                    Logger.TraceData(TraceEventType.Verbose, (int)TraceId.ReadExport, "Creating version", currentVersion);
                    continue;
                }
                if (currentVersion != null && (match = _userRegex.Match(line)).Success)
                {
                    currentVersion.AuthorLogin = string.Intern(match.Groups[1].Value);
                    continue;
                }
                if (currentVersion != null && (match = _userNameRegex.Match(line)).Success)
                {
                    currentVersion.AuthorName = string.Intern(match.Groups[1].Value);
                    continue;
                }
                if (currentVersion != null && (match = _timeRegex.Match(line)).Success)
                {
                    currentVersion.Date = _epoch.AddSeconds(long.Parse(match.Groups[1].Value));
                    if (currentVersion.Date > _originDate)
                    {
                        Logger.TraceData(TraceEventType.Information, (int)TraceId.ReadExport,
                                         string.Format("Skipping version {0} : {1} > {2}", currentVersion, currentVersion.Date, _originDate));
                        currentBranch.Versions.Remove(currentVersion);
                    }
                    continue;
                }
                if (currentVersion != null && (match = _labelRegex.Match(line)).Success)
                {
                    var label = string.Intern(match.Groups[1].Value);
                    if (_labelFilter.ShouldKeep(label))
                    {
                        currentVersion.Labels.Add(label);
                    }
                    continue;
                }
                if (currentVersion != null && (match = _commentRegex.Match(line)).Success)
                {
                    currentComment      = match.Groups[2].Value;
                    missingCommentChars = int.Parse(match.Groups[1].Value) - currentComment.Length;
                    if (missingCommentChars > 0)
                    {
                        currentComment      += eol;
                        missingCommentChars -= eol.Length;
                    }
                    if (missingCommentChars == 0 && currentComment.Length > 0)
                    {
                        currentVersion.Comment = string.Intern(currentComment);
                        currentComment         = null;
                    }
                    continue;
                }
                if (currentVersion != null && (match = _subBranchRegex.Match(line)).Success)
                {
                    string branchName = match.Groups[1].Value;
                    if (currentElement.Branches.ContainsKey(branchName))
                    {
                        throw new Exception(file + ", line " + lineNb + " : Duplicated branch " + branchName);
                    }
                    currentElement.Branches[branchName] = new ElementBranch(currentElement, branchName, currentVersion);
                    continue;
                }
                if (currentVersion != null && (match = _mergeRegex.Match(line)).Success)
                {
                    bool mergeTo = match.Groups[1].Success;
                    // Groups[i].Value is the last capture : ok here
                    string branchCapture = match.Groups[2].Value;
                    string branchName    = string.IsNullOrEmpty(branchCapture) ? "main" : branchCapture.Substring(0, branchCapture.Length - 1);
                    int    versionNumber = int.Parse(match.Groups[3].Value);

                    // not interested in merges from same branch
                    if (branchName != currentBranch.BranchName)
                    {
                        currentElementMerges.Add(new Tuple <ElementVersion, string, int, bool>(currentVersion, branchName, versionNumber, mergeTo));
                    }

                    continue;
                }
            }
            Logger.TraceData(TraceEventType.Start | TraceEventType.Information, (int)TraceId.ReadExport, "Stop reading export file", file);
        }