Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions builders/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
plugins {
id 'java-library'
id 'jacoco'
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
withJavadocJar()
withSourcesJar()
}

dependencies {
testImplementation 'junit:junit:4.13.2'
}

publishing {
publications {
maven(MavenPublication) {
groupId = "io.github.dk96-os.files-jvm"
artifactId = "builders"
apply from: "../artifacts.gradle"
version = artifactVersions.visitors
from components.java
}
}
}

tasks.test {
maxParallelForks = 3
}

tasks.jacocoTestReport {
dependsOn tasks.test
reports {
xml.required = false
csv.required = false
html.outputLocation = layout.buildDirectory.dir("jacocoReport")
}
}

tasks.jacocoTestCoverageVerification {
dependsOn tasks.test
violationRules {
failOnViolation = true
rule {
limit {
counter = "INSTRUCTION"
minimum = 0.960
}
limit {
counter = "BRANCH"
minimum = 0.850
}
}
}
}
21 changes: 21 additions & 0 deletions builders/src/main/java/files/jvm/builders/ProceduralBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package files.jvm.builders;

import java.util.Stack;

import files.jvm.builders.input.InputLineReader;

/** The Builder that follows a strict logical procedure.
*/
public final class ProceduralBuilder {

final InputLineReader reader = new InputLineReader();

final Stack<String> pathStack = new Stack<>();

/** Constructor.
*/
public ProceduralBuilder() {
pathStack.add(".");
}

}
10 changes: 10 additions & 0 deletions builders/src/main/java/files/jvm/builders/data/TreeNodeRecord.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package files.jvm.builders.data;

/** The key data points for a Tree Node.
*/
public record TreeNodeRecord(
int depth,
boolean isDirectory,
String name,
String data
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package files.jvm.builders.input;

import java.util.Arrays;

/** Manages the Key Characters found in valid Inputs.
*/
public class InputCharacters {

final int[] SpaceChars = new int[]{' ', ' ', ' ', ' '};

final int[] DirectoryChars = new int[]{'/', '\\'};

/** Determines if this string contains any directory characters.
* @param name The Name of the Node. May contain directory characters.
* @return Whether the name contained any directory characters.
*/
public boolean isDirectory(
final String name
) {
final boolean containsCharacters = name.chars()
.anyMatch(i ->
Arrays.stream(DirectoryChars).anyMatch(it -> it == i)
);
if (!containsCharacters)
return false;
// todo: Check that the character is at the start or end of the name
return true;
}

/** Count the number of space characters at the start of the
* @param line The input line to count spaces.
* @return The number of consecutive space characters at the start of the input.
*/
public long countStartingSpaces(
final String line
) {
return line.chars()
.takeWhile(i -> Arrays.binarySearch(SpaceChars, i) >= 0)
.count();
}

/** Obtain a Space Character value from the internal collection of accepted values.
* @param index The index of the character in the collection.
* @return The Char value, representing a space.
*/
public char getSpaceCharAt(
final int index
) {
char space = (char) SpaceChars[0];
if (0 < index && index < SpaceChars.length) {
space = (char) SpaceChars[index];
}
return space;
}

}
125 changes: 125 additions & 0 deletions builders/src/main/java/files/jvm/builders/input/InputLineReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package files.jvm.builders.input;

import java.util.List;
import java.util.Objects;

import files.jvm.builders.data.TreeNodeRecord;

/** The Default Input Line Reader.
*/
public final class InputLineReader {

final InputCharacters mCharacters = new InputCharacters();

/** Calculates the depth of a line in the tree structure.
* @param line A line from the tree command output.
* @return The depth of the line in the tree structure.
*/
short calculateDepth(
final String line
) {
long spaceCount = mCharacters.countStartingSpaces(line);
final short depth = (short) (spaceCount >>> 1);
if (depth << 1 == spaceCount)
return depth;
throw new IllegalArgumentException("Invalid Spacing in Line");
}

/** Creates a string of space chars equivalent to the given depth.
* Default is the first space in the list of accepted spaces.
* @param depth The amount of depth in the Tree Node Structure.
* @return The depth of the line in the tree structure.
*/
String createDepth(
int depth
) {
return createDepth(depth, 0);
}

/** Creates a string of space chars equivalent to the given depth.
* @param depth The amount of depth in the Tree Node Structure.
* @param spaceChar The specific whitespace character to use.
* @return The depth of the line in the tree structure.
*/
String createDepth(
int depth,
int spaceChar
) {
final char space = mCharacters.getSpaceCharAt(spaceChar);
if (depth < 2) {
if (depth == 1) return String.valueOf(new char[]{space, space});
return "";
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < depth; ++i) {
builder.append(space);
builder.append(space);
}
return builder.toString();
}

/** Divide the Input into multiple Arguments.
* @param input The String to check for Arguments.
* @return A List containing one or more Arguments.
*/
List<String> splitArguments(
final String input
) {
List<String> args = null;
// Search for multiple arguments
for (int ch : mCharacters.SpaceChars) {
int charIndex = input.indexOf((char) ch);
if (charIndex < 0)
continue;
// Split in two at this index
args = List.of(
input.substring(0, charIndex),
input.substring(charIndex + 1).stripLeading()
);
break;
}
return Objects.requireNonNullElse(args, List.of(input));
}

/** Process A Line from the Input Data.
* @param line The Line to process.
* @return A TreeNodeRecord of the Line Data, or null.
*/
public TreeNodeRecord processLine(
final String line
) {
final short depth;
boolean isDirectory;
String name;
String data;
// Search for multiple arguments
final List<String> args = splitArguments(line.trim());
// Count The Arguments
if (args.size() == 0)
return null;
// First arg is the Node Name
name = args.get(0);
isDirectory = mCharacters.isDirectory(name);
// Check if name needs to be fixed
if (isDirectory) {
// Remove all Directory chars
for (int ch : mCharacters.DirectoryChars) {
name = name.replace(
String.valueOf((char) ch), ""
);
}
}
// Calculate depth after arg valid, because it throws on odd space counts
depth = calculateDepth(line);
// Check Arguments for Data
data = args.size() == 1 ? "" : args.get(1);
// Create Data Object
return new TreeNodeRecord(
depth,
isDirectory,
name,
data
);
}

}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ pluginManagement {
}
rootProject.name = "files-jvm"
include(
":builders",
":visitors",
)