bool TryResolveConflict(ChangeGraphBuilder changeGraphBuilder, IMultiFileSystemHistoryService historyService, ConflictInfo conflict, out IFileReference resolved)
        {
            var graph = changeGraphBuilder.GetChangeGraphs(GetDiff(historyService, conflict)).Single();

            var sinks = graph.GetSinks().ToArray();

            return TryResolveConflict(sinks, out resolved);
        }
        public void T04_Items_returns_expected_conflicts()
        {
            var expected = new ConflictInfo("/file1", "id");

            m_Service.AddItems(expected);

            Assert.Single(m_Service.Items);
            var actual = m_Service.Items.Single();
            Assert.Equal(expected.FilePath, actual.FilePath);
            Assert.Equal(expected.SnapshotId, actual.SnapshotId);
        }
        public void T08_Indexer_throws_ItemNotFoundException_if_item_does_not_exist()
        {
            var conflict = new ConflictInfo("/file1", null);
            m_Service.AddItems(conflict);

            Assert.Throws<ItemNotFoundException>(() => m_Service["/some/other/path"]);
        }
        public void T13_ItemExists_returns_the_expected_result()
        {
            var conflict = new ConflictInfo("/some/file/path", null);
            m_Service.AddItems(conflict);

            Assert.True(m_Service.ItemExists("/SOME/file/Path"));
            Assert.False(m_Service.ItemExists("/another/path"));
        }
        public void T11_RemoveItems_removes_the_specified_items()
        {
            var commitCount = m_Group.Repository.GetAllCommits().Count();
            var conflict1 = new ConflictInfo("/file1", null);
            var conflict2 = new ConflictInfo("/file2", null);

            Assert.Empty(m_Service.Items);
            m_Service.AddItems(conflict1, conflict2);
            Assert.NotEmpty(m_Service.Items);

            m_Service.RemoveItems(conflict1, conflict2);
            Assert.Empty(m_Service.Items);
            Assert.Equal(commitCount + 2, m_Group.Repository.GetAllCommits().Count());
        }
 public void T10_RemoveItems_throws_ItemNotFoundException_if_conflict_does_not_exist()
 {
     var conflict = new ConflictInfo("/file1", null);            
     Assert.Throws<ItemNotFoundException>(() => m_Service.RemoveItems(conflict));
 }
        public void T09_AddItems_properly_stores_added_conflicts()
        {
            var conflict1 = new ConflictInfo("/file1", null);
            var conflict2 = new ConflictInfo("/file2", null);

            var commitCount = m_Group.Repository.GetAllCommits().Count();

            m_Service.AddItems(conflict1, conflict2);
            Assert.Equal(commitCount +1 , m_Group.Repository.GetAllCommits().Count());

            var newServiceInstance = new GitConflictService(m_Group);
            Assert.Equal(2, newServiceInstance.Items.Count());            
        }
 public void T08_AddItems_throws_DuplicateItemException_if_conflict_has_already_been_added()
 {
     var conflict = new ConflictInfo("/file1", null);
     m_Service.AddItems(conflict);
     Assert.Throws<DuplicateItemException>(() => m_Service.AddItems(conflict));
 }
        public void T09_Indexer_returns_expected_result()
        {
            var expected = new ConflictInfo("/file1", null);
            m_Service.AddItems(expected);

            var actual = m_Service[expected.FilePath];

            Assert.NotNull(actual);
            Assert.Equal(expected.FilePath,actual.FilePath);
            Assert.Equal(expected.SnapshotId, actual.SnapshotId);
        }
Beispiel #10
0
 IMultiFileSystemDiff GetDiff(IMultiFileSystemHistoryService historyService, ConflictInfo conflict)
 {
     return historyService.GetChanges(conflict.SnapshotId, historyService.LatestSnapshot.Id, new[] {conflict.FilePath});         
 }
Beispiel #11
0
        public void Synchronize(IGroup group)
        {
            var syncFolders = group.GetConfigurationService().Items.ToArray();

            // there need to be at least 2 sync folders, otherwise, syncing makes no sense
            if (syncFolders.Length < 2)
            {
                return;
            }

            var historyService = group.GetService<IMultiFileSystemHistoryService>();
            historyService.CreateSnapshot();

            // we cannot sync if there isn't at least one snapshot
            if(!historyService.Snapshots.Any())
            {
                return;                
            }
            
            // we cannot sync if there is not at least one snapshot per history
            if (historyService.LatestSnapshot.HistoryNames.Any(name => historyService.LatestSnapshot.GetSnapshot(name) == null))
            {
                return;
            }

            // get required services
            var syncPointService = group.GetSyncPointService();
            var conflictService = group.GetSyncConflictService();
            var syncActionService = group.GetSyncActionService();

            var filter = syncFolders.ToMultiFileSystemChangeFilter(m_FilterFactory);

            var latestSyncPoint = syncPointService.LatestSyncPoint;
            var diff = GetDiff(historyService, latestSyncPoint, filter);

            var wasReset = ResetSyncStateIfNecessary(group, diff);
            if (wasReset)
            {
                diff = GetDiff(historyService, latestSyncPoint, filter);
                latestSyncPoint = syncPointService.LatestSyncPoint;
            }
            
            // for all folders, get the changes since the last sync
                
            var newSyncPoint = new MutableSyncPoint()
            {
                Id = GetNextSyncPointId(syncPointService.LatestSyncPoint),                                
                MultiFileSystemSnapshotId = diff.ToSnapshot.Id,
                FilterConfigurations = syncFolders.ToDictionary(f => f.Name, f => f.Filter)
            };

            
                                                   
            
            var syncStateUpdater = new SyncActionUpdateBuilder();
            var changeGraphBuilder = new ChangeGraphBuilder(m_FileReferenceComparer);

            foreach (var graph in changeGraphBuilder.GetChangeGraphs(diff))
            {
                var path = graph.ValueNodes.First(node => node.Value != null).Value.Path;

                // skip if there is a conflict for the current file
                if (conflictService.ItemExists(path))
                {
                    continue;                    
                }                

                // check if all pending sync actions can be applied to the change graph
                var unapplicaleSyncActions = GetUnapplicableSyncActions(graph, syncActionService[path].Where(IsPendingSyncAction));

                // pending sync actions could not be applied => skip file
                if (unapplicaleSyncActions.Any())
                {
                    // cancel unapplicable actions
                    syncStateUpdater.UpdateSyncActions(unapplicaleSyncActions.Select(a => a.WithState(SyncActionState.Cancelled)));
                   
                    // add a conflict for the file (the snapshot id of the conflict can be determined from the oldest unapplicable sync action)
                    var oldestSyncPointId = unapplicaleSyncActions.Min(a => a.SyncPointId);                    
                    var snapshotId = oldestSyncPointId > 1 
                        ? syncPointService[oldestSyncPointId - 1].MultiFileSystemSnapshotId
                        : null;                    
                    syncStateUpdater.AddConflict(new ConflictInfo(unapplicaleSyncActions.First().Path, snapshotId));
                                        
                    continue;
                }
                
                //in the change graph, detect conflicts
                // if there is only one sink, no conflicts exist
                var acylicGraph = graph.ToAcyclicGraph();
                var sinks = acylicGraph.GetSinks().ToArray();
                if (!sinks.Any())
                {
                    // not possible (in this case the graph would be empty, which cannot happen)
                    throw new InvalidOperationException();
                }

                if (sinks.Length == 1)
                {                 
                    // no conflict => generate sync actions, to replace the outdated file versions or add the file to a target

                    var sink = sinks.Single();

                    //TODO: Use C# 7 tuples after it was released
                    IEnumerable<Tuple<string, IFile>> currentFiles = diff.ToSnapshot.GetFiles(path);                
                    foreach (var historyFileTuple in currentFiles)
                    {
                        var targetSyncFolderName = historyFileTuple.Item1;
                        var currentVersion = historyFileTuple.Item2;

                        var syncAction = m_SyncActionFactory.GetSyncAction(targetSyncFolderName, newSyncPoint.Id, currentVersion?.ToReference(), sink);
                        if (syncAction != null && filter.GetFilter(targetSyncFolderName).IncludeInResult(syncAction))
                        {
                            syncStateUpdater.AddSyncAction(syncAction);
                        }
                    }
                
                }
                else
                {
                    // multiple sinks in the change graph => conflict

                    // if there are pending actions for this file, they need to be cancelled
                    var pendingSyncActions = syncActionService[path]
                        .Where(IsPendingSyncAction)
                        .ToArray();

                    if (pendingSyncActions.Any())
                    {
                        //cancel actions          
                        syncStateUpdater.UpdateSyncActions(pendingSyncActions.Select(a => a.WithState(SyncActionState.Cancelled)));                        

                        //determine the oldest sync action to determine the snapshot ids for the conflict
                        var syncPointId = pendingSyncActions.Min(x => x.SyncPointId);
                        var snapshotId = syncPointId > 1
                            ? syncPointService[syncPointId - 1].MultiFileSystemSnapshotId
                            : null;

                        // generate conflict;
                        syncStateUpdater.AddConflict(new ConflictInfo(path, snapshotId));
                    }
                    else
                    {
                        // no pending action => the snapshot ids for the conflict are the start snapshots of the current sync

                        // generate conflict                        
                        var conflictInfo = new ConflictInfo(path, diff.FromSnapshot?.Id);
                        syncStateUpdater.AddConflict(conflictInfo);
                    }
                }
            }

            // save actions, conflicts and sync point          
            syncPointService.AddItem(newSyncPoint);            
            syncStateUpdater.Apply(syncActionService, conflictService);
                        
        }