org.discosync.ApplySyncPack.java Source code

Java tutorial

Introduction

Here is the source code for org.discosync.ApplySyncPack.java

Source

/*
 * This file is part of DiscoSync (home: github.com, leitwolf7/discosync)
 *
 * Copyright (C) 2015, 2015 leitwolf7
 *
 *  DiscoSync 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, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  DiscoSync 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 DiscoSync.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.discosync;

import java.io.*;
import java.nio.file.*;
import java.sql.SQLException;
import java.util.*;

import org.apache.commons.cli.CommandLine;
import org.discosync.data.*;

public class ApplySyncPack implements IInvokable {

    @Override
    public boolean invoke(CommandLine cmd) throws SQLException, IOException {

        boolean retval = true;

        // apply <syncpack> to <basedir>
        if (!cmd.hasOption("syncpack")) {
            System.out.println("Syntax error: Command applysyncpack requires option syncpack.");
            retval = false;
        }
        if (!cmd.hasOption("basedir")) {
            System.out.println("Syntax error: Command applysyncpack requires option basedir.");
            retval = false;
        }

        if (!retval) {
            return false;
        }

        String syncPackDir = cmd.getOptionValue("syncpack");
        String targetDir = cmd.getOptionValue("basedir");

        System.out.println("Apply syncpack '" + syncPackDir + "' to directory '" + targetDir + "'.");

        System.out.println("Applying syncpack ...");
        applySyncPack(syncPackDir, targetDir);

        return true;
    }

    /**
     * Apply a syncpack to a target directory.
     */
    protected void applySyncPack(String syncPackDir, String targetDir) throws SQLException, IOException {

        // read file operations from database
        File fileOpDbFile = new File(syncPackDir, "fileoperations");
        FileOperationDatabase db = new FileOperationDatabase(fileOpDbFile.getAbsolutePath());
        db.open();

        Iterator<FileListEntry> it = db.getFileListOperationIterator();

        Path syncFileBaseDir = Paths.get(syncPackDir, "files");
        String syncFileBaseDirStr = syncFileBaseDir.toAbsolutePath().toString();

        int filesCopied = 0;
        int filesReplaced = 0;
        int filesDeleted = 0;
        long copySize = 0L;
        long deleteSize = 0L;

        // Collect directories during processing.
        List<FileListEntry> directoryOperations = new ArrayList<>();

        // First process all files, then the directories
        while (it.hasNext()) {

            FileListEntry e = it.next();

            // Remember directories
            if (e.isDirectory()) {
                directoryOperations.add(e);
                continue;
            }

            String path = e.getPath();
            Path sourcePath = Paths.get(syncFileBaseDirStr, path); // may not exist
            Path targetPath = Paths.get(targetDir, path); // may not exist

            if (e.getOperation() == FileOperations.COPY) {
                // copy new file, target files should not exist
                if (Files.exists(targetPath)) {
                    System.out
                            .println("Error: the file should not exist: " + targetPath.toAbsolutePath().toString());
                } else {
                    if (!Files.exists(targetPath.getParent())) {
                        Files.createDirectories(targetPath.getParent());
                    }

                    Files.copy(sourcePath, targetPath);
                    filesCopied++;
                    copySize += e.getSize();
                }

            } else if (e.getOperation() == FileOperations.REPLACE) {
                // replace existing file
                if (!Files.exists(targetPath)) {
                    System.out.println("Info: the file should exist: " + targetPath.toAbsolutePath().toString());
                }
                Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
                filesReplaced++;
                copySize += e.getSize();

            } else if (e.getOperation() == FileOperations.DELETE) {
                // delete existing file
                if (!Files.exists(targetPath)) {
                    System.out.println("Info: the file should exist: " + targetPath.toAbsolutePath().toString());
                } else {
                    long fileSize = Files.size(targetPath);
                    if (fileSize != e.getSize()) {
                        // show info, delete anyway
                        System.out.println(
                                "Info: the file size is different: " + targetPath.toAbsolutePath().toString());
                    }
                    deleteSize += fileSize;
                    Files.delete(targetPath);
                    filesDeleted++;
                }
            }
        }

        db.close();

        // Sort directory list to ensure directories are deleted bottom-up (first /dir1/dir2, then /dir1)
        Collections.sort(directoryOperations, new Comparator<FileListEntry>() {
            @Override
            public int compare(FileListEntry e1, FileListEntry e2) {
                return e2.getPath().compareTo(e1.getPath().toString());
            }
        });

        // Now process directories - create and delete empty directories
        for (FileListEntry e : directoryOperations) {

            String path = e.getPath();
            Path targetPath = Paths.get(targetDir, path); // may not exist

            if (e.getOperation() == FileOperations.COPY) {
                // create directory if needed
                if (!Files.exists(targetPath)) {
                    Files.createDirectories(targetPath);
                }
            } else if (e.getOperation() == FileOperations.DELETE) {

                if (!Files.exists(targetPath)) {
                    System.out.println(
                            "Info: Directory to DELETE does not exist: " + targetPath.toAbsolutePath().toString());

                } else if (!Files.isDirectory(targetPath, LinkOption.NOFOLLOW_LINKS)) {
                    System.out.println("Info: Directory to DELETE is not a directory, but a file: "
                            + targetPath.toAbsolutePath().toString());

                } else if (!Utils.isDirectoryEmpty(targetPath)) {
                    System.out.println("Info: Directory to DELETE is not empty, but should be empty: "
                            + targetPath.toAbsolutePath().toString());

                } else {
                    // delete directory
                    Files.delete(targetPath);
                }
            }
        }

        System.out.println("Apply of syncpack '" + syncPackDir + "' to directory '" + targetDir + "' finished.");
        System.out.println("Files copied  : " + String.format("%,d", filesCopied));
        System.out.println("Files replaced: " + String.format("%,d", filesReplaced));
        System.out.println("Files deleted : " + String.format("%,d", filesDeleted));
        System.out.println("Bytes copied  : " + String.format("%,d", copySize));
        System.out.println("Bytes deleted : " + String.format("%,d", deleteSize));
    }
}