package org.argeo.slc.jsch;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.slc.SlcException;
import org.springframework.core.io.Resource;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.PathMatcher;
+import org.springframework.util.StringUtils;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
public class ScpTo extends AbstractJschTask {
private final static Log log = LogFactory.getLog(ScpTo.class);
- private Resource localFile;
- private String remoteFile;
+ private Resource localResource;
+ private String remotePath;
- public void run() {
+ private String dir;
+ private String remoteDir;
+ private List<String> includes = new ArrayList<String>();
+
+ private List<String> excludes = new ArrayList<String>();
+
+ private PathMatcher pathMatcher;
+
+ public void run(Session session) {
+ if (StringUtils.hasText(dir)) {
+ if (!StringUtils.hasText(remoteDir))
+ throw new SlcException("Remote dir has to be specified.");
+
+ String dirOs = dir.replace('/', File.separatorChar);
+ if (dirOs.charAt(dir.length() - 1) != File.separatorChar) {
+ dirOs = dirOs + File.separator;
+ }
+
+ if (pathMatcher == null)
+ pathMatcher = new AntPathMatcher();
+
+ log.info("Start multiple scp based on " + dirOs);
+ scanDir(session, dirOs, "", includes, excludes);
+ }
+
+ if (localResource != null) {
+ try {
+ File lFile = localResource.getFile();
+ uploadFile(session, lFile, remotePath);
+ } catch (IOException e) {
+ OutputStream out = null;
+ InputStream in = null;
+ File tempFile = null;
+ try {
+ tempFile = File.createTempFile(getClass().getSimpleName()
+ + "-" + localResource.getFilename(), null);
+ out = FileUtils.openOutputStream(tempFile);
+ in = localResource.getInputStream();
+ IOUtils.copy(in, out);
+ uploadFile(session, tempFile, remotePath);
+ } catch (IOException e1) {
+ throw new SlcException("Can neither interpret resource "
+ + localResource
+ + " as file, nor create a temporary file", e1);
+ } finally {
+ IOUtils.closeQuietly(in);
+ IOUtils.closeQuietly(out);
+ FileUtils.deleteQuietly(tempFile);
+ }
+ }
+ }
+ }
+
+ protected void scanDir(Session session, String dir, String currentRelPath,
+ List<String> includes, List<String> excludes) {
+ File[] files = new File(dir).listFiles();
+ for (File file : files) {
+ if (!file.isDirectory()) {
+ String relPath = currentRelPath.concat(file.getName());
+ if (match(relPath, includes, excludes, false)) {
+ uploadFile(session, file, remoteDir + '/' + relPath);
+ }
+ } else {
+ String relPath = currentRelPath.concat(file.getName()).concat(
+ "/");
+ if (match(relPath, includes, excludes, true)) {
+ String nextDir = dir.concat(file.getName()).concat(
+ File.separator);
+ scanDir(session, nextDir, relPath, includes, excludes);
+ }
+ }
+ }
+ }
+
+ protected Boolean match(String path, List<String> includes,
+ List<String> excludes, boolean matchStart) {
+ for (String patternIn : includes) {
+ boolean matchIn = matchStart ? pathMatcher.matchStart(patternIn,
+ path) : pathMatcher.match(patternIn, path);
+ if (matchIn) {
+ // Could be included, check excludes
+ boolean excluded = false;
+ ex: for (String patternEx : excludes) {
+ boolean matchEx = matchStart ? pathMatcher.matchStart(
+ patternEx, path) : pathMatcher.match(patternEx,
+ path);
+
+ if (matchEx) {
+ excluded = true;
+ break ex;
+ }
+ }
+ if (!excluded)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected void uploadFile(Session session, File localFile, String remoteFile) {
InputStream in = null;
OutputStream channelOut;
InputStream channelIn;
-
- Session session = openSession();
try {
// exec 'scp -t rfile' remotely
// send "C0644 filesize filename", where filename should not include
// '/'
- File lFile = localFile.getFile();
- long filesize = lFile.length();
+ long filesize = localFile.length();
command = "C0644 " + filesize + " ";
- int index = lFile.getPath().lastIndexOf('/');
+ int index = localFile.getPath().lastIndexOf('/');
if (index > 0) {
- command += lFile.getPath().substring(index + 1);
+ command += localFile.getPath().substring(index + 1);
} else {
- command += lFile.getPath();
+ command += localFile.getPath();
}
command += "\n";
channelOut.flush();
checkAck(channelIn);
- if (log.isDebugEnabled())
+ if (log.isTraceEnabled())
log.debug("Start copy of " + localFile + " to " + remoteFile
+ " on " + getSshTarget() + "...");
+ final long oneMB = 1024l;// in KB
+ final long tenMB = 10 * oneMB;// in KB
+
// send a content of lfile
- in = localFile.getInputStream();
+ in = new FileInputStream(localFile);
byte[] buf = new byte[1024];
long cycleCount = 0;
while (true) {
if (len <= 0)
break;
channelOut.write(buf, 0, len); // out.flush();
- if ((cycleCount % 1024) == 0)// each 1 MB
+ if (((cycleCount % oneMB) == 0) && cycleCount != 0)// each 1 MB
System.out.print('#');
+ if (((cycleCount % (tenMB)) == 0) && cycleCount != 0)// each 10
+ // MB
+ System.out.print(" - " + cycleCount / tenMB + "0 MB\n");
cycleCount++;
}
// send '\0'
channelOut.flush();
checkAck(channelIn);
+ if (log.isTraceEnabled())
+ log.debug((cycleCount) + " KB sent to server. ("
+ + (cycleCount / oneMB + " MB)"));
+
if (log.isDebugEnabled())
- log.debug("Finished copy of " + localFile + " to " + remoteFile
- + " on " + getSshTarget() + "...");
+ log.debug("Finished copy to " + remoteFile + " on "
+ + getSshTarget() + " from " + localFile);
IOUtils.closeQuietly(channelOut);
channel.disconnect();
- session.disconnect();
-
} catch (Exception e) {
throw new SlcException("Cannot copy " + localFile + " to "
+ remoteFile, e);
}
}
- public void setLocalFile(Resource localFile) {
- this.localFile = localFile;
+ public void setLocalResource(Resource localFile) {
+ this.localResource = localFile;
+ }
+
+ public void setRemotePath(String remoteFile) {
+ this.remotePath = remoteFile;
+ }
+
+ public void setDir(String dir) {
+ this.dir = dir;
+ }
+
+ public void setRemoteDir(String remoteDir) {
+ this.remoteDir = remoteDir;
+ }
+
+ public void setIncludes(List<String> includes) {
+ this.includes = includes;
+ }
+
+ public void setExcludes(List<String> excludes) {
+ this.excludes = excludes;
}
- public void setRemoteFile(String remoteFile) {
- this.remoteFile = remoteFile;
+ public void setPathMatcher(PathMatcher pathMatcher) {
+ this.pathMatcher = pathMatcher;
}
}