From 32d6088d027af13352bf6a71c47bcd14505a743f Mon Sep 17 00:00:00 2001 From: Ovidiu Mircescu Date: Mon, 5 Feb 2018 17:50:54 +0100 Subject: [PATCH] Add rsync as a new protocol for copy. --- CMakeModules/libbatchMacros.cmake | 4 +- libbatch_config.h.in | 6 ++ src/Core/BatchManager.cxx | 9 +- src/Core/CMakeLists.txt | 4 + src/Core/CommunicationProtocol.cxx | 15 +++- src/Core/CommunicationProtocol.hxx | 2 +- src/Core/CommunicationProtocolRsync.cxx | 104 ++++++++++++++++++++++++ src/Core/CommunicationProtocolRsync.hxx | 59 ++++++++++++++ src/Core/Utils.cxx | 10 +++ src/Core/Utils.hxx | 11 +++ 10 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 src/Core/CommunicationProtocolRsync.cxx create mode 100644 src/Core/CommunicationProtocolRsync.hxx diff --git a/CMakeModules/libbatchMacros.cmake b/CMakeModules/libbatchMacros.cmake index 4d9846b..465782b 100644 --- a/CMakeModules/libbatchMacros.cmake +++ b/CMakeModules/libbatchMacros.cmake @@ -65,14 +65,16 @@ MACRO(LIBBATCH_FIND_ALL_LOCAL_COMMANDS) FIND_LOCAL_COMMAND(LIBBATCH_RCP_COMMAND rcp rcp) FIND_LOCAL_COMMAND(LIBBATCH_SSH_COMMAND ssh plink) FIND_LOCAL_COMMAND(LIBBATCH_SCP_COMMAND scp pscp) + FIND_LOCAL_COMMAND(LIBBATCH_RSYNC_COMMAND rsync pscp) EVAL (HAS_SH LIBBATCH_SH_COMMAND AND LIBBATCH_CP_COMMAND AND LIBBATCH_RM_COMMAND AND LIBBATCH_MKDIR_COMMAND) EVAL (HAS_RSH LIBBATCH_RSH_COMMAND AND LIBBATCH_RCP_COMMAND) EVAL (HAS_SSH LIBBATCH_SSH_COMMAND AND LIBBATCH_SCP_COMMAND) + EVAL (HAS_RSYNC LIBBATCH_SSH_COMMAND AND LIBBATCH_RSYNC_COMMAND) # Mark shell commands as advanced options # and assign the names without the LIBBATCH_ in front: - SET (_cmds "RM;SH;CP;MKDIR;RSH;RCP;SSH;SCP") + SET (_cmds "RM;SH;CP;MKDIR;RSH;RCP;SSH;SCP;RSYNC") FOREACH(_cmd ${_cmds}) MARK_AS_ADVANCED(LIBBATCH_${_cmd}_COMMAND) SET(${_cmd}_COMMAND ${LIBBATCH_${_cmd}_COMMAND}) diff --git a/libbatch_config.h.in b/libbatch_config.h.in index 67b60a1..941c00f 100644 --- a/libbatch_config.h.in +++ b/libbatch_config.h.in @@ -50,10 +50,16 @@ /* SSH tools (ssh, scp) found on the system */ #cmakedefine HAS_SSH +/* SSH tools and rsync found */ +#cmakedefine HAS_RSYNC + /* A path to a ssh-like command */ #cmakedefine SSH_COMMAND "@SSH_COMMAND@" /* A path to a scp-like command */ #cmakedefine SCP_COMMAND "@SCP_COMMAND@" +/* A path to a scp-like command */ +#cmakedefine RSYNC_COMMAND "@RSYNC_COMMAND@" + #endif diff --git a/src/Core/BatchManager.cxx b/src/Core/BatchManager.cxx index 047b1ed..5fdacf5 100644 --- a/src/Core/BatchManager.cxx +++ b/src/Core/BatchManager.cxx @@ -256,17 +256,14 @@ namespace Batch { CoupleType cpt = *static_cast< CoupleType * >(*Vit); Couple outputFile = cpt; string remotePath = outputFile.getRemote(); - if (!Utils::isAbsolutePath(remotePath)) { - remotePath = params[WORKDIR].str() + "/" + remotePath; + if (!Utils::isAbsolutePath(remotePath) && !Utils::isOption(remotePath)) { + // rsync creates the whole tree after /./ in the destination folder + remotePath = params[WORKDIR].str() + "/./" + remotePath; } string localPath = outputFile.getLocal(); if (!Utils::isAbsolutePath(localPath)) { localPath = directory + "/" + localPath; } - status = CommunicationProtocol::getInstance(SH).makeDirectory( - Utils::dirname(localPath), "", ""); - if (status) - LOG("Directory creation failed. Status is: " << status); status = _protocol.copyFile(remotePath, _hostname, _username, localPath, "", ""); if (status) diff --git a/src/Core/CMakeLists.txt b/src/Core/CMakeLists.txt index 6b4d8f7..491d99c 100644 --- a/src/Core/CMakeLists.txt +++ b/src/Core/CMakeLists.txt @@ -67,6 +67,10 @@ IF (HAS_SSH) APPEND_CLASSES_TO_SRC_FILES(Core/CommunicationProtocolSSH) ENDIF (HAS_SSH) +IF (HAS_RSYNC) + APPEND_CLASSES_TO_SRC_FILES(Core/CommunicationProtocolRsync) +ENDIF (HAS_RSYNC) + IF (LIBBATCH_BUILD_TESTS) ADD_SUBDIRECTORY(Test) diff --git a/src/Core/CommunicationProtocol.cxx b/src/Core/CommunicationProtocol.cxx index 57a1d52..1e50417 100644 --- a/src/Core/CommunicationProtocol.cxx +++ b/src/Core/CommunicationProtocol.cxx @@ -40,9 +40,13 @@ #ifdef HAS_SSH #include "CommunicationProtocolSSH.hxx" #endif +#ifdef HAS_RSYNC + #include "CommunicationProtocolRsync.hxx" +#endif #include "APIInternalFailureException.hxx" #include "RunTimeException.hxx" #include "Log.hxx" +#include "Utils.hxx" using namespace std; @@ -82,6 +86,14 @@ namespace Batch { #else throw RunTimeException("Can't use SSH protocol (SSH tools were " "not found on the system at compile time)."); +#endif + } else if (protocolType == RSYNC) { +#ifdef HAS_RSYNC + static CommunicationProtocolRsync instanceRsync; + return instanceRsync; +#else + throw RunTimeException("Can't use RSYNC protocol (RSYNC tools were " + "not found on the system at compile time)."); #endif } else throw APIInternalFailureException("Unknown communication protocol."); @@ -169,7 +181,8 @@ namespace Batch { // if the argument contains spaces, we surround it with simple quotes (Linux) // or double quotes (Windows) - if (commandArgs[i].find(' ') != string::npos) { + if (commandArgs[i].find(' ') != string::npos && + !Utils::isOption(commandArgs[i])){ commandStr += string("\"") + commandArgs[i] + "\""; } else { commandStr += commandArgs[i]; diff --git a/src/Core/CommunicationProtocol.hxx b/src/Core/CommunicationProtocol.hxx index 3dc6133..7b69980 100644 --- a/src/Core/CommunicationProtocol.hxx +++ b/src/Core/CommunicationProtocol.hxx @@ -36,7 +36,7 @@ namespace Batch { - enum CommunicationProtocolType {SH, SSH, RSH}; + enum CommunicationProtocolType {SH, SSH, RSH, RSYNC}; class BATCH_EXPORT CommunicationProtocol { diff --git a/src/Core/CommunicationProtocolRsync.cxx b/src/Core/CommunicationProtocolRsync.cxx new file mode 100644 index 0000000..72d3a5a --- /dev/null +++ b/src/Core/CommunicationProtocolRsync.cxx @@ -0,0 +1,104 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +/* + * CommunicationProtocolRsync.cxx : + * + * Author : EDF R&D + */ + +#include +#include "Utils.hxx" + +#include "CommunicationProtocolRsync.hxx" + +using namespace std; + +namespace Batch { + + CommunicationProtocolRsync::CommunicationProtocolRsync() + : CommunicationProtocolSSH() + { + _type = RSYNC; + } + + vector CommunicationProtocolRsync::getCopyCommandArgs(const string & sourcePath, + const string & sourceHost, + const string & sourceUser, + const string & destinationPath, + const string & destinationHost, + const string & destinationUser) const + { + vector cmd; + + string fullSource; + + if(Utils::isOption(sourcePath)) + fullSource += sourcePath; + else + { + if (sourceHost.size() != 0) { + if (sourceUser.size() != 0) { + fullSource += sourceUser + "@"; + } + fullSource += sourceHost + ":"; + } +#ifndef WIN32 + fullSource += "'"; +#endif + fullSource += sourcePath; +#ifndef WIN32 + fullSource += "'"; +#endif + } + + string fullDestination; + if (destinationHost.size() != 0) { + if (destinationUser.size() != 0) { + fullDestination += destinationUser + "@"; + } + fullDestination += destinationHost + ":"; + } +#ifndef WIN32 + fullDestination += "'"; +#endif + fullDestination += destinationPath; +#ifndef WIN32 + fullDestination += "'"; +#endif + + // Option -p is used to keep the same permissions for the destination file + // (particularly useful to keep scripts executable when copying them) + cmd.push_back(RSYNC_COMMAND); + if(!Utils::isOption(sourcePath)) + { + cmd.push_back("-p"); + cmd.push_back("-r"); + if(Utils::usesRsyncRelativePath(sourcePath)) + cmd.push_back("-R"); + } + cmd.push_back(fullSource); + cmd.push_back(fullDestination); + + return cmd; + } + +} diff --git a/src/Core/CommunicationProtocolRsync.hxx b/src/Core/CommunicationProtocolRsync.hxx new file mode 100644 index 0000000..7fa8e1c --- /dev/null +++ b/src/Core/CommunicationProtocolRsync.hxx @@ -0,0 +1,59 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +/* + * CommunicationProtocolRsync.hxx : + * + * Author : EDF R&D + */ + +#ifndef _BATCHCOMMUNICATIONPROTOCOLRSYNC_H_ +#define _BATCHCOMMUNICATIONPROTOCOLRSYNC_H_ + +#include +#include + +#include "Defines.hxx" +#include "CommunicationProtocolSSH.hxx" + +namespace Batch { + + class BATCH_EXPORT CommunicationProtocolRsync : public CommunicationProtocolSSH + { + friend class CommunicationProtocol; + + public: + std::vector getCopyCommandArgs(const std::string & sourcePath, + const std::string & sourceHost, + const std::string & sourceUser, + const std::string & destinationPath, + const std::string & destinationHost, + const std::string & destinationUser) const; + + protected: + + CommunicationProtocolRsync(); + + }; + +} + +#endif diff --git a/src/Core/Utils.cxx b/src/Core/Utils.cxx index cd3deb0..b7371f9 100644 --- a/src/Core/Utils.cxx +++ b/src/Core/Utils.cxx @@ -97,6 +97,16 @@ std::string Utils::dirname(const std::string & path) return std::string("."); } +bool Utils::isOption(const std::string & val) +{ + return val.size() > 0 && val[0] == '-'; +} + +bool Utils::usesRsyncRelativePath(const std::string & path) +{ + return path.find("/./") != std::string::npos; +} + string Utils::createAndOpenTemporaryFile(const string & prefix, ofstream & outputStream) { if (outputStream.is_open()) diff --git a/src/Core/Utils.hxx b/src/Core/Utils.hxx index ed20812..8df38c0 100644 --- a/src/Core/Utils.hxx +++ b/src/Core/Utils.hxx @@ -56,6 +56,17 @@ public: */ static std::string dirname(const std::string & path); + /** + * Test if the string in parameter begins with '-' and it should be processed + * as an option, not as a path. + */ + static bool isOption(const std::string & val); + + /** + * Test if the path in parameter contains a "/./" sequence. + */ + static bool usesRsyncRelativePath(const std::string & path); + /** * Create a temporary file and open an output stream to write into this file. * The file is created with the pattern "/libbatch--XXXXXX" where is the -- 2.39.2