Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add work dir backup options #1494

Merged
merged 4 commits into from
Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@

import io.swagger.annotations.ApiOperation;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
Expand Down Expand Up @@ -81,8 +85,19 @@ public BackupDTO getMarkdownBackup(@RequestParam("filename") String filename) {
@PostMapping("work-dir")
@ApiOperation("Backups work directory")
@DisableOnCondition
public BackupDTO backupHalo() {
return backupService.backupWorkDirectory();
public BackupDTO backupHalo(@RequestBody List<String> options) {
return backupService.backupWorkDirectory(options);
}

@GetMapping("work-dir/options")
@ApiOperation("Gets items that can be backed up")
public List<String> listBackupItems() throws IOException {
return Files.list(Paths.get(haloProperties.getWorkDir()))
.map(Path::getFileName)
.filter(Objects::nonNull)
.map(Path::toString)
.sorted()
.collect(Collectors.toList());
}

@GetMapping("work-dir")
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/run/halo/app/service/BackupService.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ public interface BackupService {
/**
* Zips work directory.
*
* @param options file or directory items to back up
* @return backup dto.
*/
@NonNull
BackupDTO backupWorkDirectory();

BackupDTO backupWorkDirectory(List<String> options);

/**
* Lists all backups.
Expand Down
19 changes: 17 additions & 2 deletions src/main/java/run/halo/app/service/impl/BackupServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import run.halo.app.config.properties.HaloProperties;
import run.halo.app.event.options.OptionUpdatedEvent;
import run.halo.app.event.theme.ThemeUpdatedEvent;
import run.halo.app.exception.BadRequestException;
import run.halo.app.exception.NotFoundException;
import run.halo.app.exception.ServiceException;
import run.halo.app.handler.file.FileHandler;
Expand Down Expand Up @@ -213,7 +215,10 @@ public BasePostDetailDTO importMarkdown(MultipartFile file) throws IOException {
}

@Override
public BackupDTO backupWorkDirectory() {
public BackupDTO backupWorkDirectory(List<String> options) {
if (CollectionUtils.isEmpty(options)) {
throw new BadRequestException("The options parameter is missing, at least one.");
}
// Zip work directory to temporary file
try {
// Create zip path for halo zip
Expand All @@ -229,7 +234,17 @@ public BackupDTO backupWorkDirectory() {

// Zip halo
run.halo.app.utils.FileUtils
.zip(Paths.get(this.haloProperties.getWorkDir()), haloZipPath);
.zip(Paths.get(this.haloProperties.getWorkDir()), haloZipPath,
path -> {
for (String itemToBackup : options) {
Path backupItemPath =
Paths.get(this.haloProperties.getWorkDir()).resolve(itemToBackup);
if (path.startsWith(backupItemPath)) {
return true;
}
}
return false;
});

// Build backup dto
return buildBackupDto(BACKUP_RESOURCE_BASE_URI, haloZipPath);
Expand Down
51 changes: 49 additions & 2 deletions src/main/java/run/halo/app/utils/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ public static void zip(@NonNull Path pathToZip, @NonNull Path pathOfArchive)
}
}

/**
* Zips folder or file with filter.
*
* @param pathToZip file path to zip must not be null
* @param pathOfArchive zip file path to archive must not be null
* @param filter folder or file filter
* @throws IOException throws when failed to access file to be zipped
*/
public static void zip(@NonNull Path pathToZip, @NonNull Path pathOfArchive,
@Nullable Predicate<Path> filter) throws IOException {
try (OutputStream outputStream = Files.newOutputStream(pathOfArchive)) {
try (ZipOutputStream zipOut = new ZipOutputStream(outputStream)) {
zip(pathToZip, zipOut, filter);
}
}
}

/**
* Zips folder or file.
*
Expand All @@ -198,6 +215,20 @@ public static void zip(@NonNull Path pathToZip, @NonNull ZipOutputStream zipOut)
zip(pathToZip, pathToZip.getFileName().toString(), zipOut);
}

/**
* Zips folder or file with filter.
*
* @param pathToZip file path to zip must not be null
* @param zipOut zip output stream must not be null
* @param filter directory or file filter
* @throws IOException throws when failed to access file to be zipped
*/
public static void zip(@NonNull Path pathToZip, @NonNull ZipOutputStream zipOut,
Predicate<Path> filter) throws IOException {
// Zip file
zip(pathToZip, pathToZip.getFileName().toString(), zipOut, filter);
}

/**
* Zips folder or file.
*
Expand All @@ -208,6 +239,20 @@ public static void zip(@NonNull Path pathToZip, @NonNull ZipOutputStream zipOut)
*/
private static void zip(@NonNull Path fileToZip, @NonNull String fileName,
@NonNull ZipOutputStream zipOut) throws IOException {
zip(fileToZip, fileName, zipOut, null);
}

/**
* Zips folder or file with path filter.
*
* @param fileToZip file path to zip must not be null
* @param fileName file name must not be blank
* @param zipOut zip output stream must not be null
* @param filter directory or file filter
* @throws IOException throws when failed to access file to be zipped
*/
private static void zip(@NonNull Path fileToZip, @NonNull String fileName,
@NonNull ZipOutputStream zipOut, @Nullable Predicate<Path> filter) throws IOException {
if (Files.isDirectory(fileToZip)) {
log.debug("Try to zip folder: [{}]", fileToZip);
// Append with '/' if missing
Expand All @@ -222,10 +267,12 @@ private static void zip(@NonNull Path fileToZip, @NonNull String fileName,
try (Stream<Path> subPathStream = Files.list(fileToZip)) {
// There should not use foreach for stream as internal zip method will throw
// IOException
List<Path> subFiles = subPathStream.collect(Collectors.toList());
List<Path> subFiles =
filter != null ? subPathStream.filter(filter).collect(Collectors.toList())
: subPathStream.collect(Collectors.toList());
for (Path subFileToZip : subFiles) {
// Zip children
zip(subFileToZip, folderName + subFileToZip.getFileName(), zipOut);
zip(subFileToZip, folderName + subFileToZip.getFileName(), zipOut, filter);
}
}
} else {
Expand Down