KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > cvsclient > commandLine > CVSCommand


1 /*****************************************************************************
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is the CVS Client Library.
16  * The Initial Developer of the Original Software is Robert Greig.
17  * Portions created by Robert Greig are Copyright (C) 2000.
18  * All Rights Reserved.
19  *
20  * Contributor(s): Robert Greig.
21  *****************************************************************************/

22 package org.netbeans.lib.cvsclient.commandLine;
23
24 import java.io.*;
25 import java.text.MessageFormat JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.Comparator JavaDoc;
28 import java.util.ResourceBundle JavaDoc;
29
30 import org.netbeans.lib.cvsclient.*;
31 import org.netbeans.lib.cvsclient.CVSRoot;
32 import org.netbeans.lib.cvsclient.admin.*;
33 import org.netbeans.lib.cvsclient.command.*;
34 import org.netbeans.lib.cvsclient.commandLine.command.CommandProvider;
35 import org.netbeans.lib.cvsclient.connection.*;
36 import org.netbeans.lib.cvsclient.connection.StandardScrambler;
37 import org.netbeans.lib.cvsclient.event.CVSListener;
38
39 /**
40  * An implementation of the standard CVS client utility (command line tool)
41  * in Java
42  * @author Robert Greig
43  */

44 public class CVSCommand {
45     
46     private static final String JavaDoc HELP_OPTIONS = "--help-options"; // NOI18N
47
private static final String JavaDoc HELP_COMMANDS = "--help-commands"; // NOI18N
48
private static final String JavaDoc HELP_SYNONYMS = "--help-synonyms"; // NOI18N
49

50     /**
51      * The path to the repository on the server
52      */

53     private String JavaDoc repository;
54
55     /**
56      * The local path to use to perform operations (the top level)
57      */

58     private String JavaDoc localPath;
59
60     /**
61      * The connection to the server
62      */

63     private Connection connection;
64
65     /**
66      * The client that manages interactions with the server
67      */

68     private Client client;
69
70     /**
71      * The global options being used. GlobalOptions are only global for a
72      * particular command.
73      */

74     private GlobalOptions globalOptions;
75     
76     /**
77      * The port number that is used to connect to the remote server.
78      * It is taken into account only when it's value is greater then zero.
79      */

80     private int port = 0;
81
82     /**
83      * Execute a configured CVS command
84      * @param command the command to execute
85      * @throws CommandException if there is an error running the command
86      */

87     public boolean executeCommand(Command command, PrintStream stderr)
88             throws CommandException, AuthenticationException {
89         client.setErrorStream(stderr);
90         return client.executeCommand(command, globalOptions);
91     }
92
93     public void setRepository(String JavaDoc repository) {
94         this.repository = repository;
95     }
96
97     public void setLocalPath(String JavaDoc localPath) {
98         this.localPath = localPath;
99     }
100
101     public void setGlobalOptions(GlobalOptions globalOptions) {
102         this.globalOptions = globalOptions;
103     }
104
105     /**
106      * Creates the connection and the client and connects.
107      */

108     private void connect(CVSRoot root, String JavaDoc password) throws IllegalArgumentException JavaDoc,
109                                                                AuthenticationException,
110                                                                CommandAbortedException {
111         connection = ConnectionFactory.getConnection(root);
112         if (CVSRoot.METHOD_PSERVER.equals(root.getMethod())) {
113             ((PServerConnection) connection).setEncodedPassword(password);
114             if (port > 0) ((PServerConnection) connection).setPort(port);
115         }
116         connection.open();
117         
118         client = new Client(connection, new StandardAdminHandler());
119         client.setLocalPath(localPath);
120     }
121     
122     private void addListener(CVSListener listener) {
123         if (client != null) {
124             // add a listener to the client
125
client.getEventManager().addCVSListener(listener);
126         }
127     }
128
129     private void close(PrintStream stderr) {
130         try {
131             connection.close();
132         }
133         catch (IOException e) {
134             stderr.println("Unable to close connection: " + e);
135             //e.printStackTrace();
136
}
137     }
138
139     /**
140      * Obtain the CVS root, either from the -D option cvs.root or from
141      * the CVS directory
142      * @return the CVSRoot string
143      */

144     private static String JavaDoc getCVSRoot(String JavaDoc workingDir) {
145         String JavaDoc root = null;
146         BufferedReader r = null;
147         if (workingDir == null) {
148             workingDir = System.getProperty("user.dir");
149         }
150         try {
151             File f = new File(workingDir);
152             File rootFile = new File(f, "CVS/Root");
153             if (rootFile.exists()) {
154                 r = new BufferedReader(new FileReader(rootFile));
155                 root = r.readLine();
156             }
157         }
158         catch (IOException e) {
159             // ignore
160
}
161         finally {
162             try {
163                 if (r != null)
164                     r.close();
165             }
166             catch (IOException e) {
167                 System.err.println("Warning: could not close CVS/Root file!");
168             }
169         }
170         if (root == null) {
171             root = System.getProperty("cvs.root");
172         }
173         return root;
174     }
175
176     /**
177      * Process global options passed into the application
178      * @param args the argument list, complete
179      * @param globalOptions the global options structure that will be passed
180      * to the command
181      */

182     private static int processGlobalOptions(String JavaDoc[] args,
183                                             GlobalOptions globalOptions,
184                                             PrintStream stderr) {
185         final String JavaDoc getOptString = globalOptions.getOptString();
186         GetOpt go = new GetOpt(args, getOptString);
187         int ch = -1;
188         boolean usagePrint = false;
189         while ((ch = go.getopt()) != go.optEOF) {
190             //System.out.println("Global option '"+((char) ch)+"', '"+go.optArgGet()+"'");
191
boolean success = globalOptions.setCVSCommand((char) ch, go.optArgGet());
192             if (!success) usagePrint = true;
193         }
194         if (usagePrint) {
195             showUsage(stderr);
196             return -10;
197         }
198         return go.optIndexGet();
199     }
200
201     private static void showUsage(PrintStream stderr) {
202         String JavaDoc usageStr = ResourceBundle.getBundle(CVSCommand.class.getPackage().getName()+".Bundle").getString("MSG_HelpUsage"); // NOI18N
203
stderr.println(MessageFormat.format(usageStr, new Object JavaDoc[] { HELP_OPTIONS, HELP_COMMANDS, HELP_SYNONYMS }));
204         //stderr.println("Usage: cvs [global options] command [command-options-and-arguments]");
205
//stderr.println(" specify "+HELP_OPTIONS+" for a list of options");
206
//stderr.println(" specify "+HELP_COMMANDS+" for a list of commands");
207
//stderr.println(" specify "+HELP_SYNONYMS+" for a list of command synonyms");
208
}
209
210     /**
211      * Perform the 'login' command, asking the user for a password. If the
212      * login is successful, the password is written to a file. The file's
213      * location is user.home, unless the cvs.passfile option is set.
214      * @param userName the userName
215      * @param hostName the host
216      */

217     private static boolean performLogin(String JavaDoc userName, String JavaDoc hostName,
218                                         String JavaDoc repository, int port,
219                                         GlobalOptions globalOptions) {
220         PServerConnection c = new PServerConnection();
221         c.setUserName(userName);
222         String JavaDoc password = null;
223         try {
224             BufferedReader in = new BufferedReader(new
225                     InputStreamReader(System.in));
226             System.out.print("Enter password: ");
227             password = in.readLine();
228         }
229         catch (IOException e) {
230             System.err.println("Could not read password: " + e);
231             return false;
232         }
233
234         String JavaDoc encodedPassword = StandardScrambler.getInstance().scramble(
235                 password);
236         c.setEncodedPassword(encodedPassword);
237         c.setHostName(hostName);
238         c.setRepository(repository);
239         c.setPort(port);
240         try {
241             c.verify();
242         }
243         catch (AuthenticationException e) {
244             System.err.println("Could not login to host " + hostName);
245             return false;
246         }
247         // was successful, so write the appropriate file out
248
// we look for cvs.passfile being set, but if not use user.dir
249
// as the default
250
String JavaDoc root = globalOptions.getCVSRoot();
251         try {
252             PasswordsFile.storePassword(root, encodedPassword);
253             System.err.println("Logged in successfully to " + repository + " on host " + hostName);
254             return true;
255         } catch (IOException e) {
256             System.err.println("Error: could not write password file.");
257             return false;
258         }
259
260     }
261
262     /**
263      * Lookup the password in the .cvspass file. This file is looked for
264      * in the user.home directory if the option cvs.passfile is not set
265      * @param CVSRoot the CVS root for which the password is being searched
266      * @return the password, scrambled
267      */

268     private static String JavaDoc lookupPassword(String JavaDoc CVSRoot, String JavaDoc CVSRootWithPort, PrintStream stderr) {
269         File passFile = new File(System.getProperty("cvs.passfile",
270                                                     System.getProperty("user.home") +
271                                                     "/.cvspass"));
272
273         BufferedReader reader = null;
274         String JavaDoc password = null;
275
276         try {
277             reader = new BufferedReader(new FileReader(passFile));
278             String JavaDoc line;
279             while ((line = reader.readLine()) != null) {
280                 if (line.startsWith("/1 ")) line = line.substring("/1 ".length());
281                 if (line.startsWith(CVSRoot+" ")) {
282                     password = line.substring(CVSRoot.length() + 1);
283                     break;
284                 } else if (line.startsWith(CVSRootWithPort+" ")) {
285                     password = line.substring(CVSRootWithPort.length() + 1);
286                     break;
287                 }
288             }
289         }
290         catch (IOException e) {
291             stderr.println("Could not read password for host: " + e);
292             return null;
293         }
294         finally {
295             if (reader != null) {
296                 try {
297                     reader.close();
298                 }
299                 catch (IOException e) {
300                     stderr.println("Warning: could not close password file.");
301                 }
302             }
303         }
304         if (password == null) {
305             stderr.println("Didn't find password for CVSROOT '"+CVSRoot+"'.");
306         }
307         return password;
308     }
309
310     /**
311      * Execute the CVS command and exit JVM.
312      */

313     public static void main(String JavaDoc[] args) {
314         if (processCommand(args, null, System.getProperty("user.dir"),
315                            System.out, System.err)) {
316             System.exit(0);
317         } else {
318             System.exit(1);
319         }
320     }
321     
322     /**
323      * Process the CVS command passed in args[] array with all necessary options.
324      * The only difference from main() method is, that this method does not exit
325      * the JVM and provides command output.
326      * @param args The command with options
327      * @param files The files to execute the command on.
328      * @param localPath The local working directory
329      * @param stdout The standard output of the command
330      * @param stderr The error output of the command.
331      */

332     public static boolean processCommand(String JavaDoc[] args, File[] files, String JavaDoc localPath,
333                                          PrintStream stdout, PrintStream stderr) {
334         return processCommand(args, files, localPath, 0, stdout, stderr);
335     }
336     
337     /**
338      * Process the CVS command passed in args[] array with all necessary options.
339      * The only difference from main() method is, that this method does not exit
340      * the JVM and provides command output.
341      * @param args The command with options
342      * @param files The files to execute the command on.
343      * @param localPath The local working directory
344      * @param port The port number that is used to connect to the remote server.
345      * It is taken into account only when it's value is greater then zero.
346      * @param stdout The standard output of the command
347      * @param stderr The error output of the command.
348      * @return whether the command was processed successfully
349      */

350     public static boolean processCommand(String JavaDoc[] args, File[] files, String JavaDoc localPath,
351                                          int port, PrintStream stdout, PrintStream stderr) {
352         assert stdout != null: "The output stream must be defined."; // NOI18N
353
assert stderr != null: "The error stream must be defined."; // NOI18N
354
// Provide help if requested
355
if (args.length > 0) {
356             if (HELP_OPTIONS.equals(args[0])) {
357                 printHelpOptions(stdout);
358                 return true;
359             } else if (HELP_COMMANDS.equals(args[0])) {
360                 printHelpCommands(stdout);
361                 return true;
362             } else if (HELP_SYNONYMS.equals(args[0])) {
363                 printHelpSynonyms(stdout);
364                 return true;
365             }
366         }
367         try { // Adjust the local path
368
localPath = new File(localPath).getCanonicalPath();
369         } catch (IOException ioex) {}
370         // Set up the CVSRoot. Note that it might still be null after this
371
// call if the user has decided to set it with the -d command line
372
// global option
373
GlobalOptions globalOptions = new GlobalOptions();
374         globalOptions.setCVSRoot(getCVSRoot(localPath));
375
376         // Set up any global options specified. These occur before the
377
// name of the command to run
378
int commandIndex = -1;
379         try {
380             commandIndex = processGlobalOptions(args, globalOptions, stderr);
381             if (commandIndex == -10) return true;
382         }
383         catch (IllegalArgumentException JavaDoc e) {
384             stderr.println("Invalid argument: " + e);
385             return false;
386         }
387         
388         if (globalOptions.isShowHelp()) {
389             printHelp(commandIndex, args, stdout, stderr);
390             return true;
391         }
392         
393         if (globalOptions.isShowVersion()) {
394             printVersion(stdout, stderr);
395             return true;
396         }
397
398         // if we don't have a CVS root by now, the user has messed up
399
if (globalOptions.getCVSRoot() == null) {
400             stderr.println("No CVS root is set. Use the cvs.root " +
401                            "property, e.g. java -Dcvs.root=\":pserver:user@host:/usr/cvs\"" +
402                            " or start the application in a directory containing a CVS subdirectory" +
403                            " or use the -d command switch.");
404             return false;
405         }
406
407         // parse the CVS root into its constituent parts
408
CVSRoot root = null;
409         final String JavaDoc cvsRoot = globalOptions.getCVSRoot();
410         try {
411             root = CVSRoot.parse(cvsRoot);
412         }
413         catch (IllegalArgumentException JavaDoc e) {
414             stderr.println("Incorrect format for CVSRoot: " + cvsRoot +
415                            "\nThe correct format is: "+
416                            "[:method:][[user][:password]@][hostname:[port]]/path/to/repository" +
417                            "\nwhere \"method\" is pserver.");
418             return false;
419         }
420
421         // if we had some options without any command, then the user messed up
422
if (commandIndex >= args.length) {
423             showUsage(stderr);
424             return false;
425         }
426
427         final String JavaDoc command = args[commandIndex];
428         if (command.equals("login")) {
429             if (CVSRoot.METHOD_PSERVER.equals(root.getMethod())) {
430                 return performLogin(root.getUserName(), root.getHostName(),
431                                     root.getRepository(), root.getPort(),
432                                     globalOptions);
433             }
434             else {
435                 stderr.println("login does not apply for connection type " +
436                                "\'" + root.getMethod() + "\'");
437                 return false;
438             }
439         }
440
441         // this is not login, but a 'real' cvs command, so construct it,
442
// set the options, and then connect to the server and execute it
443

444         Command c = null;
445         try {
446             c = CommandFactory.getDefault().createCommand(command, args, ++commandIndex, globalOptions, localPath);
447         }
448         catch (IllegalArgumentException JavaDoc e) {
449             stderr.println("Illegal argument: " + e.getMessage());
450             return false;
451         }
452         
453         if (files != null && c instanceof BasicCommand) {
454             ((BasicCommand) c).setFiles(files);
455         }
456
457         String JavaDoc password = null;
458
459         if (CVSRoot.METHOD_PSERVER.equals(root.getMethod())) {
460             password = root.getPassword();
461             if (password != null) {
462                 password = StandardScrambler.getInstance().scramble(password);
463             } else {
464                 if (port > 0) root.setPort(port);
465                 password = lookupPassword(cvsRoot, root.toString(), stderr);
466                 if (password == null) {
467                     password = StandardScrambler.getInstance().scramble(""); // an empty password
468
}
469             }
470         }
471         CVSCommand cvsCommand = new CVSCommand();
472         cvsCommand.setGlobalOptions(globalOptions);
473         cvsCommand.setRepository(root.getRepository());
474         if (port > 0) {
475             cvsCommand.port = port;
476         }
477         // the local path is just the path where we executed the
478
// command. This is the case for command-line CVS but not
479
// usually for GUI front-ends
480
cvsCommand.setLocalPath(localPath);
481         try {
482             cvsCommand.connect(root, password);
483             
484             CVSListener list;
485             if (c instanceof ListenerProvider)
486             {
487                 list = ((ListenerProvider)c).createCVSListener(stdout, stderr);
488             } else {
489                 list = new BasicListener(stdout, stderr);
490             }
491             cvsCommand.addListener(list);
492             boolean status = cvsCommand.executeCommand(c, stderr);
493             return status;
494         }
495         catch (AuthenticationException aex) {
496             stderr.println(aex.getLocalizedMessage());
497             return false;
498         }
499         catch (CommandAbortedException caex) {
500             stderr.println("Error: " + caex);
501             Thread.currentThread().interrupt();
502             return false;
503         }
504         catch (Exception JavaDoc t) {
505             stderr.println("Error: " + t);
506             t.printStackTrace(stderr);
507             return false;
508         }
509         finally {
510             if (cvsCommand != null) {
511                 cvsCommand.close(stderr);
512             }
513         }
514     }
515     
516     private static void printHelpOptions(PrintStream stdout) {
517         String JavaDoc options = ResourceBundle.getBundle(CVSCommand.class.getPackage().getName()+".Bundle").getString("MSG_HelpOptions"); // NOI18N
518
stdout.println(options);
519     }
520     
521     private static void printHelpCommands(PrintStream stdout) {
522         String JavaDoc msg = ResourceBundle.getBundle(CVSCommand.class.getPackage().getName()+".Bundle").getString("MSG_CVSCommands"); // NOI18N
523
stdout.println(msg);
524         CommandProvider[] providers = CommandFactory.getDefault().getCommandProviders();
525         Arrays.sort(providers, new CommandProvidersComparator());
526         int maxNameLength = 0;
527         for (int i = 0; i < providers.length; i++) {
528             int l = providers[i].getName().length();
529             if (maxNameLength < l) {
530                 maxNameLength = l;
531             }
532         }
533         maxNameLength += 2; // Two spaces from the longest name
534
for (int i = 0; i < providers.length; i++) {
535             stdout.print("\t"+providers[i].getName());
536             char spaces[] = new char[maxNameLength - providers[i].getName().length()];
537             Arrays.fill(spaces, ' ');
538             stdout.print(new String JavaDoc(spaces));
539             providers[i].printShortDescription(stdout);
540             stdout.println();
541         }
542     }
543     
544     private static void printHelpSynonyms(PrintStream stdout) {
545         String JavaDoc msg = ResourceBundle.getBundle(CVSCommand.class.getPackage().getName()+".Bundle").getString("MSG_CVSSynonyms"); // NOI18N
546
stdout.println(msg);
547         CommandProvider[] providers = CommandFactory.getDefault().getCommandProviders();
548         Arrays.sort(providers, new CommandProvidersComparator());
549         int maxNameLength = 0;
550         for (int i = 0; i < providers.length; i++) {
551             int l = providers[i].getName().length();
552             if (maxNameLength < l) {
553                 maxNameLength = l;
554             }
555         }
556         maxNameLength += 2; // Two spaces from the longest name
557
for (int i = 0; i < providers.length; i++) {
558             String JavaDoc[] synonyms = providers[i].getSynonyms();
559             if (synonyms.length > 0) {
560                 stdout.print("\t"+providers[i].getName());
561                 char spaces[] = new char[maxNameLength - providers[i].getName().length()];
562                 Arrays.fill(spaces, ' ');
563                 stdout.print(new String JavaDoc(spaces));
564                 for (int j = 0; j < synonyms.length; j++) {
565                     stdout.print(synonyms[j]+" ");
566                 }
567                 stdout.println();
568             }
569         }
570     }
571     
572     private static void printHelp(int commandIndex, String JavaDoc[] args,
573                                   PrintStream stdout, PrintStream stderr) {
574         if (commandIndex >= args.length) {
575             showUsage(stdout);
576         } else {
577             String JavaDoc cmdName = args[commandIndex];
578             CommandProvider provider = CommandFactory.getDefault().getCommandProvider(cmdName);
579             if (provider == null) {
580                 printUnknownCommand(cmdName, stderr);
581             } else {
582                 provider.printLongDescription(stdout);
583             }
584         }
585     }
586     
587     private static void printVersion(PrintStream stdout, PrintStream stderr) {
588         String JavaDoc version = CVSCommand.class.getPackage().getSpecificationVersion();
589         stdout.println("Java Concurrent Versions System (JavaCVS) "+version+" (client)");
590     }
591     
592     private static void printUnknownCommand(String JavaDoc commandName, PrintStream out) {
593         String JavaDoc msg = ResourceBundle.getBundle(CVSCommand.class.getPackage().getName()+".Bundle").getString("MSG_UnknownCommand"); // NOI18N
594
out.println(MessageFormat.format(msg, new Object JavaDoc[] { commandName }));
595         printHelpCommands(out);
596     }
597     
598     private static final class CommandProvidersComparator implements Comparator JavaDoc {
599         
600         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
601             if (!(o1 instanceof CommandProvider) || !(o2 instanceof CommandProvider)) {
602                 throw new IllegalArgumentException JavaDoc("Can not compare objects "+o1+" and "+o2);
603             }
604             return ((CommandProvider) o1).getName().compareTo(((CommandProvider) o2).getName());
605         }
606         
607     }
608     
609 }
610
Popular Tags