internal CherryPickProcessor(ObjectRepositoryCherryPick objectRepositoryCherryPick, ComputeTreeChangesFactory computeTreeChangesFactory, ObjectRepositorySerializerFactory serializerFactory) { if (serializerFactory == null) { throw new ArgumentNullException(nameof(serializerFactory)); } _cherryPick = objectRepositoryCherryPick ?? throw new ArgumentNullException(nameof(objectRepositoryCherryPick)); _computeTreeChangesFactory = computeTreeChangesFactory ?? throw new ArgumentNullException(nameof(computeTreeChangesFactory)); _serializer = serializerFactory(new ModelObjectSerializationContext(objectRepositoryCherryPick.Repository.Container)); }
internal RebaseProcessor(ObjectRepositoryRebase objectRepositoryRebase, ComputeTreeChangesFactory computeTreeChangesFactory, ObjectRepositorySerializerFactory serializerFactory) { if (serializerFactory == null) { throw new ArgumentNullException(nameof(serializerFactory)); } _rebase = objectRepositoryRebase ?? throw new ArgumentNullException(nameof(objectRepositoryRebase)); _computeTreeChangesFactory = computeTreeChangesFactory ?? throw new ArgumentNullException(nameof(computeTreeChangesFactory)); _serializer = serializerFactory(new ModelObjectSerializationContext(objectRepositoryRebase.Repository.Container)); }
internal static ObjectRepositoryDelete ComputeChanges_Deleted(IObjectRepositorySerializer serializer, IRepository repository, PatchEntryChanges change, Func <string, string> relativeFileDataResolver, Func <string, IList <TreeEntryChanges> > deletionConflictProvider = null) { // Only data file changes have to be taken into account // Changes made to the blobs will product a 'modified' change as well if (System.IO.Path.GetFileName(change.Path) != FileSystemStorage.DataFile) { return(null); } var conflicts = deletionConflictProvider?.Invoke(change.Path); if (conflicts?.Any() ?? false) { throw new NotImplementedException("Node deletion while children have been added or modified in head is not supported."); } var mergeBaseObject = serializer.Deserialize(repository.Lookup <Blob>(change.OldOid).GetContentStream(), relativeFileDataResolver); return(new ObjectRepositoryDelete(change.Path, mergeBaseObject.Id)); }
private static IEnumerable <IMigration> GetCommitMigrations(IRepository repository, Commit previousCommit, Commit commit, IObjectRepositorySerializer serializer) { using (var changes = repository.Diff.Compare <TreeChanges>(previousCommit.Tree, commit.Tree)) { foreach (var change in changes.Where(c => c.Path.StartsWith(FileSystemStorage.MigrationFolder, StringComparison.OrdinalIgnoreCase) && (c.Status == ChangeKind.Added || c.Status == ChangeKind.Modified))) { var blob = (Blob)commit[change.Path].Target; yield return((IMigration)serializer.Deserialize(blob.GetContentStream(), relativePath => (commit[change.Path.GetSiblingFile(relativePath)]?.Target as Blob)?.GetContentText() ?? string.Empty)); } } }
internal static void UpdateTreeDefinition(this IRepository repository, ObjectRepositoryChangeCollection changes, TreeDefinition definition, IObjectRepositorySerializer serializer, Commit oldCommit = null) { if (repository == null) { throw new ArgumentNullException(nameof(repository)); } if (definition == null) { throw new ArgumentNullException(nameof(definition)); } UpdateChangeTreeDefinitions(repository, changes.Modified, definition, serializer); UpdateChangeTreeDefinitions(repository, changes.Added, definition, serializer); UpdateDeletionTreeDefinitions(changes.Deleted, definition, oldCommit); UpdateIndexTreeDefinitions(repository, changes, definition, serializer); }
internal static Commit CommitChanges(this IRepository repository, ObjectRepositoryChangeCollection changes, IObjectRepositorySerializer serializer, string message, Signature author, Signature committer, GitHooks hooks, CommitOptions options = null, Commit mergeParent = null) { TreeDefinition definition; Commit startCommit; if (changes.OldRepository?.CommitId != null) { if (repository.Head.Tip.Id != changes.OldRepository.CommitId) { throw new GitObjectDbException("Changes are not based on the HEAD commit."); } startCommit = repository.Lookup <Commit>(changes.OldRepository.CommitId); definition = TreeDefinition.From(startCommit); } else if (repository.Info.IsHeadUnborn) { startCommit = null; definition = new TreeDefinition(); } else { throw new GitObjectDbException("Changes are not based on the HEAD commit."); } if (!hooks.OnCommitStarted(changes, message)) { return(null); } repository.UpdateTreeDefinition(changes, definition, serializer, startCommit); var result = Commit(repository, definition, message, author, committer, options, mergeParent); hooks.OnCommitCompleted(changes, message, result.Id); return(result); }
private static bool UpdateAndSerializerIndex(IObjectRepositoryIndex index, ObjectRepositoryChangeCollection changes, IObjectRepositorySerializer serializer, StringBuilder buffer, bool fullScan) { buffer.Clear(); var binding = index.DataAccessor.ConstructorParameterBinding; var updatedIndex = fullScan ? index.FullScan() : index.Update(changes); if (updatedIndex == null) { return(false); } var cloned = (IObjectRepositoryIndex)binding.Cloner(index, (instance, propertyName, type, fallback) => propertyName == nameof(IObjectRepositoryIndex.Values) ? updatedIndex : fallback, (childProperty, children, @new, dataAccessor) => throw new NotSupportedException("Index should not contain child properties.")); serializer.Serialize(cloned, buffer); return(true); }
private static void UpdateIndexTreeDefinitions(IRepository repository, ObjectRepositoryChangeCollection changes, TreeDefinition definition, IObjectRepositorySerializer serializer) { var buffer = new StringBuilder(); foreach (var index in changes.NewRepository.Indexes) { var fullScan = changes.Added.Any(c => c.New.Id == index.Id); if (UpdateAndSerializerIndex(index, changes, serializer, buffer, fullScan)) { definition.Add(index.GetDataPath(), repository.CreateBlob(buffer), Mode.NonExecutableFile); } } }
private static void UpdateChangeTreeDefinitions(IRepository repository, IEnumerable <ObjectRepositoryEntryChanges> changes, TreeDefinition definition, IObjectRepositorySerializer serializer) { var buffer = new StringBuilder(); foreach (var change in changes) { if (change.New is IObjectRepositoryIndex index) { // Index are managed separately continue; } buffer.Clear(); var nested = serializer.Serialize(change.New, buffer); definition.Add(change.Path, repository.CreateBlob(buffer), Mode.NonExecutableFile); foreach (var info in nested) { var nestedPath = change.New.GetDataPath(info.FileName); definition.Add(nestedPath, repository.CreateBlob(info.Data), Mode.NonExecutableFile); } } }
internal static ObjectRepositoryAdd ComputeChanges_Added(IObjectRepository objectRepository, IObjectRepositorySerializer serializer, IRepository repository, PatchEntryChanges change, Func <string, string> relativeFileDataResolver) { // Only data file changes have to be taken into account // Changes made to the blobs will product a 'modified' change as well if (System.IO.Path.GetFileName(change.Path) != FileSystemStorage.DataFile) { return(null); } if (objectRepository.TryGetFromGitPath(change.Path) != null) { throw new NotImplementedException("Node already present in current state."); } var parentDataPath = change.Path.GetDataParentDataPath(); if (objectRepository.TryGetFromGitPath(parentDataPath) == null) { throw new NotImplementedException("Node addition while parent has been deleted in head is not supported."); } var @new = serializer.Deserialize(repository.Lookup <Blob>(change.Oid).GetContentStream(), relativeFileDataResolver); var parentId = change.Path.GetDataParentId(objectRepository); return(new ObjectRepositoryAdd(change.Path, @new, parentId)); }
internal static IEnumerable <ObjectRepositoryPropertyChange> ComputeChanges_Modified(IObjectRepository objectRepository, IObjectRepositorySerializer serializer, PatchEntryChanges change, Func <string, Blob> relativeFileDataResolverStart, Func <string, Blob> relativeFileDataResolverEnd) { // Get data file path, in the case where a blob has changed var dataPath = change.Path.GetSiblingFile(FileSystemStorage.DataFile); var currentObject = objectRepository.TryGetFromGitPath(dataPath) ?? throw new NotImplementedException($"Conflict as a modified node {change.Path} has been deleted in current rebase state."); var changeStart = serializer.Deserialize( relativeFileDataResolverStart(FileSystemStorage.DataFile)?.GetContentStream() ?? throw new GitObjectDbException("Change start content could not be found."), relativePath => relativeFileDataResolverStart(relativePath)?.GetContentText() ?? string.Empty); var changeEnd = serializer.Deserialize( relativeFileDataResolverEnd(FileSystemStorage.DataFile)?.GetContentStream() ?? throw new GitObjectDbException("Change end content could not be found."), relativePath => relativeFileDataResolverEnd(relativePath)?.GetContentText() ?? string.Empty); var changes = ObjectRepositoryMerge.ComputeModifiedProperties(change, changeStart, changeEnd, currentObject); // Indexes will be recomputed anyways from the changes when committed, // so there is no need to track them in the modified chunks var changesWithoutIndexes = changes.Where( modifiedProperty => !typeof(IObjectRepositoryIndex).IsAssignableFrom(modifiedProperty.Property.Property.ReflectedType)); return(changesWithoutIndexes); }