Skip to content

Instantly share code, notes, and snippets.

@sim642
Last active May 9, 2016 11:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sim642/d5028f2a9dbcc70b2b1397c0a9ec5733 to your computer and use it in GitHub Desktop.
Save sim642/d5028f2a9dbcc70b2b1397c0a9ec5733 to your computer and use it in GitHub Desktop.
diff of refactoring Java NIO into shy, produced by shy, after importing git repository to shy
--- /src/main/java/ee/shy/cli/command/AddCommand.java
+++ /src/main/java/ee/shy/cli/command/AddCommand.java
@@ -2,21 +2,21 @@
import ee.shy.cli.Command;
import ee.shy.cli.HelptextBuilder;
import ee.shy.core.Repository;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Paths;
/**
* A command to add given file to its respective directory in the repository.
*/
public class AddCommand implements Command {
@Override
public void execute(String[] args) throws IOException {
Repository repository = Repository.newExisting();
- repository.add(new File(args[0]));
+ repository.add(Paths.get(args[0]));
}
@Override
public String getHelp() {
return new HelptextBuilder()
--- /src/main/java/ee/shy/cli/command/RemoveCommand.java
+++ /src/main/java/ee/shy/cli/command/RemoveCommand.java
@@ -2,21 +2,21 @@
import ee.shy.cli.Command;
import ee.shy.cli.HelptextBuilder;
import ee.shy.core.Repository;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Paths;
/**
* A command to remove given file from its respective directory in the repository.
*/
public class RemoveCommand implements Command {
@Override
public void execute(String[] args) throws IOException {
Repository repository = Repository.newExisting();
- repository.remove(new File(args[0]));
+ repository.remove(Paths.get(args[0]));
}
@Override
public String getHelp() {
return new HelptextBuilder()
--- /src/main/java/ee/shy/cli/command/TestCommand.java
+++ /src/main/java/ee/shy/cli/command/TestCommand.java
@@ -2,10 +2,12 @@
import ee.shy.cli.Command;
import ee.shy.cli.HelptextBuilder;
import ee.shy.core.Repository;
+import java.io.IOException;
+
/**
* A simple command for testing.
*/
public class TestCommand implements Command {
private final String name;
@@ -13,11 +15,11 @@
public TestCommand(String name) {
this.name = name;
}
@Override
- public void execute(String[] args) {
+ public void execute(String[] args) throws IOException {
System.out.println(name);
Repository repository = Repository.newExisting();
}
@Override
--- /src/main/java/ee/shy/core/Repository.java
+++ /src/main/java/ee/shy/core/Repository.java
@@ -1,213 +1,219 @@
package ee.shy.core;
import ee.shy.io.Json;
+import ee.shy.io.PathUtils;
import ee.shy.map.DirectoryJsonMap;
import ee.shy.map.NamedObjectMap;
import ee.shy.storage.*;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.output.TeeOutputStream;
-import java.io.*;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.Arrays;
-
/**
* Class for creating and interacting with a repository.
*/
public class Repository {
/**
- * Repository's root directory.
+ * Repository root directory path.
*/
- private final File repositoryDirectory;
+ private final Path rootPath;
- /**
- * {@link #repositoryDirectory}'s parent directory.
- */
- private final File rootDirectory;
-
private final DataStorage storage;
private final NamedObjectMap<Branch> branches;
/**
* Constructs a new repository class.
- * @param rootDirectory root directory for repository
+ * @param rootPath root directory for repository
*/
- private Repository(File rootDirectory) {
- this.rootDirectory = rootDirectory;
- this.repositoryDirectory = new File(rootDirectory, ".shy");
+ private Repository(Path rootPath) throws IOException {
+ this.rootPath = rootPath;
this.storage = new FileStorage(
Arrays.asList(
- new FlatFileLocator(new File(repositoryDirectory, "storage"))
+ new FlatFileLocator(getRepositoryPath().resolve("storage"))
),
new PlainFileAccessor());
- branches = new DirectoryJsonMap<>(Branch.class, repositoryDirectory.toPath().resolve("branches"));
+ branches = new DirectoryJsonMap<>(Branch.class, getRepositoryPath().resolve("branches"));
}
/**
* Tries to find an existing repository in the directory shy was executed or its parent directories.
* @return repository object if existing repository was found, null otherwise
*/
- public static Repository newExisting() throws RepositoryNotFoundException {
- File currentDirectory = new File(System.getProperty("user.dir"));
- while (currentDirectory != null) {
- File repositoryDirectory = new File(currentDirectory, ".shy");
- if (repositoryDirectory.exists() && repositoryDirectory.isDirectory()) {
- return new Repository(currentDirectory);
+ public static Repository newExisting() throws RepositoryNotFoundException, IOException {
+ Path currentPath = PathUtils.getCurrentPath();
+ while (currentPath != null) {
+ Path repositoryPath = getRepositoryPath(currentPath);
+ if (Files.isDirectory(repositoryPath)) {
+ return new Repository(currentPath);
}
- currentDirectory = currentDirectory.getParentFile();
+ currentPath = currentPath.getParent();
}
+
throw new RepositoryNotFoundException();
}
/**
* Creates a new repository in the directory where shy was executed.
* @return a Repository object if repository creation was successful
* @throws IOException if repository hierarchy generation fails
*/
public static Repository newEmpty() throws IOException {
- File currentDirectory = new File(System.getProperty("user.dir"));
- File repositoryDirectory = new File(currentDirectory, ".shy");
- if (repositoryDirectory.exists() || repositoryDirectory.mkdir()) {
- String[] subDirectories = {"commit", "branches", "tags", "storage"};
- for (String subDirectory : subDirectories) {
- File f = new File(repositoryDirectory, subDirectory);
- if (!f.exists())
- f.mkdir();
- }
+ Path repositoryPath = getRepositoryPath(PathUtils.getCurrentPath());
+ Files.createDirectory(repositoryPath);
- String[] repositoryFiles = {"author", "current"};
- for (String repositoryFile : repositoryFiles) {
- File f = new File(repositoryDirectory, repositoryFile);
- if (!f.exists())
- f.createNewFile();
- }
+ String[] subDirectories = {"commit", "branches", "tags", "storage"};
+ for (String subDirectory : subDirectories) {
+ Files.createDirectory(repositoryPath.resolve(subDirectory));
+ }
- // The following will be refactored later in the project development(Phase 2)
- File current = new File(repositoryDirectory, "current");
- try (FileOutputStream currentStream = new FileOutputStream(current)) {
- currentStream.write(Hash.ZERO.toString().getBytes());
- }
+ String[] repositoryFiles = {"author", "current"};
+ for (String repositoryFile : repositoryFiles) {
+ Files.createFile(repositoryPath.resolve(repositoryFile));
+ }
- // TODO: 26.03.16 Create a config file to home directory upon installation to get author's details from.
- Author author = new Author(null, null);
- author.write(new FileOutputStream(new File(repositoryDirectory, "author")));
+ // TODO: 6.04.16 move current commit handling into separate class
+ IOUtils.write(Hash.ZERO.toString(), Files.newOutputStream(repositoryPath.resolve("current")));
- System.out.println("Initialized a shy repository in " + currentDirectory.getAbsolutePath());
+ Repository repository = new Repository(repositoryPath.getParent());
- Repository repository = new Repository(currentDirectory);
- repository.getBranches().put("master", new Branch(Hash.ZERO));
+ // TODO: 26.03.16 Create a config file to home directory upon installation to get author's details from.
+ Author author = new Author(null, null);
+ repository.setAuthor(author);
- return repository;
- }
- else {
- throw new IOException("Repository initialization failed!");
- }
+ repository.getBranches().put("master", new Branch(Hash.ZERO));
+
+ System.out.println("Initialized a shy repository in " + repository.getRootPath());
+ return repository;
}
/**
+ * Returns current directory file's path in ".shy/commit/" directory.
+ * @param path file which's path to transform
+ * @return transformed path in ".shy/commit/"
+ */
+ private Path getCommitPath(Path path) throws IOException {
+ Path commitPath = getRepositoryPath().resolve("commit");
+ /*
+ Beware of the pitfalls of oh-so-wonderful Path:
+ Path#toAbsolutePath does NOT normalize the path to an actual absolute path,
+ but simply prepends the current working directory.
+ */
+ return commitPath.resolve(rootPath.relativize(path.toRealPath()));
+ }
+
+ /**
* Copies given file to its respective directory in ".shy/commit/" directory.
- * @param file file that user wants to add to repository
+ * @param path file that user wants to add to repository
* @throws IOException if file can't be found or copying fails
*/
- public void add(File file) throws IOException {
- File fullFilePath = fullFilePath(file);
- fullFilePath.getParentFile().mkdirs();
- try (InputStream input = new FileInputStream(file)) {
- try (OutputStream output = new FileOutputStream(fullFilePath)) {
- IOUtils.copy(input, output);
- }
- }
+ public void add(Path path) throws IOException {
+ Path commitPath = getCommitPath(path);
+ /*
+ Beware of the pitfalls of oh-so-wonderful Path:
+ Files.createDirectories does unintuitive things for paths ending in "..".
+ For example, "/tmp/foo/bar/.." will cause "/tmp/foo/bar/" to be created yet it's not in the normalized path.
+ */
+ Files.createDirectories(commitPath.getParent());
+ Files.copy(path, commitPath);
}
/**
* Removes given file from its directory in ".shy/commit".
- * @param file file that user wants to remove from repository
+ * @param path file that user wants to remove from repository
* @throws IOException if file could not be deleted
*/
- public void remove(File file) throws IOException {
- Files.deleteIfExists(fullFilePath(file).toPath());
+ public void remove(Path path) throws IOException {
+ Files.deleteIfExists(getCommitPath(path));
}
/**
* Creates and stores the complete ".shy/commit/" directory tree.
* @return hash of stored tree
* @throws IOException if there was a problem storing the tree
*/
private Hash createCommitTree() throws IOException {
- Tree tree = new Tree.Builder(storage).fromDirectory(new File(repositoryDirectory, "commit")).create();
+ Tree tree = new Tree.Builder(storage).fromDirectory(getRepositoryPath().resolve("commit")).create();
return storage.put(tree.inputify());
}
/**
* Commits current commit with given message.
* @param message commit message
* @throws IOException if there was a problem storing the tree/commit or modifying ".shy/current"
*/
public void commit(String message) throws IOException {
Hash tree = createCommitTree();
- File currentFile = new File(repositoryDirectory, "current");
- Hash parent = new Hash(IOUtils.toString(new FileInputStream(currentFile), "UTF-8"));
+ Path currentPath = getRepositoryPath().resolve("current");
+ Hash parent = new Hash(IOUtils.toString(Files.newInputStream(currentPath), "UTF-8"));
Commit commit = new Commit.Builder()
.setTree(tree)
.addParent(parent)
.setAuthor(getAuthor())
.setTimeCurrent()
.setMessage(message)
.create();
Hash hash = storage.put(commit.inputify());
- File branchFile = new File(new File(repositoryDirectory, "branches"), "master"); // TODO: 26.03.16 update correct branch
- IOUtils.write(hash.toString(), new TeeOutputStream(new FileOutputStream(currentFile), new FileOutputStream(branchFile)), "UTF-8");
+ branches.put("master", new Branch(hash)); // TODO: 26.03.16 update correct branch
+ IOUtils.write(hash.toString(), Files.newOutputStream(currentPath));
}
/**
- * Creates given file's path relative to repository's directory.
- * @param file file that's relative path is wanted to be create
- * @return file's path relative to repository's directory
- */
- private File relativeFilePath(File file) {
- File fileDir = new File(System.getProperty("user.dir"), file.getPath()).getParentFile();
-
- Path path = Paths.get(fileDir.getPath());
- path = this.rootDirectory.toPath().relativize(path);
-
- return new File(path.toFile().getPath(), file.getName());
- }
-
- /**
- * Creates full path from system's root to given file in ".shy/commit/" directory.
- * @param file file that's path is wanted to be create
- * @return file path from system's root to given file'is directory in ".shy/commit/"
- */
- private File fullFilePath(File file) {
- File repositoryDirectory = new File(this.rootDirectory.getPath(), ".shy/commit/");
- return new File(repositoryDirectory, relativeFilePath(file).getPath());
- }
-
- /**
* Get the Author object of this repository.
* @return Author object of '.shy/author' file
* @throws IOException if file '.shy/author' does not exist or reading fails
*/
public Author getAuthor() throws IOException {
- FileInputStream fis = new FileInputStream(new File(repositoryDirectory, "author"));
- return Json.read(fis, Author.class);
+ return Json.read(Files.newInputStream(getAuthorPath()), Author.class);
}
/**
* Set the '.shy/author' file contents to given Author file contents.
* @param author Author object that is assigned to this repository
* @throws IOException if write fails
*/
public void setAuthor(Author author) throws IOException {
- author.write(new FileOutputStream(new File(repositoryDirectory, "author")));
+ author.write(Files.newOutputStream(getAuthorPath()));
}
public NamedObjectMap<Branch> getBranches() {
return branches;
}
+
+ /**
+ * Returns repository's root path.
+ * @return root directory path
+ */
+ public Path getRootPath() {
+ return rootPath;
+ }
+
+ /**
+ * Returns repository's ".shy/" directory path in given root directory.
+ * @param rootPath root directory of repository
+ * @return repository directory path
+ */
+ private static Path getRepositoryPath(Path rootPath) {
+ return rootPath.resolve(".shy");
+ }
+
+ /**
+ * Returns repository's ".shy/" directory path.
+ * @return repository directory path
+ */
+ private Path getRepositoryPath() {
+ return getRepositoryPath(rootPath);
+ }
+
+ /**
+ * Returns repository's "author" file path.
+ * @return author file path
+ */
+ private Path getAuthorPath() {
+ return getRepositoryPath().resolve("author");
+ }
}
--- /src/main/java/ee/shy/core/Tree.java
+++ /src/main/java/ee/shy/core/Tree.java
@@ -2,16 +2,15 @@
import ee.shy.io.Jsonable;
import ee.shy.storage.DataStorage;
import ee.shy.storage.Hash;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.TreeMap;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.stream.Collectors;
/**
* Class representing a directory tree.
*/
public class Tree extends Jsonable {
@@ -66,26 +65,24 @@
* Builds tree using given directory content and stores all referenced data.
* @param directory directory to build tree from
* @return builder itself
* @throws IOException if there was a problem reading an addable file or tree to storage
*/
- public Builder fromDirectory(File directory) throws IOException {
- File[] files = directory.listFiles();
- if (files == null)
- throw new IOException("Attempted to build Tree from a non-directory");
+ public Builder fromDirectory(Path directory) throws IOException {
+ List<Path> files = new ArrayList<>(Files.list(directory).collect(Collectors.toList())); // TODO: 6.04.16 Stream#toCollection for creating ArrayList
- Arrays.sort(files); // guarantee stable order
+ Collections.sort(files);
- for (File file : files) {
- if (file.isFile()) {
- Hash hash = storage.put(new FileInputStream(file));
- addItem(file.getName(), new TreeItem(TreeItem.Type.FILE, hash));
+ for (Path file : files) {
+ if (Files.isRegularFile(file)) {
+ Hash hash = storage.put(Files.newInputStream(file));
+ addItem(file.getFileName().toString(), new TreeItem(TreeItem.Type.FILE, hash));
}
- else if (file.isDirectory()) {
+ else if (Files.isDirectory(file)) {
Tree tree = new Builder(storage).fromDirectory(file).create();
Hash hash = storage.put(tree.inputify());
- addItem(file.getName(), new TreeItem(TreeItem.Type.TREE, hash));
+ addItem(file.getFileName().toString(), new TreeItem(TreeItem.Type.TREE, hash));
}
}
return this;
}
+++ /src/main/java/ee/shy/io/PathUtils.java
@@ -1,0 +1,42 @@
+package ee.shy.io;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Utilities class for I/O-related methods.
+ */
+public class PathUtils {
+ private PathUtils() {
+
+ }
+
+ /**
+ * Returns current working directory as path.
+ * @return current working directory
+ */
+ public static Path getCurrentPath() {
+ return Paths.get(System.getProperty("user.dir"));
+ }
+
+ /**
+ * Adds given extension to file path.
+ * @param path file path to extend
+ * @param extension extension to add
+ * @return file path with given extension
+ */
+ public static Path addExtension(Path path, String extension) {
+ return path.resolveSibling(path.getFileName().toString() + extension);
+ }
+
+ /**
+ * Creates given path's parent directories.
+ * If path itself is a directory, it too will be created.
+ * @param path path which's parent directories to create
+ */
+ public static void createParentDirectories(Path path) throws IOException {
+ Files.createDirectories(Files.isDirectory(path) ? path : path.getParent());
+ }
+}
+++ /src/main/java/ee/shy/io/Utils.java
@@ -1,0 +1,14 @@
+package ee.shy.io;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class Utils {
+ private Utils() {
+
+ }
+
+ public static Path getCurrentPath() {
+ return Paths.get(System.getProperty("user.dir"));
+ }
+}
--- /src/main/java/ee/shy/storage/AggregateFileAccessor.java
+++ /src/main/java/ee/shy/storage/AggregateFileAccessor.java
@@ -1,10 +1,10 @@
package ee.shy.storage;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
import java.util.List;
/**
* File accessor to aggregate other file accessors.
* Allows simultaneous support for multiple accessors.
@@ -23,30 +23,30 @@
this.accessors = accessors;
}
/**
* Adds file content via first file accessor.
- * @param file base path of file to add
+ * @param path base path of file to add
* @param source input stream to get data from
* @throws IOException if there was a problem reading the input stream or writing to the file
*/
@Override
- public void add(File file, InputStream source) throws IOException {
- accessors.get(0).add(file, source); // always use first accessor for add
+ public void add(Path path, InputStream source) throws IOException {
+ accessors.get(0).add(path, source); // always use first accessor for add
}
/**
* Gets file content via first successful file accessor.
- * @param file base path of file to get
+ * @param path base path of file to get
* @return input stream to get data from
* @throws IOException if there was a problem reading from the file
*/
@Override
- public InputStream get(File file) throws IOException {
+ public InputStream get(Path path) throws IOException {
InputStream source;
for (FileAccessor accessor : accessors) {
- if ((source = accessor.get(file)) != null)
+ if ((source = accessor.get(path)) != null)
return source;
}
return null;
}
}
--- /src/main/java/ee/shy/storage/FileAccessor.java
+++ /src/main/java/ee/shy/storage/FileAccessor.java
@@ -1,27 +1,27 @@
package ee.shy.storage;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
/**
* An interface for accessing file content by base path from a {@link FileLocator}.
* Used to add/get data via a stream.
*/
public interface FileAccessor {
/**
* Adds file content to given base path of file
- * @param file base path of file to add
+ * @param path base path of file to add
* @param source input stream to get data from
* @throws IOException if there was a problem reading the input stream or writing to the file
*/
- void add(File file, InputStream source) throws IOException;
+ void add(Path path, InputStream source) throws IOException;
/**
* Gets file content from given base path of file
- * @param file base path of file to get
+ * @param path base path of file to get
* @return input stream to get data from
* @throws IOException if there was a problem reading from some input
*/
- InputStream get(File file) throws IOException;
+ InputStream get(Path path) throws IOException;
}
--- /src/main/java/ee/shy/storage/FileLocator.java
+++ /src/main/java/ee/shy/storage/FileLocator.java
@@ -1,57 +1,55 @@
package ee.shy.storage;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
/**
* An abstract class for locating files by hash.
* Used to get file paths by hash to use with {@link FileAccessor}.
*/
public abstract class FileLocator {
/**
* Root directory to use.
*/
- protected final File root;
+ protected final Path root;
/**
* Constructs a new locator with given root.
* @param root root directory to use
*/
- public FileLocator(File root) {
- if (!root.exists())
- root.mkdirs();
- if (!root.isDirectory())
- throw new RuntimeException("root must be a directory"); // TODO: 9.03.16 throw better exception
-
+ public FileLocator(Path root) throws IOException {
+ Files.createDirectories(root);
this.root = root;
}
/**
* Locates a file by hash.
* Suitable for overriding both {@link #locateAdd(Hash)} and {@link #locateGet(Hash)}.
* @param hash hash to get path for
* @return path to file for given hash
*/
- public File locate(Hash hash) {
+ public Path locate(Hash hash) throws IOException {
return null;
}
/**
* Locates a supposed file by hash for addition.
* Suitable for overriding to add extra behavior on addition.
* @param hash hash to get path for
* @return supposed path to file for given hash
*/
- public File locateAdd(Hash hash) {
+ public Path locateAdd(Hash hash) throws IOException {
return locate(hash);
}
/**
* Locates a file by hash for retrieval.
* Suitable for overriding to add extra behavior on retrieval.
* @param hash hash to get path for
* @return path to file for given hash
*/
- public File locateGet(Hash hash) {
+ public Path locateGet(Hash hash) throws IOException {
return locate(hash);
}
}
--- /src/main/java/ee/shy/storage/FlatFileLocator.java
+++ /src/main/java/ee/shy/storage/FlatFileLocator.java
@@ -1,21 +1,22 @@
package ee.shy.storage;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
/**
* File locator for having all hashes in the root directory.
*/
public class FlatFileLocator extends FileLocator {
/**
* Constructs a new flat file locator with given root.
* @param root root directory to use
*/
- public FlatFileLocator(File root) {
+ public FlatFileLocator(Path root) throws IOException {
super(root);
}
@Override
- public File locate(Hash hash) {
- return new File(root, hash.toString());
+ public Path locate(Hash hash) {
+ return root.resolve(hash.toString());
}
}
--- /src/main/java/ee/shy/storage/GitFileLocator.java
+++ /src/main/java/ee/shy/storage/GitFileLocator.java
@@ -1,8 +1,9 @@
package ee.shy.storage;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
/**
* File locator for having hashes in git-like directory structure in the root directory:
* first two characters of hash represent a subdirectory,
* remaining hash characters the filename.
@@ -10,9 +11,9 @@
public class GitFileLocator extends NestedFileLocator {
/**
* Constructs a new git file locator with given root.
* @param root root directory to use
*/
- public GitFileLocator(File root) {
+ public GitFileLocator(Path root) throws IOException {
super(root, 2, 1);
}
}
--- /src/main/java/ee/shy/storage/GzipFileAccessor.java
+++ /src/main/java/ee/shy/storage/GzipFileAccessor.java
@@ -1,10 +1,13 @@
package ee.shy.storage;
+import ee.shy.io.PathUtils;
import org.apache.commons.io.IOUtils;
import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* File accessor to store data compressed using GZIP.
@@ -15,20 +18,20 @@
* Extension used on base paths.
*/
private static final String EXTENSION = ".gz"; // TODO: 9.03.16 create superclass for extension handling
@Override
- public void add(File file, InputStream source) throws IOException {
- try (GZIPOutputStream target = new GZIPOutputStream(new FileOutputStream(Util.addExtension(file, EXTENSION)))) {
+ public void add(Path path, InputStream source) throws IOException {
+ try (GZIPOutputStream target = new GZIPOutputStream(Files.newOutputStream(PathUtils.addExtension(path, EXTENSION)))) {
IOUtils.copy(source, target);
}
}
@Override
- public InputStream get(File file) throws IOException {
+ public InputStream get(Path path) throws IOException {
try {
- return new GZIPInputStream(new FileInputStream(Util.addExtension(file, EXTENSION)));
+ return new GZIPInputStream(Files.newInputStream(PathUtils.addExtension(path, EXTENSION)));
}
catch (FileNotFoundException e) {
return null;
}
}
--- /src/main/java/ee/shy/storage/NestedFileLocator.java
+++ /src/main/java/ee/shy/storage/NestedFileLocator.java
@@ -1,9 +1,12 @@
package ee.shy.storage;
-import java.io.File;
+import ee.shy.io.PathUtils;
+import java.io.IOException;
+import java.nio.file.Path;
+
/**
* File locator for having hashes in nested directory structure in the root directory:
* every {@link #directoryLength} characters of hash represent a subdirectory,
* limited by having at most {@link #depthMax} subdirectories,
* remaining hash characters the filename.
@@ -27,40 +30,41 @@
/**
* Constructs a new nested file locator with given root with unlimited nesting depth.
* @param root root directory to use
* @param directoryLength length of each subdirectory name
*/
- public NestedFileLocator(File root, int directoryLength) {
+ public NestedFileLocator(Path root, int directoryLength) throws IOException {
this(root, directoryLength, DEPTH_UNLIMITED);
}
/**
* Constructs a new nested file locator with given root.
* @param root root directory to use
* @param directoryLength length of each subdirectory name
* @param depthMax maximum nesting depth, unlimited with {@link #DEPTH_UNLIMITED}
*/
- public NestedFileLocator(File root, int directoryLength, int depthMax) {
+ public NestedFileLocator(Path root, int directoryLength, int depthMax) throws IOException {
super(root);
this.directoryLength = directoryLength;
this.depthMax = depthMax;
}
@Override
- public File locate(Hash hash) {
+ public Path locate(Hash hash) {
String hashString = hash.toString();
- File file = root;
+ Path path = root;
int depth;
for (depth = 0; (depthMax == DEPTH_UNLIMITED || depth < depthMax) && (directoryLength * (depth + 1) < hashString.length()); depth++)
- file = new File(file, hashString.substring(directoryLength * depth, directoryLength * (depth + 1)));
+ path = path.resolve(hashString.substring(directoryLength * depth, directoryLength * (depth + 1)));
- file = new File(file, hashString.substring(directoryLength * depth));
- return file;
+ path = path.resolve(hashString.substring(directoryLength * depth));
+ return path;
}
@Override
- public File locateAdd(Hash hash) {
- File file = locate(hash);
- return Util.ensurePath(file) ? file : null;
+ public Path locateAdd(Hash hash) throws IOException {
+ Path path = locate(hash);
+ PathUtils.createParentDirectories(path);
+ return path;
}
}
--- /src/main/java/ee/shy/storage/PlainFileAccessor.java
+++ /src/main/java/ee/shy/storage/PlainFileAccessor.java
@@ -1,29 +1,31 @@
package ee.shy.storage;
import org.apache.commons.io.IOUtils;
import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
/**
* File accessor to store data plainly as-is.
* No extension is used on base paths.
*/
public class PlainFileAccessor implements FileAccessor {
@Override
- public void add(File file, InputStream source) throws IOException {
- try (FileOutputStream target = new FileOutputStream(file)) {
+ public void add(Path path, InputStream source) throws IOException {
+ try (OutputStream target = Files.newOutputStream(path)) {
IOUtils.copy(source, target);
}
}
@Override
- public InputStream get(File file) {
+ public InputStream get(Path path) throws IOException {
try {
- return new FileInputStream(file);
+ return Files.newInputStream(path);
}
- catch (FileNotFoundException e) {
+ catch (FileNotFoundException e) { // TODO: 6.04.16 don't catch exception
return null;
}
}
}
--- /src/main/java/ee/shy/storage/StorageTest.java
+++ /src/main/java/ee/shy/storage/StorageTest.java
@@ -1,36 +1,37 @@
package ee.shy.storage;
import org.apache.commons.io.IOUtils;
import java.io.*;
+import java.nio.file.Paths;
import java.util.Arrays;
public class StorageTest {
public static void main(String[] args) throws IOException {
DataStorage storage = new FileStorage(
Arrays.asList(
- new GitFileLocator(new File("teststore")),
- new FlatFileLocator(new File("teststore2"))),
+ new GitFileLocator(Paths.get("teststore")),
+ new FlatFileLocator(Paths.get("teststore2"))),
new AggregateFileAccessor(Arrays.asList(
new GzipFileAccessor(),
new PlainFileAccessor())));
- /*Hash h1 = storage.add(new ByteArrayInputStream("foo".getBytes("UTF-8")));
- Hash h2 = storage.add(new ByteArrayInputStream("bar".getBytes("UTF-8")));
- Hash h3 = storage.add(new FileInputStream("README.md"));
+ Hash h1 = storage.put(new ByteArrayInputStream("foo".getBytes("UTF-8")));
+ Hash h2 = storage.put(new ByteArrayInputStream("bar".getBytes("UTF-8")));
+ Hash h3 = storage.put(new FileInputStream("README.md"));
System.out.println(h1);
System.out.println(h2);
System.out.println(h3);
InputStream i1 = storage.get(new Hash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"));
System.out.println(new String(IOUtils.toByteArray(i1), "UTF-8"));
InputStream i2 = storage.get(h2);
System.out.println(new String(IOUtils.toByteArray(i2), "UTF-8"));
InputStream i3 = storage.get(h3);
- IOUtils.copyStream(i3, new FileOutputStream("README2.md"));*/
+ IOUtils.copy(i3, new FileOutputStream("README2.md"));
InputStream i = storage.get(new Hash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"));
System.out.println(new String(IOUtils.toByteArray(i), "UTF-8"));
}
}
--- /src/main/java/ee/shy/storage/Util.java
+++ /src/main/java/ee/shy/storage/Util.java
@@ -1,8 +1,10 @@
package ee.shy.storage;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
/**
* Utilities class for storage-related functions.
*/
public class Util {
@@ -10,30 +12,22 @@
}
/**
* Adds given extension to file path.
- * @param file file path to extend
+ * @param path file path to extend
* @param extension extension to add
* @return file path with given extension
*/
- public static File addExtension(File file, String extension) {
- return new File(file.getAbsolutePath() + extension);
+ public static Path addExtension(Path path, String extension) {
+ return path.resolveSibling(path.getFileName().toString() + extension);
}
/**
* Ensures file path's validity by creating required missing parent directories.
- * @param file file path which's validity to ensure
- * @return whether file path is now valid
+ * @param path file path which's validity to ensure
*/
- public static boolean ensurePath(File file) {
- if (file.isDirectory())
- return true;
- else {
- File parent = file.getParentFile();
- if (parent.exists())
- return parent.isDirectory();
- else
- return parent.mkdirs();
- }
+ public static void ensurePath(Path path) throws IOException {
+ if (!Files.isDirectory(path))
+ Files.createDirectories(path.getParent());
}
}
diff --git a/src/main/java/ee/shy/cli/command/AddCommand.java b/src/main/java/ee/shy/cli/command/AddCommand.java
index b60dd61..1a47318 100644
--- a/src/main/java/ee/shy/cli/command/AddCommand.java
+++ b/src/main/java/ee/shy/cli/command/AddCommand.java
@@ -4,8 +4,8 @@ import ee.shy.cli.Command;
import ee.shy.cli.HelptextBuilder;
import ee.shy.core.Repository;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Paths;
/**
* A command to add given file to its respective directory in the repository.
@@ -14,7 +14,7 @@ public class AddCommand implements Command {
@Override
public void execute(String[] args) throws IOException {
Repository repository = Repository.newExisting();
- repository.add(new File(args[0]));
+ repository.add(Paths.get(args[0]));
}
@Override
diff --git a/src/main/java/ee/shy/cli/command/RemoveCommand.java b/src/main/java/ee/shy/cli/command/RemoveCommand.java
index d1caff9..2f1039c 100644
--- a/src/main/java/ee/shy/cli/command/RemoveCommand.java
+++ b/src/main/java/ee/shy/cli/command/RemoveCommand.java
@@ -4,8 +4,8 @@ import ee.shy.cli.Command;
import ee.shy.cli.HelptextBuilder;
import ee.shy.core.Repository;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Paths;
/**
* A command to remove given file from its respective directory in the repository.
@@ -14,7 +14,7 @@ public class RemoveCommand implements Command {
@Override
public void execute(String[] args) throws IOException {
Repository repository = Repository.newExisting();
- repository.remove(new File(args[0]));
+ repository.remove(Paths.get(args[0]));
}
@Override
diff --git a/src/main/java/ee/shy/cli/command/TestCommand.java b/src/main/java/ee/shy/cli/command/TestCommand.java
index 7a7ca34..21be95b 100644
--- a/src/main/java/ee/shy/cli/command/TestCommand.java
+++ b/src/main/java/ee/shy/cli/command/TestCommand.java
@@ -4,6 +4,8 @@ import ee.shy.cli.Command;
import ee.shy.cli.HelptextBuilder;
import ee.shy.core.Repository;
+import java.io.IOException;
+
/**
* A simple command for testing.
*/
@@ -15,7 +17,7 @@ public class TestCommand implements Command {
}
@Override
- public void execute(String[] args) {
+ public void execute(String[] args) throws IOException {
System.out.println(name);
Repository repository = Repository.newExisting();
}
diff --git a/src/main/java/ee/shy/core/Repository.java b/src/main/java/ee/shy/core/Repository.java
index 5e9b077..b25d4a2 100644
--- a/src/main/java/ee/shy/core/Repository.java
+++ b/src/main/java/ee/shy/core/Repository.java
@@ -1,64 +1,57 @@
package ee.shy.core;
import ee.shy.io.Json;
+import ee.shy.io.PathUtils;
import ee.shy.map.DirectoryJsonMap;
import ee.shy.map.NamedObjectMap;
import ee.shy.storage.*;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.output.TeeOutputStream;
-import java.io.*;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.Arrays;
-
/**
* Class for creating and interacting with a repository.
*/
public class Repository {
/**
- * Repository's root directory.
- */
- private final File repositoryDirectory;
-
- /**
- * {@link #repositoryDirectory}'s parent directory.
+ * Repository root directory path.
*/
- private final File rootDirectory;
+ private final Path rootPath;
private final DataStorage storage;
private final NamedObjectMap<Branch> branches;
/**
* Constructs a new repository class.
- * @param rootDirectory root directory for repository
+ * @param rootPath root directory for repository
*/
- private Repository(File rootDirectory) {
- this.rootDirectory = rootDirectory;
- this.repositoryDirectory = new File(rootDirectory, ".shy");
+ private Repository(Path rootPath) throws IOException {
+ this.rootPath = rootPath;
this.storage = new FileStorage(
Arrays.asList(
- new FlatFileLocator(new File(repositoryDirectory, "storage"))
+ new FlatFileLocator(getRepositoryPath().resolve("storage"))
),
new PlainFileAccessor());
- branches = new DirectoryJsonMap<>(Branch.class, repositoryDirectory.toPath().resolve("branches"));
+ branches = new DirectoryJsonMap<>(Branch.class, getRepositoryPath().resolve("branches"));
}
/**
* Tries to find an existing repository in the directory shy was executed or its parent directories.
* @return repository object if existing repository was found, null otherwise
*/
- public static Repository newExisting() throws RepositoryNotFoundException {
- File currentDirectory = new File(System.getProperty("user.dir"));
- while (currentDirectory != null) {
- File repositoryDirectory = new File(currentDirectory, ".shy");
- if (repositoryDirectory.exists() && repositoryDirectory.isDirectory()) {
- return new Repository(currentDirectory);
+ public static Repository newExisting() throws RepositoryNotFoundException, IOException {
+ Path currentPath = PathUtils.getCurrentPath();
+ while (currentPath != null) {
+ Path repositoryPath = getRepositoryPath(currentPath);
+ if (Files.isDirectory(repositoryPath)) {
+ return new Repository(currentPath);
}
- currentDirectory = currentDirectory.getParentFile();
+ currentPath = currentPath.getParent();
}
+
throw new RepositoryNotFoundException();
}
@@ -68,67 +61,72 @@ public class Repository {
* @throws IOException if repository hierarchy generation fails
*/
public static Repository newEmpty() throws IOException {
- File currentDirectory = new File(System.getProperty("user.dir"));
- File repositoryDirectory = new File(currentDirectory, ".shy");
- if (repositoryDirectory.exists() || repositoryDirectory.mkdir()) {
- String[] subDirectories = {"commit", "branches", "tags", "storage"};
- for (String subDirectory : subDirectories) {
- File f = new File(repositoryDirectory, subDirectory);
- if (!f.exists())
- f.mkdir();
- }
+ Path repositoryPath = getRepositoryPath(PathUtils.getCurrentPath());
+ Files.createDirectory(repositoryPath);
- String[] repositoryFiles = {"author", "current"};
- for (String repositoryFile : repositoryFiles) {
- File f = new File(repositoryDirectory, repositoryFile);
- if (!f.exists())
- f.createNewFile();
- }
+ String[] subDirectories = {"commit", "branches", "tags", "storage"};
+ for (String subDirectory : subDirectories) {
+ Files.createDirectory(repositoryPath.resolve(subDirectory));
+ }
- // The following will be refactored later in the project development(Phase 2)
- File current = new File(repositoryDirectory, "current");
- try (FileOutputStream currentStream = new FileOutputStream(current)) {
- currentStream.write(Hash.ZERO.toString().getBytes());
- }
+ String[] repositoryFiles = {"author", "current"};
+ for (String repositoryFile : repositoryFiles) {
+ Files.createFile(repositoryPath.resolve(repositoryFile));
+ }
- // TODO: 26.03.16 Create a config file to home directory upon installation to get author's details from.
- Author author = new Author(null, null);
- author.write(new FileOutputStream(new File(repositoryDirectory, "author")));
+ // TODO: 6.04.16 move current commit handling into separate class
+ IOUtils.write(Hash.ZERO.toString(), Files.newOutputStream(repositoryPath.resolve("current")));
- System.out.println("Initialized a shy repository in " + currentDirectory.getAbsolutePath());
+ Repository repository = new Repository(repositoryPath.getParent());
- Repository repository = new Repository(currentDirectory);
- repository.getBranches().put("master", new Branch(Hash.ZERO));
+ // TODO: 26.03.16 Create a config file to home directory upon installation to get author's details from.
+ Author author = new Author(null, null);
+ repository.setAuthor(author);
- return repository;
- }
- else {
- throw new IOException("Repository initialization failed!");
- }
+ repository.getBranches().put("master", new Branch(Hash.ZERO));
+
+ System.out.println("Initialized a shy repository in " + repository.getRootPath());
+ return repository;
+ }
+
+ /**
+ * Returns current directory file's path in ".shy/commit/" directory.
+ * @param path file which's path to transform
+ * @return transformed path in ".shy/commit/"
+ */
+ private Path getCommitPath(Path path) throws IOException {
+ Path commitPath = getRepositoryPath().resolve("commit");
+ /*
+ Beware of the pitfalls of oh-so-wonderful Path:
+ Path#toAbsolutePath does NOT normalize the path to an actual absolute path,
+ but simply prepends the current working directory.
+ */
+ return commitPath.resolve(rootPath.relativize(path.toRealPath()));
}
/**
* Copies given file to its respective directory in ".shy/commit/" directory.
- * @param file file that user wants to add to repository
+ * @param path file that user wants to add to repository
* @throws IOException if file can't be found or copying fails
*/
- public void add(File file) throws IOException {
- File fullFilePath = fullFilePath(file);
- fullFilePath.getParentFile().mkdirs();
- try (InputStream input = new FileInputStream(file)) {
- try (OutputStream output = new FileOutputStream(fullFilePath)) {
- IOUtils.copy(input, output);
- }
- }
+ public void add(Path path) throws IOException {
+ Path commitPath = getCommitPath(path);
+ /*
+ Beware of the pitfalls of oh-so-wonderful Path:
+ Files.createDirectories does unintuitive things for paths ending in "..".
+ For example, "/tmp/foo/bar/.." will cause "/tmp/foo/bar/" to be created yet it's not in the normalized path.
+ */
+ Files.createDirectories(commitPath.getParent());
+ Files.copy(path, commitPath);
}
/**
* Removes given file from its directory in ".shy/commit".
- * @param file file that user wants to remove from repository
+ * @param path file that user wants to remove from repository
* @throws IOException if file could not be deleted
*/
- public void remove(File file) throws IOException {
- Files.deleteIfExists(fullFilePath(file).toPath());
+ public void remove(Path path) throws IOException {
+ Files.deleteIfExists(getCommitPath(path));
}
/**
@@ -137,7 +135,7 @@ public class Repository {
* @throws IOException if there was a problem storing the tree
*/
private Hash createCommitTree() throws IOException {
- Tree tree = new Tree.Builder(storage).fromDirectory(new File(repositoryDirectory, "commit")).create();
+ Tree tree = new Tree.Builder(storage).fromDirectory(getRepositoryPath().resolve("commit")).create();
return storage.put(tree.inputify());
}
@@ -148,8 +146,8 @@ public class Repository {
*/
public void commit(String message) throws IOException {
Hash tree = createCommitTree();
- File currentFile = new File(repositoryDirectory, "current");
- Hash parent = new Hash(IOUtils.toString(new FileInputStream(currentFile), "UTF-8"));
+ Path currentPath = getRepositoryPath().resolve("current");
+ Hash parent = new Hash(IOUtils.toString(Files.newInputStream(currentPath), "UTF-8"));
Commit commit = new Commit.Builder()
.setTree(tree)
@@ -160,32 +158,8 @@ public class Repository {
.create();
Hash hash = storage.put(commit.inputify());
- File branchFile = new File(new File(repositoryDirectory, "branches"), "master"); // TODO: 26.03.16 update correct branch
- IOUtils.write(hash.toString(), new TeeOutputStream(new FileOutputStream(currentFile), new FileOutputStream(branchFile)), "UTF-8");
- }
-
- /**
- * Creates given file's path relative to repository's directory.
- * @param file file that's relative path is wanted to be create
- * @return file's path relative to repository's directory
- */
- private File relativeFilePath(File file) {
- File fileDir = new File(System.getProperty("user.dir"), file.getPath()).getParentFile();
-
- Path path = Paths.get(fileDir.getPath());
- path = this.rootDirectory.toPath().relativize(path);
-
- return new File(path.toFile().getPath(), file.getName());
- }
-
- /**
- * Creates full path from system's root to given file in ".shy/commit/" directory.
- * @param file file that's path is wanted to be create
- * @return file path from system's root to given file'is directory in ".shy/commit/"
- */
- private File fullFilePath(File file) {
- File repositoryDirectory = new File(this.rootDirectory.getPath(), ".shy/commit/");
- return new File(repositoryDirectory, relativeFilePath(file).getPath());
+ branches.put("master", new Branch(hash)); // TODO: 26.03.16 update correct branch
+ IOUtils.write(hash.toString(), Files.newOutputStream(currentPath));
}
/**
@@ -194,8 +168,7 @@ public class Repository {
* @throws IOException if file '.shy/author' does not exist or reading fails
*/
public Author getAuthor() throws IOException {
- FileInputStream fis = new FileInputStream(new File(repositoryDirectory, "author"));
- return Json.read(fis, Author.class);
+ return Json.read(Files.newInputStream(getAuthorPath()), Author.class);
}
/**
@@ -204,10 +177,43 @@ public class Repository {
* @throws IOException if write fails
*/
public void setAuthor(Author author) throws IOException {
- author.write(new FileOutputStream(new File(repositoryDirectory, "author")));
+ author.write(Files.newOutputStream(getAuthorPath()));
}
public NamedObjectMap<Branch> getBranches() {
return branches;
}
+
+ /**
+ * Returns repository's root path.
+ * @return root directory path
+ */
+ public Path getRootPath() {
+ return rootPath;
+ }
+
+ /**
+ * Returns repository's ".shy/" directory path in given root directory.
+ * @param rootPath root directory of repository
+ * @return repository directory path
+ */
+ private static Path getRepositoryPath(Path rootPath) {
+ return rootPath.resolve(".shy");
+ }
+
+ /**
+ * Returns repository's ".shy/" directory path.
+ * @return repository directory path
+ */
+ private Path getRepositoryPath() {
+ return getRepositoryPath(rootPath);
+ }
+
+ /**
+ * Returns repository's "author" file path.
+ * @return author file path
+ */
+ private Path getAuthorPath() {
+ return getRepositoryPath().resolve("author");
+ }
}
\ No newline at end of file
diff --git a/src/main/java/ee/shy/core/Tree.java b/src/main/java/ee/shy/core/Tree.java
index a4ecfe4..274d4c3 100644
--- a/src/main/java/ee/shy/core/Tree.java
+++ b/src/main/java/ee/shy/core/Tree.java
@@ -4,12 +4,11 @@ import ee.shy.io.Jsonable;
import ee.shy.storage.DataStorage;
import ee.shy.storage.Hash;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.TreeMap;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.stream.Collectors;
/**
* Class representing a directory tree.
@@ -68,22 +67,20 @@ public class Tree extends Jsonable {
* @return builder itself
* @throws IOException if there was a problem reading an addable file or tree to storage
*/
- public Builder fromDirectory(File directory) throws IOException {
- File[] files = directory.listFiles();
- if (files == null)
- throw new IOException("Attempted to build Tree from a non-directory");
+ public Builder fromDirectory(Path directory) throws IOException {
+ List<Path> files = new ArrayList<>(Files.list(directory).collect(Collectors.toList())); // TODO: 6.04.16 Stream#toCollection for creating ArrayList
- Arrays.sort(files); // guarantee stable order
+ Collections.sort(files);
- for (File file : files) {
- if (file.isFile()) {
- Hash hash = storage.put(new FileInputStream(file));
- addItem(file.getName(), new TreeItem(TreeItem.Type.FILE, hash));
+ for (Path file : files) {
+ if (Files.isRegularFile(file)) {
+ Hash hash = storage.put(Files.newInputStream(file));
+ addItem(file.getFileName().toString(), new TreeItem(TreeItem.Type.FILE, hash));
}
- else if (file.isDirectory()) {
+ else if (Files.isDirectory(file)) {
Tree tree = new Builder(storage).fromDirectory(file).create();
Hash hash = storage.put(tree.inputify());
- addItem(file.getName(), new TreeItem(TreeItem.Type.TREE, hash));
+ addItem(file.getFileName().toString(), new TreeItem(TreeItem.Type.TREE, hash));
}
}
diff --git a/src/main/java/ee/shy/io/PathUtils.java b/src/main/java/ee/shy/io/PathUtils.java
new file mode 100644
index 0000000..b3b4bc2
--- /dev/null
+++ b/src/main/java/ee/shy/io/PathUtils.java
@@ -0,0 +1,42 @@
+package ee.shy.io;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Utilities class for I/O-related methods.
+ */
+public class PathUtils {
+ private PathUtils() {
+
+ }
+
+ /**
+ * Returns current working directory as path.
+ * @return current working directory
+ */
+ public static Path getCurrentPath() {
+ return Paths.get(System.getProperty("user.dir"));
+ }
+
+ /**
+ * Adds given extension to file path.
+ * @param path file path to extend
+ * @param extension extension to add
+ * @return file path with given extension
+ */
+ public static Path addExtension(Path path, String extension) {
+ return path.resolveSibling(path.getFileName().toString() + extension);
+ }
+
+ /**
+ * Creates given path's parent directories.
+ * If path itself is a directory, it too will be created.
+ * @param path path which's parent directories to create
+ */
+ public static void createParentDirectories(Path path) throws IOException {
+ Files.createDirectories(Files.isDirectory(path) ? path : path.getParent());
+ }
+}
diff --git a/src/main/java/ee/shy/storage/AggregateFileAccessor.java b/src/main/java/ee/shy/storage/AggregateFileAccessor.java
index 8bf8388..df6ae83 100644
--- a/src/main/java/ee/shy/storage/AggregateFileAccessor.java
+++ b/src/main/java/ee/shy/storage/AggregateFileAccessor.java
@@ -1,8 +1,8 @@
package ee.shy.storage;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
import java.util.List;
/**
@@ -25,26 +25,26 @@ public class AggregateFileAccessor implements FileAccessor {
/**
* Adds file content via first file accessor.
- * @param file base path of file to add
+ * @param path base path of file to add
* @param source input stream to get data from
* @throws IOException if there was a problem reading the input stream or writing to the file
*/
@Override
- public void add(File file, InputStream source) throws IOException {
- accessors.get(0).add(file, source); // always use first accessor for add
+ public void add(Path path, InputStream source) throws IOException {
+ accessors.get(0).add(path, source); // always use first accessor for add
}
/**
* Gets file content via first successful file accessor.
- * @param file base path of file to get
+ * @param path base path of file to get
* @return input stream to get data from
* @throws IOException if there was a problem reading from the file
*/
@Override
- public InputStream get(File file) throws IOException {
+ public InputStream get(Path path) throws IOException {
InputStream source;
for (FileAccessor accessor : accessors) {
- if ((source = accessor.get(file)) != null)
+ if ((source = accessor.get(path)) != null)
return source;
}
return null;
diff --git a/src/main/java/ee/shy/storage/FileAccessor.java b/src/main/java/ee/shy/storage/FileAccessor.java
index 6bc11e4..91c9b70 100644
--- a/src/main/java/ee/shy/storage/FileAccessor.java
+++ b/src/main/java/ee/shy/storage/FileAccessor.java
@@ -1,8 +1,8 @@
package ee.shy.storage;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
/**
* An interface for accessing file content by base path from a {@link FileLocator}.
@@ -11,17 +11,17 @@ import java.io.InputStream;
public interface FileAccessor {
/**
* Adds file content to given base path of file
- * @param file base path of file to add
+ * @param path base path of file to add
* @param source input stream to get data from
* @throws IOException if there was a problem reading the input stream or writing to the file
*/
- void add(File file, InputStream source) throws IOException;
+ void add(Path path, InputStream source) throws IOException;
/**
* Gets file content from given base path of file
- * @param file base path of file to get
+ * @param path base path of file to get
* @return input stream to get data from
* @throws IOException if there was a problem reading from some input
*/
- InputStream get(File file) throws IOException;
+ InputStream get(Path path) throws IOException;
}
diff --git a/src/main/java/ee/shy/storage/FileLocator.java b/src/main/java/ee/shy/storage/FileLocator.java
index cf40257..f178c12 100644
--- a/src/main/java/ee/shy/storage/FileLocator.java
+++ b/src/main/java/ee/shy/storage/FileLocator.java
@@ -1,6 +1,8 @@
package ee.shy.storage;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
/**
* An abstract class for locating files by hash.
@@ -10,18 +12,14 @@ public abstract class FileLocator {
/**
* Root directory to use.
*/
- protected final File root;
+ protected final Path root;
/**
* Constructs a new locator with given root.
* @param root root directory to use
*/
- public FileLocator(File root) {
- if (!root.exists())
- root.mkdirs();
- if (!root.isDirectory())
- throw new RuntimeException("root must be a directory"); // TODO: 9.03.16 throw better exception
-
+ public FileLocator(Path root) throws IOException {
+ Files.createDirectories(root);
this.root = root;
}
@@ -31,7 +29,7 @@ public abstract class FileLocator {
* @param hash hash to get path for
* @return path to file for given hash
*/
- public File locate(Hash hash) {
+ public Path locate(Hash hash) throws IOException {
return null;
}
@@ -41,7 +39,7 @@ public abstract class FileLocator {
* @param hash hash to get path for
* @return supposed path to file for given hash
*/
- public File locateAdd(Hash hash) {
+ public Path locateAdd(Hash hash) throws IOException {
return locate(hash);
}
@@ -51,7 +49,7 @@ public abstract class FileLocator {
* @param hash hash to get path for
* @return path to file for given hash
*/
- public File locateGet(Hash hash) {
+ public Path locateGet(Hash hash) throws IOException {
return locate(hash);
}
}
diff --git a/src/main/java/ee/shy/storage/FlatFileLocator.java b/src/main/java/ee/shy/storage/FlatFileLocator.java
index 22faf46..197d249 100644
--- a/src/main/java/ee/shy/storage/FlatFileLocator.java
+++ b/src/main/java/ee/shy/storage/FlatFileLocator.java
@@ -1,6 +1,7 @@
package ee.shy.storage;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
/**
* File locator for having all hashes in the root directory.
@@ -10,12 +11,12 @@ public class FlatFileLocator extends FileLocator {
* Constructs a new flat file locator with given root.
* @param root root directory to use
*/
- public FlatFileLocator(File root) {
+ public FlatFileLocator(Path root) throws IOException {
super(root);
}
@Override
- public File locate(Hash hash) {
- return new File(root, hash.toString());
+ public Path locate(Hash hash) {
+ return root.resolve(hash.toString());
}
}
diff --git a/src/main/java/ee/shy/storage/GitFileLocator.java b/src/main/java/ee/shy/storage/GitFileLocator.java
index 46ff539..36728a6 100644
--- a/src/main/java/ee/shy/storage/GitFileLocator.java
+++ b/src/main/java/ee/shy/storage/GitFileLocator.java
@@ -1,6 +1,7 @@
package ee.shy.storage;
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
/**
* File locator for having hashes in git-like directory structure in the root directory:
@@ -12,7 +13,7 @@ public class GitFileLocator extends NestedFileLocator {
* Constructs a new git file locator with given root.
* @param root root directory to use
*/
- public GitFileLocator(File root) {
+ public GitFileLocator(Path root) throws IOException {
super(root, 2, 1);
}
}
diff --git a/src/main/java/ee/shy/storage/GzipFileAccessor.java b/src/main/java/ee/shy/storage/GzipFileAccessor.java
index ca1fb2b..393bc76 100644
--- a/src/main/java/ee/shy/storage/GzipFileAccessor.java
+++ b/src/main/java/ee/shy/storage/GzipFileAccessor.java
@@ -1,8 +1,11 @@
package ee.shy.storage;
+import ee.shy.io.PathUtils;
import org.apache.commons.io.IOUtils;
import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -17,16 +20,16 @@ public class GzipFileAccessor implements FileAccessor {
private static final String EXTENSION = ".gz"; // TODO: 9.03.16 create superclass for extension handling
@Override
- public void add(File file, InputStream source) throws IOException {
- try (GZIPOutputStream target = new GZIPOutputStream(new FileOutputStream(Util.addExtension(file, EXTENSION)))) {
+ public void add(Path path, InputStream source) throws IOException {
+ try (GZIPOutputStream target = new GZIPOutputStream(Files.newOutputStream(PathUtils.addExtension(path, EXTENSION)))) {
IOUtils.copy(source, target);
}
}
@Override
- public InputStream get(File file) throws IOException {
+ public InputStream get(Path path) throws IOException {
try {
- return new GZIPInputStream(new FileInputStream(Util.addExtension(file, EXTENSION)));
+ return new GZIPInputStream(Files.newInputStream(PathUtils.addExtension(path, EXTENSION)));
}
catch (FileNotFoundException e) {
return null;
diff --git a/src/main/java/ee/shy/storage/NestedFileLocator.java b/src/main/java/ee/shy/storage/NestedFileLocator.java
index e57f194..126a358 100644
--- a/src/main/java/ee/shy/storage/NestedFileLocator.java
+++ b/src/main/java/ee/shy/storage/NestedFileLocator.java
@@ -1,6 +1,9 @@
package ee.shy.storage;
-import java.io.File;
+import ee.shy.io.PathUtils;
+
+import java.io.IOException;
+import java.nio.file.Path;
/**
* File locator for having hashes in nested directory structure in the root directory:
@@ -29,7 +32,7 @@ public class NestedFileLocator extends FileLocator {
* @param root root directory to use
* @param directoryLength length of each subdirectory name
*/
- public NestedFileLocator(File root, int directoryLength) {
+ public NestedFileLocator(Path root, int directoryLength) throws IOException {
this(root, directoryLength, DEPTH_UNLIMITED);
}
@@ -39,28 +42,29 @@ public class NestedFileLocator extends FileLocator {
* @param directoryLength length of each subdirectory name
* @param depthMax maximum nesting depth, unlimited with {@link #DEPTH_UNLIMITED}
*/
- public NestedFileLocator(File root, int directoryLength, int depthMax) {
+ public NestedFileLocator(Path root, int directoryLength, int depthMax) throws IOException {
super(root);
this.directoryLength = directoryLength;
this.depthMax = depthMax;
}
@Override
- public File locate(Hash hash) {
+ public Path locate(Hash hash) {
String hashString = hash.toString();
- File file = root;
+ Path path = root;
int depth;
for (depth = 0; (depthMax == DEPTH_UNLIMITED || depth < depthMax) && (directoryLength * (depth + 1) < hashString.length()); depth++)
- file = new File(file, hashString.substring(directoryLength * depth, directoryLength * (depth + 1)));
+ path = path.resolve(hashString.substring(directoryLength * depth, directoryLength * (depth + 1)));
- file = new File(file, hashString.substring(directoryLength * depth));
- return file;
+ path = path.resolve(hashString.substring(directoryLength * depth));
+ return path;
}
@Override
- public File locateAdd(Hash hash) {
- File file = locate(hash);
- return Util.ensurePath(file) ? file : null;
+ public Path locateAdd(Hash hash) throws IOException {
+ Path path = locate(hash);
+ PathUtils.createParentDirectories(path);
+ return path;
}
}
diff --git a/src/main/java/ee/shy/storage/PlainFileAccessor.java b/src/main/java/ee/shy/storage/PlainFileAccessor.java
index 8bd6b14..8cf010a 100644
--- a/src/main/java/ee/shy/storage/PlainFileAccessor.java
+++ b/src/main/java/ee/shy/storage/PlainFileAccessor.java
@@ -3,6 +3,8 @@ package ee.shy.storage;
import org.apache.commons.io.IOUtils;
import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
/**
* File accessor to store data plainly as-is.
@@ -10,19 +12,19 @@ import java.io.*;
*/
public class PlainFileAccessor implements FileAccessor {
@Override
- public void add(File file, InputStream source) throws IOException {
- try (FileOutputStream target = new FileOutputStream(file)) {
+ public void add(Path path, InputStream source) throws IOException {
+ try (OutputStream target = Files.newOutputStream(path)) {
IOUtils.copy(source, target);
}
}
@Override
- public InputStream get(File file) {
+ public InputStream get(Path path) throws IOException {
try {
- return new FileInputStream(file);
+ return Files.newInputStream(path);
}
- catch (FileNotFoundException e) {
+ catch (FileNotFoundException e) { // TODO: 6.04.16 don't catch exception
return null;
}
}
diff --git a/src/main/java/ee/shy/storage/StorageTest.java b/src/main/java/ee/shy/storage/StorageTest.java
index 6abc1f9..83db965 100644
--- a/src/main/java/ee/shy/storage/StorageTest.java
+++ b/src/main/java/ee/shy/storage/StorageTest.java
@@ -3,21 +3,22 @@ package ee.shy.storage;
import org.apache.commons.io.IOUtils;
import java.io.*;
+import java.nio.file.Paths;
import java.util.Arrays;
public class StorageTest {
public static void main(String[] args) throws IOException {
DataStorage storage = new FileStorage(
Arrays.asList(
- new GitFileLocator(new File("teststore")),
- new FlatFileLocator(new File("teststore2"))),
+ new GitFileLocator(Paths.get("teststore")),
+ new FlatFileLocator(Paths.get("teststore2"))),
new AggregateFileAccessor(Arrays.asList(
new GzipFileAccessor(),
new PlainFileAccessor())));
- /*Hash h1 = storage.add(new ByteArrayInputStream("foo".getBytes("UTF-8")));
- Hash h2 = storage.add(new ByteArrayInputStream("bar".getBytes("UTF-8")));
- Hash h3 = storage.add(new FileInputStream("README.md"));
+ Hash h1 = storage.put(new ByteArrayInputStream("foo".getBytes("UTF-8")));
+ Hash h2 = storage.put(new ByteArrayInputStream("bar".getBytes("UTF-8")));
+ Hash h3 = storage.put(new FileInputStream("README.md"));
System.out.println(h1);
System.out.println(h2);
@@ -28,7 +29,7 @@ public class StorageTest {
InputStream i2 = storage.get(h2);
System.out.println(new String(IOUtils.toByteArray(i2), "UTF-8"));
InputStream i3 = storage.get(h3);
- IOUtils.copyStream(i3, new FileOutputStream("README2.md"));*/
+ IOUtils.copy(i3, new FileOutputStream("README2.md"));
InputStream i = storage.get(new Hash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"));
System.out.println(new String(IOUtils.toByteArray(i), "UTF-8"));
diff --git a/src/main/java/ee/shy/storage/Util.java b/src/main/java/ee/shy/storage/Util.java
deleted file mode 100644
index c3f4dbc..0000000
--- a/src/main/java/ee/shy/storage/Util.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package ee.shy.storage;
-
-import java.io.File;
-
-/**
- * Utilities class for storage-related functions.
- */
-public class Util {
- private Util() {
-
- }
-
- /**
- * Adds given extension to file path.
- * @param file file path to extend
- * @param extension extension to add
- * @return file path with given extension
- */
- public static File addExtension(File file, String extension) {
- return new File(file.getAbsolutePath() + extension);
- }
-
- /**
- * Ensures file path's validity by creating required missing parent directories.
- * @param file file path which's validity to ensure
- * @return whether file path is now valid
- */
- public static boolean ensurePath(File file) {
- if (file.isDirectory())
- return true;
- else {
- File parent = file.getParentFile();
- if (parent.exists())
- return parent.isDirectory();
- else
- return parent.mkdirs();
- }
- }
-}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment