Skip to content

Commit

Permalink
feat: Add restore feature (#113)
Browse files Browse the repository at this point in the history
* change logic in BackupUtils

* add restore method
  • Loading branch information
hizumiaoba authored Sep 30, 2024
1 parent a510027 commit e12e7ed
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import java.util.stream.Stream;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
Expand Down Expand Up @@ -207,4 +209,40 @@ private void onCopyDirectoryButtonClicked() {
}
}, this::onErrorFindingDir);
}

public void onRestoreWorldButtonClicked(ActionEvent actionEvent) throws IOException {
String selectedWorld = backupFolderListView.getSelectionModel().getSelectedItem();
Path selectedWorldPath = MainController.backupUtils.getBackupDirPaths().stream()
.filter(p -> p.getFileName().toString().equals(selectedWorld))
.findFirst()
.orElseThrow();
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("ワールドの復元");
alert.setHeaderText("ワールド:" + selectedWorld + "を復元しますか?");
alert.setContentText("この操作は元に戻せません。バックアップフォルダは削除されません。");
alert.getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL);
alert.initModality(Modality.APPLICATION_MODAL);
alert.showAndWait().ifPresent(response -> {
if (response == ButtonType.OK) {
try {
MainController.backupUtils.restoreBackup(selectedWorldPath);
Alert info = new Alert(Alert.AlertType.INFORMATION);
info.setTitle("ワールドの復元");
info.setHeaderText("ワールドの復元が完了しました");
info.setContentText("ワールド:" + selectedWorld + "を復元しました。");
info.initModality(Modality.APPLICATION_MODAL);
info.showAndWait();
} catch (IOException e) {
log.error("Failed to restore world", e);
ExceptionPopup p = new ExceptionPopup(e, "ワールドの復元に失敗しました",
"BackupManagerController#onRestoreWorldButtonClicked");
p.pop();
}
} else if (response == ButtonType.CANCEL) {
log.info("Cancelled restoring world");
} else {
log.warn("Neither OK nor CANCEL button clicked");
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ void initialize() {
Tooltip backupOnQuitTooltip = new Tooltip("ランチャーをここから起動した際、Minecraft終了を自動で検知してバックアップを作成します。");
backupOnQuitTooltip.setStyle("-fx-font-size: 12px;");
enableAutoBackupOnQuittingGamesChkbox.setTooltip(backupOnQuitTooltip);
backupUtils = new BackupUtils(backupSavingFolderPathField.getText());
backupUtils = new BackupUtils(backupSavingFolderPathField.getText(), savesFolderPathField.getText());
}

private void checkPath() {
Expand All @@ -222,8 +222,7 @@ void onBackupNowBtnClick() {
checkPath();
backupUtils.createBackupDir();
try {
backupUtils.backup(Paths.get(
savesFolderPathField.getText()),
backupUtils.backup(
false,
backupCountSpinner.getValue());
} catch (IOException e) {
Expand Down Expand Up @@ -452,7 +451,6 @@ void onSpecialBackupNowBtnClick() {
log.info("Starting special backup...");
try {
backupUtils.backup(
Paths.get(savesFolderPathField.getText()),
true,
backupCountSpinner.getValue());
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class BackupUtils {

private static final SimpleDateFormat dirNameFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
private Path backupPath;
private Path savesDirPath;

public BackupUtils(String backupPath) {
this(Paths.get(backupPath));
Expand All @@ -32,6 +33,15 @@ public BackupUtils(Path backupPath) {
this.backupPath = backupPath;
}

public BackupUtils(String backupPath, String savesDirPath) {
this(Paths.get(backupPath), Paths.get(savesDirPath));
}

public BackupUtils(Path backupPath, Path savesDirPath) {
this.backupPath = backupPath;
this.savesDirPath = savesDirPath;
}

public void setBackupPath(String backupPath) {
this.backupPath = Paths.get(backupPath);
}
Expand All @@ -42,7 +52,7 @@ public List<Path> getBackupDirPaths() throws IOException {
}
}

public void backup(Path savesDirPath, boolean isSpecial, long maxBackupCount) throws IOException {
public void backup(boolean isSpecial, long maxBackupCount) throws IOException {
if (!isSpecial && didReachMaxBackupCount(maxBackupCount)) {
log.info("Reached maximum backup count. Deleting the oldest backup...");
getOldestBackupDir().ifPresent(p -> {
Expand All @@ -54,10 +64,10 @@ public void backup(Path savesDirPath, boolean isSpecial, long maxBackupCount) th
}
});
}
createBackup(savesDirPath, isSpecial);
createBackup(isSpecial);
}

private void createBackup(Path savesDirPath, boolean isSpecial) throws IOException {
private void createBackup(boolean isSpecial) throws IOException {
log.info("Commencing backup...");
Path targetDir = this.backupPath.resolve(
String.format("%s%s", isSpecial ? "Sp_" : "", dirNameFormat.format(new Date())));
Expand Down Expand Up @@ -163,4 +173,30 @@ public void archive(Path targetDir) throws IOException {
}
}
}

public void restoreBackup(Path p) throws IOException {
// restore the backup directory `p` to the saves directory
// once delete all files in the saves directory, then copy all files in the backup directory to the saves directory
log.info("Commencing restoration...");
try (var stream = Files.walk(this.savesDirPath)) {
stream.forEach(path -> {
try {
this.deleteBackupRecursively(path);
} catch (IOException e) {
log.error("Failed to delete file: {}", path, e);
}
});
}
try (var stream = Files.walk(p)) {
stream.forEach(source -> {
Path target = this.savesDirPath.resolve(p.relativize(source));
try {
Files.createDirectories(target.getParent());
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
log.error("Failed to copy file: {}", source, e);
}
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<children>
<Button disable="true" mnemonicParsing="false" onAction="#onDeleteButtonClicked" text="削除" />
<Button disable="true" mnemonicParsing="false" onAction="#onCopyDirectoryButtonClicked" text="コピー" />
<Button disable="true" mnemonicParsing="false" text="復元" />
<Button mnemonicParsing="false" onAction="#onRestoreWorldButtonClicked" text="復元" />
<Button mnemonicParsing="false" onAction="#onCloseButtonClicked" text="閉じる" />
</children>
</HBox>
Expand Down

0 comments on commit e12e7ed

Please sign in to comment.