Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
be9ee23
Initial commit
inv-jishnu Apr 10, 2025
89b9f05
Spotless applied again
inv-jishnu Apr 11, 2025
49c83b6
Removed unused code
inv-jishnu Apr 11, 2025
b2871fb
Merge branch 'master' into feat/data-loader/import-log-2
ypeckstadt Apr 15, 2025
c5c9c0a
Removed unused classes and references
inv-jishnu Apr 15, 2025
4964e8d
Merge branch 'master' into feat/data-loader/import-log-2
inv-jishnu Apr 15, 2025
ff81f5f
Merge branch 'master' into feat/data-loader/import-log-2
inv-jishnu Apr 15, 2025
3934c2a
Improve Javadocs
ypeckstadt Apr 16, 2025
9958f95
Changes
inv-jishnu Apr 21, 2025
1afbc21
Renamed parameters
inv-jishnu Apr 21, 2025
8c5114d
logging changes
inv-jishnu Apr 21, 2025
ffab395
removed repeated code
inv-jishnu Apr 22, 2025
79df1ed
Merge branch 'master' into feat/data-loader/import-log-2
inv-jishnu Apr 22, 2025
cf31672
Merge branch 'master' into feat/data-loader/import-log-2
brfrn169 Apr 23, 2025
6dd213e
Added excetpion throw
inv-jishnu Apr 23, 2025
6542177
Synchronisation changes
inv-jishnu Apr 25, 2025
603e46e
Added volatile back to fix spotbugs issue
inv-jishnu Apr 25, 2025
eaf9d88
Removed unused variable
inv-jishnu Apr 25, 2025
0a2518a
Changes
inv-jishnu Apr 29, 2025
378effb
Initial commit
inv-jishnu Apr 29, 2025
8a71c75
Revert "Initial commit"
inv-jishnu Apr 29, 2025
df32a6f
Removed unused file
inv-jishnu May 7, 2025
e76e27a
Merged latest changes from master after resolving conflicts
inv-jishnu May 8, 2025
bed04c6
Added back new line
inv-jishnu May 8, 2025
8dc0d8a
Merge branch 'master' into feat/data-loader/cli-utils-2
inv-jishnu May 9, 2025
872412f
Merge branch 'master' into feat/data-loader/cli-utils-2
inv-jishnu May 13, 2025
f78de2d
Changes
inv-jishnu May 13, 2025
0d55aa8
Merge branch 'master' into feat/data-loader/cli-utils-2
inv-jishnu May 13, 2025
8ad50d9
Merge branch 'master' into feat/data-loader/cli-utils-2
ypeckstadt May 14, 2025
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
28 changes: 28 additions & 0 deletions core/src/main/java/com/scalar/db/common/error/CoreError.java
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,34 @@ public enum CoreError implements ScalarDbError {
"The replication feature is not enabled. To use this feature, you must enable it",
"",
""),
DATA_LOADER_IMPORT_TARGET_MISSING(
Category.USER_ERROR,
"0189",
"Missing option: either '--namespace' and'--table' or '--control-file' options must be specified.",
"",
""),
DATA_LOADER_MISSING_IMPORT_FILE(
Category.USER_ERROR,
"0190",
"The file '%s' specified by the argument '%s' does not exist.",
"",
""),
DATA_LOADER_LOG_DIRECTORY_WRITE_ACCESS_DENIED(
Category.USER_ERROR, "0191", "Cannot write to the log directory: %s", "", ""),
DATA_LOADER_LOG_DIRECTORY_CREATION_FAILED(
Category.USER_ERROR, "0192", "Failed to create the log directory: %s", "", ""),
DATA_LOADER_INVALID_CONTROL_FILE(
Category.USER_ERROR, "0193", "Failed to parse the control file: %s", "", ""),
DATA_LOADER_DIRECTORY_WRITE_ACCESS(
Category.USER_ERROR,
"0194",
"No permission to create or write files in the directory: %s",
"",
""),
DATA_LOADER_DIRECTORY_CREATION_FAILED(
Category.USER_ERROR, "0195", "Failed to create the directory: %s", "", ""),
DATA_LOADER_PATH_IS_NOT_A_DIRECTORY(
Category.USER_ERROR, "0196", "Path exists but is not a directory: %s", "", ""),

//
// Errors for the concurrency error category
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ private void validateOutputDirectory(@Nullable String path)
private void validateDirectory(String directoryPath) throws DirectoryValidationException {
// If the directory path is null or empty, use the current working directory
if (directoryPath == null || directoryPath.isEmpty()) {
DirectoryUtils.validateTargetDirectory(DirectoryUtils.getCurrentWorkingDirectory());
DirectoryUtils.validateOrCreateTargetDirectory(DirectoryUtils.getCurrentWorkingDirectory());
} else {
DirectoryUtils.validateTargetDirectory(directoryPath);
DirectoryUtils.validateOrCreateTargetDirectory(directoryPath);
}
}

Expand Down
23 changes: 21 additions & 2 deletions data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/DirectoryUtils.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,30 @@ private DirectoryUtils() {
// restrict instantiation
}

/**
* Validates the current working directory. Ensures that it is writable.
*
* @throws DirectoryValidationException if the current working directory is not writable
*/
public static void validateWorkingDirectory() throws DirectoryValidationException {
Path workingDirectoryPath = Paths.get(System.getProperty("user.dir"));

// Check if the current working directory is writable
if (!Files.isWritable(workingDirectoryPath)) {
throw new DirectoryValidationException(
CoreError.DATA_LOADER_DIRECTORY_WRITE_ACCESS.buildMessage(
workingDirectoryPath.toAbsolutePath()));
}
}

/**
* Validates the provided directory path. Ensures that the directory exists and is writable. If
* the directory doesn't exist, a creation attempt is made.
*
* @param directoryPath the directory path to validate
* @throws DirectoryValidationException if the directory is not writable or cannot be created
*/
public static void validateTargetDirectory(String directoryPath)
public static void validateOrCreateTargetDirectory(String directoryPath)
throws DirectoryValidationException {
if (StringUtils.isBlank(directoryPath)) {
throw new IllegalArgumentException(
Expand All @@ -32,7 +48,10 @@ public static void validateTargetDirectory(String directoryPath)
Path path = Paths.get(directoryPath);

if (Files.exists(path)) {
// Check if the provided directory is writable
if (!Files.isDirectory(path)) {
throw new DirectoryValidationException(
CoreError.DATA_LOADER_PATH_IS_NOT_A_DIRECTORY.buildMessage(path));
}
if (!Files.isWritable(path)) {
throw new DirectoryValidationException(
CoreError.DATA_LOADER_DIRECTORY_WRITE_ACCESS_NOT_ALLOWED.buildMessage(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.scalar.db.dataloader.cli.util;

import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.lang3.StringUtils;

public class FileUtils {

/**
* Validates the provided file path.
*
* @param filePath the file path to validate
* @throws InvalidFilePathException if the file path is invalid
*/
public static void validateFilePath(String filePath) throws InvalidFilePathException {
if (StringUtils.isBlank(filePath)) {
throw new IllegalArgumentException("File path must not be blank.");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this message to CoreError.

}
Path pathToCheck = Paths.get(filePath);

if (!pathToCheck.isAbsolute()) {
// If the path is not absolute, it's either a file name or a relative path
Path currentDirectory = Paths.get("").toAbsolutePath();
Path fileInCurrentDirectory = currentDirectory.resolve(pathToCheck);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not sufficient to use only pathToCheck without currentDirectory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, only need to check pathToCheck exists. The specific condition is not required. I had added this in an early phase where I tried testing with a file name passed as an argument and that scenario is no longer required.
I have removed this part.
Thank you.


if (!fileInCurrentDirectory.toFile().exists()) {
throw new InvalidFilePathException("File not found: " + pathToCheck);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

}
return;
}

// It's an absolute path
if (!pathToCheck.toFile().exists()) {
throw new InvalidFilePathException("File not found: " + pathToCheck);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.scalar.db.dataloader.cli.util;

public class InvalidFilePathException extends Exception {

public InvalidFilePathException(String message) {
super(message);
}

public InvalidFilePathException(String message, Throwable cause) {
super(message, cause);
}
}
16 changes: 8 additions & 8 deletions data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/DirectoryUtilsTest.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,26 @@ public void cleanup() throws IOException {
@Test
void validateTargetDirectory_ValidDirectory_NoExceptionThrown()
throws DirectoryValidationException {
DirectoryUtils.validateTargetDirectory(tempDir.toString());
DirectoryUtils.validateOrCreateTargetDirectory(tempDir.toString());
}

@Test
void validateTargetDirectory_DirectoryDoesNotExist_CreatesDirectory()
void validateOrCreateTargetDirectory_DirectoryDoesNotExist_CreatesDirectory()
throws DirectoryValidationException {
Path newDirectory = Paths.get(tempDir.toString(), "newDir");
DirectoryUtils.validateTargetDirectory(newDirectory.toString());
DirectoryUtils.validateOrCreateTargetDirectory(newDirectory.toString());
assertTrue(Files.exists(newDirectory));
}

@Test
void validateTargetDirectory_DirectoryNotWritable_ThrowsException() throws IOException {
void validateOrCreateTargetDirectory_DirectoryNotWritable_ThrowsException() throws IOException {
Path readOnlyDirectory = Files.createDirectory(Paths.get(tempDir.toString(), "readOnlyDir"));
readOnlyDirectory.toFile().setWritable(false);

assertThrows(
DirectoryValidationException.class,
() -> {
DirectoryUtils.validateTargetDirectory(readOnlyDirectory.toString());
DirectoryUtils.validateOrCreateTargetDirectory(readOnlyDirectory.toString());
});
}

Expand All @@ -58,16 +58,16 @@ void validateTargetDirectory_NullDirectory_ThrowsException() {
assertThrows(
IllegalArgumentException.class,
() -> {
DirectoryUtils.validateTargetDirectory(null);
DirectoryUtils.validateOrCreateTargetDirectory(null);
});
}

@Test
void validateTargetDirectory_EmptyDirectory_ThrowsException() {
void validateOrCreateTargetDirectory_EmptyDirectory_ThrowsException() {
assertThrows(
IllegalArgumentException.class,
() -> {
DirectoryUtils.validateTargetDirectory("");
DirectoryUtils.validateOrCreateTargetDirectory("");
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.scalar.db.dataloader.cli.util;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.nio.file.Paths;
import org.junit.jupiter.api.Test;

public class FileUtilsTest {

private static final String currentPath = Paths.get("").toAbsolutePath().toString();

@Test
void validateFilePath_withValidFilePath_shouldNotThrowException()
throws InvalidFilePathException {
// Test and confirm no exception is thrown when a valid path is provided
FileUtils.validateFilePath(currentPath);
}

@Test
void validateFilePath_withInvalidFilePath_shouldThrowException() {
assertThatThrownBy(() -> FileUtils.validateFilePath(currentPath + "/demo"))
.isInstanceOf(InvalidFilePathException.class)
.hasMessage("File not found: " + currentPath + "/demo");
}

@Test
void validateFilePath_withBlankFilePath_shouldThrowException() {
assertThatThrownBy(() -> FileUtils.validateFilePath(""))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("File path must not be blank.");
}
}