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.opt;
45
46 import java.io.IOException;
47 import java.io.Writer;
48 import java.lang.reflect.Field;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.ResourceBundle;
54
55 import org.eclipse.jgit.lib.ObjectId;
56 import org.eclipse.jgit.lib.Repository;
57 import org.eclipse.jgit.pgm.Die;
58 import org.eclipse.jgit.pgm.TextBuiltin;
59 import org.eclipse.jgit.pgm.internal.CLIText;
60 import org.eclipse.jgit.revwalk.RevCommit;
61 import org.eclipse.jgit.revwalk.RevTree;
62 import org.eclipse.jgit.revwalk.RevWalk;
63 import org.eclipse.jgit.transport.RefSpec;
64 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
65 import org.kohsuke.args4j.Argument;
66 import org.kohsuke.args4j.CmdLineException;
67 import org.kohsuke.args4j.IllegalAnnotationError;
68 import org.kohsuke.args4j.NamedOptionDef;
69 import org.kohsuke.args4j.Option;
70 import org.kohsuke.args4j.OptionDef;
71 import org.kohsuke.args4j.spi.OptionHandler;
72 import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
73 import org.kohsuke.args4j.spi.Setter;
74
75
76
77
78
79
80
81
82
83 public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
84 static {
85 registerHandler(AbstractTreeIterator.class,
86 AbstractTreeIteratorHandler.class);
87 registerHandler(ObjectId.class, ObjectIdHandler.class);
88 registerHandler(RefSpec.class, RefSpecHandler.class);
89 registerHandler(RevCommit.class, RevCommitHandler.class);
90 registerHandler(RevTree.class, RevTreeHandler.class);
91 registerHandler(List.class, OptionWithValuesListHandler.class);
92 }
93
94 private final Repository db;
95
96 private RevWalk walk;
97
98 private boolean seenHelp;
99
100 private TextBuiltin cmd;
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public CmdLineParser(final Object bean) {
115 this(bean, null);
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131 public CmdLineParser(final Object bean, Repository repo) {
132 super(bean);
133 if (bean instanceof TextBuiltin) {
134 cmd = (TextBuiltin) bean;
135 }
136 if (repo == null && cmd != null) {
137 repo = cmd.getRepository();
138 }
139 this.db = repo;
140 }
141
142 @Override
143 public void parseArgument(final String... args) throws CmdLineException {
144 final ArrayList<String> tmp = new ArrayList<String>(args.length);
145 for (int argi = 0; argi < args.length; argi++) {
146 final String str = args[argi];
147 if (str.equals("--")) {
148 while (argi < args.length)
149 tmp.add(args[argi++]);
150 break;
151 }
152
153 if (str.startsWith("--")) {
154 final int eq = str.indexOf('=');
155 if (eq > 0) {
156 tmp.add(str.substring(0, eq));
157 tmp.add(str.substring(eq + 1));
158 continue;
159 }
160 }
161
162 tmp.add(str);
163
164 if (containsHelp(args)) {
165
166 seenHelp = true;
167
168 break;
169 }
170 }
171 List<OptionHandler> backup = null;
172 if (seenHelp) {
173 backup = unsetRequiredOptions();
174 }
175
176 try {
177 super.parseArgument(tmp.toArray(new String[tmp.size()]));
178 } catch (Die e) {
179 if (!seenHelp) {
180 throw e;
181 }
182 printToErrorWriter(CLIText.fatalError(e.getMessage()));
183 } finally {
184
185 if (backup != null && !backup.isEmpty()) {
186 restoreRequiredOptions(backup);
187 }
188 seenHelp = false;
189 }
190 }
191
192 private void printToErrorWriter(String error) {
193 if (cmd == null) {
194 System.err.println(error);
195 } else {
196 try {
197 cmd.getErrorWriter().println(error);
198 } catch (IOException e1) {
199 System.err.println(error);
200 }
201 }
202 }
203
204 private List<OptionHandler> unsetRequiredOptions() {
205 List<OptionHandler> options = getOptions();
206 List<OptionHandler> backup = new ArrayList<>(options);
207 for (Iterator<OptionHandler> iterator = options.iterator(); iterator
208 .hasNext();) {
209 OptionHandler handler = iterator.next();
210 if (handler.option instanceof NamedOptionDef
211 && handler.option.required()) {
212 iterator.remove();
213 }
214 }
215 return backup;
216 }
217
218 private void restoreRequiredOptions(List<OptionHandler> backup) {
219 List<OptionHandler> options = getOptions();
220 options.clear();
221 options.addAll(backup);
222 }
223
224
225
226
227
228
229
230 protected boolean containsHelp(final String... args) {
231 return TextBuiltin.containsHelp(args);
232 }
233
234
235
236
237
238
239 public Repository getRepository() {
240 if (db == null)
241 throw new IllegalStateException(CLIText.get().noGitRepositoryConfigured);
242 return db;
243 }
244
245
246
247
248
249
250 public RevWalk getRevWalk() {
251 if (walk == null)
252 walk = new RevWalk(getRepository());
253 return walk;
254 }
255
256
257
258
259
260
261
262
263 public RevWalk getRevWalkGently() {
264 return walk;
265 }
266
267 class MyOptionDef extends OptionDef {
268
269 public MyOptionDef(OptionDef o) {
270 super(o.usage(), o.metaVar(), o.required(), o.handler(), o
271 .isMultiValued());
272 }
273
274 @Override
275 public String toString() {
276 if (metaVar() == null)
277 return "ARG";
278 try {
279 Field field = CLIText.class.getField(metaVar());
280 String ret = field.get(CLIText.get()).toString();
281 return ret;
282 } catch (Exception e) {
283 e.printStackTrace(System.err);
284 return metaVar();
285 }
286 }
287
288 @Override
289 public boolean required() {
290 return seenHelp ? false : super.required();
291 }
292 }
293
294 @Override
295 protected OptionHandler createOptionHandler(OptionDef o, Setter setter) {
296 if (o instanceof NamedOptionDef)
297 return super.createOptionHandler(o, setter);
298 else
299 return super.createOptionHandler(new MyOptionDef(o), setter);
300
301 }
302
303 @SuppressWarnings("unchecked")
304 private List<OptionHandler> getOptions() {
305 List<OptionHandler> options = null;
306 try {
307 Field field = org.kohsuke.args4j.CmdLineParser.class
308 .getDeclaredField("options");
309 field.setAccessible(true);
310 options = (List<OptionHandler>) field.get(this);
311 } catch (NoSuchFieldException | SecurityException
312 | IllegalArgumentException | IllegalAccessException e) {
313
314 }
315 if (options == null) {
316 return Collections.emptyList();
317 }
318 return options;
319 }
320
321 @Override
322 public void printSingleLineUsage(Writer w, ResourceBundle rb) {
323 List<OptionHandler> options = getOptions();
324 if (options.isEmpty()) {
325 super.printSingleLineUsage(w, rb);
326 return;
327 }
328 List<OptionHandler> backup = new ArrayList<>(options);
329 boolean changed = sortRestOfArgumentsHandlerToTheEnd(options);
330 try {
331 super.printSingleLineUsage(w, rb);
332 } finally {
333 if (changed) {
334 options.clear();
335 options.addAll(backup);
336 }
337 }
338 }
339
340 private boolean sortRestOfArgumentsHandlerToTheEnd(
341 List<OptionHandler> options) {
342 for (int i = 0; i < options.size(); i++) {
343 OptionHandler handler = options.get(i);
344 if (handler instanceof RestOfArgumentsHandler
345 || handler instanceof PathTreeFilterHandler) {
346 options.remove(i);
347 options.add(handler);
348 return true;
349 }
350 }
351 return false;
352 }
353 }