/*
* JFileSync
* Copyright (C) 2002-2007, Jens Heidrich
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301, USA
*/
package jfs.shell;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.List;
import jfs.conf.JFSConfig;
import jfs.conf.JFSConst;
import jfs.conf.JFSLog;
import jfs.conf.JFSSettings;
import jfs.conf.JFSSyncModes;
import jfs.conf.JFSText;
import jfs.conf.JFSViewModes;
import jfs.sync.JFSComparison;
import jfs.sync.JFSCopyStatement;
import jfs.sync.JFSDeleteStatement;
import jfs.sync.JFSProgress;
import jfs.sync.JFSSynchronization;
import jfs.sync.JFSTable;
/**
* The JFS shell performs a command line comparison and synchronization. First
* of all the specified directory pair is compared. After that, you may enter
* different options via a shell-like environment or skip the shell and directly
* perform the synchronization depeding on the command line options.
*
* @author Jens Heidrich
* @version $Id: JFSShell.java,v 1.11 2007/02/26 18:49:11 heidrich Exp $
*/
public final class JFSShell {
private JFSShell() {
}
/**
* Reads a positive number out of a string of the following form: "[command]
* [number]"
*
* @param input
* The input string.
* @param min
* The minimum value of the parsed number.
* @param max
* The maximum value of the parsed number.
* @return The parsed number or '-1' if the parsing failed.
*/
public static int parseInt(String input, int min, int max) {
// Get translation object:
JFSText t = JFSText.getInstance();
String[] cmd = input.split(" ");
int number = -1;
if (cmd.length == 2) {
try {
number = Integer.parseInt(cmd[1]);
if ((number < min) || (number > max)) {
JFSLog.getErr().getStream().println(
t.get("error.validIndex") + " '" + number + "'.");
number = -1;
}
} catch (NumberFormatException e) {
JFSLog.getErr().getStream()
.println(t.get("error.numberFormat"));
}
} else {
JFSLog.getErr().getStream().println(t.get("error.inputNumber") + " '" + cmd.length + "'.");
}
return number;
}
/**
* Prints the content of URL to standard out.
*
* @param url
* The input url.
*/
public static void printURL(URL url) {
// Get translation object:
JFSText t = JFSText.getInstance();
InputStream stream;
int c;
try {
stream = url.openStream();
while ((c = stream.read()) != -1) {
JFSLog.getOut().getStream().print((char) c);
}
stream.close();
} catch (IOException e) {
JFSLog.getErr().getStream().println(
t.get("error.io") + " '" + url + "'.");
}
}
/**
* Starts the JFS command line shell in order to perform comparisons and
* synchronizations.
*
* @param quiet
* This option has to be true, if comparison and synchronization
* should run in background. It has to be false, if a shell
* prompt should appear.
*/
public static void startShell(boolean quiet) {
// Get translation object, configuration, output stream, and task:
JFSText t = JFSText.getInstance();
JFSConfig config = JFSConfig.getInstance();
PrintStream p = JFSLog.getOut().getStream();
JFSTable table = JFSTable.getInstance();
JFSComparison comparison = JFSComparison.getInstance();
JFSSynchronization synchronization = JFSSynchronization.getInstance();
// Start Command Line Processing:
JFSPrint.simplePrint();
p.println(t.get("cmd.init"));
p.println();
JFSProgress.getInstance().attach(new JFSProgressPrint());
// Set question oracle if not quiet:
if (!quiet) {
synchronization.getQuestion().setOracle(new JFSQuestionPrint());
}
p.println(t.get("cmd.startComp"));
p.println();
comparison.compare();
synchronization.computeSynchronizationLists();
if (!quiet) {
// Start the JFileSync Shell:
BufferedReader din = new BufferedReader(new InputStreamReader(
System.in));
p.println();
p.println(t.get("cmd.shell"));
p.println();
String input = "";
while (!"exit".equals(input) && !"sync".equals(input)) {
p.print("jfs>");
try {
input = din.readLine().toLowerCase();
if ("t".equals(input)) {
JFSPrint.printComparisonTable();
} else if ("c".equals(input)) {
JFSPrint.printCopyStatements(table.getCopyStatements());
} else if ("d".equals(input)) {
JFSPrint.printDeleteStatements(table
.getDeleteStatements());
} else if (input.startsWith("c ")) {
List<JFSCopyStatement> list = table.getCopyStatements();
int number = JFSShell.parseInt(input, 1, list.size());
if (number != -1) {
JFSCopyStatement cs = list.get(number - 1);
cs.setCopyFlag(!cs.getCopyFlag());
}
} else if (input.startsWith("d ")) {
List<JFSDeleteStatement> list = table.getDeleteStatements();
int number = JFSShell.parseInt(input, 1, list.size());
if (number != -1) {
JFSDeleteStatement ds = list.get(number - 1);
ds.setDeleteFlag(!ds.getDeleteFlag());
}
} else if (input.startsWith("view ")) {
int number = JFSShell.parseInt(input, 0,
Integer.MAX_VALUE);
// If the argument is a valid number then set a
// new view in the configuration object:
if (JFSViewModes.getInstance().contains(number)) {
config.setView((byte) number);
} else {
JFSLog.getErr().getStream().println(
t.get("error.numberFormat"));
}
} else if (input.startsWith("sync ")) {
int number = JFSShell.parseInt(input, 0,
Integer.MAX_VALUE);
// If the argument is a valid number then set the
// new mode in the configuration object and re-init
// the tables of files to copy and to delete
// appropriately:
JFSSyncModes modes = JFSSyncModes.getInstance();
if (modes.contains(number)) {
config.setSyncMode((byte) number);
JFSTable.getInstance().recomputeActionsAndView();
synchronization.computeSynchronizationLists();
} else {
JFSLog.getErr().getStream().println(t.get("error.numberFormat"));
}
} else if ("help".equals(input)) {
JFSShell.printURL(JFSConst.getInstance().getResourceUrl("jfs.help.topic.shell"));
} else if ("sync".equals(input)) {
synchronize();
} else if ("exit".equals(input)) {
// Just leave the loop.
} else if (input.length() > 0) {
JFSLog.getErr().getStream().println(t.get("error.validCommand"));
}
} catch (IOException e) {
// Thrown by readLine(). Continue in this case.
JFSLog.getErr().getStream().println(
t.get("error.inputRead"));
}
}
} else {
synchronize();
}
p.println();
p.println(t.get("cmd.exit"));
p.println();
// Store settings:
JFSSettings.getInstance().store();
}
/**
* Performs a command line synchronization.
*/
private static void synchronize() {
// Start synchronization:
PrintStream p = JFSLog.getOut().getStream();
JFSTable table = JFSTable.getInstance();
JFSSynchronization synchronization = JFSSynchronization.getInstance();
p.println();
p.println(JFSText.getInstance().get("cmd.startSync"));
p.println();
synchronization.synchronize();
// Print all failed copy and delete statements:
p.println();
JFSPrint.printFailedCopyStatements(table.getFailedCopyStatements());
JFSPrint.printFailedDeleteStatements(table.getFailedDeleteStatements());
}
}