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

com.beijunyi.parallelgit.filesystem.io.GfsIO Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
package com.beijunyi.parallelgit.filesystem.io;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileAttributeView;
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.beijunyi.parallelgit.filesystem.GitFileSystem;
import com.beijunyi.parallelgit.filesystem.GitPath;
import com.beijunyi.parallelgit.filesystem.utils.FileAttributeReader;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;

public final class GfsIO {

  @Nonnull
  private static GitPath getParent(@Nonnull GitPath child) {
    if(child.isRoot())
      throw new IllegalArgumentException(child.toString());
    GitPath parent = child.getParent();
    if(parent == null)
      throw new IllegalStateException(child.toString());
    return parent;
  }

  @Nullable
  private static Node findNode(@Nonnull GitPath path) throws IOException {
    if(!path.isAbsolute())
      throw new IllegalArgumentException(path.toString());
    Node current = path.getFileStore().getRoot();
    for(int i = 0; i < path.getNameCount(); i++) {
      GitPath name = path.getName(i);
      if(current instanceof DirectoryNode)
        current = prepareDirectory((DirectoryNode) current, path.getFileSystem()).getChild(name.toString());
      else
        return null;
    }
    return current;
  }

  @Nonnull
  private static Node getNode(@Nonnull GitPath path) throws IOException {
    Node node = findNode(path);
    if(node == null)
      throw new NoSuchFileException(path.toString());
    return node;
  }

  @Nonnull
  private static FileNode asFile(@Nullable Node node, @Nonnull GitPath path) throws NoSuchFileException, AccessDeniedException {
    if(node == null)
      throw new NoSuchFileException(path.toString());
    if(node instanceof FileNode)
      return (FileNode) node;
    throw new AccessDeniedException(path.toString());
  }

  @Nonnull
  static FileNode findFile(@Nonnull GitPath file) throws IOException {
    return asFile(findNode(file), file);
  }

  @Nonnull
  private static DirectoryNode asDirectory(@Nullable Node node, @Nonnull GitPath path) throws NotDirectoryException {
    if(node instanceof DirectoryNode)
      return (DirectoryNode) node;
    throw new NotDirectoryException(path.toString());
  }

  @Nonnull
  static DirectoryNode findDirectory(@Nonnull GitPath dir) throws IOException {
    return asDirectory(findNode(dir), dir);
  }

  @Nonnull
  private static String getFileName(@Nonnull GitPath path) throws IOException {
    GitPath name = path.getFileName();
    assert name != null;
    return name.toString();
  }

  @Nonnull
  private static byte[] readBlobObject(@Nullable AnyObjectId blobObjectId, @Nonnull GitFileSystem gfs) throws IOException {
    if(blobObjectId == null)
      return new byte[0];
    return gfs.loadObject(blobObjectId);
  }

  @Nonnull
  private static byte[] loadFileData(@Nonnull FileNode file, @Nonnull GitFileSystem gfs) throws IOException {
    byte[] bytes = readBlobObject(file.getObject(), gfs);
    file.loadContent(bytes);
    return bytes;
  }

  @Nonnull
  public static byte[] getFileData(@Nonnull FileNode file, @Nonnull GitFileSystem gfs) throws IOException {
    byte[] bytes = file.getBytes();
    if(bytes == null)
      bytes = loadFileData(file, gfs);
    return bytes;
  }

  private static long readBlobSize(@Nullable AnyObjectId blobObjectId, @Nonnull GitFileSystem gfs) throws IOException {
    if(blobObjectId == null)
      return 0;
    return gfs.getBlobSize(blobObjectId);
  }

  private static long loadFileSize(@Nonnull FileNode file, @Nonnull GitFileSystem gfs) throws IOException {
    long size = readBlobSize(file.getObject(), gfs);
    file.setSize(size);
    return size;
  }

  @Nonnull
  private static Map readTreeObject(@Nullable AnyObjectId treeObjectId, @Nonnull GitFileSystem gfs, @Nonnull DirectoryNode parent) throws IOException {
    Map children = new HashMap<>();
    if(treeObjectId != null) {
      byte[] treeData = gfs.loadObject(treeObjectId);
      CanonicalTreeParser treeParser = new CanonicalTreeParser();
      treeParser.reset(treeData);
      while(!treeParser.eof()) {
        children.put(treeParser.getEntryPathString(), Node.forObject(treeParser.getEntryObjectId(), treeParser.getEntryFileMode(), parent));
        treeParser.next();
      }
    }
    return children;
  }

  @Nonnull
  private static Map loadChildren(@Nonnull DirectoryNode dir, @Nonnull GitFileSystem gfs) throws IOException {
    Map children = readTreeObject(dir.getObject(), gfs, dir);
    dir.loadChildren(children);
    return children;
  }

  @Nonnull
  private static DirectoryNode prepareDirectory(@Nonnull DirectoryNode dir, @Nonnull GitFileSystem gfs) throws IOException {
    if(dir.getChildren() == null)
      loadChildren(dir, gfs);
    return dir;
  }

  @Nonnull
  public static Map getChildren(@Nonnull DirectoryNode dir, @Nonnull GitFileSystem gfs) throws IOException {
    Map children = prepareDirectory(dir, gfs).getChildren();
    assert children != null;
    return children;
  }

  public static long getSize(@Nonnull Node node, @Nonnull GitFileSystem gfs) throws IOException {
    long size;
    if(node instanceof FileNode) {
      FileNode file = (FileNode) node;
      size = file.getSize();
      if(size == -1L)
        size = loadFileSize(file, gfs);
    } else
      size = 0;
    return size;
  }

  @Nonnull
  public static GfsSeekableByteChannel newByteChannel(@Nonnull GitPath file, @Nonnull Set options, @Nonnull Collection attrs) throws IOException {
    if(file.isRoot())
      throw new AccessDeniedException(file.toString());
    FileNode node;
    if(options.contains(StandardOpenOption.CREATE) || options.contains(StandardOpenOption.CREATE_NEW)) {
      GitPath parent = getParent(file);
      DirectoryNode parentNode = prepareDirectory(findDirectory(parent), file.getFileSystem());
      String name = getFileName(file);
      if(options.contains(StandardOpenOption.CREATE_NEW) || !parentNode.hasChild(name)) {
        node = FileNode.newFile(FileAttributeReader.read(attrs).isExecutable(), parentNode);
        if(!parentNode.addChild(name, node, false))
          throw new FileAlreadyExistsException(file.toString());
      } else {
        node = asFile(parentNode.getChild(name), file);
      }
    } else
      node = findFile(file);
    return new GfsSeekableByteChannel(node, file.getFileSystem(), options);
  }

  @Nonnull
  public static GfsDirectoryStream newDirectoryStream(@Nonnull GitPath dir, @Nullable DirectoryStream.Filter filter) throws IOException {
    DirectoryNode node = prepareDirectory(findDirectory(dir), dir.getFileSystem());
    return new GfsDirectoryStream(node, dir, filter);
  }

  public static void createDirectory(@Nonnull GitPath dir) throws IOException {
    if(dir.isRoot())
      throw new FileAlreadyExistsException(dir.toString());
    GitPath parent = getParent(dir);
    DirectoryNode parentNode = prepareDirectory(findDirectory(parent), dir.getFileSystem());
    if(!parentNode.addChild(getFileName(dir), DirectoryNode.newDirectory(parentNode), false))
      throw new FileAlreadyExistsException(dir.toString());
  }

  private static void copyFile(@Nonnull FileNode source, @Nonnull GitFileSystem sourceFs, @Nonnull FileNode target) throws IOException {
    byte[] bytes = source.getBytes();
    if(bytes == null) {
      assert source.getObject() != null;
      bytes = sourceFs.loadObject(source.getObject());
    }
    target.updateContent(bytes);
  }

  private static void copyDirectory(@Nonnull DirectoryNode source, @Nonnull GitFileSystem sourceFs, @Nonnull DirectoryNode target, @Nonnull GitFileSystem targetFs) throws IOException {
    Map children = source.getChildren();
    if(children == null)
      children = readTreeObject(source.getObject(), sourceFs, source);
    Map clonedChildren = new HashMap<>();
    for(Map.Entry child : children.entrySet()) {
      Node clonedChild = Node.cloneNode(child.getValue(), target);
      clonedChildren.put(child.getKey(), clonedChild);
      copyNode(child.getValue(), sourceFs, clonedChild, targetFs);
    }
    target.setChildren(clonedChildren);
  }

  private static void copyNode(@Nonnull Node source, @Nonnull GitFileSystem sourceFs, @Nonnull Node target, @Nonnull GitFileSystem targetFs) throws IOException {
    if(!source.isDirty() && source.getObject() != null && targetFs.hasObject(source.getObject())) {
      target.setObject(source.getObject());
      return;
    }
    if(source instanceof FileNode && target instanceof FileNode)
      copyFile((FileNode) source, sourceFs, (FileNode) target);
    else if(source instanceof DirectoryNode && target instanceof DirectoryNode)
      copyDirectory((DirectoryNode) source, sourceFs, (DirectoryNode) target, targetFs);
    else
      throw new IllegalStateException();
  }

  public static boolean copy(@Nonnull GitPath source, @Nonnull GitPath target, @Nonnull Set options) throws IOException {
    Node sourceNode = getNode(source);
    if(source.equals(target))
      return false;
    if(target.isRoot())
      throw new FileAlreadyExistsException(target.toString());
    GitPath targetParent = getParent(target);
    DirectoryNode targetDirectory = prepareDirectory(findDirectory(targetParent), target.getFileSystem());
    Node targetNode = Node.cloneNode(sourceNode, targetDirectory);
    if(!targetDirectory.addChild(getFileName(target), targetNode, options.contains(StandardCopyOption.REPLACE_EXISTING)))
      throw new FileAlreadyExistsException(target.toString());
    copyNode(sourceNode, source.getFileSystem(), targetNode, target.getFileSystem());
    return true;
  }

  public static boolean move(@Nonnull GitPath source, @Nonnull GitPath target, @Nonnull Set options) throws IOException {
    if(copy(source, target, options)) {
      delete(source);
      return true;
    }
    return false;
  }

  public static void delete(@Nonnull GitPath file) throws IOException {
    if(file.isRoot())
      throw new AccessDeniedException(file.toString());
    GitPath parent = getParent(file);
    DirectoryNode parentNode = prepareDirectory(findDirectory(parent), file.getFileSystem());
    if(!parentNode.removeChild(getFileName(file)))
      throw new NoSuchFileException(file.toString());
  }

  public static void checkAccess(@Nonnull GitPath path, @Nonnull Set modes) throws IOException {
    Node node = getNode(path);
    if(modes.contains(AccessMode.EXECUTE) && !node.isExecutableFile())
      throw new AccessDeniedException(path.toString());
  }

  @Nullable
  public static  V getFileAttributeView(@Nonnull GitPath path, @Nonnull Class type) throws IOException, UnsupportedOperationException {
    Node node = findNode(path);
    if(node != null)
      return GfsFileAttributeView.forNode(node, path.getFileSystem(), type);
    return null;
  }

  @Nonnull
  private static AnyObjectId persistFile(@Nonnull FileNode file, @Nonnull GitFileSystem gfs) throws IOException {
    byte[] bytes = file.getBytes();
    if(bytes == null)
      throw new IllegalStateException();
    return gfs.saveBlob(bytes);
  }

  @Nullable
  private static AnyObjectId persistDirectory(@Nonnull DirectoryNode dir, boolean isRoot, @Nonnull GitFileSystem gfs) throws IOException {
    Map children = dir.getChildren();
    int count = 0;
    TreeFormatter formatter = new TreeFormatter();
    if(children != null) {
      for(Map.Entry child : new TreeMap<>(children).entrySet()) {
        String name = child.getKey();
        Node node = child.getValue();
        AnyObjectId nodeObject = persistNode(node, false, gfs);
        if(nodeObject != null) {
          formatter.append(name, node.getType().toFileMode(), nodeObject);
          count++;
        }
      }
    }
    return (isRoot || count != 0) ? gfs.saveTree(formatter) : null;
  }

  @Nullable
  private static AnyObjectId persistNode(@Nonnull Node node, boolean isRoot, @Nonnull GitFileSystem gfs) throws IOException {
    if(!node.isDirty())
      return node.getObject();
    AnyObjectId nodeObject;
    if(node instanceof FileNode)
      nodeObject = persistFile((FileNode) node, gfs);
    else if(node instanceof DirectoryNode)
      nodeObject = persistDirectory((DirectoryNode) node, isRoot, gfs);
    else
      throw new IllegalStateException();
    if(nodeObject != null)
      node.markClean(nodeObject);
    return nodeObject;
  }

  @Nonnull
  public static AnyObjectId persistRoot(@Nonnull GitFileSystem gfs) throws IOException {
    Node root = gfs.getFileStore().getRoot();
    AnyObjectId ret = persistNode(root, true, gfs);
    assert ret != null;
    return ret;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy