1 /*
2 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
3 * and other copyright owners as documented in the project's IP log.
4 *
5 * This program and the accompanying materials are made available
6 * under the terms of the Eclipse Distribution License v1.0 which
7 * accompanies this distribution, is reproduced below, and is
8 * available at http://www.eclipse.org/org/documents/edl-v10.php
9 *
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials provided
22 * with the distribution.
23 *
24 * - Neither the name of the Eclipse Foundation, Inc. nor the
25 * names of its contributors may be used to endorse or promote
26 * products derived from this software without specific prior
27 * written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 package org.eclipse.jgit.pgm.opt;
45
46 import java.lang.reflect.Field;
47 import java.util.ArrayList;
48
49 import org.kohsuke.args4j.Argument;
50 import org.kohsuke.args4j.CmdLineException;
51 import org.kohsuke.args4j.IllegalAnnotationError;
52 import org.kohsuke.args4j.NamedOptionDef;
53 import org.kohsuke.args4j.Option;
54 import org.kohsuke.args4j.OptionDef;
55 import org.kohsuke.args4j.spi.OptionHandler;
56 import org.kohsuke.args4j.spi.Setter;
57 import org.eclipse.jgit.lib.ObjectId;
58 import org.eclipse.jgit.lib.Repository;
59 import org.eclipse.jgit.pgm.TextBuiltin;
60 import org.eclipse.jgit.pgm.internal.CLIText;
61 import org.eclipse.jgit.revwalk.RevCommit;
62 import org.eclipse.jgit.revwalk.RevTree;
63 import org.eclipse.jgit.revwalk.RevWalk;
64 import org.eclipse.jgit.transport.RefSpec;
65 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
66
67 /**
68 * Extended command line parser which handles --foo=value arguments.
69 * <p>
70 * The args4j package does not natively handle --foo=value and instead prefers
71 * to see --foo value on the command line. Many users are used to the GNU style
72 * --foo=value long option, so we convert from the GNU style format to the
73 * args4j style format prior to invoking args4j for parsing.
74 */
75 public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
76 static {
77 registerHandler(AbstractTreeIterator.class,
78 AbstractTreeIteratorHandler.class);
79 registerHandler(ObjectId.class, ObjectIdHandler.class);
80 registerHandler(RefSpec.class, RefSpecHandler.class);
81 registerHandler(RevCommit.class, RevCommitHandler.class);
82 registerHandler(RevTree.class, RevTreeHandler.class);
83 }
84
85 private final Repository db;
86
87 private RevWalk walk;
88
89 /**
90 * Creates a new command line owner that parses arguments/options and set
91 * them into the given object.
92 *
93 * @param bean
94 * instance of a class annotated by {@link Option} and
95 * {@link Argument}. this object will receive values.
96 *
97 * @throws IllegalAnnotationError
98 * if the option bean class is using args4j annotations
99 * incorrectly.
100 */
101 public CmdLineParser(final Object bean) {
102 this(bean, null);
103 }
104
105 /**
106 * Creates a new command line owner that parses arguments/options and set
107 * them into the given object.
108 *
109 * @param bean
110 * instance of a class annotated by {@link Option} and
111 * {@link Argument}. this object will receive values.
112 * @param repo
113 * repository this parser can translate options through.
114 * @throws IllegalAnnotationError
115 * if the option bean class is using args4j annotations
116 * incorrectly.
117 */
118 public CmdLineParser(final Object bean, Repository repo) {
119 super(bean);
120 if (repo == null && bean instanceof TextBuiltin)
121 repo = ((TextBuiltin) bean).getRepository();
122 this.db = repo;
123 }
124
125 @Override
126 public void parseArgument(final String... args) throws CmdLineException {
127 final ArrayList<String> tmp = new ArrayList<String>(args.length);
128 for (int argi = 0; argi < args.length; argi++) {
129 final String str = args[argi];
130 if (str.equals("--")) { //$NON-NLS-1$
131 while (argi < args.length)
132 tmp.add(args[argi++]);
133 break;
134 }
135
136 if (str.startsWith("--")) { //$NON-NLS-1$
137 final int eq = str.indexOf('=');
138 if (eq > 0) {
139 tmp.add(str.substring(0, eq));
140 tmp.add(str.substring(eq + 1));
141 continue;
142 }
143 }
144
145 tmp.add(str);
146 }
147
148 super.parseArgument(tmp.toArray(new String[tmp.size()]));
149 }
150
151 /**
152 * Get the repository this parser translates values through.
153 *
154 * @return the repository, if specified during construction.
155 */
156 public Repository getRepository() {
157 if (db == null)
158 throw new IllegalStateException(CLIText.get().noGitRepositoryConfigured);
159 return db;
160 }
161
162 /**
163 * Get the revision walker used to support option parsing.
164 *
165 * @return the revision walk used by this option parser.
166 */
167 public RevWalk getRevWalk() {
168 if (walk == null)
169 walk = new RevWalk(getRepository());
170 return walk;
171 }
172
173 /**
174 * Get the revision walker used to support option parsing.
175 * <p>
176 * This method does not initialize the RevWalk and may return null.
177 *
178 * @return the revision walk used by this option parser, or null.
179 */
180 public RevWalk getRevWalkGently() {
181 return walk;
182 }
183
184 static class MyOptionDef extends OptionDef {
185
186 public MyOptionDef(OptionDef o) {
187 super(o.usage(), o.metaVar(), o.required(), o.handler(), o
188 .isMultiValued());
189 }
190
191 @Override
192 public String toString() {
193 if (metaVar() == null)
194 return "ARG"; //$NON-NLS-1$
195 try {
196 Field field = CLIText.class.getField(metaVar());
197 String ret = field.get(CLIText.get()).toString();
198 return ret;
199 } catch (Exception e) {
200 e.printStackTrace(System.err);
201 return metaVar();
202 }
203 }
204 }
205
206 @Override
207 protected OptionHandler createOptionHandler(OptionDef o, Setter setter) {
208 if (o instanceof NamedOptionDef)
209 return super.createOptionHandler(o, setter);
210 else
211 return super.createOptionHandler(new MyOptionDef(o), setter);
212
213 }
214 }