Big refactoring

This commit is contained in:
Robert Vokac 2023-08-05 17:15:34 +02:00
parent edba08f896
commit 46eaeb824e
No known key found for this signature in database
GPG Key ID: 693D30BEE3329055
32 changed files with 881 additions and 687 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@
#*.class
/target/
/nbproject/

28
pom.xml
View File

@ -25,7 +25,7 @@
<parent>
<groupId>org.nanoboot.essential</groupId>
<artifactId>nanoboot-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>0.1.1-SNAPSHOT</version>
</parent>
<groupId>org.nanoboot.tools</groupId>
@ -42,7 +42,7 @@
<power.version>2.0.1-SNAPSHOT</power.version>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<db-migration-core.version>0.1.0</db-migration-core.version>
<db-migration-core.version>0.1.1-SNAPSHOT</db-migration-core.version>
</properties>
<build>
@ -158,11 +158,24 @@
<!-- Other dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit4.version}</version>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.nanoboot.tools.dbmigration</groupId>
<artifactId>db-migration-core</artifactId>
@ -202,6 +215,11 @@
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>dev.mccue</groupId>
<artifactId>guava-io</artifactId>
<version>0.0.3</version>
</dependency>
</dependencies>

View File

@ -25,4 +25,5 @@ module bitinspector {
requires java.sql;
requires powerframework.time;
requires powerframework.collections;
requires dev.mccue.guava.io;
}

View File

@ -27,30 +27,41 @@ import org.nanoboot.bitinspector.core.Utils;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class BirIgnoreRegex implements Predicate<String> {
private final List<String> patterns = new ArrayList<>();
public BirIgnoreRegex(File birIgnoreFile) {
patterns.add(convertUnixRegexToJavaRegex("*.birreport.csv"));
addBirIgnoreFile(birIgnoreFile);
}
public final void addBirIgnoreFile(File birIgnoreFile) {
addBirIgnoreFile(birIgnoreFile, null);
}
public final void addBirIgnoreFile(File birIgnoreFile, File workingDir) {
String[] lines = birIgnoreFile.exists() ? Utils.readTextFromFile(birIgnoreFile).split("\\R") : new String[]{};
if (lines.length == 0) {
//nothing to do
return;
}
String addPrefix = workingDir == null ? "" : birIgnoreFile.getParentFile().getAbsolutePath().replace(workingDir.getAbsolutePath() + "/", "");
for (String l : lines) {
if (l.isBlank() || l.trim().startsWith("#")) {
//nothing to do
continue;
}
patterns.add(convertUnixRegexToJavaRegex(l));
if(addPrefix == null) {
patterns.add(convertUnixRegexToJavaRegex(l));
} else {
patterns.add(convertUnixRegexToJavaRegex(addPrefix + l));
patterns.forEach(e->System.out.println("$$$" + e));
}
}
patterns.add(convertUnixRegexToJavaRegex("*.birreport.csv"));
}
@Override
public boolean test(String text) {
if (patterns.isEmpty()) {
@ -63,7 +74,7 @@ public class BirIgnoreRegex implements Predicate<String> {
if (b) {
ignore = true;
} else {
}
}
// if (ignore) {
@ -73,7 +84,7 @@ public class BirIgnoreRegex implements Predicate<String> {
// }
return ignore;
}
public static String convertUnixRegexToJavaRegex(String wildcard) {
StringBuffer s = new StringBuffer(wildcard.length());
s.append('^');
@ -109,5 +120,5 @@ public class BirIgnoreRegex implements Predicate<String> {
s.append('$');
return (s.toString());
}
}

View File

@ -22,225 +22,195 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nanoboot.bitinspector.core.BirContext;
import org.nanoboot.bitinspector.core.Command;
import org.nanoboot.bitinspector.core.BitInspectorArgs;
import org.nanoboot.bitinspector.core.BirArgs;
import org.nanoboot.bitinspector.core.BitInspectorException;
import org.nanoboot.bitinspector.core.BirFiles;
import org.nanoboot.bitinspector.core.ListSet;
import org.nanoboot.bitinspector.core.Utils;
import org.nanoboot.bitinspector.entity.FsFile;
import org.nanoboot.bitinspector.entity.SystemItem;
import org.nanoboot.bitinspector.persistence.api.FileRepository;
import org.nanoboot.bitinspector.persistence.api.SystemItemRepository;
import org.nanoboot.bitinspector.persistence.impl.sqlite.FileRepositoryImplSqlite;
import org.nanoboot.bitinspector.persistence.impl.sqlite.SqliteDatabaseMigration;
import org.nanoboot.bitinspector.persistence.impl.sqlite.SystemItemRepositoryImplSqlite;
import org.nanoboot.dbmigration.core.main.MigrationResult;
import org.nanoboot.powerframework.time.duration.Duration;
import org.nanoboot.powerframework.time.moment.LocalDateTime;
import org.nanoboot.powerframework.time.utils.RemainingTimeCalculator;
import org.nanoboot.powerframework.time.utils.TimeUnit;
/**
*
* @author pc00289
* @author r
*/
public class CheckCommand implements Command {
private final File currentDirRoot = new File(".");
private final File birSQLite3File = new File("./.bir.sqlite3");
private final File birSQLite3FileSha512 = new File("./.bir.sqlite3.sha512");
private final File birIgnore = new File("./.birignore");
BirIgnoreRegex birIgnoreRegex = new BirIgnoreRegex(birIgnore);
private static final Logger LOG = LogManager.getLogger(CheckCommand.class);
public static final String NAME = "check";
public CheckCommand() {
}
@Override
public String getName() {
return "check";
return NAME;
}
static int i = 0;
enum CheckCommandPart {
CHECK_OLD_DB_CHECKSUM(1),
MIGRATE_DB_SCHEMA_IF_NEEDED(2),
UPDATE_VERSION(3),
FOUND_FILES_IN_FILESYSTEM(4),
FOUND_FILES_IN_DB(5),
ADD_NEW_FILES_TO_DB(6),
REMOVE_DELETED_FILES_FROM_DB(7),
COMPARE_CONTENT_AND_LAST_MODTIME(8),
CREATE_REPORT_CSV_IF_NEEDED(9),
CHECK_NEW_DB_CHECKSUM(10);
private int number;
CheckCommandPart(int number) {
this.number = number;
}
public String toText() {
return "Part " + number + ": ";
}
}
static int iStatic = 0;
@Override
public void run(BitInspectorArgs bitInspectorArgs) {
SqliteDatabaseMigration sqliteDatabaseMigration = new SqliteDatabaseMigration();
sqliteDatabaseMigration.migrate();
SystemItemRepository systemItemRepository = new SystemItemRepositoryImplSqlite();
FileRepository fileRepository = new FileRepositoryImplSqlite();
////
String version = systemItemRepository.read("bir.version").getValue();
System.out.println("bir.version=" + version);
if (version == null) {
systemItemRepository.create(new SystemItem("bir.version", "0.0.0-SNAPSHOT"));
public String run(BirArgs birArgs) {
BirFiles birFiles = new BirFiles(birArgs);
BirContext birContext = new BirContext(birFiles.getWorkingDirAbsolutePath());
//
//part 1:
part1CheckDbHasExpectedHashSum(birFiles);
//part 2:
boolean part2Result = part2MigrateDbSchemaIfNeeded(birFiles);
if(!part2Result) {
return "part 2 failed";
}
System.out.println("Updating version in DB.");
version = systemItemRepository.read("bir.version").getValue();
System.out.println("bir.version=" + version);
////
//part 3:
part3UpdateVersionInDbIfNeeded(birContext);
//// Check ,SQLite DB file has the expected SHA-512 hash sum
if (birSQLite3File.exists() && birSQLite3FileSha512.exists()) {
String expectedHash = Utils.readTextFromFile(birSQLite3FileSha512);
String returnedHash = Utils.calculateSHA512Hash(birSQLite3File);
if (!returnedHash.equals(expectedHash)) {
throw new BitInspectorException("Unexpected hash " + returnedHash + ". Expected SHA-512 hash sum was: " + expectedHash + " for file " + birSQLite3File.getAbsolutePath());
}
}
//// Found files in directory
ListSet<File> filesInFileSystem = part4FoundFilesInFileSystem(birFiles, birArgs);
ListSet<FsFile> filesInDb = part5FoundFilesInDb(birContext.getFileRepository(), birArgs);
List<File> filesInDir = foundFilesInCurrentDir(currentDirRoot, new ArrayList<>());
Set<String> filesInDirSet = filesInDir.stream().map(f -> loadPathButOnlyTheNeededPart(currentDirRoot, f)).collect(Collectors.toSet());
System.out.println("Found files:");
filesInDir.stream().forEach((f -> System.out.println("#" + (++i) + " " + f.getAbsolutePath().substring(currentDirRoot.getAbsolutePath().length() + 1))));
LocalDateTime now = part6AddNewFilesToDb(filesInFileSystem, birFiles, filesInDb, birContext);
//// Found files in DB
List<FsFile> filesInDb = fileRepository.list();
Set<String> filesInDbSet = filesInDb.stream().map(f -> f.getAbsolutePath()).collect(Collectors.toSet());
System.out.println("Files in DB:");
i = 0;
filesInDb.stream().forEach((f -> System.out.println("#" + (++i) + " " + f.toString())));
List<FsFile> filesToBeRemovedFromDb = part7RemoveDeletedFilesFromDb(filesInDb, filesInFileSystem, birContext);
//// Add new files
Date lastChecked = new Date();
org.nanoboot.powerframework.time.moment.LocalDateTime now = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastChecked);
List<FsFile> filesWithBitRot = part8CompareContentAndLastModificationDate(filesInDb, filesToBeRemovedFromDb, birContext, now);
int processedCount0 = 0;
part9CreateReportCsvIfNeeded(birArgs, birFiles, filesWithBitRot);
part10CalculateCurrentHashSumOfDbFile(birFiles);
List<FsFile> filesMissingInDb = new ArrayList<>();
for (File fileInDir : filesInDir) {
processedCount0 = processedCount0 + 1;
if (processedCount0 % 100 == 0) {
double progress = ((double) processedCount0) / filesInDir.size() * 100;
System.out.println("Add - Progress: " + processedCount0 + "/" + filesInDir.size() + " " + String.format("%,.2f", progress) + "%");
}
String absolutePathOfFileInDir = loadPathButOnlyTheNeededPart(currentDirRoot, fileInDir);
if (!filesInDbSet.contains(absolutePathOfFileInDir)) {
Date lastModified = new Date(fileInDir.lastModified());
org.nanoboot.powerframework.time.moment.LocalDateTime ldt = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastModified);
FsFile fsFile = new FsFile(
UUID.randomUUID().toString(),
fileInDir.getName(),
absolutePathOfFileInDir,
ldt.toString(),
now.toString(),
Utils.calculateSHA512Hash(fileInDir),
"SHA-512"
);
filesMissingInDb.add(fsFile);
}
}
fileRepository.create(filesMissingInDb);
//// Remove deleted files
List<FsFile> filesToBeRemovedFromDb = new ArrayList<>();
int processedCount1 = 0;
for (FsFile fileInDb : filesInDb) {
processedCount1 = processedCount1 + 1;
if (processedCount1 % 100 == 0) {
double progress = ((double) processedCount1) / filesInDb.size() * 100;
System.out.println("Remove - Progress: " + processedCount1 + "/" + filesInDb.size() + " " + String.format("%,.2f", progress) + "%");
}
String absolutePathOfFileInDb = fileInDb.getAbsolutePath();
if (!filesInDirSet.contains(absolutePathOfFileInDb)) {
filesToBeRemovedFromDb.add(fileInDb);
}
}
for (FsFile f : filesToBeRemovedFromDb) {
fileRepository.remove(f);
}
double countOfFilesToCalculateHashSum = filesInDb.size() - filesToBeRemovedFromDb.size();
int processedCount = 0;
//// Update modified files with same last modification date
List<FsFile> filesWithBitRot = new ArrayList<>();
List<FsFile> filesToUpdateLastCheckDate = new ArrayList<>();
for (FsFile fileInDb : filesInDb) {
String absolutePathOfFileInDb = fileInDb.getAbsolutePath();
if (filesToBeRemovedFromDb.contains(fileInDb)) {
//nothing to do
continue;
}
processedCount = processedCount + 1;
if (processedCount % 100 == 0) {
double progress = ((double) processedCount) / countOfFilesToCalculateHashSum * 100;
System.out.println("Update - Progress: " + processedCount + "/" + countOfFilesToCalculateHashSum + " " + String.format("%,.2f", progress) + "%");
}
File file = new File("./" + absolutePathOfFileInDb);
Date lastModified = new Date(file.lastModified());
org.nanoboot.powerframework.time.moment.LocalDateTime ldt = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastModified);
String calculatedHash = Utils.calculateSHA512Hash(file);
if (ldt.toString().equals(fileInDb.getLastModificationDate()) && !calculatedHash.equals(fileInDb.getHashSumValue())) {
filesWithBitRot.add(fileInDb);
fileInDb.setLastCheckDate(now.toString());
fileRepository.updateFile(fileInDb);
continue;
}
if (!ldt.toString().equals(fileInDb.getLastModificationDate())) {
fileInDb.setLastCheckDate(now.toString());
fileInDb.setLastModificationDate(ldt.toString());
fileInDb.setHashSumValue(calculatedHash);
fileInDb.setHashSumAlgorithm("SHA-512");
fileRepository.updateFile(fileInDb);
continue;
}
if (ldt.toString().equals(fileInDb.getLastModificationDate())) {
filesToUpdateLastCheckDate.add(fileInDb);
continue;
}
}
fileRepository.updateLastCheckDate(now.toString(), filesToUpdateLastCheckDate);
//// Report files, which may have a bitrot and will have to be restored from a backup
System.out.println("\n\n");
LOG.info("==========");
LOG.info("Summary");
if (filesWithBitRot.isEmpty()) {
System.out.println("No files with bit rot were found.");
}
filesWithBitRot.stream().forEach(f
-> System.out.println("Bit rot detected: \"" + f.getAbsolutePath() + "\"" + " expected_sha512=" + f.getHashSumValue() + " returned_sha512=" + Utils.calculateSHA512Hash(new File("./" + f.getAbsolutePath())))
);
if (bitInspectorArgs.hasArgument("reportid")) {
String reportId = bitInspectorArgs.getArgument("reportid");
File reportIdFile = new File("./" + reportId + ".birreport.csv");
if (reportIdFile.exists()) {
Long nowLong = org.nanoboot.powerframework.time.moment.UniversalDateTime.now().toLong();
File backup = new File(reportIdFile.getParentFile().getAbsolutePath() + "/" + nowLong + "." + reportIdFile.getName());
System.out.println("backup=" + backup);
reportIdFile.renameTo(backup);
}
StringBuilder sb = new StringBuilder();
if (!filesWithBitRot.isEmpty()) {
sb.append("file;expected;calculated\n");
}
LOG.info("Summary: OK : No files with bit rot were found.");
} else {
LOG.error("Summary: KO : Some files {} with bit rot were found.", filesWithBitRot.size());
filesWithBitRot.stream().forEach(f
-> sb.append(f.getAbsolutePath())
.append(";")
.append(f.getHashSumValue())
.append(";")
.append(Utils.calculateSHA512Hash(new File("./" + f.getAbsolutePath())))
.append("\n")
-> LOG.error("Bit rot detected: \"" + f.getAbsolutePath() + "\"" + " expected_sha512=" + f.getHashSumValue() + " returned_sha512=" + Utils.calculateSHA512Hash(new File("./" + f.getAbsolutePath())))
);
Utils.writeTextToFile(sb.toString(), reportIdFile);
}
//// Calculate current checksum of DB file.
Utils.writeTextToFile(Utils.calculateSHA512Hash(birSQLite3File), birSQLite3FileSha512);
System.out.println("foundFiles=" + foundFiles);
System.out.println("foundDirs=" + foundDirs);
return filesWithBitRot.isEmpty() ? "" : filesWithBitRot.stream().map(FsFile::getAbsolutePath).collect(Collectors.joining("\n"));
}
/**
* Checks, if SQLite DB file has the expected SHA-512 hash sum
*
* @param birSQLite3File
* @param birSQLite3FileSha512
* @throws BitInspectorException - if this check fails.
*/
private void part1CheckDbHasExpectedHashSum(BirFiles birInspectorFiles) throws BitInspectorException {
LOG.info("** Part {}: Checking DB, if has expected check sum.", CheckCommandPart.CHECK_OLD_DB_CHECKSUM.number);
final boolean dbExists = birInspectorFiles.getBirSQLite3File().exists();
final boolean checkSumExists = birInspectorFiles.getBirSQLite3FileSha512().exists();
if (dbExists && checkSumExists) {
String expectedHash = Utils.readTextFromFile(birInspectorFiles.getBirSQLite3FileSha512());
String returnedHash = Utils.calculateSHA512Hash(birInspectorFiles.getBirSQLite3File());
if (!returnedHash.equals(expectedHash)) {
String msg
= "Part {}: KO. "
+ "Unexpected hash "
+ returnedHash
+ ". Expected SHA-512 hash sum was: "
+ expectedHash
+ " for file "
+ birInspectorFiles.getBirSQLite3File().getAbsolutePath();
LOG.error(msg, CheckCommandPart.CHECK_OLD_DB_CHECKSUM.number);
LOG.info("Exiting because of the previous error.");
throw new BitInspectorException(msg);
}
} else {
LOG.info("Part {}: OK. Nothing to do: {}",
CheckCommandPart.CHECK_OLD_DB_CHECKSUM.number,
!dbExists ? "DB does not yet exist." : "Check sum file does not exist.");
}
}
private boolean part2MigrateDbSchemaIfNeeded(BirFiles birFiles) {
LOG.info("** Part {}: Migrating schema, if needed.", CheckCommandPart.MIGRATE_DB_SCHEMA_IF_NEEDED.number);
try {
MigrationResult migrationResult = SqliteDatabaseMigration.getInstance().migrate(birFiles.getWorkingDirAbsolutePath());
if (migrationResult == MigrationResult.SUCCESS) {
LOG.info("Part {}: OK. Success.", CheckCommandPart.MIGRATE_DB_SCHEMA_IF_NEEDED.number);
return true;
} else {
LOG.error("Part {}: KO. Failed.", CheckCommandPart.MIGRATE_DB_SCHEMA_IF_NEEDED.number);
throw new RuntimeException("Part " + CheckCommandPart.MIGRATE_DB_SCHEMA_IF_NEEDED.number + ": KO. Failed.");
}
} catch (Exception e) {
LOG.error("Part {}: KO. {}", CheckCommandPart.MIGRATE_DB_SCHEMA_IF_NEEDED.number, e.getMessage());
return false;
}
}
private void part3UpdateVersionInDbIfNeeded(BirContext birContext) {
LOG.info("** Part {}: Updating version, if needed.", CheckCommandPart.UPDATE_VERSION.number);
String version = birContext.getSystemItemRepository().read("bir.version").getValue();
System.out.println("Before: bir.version=" + version);
if (version == null) {
birContext.getSystemItemRepository().create(new SystemItem("bir.version", "0.0.0-SNAPSHOT"));
}
System.out.println("Updating version in DB.");
version = birContext.getSystemItemRepository().read("bir.version").getValue();
System.out.println("After: bir.version=" + version);
LOG.info("Part {}: OK.", CheckCommandPart.UPDATE_VERSION.number);
}
private ListSet<File> part4FoundFilesInFileSystem(BirFiles birFiles, BirArgs birArgs) {
LOG.info("** Part {}: Loading files in filesystem", CheckCommandPart.FOUND_FILES_IN_FILESYSTEM.number);
String workingDir = birFiles.getWorkingDirAbsolutePath();
List<File> filesAlreadyFound = new ArrayList<>();
List<File> filesInDirList = foundFilesInCurrentDir(birFiles.getWorkingDir(), filesAlreadyFound, birFiles);
ListSet<File> listSet = new ListSet<>(filesInDirList, f -> loadPathButOnlyTheNeededPart(birFiles.getWorkingDir(), f));
LOG.info("Part {}: Found {} files.", CheckCommandPart.FOUND_FILES_IN_FILESYSTEM.number, listSet.size());
if (birArgs.isVerboseLoggingEnabled()) {
filesInDirList.stream().forEach((f -> LOG.info("#" + (++iStatic) + " " + f.getAbsolutePath().substring(workingDir.length() + 1))));
}
return listSet;
}
private String loadPathButOnlyTheNeededPart(File currentDir, File file) {
return file.getAbsolutePath().substring(currentDir.getAbsolutePath().length() + 1);
}
@ -249,32 +219,244 @@ public class CheckCommand implements Command {
private int foundFiles;
private int foundDirs;
private List<File> foundFilesInCurrentDir(File currentDir, List<File> files) {
private List<File> foundFilesInCurrentDir(File currentDir, List<File> filesAlreadyFound, BirFiles birFiles) {
for (File f : currentDir.listFiles()) {
boolean isAlsoBirIgnore =f.getName().equals(birFiles.getBirIgnore().getName());
if(isAlsoBirIgnore && !f.getAbsolutePath().equals(birFiles.getBirIgnore().getAbsoluteFile())) {
birFiles.getBirIgnoreRegex().addBirIgnoreFile(f, birFiles.getWorkingDir());
}
if (f.isDirectory()) {
++foundDirs;
foundFilesInCurrentDir(f, files);
foundFilesInCurrentDir(f, filesAlreadyFound, birFiles);
} else {
++foundFiles;
if (f.getAbsolutePath().equals(birSQLite3File.getAbsolutePath())) {
if (f.getAbsolutePath().equals(birFiles.getBirSQLite3File().getAbsolutePath())) {
continue;
}
if (f.getAbsolutePath().equals(birSQLite3FileSha512.getAbsolutePath())) {
continue;
}
if (f.getAbsolutePath().equals(birIgnore.getAbsolutePath())) {
if (f.getAbsolutePath().equals(birFiles.getBirSQLite3FileSha512().getAbsolutePath())) {
continue;
}
++iii;
//System.out.println("Testing file: " + iii + "#" + " " + loadPathButOnlyTheNeededPart(currentDirRoot, f));
if (birIgnoreRegex.test(loadPathButOnlyTheNeededPart(currentDirRoot, f))) {
if (birFiles.getBirIgnoreRegex().test(loadPathButOnlyTheNeededPart(birFiles.getWorkingDir(), f))) {
continue;
}
files.add(f);
filesAlreadyFound.add(f);
}
}
return files;
return filesAlreadyFound;
}
private ListSet<FsFile> part5FoundFilesInDb(FileRepository fileRepository, BirArgs birArgs) {
LOG.info("** Part {}: Loading files in DB", CheckCommandPart.FOUND_FILES_IN_DB.number);
List<FsFile> filesInDb = fileRepository.list();
ListSet<FsFile> listSet = new ListSet<>(filesInDb, f -> f.getAbsolutePath());
LOG.info("Part {}: Found {} files.", CheckCommandPart.FOUND_FILES_IN_DB.number, listSet.size());
iStatic = 0;
if (birArgs.isVerboseLoggingEnabled()) {
filesInDb.stream().forEach((f -> System.out.println("#" + (++iStatic) + " " + f.toString())));
}
return listSet;
}
private LocalDateTime part6AddNewFilesToDb(ListSet<File> filesInFileSystem, BirFiles birFiles, ListSet<FsFile> filesInDb, BirContext birContext) {
LOG.info("** Part {}: Adding new files to DB", CheckCommandPart.ADD_NEW_FILES_TO_DB.number);
Date lastChecked = new Date();
org.nanoboot.powerframework.time.moment.LocalDateTime now = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastChecked);
int processedCount0 = 0;
List<FsFile> filesMissingInDb = new ArrayList<>();
for (File fileInDir : filesInFileSystem.getList()) {
processedCount0 = processedCount0 + 1;
if (processedCount0 % 100 == 0) {
double progress = ((double) processedCount0) / filesInFileSystem.getList().size() * 100;
LOG.info("Part {}: Add - Progress: {}/{} {} %",
CheckCommandPart.ADD_NEW_FILES_TO_DB.number,
processedCount0,
filesInFileSystem.getList().size(),
String.format("%,.2f", progress));
}
String absolutePathOfFileInDir = loadPathButOnlyTheNeededPart(birFiles.getWorkingDir(), fileInDir);
if (!filesInDb.doesSetContains(absolutePathOfFileInDir)) {
Date lastModified = new Date(fileInDir.lastModified());
org.nanoboot.powerframework.time.moment.LocalDateTime ldt = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastModified);
FsFile fsFile = new FsFile(
UUID.randomUUID().toString(),
fileInDir.getName(),
absolutePathOfFileInDir,
ldt.toString(),
now.toString(),
Utils.calculateSHA512Hash(fileInDir),
"SHA-512",
fileInDir.length(),
"OK"
);
filesMissingInDb.add(fsFile);
}
}
LOG.info("Adding new files: {}", filesMissingInDb.size());
birContext.getFileRepository().create(filesMissingInDb);
return now;
}
private List<FsFile> part7RemoveDeletedFilesFromDb(ListSet<FsFile> filesInDb, ListSet<File> filesInFileSystem, BirContext birContext) {
LOG.info("** Part {}: Removing deleted files from DB", CheckCommandPart.REMOVE_DELETED_FILES_FROM_DB.number);
List<FsFile> filesToBeRemovedFromDb = new ArrayList<>();
int processedCount = 0;
for (FsFile fileInDb : filesInDb.getList()) {
processedCount = processedCount + 1;
if (processedCount % 100 == 0) {
double progress = ((double) processedCount) / filesInDb.getList().size() * 100;
LOG.info(
"Part {}: Remove - Progress: {}/{} {}%",
CheckCommandPart.REMOVE_DELETED_FILES_FROM_DB.number,
processedCount,
filesInDb.getList().size(),
String.format("%,.2f", progress)
);
}
String absolutePathOfFileInDb = fileInDb.getAbsolutePath();
if (!filesInFileSystem.doesSetContains(absolutePathOfFileInDb)) {
filesToBeRemovedFromDb.add(fileInDb);
}
}
LOG.info("Part {}: Removing files: {}",
CheckCommandPart.REMOVE_DELETED_FILES_FROM_DB.number,
filesToBeRemovedFromDb.size());
for (FsFile f : filesToBeRemovedFromDb) {
birContext.getFileRepository().remove(f);
}
return filesToBeRemovedFromDb;
}
private List<FsFile> part8CompareContentAndLastModificationDate(
ListSet<FsFile> filesInDb, List<FsFile> filesToBeRemovedFromDb, BirContext birContext, LocalDateTime now) {
LOG.info("** Part {}: Comparing Content and last modification date", CheckCommandPart.COMPARE_CONTENT_AND_LAST_MODTIME.number);
double countOfFilesToCalculateHashSum = filesInDb.size() - filesToBeRemovedFromDb.size();
int processedCount = 0;
//// Update modified files with same last modification date
List<FsFile> filesWithBitRot = new ArrayList<>();
List<FsFile> filesToUpdateLastCheckDate = new ArrayList<>();
int contentAndModTimeWereChanged = 0;
RemainingTimeCalculator rtc = new RemainingTimeCalculator(filesInDb.size() - filesToBeRemovedFromDb.size());
for (FsFile fileInDb : filesInDb) {
String absolutePathOfFileInDb = fileInDb.getAbsolutePath();
if (filesToBeRemovedFromDb.contains(fileInDb)) {
//nothing to do
continue;
}
rtc.nextDone();
processedCount = processedCount + 1;
if (processedCount % 100 == 0) {
double progress = ((double) processedCount) / countOfFilesToCalculateHashSum * 100;
LOG.info("Update - Progress: " + processedCount + "/" + countOfFilesToCalculateHashSum + " " + String.format("%,.2f", progress) + "%");
LOG.info("Remains: " + Duration.of(rtc.remainingSecondsUntilEnd(), TimeUnit.SECOND).toString());
}
File file = new File("./" + absolutePathOfFileInDb);
Date lastModified = new Date(file.lastModified());
org.nanoboot.powerframework.time.moment.LocalDateTime ldt = org.nanoboot.powerframework.time.moment.LocalDateTime.convertJavaUtilDateToPowerLocalDateTime(lastModified);
String calculatedHash = Utils.calculateSHA512Hash(file);
if (ldt.toString().equals(fileInDb.getLastModificationDate()) && !calculatedHash.equals(fileInDb.getHashSumValue())) {
filesWithBitRot.add(fileInDb);
fileInDb.setLastCheckDate(now.toString());
fileInDb.setLastCheckResult("KO");
birContext.getFileRepository().updateFile(fileInDb);
continue;
}
if (!ldt.toString().equals(fileInDb.getLastModificationDate())) {
fileInDb.setLastCheckDate(now.toString());
fileInDb.setLastModificationDate(ldt.toString());
fileInDb.setHashSumValue(calculatedHash);
fileInDb.setHashSumAlgorithm("SHA-512");
fileInDb.setSize(file.length());
fileInDb.setLastCheckResult("OK");
birContext.getFileRepository().updateFile(fileInDb);
//System.out.println(fileInDb.toString());
contentAndModTimeWereChanged++;
continue;
}
if (ldt.toString().equals(fileInDb.getLastModificationDate())) {
fileInDb.setLastCheckResult("OK");
if (fileInDb.getSize() == 0) {
fileInDb.setSize(file.length());
birContext.getFileRepository().updateFile(fileInDb);
} else {
filesToUpdateLastCheckDate.add(fileInDb);
}
continue;
}
}
LOG.info("Part {}: Updating files - found bit rots - content was changed and last modification is the same): {}",
CheckCommandPart.COMPARE_CONTENT_AND_LAST_MODTIME.number,
filesWithBitRot.size());
LOG.info("Part {}: Updating files - content and last modification date were changed): {}",
CheckCommandPart.COMPARE_CONTENT_AND_LAST_MODTIME.number,
contentAndModTimeWereChanged);
LOG.info("Part {}: Updating files - content and last modification date were not changed): {}",
CheckCommandPart.COMPARE_CONTENT_AND_LAST_MODTIME.number,
filesToUpdateLastCheckDate.size());
birContext.getFileRepository().updateLastCheckDate(now.toString(), filesToUpdateLastCheckDate);
return filesWithBitRot;
}
private void part9CreateReportCsvIfNeeded(BirArgs birArgs, BirFiles birFiles, List<FsFile> filesWithBitRot) {
LOG.info("** Part {}: Creating csv report, if needed", CheckCommandPart.CREATE_REPORT_CSV_IF_NEEDED.number);
if (!birArgs.hasArgument("report")) {
LOG.info(" Part {}: OK. Nothing to do. No option report was passed.", CheckCommandPart.CREATE_REPORT_CSV_IF_NEEDED.number);
return;
}
if (!birArgs.getArgument("report").equals("true")) {
LOG.info("Part {}: Nothing to do. Option report={}",
CheckCommandPart.CREATE_REPORT_CSV_IF_NEEDED.number,
birArgs.getArgument("report"));
return;
}
File birReportCsv = birFiles.getBirReportCsv();
if (birReportCsv.exists()) {
Long nowLong = org.nanoboot.powerframework.time.moment.UniversalDateTime.now().toLong();
File backup = new File(birReportCsv.getParentFile().getAbsolutePath() + "/" + nowLong + "." + birReportCsv.getName());
birReportCsv.renameTo(backup);
}
StringBuilder sb = new StringBuilder();
if (!filesWithBitRot.isEmpty()) {
sb.append("file;expected;calculated\n");
}
filesWithBitRot.stream().forEach(f
-> sb.append(f.getAbsolutePath())
.append(";")
.append(f.getHashSumValue())
.append(";")
.append(Utils.calculateSHA512Hash(new File("./" + f.getAbsolutePath())))
.append("\n")
);
Utils.writeTextToFile(sb.toString(), birReportCsv);
LOG.info("Part {}: OK.",
CheckCommandPart.CREATE_REPORT_CSV_IF_NEEDED.number);
}
private void part10CalculateCurrentHashSumOfDbFile(BirFiles birFiles) {
LOG.info("** Part {}: Calculating current hash sum of DB file", CheckCommandPart.CHECK_NEW_DB_CHECKSUM.number);
Utils.writeTextToFile(Utils.calculateSHA512Hash(birFiles.getBirSQLite3File()), birFiles.getBirSQLite3FileSha512());
}
}

View File

@ -1,304 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// dog: Tool generating documentation.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.dog.commands;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import org.nanoboot.dog.Command;
import org.nanoboot.dog.DogArgs;
import org.nanoboot.dog.Menu;
import org.nanoboot.dog.Utils;
import org.asciidoctor.Asciidoctor;
import static org.asciidoctor.Asciidoctor.Factory.create;
import org.nanoboot.dog.DogException;
import org.apache.commons.io.FileUtils;
/**
*
* @author pc00289
*/
public class GenCommand implements Command {
private static final String ADOC_EXTENSION = ".adoc";
public GenCommand() {
}
@Override
public String getName() {
return "gen";
}
@Override
public void run(DogArgs dogArgs) {
if (!dogArgs.hasArgument("in")) {
dogArgs.addArgument("in", new File(".").getAbsolutePath());
}
if (dogArgs.getArgument("in") == null) {
throw new DogException("Argument in must have a value (must not be empty).");
}
if (dogArgs.hasArgument("out") && !(new File(dogArgs.getArgument("out")).exists())) {
throw new DogException("Argument out must be an existing directory.");
}
File inDir = new File(dogArgs.getArgument("in"));
if (!inDir.exists()) {
throw new DogException("Argument in must be an existing directory, but that directory does not exist.");
}
File dogConfFile = new File(inDir, "dog.conf");
if (!dogConfFile.exists()) {
throw new DogException("File dog.conf was not found.");
}
File generatedDir = new File((dogArgs.hasArgument("out") ? new File(dogArgs.getArgument("out")) : inDir), "generated");
if (generatedDir.exists()) {
try {
FileUtils.deleteDirectory(generatedDir);
} catch (IOException ex) {
ex.printStackTrace();
throw new DogException("Deleting generated directory failed.", ex);
}
}
generatedDir.mkdir();
if (!generatedDir.exists()) {
throw new DogException("Argument out must be an existing directory, but that directory does not exist.");
}
//
Properties dogConfProperties = null;
try (InputStream input = new FileInputStream(dogConfFile.getAbsolutePath())) {
dogConfProperties = new Properties();
dogConfProperties.load(input);
} catch (IOException ex) {
ex.printStackTrace();
throw new DogException("Loading file dog.conf failed.", ex);
}
Utils.writeTextToFile(Utils.readTextFromResourceFile("/dog.css"), new File(generatedDir, "dog.css"));
File contentDir = new File(inDir, "content");
Menu menuInstance = new Menu(contentDir);
File templateDir = new File(contentDir.getParentFile().getAbsolutePath() + "/templates");
String headerTemplate = Utils.readTextFromFile(new File(templateDir, "header.html"));
String footerTemplate = Utils.readTextFromFile(new File(templateDir, "footer.html"));
processContentDir(contentDir, generatedDir, contentDir, dogConfProperties, menuInstance, headerTemplate, footerTemplate);
}
private static void processContentDir(File dir, File generatedDir, File contentDir, Properties dogConfProperties, Menu menuInstance, String headerTemplate, String footerTemplate) {
for (File inFile : dir.listFiles()) {
if (inFile.isFile()) {
processFileInContentDir(inFile, dir, contentDir, dogConfProperties, headerTemplate, menuInstance, footerTemplate, generatedDir);
}
if (inFile.isDirectory()) {
processDirInContentDir(generatedDir, inFile, contentDir, dogConfProperties, menuInstance, headerTemplate, footerTemplate);
}
}
}
public static void processDirInContentDir(File generatedDir, File inFile, File contentDir, Properties dogConfProperties, Menu menuInstance, String headerTemplate, String footerTemplate) {
File generatedDir2 = new File(generatedDir, inFile.getName());
generatedDir2.mkdir();
processContentDir(inFile, generatedDir2, contentDir, dogConfProperties, menuInstance, headerTemplate, footerTemplate);
}
public static void processFileInContentDir(File inFile, File dir, File contentDir, Properties dogConfProperties, String headerTemplate, Menu menuInstance, String footerTemplate, File generatedDir) {
if (inFile.getName().endsWith(ADOC_EXTENSION)) {
Asciidoctor asciidoctor = create();
String asciidocText = Utils.readTextFromFile(inFile);
String asciidocCompiled = asciidoctor
.convert(asciidocText, new HashMap<String, Object>());
String pathToRoot = dir.getAbsolutePath().replace(contentDir.getAbsolutePath(), "");
if (!pathToRoot.trim().isEmpty()) {
int count = 0;
for (char ch : pathToRoot.toCharArray()) {
if (ch == '/') {
count++;
}
}
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= count; i++) {
sb.append("../");
}
pathToRoot = sb.toString();
}
String titleSeparator = dogConfProperties.containsKey("titleSeparator") ? dogConfProperties.getProperty("titleSeparator") : "::";
final String humanName = createHumanName(inFile, dogConfProperties);
String start
= """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.16">
<title>
"""
+ humanName
+ (dogConfProperties.containsKey("title")
? (" " + titleSeparator + " " + dogConfProperties.getProperty("title")) : "")
+ """
</title>
<link rel="stylesheet" href="
"""
+ pathToRoot
+ """
dog.css">
</head>
<body class="article">
"""
+ headerTemplate
+ """
<div id="header">
"""
+ createNavigation(inFile, contentDir, dogConfProperties)
+ "<h1>"
+ humanName
+ """
</h1>
</div>"""
+ createMenu(menuInstance, inFile)
+ """
<div id="content">
""";
String end
= """
</div>
<div id="footer">
<div id="footer-text">
Last updated """
+ " "
+ (org.nanoboot.dog.Constants.YYYYMMDDHHMMSSZ_DATE_FORMAT.format(new Date()))
+ "<br>" + footerTemplate
+ """
</div>
</div>
</body>
</html>
""";
List<String> dirs = new ArrayList<>();
File currentFile = inFile;
String rootContentDirPath = contentDir.getAbsolutePath();
while (!currentFile.getAbsolutePath().equals(rootContentDirPath)) {
dirs.add(currentFile.getName());
currentFile = currentFile.getParentFile();
}
StringBuilder sb = new StringBuilder();
for (int i = dirs.size() - 1; i >= 0; i--) {
String d = dirs.get(i);
sb.append(d);
if (i > 0) {
sb.append("/");
}
}
String editThisPage = "<hr><a href=\"" + dogConfProperties.getProperty("editURL") + sb.toString() + "\">Edit this page</a>";
String htmlOutput = start + asciidocCompiled + editThisPage + end;
File htmlFile = new File(generatedDir, inFile.getName().replace(ADOC_EXTENSION, ".html"));
Utils.writeTextToFile(htmlOutput, htmlFile);
} else {
Utils.copyFile(inFile, generatedDir);
}
}
private static String createMenu(Menu menu, File currentFile) {
return //"<pre>" + menu.toAsciidoc(currentFile.getAbsolutePath().split("content")[1]) + "</pre>" +
menu.toHtml(currentFile.getAbsolutePath().split("content")[1]);
}
private static String createNavigation(File adocFile, File rootContentDir, Properties dogConfProperties) {
List<File> files = new ArrayList<>();
File currentFile = adocFile;
while (!currentFile.getAbsolutePath().equals(rootContentDir.getAbsolutePath())) {
if (currentFile.getName().equals("content")) {
continue;
}
files.add(currentFile);
currentFile = currentFile.getParentFile();
}
StringBuilder sb = new StringBuilder("<div class=\"navigation\" style=\"margin-top:20px;\"><a href=\"" + /*path +*/ Utils.createDoubleDotSlash(files.size() - 1) + "index.html\">Home</a>");
if (files.size() > 1 || !currentFile.getName().equals("index.adoc")) {
sb.append(" > ");
}
for (int i = (files.size() - 1); i >= 0; i--) {
File file = files.get(i);
if (file.getName().equals("index.adoc")) {
continue;
}
sb
.append("<a href=\"")
.append(Utils.createDoubleDotSlash(i - 1))
.append(i == 0 ? (file.getName().replace(ADOC_EXTENSION, "")) : "index")
.append(".html\">")
.append(createHumanName(file, dogConfProperties))
.append("</a>\n");
sb.append(" > ");
}
sb.append("</div>");
String result = sb.toString();
if (result.endsWith(" > </div>")) {
result = result.substring(0, result.length() - 9);
result = result + "</div>";
}
return result + "<hr>";
}
private static String createHumanName(File inFile, Properties dogConfProperties) {
String result = inFile.getName();
if (result.endsWith(ADOC_EXTENSION)) {
result = result.substring(0, inFile.getName().length() - ADOC_EXTENSION.length());
}
result = result.replace("_", " ");
if (Character.isLetter(result.charAt(0))) {
result = Character.toUpperCase(result.charAt(0)) + result.substring(1);
}
if (result.equals("Index")) {
File parentFile = inFile.getParentFile();
if (parentFile.getName().equals("content")) {
String frontPageName = dogConfProperties.getProperty("frontPageName", "");
return frontPageName.isBlank() ? "Home" : frontPageName;
}
return createHumanName(parentFile, dogConfProperties);
}
return result;
}
}

View File

@ -19,24 +19,26 @@
package org.nanoboot.bitinspector.commands;
import org.nanoboot.bitinspector.core.Command;
import org.nanoboot.bitinspector.core.BitInspectorArgs;
import org.nanoboot.bitinspector.core.BirArgs;
/**
*
* @author pc00289
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class HelpCommand implements Command {
public static final String NAME = "help";
public HelpCommand() {
}
@Override
public String getName() {
return "help";
return NAME;
}
@Override
public void run(BitInspectorArgs bitInspectorArgs) {
public String run(BirArgs bitInspectorArgs) {
String str = """
NAME
bir - " Bit Inspector"
@ -51,13 +53,15 @@ public class HelpCommand implements Command {
COMMAND
check Generates the static website
OPTIONS
reportid={unique name for this report, usually `date +'%Y%m%d_%H%M%S'`}
Optional. Default= (nothing will be reported to file report.{reportid}.bitreport.txt).
dir={working directory to be checked for bit rot}
Optional. Default=. (current working directory)
report=true or false
Optional. Default= false (nothing will be reported to file .birreport.csv).
help Display help information
version Display version information
""";
System.out.println(str);
return str;
}
}

View File

@ -19,26 +19,32 @@
package org.nanoboot.bitinspector.commands;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nanoboot.bitinspector.core.Command;
import org.nanoboot.bitinspector.core.BitInspectorArgs;
import org.nanoboot.bitinspector.core.BirArgs;
/**
*
* @author pc00289
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class VersionCommand implements Command {
public static final String NAME = "version";
private static final Logger LOG = LogManager.getLogger(VersionCommand.class);
public VersionCommand() {
}
@Override
public String getName() {
return "version";
return NAME;
}
@Override
public void run(BitInspectorArgs bitInspectorArgs) {
System.out.println("Bit Inspector 0.0.0-SNAPSHOT");
public String run(BirArgs bitInspectorArgs) {
String result = "Bit Inspector 0.0.0-SNAPSHOT";
LOG.info(result);
return result;
}
}

View File

@ -16,7 +16,6 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import java.util.HashMap;
@ -25,15 +24,33 @@ import lombok.Getter;
/**
*
* @author pc00289
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class BitInspectorArgs {
public class BirArgs {
@Getter
private final String command;
private final Map<String, String> internalMap = new HashMap<>();
public BitInspectorArgs(String[] args) {
private static String[] convertToStringArray(String command, Map<String, String> map) {
String[] array = new String[1 + map.size()];
array[0] = command;
int i = 0;
for (String key : map.keySet()) {
array[++i] = key + "=" + map.get(key);
}
return array;
}
public BirArgs(BitInspectorCommand command, Map<String, String> map) {
this(convertToStringArray(command.name().toLowerCase(), map));
}
public BirArgs(String command, Map<String, String> map) {
this(convertToStringArray(command, map));
}
public BirArgs(String[] args) {
command = args.length == 0 ? "check" : args[0];
if (args.length > 1) {
@ -54,15 +71,20 @@ public class BitInspectorArgs {
}
}
public boolean hasArgument(String arg) {
return internalMap.containsKey(arg);
}
public void addArgument(String arg, String value) {
this.internalMap.put(arg,value);
this.internalMap.put(arg, value);
}
public String getArgument(String arg) {
return internalMap.get(arg);
}
public boolean isVerboseLoggingEnabled() {
return hasArgument("verbose")&&getArgument("verbose").equals("true");
}
}

View File

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import lombok.Getter;
import org.nanoboot.bitinspector.persistence.api.ConnectionFactory;
import org.nanoboot.bitinspector.persistence.api.FileRepository;
import org.nanoboot.bitinspector.persistence.api.SystemItemRepository;
import org.nanoboot.bitinspector.persistence.impl.sqlite.FileRepositoryImplSqlite;
import org.nanoboot.bitinspector.persistence.impl.sqlite.SqliteConnectionFactory;
import org.nanoboot.bitinspector.persistence.impl.sqlite.SystemItemRepositoryImplSqlite;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class BirContext {
private final String directoryWhereSqliteFileIs;
private ConnectionFactory connectionFactory;
@Getter
private SystemItemRepository systemItemRepository;
@Getter
private FileRepository fileRepository;
public BirContext(String directoryWhereSqliteFileIs) {
this.directoryWhereSqliteFileIs = directoryWhereSqliteFileIs;
this.connectionFactory = new SqliteConnectionFactory(directoryWhereSqliteFileIs);
systemItemRepository = new SystemItemRepositoryImplSqlite((SqliteConnectionFactory) connectionFactory);
fileRepository = new FileRepositoryImplSqlite((SqliteConnectionFactory) connectionFactory);
}
}

View File

@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import java.io.File;
import lombok.Data;
import lombok.Getter;
import org.nanoboot.bitinspector.commands.BirIgnoreRegex;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
@Data
@Getter
public class BirFiles {
private final File workingDir;
private final String workingDirAbsolutePath;
private final File birSQLite3File;
private final File birSQLite3FileSha512;
private final File birIgnore;
private final BirIgnoreRegex birIgnoreRegex;
private final File birReportCsv;
public BirFiles(BirArgs bitInspectorArgs) {
workingDir = new File(bitInspectorArgs.hasArgument("dir") ? bitInspectorArgs.getArgument("dir") : ".");
workingDirAbsolutePath = workingDir.getAbsolutePath();
birSQLite3File = new File(workingDirAbsolutePath + "/.bir.sqlite3");
birSQLite3FileSha512 = new File(workingDirAbsolutePath + "/.bir.sqlite3.sha512");
birIgnore = new File(workingDirAbsolutePath + "/.birignore");
birIgnoreRegex = new BirIgnoreRegex(birIgnore);
birReportCsv = new File(workingDirAbsolutePath + "/.birreport.csv");
}
}

View File

@ -0,0 +1,69 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import java.util.HashSet;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nanoboot.bitinspector.commands.CheckCommand;
import org.nanoboot.bitinspector.commands.HelpCommand;
import org.nanoboot.bitinspector.commands.VersionCommand;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class BitInspector {
private static final Logger LOG = LogManager.getLogger(BitInspector.class);
private final Set<Command> commandImplementations;
public BitInspector() {
commandImplementations = new HashSet<>();
commandImplementations.add(new CheckCommand());
commandImplementations.add(new HelpCommand());
commandImplementations.add(new VersionCommand());
}
public void run(String[] args) {
run(new BirArgs(args));
}
public void run(BirArgs bitInspectorArgs) {
String command = bitInspectorArgs.getCommand();
Command foundCommand = null;
for(Command e:commandImplementations) {
if(e.getName().equals(command)) {
foundCommand = e;
break;
}
}
if(foundCommand == null) {
String msg = "Command \"" + command + "\" is not supported.";
LOG.error(msg);
new HelpCommand().run(bitInspectorArgs);
throw new BitInspectorException(msg);
}
foundCommand.run(bitInspectorArgs);
}
}

View File

@ -0,0 +1,28 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public enum BitInspectorCommand {
CHECK, HELP, VERSION;
}

View File

@ -21,11 +21,11 @@ package org.nanoboot.bitinspector.core;
/**
*
* @author pc00289
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public interface Command {
public String getName();
default void run(BitInspectorArgs bitInspectorArgs) {
default String run(BirArgs bitInspectorArgs) {
throw new BitInspectorException("Not yet implemented.");
}

View File

@ -23,7 +23,7 @@ import java.text.SimpleDateFormat;
/**
*
* @author pc00289
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class Constants {

View File

@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.Getter;
/**
*
* @author robertvokac
*/
public class ListSet<T> implements Iterable<T> {
@Getter
private final List<T> list;
@Getter
private final Set<String> set;
public ListSet(List<T> list, Function<? super T, String> mapper) {
this.list = Collections.unmodifiableList(list);
this.set = Collections.unmodifiableSet(list.stream().map(mapper).collect(Collectors.toSet()));
}
public boolean doesSetContains(String s) {
return set.contains(s);
}
public int size() {
return list.size();
}
@Override
public Iterator<T> iterator() {
return list.iterator();
}
}

View File

@ -18,12 +18,6 @@
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import org.nanoboot.bitinspector.commands.HelpCommand;
import org.nanoboot.bitinspector.commands.CheckCommand;
import org.nanoboot.bitinspector.commands.VersionCommand;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
* @since 0.0.0
@ -32,28 +26,9 @@ public class Main {
public static void main(String[] args) {
System.out.println("Bir - Detects bit rotten files in the given directory to keep your files forever.\n");
BitInspectorArgs BitInspectorArgs = new BitInspectorArgs(args);
String command = BitInspectorArgs.getCommand();
Set<Command> commandImplementations = new HashSet<>();
commandImplementations.add(new CheckCommand());
commandImplementations.add(new HelpCommand());
commandImplementations.add(new VersionCommand());
Command foundCommand = null;
for(Command e:commandImplementations) {
if(e.getName().equals(command)) {
foundCommand = e;
break;
}
}
if(foundCommand == null) {
System.err.println("Error: Command \"" + command + "\" is not supported.\n");
new HelpCommand().run(BitInspectorArgs);
System.exit(1);
}
foundCommand.run(BitInspectorArgs);
BitInspector bitInspector = new BitInspector();
bitInspector.run(args);
}

View File

@ -16,8 +16,11 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.core;
import dev.mccue.guava.hash.Hashing;
import dev.mccue.guava.io.Files;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
@ -25,12 +28,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
@ -38,7 +39,7 @@ import java.util.logging.Logger;
/**
*
* @author pc00289
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class Utils {
@ -65,31 +66,6 @@ public class Utils {
}
}
public static int getCountOfSlashOccurences(String string) {
int i = 0;
for (char ch : string.toCharArray()) {
if (ch == '/') {
i++;
}
}
return i++;
}
public static List<File> listAdocFilesInDir(File dir) {
return listAdocFilesInDir(dir, new ArrayList<>());
}
private static List<File> listAdocFilesInDir(File dir, List<File> files) {
List<File> allFiles = listAllFilesInDir(dir, files);
List<File> adocFiles = new ArrayList<>();
for (File f : allFiles) {
if (f.getName().endsWith(".adoc") && !f.isDirectory()) {
adocFiles.add(f);
}
}
return adocFiles;
}
public static List<File> listAllFilesInDir(File dir) {
return listAllFilesInDir(dir, new ArrayList<>());
}
@ -106,21 +82,12 @@ public class Utils {
return files;
}
public static String createDoubleDotSlash(int times) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= times; i++) {
sb.append("../");
}
String result = sb.toString();
return result;//.substring(0, result.length() - 1);
}
public static void copyFile(File originalFile, File copiedFile) throws BitInspectorException {
Path originalPath = originalFile.toPath();
Path copied = new File(copiedFile, originalFile.getName()).toPath();
try {
Files.copy(originalPath, copied, StandardCopyOption.REPLACE_EXISTING);
java.nio.file.Files.copy(originalPath, copied, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
ex.printStackTrace();
throw new BitInspectorException("Copying file failed: " + originalFile.getAbsolutePath());
@ -145,7 +112,7 @@ public class Utils {
return "";
}
try {
return new String(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
return new String(java.nio.file.Files.readAllBytes(Paths.get(file.getAbsolutePath())));
} catch (IOException ex) {
throw new BitInspectorException("Reading file failed: " + file.getName(), ex);
}
@ -176,24 +143,36 @@ public class Utils {
}
public static String calculateSHA512Hash(File file) {
final Path path = Paths.get(file.getAbsolutePath());
byte[] bytes;
try {
bytes = Files.readAllBytes(path);
return Files.hash(file, Hashing.sha512()).toString();
// final Path path = Paths.get(file.getAbsolutePath());
// byte[] bytes;
// try {
// bytes = Files.readAllBytes(path);
// } catch (IOException ex) {
// throw new BitInspectorException(ex);
// }
// byte[] sha512sumByteArray;
// if(file.length() >= Integer.MAX_VALUE) {
// throw new RuntimeException("File is too large: " + file.getAbsolutePath());
// }
// try {
// sha512sumByteArray = MessageDigest.getInstance("SHA-512").digest(bytes);
// } catch (NoSuchAlgorithmException ex) {
// throw new BitInspectorException(ex);
// }
// StringBuilder sb = new StringBuilder(sha512sumByteArray.length * 2);
// for (byte b : sha512sumByteArray) {
// sb.append(String.format("%02x", b));
// }
// String hexString = sb.toString();
// return hexString;
} catch (IOException ex) {
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
throw new BitInspectorException(ex);
}
byte[] sha512sumByteArray;
try {
sha512sumByteArray = MessageDigest.getInstance("SHA-512").digest(bytes);
} catch (NoSuchAlgorithmException ex) {
throw new BitInspectorException(ex);
}
StringBuilder sb = new StringBuilder(sha512sumByteArray.length * 2);
for (byte b : sha512sumByteArray) {
sb.append(String.format("%02x", b));
}
String hexString = sb.toString();
return hexString;
}
public static String createJdbcUrl(String directoryWhereSqliteFileIs) {
return "jdbc:sqlite:" + directoryWhereSqliteFileIs + "/" + ".bir.sqlite3?foreign_keys=on;";
}
}

View File

@ -26,7 +26,7 @@ import lombok.ToString;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
@Getter
@Setter
@ -40,5 +40,7 @@ public class FsFile {
private String lastCheckDate;
private String hashSumValue;
private String hashSumAlgorithm;
private long size;
private String lastCheckResult;
}

View File

@ -25,7 +25,7 @@ import lombok.Setter;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
@Getter
@Setter

View File

@ -1,38 +1,30 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// dog: Tool generating documentation.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.dog.commands;
import org.nanoboot.dog.Command;
/**
*
* @author pc00289
*/
public class HelpCommand implements Command {
public HelpCommand() {
}
@Override
public String getName() {
return "help";
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.api;
import java.sql.Connection;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public interface ConnectionFactory {
Connection createConnection() throws ClassNotFoundException;
}

View File

@ -24,7 +24,7 @@ import org.nanoboot.bitinspector.entity.FsFile;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public interface FileRepository {
void create(List<FsFile> files);

View File

@ -24,7 +24,7 @@ import org.nanoboot.bitinspector.entity.SystemItem;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public interface SystemItemRepository {
String create(SystemItem systemItem);

View File

@ -20,10 +20,10 @@ package org.nanoboot.bitinspector.persistence.impl.sqlite;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class Constants {
static final String JDBC_URL = "jdbc:sqlite:" + "." + "/" + ".bir.sqlite3?foreign_keys=on;";
private Constants() {
//Not meant to be instantiated.
}

View File

@ -31,10 +31,16 @@ import org.nanoboot.bitinspector.persistence.api.FileRepository;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class FileRepositoryImplSqlite implements FileRepository {
private SqliteConnectionFactory sqliteConnectionFactory;
public FileRepositoryImplSqlite(SqliteConnectionFactory sqliteConnectionFactory) {
this.sqliteConnectionFactory = sqliteConnectionFactory;
}
@Override
public void create(List<FsFile> files) {
if (files.isEmpty()) {
@ -69,13 +75,15 @@ public class FileRepositoryImplSqlite implements FileRepository {
.append(FileTable.LAST_CHECK_DATE).append(",")
//
.append(FileTable.HASH_SUM_VALUE).append(",")
.append(FileTable.HASH_SUM_ALGORITHM);
.append(FileTable.HASH_SUM_ALGORITHM).append(",")
.append(FileTable.SIZE).append(",")
.append(FileTable.LAST_CHECK_RESULT).append("");
sb.append(") VALUES ");
int index = 0;
for (FsFile f : files) {
sb.append(" (?,?,?,?,?, ?,?)");
sb.append(" (?,?,?,?,?, ?,?,?,?)");
boolean lastFile = index == (files.size() - 1);
if (!lastFile) {
sb.append(",");
@ -84,7 +92,7 @@ public class FileRepositoryImplSqlite implements FileRepository {
}
String sql = sb.toString();
System.err.println(sql);
//System.err.println(sql);
try (
Connection connection = createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
@ -99,11 +107,13 @@ public class FileRepositoryImplSqlite implements FileRepository {
//
stmt.setString(++i, f.getHashSumValue());
stmt.setString(++i, f.getHashSumAlgorithm());
stmt.setLong(++i, f.getSize());
stmt.setString(++i, f.getLastCheckResult());
}
//
stmt.execute();
System.out.println(stmt.toString());
//System.out.println(stmt.toString());
} catch (SQLException e) {
System.out.println(e.getMessage());
@ -124,7 +134,7 @@ public class FileRepositoryImplSqlite implements FileRepository {
.append(FileTable.TABLE_NAME);
String sql = sb.toString();
System.err.println(sql);
// System.err.println(sql);
int i = 0;
ResultSet rs = null;
try (
@ -165,7 +175,7 @@ public class FileRepositoryImplSqlite implements FileRepository {
sb.append(FileTable.ID);
sb.append("=?");
String sql = sb.toString();
System.err.println("SQL::" + sql);
//System.err.println("SQL::" + sql);
int i = 0;
try (
@ -173,7 +183,7 @@ public class FileRepositoryImplSqlite implements FileRepository {
stmt.setString(++i, file.getId());
System.err.println(stmt.toString());
//System.err.println(stmt.toString());
stmt.execute();
} catch (SQLException e) {
@ -185,7 +195,7 @@ public class FileRepositoryImplSqlite implements FileRepository {
}
private Connection createConnection() throws ClassNotFoundException {
return new SqliteConnectionFactory().createConnection();
return sqliteConnectionFactory.createConnection();
}
@Override
@ -199,7 +209,9 @@ public class FileRepositoryImplSqlite implements FileRepository {
.append(FileTable.LAST_MODIFICATION_DATE).append("=?, ")
.append(FileTable.LAST_CHECK_DATE).append("=?, ")
.append(FileTable.HASH_SUM_VALUE).append("=?, ")
.append(FileTable.HASH_SUM_ALGORITHM).append("=? ")
.append(FileTable.HASH_SUM_ALGORITHM).append("=?, ")
.append(FileTable.SIZE).append("=?, ")
.append(FileTable.LAST_CHECK_RESULT).append("=? ")
.append(" WHERE ").append(FileTable.ID).append("=?");
String sql = sb.toString();
@ -211,6 +223,8 @@ public class FileRepositoryImplSqlite implements FileRepository {
stmt.setString(++i, file.getLastCheckDate());
stmt.setString(++i, file.getHashSumValue());
stmt.setString(++i, file.getHashSumAlgorithm());
stmt.setLong(++i, file.getSize());
stmt.setString(++i, file.getLastCheckResult());
stmt.setString(++i, file.getId());
@ -232,14 +246,16 @@ public class FileRepositoryImplSqlite implements FileRepository {
rs.getString(FileTable.LAST_MODIFICATION_DATE),
rs.getString(FileTable.LAST_CHECK_DATE),
rs.getString(FileTable.HASH_SUM_VALUE),
rs.getString(FileTable.HASH_SUM_ALGORITHM)
rs.getString(FileTable.HASH_SUM_ALGORITHM),
rs.getLong(FileTable.SIZE),
rs.getString(FileTable.LAST_CHECK_RESULT)
);
}
@Override
public void updateLastCheckDate(String lastCheckDate, List<FsFile> files) {
if (files.isEmpty()) {
if (files.isEmpty()) {
return;
}
if (files.size() > 100) {
@ -258,13 +274,14 @@ public class FileRepositoryImplSqlite implements FileRepository {
}
return;
}
StringBuilder sb = new StringBuilder();
sb
.append("UPDATE ")
.append(FileTable.TABLE_NAME)
.append(" SET ")
.append(FileTable.LAST_CHECK_DATE).append("=? ")
.append(FileTable.LAST_CHECK_DATE).append("=?, ")
.append(FileTable.LAST_CHECK_RESULT).append("='OK' ")
.append(" WHERE ").append(FileTable.ID).append(" IN (");
int index = 0;
for (FsFile f : files) {

View File

@ -24,7 +24,7 @@ import lombok.Setter;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
@Getter
@Setter
@ -40,5 +40,8 @@ class FileTable {
//
public static final String HASH_SUM_VALUE = "HASH_SUM_VALUE";
public static final String HASH_SUM_ALGORITHM = "HASH_SUM_ALGORITHM";
public static final String SIZE = "SIZE";
public static final String LAST_CHECK_RESULT = "LAST_CHECK_RESULT";
}

View File

@ -18,21 +18,26 @@
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
import org.nanoboot.bitinspector.persistence.api.ConnectionFactory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.nanoboot.bitinspector.core.Utils;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class SqliteConnectionFactory {
public class SqliteConnectionFactory implements ConnectionFactory {
private final String jdbcUrl;
public SqliteConnectionFactory(String directoryWhereSqliteFileIs) {
this.jdbcUrl = Utils.createJdbcUrl(directoryWhereSqliteFileIs);
}
public Connection createConnection() throws ClassNotFoundException {
try {
Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection(Constants.JDBC_URL);
Connection conn = DriverManager.getConnection(jdbcUrl);
return conn;

View File

@ -18,33 +18,48 @@
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.bitinspector.persistence.impl.sqlite;
import org.nanoboot.bitinspector.core.Utils;
import org.nanoboot.dbmigration.core.main.DBMigration;
import org.nanoboot.dbmigration.core.main.MigrationResult;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class SqliteDatabaseMigration {
public void migrate() {
private static SqliteDatabaseMigration INSTANCE;
private SqliteDatabaseMigration() {
//Not meant to be instantiated
}
public static SqliteDatabaseMigration getInstance() {
if (INSTANCE == null) {
INSTANCE = new SqliteDatabaseMigration();
}
return INSTANCE;
}
public MigrationResult migrate(String directoryWhereSqliteFileIs) {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException ex) {
System.err.println(ex.getMessage());
throw new RuntimeException(ex);
}
System.err.println("jdbcUrl=" + Constants.JDBC_URL);
String jdbcUrl = Utils.createJdbcUrl(directoryWhereSqliteFileIs);
System.err.println("jdbcUrl=" + jdbcUrl);
String clazz = this.getClass().getName();
DBMigration dbMigration = DBMigration
.configure()
.dataSource(Constants.JDBC_URL)
.dataSource(jdbcUrl)
.installedBy("bitinspector-persistence-impl-sqlite")
.name("bitinspector")
.sqlDialect("sqlite", "org.nanoboot.dbmigration.core.persistence.impl.sqlite.DBMigrationPersistenceSqliteImpl")
.sqlMigrationsClass(clazz)
.load();
dbMigration.migrate();
return dbMigration.migrate();
}
}

View File

@ -30,10 +30,16 @@ import org.nanoboot.bitinspector.persistence.api.SystemItemRepository;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class SystemItemRepositoryImplSqlite implements SystemItemRepository {
public SystemItemRepositoryImplSqlite(SqliteConnectionFactory sqliteConnectionFactory) {
this.sqliteConnectionFactory = sqliteConnectionFactory;
}
private final SqliteConnectionFactory sqliteConnectionFactory;
@Override
public String create(SystemItem systemItem) {
@ -52,7 +58,7 @@ public class SystemItemRepositoryImplSqlite implements SystemItemRepository {
String sql = sb.toString();
System.err.println(sql);
try (
Connection connection = new SqliteConnectionFactory().createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, systemItem.getKey());
stmt.setString(++i, systemItem.getValue());
@ -95,7 +101,7 @@ public class SystemItemRepositoryImplSqlite implements SystemItemRepository {
int i = 0;
ResultSet rs = null;
try (
Connection connection = new SqliteConnectionFactory().createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setString(++i, key);

View File

@ -24,7 +24,7 @@ import lombok.Setter;
/**
*
* @author robertvokac
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
@Getter
@Setter

View File

@ -0,0 +1,2 @@
ALTER TABLE "FILE" ADD COLUMN SIZE NUMBER

View File

@ -0,0 +1,2 @@
ALTER TABLE "FILE" ADD COLUMN LAST_CHECK_RESULT NUMBER