All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.resys.thena.docdb.spi.commits.CommitVisitor Maven / Gradle / Ivy

The newest version!
package io.resys.thena.docdb.spi.commits;

/*-
 * #%L
 * thena-docdb-api
 * %%
 * Copyright (C) 2021 Copyright 2021 ReSys OÜ
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.immutables.value.Value;

import io.resys.thena.docdb.api.actions.ObjectsActions.RefObjects;
import io.resys.thena.docdb.api.models.ImmutableBlob;
import io.resys.thena.docdb.api.models.ImmutableCommit;
import io.resys.thena.docdb.api.models.ImmutableMessage;
import io.resys.thena.docdb.api.models.ImmutableRef;
import io.resys.thena.docdb.api.models.ImmutableTree;
import io.resys.thena.docdb.api.models.ImmutableTreeValue;
import io.resys.thena.docdb.api.models.Message;
import io.resys.thena.docdb.api.models.Objects.Blob;
import io.resys.thena.docdb.api.models.Objects.Commit;
import io.resys.thena.docdb.api.models.Objects.Ref;
import io.resys.thena.docdb.api.models.Objects.Tree;
import io.resys.thena.docdb.api.models.Objects.TreeValue;
import io.resys.thena.docdb.api.models.Repo;

public class CommitVisitor {
  
  
  @Value.Immutable
  interface RedundentCommitTree {
    boolean isEmpty();
    Map getTreeValues();
    Map getBlobs();
    String getLog();
  }

  @Value.Immutable
  public interface RedundentHashedBlob {
    String getName();
    String getHash();
    String getBlob();
  }
  
  @Value.Immutable
  public interface CommitInput {
    Optional getParent();
    Repo getRepo();
    String getRef();
    String getCommitAuthor();
    String getCommitMessage();
    Map getAppend();
    Collection getRemove();
  }
  
  public enum CommitOutputStatus {
    OK, EMPTY, ERROR, CONFLICT
  }
  
  @Value.Immutable
  public interface CommitOutput {
    CommitOutputStatus getStatus();
    Repo getRepo();
    Message getLog();
    Ref getRef();
    Commit getCommit();
    Tree getTree();
    Collection getBlobs();
    List getMessages();
  }
  
  private final Map nextBlobs = new HashMap<>();
  private final Map nextTree = new HashMap<>();
  private final StringBuilder logger = new StringBuilder();
  private boolean dataDeleted = false;
  private boolean dataAdded = false;
  
  
  public CommitOutput visit(CommitInput input) {
    if(input.getParent().isPresent()) {
      visitParent(input.getParent().get());
    }
    visitAppend(input.getAppend());
    visitRemove(input.getRemove());
    
    Tree tree = visitTree();
    Collection blobs = visitBlobs();
    Commit commit = visitCommit(tree, input);
    
    return ImmutableCommitOutput.builder()
        .log(visitLog())
        .repo(input.getRepo())
        .ref(visitRef(commit, input))
        .status(visitEmpty())
        .tree(tree)
        .blobs(blobs)
        .commit(commit)
        .build();
  }
  private Ref visitRef(Commit commit, CommitInput input) {
    return ImmutableRef.builder()
        .commit(commit.getId())
        .name(input.getRef())
        .build();
  }
  
  private Commit visitCommit(Tree tree, CommitInput input) {
    final Optional parent = input.getParent().map(r -> r.getCommit().getId());
    final Commit commitTemplate = ImmutableCommit.builder()
      .id("commit-template")
      .author(input.getCommitAuthor())
      .message(input.getCommitMessage())
      .dateTime(LocalDateTime.now())
      .parent(parent)
      .tree(tree.getId())
      .build();
    final Commit commit = ImmutableCommit.builder()
        .from(commitTemplate)
        .id(Sha2.commitId(commitTemplate))
        .build();
    
    return commit;
  }
  
  private Collection visitBlobs() {
    final Collection blobs = nextBlobs.values();
    return blobs;
  }
  
  private Tree visitTree() {
    final Tree tree = ImmutableTree.builder()
        .id(Sha2.treeId(nextTree))
        .values(nextTree)
        .build();
    return tree;
  }
  
  private CommitOutputStatus visitEmpty() {
    boolean isEmpty = !(dataDeleted || dataAdded);
    return isEmpty ? CommitOutputStatus.EMPTY : CommitOutputStatus.OK;
  }
  private Message visitLog() {
    return ImmutableMessage.builder().text(logger.toString()).build();
  }
  
  private void visitParent(RefObjects parent) {
    this.nextTree.putAll(parent.getTree().getValues());
  }
  
  private void visitAppend(Map newBlobs) {
    List hashed = newBlobs.entrySet().stream()
      .map(this::visitAppendEntry)
      .collect(Collectors.toList());
    
    for(RedundentHashedBlob entry : hashed) {
      logger
      .append(System.lineSeparator())
      .append("  + ").append(entry.getName());
      
      if(nextTree.containsKey(entry.getName())) {
        TreeValue previous = nextTree.get(entry.getName());
        if(previous.getBlob().equals(entry.getHash())) {
          logger.append(" | no changes");
          continue;
        }
        logger.append(" | changed"); 
      } else {
        logger.append(" | added");        
      }
      
      nextBlobs.put(entry.getHash(), ImmutableBlob.builder()
          .id(entry.getHash())
          .value(new io.vertx.core.json.JsonObject(entry.getBlob()))
          .build());
      nextTree.put(entry.getName(), ImmutableTreeValue.builder()
          .name(entry.getName())
          .blob(entry.getHash())
          .build());
      dataAdded = true;
    }
    
    if(!hashed.isEmpty()) {
      logger.append(System.lineSeparator());
    }
  }
  
  private void visitRemove(Collection removeBlobs) {
    if(!removeBlobs.isEmpty()) {
      logger.append("Removing following:").append(System.lineSeparator());
    }
    for(String name : removeBlobs) {
      logger.append(System.lineSeparator()).append("  - ").append(name);
      if(nextTree.containsKey(name)) {
        nextTree.remove(name);
        dataDeleted = true;
        logger.append(" | deleted");
      } else {
        logger.append(" | doesn't exist");
      }
    }
    if(!removeBlobs.isEmpty()) {
      logger.append(System.lineSeparator());
    }
  }
  
  private RedundentHashedBlob visitAppendEntry(Map.Entry entry) {
    return ImmutableRedundentHashedBlob.builder()
      .hash(Sha2.blobId(new io.vertx.core.json.JsonObject(entry.getValue()).encode()))
      .blob(entry.getValue())
      .name(entry.getKey())
      .build();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy