Versionr.Network.Client.PullVersions C# (CSharp) Method

PullVersions() private method

private PullVersions ( SharedNetwork sharedInfo, bool &receivedData ) : bool
sharedInfo SharedNetwork
receivedData bool
return bool
        private bool PullVersions(SharedNetwork.SharedNetworkInfo sharedInfo, out bool receivedData)
        {
            bool importResult = sharedInfo.Workspace.RunLocked(() =>
            {
                return SharedNetwork.ImportRecords(sharedInfo, true);
            }, false);
            receivedData = false;
            if (!importResult)
                return false;
            if (sharedInfo.PushedVersions.Count == 0 && sharedInfo.ReceivedBranchJournals.Count == 0 && sharedInfo.ReceivedBranches.Count == 0)
                return true;
            receivedData = true;
            return sharedInfo.Workspace.RunLocked(() =>
            {
                lock (sharedInfo.Workspace)
                {
                    try
                    {
                        sharedInfo.Workspace.BeginDatabaseTransaction();
                        if (!SharedNetwork.ImportBranchJournal(sharedInfo, true))
                            return false;
                        SharedNetwork.ImportBranches(sharedInfo);
                        Dictionary<Guid, List<Head>> temporaryHeads = new Dictionary<Guid, List<Head>>();
                        Dictionary<Guid, Guid> pendingMerges = new Dictionary<Guid, Guid>();
                        Dictionary<Guid, HashSet<Guid>> headAncestry = new Dictionary<Guid, HashSet<Guid>>();
                        HashSet<Guid> terminatedBranches = new HashSet<Guid>();
                        List<Guid> mergeResults = new List<Guid>();
                        foreach (var x in ((IEnumerable<VersionInfo>)sharedInfo.PushedVersions).Reverse())
                        {
                            if (terminatedBranches.Contains(x.Version.Branch))
                                continue;
                            List<Head> heads;
                            if (!temporaryHeads.TryGetValue(x.Version.Branch, out heads))
                            {
                                Branch branch = sharedInfo.Workspace.GetBranch(x.Version.Branch);
                                if (branch.Terminus.HasValue)
                                {
                                    terminatedBranches.Add(branch.ID);
                                    continue;
                                }
                                heads = new List<Head>();
                                var bheads = sharedInfo.Workspace.GetBranchHeads(branch);
                                if (bheads.Count == 0)
                                    heads.Add(new Head() { Branch = branch.ID, Version = x.Version.ID });
                                else
                                {
                                    foreach (var h in bheads)
                                        heads.Add(h);
                                }
                                temporaryHeads[branch.ID] = heads;
                            }
                            mergeResults.Clear();
                            for (int i = 0; i < heads.Count; i++)
                            {
                                if (heads[i].Version != x.Version.ID)
                                {
                                    HashSet<Guid> headAncestors = null;
                                    if (!headAncestry.TryGetValue(heads[i].Version, out headAncestors))
                                    {
                                        headAncestors = SharedNetwork.GetAncestry(heads[i].Version, sharedInfo);
                                        headAncestry[heads[i].Version] = headAncestors;
                                    }
                                    if (headAncestors.Contains(x.Version.ID))
                                    {
                                        // all best
                                        mergeResults.Add(heads[i].Version);
                                    }
                                    else if (SharedNetwork.IsAncestor(heads[i].Version, x.Version.ID, sharedInfo))
                                    {
                                        mergeResults.Add(x.Version.ID);
                                    }
                                    else
                                    {
                                        mergeResults.Add(Guid.Empty);
                                    }
                                }
                            }
                            pendingMerges[x.Version.Branch] = Guid.Empty;
                            // Remove any superceded heads
                            // Add a merge if required
                            bool unrelated = true;
                            for (int i = 0; i < mergeResults.Count; i++)
                            {
                                if (mergeResults[i] == Guid.Empty)
                                    continue;
                                else if (mergeResults[i] != heads[i].Version)
                                {
                                    headAncestry.Remove(heads[i].Version);
                                    heads[i].Version = x.Version.ID;
                                    unrelated = false;
                                }
                                else
                                    unrelated = false;
                            }
                            if (unrelated)
                            {
                                heads.Add(new Head() { Branch = x.Version.Branch, Version = x.Version.ID });
                            }
                            for (int i = 0; i < heads.Count; i++)
                            {
                                for (int j = i + 1; j < heads.Count; j++)
                                {
                                    if (heads[i].Version == heads[j].Version)
                                    {
                                        heads.RemoveAt(j);
                                        --j;
                                    }
                                }
                            }
                        }
                        List<Head> newHeads = new List<Head>();
                        List<VersionInfo> autoMerged = new List<VersionInfo>();
                        foreach (var x in pendingMerges)
                        {
                            Branch branch = sharedInfo.Workspace.GetBranch(x.Key);
                            List<Head> heads = temporaryHeads[x.Key];
                            var bheads = sharedInfo.Workspace.GetBranchHeads(branch);

                            bool headsChanged = bheads.Count != heads.Count;
                            if (!headsChanged)
                            {
                                for (int i = 0; i < bheads.Count; i++)
                                {
                                    if (bheads[i].Version != heads[i].Version)
                                        headsChanged = true;
                                }
                            }

                            if (!headsChanged)
                            {
                                temporaryHeads[x.Key] = null;
                                continue;
                            }

                            if (heads.Count == 1)
                            {
                                Printer.PrintDiagnostics("Uncontested head update for branch \"{0}\".", Workspace.GetBranch(x.Key).Name);
                                Printer.PrintDiagnostics(" - Head updated to {0}", temporaryHeads[x.Key][0].Version);
                                continue;
                            }

                            var localVersions = bheads.Where(h => heads.Any(y => y.Version != h.Version));
                            var remoteVersions = heads.Where(h => !bheads.Any(y => y.Version != h.Version));

                            if (localVersions.Count() != 1)
                            {
                                Printer.PrintDiagnostics("Too many heads in local branch to merge remote head. Please merge locally and try again to update branch \"{0}\".", Workspace.GetBranch(x.Key).Name);
                                return false;
                            }

                            Guid localVersion = localVersions.First().Version;

                            if (remoteVersions.Count() == 1)
                            {
                                VersionInfo result;
                                string error;
                                result = Workspace.MergeRemote(Workspace.GetLocalOrRemoteVersion(localVersion, sharedInfo), remoteVersions.First().Version, sharedInfo, out error, true);

                                Printer.PrintMessage("Resolved incoming merge for branch \"{0}\".", branch.Name);
                                Printer.PrintDiagnostics(" - Merge local input {0}", localVersion);
                                Printer.PrintDiagnostics(" - Merge remote input {0}", remoteVersions.First().Version);
                                Printer.PrintDiagnostics(" - Head updated to {0}", result.Version.ID);

                                for (int i = 0; i < heads.Count; i++)
                                {
                                    if ((remoteVersions.Any() && heads[i].Version == remoteVersions.First().Version) || heads[i].Version == localVersion)
                                    {
                                        heads.RemoveAt(i);
                                        --i;
                                    }
                                }
                                heads.Add(new Head() { Branch = branch.ID, Version = result.Version.ID });
                                autoMerged.Add(result);
                            }
                        }
                        var versionsToImport = sharedInfo.PushedVersions.OrderBy(x => x.Version.Timestamp).ToArray();
                        if (versionsToImport.Length != 0)
                        {
                            Dictionary<Guid, bool> importList = new Dictionary<Guid, bool>();
                            foreach (var x in versionsToImport)
                                importList[x.Version.ID] = false;
                            int importCount = versionsToImport.Length;
                            var orderedImports = versionsToImport.OrderBy(x => x.Version.Revision).ToList();
                            Printer.InteractivePrinter printer = null;
                            Printer.PrintMessage("Importing #b#{0}## versions...", orderedImports.Count);
                            printer = Printer.CreateProgressBarPrinter("Importing", string.Empty,
                                    (obj) =>
                                    {
                                        return string.Empty;
                                    },
                                    (obj) =>
                                    {
                                        return (100.0f * (int)(orderedImports.Count - importCount)) / (float)orderedImports.Count;
                                    },
                                    (pct, obj) =>
                                    {
                                        return string.Format("{0}/{1}", (int)(orderedImports.Count - importCount), orderedImports.Count);
                                    },
                                    60);
                            while (importCount > 0)
                            {
                                foreach (var x in orderedImports)
                                {
                                    if (importList[x.Version.ID] != true)
                                    {
                                        bool accept;
                                        if (!x.Version.Parent.HasValue || !importList.TryGetValue(x.Version.Parent.Value, out accept))
                                            accept = true;
                                        if (accept)
                                        {
                                            sharedInfo.Workspace.ImportVersionNoCommit(sharedInfo, x, true);
                                            importList[x.Version.ID] = true;
                                            importCount--;
                                            printer.Update(importCount);
                                        }
                                    }
                                }
                            }
                            printer.End(importCount);
                        }
                        Printer.PrintMessage("Updating internal state...");
                        foreach (var x in autoMerged)
                            Workspace.ImportVersionNoCommit(sharedInfo, x, false);
                        foreach (var x in temporaryHeads)
                        {
                            if (x.Value != null)
                                Workspace.ReplaceHeads(x.Key, x.Value);
                        }
                        Workspace.CommitDatabaseTransaction();
                        sharedInfo.Workspace.CommitDatabaseTransaction();
                        return true;
                    }
                    catch
                    {
                        sharedInfo.Workspace.RollbackDatabaseTransaction();
                        throw;
                    }
                }
            }, false);
        }