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 static java.util.Arrays.asList;
021
022import java.util.List;
023import java.util.logging.Logger;
024
025import joptsimple.OptionParser;
026import joptsimple.OptionSet;
027import joptsimple.OptionSpec;
028
029import org.syncany.database.PartialFileHistory.FileHistoryId;
030import org.syncany.operations.OperationResult;
031import org.syncany.operations.restore.RestoreOperation;
032import org.syncany.operations.restore.RestoreOperationOptions;
033import org.syncany.operations.restore.RestoreOperationResult;
034
035public class RestoreCommand extends Command {
036        protected static final Logger logger = Logger.getLogger(RestoreCommand.class.getSimpleName());
037
038        @Override
039        public CommandScope getRequiredCommandScope() { 
040                return CommandScope.INITIALIZED_LOCALDIR;
041        }
042        
043        @Override
044        public boolean canExecuteInDaemonScope() {
045                return true;
046        }
047        
048        @Override
049        public int execute(String[] operationArgs) throws Exception {
050                RestoreOperationOptions operationOptions = parseOptions(operationArgs);
051                RestoreOperationResult operationResult = new RestoreOperation(config, operationOptions).execute();
052                
053                printResults(operationResult);
054                
055                return 0;               
056        }
057        
058        @Override
059        public RestoreOperationOptions parseOptions(String[] operationArgs) throws Exception {
060                RestoreOperationOptions operationOptions = new RestoreOperationOptions();
061
062                OptionParser parser = new OptionParser();       
063                parser.allowsUnrecognizedOptions();
064                
065                OptionSpec<Integer> optionRevision = parser.acceptsAll(asList("r", "revision")).withRequiredArg().ofType(Integer.class);
066                OptionSpec<String> optionTarget = parser.acceptsAll(asList("t", "target")).withRequiredArg().ofType(String.class);
067                
068                OptionSet options = parser.parse(operationArgs);        
069                
070                // --revision=<n>
071                if (options.has(optionRevision)) {
072                        operationOptions.setFileVersion(options.valueOf(optionRevision));
073                }
074                
075                // --target=<file>
076                if (options.has(optionTarget)) {
077                        operationOptions.setRelativeTargetPath(options.valueOf(optionTarget));
078                }
079                
080                // <file-history-id>
081                List<?> nonOptionArgs = options.nonOptionArguments();
082                
083                if (nonOptionArgs.size() != 1) {
084                        throw new Exception("Invalid Syntax: File history ID must be specified.");
085                }
086                                
087                FileHistoryId restoreFileHistory = FileHistoryId.parseFileId(nonOptionArgs.get(0).toString());
088                operationOptions.setFileHistoryId(restoreFileHistory);  
089                
090                return operationOptions;
091        }
092        
093        @Override
094        public void printResults(OperationResult operationResult) {
095                RestoreOperationResult concreteOperationResult = (RestoreOperationResult) operationResult;
096                
097                switch (concreteOperationResult.getResultCode()) {
098                case ACK:
099                        out.println("File restored to " + concreteOperationResult.getTargetFile());
100                        break;
101                        
102                case NACK_INVALID_FILE:
103                        out.println("Could not restore file. File entry is present but invalid (Folder?).");
104                        break;
105                        
106                case NACK_NO_FILE:
107                        out.println("Could not restore file. No file by that ID or version found, or file ID prefix matches more than one file.");
108                        break;
109                        
110                default:
111                        throw new RuntimeException("Invalid result code: " + concreteOperationResult.getResultCode());  
112                }
113        }
114}