2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org
.argeo
.slc
.jsch
;
19 import java
.util
.ArrayList
;
20 import java
.util
.HashMap
;
21 import java
.util
.List
;
23 import java
.util
.StringTokenizer
;
25 import org
.apache
.commons
.logging
.Log
;
26 import org
.apache
.commons
.logging
.LogFactory
;
27 import org
.argeo
.slc
.SlcException
;
28 import org
.argeo
.slc
.core
.deploy
.DigestCheck
;
29 import org
.argeo
.slc
.core
.deploy
.ResourceSet
;
30 import org
.springframework
.core
.io
.Resource
;
32 import com
.jcraft
.jsch
.Session
;
34 public class SshFilesDeployment
extends AbstractJschTask
implements Runnable
{
35 private final static Log log
= LogFactory
.getLog(SshFilesDeployment
.class);
36 private String targetBase
= "";
37 private ResourceSet resourceSet
;
39 * Activate with algorithm as per
40 * http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html#AppA
42 private String checksum
= "MD5";
43 private int remoteChecksumsPerCall
= 20;
45 public SshFilesDeployment() {
48 public SshFilesDeployment(SshTarget sshTarget
, ResourceSet resourceSet
) {
49 setSshTarget(sshTarget
);
50 this.resourceSet
= resourceSet
;
54 void run(Session session
) {
55 JschMultiTasks multiTasks
= new JschMultiTasks();
57 Map
<String
, Resource
> resources
= resourceSet
.listResources();
60 List
<String
> subDirs
= new ArrayList
<String
>();
61 Map
<String
, String
> targetPaths
= new HashMap
<String
, String
>();
62 for (String relPath
: resources
.keySet()) {
64 int lastIndexSubDir
= relPath
.lastIndexOf('/');
65 if (lastIndexSubDir
> 0)
66 parentDir
= targetBase
+ '/'
67 + relPath
.substring(0, lastIndexSubDir
);
69 parentDir
= targetBase
;
71 boolean skipDir
= false;
72 registerDirs
: for (String registeredDir
: new ArrayList
<String
>(
74 if (parentDir
.equals(registeredDir
)) {
75 if (log
.isTraceEnabled())
76 log
.trace("Already registered, skip " + parentDir
);
81 if (parentDir
.startsWith(registeredDir
))
82 if (subDirs
.contains(registeredDir
)) {
83 subDirs
.remove(registeredDir
);
84 if (log
.isTraceEnabled())
85 log
.trace("Remove parent " + registeredDir
+ " of "
87 continue registerDirs
;
90 if (registeredDir
.startsWith(parentDir
)) {
92 if (log
.isTraceEnabled())
93 log
.trace("Skip " + parentDir
94 + " because child already registered.");
99 if (!subDirs
.contains(parentDir
) && !skipDir
) {
100 subDirs
.add(parentDir
);
103 targetPaths
.put(relPath
, targetBase
+ "/" + relPath
);
107 List
<String
> targetPathsEqualsToLocal
= new ArrayList
<String
>();
108 if (checksum
!= null) {
109 Map
<String
, String
> remoteChecksums
= new HashMap
<String
, String
>();
110 List
<String
> csLines
= new ArrayList
<String
>();
112 if ("MD5".equals(checksum
))
113 csExecutable
= "/usr/bin/md5sum";
114 else if ("SHA".equals(checksum
))
115 csExecutable
= "/usr/bin/sha1sum";
116 else if ("SHA-256".equals(checksum
))
117 csExecutable
= "/usr/bin/sha256sum";
118 else if ("SHA-512".equals(checksum
))
119 csExecutable
= "/usr/bin/sha512sum";
121 throw new SlcException(
122 "Don't know how to remotely execute checksum "
125 StringBuffer csCmd
= new StringBuffer(csExecutable
);
126 int numberOfPaths
= targetPaths
.size();
128 for (String targetPath
: targetPaths
.values()) {
129 csCmd
.append(" ").append(targetPath
);
132 if ((count
% remoteChecksumsPerCall
== 0)
133 || count
== numberOfPaths
) {
134 RemoteExec remoteCs
= new RemoteExec();
135 remoteCs
.setSshTarget(getSshTarget());
136 remoteCs
.setCommand(csCmd
.toString());
137 remoteCs
.setStdOutLines(csLines
);
138 remoteCs
.setFailOnBadExitStatus(false);
139 remoteCs
.run(session
);
140 csCmd
= new StringBuffer(csExecutable
);
145 remoteChecksums
: for (String csLine
: csLines
) {
146 StringTokenizer st
= new StringTokenizer(csLine
, ": ");
147 String cs
= st
.nextToken();
148 if (cs
.equals(csExecutable
)) {
149 // remote does not exist
150 continue remoteChecksums
;
152 String targetPath
= st
.nextToken();
153 if (log
.isTraceEnabled())
154 log
.trace("REMOTE: " + targetPath
+ "=" + cs
);
155 remoteChecksums
.put(targetPath
, cs
);
160 for (String relPath
: resources
.keySet()) {
161 Resource resource
= resources
.get(relPath
);
162 String targetPath
= targetPaths
.get(relPath
);
163 if (remoteChecksums
.containsKey(targetPath
)) {
164 String cs
= DigestCheck
.digest(checksum
, resource
);
165 if (log
.isTraceEnabled())
166 log
.trace("LOCAL : " + targetPath
+ "=" + cs
);
167 if (remoteChecksums
.get(targetPath
).equals(cs
))
168 targetPathsEqualsToLocal
.add(targetPath
);
176 StringBuffer mkdirCmd
= new StringBuffer("mkdir -p");
177 RemoteExec remoteExec
= new RemoteExec();
178 for (String dir
: subDirs
) {
179 // remoteExec.getCommands().add("mkdir -p " + dir);
180 mkdirCmd
.append(' ');
181 if (dir
.indexOf(' ') >= 0)
182 mkdirCmd
.append('\"').append(dir
).append('\"');
184 mkdirCmd
.append(dir
);
186 remoteExec
.setCommand(mkdirCmd
.toString());
187 multiTasks
.getTasks().add(remoteExec
);
192 copy
: for (String relPath
: resources
.keySet()) {
193 String targetPath
= targetPaths
.get(relPath
);
194 if (targetPathsEqualsToLocal
.contains(targetPath
)) {
195 if (log
.isTraceEnabled())
196 log
.trace("Skip copy of " + relPath
197 + " since it is equal to remote " + targetPath
);
202 Resource resource
= resources
.get(relPath
);
203 ScpTo scpTo
= new ScpTo();
204 scpTo
.setLocalResource(resource
);
205 scpTo
.setRemotePath(targetPath
);
206 multiTasks
.getTasks().add(scpTo
);
208 // TODO: set permissions
211 multiTasks
.setSshTarget(getSshTarget());
212 multiTasks
.run(session
);
214 if (checksum
!= null && log
.isDebugEnabled())
215 log
.debug("Copied " + copied
+ " files, skipped " + skipped
216 + " with same checksum.");
219 public void setTargetBase(String targetBase
) {
220 this.targetBase
= targetBase
;
223 public void setResourceSet(ResourceSet resourceSet
) {
224 this.resourceSet
= resourceSet
;
227 public void setChecksum(String checksum
) {
228 this.checksum
= checksum
;
231 /** Number of remote checksums per remote call */
232 public void setRemoteChecksumsPerCall(int remoteChecksumsPerCall
) {
233 this.remoteChecksumsPerCall
= remoteChecksumsPerCall
;