1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.pgm;
45
46 import java.io.File;
47 import java.io.IOException;
48 import java.net.InetSocketAddress;
49 import java.net.URISyntaxException;
50 import java.text.MessageFormat;
51 import java.util.ArrayList;
52 import java.util.List;
53 import java.util.concurrent.Executors;
54
55 import org.eclipse.jgit.errors.ConfigInvalidException;
56 import org.eclipse.jgit.internal.ketch.KetchLeader;
57 import org.eclipse.jgit.internal.ketch.KetchLeaderCache;
58 import org.eclipse.jgit.internal.ketch.KetchPreReceive;
59 import org.eclipse.jgit.internal.ketch.KetchSystem;
60 import org.eclipse.jgit.internal.ketch.KetchText;
61 import org.eclipse.jgit.lib.Repository;
62 import org.eclipse.jgit.lib.StoredConfig;
63 import org.eclipse.jgit.pgm.internal.CLIText;
64 import org.eclipse.jgit.storage.file.FileBasedConfig;
65 import org.eclipse.jgit.storage.file.WindowCacheConfig;
66 import org.eclipse.jgit.storage.pack.PackConfig;
67 import org.eclipse.jgit.transport.DaemonClient;
68 import org.eclipse.jgit.transport.DaemonService;
69 import org.eclipse.jgit.transport.ReceivePack;
70 import org.eclipse.jgit.transport.resolver.FileResolver;
71 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
72 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
73 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
74 import org.eclipse.jgit.util.FS;
75 import org.eclipse.jgit.util.SystemReader;
76 import org.kohsuke.args4j.Argument;
77 import org.kohsuke.args4j.Option;
78
79 @Command(common = true, usage = "usage_exportRepositoriesOverGit")
80 class Daemon extends TextBuiltin {
81 @Option(name = "--config-file", metaVar = "metaVar_configFile", usage = "usage_configFile")
82 File configFile;
83
84 @Option(name = "--port", metaVar = "metaVar_port", usage = "usage_portNumberToListenOn")
85 int port = org.eclipse.jgit.transport.Daemon.DEFAULT_PORT;
86
87 @Option(name = "--listen", metaVar = "metaVar_hostName", usage = "usage_hostnameOrIpToListenOn")
88 String host;
89
90 @Option(name = "--timeout", metaVar = "metaVar_seconds", usage = "usage_abortConnectionIfNoActivity")
91 int timeout = -1;
92
93 @Option(name = "--enable", metaVar = "metaVar_service", usage = "usage_enableTheServiceInAllRepositories")
94 List<String> enable = new ArrayList<>();
95
96 @Option(name = "--disable", metaVar = "metaVar_service", usage = "usage_disableTheServiceInAllRepositories")
97 List<String> disable = new ArrayList<>();
98
99 @Option(name = "--allow-override", metaVar = "metaVar_service", usage = "usage_configureTheServiceInDaemonServicename")
100 List<String> canOverride = new ArrayList<>();
101
102 @Option(name = "--forbid-override", metaVar = "metaVar_service", usage = "usage_configureTheServiceInDaemonServicename")
103 List<String> forbidOverride = new ArrayList<>();
104
105 @Option(name = "--export-all", usage = "usage_exportWithoutGitDaemonExportOk")
106 boolean exportAll;
107
108 @Option(name = "--ketch", metaVar = "metaVar_ketchServerType", usage = "usage_ketchServerType")
109 KetchServerType ketchServerType;
110
111 enum KetchServerType {
112 LEADER;
113 }
114
115 @Argument(required = true, metaVar = "metaVar_directory", usage = "usage_directoriesToExport")
116 List<File> directory = new ArrayList<>();
117
118
119 @Override
120 protected boolean requiresRepository() {
121 return false;
122 }
123
124
125 @Override
126 protected void run() throws Exception {
127 PackConfig packConfig = new PackConfig();
128 StoredConfig cfg;
129 if (configFile == null) {
130 cfg = getUserConfig();
131 } else {
132 if (!configFile.exists()) {
133 throw die(MessageFormat.format(
134 CLIText.get().configFileNotFound,
135 configFile.getAbsolutePath()));
136 }
137 cfg = new FileBasedConfig(configFile, FS.DETECTED);
138 }
139 cfg.load();
140 new WindowCacheConfig().fromConfig(cfg).install();
141 packConfig.fromConfig(cfg);
142
143 int threads = packConfig.getThreads();
144 if (threads <= 0)
145 threads = Runtime.getRuntime().availableProcessors();
146 if (1 < threads)
147 packConfig.setExecutor(Executors.newFixedThreadPool(threads));
148
149 final FileResolver<DaemonClient> resolver = new FileResolver<>();
150 for (File f : directory) {
151 outw.println(MessageFormat.format(CLIText.get().exporting, f.getAbsolutePath()));
152 resolver.exportDirectory(f);
153 }
154 resolver.setExportAll(exportAll);
155
156 final org.eclipse.jgit.transport.Daemon d;
157 d = new org.eclipse.jgit.transport.Daemon(
158 host != null ? new InetSocketAddress(host, port)
159 : new InetSocketAddress(port));
160 d.setPackConfig(packConfig);
161 d.setRepositoryResolver(resolver);
162 if (0 <= timeout)
163 d.setTimeout(timeout);
164
165 for (String n : enable)
166 service(d, n).setEnabled(true);
167 for (String n : disable)
168 service(d, n).setEnabled(false);
169
170 for (String n : canOverride)
171 service(d, n).setOverridable(true);
172 for (String n : forbidOverride)
173 service(d, n).setOverridable(false);
174 if (ketchServerType == KetchServerType.LEADER) {
175 startKetchLeader(d);
176 }
177 d.start();
178 outw.println(MessageFormat.format(CLIText.get().listeningOn, d.getAddress()));
179 }
180
181 private StoredConfig getUserConfig() throws IOException {
182 StoredConfig userConfig = null;
183 try {
184 userConfig = SystemReader.getInstance().getUserConfig();
185 } catch (ConfigInvalidException e) {
186 throw die(e.getMessage());
187 }
188 return userConfig;
189 }
190
191 private static DaemonService service(
192 final org.eclipse.jgit.transport.Daemon d,
193 final String n) {
194 final DaemonService svc = d.getService(n);
195 if (svc == null)
196 throw die(MessageFormat.format(CLIText.get().serviceNotSupported, n));
197 return svc;
198 }
199
200 private void startKetchLeader(org.eclipse.jgit.transport.Daemon daemon) {
201 KetchSystem system = new KetchSystem();
202 final KetchLeaderCache leaders = new KetchLeaderCache(system);
203 final ReceivePackFactory<DaemonClient> factory;
204
205 factory = daemon.getReceivePackFactory();
206 daemon.setReceivePackFactory(new ReceivePackFactory<DaemonClient>() {
207 @Override
208 public ReceivePack create(DaemonClient req, Repository repo)
209 throws ServiceNotEnabledException,
210 ServiceNotAuthorizedException {
211 ReceivePack rp = factory.create(req, repo);
212 KetchLeader leader;
213 try {
214 leader = leaders.get(repo);
215 } catch (URISyntaxException err) {
216 throw new ServiceNotEnabledException(
217 KetchText.get().invalidFollowerUri, err);
218 }
219 rp.setPreReceiveHook(new KetchPreReceive(leader));
220 return rp;
221 }
222 });
223 }
224 }