package com.loopperfect.buckaroo.io;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.loopperfect.buckaroo.Either;
import com.loopperfect.buckaroo.Unit;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@FunctionalInterface
public interface FSContext {
FileSystem getFS();
default String homeDirectory() {
return getFS().getPath(System.getProperty("user.home")).toString();
}
default String workingDirectory() {
return getFS().getPath(System.getProperty("user.dir")).toString();
}
default Path getPath(String... path) {
String[] paths = Arrays
.stream(path)
.toArray(String[]::new);
return getFS().getPath("", paths);
}
default boolean isFile(final String path) {
Preconditions.checkNotNull(path);
return Files.isRegularFile(getFS().getPath(path));
}
default boolean isDirectory(final String path) {
Preconditions.checkNotNull(path);
return Files.isDirectory(getFS().getPath(path));
}
default boolean exists(final String path) {
Preconditions.checkNotNull(path);
return Files.exists(getFS().getPath(path).toAbsolutePath());
}
default Optional<IOException> createDirectory(final String p) {
Preconditions.checkNotNull(p);
final Path path = getFS().getPath(p);
try {
Files.createDirectories(path);
} catch (IOException e) {
return Optional.of(e);
}
if (!Files.isDirectory(path) || !Files.exists(path)) {
return Optional.of(new IOException("Could not of a directory at " + path));
}
return Optional.empty();
}
default Either<IOException, String> readFile(final String p) {
Preconditions.checkNotNull(p);
final Path path = getFS().getPath(p);
try {
final String content = Files.readAllLines(getFS().getPath(path.toString()), Charset.defaultCharset())
.stream()
.collect(Collectors.joining("\n"));
return Either.right(content);
} catch (final IOException e) {
return Either.left(e);
}
}
default Optional<IOException> writeFile(final String p, final String content, final boolean overwrite) {
Preconditions.checkNotNull(p);
Preconditions.checkNotNull(content);
final Path path = getFS().getPath(p);
try {
if (Files.exists(path)) {
if (!overwrite) {
throw new IOException("There is already a file at " + path);
}
Files.delete(path);
} else {
if (path.getParent() != null && !Files.exists(path.getParent())) {
Files.createDirectories(path.getParent());
}
}
Files.write(path, ImmutableList.of(content), Charset.defaultCharset(), StandardOpenOption.CREATE);
return Optional.empty();
} catch (final IOException e) {
return Optional.of(e);
}
}
default Optional<IOException> touch(final String p) {
Preconditions.checkNotNull(p);
final Path path = getFS().getPath(p);
try {
if (!Files.exists(path)) {
if (path.getParent() != null && !Files.exists(path.getParent())) {
Files.createDirectories(path.getParent());
}
Files.createFile(path);
}
return Optional.empty();
} catch (final IOException e) {
return Optional.of(e);
}
}
default Optional<IOException> deleteFile(final String path) {
final Path p = getFS().getPath(path);
try {
Files.deleteIfExists(p);
return Optional.empty();
} catch (final IOException e) {
return Optional.of(e);
}
}
default Optional<IOException> writeFile(final String path, final String content) {
return writeFile(path, content, false);
}
default Either<IOException, ImmutableList<String>> listFiles(final String p) {
Preconditions.checkNotNull(p);
final Path path = getFS().getPath(p);
try (final Stream<Path> paths = java.nio.file.Files.list(path)) {
return Either.right(paths
.map(Path::toString)
.collect(ImmutableList.toImmutableList()));
} catch (final IOException e) {
return Either.left(e);
}
}
static FSContext actual() {
return of(FileSystems.getDefault());
}
static FSContext fake() {
return of(Jimfs.newFileSystem(Configuration.unix()));
}
static FSContext of(final FileSystem fs) {
Preconditions.checkNotNull(fs);
return () -> fs;
}
}