initial push

This commit is contained in:
2022-06-29 14:56:42 +02:00
commit 75e95e8430
18 changed files with 686 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
import net.horizoncode.sysbackup.App;
public class Bootstrapper {
public static void main(String[] args) {
App.getInstance().start(args);
}
}

View File

@@ -0,0 +1,17 @@
package net.horizoncode.sysbackup;
import net.horizoncode.sysbackup.cli.CLIProcessor;
public class App {
private static App instance;
public static App getInstance() {
if (instance != null) return instance;
return instance = new App();
}
public void start(String[] args){
CLIProcessor cliProcessor = new CLIProcessor();
cliProcessor.startCLI(args);
}
}

View File

@@ -0,0 +1,123 @@
package net.horizoncode.sysbackup.cli;
import net.horizoncode.sysbackup.App;
import net.horizoncode.sysbackup.config.Config;
import net.horizoncode.sysbackup.tasks.TaskBuilder;
import org.apache.commons.io.FileUtils;
import org.tomlj.Toml;
import org.tomlj.TomlParseResult;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.Objects;
public class CLIProcessor {
public static void usage() {
String[] usage = {
"Usage: java -jar sysbackup.jar [action] <args>",
" Backup:",
" backup <backup task> create a backup based on a backup task configuration file",
" Miscellaneous:",
" checkTaskConf <file name> checks a backup task configuration file",
" generateTaskConf <file name> generate a example backup task configuration file",
" Examples:",
" java -jar sysbackup.jar generateTaskConf magento",
" java -jar sysbackup.jar backup magento"
};
for (String u : usage) {
System.out.println(u);
}
}
public void startCLI(String[] args) {
try {
if ((args == null) || (args.length == 0)) {
usage();
return;
}
for (int index = 0; index < args.length; index++) {
switch (args[index].toLowerCase(Locale.ROOT)) {
case "backup":
{
if (args.length <= 1) {
System.err.println("Please specify a output task config name!");
return;
}
String fileName = args[1];
File tasksFolder = new File("tasks");
if (!tasksFolder.exists())
if (!tasksFolder.mkdir()) System.err.println("Failed to create tasks folder!");
File taskFile = new File(tasksFolder, fileName + ".toml");
if (!taskFile.exists()) {
System.err.println("TaskFile " + fileName + ".toml does not exist!");
return;
}
Config taskConfig = new Config(taskFile);
TaskBuilder taskBuilder = TaskBuilder.builder().taskConfig(taskConfig).build();
taskBuilder.start();
break;
}
case "generatetaskconf":
{
if (args.length <= 1) {
System.err.println("Please specify a output task config name!");
return;
}
String fileName = args[1];
File tasksFolder = new File("tasks");
if (!tasksFolder.exists())
if (!tasksFolder.mkdir()) System.err.println("Failed to create tasks folder!");
System.out.println("Saving task config " + fileName + ".toml...");
FileUtils.copyInputStreamToFile(
Objects.requireNonNull(App.class.getResourceAsStream("/" + "exampletask.toml")),
new File(tasksFolder, fileName + ".toml"));
System.out.println(fileName + ".toml saved!");
break;
}
case "checktaskconf":
{
if (args.length <= 1) {
System.err.println("Please specify a output task config name!");
return;
}
String fileName = args[1];
File tasksFolder = new File("tasks");
if (!tasksFolder.exists())
if (!tasksFolder.mkdir()) System.err.println("Failed to create tasks folder!");
File taskFile = new File(tasksFolder, fileName + ".toml");
if (!taskFile.exists()) {
System.err.println("TaskFile " + fileName + ".toml does not exist!");
return;
}
TomlParseResult toml;
try {
toml = Toml.parse(taskFile.toPath());
} catch (IOException e) {
System.err.println("failed to read TaskFile.");
throw new RuntimeException(e);
}
if (toml.hasErrors()) {
System.err.printf(
"TaskFile checked: found %d issues!:\n", (long) toml.errors().size());
toml.errors().forEach(error -> System.err.println(error.toString()));
} else {
System.out.println("TaskFile checked successfully: no issues found!");
}
break;
}
default:
if (index == 0) {
usage();
return;
}
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}

View File

@@ -0,0 +1,79 @@
package net.horizoncode.sysbackup.config;
import lombok.AccessLevel;
import lombok.Getter;
import net.horizoncode.sysbackup.App;
import org.apache.commons.io.FileUtils;
import org.tomlj.Toml;
import org.tomlj.TomlArray;
import org.tomlj.TomlParseResult;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
@Getter
public class Config {
private final File configFile;
private TomlParseResult toml;
private boolean justCreated;
public Config(File configFile) {
this.configFile = configFile;
if (!configFile.exists()) {
try {
FileUtils.copyInputStreamToFile(
Objects.requireNonNull(App.class.getResourceAsStream("/" + configFile.getName())),
configFile);
justCreated = true;
} catch (IOException e) {
e.printStackTrace();
}
} else {
if (configFile.isDirectory()) {
try {
FileUtils.copyInputStreamToFile(
Objects.requireNonNull(App.class.getResourceAsStream("/" + configFile.getName())),
configFile);
justCreated = true;
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (justCreated) return;
try {
toml = Toml.parse(configFile.toPath());
if (toml.hasErrors()) {
toml.errors().forEach(error -> System.err.println(error.toString()));
System.exit(-1);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public int getIntOrDefault(String key, int defaultValue) {
return getToml().contains(key) && getToml().get(key) instanceof Number
? Math.toIntExact((long) getToml().get(key))
: defaultValue;
}
public boolean getBooleanOrDefault(String key, boolean defaultValue) {
return getToml().contains(key) && getToml().get(key) instanceof Boolean
? getToml().getBoolean(key)
: defaultValue;
}
public String getStringOrDefault(String key, String defaultValue) {
return getToml().contains(key) ? getToml().getString(key) : defaultValue;
}
public TomlArray getArray(String key) {
return getToml().getArrayOrEmpty(key);
}
}

View File

@@ -0,0 +1,7 @@
package net.horizoncode.sysbackup.tasks;
public class Task {
public void start() {}
public void onDone() {}
}

View File

@@ -0,0 +1,72 @@
package net.horizoncode.sysbackup.tasks;
import lombok.Builder;
import lombok.Getter;
import net.horizoncode.sysbackup.config.Config;
import net.horizoncode.sysbackup.tasks.impl.FileSystemTask;
import org.apache.commons.io.FilenameUtils;
import org.tomlj.TomlArray;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.IntStream;
@Builder
@Getter
public class TaskBuilder {
private final Config taskConfig;
@Builder.Default private final LinkedBlockingQueue<Task> taskList = new LinkedBlockingQueue<>();
public void start() {
File backupDir = new File("backups");
if (!backupDir.exists())
if (!backupDir.mkdir()) {
System.err.println("Failed to create backups directory!");
System.exit(2);
}
SimpleDateFormat sdf =
new SimpleDateFormat(
getTaskConfig().getStringOrDefault("general.dateFormat", "yyyy-MM-dd HH-mm-ss"));
String fileName =
getTaskConfig().getStringOrDefault("filesystem.fileName", "{date} {taskName}") + ".zip";
fileName =
fileName
.replace(
"{taskName}",
FilenameUtils.removeExtension(getTaskConfig().getConfigFile().getName()))
.replace("{date}", sdf.format(new Date()));
File outputFile = new File(backupDir, fileName);
if (getTaskConfig().getToml().contains("filesystem.targets")) {
TomlArray filesArray = getTaskConfig().getArray("filesystem.targets");
IntStream.range(0, filesArray.size())
.forEach(
value -> {
String target = filesArray.getString(value);
taskList.add(
new FileSystemTask(target, outputFile) {
@Override
public void onDone() {
executeNextTask();
}
});
});
}
executeNextTask();
}
private void executeNextTask() {
Task nextTask = taskList.poll();
if (nextTask != null) nextTask.start();
}
}

View File

@@ -0,0 +1,68 @@
package net.horizoncode.sysbackup.tasks.impl;
import me.tongfei.progressbar.ProgressBar;
import me.tongfei.progressbar.ProgressBarBuilder;
import me.tongfei.progressbar.ProgressBarStyle;
import net.horizoncode.sysbackup.tasks.Task;
import net.horizoncode.sysbackup.threading.ThreadPool;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.progress.ProgressMonitor;
import java.io.File;
import java.nio.file.Paths;
public class FileSystemTask extends Task {
private final File target;
private File outputZipFile;
private final ThreadPool threadPool;
public FileSystemTask(String folderOrFilePath, File outputZipFile) {
this.threadPool = new ThreadPool(3, 10);
this.target = Paths.get(folderOrFilePath).toFile();
if (!target.exists()) {
onDone();
System.err.println("File or folder named \"" + folderOrFilePath + "\" does not exist.");
System.exit(2);
return;
}
this.outputZipFile = outputZipFile;
}
@Override
public void start() {
threadPool
.getPool()
.submit(
() -> {
try (ZipFile zipFile = new ZipFile(outputZipFile)) {
System.out.println("Indexing files...");
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
zipFile.setRunInThread(true);
zipFile.addFolder(target);
ProgressBarBuilder pbb =
new ProgressBarBuilder()
.setStyle(ProgressBarStyle.ASCII)
.setInitialMax(progressMonitor.getTotalWork())
.setTaskName("Adding Files...");
try (ProgressBar pb = pbb.build()) {
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
pb.stepTo(progressMonitor.getWorkCompleted());
Thread.sleep(1);
}
pb.stepTo(progressMonitor.getTotalWork());
} catch (Exception exception) {
exception.printStackTrace();
onDone();
}
progressMonitor.endProgressMonitor();
onDone();
} catch (Exception ex) {
ex.printStackTrace();
onDone();
}
});
}
}

View File

@@ -0,0 +1,23 @@
package net.horizoncode.sysbackup.threading;
import lombok.Getter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
public class ThreadPool {
@Getter private final ExecutorService pool;
public ThreadPool(int corePoolSize, int maxPoolSize) {
this.pool = scheduledExecutorService(corePoolSize, maxPoolSize);
}
private ScheduledExecutorService scheduledExecutorService(int corePoolSize, int maxPoolSize) {
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =
new ScheduledThreadPoolExecutor(corePoolSize);
scheduledThreadPoolExecutor.setMaximumPoolSize(maxPoolSize);
return scheduledThreadPoolExecutor;
}
}

View File

@@ -0,0 +1,16 @@
[general]
dateFormat = "yyyy-MM-dd"
[mysql]
enabled = true
host = ""
port = 3306
database = "magento"
user = ""
password = ""
fileName = "{date} - {taskName}"
[filesystem]
targets = ["/home/magento/", "/home/test/test.ini"]
fileName = "{date} - {taskName}"

View File

@@ -0,0 +1,29 @@
package net.horizoncode.sysbackup;
import net.horizoncode.sysbackup.config.Config;
import org.junit.Test;
import org.tomlj.TomlArray;
import java.io.File;
import java.util.stream.IntStream;
public class TOMLArrayIterationTest {
@Test
public void testTOMLIteration() {
File tasksFolder = new File("tasks");
if (!tasksFolder.exists())
if (!tasksFolder.mkdir()) System.err.println("Failed to create tasks folder!");
Config config = new Config(new File(tasksFolder, "magento.toml"));
if (config.getToml().contains("filesystem.targets")) {
TomlArray filesArray = config.getArray("filesystem.targets");
IntStream.range(0, filesArray.size())
.forEach(
value -> {
String target = filesArray.getString(value);
System.out.println(target);
});
}
}
}