org.fim.Fim.java Source code

Java tutorial

Introduction

Here is the source code for org.fim.Fim.java

Source

/*
 * This file is part of Fim - File Integrity Manager
 *
 * Copyright (C) 2015  Etienne Vrignaud
 *
 * Fim 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.
 *
 * Fim 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 Fim.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.fim;

import static org.fim.model.HashMode.dontHash;
import static org.fim.model.HashMode.hashAll;
import static org.fim.model.HashMode.hashMediumBlock;
import static org.fim.model.HashMode.hashSmallBlock;

import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.fim.command.AbstractCommand;
import org.fim.command.CommitCommand;
import org.fim.command.DetectCorruptionCommand;
import org.fim.command.DiffCommand;
import org.fim.command.DisplayIgnoredFilesCommand;
import org.fim.command.FindDuplicatesCommand;
import org.fim.command.HelpCommand;
import org.fim.command.InitCommand;
import org.fim.command.LogCommand;
import org.fim.command.PurgeStatesCommand;
import org.fim.command.RemoveDuplicatesCommand;
import org.fim.command.ResetFileAttributesCommand;
import org.fim.command.RollbackCommand;
import org.fim.command.VersionCommand;
import org.fim.command.exception.BadFimUsageException;
import org.fim.command.exception.DontWantToContinueException;
import org.fim.command.exception.RepositoryCreationException;
import org.fim.model.Command;
import org.fim.model.Command.FimReposConstraint;
import org.fim.model.Context;
import org.fim.util.Console;
import org.fim.util.Logger;

public class Fim {
    private List<AbstractCommand> commands = buildCommands();
    private Options options = buildOptions();

    public static void main(String[] args) throws Exception {
        try {
            Fim fim = new Fim();
            Context context = new Context();
            fim.run(args, context);
        } catch (DontWantToContinueException ex) {
            System.exit(0);
        } catch (BadFimUsageException ex) {
            System.exit(-1);
        } catch (RepositoryCreationException ex) {
            System.exit(-2);
        }

        System.exit(0);
    }

    private List<AbstractCommand> buildCommands() {
        return Arrays.asList(new InitCommand(), new CommitCommand(), new DiffCommand(),
                new ResetFileAttributesCommand(), new DetectCorruptionCommand(), new FindDuplicatesCommand(),
                new RemoveDuplicatesCommand(this), new LogCommand(), new DisplayIgnoredFilesCommand(),
                new RollbackCommand(), new PurgeStatesCommand(), new HelpCommand(this), new VersionCommand());
    }

    private Options buildOptions() {
        Options options = new Options();
        options.addOption(createOption("e", "errors", false, "Display execution error details", false));
        options.addOption(createOption("m", "master-fim-repository", true,
                "Fim repository directory that you want to use as remote master.\nOnly for the remove duplicated files command",
                false));
        options.addOption(createOption("n", "do-not-hash", false,
                "Do not hash file content. Uses only file names and modification dates", false));
        options.addOption(createOption("s", "super-fast-mode", false,
                "Use super-fast mode. Hash only 3 small blocks.\nOne at the beginning, one in the middle and one at the end",
                false));
        options.addOption(createOption("f", "fast-mode", false,
                "Use fast mode. Hash only 3 medium blocks.\nOne at the beginning, one in the middle and one at the end",
                false));
        options.addOption(createOption("h", "help", false, "Prints the Fim help", false));
        options.addOption(createOption("l", "use-last-state", false,
                "Use the last committed State.\nOnly for the find local duplicated files command", false));
        options.addOption(createOption("c", "comment", true, "Comment to set during init and commit", false));
        options.addOption(createOption("q", "quiet", false, "Do not display details", false));
        options.addOption(createOption("t", "thread-count", true,
                "Number of thread used to hash file contents in parallel", false));
        options.addOption(createOption("v", "version", false, "Prints the Fim version", false));
        options.addOption(createOption("y", "always-yes", false, "Always yes to every questions", false));
        return options;
    }

    protected void run(String[] args, Context context) throws Exception {
        String[] filteredArgs = filterEmptyArgs(args);
        if (filteredArgs.length < 1) {
            youMustSpecifyACommandToRun();
        }

        Command command = null;
        String[] optionArgs = filteredArgs;
        String firstArg = filteredArgs[0];
        if (!firstArg.startsWith("-")) {
            optionArgs = Arrays.copyOfRange(filteredArgs, 1, filteredArgs.length);
            command = findCommand(firstArg);
        }

        CommandLineParser cmdLineGnuParser = new DefaultParser();

        try {
            CommandLine commandLine = cmdLineGnuParser.parse(options, optionArgs);

            context.setVerbose(!commandLine.hasOption('q'));
            context.setComment(commandLine.getOptionValue('c', context.getComment()));
            context.setUseLastState(commandLine.hasOption('l'));
            context.setMasterFimRepositoryDir(commandLine.getOptionValue('m'));
            context.setAlwaysYes(commandLine.hasOption('y'));
            context.setDisplayStackTrace(commandLine.hasOption('e'));

            if (commandLine.hasOption('t')) {
                context.setThreadCount(Integer.parseInt(commandLine.getOptionValue('t', "1")));
                context.setThreadCountSpecified(true);
            }

            if (commandLine.hasOption('n')) {
                context.setHashMode(dontHash);
            } else if (commandLine.hasOption('s')) {
                context.setHashMode(hashSmallBlock);
            } else if (commandLine.hasOption('f')) {
                context.setHashMode(hashMediumBlock);
            } else {
                context.setHashMode(hashAll);
            }

            if (commandLine.hasOption('h')) {
                command = new HelpCommand(this);
            } else if (commandLine.hasOption('v')) {
                command = new VersionCommand();
            }

        } catch (Exception ex) {
            Logger.error("Exception parsing command line", ex, context.isDisplayStackTrace());
            printUsage();
            throw new BadFimUsageException();
        }

        if (command == null) {
            youMustSpecifyACommandToRun();
        }

        FimReposConstraint constraint = command.getFimReposConstraint();
        if (constraint == FimReposConstraint.MUST_NOT_EXIST) {
            setRepositoryRootDir(context, context.getAbsoluteCurrentDirectory(), false);

            if (Files.exists(context.getRepositoryStatesDir())) {
                Logger.error("Fim repository already exist");
                throw new BadFimUsageException();
            }
        } else if (constraint == FimReposConstraint.MUST_EXIST) {
            findRepositoryRootDir(context);

            if (!Files.exists(context.getRepositoryStatesDir())) {
                Logger.error("Fim repository does not exist. Please run 'fim init' before.");
                throw new BadFimUsageException();
            }
        }

        command.execute(context.clone());
    }

    private void findRepositoryRootDir(Context context) {
        boolean invokedFromSubDirectory = false;
        Path directory = context.getAbsoluteCurrentDirectory();
        while (directory != null) {
            Path dotFimDir = directory.resolve(Context.DOT_FIM_DIR);
            if (Files.exists(dotFimDir)) {
                setRepositoryRootDir(context, directory, invokedFromSubDirectory);
                return;
            }

            directory = directory.getParent();
            invokedFromSubDirectory = true;
        }
    }

    private void setRepositoryRootDir(Context context, Path directory, boolean invokedFromSubDirectory) {
        context.setRepositoryRootDir(directory);
        context.setInvokedFromSubDirectory(invokedFromSubDirectory);
    }

    private Command findCommand(final String cmdName) {
        for (final Command command : commands) {
            if (command.getCmdName().equals(cmdName)) {
                return command;
            }

            if (command.getShortCmdName().length() > 0 && command.getShortCmdName().equals(cmdName)) {
                return command;
            }
        }
        return null;
    }

    private Option createOption(String opt, String longOpt, boolean hasArg, String description, boolean required) {
        Option option = new Option(opt, longOpt, hasArg, description);
        option.setRequired(required);
        return option;
    }

    private String[] filterEmptyArgs(String[] args) {
        List<String> filteredArgs = new ArrayList<>();
        for (String arg : args) {
            if (arg.length() > 0) {
                filteredArgs.add(arg);
            }
        }
        return filteredArgs.toArray(new String[0]);
    }

    private void youMustSpecifyACommandToRun() {
        Logger.error("You must specify the command to run");
        printUsage();
        throw new BadFimUsageException();
    }

    public void printUsage() {
        StringBuilder usage = new StringBuilder();
        usage.append("\n");
        usage.append("File Integrity Checker\n");
        usage.append("\n");
        usage.append("Available commands:\n");
        for (final Command command : commands) {
            String cmdName;
            if (command.getShortCmdName() != null && command.getShortCmdName().length() > 0) {
                cmdName = command.getShortCmdName() + " / " + command.getCmdName();
            } else {
                cmdName = command.getCmdName();
            }
            usage.append(String.format("     %-26s %s\n", cmdName, command.getDescription()));
        }

        usage.append("\n");
        usage.append("Available options:\n");

        PrintWriter writer = new PrintWriter(System.out);
        HelpFormatter helpFormatter = new HelpFormatter();

        Console.newLine();
        helpFormatter.printHelp(writer, 120, "fim <command>", usage.toString(), options, 5, 3, "", true);
        writer.flush();
        Console.newLine();
    }
}