All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.nagyesta.filebarj.job.cli.CliRestoreParser Maven / Gradle / Ivy

package com.github.nagyesta.filebarj.job.cli;

import com.github.nagyesta.filebarj.core.common.PermissionComparisonStrategy;
import com.github.nagyesta.filebarj.core.model.BackupPath;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

import java.io.Console;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Optional;

/**
 * Parser class for the command line arguments of the restore task.
 */
@Slf4j
public class CliRestoreParser extends CliICommonBackupFileParser {

    private static final String THREADS = "threads";
    private static final String DRY_RUN = "dry-run";
    private static final String TARGET = "target-mapping";
    private static final String DELETE_MISSING = "delete-missing";
    private static final String AT_EPOCH_SECONDS = "at-epoch-seconds";
    private static final String INCLUDED_PATH = "include-path";
    private static final String PERMISSION_COMPARISON = "permission-comparison";

    /**
     * Creates a new {@link CliRestoreParser} instance and sets the input arguments.
     *
     * @param args    the command line arguments
     * @param console the console we should use for password input
     */
    public CliRestoreParser(final String[] args, final Console console) {
        super(Task.RESTORE, args, commandLine -> {
            final var threads = Integer.parseInt(commandLine.getOptionValue(THREADS, "1"));
            final var dryRun = Boolean.parseBoolean(commandLine.getOptionValue(DRY_RUN, "false"));
            final var deleteMissing = Boolean.parseBoolean(commandLine.getOptionValue(DELETE_MISSING, "false"));
            final var backupSource = Path.of(commandLine.getOptionValue(BACKUP_SOURCE)).toAbsolutePath();
            final var prefix = commandLine.getOptionValue(PREFIX);
            final var nowEpochSeconds = Instant.now().getEpochSecond() + "";
            final var atPointInTime = Long.parseLong(commandLine.getOptionValue(AT_EPOCH_SECONDS, nowEpochSeconds));
            final var includedPath = Optional.ofNullable(commandLine.getOptionValue(INCLUDED_PATH))
                    .map(BackupPath::ofPathAsIs)
                    .orElse(null);
            final var permissionComparison = PermissionComparisonStrategy
                    .valueOf(commandLine.getOptionValue(PERMISSION_COMPARISON, PermissionComparisonStrategy.STRICT.name()));
            final var targets = new HashMap();
            if (commandLine.hasOption(TARGET)) {
                final var mappings = commandLine.getOptionValues(TARGET);
                final var invalid = Arrays.stream(mappings).filter(m -> !m.matches("^[^=]+=[^=]+$"))
                        .toList();
                if (!invalid.isEmpty()) {
                    log.error("Invalid target mappings: \n    {}", String.join("\n    ", invalid));
                    throw new IllegalArgumentException("Invalid target mappings found.");
                }
                Arrays.stream(mappings)
                        .map(s -> s.split("="))
                        .forEach(s -> targets.put(BackupPath.ofPathAsIs(s[0]), Path.of(s[1]).toAbsolutePath()));
            }
            final var keyProperties = parseKeyProperties(console, commandLine);
            return RestoreProperties.builder()
                    .threads(threads)
                    .dryRun(dryRun)
                    .deleteFilesNotInBackup(deleteMissing)
                    .backupSource(backupSource)
                    .keyProperties(keyProperties)
                    .prefix(prefix)
                    .targets(targets)
                    .pointInTimeEpochSeconds(atPointInTime)
                    .includedPath(includedPath)
                    .permissionComparisonStrategy(permissionComparison)
                    .build();
        });
    }

    @Override
    protected Options createOptions() {
        return super.createOptions()
                .addOption(Option.builder()
                        .longOpt(THREADS)
                        .hasArg(true)
                        .numberOfArgs(1)
                        .argName("thread_number")
                        .type(Integer.class)
                        .desc("Sets the number of threads to use. Default: 1").build())
                .addOption(Option.builder()
                        .longOpt(DRY_RUN)
                        .numberOfArgs(1)
                        .argName("boolean")
                        .type(Boolean.class)
                        .desc("Only simulates file operations if provided.").build())
                .addOption(Option.builder()
                        .longOpt(DELETE_MISSING)
                        .numberOfArgs(1)
                        .argName("boolean")
                        .type(Boolean.class)
                        .desc("Allow deleting the files from the target directory that are matching the backup source patterns "
                                + "but are not present in the backup increment.").build())
                .addOption(Option.builder()
                        .longOpt(TARGET)
                        .hasArgs()
                        .type(String.class)
                        .argName("from_dir=to_dir")
                        .desc("Defines where the files should be restored to by defining mappings that can specify which from_dir"
                                + " of the backup source should be restored to which to_dir (as if the two were equivalent). Optional.")
                        .build())
                .addOption(Option.builder()
                        .longOpt(AT_EPOCH_SECONDS)
                        .numberOfArgs(1)
                        .argName("epoch_seconds")
                        .required(false)
                        .type(Long.class)
                        .desc("The date and time using UTC epoch seconds at which the content should be restored.")
                        .build())
                .addOption(Option.builder()
                        .longOpt(INCLUDED_PATH)
                        .numberOfArgs(1)
                        .argName("path_from_backup")
                        .required(false)
                        .type(Path.class)
                        .desc("Path of the file or directory which should be restored from the backup. Optional. If not provided,"
                                + " all files should be restored.")
                        .build())
                .addOption(Option.builder()
                        .longOpt(PERMISSION_COMPARISON)
                        .numberOfArgs(1)
                        .argName("strategy")
                        .required(false)
                        .type(PermissionComparisonStrategy.class)
                        .desc("The strategy we should use when comparing permissions. "
                                + "Possible values are STRICT, PERMISSION_ONLY, RELAXED, IGNORE. Optional. Default: STRICT")
                        .build());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy