public List <ElementVersion> Read(string directoriesFile, string elementsFile, string versionsFile)
        {
            List <ElementVersion> result = null;

            if (!string.IsNullOrWhiteSpace(elementsFile))
            {
                Logger.TraceData(TraceEventType.Start | TraceEventType.Information, (int)TraceId.ReadCleartool, "Start reading file elements", elementsFile);
                var allActions = new List <Action>();
                using (var files = new StreamReader(elementsFile, Encoding.Default))
                {
                    string line;
                    int    i = 0;
                    while ((line = files.ReadLine()) != null)
                    {
                        int    iTask       = ++i;
                        string currentLine = line;
                        allActions.Add(() =>
                        {
                            if (iTask % 100 == 0)
                            {
                                Logger.TraceData(TraceEventType.Information, (int)TraceId.ReadCleartool, "Reading file element " + iTask);
                            }
                            ReadElement(currentLine, false, _cleartools[iTask % _nbCleartool]);
                        });
                    }
                }
                Parallel.Invoke(new ParallelOptions {
                    MaxDegreeOfParallelism = _nbCleartool * 2
                }, allActions.ToArray());
                Logger.TraceData(TraceEventType.Stop | TraceEventType.Information, (int)TraceId.ReadCleartool, "Stop reading file elements", elementsFile);
            }

            if (!string.IsNullOrWhiteSpace(directoriesFile))
            {
                Logger.TraceData(TraceEventType.Start | TraceEventType.Information, (int)TraceId.ReadCleartool, "Start reading directory elements", directoriesFile);
                var allActions = new List <Action>();
                using (var directories = new StreamReader(directoriesFile, Encoding.Default))
                {
                    string line;
                    int    i = 0;
                    while ((line = directories.ReadLine()) != null)
                    {
                        int    iTask       = ++i;
                        string currentLine = line;
                        allActions.Add(() =>
                        {
                            if (iTask % 20 == 0)
                            {
                                Logger.TraceData(TraceEventType.Information, (int)TraceId.ReadCleartool, "Reading directory element " + iTask);
                            }
                            ReadElement(currentLine, true, _cleartools[iTask % _nbCleartool]);
                        });
                    }
                }
                Parallel.Invoke(new ParallelOptions {
                    MaxDegreeOfParallelism = _nbCleartool * 2
                }, allActions.ToArray());
                Logger.TraceData(TraceEventType.Stop | TraceEventType.Information, (int)TraceId.ReadCleartool, "Stop reading directory elements", directoriesFile);
            }

            if (!string.IsNullOrWhiteSpace(versionsFile))
            {
                Logger.TraceData(TraceEventType.Start | TraceEventType.Information, (int)TraceId.ReadCleartool, "Start reading individual versions", versionsFile);
                result = new List <ElementVersion>();
                using (var versions = new StreamReader(versionsFile))
                {
                    string line;
                    int    i = 0;
                    // not parallel because not as useful, and trickier to handle versions in "random" order
                    while ((line = versions.ReadLine()) != null)
                    {
                        if (++i % 100 == 0)
                        {
                            Logger.TraceData(TraceEventType.Information, (int)TraceId.ReadCleartool, "Reading version " + i);
                        }
                        ReadVersion(line, result, _cleartools[i % _nbCleartool]);
                    }
                }
                Logger.TraceData(TraceEventType.Stop | TraceEventType.Information, (int)TraceId.ReadCleartool, "Stop reading individual versions", versionsFile);
            }

            // oids still in _oidsToCheck are not to be really imported
            if (_oidsToCheck.Count > 0)
            {
                foreach (var oid in _oidsToCheck)
                {
                    ElementsByOid.Remove(oid);
                }
                foreach (var directory in ElementsByOid.Values.Where(e => e.IsDirectory))
                {
                    foreach (var branch in directory.Branches.Values)
                    {
                        foreach (DirectoryVersion directoryVersion in branch.Versions)
                        {
                            // use a copy to be able to remove
                            var original = directoryVersion.Content.ToList();
                            directoryVersion.Content.Clear();
                            directoryVersion.Content.AddRange(original.Where(p => !_oidsToCheck.Contains(p.Value.Oid)));
                        }
                    }
                }
            }

            Logger.TraceData(TraceEventType.Start | TraceEventType.Information, (int)TraceId.ReadCleartool, "Start fixups");
            foreach (var fixup in _contentFixups)
            {
                Element childElement;
                if (ElementsByOid.TryGetValue(fixup.Item3, out childElement))
                {
                    fixup.Item1.Content.Add(new KeyValuePair <string, Element>(fixup.Item2, childElement));
                }
                else
                {
                    Logger.TraceData(TraceEventType.Warning, (int)TraceId.ReadCleartool,
                                     "Element " + fixup.Item2 + " (oid:" + fixup.Item3 + ") referenced as " + fixup.Item2 + " in " + fixup.Item1 + " was not imported");
                }
            }
            foreach (var fixup in _mergeFixups)
            {
                ElementVersion toFix  = fixup.Item1;
                ElementVersion linkTo = toFix.Element.GetVersion(fixup.Item2, fixup.Item3);
                if (linkTo == null)
                {
                    Logger.TraceData(TraceEventType.Warning, (int)TraceId.ReadCleartool,
                                     "Version " + fixup.Item2 + "/" + fixup.Item3 + " of " + toFix.Element +
                                     ", linked to " + toFix.Branch.BranchName + "/" + toFix.VersionNumber + ", was not imported");
                    continue;
                }
                (fixup.Item4 ? toFix.MergesTo : toFix.MergesFrom).Add(linkTo);
            }
            Logger.TraceData(TraceEventType.Stop | TraceEventType.Information, (int)TraceId.ReadCleartool, "Stop fixups");

            Logger.TraceData(TraceEventType.Start | TraceEventType.Information, (int)TraceId.ReadCleartool, "Start reading label meta info");
            var           labelActions = new List <Action>();
            int           task         = 0;
            List <string> labels;

            lock (_cleartools[0])
                labels = _cleartools[0].ListLabels();
            foreach (var label in labels)
            {
                int iTask = ++task;
                labelActions.Add(() =>
                {
                    if (iTask % 100 == 0)
                    {
                        Logger.TraceData(TraceEventType.Information, (int)TraceId.ReadCleartool, "Reading label meta info " + iTask);
                    }
                    string author;
                    string login;
                    DateTime date;

                    var cleartool = _cleartools[task % _nbCleartool];
                    lock (cleartool)
                        cleartool.GetLabelDetails(label, out author, out login, out date);

                    LabelMeta labelMeta   = new LabelMeta();
                    labelMeta.Name        = label;
                    labelMeta.AuthorName  = author;
                    labelMeta.AuthorLogin = login;
                    labelMeta.Created     = date;

                    lock (_labelMetas)
                        _labelMetas[label] = labelMeta;
                });
            }
            Parallel.Invoke(new ParallelOptions {
                MaxDegreeOfParallelism = _nbCleartool * 2
            }, labelActions.ToArray());
            Logger.TraceData(TraceEventType.Stop | TraceEventType.Information, (int)TraceId.ReadCleartool, "Stop reading label meta info");

            return(result);
        }
Exemple #2
0
        private void WriteChangeSet(ChangeSet changeSet, Dictionary <string, List <ChangeSet> > branches, Dictionary <string, LabelInfo> labels, Dictionary <string, LabelMeta> labelMetas)
        {
            if (changeSet.IsEmpty)
            {
                Logger.TraceData(TraceEventType.Information, (int)TraceId.ApplyChangeSet, "Skipped empty ChangeSet " + changeSet);
                return;
            }

            bool writeCommit = true;

            if (changeSet.IsEmptyGitCommit)
            {
                Logger.TraceData(TraceEventType.Information, (int)TraceId.ApplyChangeSet, "Only writing the tags (if any) for " + changeSet);
                writeCommit = false;
            }

            string branchName = changeSet.Branch == "main" ? "master" : MaybeRenamed(changeSet.Branch);

            if (writeCommit)
            {
                _writer.Write("commit refs/heads/" + branchName + "\n");
                _writer.Write("mark :" + changeSet.Id + "\n");
                _writer.Write("committer " + changeSet.AuthorName + " <" + changeSet.AuthorLogin + "> " + (changeSet.StartTime - Epoch).TotalSeconds + " +0200\n");
                _writer.Write("# " + changeSet.StartTime + "\n");
                InlineString(changeSet.GetComment());
                if (changeSet.BranchingPoint != null)
                {
                    _writer.Write("from :" + changeSet.BranchingPoint.Id + "\n");
                    _startedBranches.Add(branchName);
                }
                else if (_isIncremental && !_startedBranches.Contains(branchName))
                {
                    _writer.Write("from refs/heads/" + branchName + "^0\n");
                    _startedBranches.Add(branchName);
                }
                foreach (var merge in changeSet.Merges)
                {
                    _writer.Write("merge :" + merge.Id + "\n");
                }

                if (!_initialFilesAdded && branchName == "master")
                {
                    _initialFilesAdded = true;
                    foreach (var initialFile in InitialFiles)
                    {
                        var fileInfo = new FileInfo(initialFile.Item2);
                        if (fileInfo.Exists)
                        {
                            _writer.Write("M 644 inline " + initialFile.Item1 + "\n");
                            InlineString(File.ReadAllText(initialFile.Item2));
                        }
                    }
                }

                // order is significant : we must Rename and Copy files before (maybe) deleting their directory
                foreach (var pair in changeSet.Renamed)
                {
                    _writer.Write("R \"" + RemoveDotRoot(pair.Item1) + "\" \"" + RemoveDotRoot(pair.Item2) + "\"\n");
                }
                foreach (var pair in changeSet.Copied)
                {
                    _writer.Write("C \"" + RemoveDotRoot(pair.Item1) + "\" \"" + RemoveDotRoot(pair.Item2) + "\"\n");
                }
                foreach (var removed in changeSet.Removed)
                {
                    _writer.Write("D " + RemoveDotRoot(removed) + "\n");
                }

                foreach (var symLink in changeSet.SymLinks)
                {
                    _writer.Write("M 120000 inline " + RemoveDotRoot(symLink.Item1) + "\n");
                    InlineString(RemoveDotRoot(symLink.Item2));
                }

                foreach (var namedVersion in changeSet.Versions)
                {
                    if (namedVersion.Version is DirectoryVersion || namedVersion.Names.Count == 0)
                    {
                        continue;
                    }

                    bool isEmptyFile = namedVersion.Version.VersionNumber == 0 && namedVersion.Version.Branch.BranchName == "main";

                    if (_doNotIncludeFileContent || isEmptyFile)
                    {
                        foreach (string name in namedVersion.Names.Select(RemoveDotRoot))
                        {
                            if (isEmptyFile)
                            {
                                _writer.Write("M 644 inline " + name + "\ndata 0\n\n");
                            }
                            else
                            {
                                // don't use InlineString here, so that /FetchFileContent is easy to implement
                                _writer.Write("M 644 inline " + name + "\ndata <<EOF\n" + namedVersion.Version + "#" + namedVersion.Version.Element.Oid + "\nEOF\n\n");
                                // also include name in a comment for hooks in /FetchFileContent
                                _writer.Write("#" + name + "\n");
                            }
                        }
                        continue;
                    }

                    InlineClearcaseFileVersion(namedVersion.Version.Element.Name, namedVersion.Version.Element.Oid, namedVersion.Version.VersionPath, namedVersion.Names.Select(RemoveDotRoot), true);
                }
            }

            foreach (var label in changeSet.Labels)
            {
                _writer.Write("tag " + label + "\n");
                _writer.Write("from :" + changeSet.Id + "\n");
                LabelMeta meta = labelMetas[label];

                var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                _writer.Write("tagger " + meta.AuthorName + " <" + meta.AuthorLogin + "> " + (meta.Created - epoch).TotalSeconds + " +0000\n"); // var +0200

                List <Tuple <ElementVersion, ElementVersion> > possibleBroken = labels[label].PossiblyBroken.Where(
                    t => null != _relativeRoots.Find(
                        r => RemoveDotRoot(t.Item1.ToString().Replace("\\", "/") + "/").StartsWith(r + "/")
                        )).ToList();
                if (possibleBroken.Count > 0)
                {
                    Logger.TraceData(TraceEventType.Warning, (int)TraceId.ApplyChangeSet, "Label " + label + " was inconsistent when writing it. Count", possibleBroken.Count);
                    string msg = "Warning! This tag could be incorrect.\nGot an unexpected result, though it could still be correct.\n\n";
                    foreach (Tuple <ElementVersion, ElementVersion> items in possibleBroken)
                    {
                        msg += "Expected \"" + RemoveDotRoot(items.Item1.ToString()) + "\", but got " + (items.Item2 == null ? "nothing" : "\"" + RemoveDotRoot(items.Item2.ToString()) + "\"") + ".\n";
                    }
                    InlineString(msg);
                }
                else
                {
                    _writer.Write("data 0\n\n");
                }
            }
        }