1 package org.cyclopsgroup.gitcon.jgit;
2
3 import java.io.File;
4
5 import org.eclipse.jgit.api.errors.GitAPIException;
6 import org.eclipse.jgit.transport.JschConfigSessionFactory;
7 import org.eclipse.jgit.transport.OpenSshConfig;
8 import org.eclipse.jgit.transport.SshSessionFactory;
9 import org.eclipse.jgit.util.FS;
10
11 import com.jcraft.jsch.JSch;
12 import com.jcraft.jsch.JSchException;
13 import com.jcraft.jsch.Session;
14
15
16
17
18 abstract class JGitCallExecutor
19 {
20 private static class Direct
21 extends JGitCallExecutor
22 {
23 @Override
24 <T> T invokeCall( JGitCall<T> call )
25 throws GitAPIException
26 {
27 return call.call();
28 }
29 }
30
31 private static class KeySessionFactory
32 extends JschConfigSessionFactory
33 {
34 private final String privateKeyPath;
35
36 private KeySessionFactory( String keyPath )
37 {
38 this.privateKeyPath = keyPath;
39 }
40
41 @Override
42 protected void configure( OpenSshConfig.Host host, Session session )
43 {
44 session.setConfig( "StrictHostKeyChecking", "no" );
45 }
46
47 @Override
48 protected JSch getJSch( final OpenSshConfig.Host hostConfig, FS fs )
49 throws JSchException
50 {
51 JSch jsch = super.getJSch( hostConfig, fs );
52 jsch.removeAllIdentity();
53 jsch.addIdentity( privateKeyPath );
54 return jsch;
55 }
56 }
57
58 private static class SshContext
59 extends JGitCallExecutor
60 {
61 private final KeySessionFactory context;
62
63 private SshContext( KeySessionFactory context )
64 {
65 this.context = context;
66 }
67
68 @Override
69 <T> T invokeCall( JGitCall<T> call )
70 throws GitAPIException
71 {
72 if ( !new File( context.privateKeyPath ).canRead() )
73 {
74 throw new IllegalArgumentException( "Private key "
75 + context.privateKeyPath + " is not accessible" );
76 }
77 synchronized ( JGitCallExecutor.class )
78 {
79 SshSessionFactory original = SshSessionFactory.getInstance();
80 SshSessionFactory.setInstance( context );
81 try
82 {
83 return call.call();
84 }
85 finally
86 {
87 SshSessionFactory.setInstance( original );
88 }
89 }
90 }
91 }
92
93 private static class Synchronized
94 extends JGitCallExecutor
95 {
96 private final JGitCallExecutor executor;
97
98 private Synchronized( JGitCallExecutor executor )
99 {
100 this.executor = executor;
101 }
102
103 @Override
104 <T> T invokeCall( JGitCall<T> call )
105 throws GitAPIException
106 {
107 synchronized ( JGitCallExecutor.class )
108 {
109 return executor.invokeCall( call );
110 }
111 }
112 }
113
114 private static final JGitCallExecutor DIRECT_INSTANCE = new Direct();
115
116
117
118
119 static JGitCallExecutor direct()
120 {
121 return DIRECT_INSTANCE;
122 }
123
124
125
126
127
128
129 static JGitCallExecutor synchronize( JGitCallExecutor executor )
130 {
131 return new Synchronized( executor );
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145 static JGitCallExecutor withSshPrivateKey( String sshPrivateKey )
146 {
147 return new SshContext( new KeySessionFactory( sshPrivateKey ) );
148 }
149
150
151
152
153
154
155
156
157 abstract <T> T invokeCall( JGitCall<T> call )
158 throws GitAPIException;
159 }