2 * Copyright (C) 2007-2012 Argeo GmbH
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.
16 package org
.argeo
.slc
.jsch
;
18 import java
.util
.ArrayList
;
19 import java
.util
.HashMap
;
20 import java
.util
.List
;
22 import java
.util
.StringTokenizer
;
24 import org
.apache
.commons
.logging
.Log
;
25 import org
.apache
.commons
.logging
.LogFactory
;
26 import org
.argeo
.slc
.SlcException
;
27 import org
.argeo
.slc
.core
.deploy
.DigestCheck
;
28 import org
.argeo
.slc
.core
.deploy
.ResourceSet
;
29 import org
.springframework
.core
.io
.Resource
;
31 import com
.jcraft
.jsch
.Session
;
33 public class SshFilesDeployment
extends AbstractJschTask
implements Runnable
{
34 private final static Log log
= LogFactory
.getLog(SshFilesDeployment
.class);
35 private String targetBase
= "";
36 private ResourceSet resourceSet
;
38 * Activate with algorithm as per
39 * http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html#AppA
41 private String checksum
= "MD5";
42 private int remoteChecksumsPerCall
= 20;
44 public SshFilesDeployment() {
47 public SshFilesDeployment(SshTarget sshTarget
, ResourceSet resourceSet
) {
48 setSshTarget(sshTarget
);
49 this.resourceSet
= resourceSet
;
53 void run(Session session
) {
54 JschMultiTasks multiTasks
= new JschMultiTasks();
56 Map
<String
, Resource
> resources
= resourceSet
.listResources();
59 List
<String
> subDirs
= new ArrayList
<String
>();
60 Map
<String
, String
> targetPaths
= new HashMap
<String
, String
>();
61 for (String relPath
: resources
.keySet()) {
63 int lastIndexSubDir
= relPath
.lastIndexOf('/');
64 if (lastIndexSubDir
> 0)
65 parentDir
= targetBase
+ '/'
66 + relPath
.substring(0, lastIndexSubDir
);
68 parentDir
= targetBase
;
70 boolean skipDir
= false;
71 registerDirs
: for (String registeredDir
: new ArrayList
<String
>(
73 if (parentDir
.equals(registeredDir
)) {
74 if (log
.isTraceEnabled())
75 log
.trace("Already registered, skip " + parentDir
);
80 if (parentDir
.startsWith(registeredDir
))
81 if (subDirs
.contains(registeredDir
)) {
82 subDirs
.remove(registeredDir
);
83 if (log
.isTraceEnabled())
84 log
.trace("Remove parent " + registeredDir
+ " of "
86 continue registerDirs
;
89 if (registeredDir
.startsWith(parentDir
)) {
91 if (log
.isTraceEnabled())
92 log
.trace("Skip " + parentDir
93 + " because child already registered.");
98 if (!subDirs
.contains(parentDir
) && !skipDir
) {
99 subDirs
.add(parentDir
);
102 targetPaths
.put(relPath
, targetBase
+ "/" + relPath
);
106 List
<String
> targetPathsEqualsToLocal
= new ArrayList
<String
>();
107 if (checksum
!= null) {
108 Map
<String
, String
> remoteChecksums
= new HashMap
<String
, String
>();
109 List
<String
> csLines
= new ArrayList
<String
>();
111 if ("MD5".equals(checksum
))
112 csExecutable
= "/usr/bin/md5sum";
113 else if ("SHA".equals(checksum
))
114 csExecutable
= "/usr/bin/sha1sum";
115 else if ("SHA-256".equals(checksum
))
116 csExecutable
= "/usr/bin/sha256sum";
117 else if ("SHA-512".equals(checksum
))
118 csExecutable
= "/usr/bin/sha512sum";
120 throw new SlcException(
121 "Don't know how to remotely execute checksum "
124 StringBuffer csCmd
= new StringBuffer(csExecutable
);
125 int numberOfPaths
= targetPaths
.size();
127 for (String targetPath
: targetPaths
.values()) {
128 csCmd
.append(" ").append(targetPath
);
131 if ((count
% remoteChecksumsPerCall
== 0)
132 || count
== numberOfPaths
) {
133 RemoteExec remoteCs
= new RemoteExec();
134 remoteCs
.setSshTarget(getSshTarget());
135 remoteCs
.setCommand(csCmd
.toString());
136 remoteCs
.setStdOutLines(csLines
);
137 remoteCs
.setFailOnBadExitStatus(false);
138 remoteCs
.run(session
);
139 csCmd
= new StringBuffer(csExecutable
);
144 remoteChecksums
: for (String csLine
: csLines
) {
145 StringTokenizer st
= new StringTokenizer(csLine
, ": ");
146 String cs
= st
.nextToken();
147 if (cs
.equals(csExecutable
)) {
148 // remote does not exist
149 continue remoteChecksums
;
151 String targetPath
= st
.nextToken();
152 if (log
.isTraceEnabled())
153 log
.trace("REMOTE: " + targetPath
+ "=" + cs
);
154 remoteChecksums
.put(targetPath
, cs
);
159 for (String relPath
: resources
.keySet()) {
160 Resource resource
= resources
.get(relPath
);
161 String targetPath
= targetPaths
.get(relPath
);
162 if (remoteChecksums
.containsKey(targetPath
)) {
163 String cs
= DigestCheck
.digest(checksum
, resource
);
164 if (log
.isTraceEnabled())
165 log
.trace("LOCAL : " + targetPath
+ "=" + cs
);
166 if (remoteChecksums
.get(targetPath
).equals(cs
))
167 targetPathsEqualsToLocal
.add(targetPath
);
175 StringBuffer mkdirCmd
= new StringBuffer("mkdir -p");
176 RemoteExec remoteExec
= new RemoteExec();
177 for (String dir
: subDirs
) {
178 // remoteExec.getCommands().add("mkdir -p " + dir);
179 mkdirCmd
.append(' ');
180 if (dir
.indexOf(' ') >= 0)
181 mkdirCmd
.append('\"').append(dir
).append('\"');
183 mkdirCmd
.append(dir
);
185 remoteExec
.setCommand(mkdirCmd
.toString());
186 multiTasks
.getTasks().add(remoteExec
);
191 copy
: for (String relPath
: resources
.keySet()) {
192 String targetPath
= targetPaths
.get(relPath
);
193 if (targetPathsEqualsToLocal
.contains(targetPath
)) {
194 if (log
.isTraceEnabled())
195 log
.trace("Skip copy of " + relPath
196 + " since it is equal to remote " + targetPath
);
201 Resource resource
= resources
.get(relPath
);
202 ScpTo scpTo
= new ScpTo();
203 scpTo
.setLocalResource(resource
);
204 scpTo
.setRemotePath(targetPath
);
205 multiTasks
.getTasks().add(scpTo
);
207 // TODO: set permissions
210 multiTasks
.setSshTarget(getSshTarget());
211 multiTasks
.run(session
);
213 if (checksum
!= null && log
.isDebugEnabled())
214 log
.debug("Copied " + copied
+ " files, skipped " + skipped
215 + " with same checksum.");
218 public void setTargetBase(String targetBase
) {
219 this.targetBase
= targetBase
;
222 public void setResourceSet(ResourceSet resourceSet
) {
223 this.resourceSet
= resourceSet
;
226 public void setChecksum(String checksum
) {
227 this.checksum
= checksum
;
230 /** Number of remote checksums per remote call */
231 public void setRemoteChecksumsPerCall(int remoteChecksumsPerCall
) {
232 this.remoteChecksumsPerCall
= remoteChecksumsPerCall
;