1
2
3
4
5
6
7
8
9
10
11
12 package org.eclipse.jgit.pgm;
13
14 import static java.nio.charset.StandardCharsets.UTF_8;
15
16 import java.io.File;
17 import java.io.IOException;
18 import java.io.OutputStreamWriter;
19 import java.io.PrintWriter;
20 import java.lang.reflect.InvocationTargetException;
21 import java.net.MalformedURLException;
22 import java.net.URL;
23 import java.text.MessageFormat;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Locale;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.TimeUnit;
31
32 import org.eclipse.jgit.awtui.AwtAuthenticator;
33 import org.eclipse.jgit.awtui.AwtCredentialsProvider;
34 import org.eclipse.jgit.errors.TransportException;
35 import org.eclipse.jgit.lfs.BuiltinLFS;
36 import org.eclipse.jgit.lib.Repository;
37 import org.eclipse.jgit.lib.RepositoryBuilder;
38 import org.eclipse.jgit.pgm.internal.CLIText;
39 import org.eclipse.jgit.pgm.opt.CmdLineParser;
40 import org.eclipse.jgit.pgm.opt.SubcommandHandler;
41 import org.eclipse.jgit.transport.HttpTransport;
42 import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory;
43 import org.eclipse.jgit.util.CachedAuthenticator;
44 import org.kohsuke.args4j.Argument;
45 import org.kohsuke.args4j.CmdLineException;
46 import org.kohsuke.args4j.Option;
47 import org.kohsuke.args4j.OptionHandlerFilter;
48
49
50
51
52 public class Main {
53 @Option(name = "--help", usage = "usage_displayThisHelpText", aliases = { "-h" })
54 private boolean help;
55
56 @Option(name = "--version", usage = "usage_displayVersion")
57 private boolean version;
58
59 @Option(name = "--show-stack-trace", usage = "usage_displayThejavaStackTraceOnExceptions")
60 private boolean showStackTrace;
61
62 @Option(name = "--git-dir", metaVar = "metaVar_gitDir", usage = "usage_setTheGitRepositoryToOperateOn")
63 private String gitdir;
64
65 @Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class)
66 private TextBuiltin subcommand;
67
68 @Argument(index = 1, metaVar = "metaVar_arg")
69 private List<String> arguments = new ArrayList<>();
70
71 PrintWriter writer;
72
73 private ExecutorService gcExecutor;
74
75
76
77
78 public Main() {
79 HttpTransport.setConnectionFactory(new HttpClientConnectionFactory());
80 BuiltinLFS.register();
81 gcExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
82 private final ThreadFactory baseFactory = Executors
83 .defaultThreadFactory();
84
85 @Override
86 public Thread newThread(Runnable taskBody) {
87 Thread thr = baseFactory.newThread(taskBody);
88 thr.setName("JGit-autoGc");
89 return thr;
90 }
91 });
92 }
93
94
95
96
97
98
99
100
101 public static void main(String[] argv) throws Exception {
102
103 BuiltinLFS.register();
104
105 new Main().run(argv);
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 protected void run(String[] argv) throws Exception {
126 writer = createErrorWriter();
127 try {
128 if (!installConsole()) {
129 AwtAuthenticator.install();
130 AwtCredentialsProvider.install();
131 }
132 configureHttpProxy();
133 execute(argv);
134 } catch (Die err) {
135 if (err.isAborted()) {
136 exit(1, err);
137 }
138 writer.println(CLIText.fatalError(err.getMessage()));
139 if (showStackTrace) {
140 err.printStackTrace(writer);
141 }
142 exit(128, err);
143 } catch (Exception err) {
144
145
146
147
148 if (err.getClass() == IOException.class) {
149
150 if (err.getMessage().equals("Broken pipe")) {
151 exit(0, err);
152 }
153
154 if (err.getMessage().equals("The pipe is being closed")) {
155 exit(0, err);
156 }
157 }
158 if (!showStackTrace && err.getCause() != null
159 && err instanceof TransportException) {
160 writer.println(CLIText.fatalError(err.getCause().getMessage()));
161 }
162
163 if (err.getClass().getName().startsWith("org.eclipse.jgit.errors.")) {
164 writer.println(CLIText.fatalError(err.getMessage()));
165 if (showStackTrace) {
166 err.printStackTrace();
167 }
168 exit(128, err);
169 }
170 err.printStackTrace();
171 exit(1, err);
172 }
173 if (System.out.checkError()) {
174 writer.println(CLIText.get().unknownIoErrorStdout);
175 exit(1, null);
176 }
177 if (writer.checkError()) {
178
179
180 exit(1, null);
181 }
182 gcExecutor.shutdown();
183 gcExecutor.awaitTermination(10, TimeUnit.MINUTES);
184 }
185
186 PrintWriter createErrorWriter() {
187 return new PrintWriter(new OutputStreamWriter(System.err, UTF_8));
188 }
189
190 private void execute(String[] argv) throws Exception {
191 final CmdLineParser clp = new SubcommandLineParser(this);
192
193 try {
194 clp.parseArgument(argv);
195 } catch (CmdLineException err) {
196 if (argv.length > 0 && !help && !version) {
197 writer.println(CLIText.fatalError(err.getMessage()));
198 writer.flush();
199 exit(1, err);
200 }
201 }
202
203 if (argv.length == 0 || help) {
204 final String ex = clp.printExample(OptionHandlerFilter.ALL,
205 CLIText.get().resourceBundle());
206 writer.println("jgit" + ex + " command [ARG ...]");
207 if (help) {
208 writer.println();
209 clp.printUsage(writer, CLIText.get().resourceBundle());
210 writer.println();
211 } else if (subcommand == null) {
212 writer.println();
213 writer.println(CLIText.get().mostCommonlyUsedCommandsAre);
214 final CommandRef[] common = CommandCatalog.common();
215 int width = 0;
216 for (CommandRef c : common) {
217 width = Math.max(width, c.getName().length());
218 }
219 width += 2;
220
221 for (CommandRef c : common) {
222 writer.print(' ');
223 writer.print(c.getName());
224 for (int i = c.getName().length(); i < width; i++) {
225 writer.print(' ');
226 }
227 writer.print(CLIText.get().resourceBundle().getString(c.getUsage()));
228 writer.println();
229 }
230 writer.println();
231 }
232 writer.flush();
233 exit(1, null);
234 }
235
236 if (version) {
237 String cmdId = Version.class.getSimpleName()
238 .toLowerCase(Locale.ROOT);
239 subcommand = CommandCatalog.get(cmdId).create();
240 }
241
242 final TextBuiltin cmd = subcommand;
243 init(cmd);
244 try {
245 cmd.execute(arguments.toArray(new String[0]));
246 } finally {
247 if (cmd.outw != null) {
248 cmd.outw.flush();
249 }
250 if (cmd.errw != null) {
251 cmd.errw.flush();
252 }
253 }
254 }
255
256 void init(TextBuiltin cmd) throws IOException {
257 if (cmd.requiresRepository()) {
258 cmd.init(openGitDir(gitdir), null);
259 } else {
260 cmd.init(null, gitdir);
261 }
262 }
263
264
265
266
267
268
269
270 void exit(int status, Exception t) throws Exception {
271 writer.flush();
272 System.exit(status);
273 }
274
275
276
277
278
279
280
281
282
283
284
285 protected Repository openGitDir(String aGitdir) throws IOException {
286 RepositoryBuilder rb = new RepositoryBuilder()
287 .setGitDir(aGitdir != null ? new File(aGitdir) : null)
288 .readEnvironment()
289 .findGitDir();
290 if (rb.getGitDir() == null)
291 throw new Die(CLIText.get().cantFindGitDirectory);
292 return rb.build();
293 }
294
295 private static boolean installConsole() {
296 try {
297 install("org.eclipse.jgit.console.ConsoleAuthenticator");
298 install("org.eclipse.jgit.console.ConsoleCredentialsProvider");
299 return true;
300 } catch (ClassNotFoundException | NoClassDefFoundError
301 | UnsupportedClassVersionError e) {
302 return false;
303 } catch (IllegalArgumentException | SecurityException
304 | IllegalAccessException | InvocationTargetException
305 | NoSuchMethodException e) {
306 throw new RuntimeException(CLIText.get().cannotSetupConsole, e);
307 }
308 }
309
310 private static void install(String name)
311 throws IllegalAccessException, InvocationTargetException,
312 NoSuchMethodException, ClassNotFoundException {
313 try {
314 Class.forName(name).getMethod("install").invoke(null);
315 } catch (InvocationTargetException e) {
316 if (e.getCause() instanceof RuntimeException)
317 throw (RuntimeException) e.getCause();
318 if (e.getCause() instanceof Error)
319 throw (Error) e.getCause();
320 throw e;
321 }
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341 static void configureHttpProxy() throws MalformedURLException {
342 for (String protocol : new String[] { "http", "https" }) {
343 if (System.getProperty(protocol + ".proxyHost") != null) {
344 continue;
345 }
346 String s = System.getenv(protocol + "_proxy");
347 if (s == null && protocol.equals("https")) {
348 s = System.getenv("HTTPS_PROXY");
349 }
350 if (s == null || s.isEmpty()) {
351 continue;
352 }
353
354 final URL u = new URL(
355 (!s.contains("://")) ? protocol + "://" + s : s); //$NON-NLS-1$ //$NON-NLS-2$
356 if (!u.getProtocol().startsWith("http"))
357 throw new MalformedURLException(MessageFormat.format(
358 CLIText.get().invalidHttpProxyOnlyHttpSupported, s));
359
360 final String proxyHost = u.getHost();
361 final int proxyPort = u.getPort();
362
363 System.setProperty(protocol + ".proxyHost", proxyHost);
364 if (proxyPort > 0)
365 System.setProperty(protocol + ".proxyPort",
366 String.valueOf(proxyPort));
367
368 final String userpass = u.getUserInfo();
369 if (userpass != null && userpass.contains(":")) {
370 final int c = userpass.indexOf(':');
371 final String user = userpass.substring(0, c);
372 final String pass = userpass.substring(c + 1);
373 CachedAuthenticator.add(
374 new CachedAuthenticator.CachedAuthentication(proxyHost,
375 proxyPort, user, pass));
376 }
377 }
378 }
379
380
381
382
383
384 static class SubcommandLineParser extends CmdLineParser {
385 public SubcommandLineParser(Object bean) {
386 super(bean);
387 }
388
389 @Override
390 protected boolean containsHelp(String... args) {
391 return false;
392 }
393 }
394 }