001/*
002 * Syncany, www.syncany.org
003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package org.syncany.cli;
019
020import java.io.File;
021import java.io.PrintStream;
022
023import org.syncany.cli.util.CarriageReturnPrinter;
024import org.syncany.config.Config;
025import org.syncany.config.LocalEventBus;
026import org.syncany.operations.OperationOptions;
027import org.syncany.operations.OperationResult;
028
029/**
030 * Commands are the central part of Syncany's command line client. Each implementation 
031 * of this abstract class represents a command that a user can run on the command line.
032 * 
033 * <p>The purpose of a command is to read required and optional arguments from the command
034 * line, run the corresponding operation, and display the results on the console.
035 * Implementations are not supposed to actually run any detailed logic, but are merely
036 * the user interface to collection options and print operation output. 
037 * 
038 * <p>Implementations must implement the {@link #execute(String[]) execute()} method and
039 * the {@link #getRequiredCommandScope()} method. While the former actually implements
040 * the logic, the latter specifies whether a command must be called inside (or outside) a 
041 * local Syncany directory. 
042 * 
043 * <p>Commands are automatically mapped from their camel case name on the command line
044 * to a class name using the {@link CommandFactory}. The command 'ls-remote', for instance,
045 * is mapped to the <code>LsRemoteCommand</code>.
046 *  
047 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
048 */
049public abstract class Command {
050        protected Config config;
051        protected File localDir;
052        protected CarriageReturnPrinter out;
053
054        protected LocalEventBus eventBus;
055        
056        public Command() {
057                this.eventBus = LocalEventBus.getInstance();
058                this.eventBus.register(this);
059        }
060        
061        /**
062         * This method implements the command-specific option-parsing, operation calling 
063         * and output printing. To do so, the method must read and evaluate the given 
064         * arguments, prepare a corresponding operation, call it and display the results
065         * according to a well-defined format.
066         * 
067         * <p>Implementations should not move any business logic in the execute method
068         * (or any other parts of the command).  
069         * 
070         * @param operationArgs Command-specific arguments (might also contain global options) 
071         * @return Returns a return code
072         * @throws Exception If the command or the corresponding operation fails 
073         */
074        public abstract int execute(String[] operationArgs) throws Exception;
075
076        /**
077         * A command can either be executed within an initialized local directory or 
078         * in a regular (non-Syncany) directory. Syncany determines this by searching for
079         * a .syncany folder.
080         * 
081         * <p>The required command scope resembles whether or not a command must be executed 
082         * inside a .syncany directory or not -- or whether it does not matter.
083         *  
084         * @return Returns the required command scope of the command 
085         */
086        public abstract CommandScope getRequiredCommandScope();
087
088        /**
089         * Returns whether a command can be run inside the scope of the daemon. 
090         * 
091         * <p>If a folder is daemon-managed, the command line client passes the command
092         * to the daemon via REST and the daemon executes this command/operation. For some
093         * commands, this does not make sense or is dangerous. This method allows certain
094         * commands to be daemon-enabled, and other to be daemon-disabled.
095         */
096        public abstract boolean canExecuteInDaemonScope();
097
098        /**
099         * A command can typically be configured using command line options. This method
100         * parses these command line options and returns an {@link OperationOptions} object
101         * representing the options.
102         */
103        public abstract OperationOptions parseOptions(String[] operationArgs) throws Exception;
104        
105        /**
106         * A command typically prints a result to the console. This method takes an
107         * {@link OperationResult} object and formats it to be human-readable.
108         */
109        public abstract void printResults(OperationResult result);
110                
111        public void setLocalDir(File localDir) {
112                this.localDir = localDir;
113        }
114
115        public Config getConfig() {
116                return config;
117        }
118
119        public void setConfig(Config config) {
120                this.config = config;
121        }
122
123        public void setOut(PrintStream out) {
124                this.out = new CarriageReturnPrinter(out);
125        }
126        
127        public void setOut(CarriageReturnPrinter out) {
128                this.out = out;
129        }
130}