Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

TextBuiltin.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
  3. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  4. * and other copyright owners as documented in the project's IP log.
  5. *
  6. * This program and the accompanying materials are made available
  7. * under the terms of the Eclipse Distribution License v1.0 which
  8. * accompanies this distribution, is reproduced below, and is
  9. * available at http://www.eclipse.org/org/documents/edl-v10.php
  10. *
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or
  14. * without modification, are permitted provided that the following
  15. * conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. *
  20. * - Redistributions in binary form must reproduce the above
  21. * copyright notice, this list of conditions and the following
  22. * disclaimer in the documentation and/or other materials provided
  23. * with the distribution.
  24. *
  25. * - Neither the name of the Eclipse Foundation, Inc. nor the
  26. * names of its contributors may be used to endorse or promote
  27. * products derived from this software without specific prior
  28. * written permission.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  31. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  32. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  33. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  35. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  39. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  42. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43. */
  44. package org.eclipse.jgit.pgm;
  45. import static org.eclipse.jgit.lib.Constants.R_HEADS;
  46. import static org.eclipse.jgit.lib.Constants.R_REMOTES;
  47. import static org.eclipse.jgit.lib.Constants.R_TAGS;
  48. import java.io.BufferedWriter;
  49. import java.io.FileDescriptor;
  50. import java.io.FileInputStream;
  51. import java.io.FileOutputStream;
  52. import java.io.IOException;
  53. import java.io.InputStream;
  54. import java.io.OutputStream;
  55. import java.io.OutputStreamWriter;
  56. import java.text.MessageFormat;
  57. import java.util.ResourceBundle;
  58. import org.eclipse.jgit.lib.ObjectId;
  59. import org.eclipse.jgit.lib.Repository;
  60. import org.eclipse.jgit.pgm.internal.CLIText;
  61. import org.eclipse.jgit.pgm.opt.CmdLineParser;
  62. import org.eclipse.jgit.revwalk.RevWalk;
  63. import org.eclipse.jgit.util.io.ThrowingPrintWriter;
  64. import org.kohsuke.args4j.CmdLineException;
  65. import org.kohsuke.args4j.Option;
  66. /**
  67. * Abstract command which can be invoked from the command line.
  68. * <p>
  69. * Commands are configured with a single "current" repository and then the
  70. * {@link #execute(String[])} method is invoked with the arguments that appear
  71. * on the command line after the command name.
  72. * <p>
  73. * Command constructors should perform as little work as possible as they may be
  74. * invoked very early during process loading, and the command may not execute
  75. * even though it was constructed.
  76. */
  77. public abstract class TextBuiltin {
  78. private String commandName;
  79. @Option(name = "--help", usage = "usage_displayThisHelpText", aliases = { "-h" })
  80. private boolean help;
  81. /**
  82. * Input stream, typically this is standard input.
  83. *
  84. * @since 3.4
  85. */
  86. protected InputStream ins;
  87. /**
  88. * Writer to output to, typically this is standard output.
  89. *
  90. * @since 2.2
  91. */
  92. protected ThrowingPrintWriter outw;
  93. /**
  94. * Stream to output to, typically this is standard output.
  95. *
  96. * @since 2.2
  97. */
  98. protected OutputStream outs;
  99. /**
  100. * Error writer, typically this is standard error.
  101. *
  102. * @since 3.4
  103. */
  104. protected ThrowingPrintWriter errw;
  105. /**
  106. * Error output stream, typically this is standard error.
  107. *
  108. * @since 3.4
  109. */
  110. protected OutputStream errs;
  111. /** Git repository the command was invoked within. */
  112. protected Repository db;
  113. /** Directory supplied via --git-dir command line option. */
  114. protected String gitdir;
  115. /** RevWalk used during command line parsing, if it was required. */
  116. protected RevWalk argWalk;
  117. final void setCommandName(final String name) {
  118. commandName = name;
  119. }
  120. /**
  121. * If this command requires a repository.
  122. *
  123. * @return true if {@link #db}/{@link #getRepository()} is required
  124. */
  125. protected boolean requiresRepository() {
  126. return true;
  127. }
  128. /**
  129. * Initializes the command to work with a repository, including setting the
  130. * output and error streams.
  131. *
  132. * @param repository
  133. * the opened repository that the command should work on.
  134. * @param gitDir
  135. * value of the {@code --git-dir} command line option, if
  136. * {@code repository} is null.
  137. * @param input
  138. * input stream from which input will be read
  139. * @param output
  140. * output stream to which output will be written
  141. * @param error
  142. * error stream to which errors will be written
  143. * @since 4.9
  144. */
  145. public void initRaw(final Repository repository, final String gitDir,
  146. InputStream input, OutputStream output, OutputStream error) {
  147. this.ins = input;
  148. this.outs = output;
  149. this.errs = error;
  150. init(repository, gitDir);
  151. }
  152. /**
  153. * Initialize the command to work with a repository.
  154. *
  155. * @param repository
  156. * the opened repository that the command should work on.
  157. * @param gitDir
  158. * value of the {@code --git-dir} command line option, if
  159. * {@code repository} is null.
  160. */
  161. protected void init(Repository repository, String gitDir) {
  162. try {
  163. final String outputEncoding = repository != null ? repository
  164. .getConfig().getString("i18n", null, "logOutputEncoding") : null; //$NON-NLS-1$ //$NON-NLS-2$
  165. if (ins == null)
  166. ins = new FileInputStream(FileDescriptor.in);
  167. if (outs == null)
  168. outs = new FileOutputStream(FileDescriptor.out);
  169. if (errs == null)
  170. errs = new FileOutputStream(FileDescriptor.err);
  171. BufferedWriter outbufw;
  172. if (outputEncoding != null)
  173. outbufw = new BufferedWriter(new OutputStreamWriter(outs,
  174. outputEncoding));
  175. else
  176. outbufw = new BufferedWriter(new OutputStreamWriter(outs));
  177. outw = new ThrowingPrintWriter(outbufw);
  178. BufferedWriter errbufw;
  179. if (outputEncoding != null)
  180. errbufw = new BufferedWriter(new OutputStreamWriter(errs,
  181. outputEncoding));
  182. else
  183. errbufw = new BufferedWriter(new OutputStreamWriter(errs));
  184. errw = new ThrowingPrintWriter(errbufw);
  185. } catch (IOException e) {
  186. throw die(CLIText.get().cannotCreateOutputStream);
  187. }
  188. if (repository != null && repository.getDirectory() != null) {
  189. db = repository;
  190. gitdir = repository.getDirectory().getAbsolutePath();
  191. } else {
  192. db = repository;
  193. gitdir = gitDir;
  194. }
  195. }
  196. /**
  197. * Parse arguments and run this command.
  198. *
  199. * @param args
  200. * command line arguments passed after the command name.
  201. * @throws java.lang.Exception
  202. * an error occurred while processing the command. The main
  203. * framework will catch the exception and print a message on
  204. * standard error.
  205. */
  206. public final void execute(String[] args) throws Exception {
  207. parseArguments(args);
  208. run();
  209. }
  210. /**
  211. * Parses the command line arguments prior to running.
  212. * <p>
  213. * This method should only be invoked by {@link #execute(String[])}, prior
  214. * to calling {@link #run()}. The default implementation parses all
  215. * arguments into this object's instance fields.
  216. *
  217. * @param args
  218. * the arguments supplied on the command line, if any.
  219. * @throws java.io.IOException
  220. */
  221. protected void parseArguments(String[] args) throws IOException {
  222. final CmdLineParser clp = new CmdLineParser(this);
  223. help = containsHelp(args);
  224. try {
  225. clp.parseArgument(args);
  226. } catch (CmdLineException err) {
  227. this.errw.println(CLIText.fatalError(err.getMessage()));
  228. if (help) {
  229. printUsage("", clp); //$NON-NLS-1$
  230. }
  231. throw die(true, err);
  232. }
  233. if (help) {
  234. printUsage("", clp); //$NON-NLS-1$
  235. throw new TerminatedByHelpException();
  236. }
  237. argWalk = clp.getRevWalkGently();
  238. }
  239. /**
  240. * Print the usage line
  241. *
  242. * @param clp
  243. * a {@link org.eclipse.jgit.pgm.opt.CmdLineParser} object.
  244. * @throws java.io.IOException
  245. */
  246. public void printUsageAndExit(CmdLineParser clp) throws IOException {
  247. printUsageAndExit("", clp); //$NON-NLS-1$
  248. }
  249. /**
  250. * Print an error message and the usage line
  251. *
  252. * @param message
  253. * a {@link java.lang.String} object.
  254. * @param clp
  255. * a {@link org.eclipse.jgit.pgm.opt.CmdLineParser} object.
  256. * @throws java.io.IOException
  257. */
  258. public void printUsageAndExit(String message, CmdLineParser clp) throws IOException {
  259. printUsage(message, clp);
  260. throw die(true);
  261. }
  262. /**
  263. * Print usage help text.
  264. *
  265. * @param message
  266. * non null
  267. * @param clp
  268. * parser used to print options
  269. * @throws java.io.IOException
  270. * @since 4.2
  271. */
  272. protected void printUsage(String message, CmdLineParser clp)
  273. throws IOException {
  274. errw.println(message);
  275. errw.print("jgit "); //$NON-NLS-1$
  276. errw.print(commandName);
  277. clp.printSingleLineUsage(errw, getResourceBundle());
  278. errw.println();
  279. errw.println();
  280. clp.printUsage(errw, getResourceBundle());
  281. errw.println();
  282. errw.flush();
  283. }
  284. /**
  285. * Get error writer
  286. *
  287. * @return error writer, typically this is standard error.
  288. * @since 4.2
  289. */
  290. public ThrowingPrintWriter getErrorWriter() {
  291. return errw;
  292. }
  293. /**
  294. * Get output writer
  295. *
  296. * @return output writer, typically this is standard output.
  297. * @since 4.9
  298. */
  299. public ThrowingPrintWriter getOutputWriter() {
  300. return outw;
  301. }
  302. /**
  303. * Get resource bundle with localized texts
  304. *
  305. * @return the resource bundle that will be passed to args4j for purpose of
  306. * string localization
  307. */
  308. protected ResourceBundle getResourceBundle() {
  309. return CLIText.get().resourceBundle();
  310. }
  311. /**
  312. * Perform the actions of this command.
  313. * <p>
  314. * This method should only be invoked by {@link #execute(String[])}.
  315. *
  316. * @throws java.lang.Exception
  317. * an error occurred while processing the command. The main
  318. * framework will catch the exception and print a message on
  319. * standard error.
  320. */
  321. protected abstract void run() throws Exception;
  322. /**
  323. * Get the repository
  324. *
  325. * @return the repository this command accesses.
  326. */
  327. public Repository getRepository() {
  328. return db;
  329. }
  330. ObjectId resolve(final String s) throws IOException {
  331. final ObjectId r = db.resolve(s);
  332. if (r == null)
  333. throw die(MessageFormat.format(CLIText.get().notARevision, s));
  334. return r;
  335. }
  336. /**
  337. * Exit the command with an error message
  338. *
  339. * @param why
  340. * textual explanation
  341. * @return a runtime exception the caller is expected to throw
  342. */
  343. protected static Die die(String why) {
  344. return new Die(why);
  345. }
  346. /**
  347. * Exit the command with an error message and an exception
  348. *
  349. * @param why
  350. * textual explanation
  351. * @param cause
  352. * why the command has failed.
  353. * @return a runtime exception the caller is expected to throw
  354. */
  355. protected static Die die(String why, Throwable cause) {
  356. return new Die(why, cause);
  357. }
  358. /**
  359. * Exit the command
  360. *
  361. * @param aborted
  362. * boolean indicating that the execution has been aborted before
  363. * running
  364. * @return a runtime exception the caller is expected to throw
  365. * @since 3.4
  366. */
  367. protected static Die die(boolean aborted) {
  368. return new Die(aborted);
  369. }
  370. /**
  371. * Exit the command
  372. *
  373. * @param aborted
  374. * boolean indicating that the execution has been aborted before
  375. * running
  376. * @param cause
  377. * why the command has failed.
  378. * @return a runtime exception the caller is expected to throw
  379. * @since 4.2
  380. */
  381. protected static Die die(boolean aborted, Throwable cause) {
  382. return new Die(aborted, cause);
  383. }
  384. String abbreviateRef(String dst, boolean abbreviateRemote) {
  385. if (dst.startsWith(R_HEADS))
  386. dst = dst.substring(R_HEADS.length());
  387. else if (dst.startsWith(R_TAGS))
  388. dst = dst.substring(R_TAGS.length());
  389. else if (abbreviateRemote && dst.startsWith(R_REMOTES))
  390. dst = dst.substring(R_REMOTES.length());
  391. return dst;
  392. }
  393. /**
  394. * Check if the arguments contain a help option
  395. *
  396. * @param args
  397. * non null
  398. * @return true if the given array contains help option
  399. * @since 4.2
  400. */
  401. public static boolean containsHelp(String[] args) {
  402. for (String str : args) {
  403. if (str.equals("-h") || str.equals("--help")) { //$NON-NLS-1$ //$NON-NLS-2$
  404. return true;
  405. }
  406. }
  407. return false;
  408. }
  409. /**
  410. * Exception thrown by {@link TextBuiltin} if it proceeds 'help' option
  411. *
  412. * @since 4.2
  413. */
  414. public static class TerminatedByHelpException extends Die {
  415. private static final long serialVersionUID = 1L;
  416. /**
  417. * Default constructor
  418. */
  419. public TerminatedByHelpException() {
  420. super(true);
  421. }
  422. }
  423. }