1 package org
.argeo
.slc
.jsch
;
3 import java
.util
.ArrayList
;
4 import java
.util
.HashMap
;
7 import java
.util
.StringTokenizer
;
9 import org
.apache
.commons
.logging
.Log
;
10 import org
.apache
.commons
.logging
.LogFactory
;
11 import org
.argeo
.slc
.SlcException
;
12 import org
.argeo
.slc
.core
.deploy
.DigestCheck
;
13 import org
.argeo
.slc
.core
.deploy
.ResourceSet
;
14 import org
.springframework
.core
.io
.Resource
;
16 import com
.jcraft
.jsch
.Session
;
18 public class SshFilesDeployment
extends AbstractJschTask
implements Runnable
{
19 private final static Log log
= LogFactory
.getLog(SshFilesDeployment
.class);
20 private String targetBase
= "";
21 private ResourceSet resourceSet
;
23 * Activate with algorithm as per
24 * http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html#AppA
26 private String checksum
= "MD5";
27 private int remoteChecksumsPerCall
= 20;
29 public SshFilesDeployment() {
32 public SshFilesDeployment(SshTarget sshTarget
, ResourceSet resourceSet
) {
33 setSshTarget(sshTarget
);
34 this.resourceSet
= resourceSet
;
38 void run(Session session
) {
39 JschMultiTasks multiTasks
= new JschMultiTasks();
41 Map
<String
, Resource
> resources
= resourceSet
.listResources();
44 List
<String
> subDirs
= new ArrayList
<String
>();
45 Map
<String
, String
> targetPaths
= new HashMap
<String
, String
>();
46 for (String relPath
: resources
.keySet()) {
48 int lastIndexSubDir
= relPath
.lastIndexOf('/');
49 if (lastIndexSubDir
> 0)
50 parentDir
= targetBase
+ '/'
51 + relPath
.substring(0, lastIndexSubDir
);
53 parentDir
= targetBase
;
55 boolean skipDir
= false;
56 registerDirs
: for (String registeredDir
: new ArrayList
<String
>(
58 if (parentDir
.equals(registeredDir
)) {
59 if (log
.isTraceEnabled())
60 log
.trace("Already registered, skip " + parentDir
);
65 if (parentDir
.startsWith(registeredDir
))
66 if (subDirs
.contains(registeredDir
)) {
67 subDirs
.remove(registeredDir
);
68 if (log
.isTraceEnabled())
69 log
.trace("Remove parent " + registeredDir
+ " of "
71 continue registerDirs
;
74 if (registeredDir
.startsWith(parentDir
)) {
76 if (log
.isTraceEnabled())
77 log
.trace("Skip " + parentDir
78 + " because child already registered.");
83 if (!subDirs
.contains(parentDir
) && !skipDir
) {
84 subDirs
.add(parentDir
);
87 targetPaths
.put(relPath
, targetBase
+ "/" + relPath
);
91 List
<String
> targetPathsEqualsToLocal
= new ArrayList
<String
>();
92 if (checksum
!= null) {
93 Map
<String
, String
> remoteChecksums
= new HashMap
<String
, String
>();
94 List
<String
> csLines
= new ArrayList
<String
>();
96 if ("MD5".equals(checksum
))
97 csExecutable
= "/usr/bin/md5sum";
98 else if ("SHA".equals(checksum
))
99 csExecutable
= "/usr/bin/sha1sum";
100 else if ("SHA-256".equals(checksum
))
101 csExecutable
= "/usr/bin/sha256sum";
102 else if ("SHA-512".equals(checksum
))
103 csExecutable
= "/usr/bin/sha512sum";
105 throw new SlcException(
106 "Don't know how to remotely execute checksum "
109 StringBuffer csCmd
= new StringBuffer(csExecutable
);
110 int numberOfPaths
= targetPaths
.size();
112 for (String targetPath
: targetPaths
.values()) {
113 csCmd
.append(" ").append(targetPath
);
116 if ((count
% remoteChecksumsPerCall
== 0)
117 || count
== numberOfPaths
) {
118 RemoteExec remoteCs
= new RemoteExec();
119 remoteCs
.setSshTarget(getSshTarget());
120 remoteCs
.setCommand(csCmd
.toString());
121 remoteCs
.setStdOutLines(csLines
);
122 remoteCs
.setFailOnBadExitStatus(false);
123 remoteCs
.run(session
);
124 csCmd
= new StringBuffer(csExecutable
);
129 remoteChecksums
: for (String csLine
: csLines
) {
130 StringTokenizer st
= new StringTokenizer(csLine
, ": ");
131 String cs
= st
.nextToken();
132 if (cs
.equals(csExecutable
)) {
133 // remote does not exist
134 continue remoteChecksums
;
136 String targetPath
= st
.nextToken();
137 if (log
.isTraceEnabled())
138 log
.trace("REMOTE: " + targetPath
+ "=" + cs
);
139 remoteChecksums
.put(targetPath
, cs
);
144 for (String relPath
: resources
.keySet()) {
145 Resource resource
= resources
.get(relPath
);
146 String targetPath
= targetPaths
.get(relPath
);
147 if (remoteChecksums
.containsKey(targetPath
)) {
148 String cs
= DigestCheck
.digest(checksum
, resource
);
149 if (log
.isTraceEnabled())
150 log
.trace("LOCAL : " + targetPath
+ "=" + cs
);
151 if (remoteChecksums
.get(targetPath
).equals(cs
))
152 targetPathsEqualsToLocal
.add(targetPath
);
160 StringBuffer mkdirCmd
= new StringBuffer("mkdir -p");
161 RemoteExec remoteExec
= new RemoteExec();
162 for (String dir
: subDirs
) {
163 // remoteExec.getCommands().add("mkdir -p " + dir);
164 mkdirCmd
.append(' ');
165 if (dir
.indexOf(' ') >= 0)
166 mkdirCmd
.append('\"').append(dir
).append('\"');
168 mkdirCmd
.append(dir
);
170 remoteExec
.setCommand(mkdirCmd
.toString());
171 multiTasks
.getTasks().add(remoteExec
);
176 copy
: for (String relPath
: resources
.keySet()) {
177 String targetPath
= targetPaths
.get(relPath
);
178 if (targetPathsEqualsToLocal
.contains(targetPath
)) {
179 if (log
.isTraceEnabled())
180 log
.trace("Skip copy of " + relPath
181 + " since it is equal to remote " + targetPath
);
186 Resource resource
= resources
.get(relPath
);
187 ScpTo scpTo
= new ScpTo();
188 scpTo
.setLocalResource(resource
);
189 scpTo
.setRemotePath(targetPath
);
190 multiTasks
.getTasks().add(scpTo
);
192 // TODO: set permissions
195 multiTasks
.setSshTarget(getSshTarget());
196 multiTasks
.run(session
);
198 if (checksum
!= null && log
.isDebugEnabled())
199 log
.debug("Copied " + copied
+ " files, skipped " + skipped
200 + " with same checksum.");
203 public void setTargetBase(String targetBase
) {
204 this.targetBase
= targetBase
;
207 public void setResourceSet(ResourceSet resourceSet
) {
208 this.resourceSet
= resourceSet
;
211 public void setChecksum(String checksum
) {
212 this.checksum
= checksum
;
215 /** Number of remote checksums per remote call */
216 public void setRemoteChecksumsPerCall(int remoteChecksumsPerCall
) {
217 this.remoteChecksumsPerCall
= remoteChecksumsPerCall
;