001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.lib.cvsclient.command.importcmd;
042:
043: import java.io.*;
044: import java.util.*;
045:
046: import org.netbeans.lib.cvsclient.*;
047: import org.netbeans.lib.cvsclient.command.*;
048: import org.netbeans.lib.cvsclient.connection.*;
049: import org.netbeans.lib.cvsclient.event.*;
050: import org.netbeans.lib.cvsclient.request.*;
051: import org.netbeans.lib.cvsclient.response.WrapperSendResponse;
052: import org.netbeans.lib.cvsclient.util.*;
053:
054: /**
055: * The import command imports local directory structures into the repository.
056: *
057: * @author Thomas Singer
058: */
059: public class ImportCommand extends BuildableCommand {
060: private Map wrapperMap = new HashMap();
061: private String logMessage;
062: private String module;
063: private String releaseTag;
064: private String vendorBranch;
065: private String vendorTag;
066: private String importDirectory;
067: private KeywordSubstitutionOptions keywordSubstitutionOptions;
068: private boolean useFileModifTime;
069: private List ignoreList = new LinkedList();
070:
071: public ImportCommand() {
072: resetCVSCommand();
073: }
074:
075: public void addWrapper(String filenamePattern,
076: KeywordSubstitutionOptions keywordSubstitutionOptions) {
077: if (keywordSubstitutionOptions == null) {
078: throw new IllegalArgumentException(
079: "keywordSubstitutionOptions must not be null");
080: }
081:
082: wrapperMap.put(new SimpleStringPattern(filenamePattern),
083: keywordSubstitutionOptions);
084: }
085:
086: public void addWrapper(StringPattern filenamePattern,
087: KeywordSubstitutionOptions keywordSubstitutionOptions) {
088: if (keywordSubstitutionOptions == null) {
089: throw new IllegalArgumentException(
090: "keywordSubstitutionOptions must not be null");
091: }
092:
093: wrapperMap.put(filenamePattern, keywordSubstitutionOptions);
094: }
095:
096: /**
097: * Compliant method to addWrapper. It replaces the whole list of cvswrappers.
098: * The Map's structure should be following:
099: * Key: instance of StringPattern(fileName wildpattern)
100: * Value: instance of KeywordSubstitutionOptions
101: */
102: public void setWrappers(Map wrapperMap) {
103: this .wrapperMap = wrapperMap;
104: }
105:
106: /**
107: * Returns a map with all wrappers.
108: * For map descriptions see setWrapper()
109: */
110: public Map getWrappers() {
111: return wrapperMap;
112: }
113:
114: /**
115: * Returns the keyword substitution option.
116: */
117: public KeywordSubstitutionOptions getKeywordSubstitutionOptions() {
118: return keywordSubstitutionOptions;
119: }
120:
121: /**
122: * Sets the keywords substitution option.
123: */
124: public void setKeywordSubstitutionOptions(
125: KeywordSubstitutionOptions keywordSubstitutionOptions) {
126: this .keywordSubstitutionOptions = keywordSubstitutionOptions;
127: }
128:
129: /**
130: * Returns the release tag.
131: */
132: public String getReleaseTag() {
133: return releaseTag;
134: }
135:
136: /**
137: * Sets the necessary release tag.
138: */
139: public void setReleaseTag(String releaseTag) {
140: this .releaseTag = getTrimmedString(releaseTag);
141: }
142:
143: /**
144: * Returns the log message.
145: */
146: public String getLogMessage() {
147: return logMessage;
148: }
149:
150: /**
151: * Sets the log message.
152: */
153: public void setLogMessage(String logMessage) {
154: this .logMessage = getTrimmedString(logMessage);
155: }
156:
157: /**
158: * Returns the module (the in-repository path, where the files should be
159: * stored.
160: */
161: public String getModule() {
162: return module;
163: }
164:
165: /**
166: * Sets the module (the in-repository path, where the files should be
167: * stored).
168: */
169: public void setModule(String module) {
170: this .module = getTrimmedString(module);
171: }
172:
173: /**
174: * Pints to directoty to import.
175: */
176: public void setImportDirectory(String directory) {
177: importDirectory = directory;
178: }
179:
180: public String getImportDirectory() {
181: return importDirectory;
182: }
183:
184: /**
185: * Returns the vendor branch.
186: */
187: public String getVendorBranch() {
188: return vendorBranch;
189: }
190:
191: /**
192: * Returns the vendor branch.
193: * If not set, then 1.1.1 is returned.
194: */
195: private String getVendorBranchNotNull() {
196: if (vendorBranch == null) {
197: return "1.1.1"; //NOI18N
198: }
199:
200: return vendorBranch;
201: }
202:
203: /**
204: * Sets the vendor branch.
205: * If null is set, the default branch 1.1.1 is used automatically.
206: */
207: public void setVendorBranch(String vendorBranch) {
208: this .vendorBranch = getTrimmedString(vendorBranch);
209: }
210:
211: /**
212: * Returns the vendor tag.
213: */
214: public String getVendorTag() {
215: return vendorTag;
216: }
217:
218: /**
219: * Sets the necessary vendor tag.
220: */
221: public void setVendorTag(String vendorTag) {
222: this .vendorTag = getTrimmedString(vendorTag);
223: }
224:
225: /**
226: * Tells, whether the file modification time is to be used as the time of the import.
227: */
228: public boolean isUseFileModifTime() {
229: return useFileModifTime;
230: }
231:
232: /**
233: * Sets whether the file modification time is to be used as the time of the import.
234: */
235: public void setUseFileModifTime(boolean useFileModifTime) {
236: this .useFileModifTime = useFileModifTime;
237: }
238:
239: /**
240: * Get a list of files that are ignored by import.
241: */
242: public List getIgnoreFiles() {
243: return Collections.unmodifiableList(ignoreList);
244: }
245:
246: /**
247: * Add a file name that is to be ignored by the import.
248: */
249: public void addIgnoredFile(String ignoredFileName) {
250: ignoreList.add(ignoredFileName);
251: }
252:
253: /**
254: * Executes thiz command using the set options.
255: */
256: public void execute(ClientServices client, EventManager eventManager)
257: throws CommandException, AuthenticationException {
258: // check necessary fields
259: if (getLogMessage() == null) {
260: String localizedMsg = CommandException
261: .getLocalMessage("ImportCommand.messageEmpty"); //NOI18N
262: throw new CommandException(
263: "message may not be null nor empty", //NOI18N
264: localizedMsg);
265: }
266: if (getModule() == null) {
267: String localizedMsg = CommandException
268: .getLocalMessage("ImportCommand.moduleEmpty"); //NOI18N
269: throw new CommandException(
270: "module may not be null nor empty", //NOI18N
271: localizedMsg);
272: }
273: if (getReleaseTag() == null) {
274: String localizedMsg = CommandException
275: .getLocalMessage("ImportCommand.releaseTagEmpty"); //NOI18N
276: throw new CommandException(
277: "release tag may not be null nor empty", //NOI18N
278: localizedMsg);
279: }
280: if (getVendorTag() == null) {
281: String localizedMsg = CommandException
282: .getLocalMessage("ImportCommand.vendorTagEmpty"); //NOI18N
283: throw new CommandException(
284: "vendor tag may not be null nor empty", //NOI18N
285: localizedMsg);
286: }
287:
288: client.ensureConnection();
289:
290: // get the connection wrappers here
291: Map allWrappersMap = new HashMap(client.getWrappersMap());
292: allWrappersMap.putAll(getWrappers());
293: setWrappers(allWrappersMap);
294:
295: // start working
296: super .execute(client, eventManager);
297: assert getLocalDirectory() != null : "local directory may not be null";
298:
299: List requestList = new ArrayList();
300:
301: try {
302: // add requests
303: requestList.add(new ArgumentRequest("-b")); //NOI18N
304: requestList.add(new ArgumentRequest(
305: getVendorBranchNotNull()));
306:
307: if (getKeywordSubstitutionOptions() != null) {
308: requestList.add(new ArgumentRequest("-k")); //NOI18N
309: requestList.add(new ArgumentRequest(
310: getKeywordSubstitutionOptions().toString()));
311: }
312:
313: addMessageRequests(requestList, getLogMessage());
314:
315: addWrapperRequests(requestList, this .wrapperMap);
316:
317: if (isUseFileModifTime()) {
318: requestList.add(new ArgumentRequest("-d")); //NOI18N
319: }
320:
321: for (int i = 0; i < ignoreList.size(); i++) {
322: requestList.add(new ArgumentRequest("-I")); //NOI18N
323: requestList.add(new ArgumentRequest((String) ignoreList
324: .get(i)));
325: }
326:
327: requestList.add(new ArgumentRequest(getModule()));
328: requestList.add(new ArgumentRequest(getVendorTag()));
329: requestList.add(new ArgumentRequest(getReleaseTag()));
330:
331: addFileRequests(new File(getLocalDirectory()), requestList,
332: client);
333:
334: requestList.add(new DirectoryRequest(".",
335: getRepositoryRoot(client))); //NOI18N
336:
337: requestList.add(CommandRequest.IMPORT);
338:
339: // process the requests
340: client.processRequests(requestList);
341: } catch (CommandException ex) {
342: throw ex;
343: } catch (EOFException ex) {
344: String localizedMsg = CommandException.getLocalMessage(
345: "CommandException.EndOfFile", null); //NOI18N
346: throw new CommandException(ex, localizedMsg);
347: } catch (Exception ex) {
348: throw new CommandException(ex, ex.getLocalizedMessage());
349: }
350: }
351:
352: public String getCVSCommand() {
353: StringBuffer toReturn = new StringBuffer("import "); //NOI18N
354: toReturn.append(getCVSArguments());
355: if (getModule() != null) {
356: toReturn.append(" "); //NOI18N
357: toReturn.append(getModule());
358: } else {
359: String localizedMsg = CommandException
360: .getLocalMessage("ImportCommand.moduleEmpty.text"); //NOI18N
361: toReturn.append(" "); //NOI18N
362: toReturn.append(localizedMsg);
363: }
364: if (getVendorTag() != null) {
365: toReturn.append(" "); //NOI18N
366: toReturn.append(getVendorTag());
367: } else {
368: String localizedMsg = CommandException
369: .getLocalMessage("ImportCommand.vendorTagEmpty.text"); //NOI18N
370: toReturn.append(" "); //NOI18N
371: toReturn.append(localizedMsg);
372: }
373: if (getReleaseTag() != null) {
374: toReturn.append(" "); //NOI18N
375: toReturn.append(getReleaseTag());
376: } else {
377: String localizedMsg = CommandException
378: .getLocalMessage("ImportCommand.releaseTagEmpty.text"); //NOI18N
379: toReturn.append(" "); //NOI18N
380: toReturn.append(localizedMsg);
381: }
382: return toReturn.toString();
383: }
384:
385: public String getCVSArguments() {
386: StringBuffer toReturn = new StringBuffer(""); //NOI18N
387: if (getLogMessage() != null) {
388: toReturn.append("-m \""); //NOI18N
389: toReturn.append(getLogMessage());
390: toReturn.append("\" "); //NOI18N
391: }
392: if (getKeywordSubstitutionOptions() != null) {
393: toReturn.append("-k"); //NOI18N
394: toReturn.append(getKeywordSubstitutionOptions().toString());
395: toReturn.append(" "); //NOI18N
396: }
397: if (getVendorBranch() != null) {
398: toReturn.append("-b "); //NOI18N
399: toReturn.append(getVendorBranch());
400: toReturn.append(" "); //NOI18N
401: }
402: if (isUseFileModifTime()) {
403: toReturn.append("-d "); // NOI18N
404: }
405: if (wrapperMap.size() > 0) {
406: Iterator it = wrapperMap.keySet().iterator();
407: while (it.hasNext()) {
408: StringPattern pattern = (StringPattern) it.next();
409: KeywordSubstitutionOptions keywordSubstitutionOptions = (KeywordSubstitutionOptions) wrapperMap
410: .get(pattern);
411: toReturn.append("-W "); //NOI18N
412: toReturn.append(pattern.toString());
413: toReturn.append(" -k '"); //NOI18N
414: toReturn.append(keywordSubstitutionOptions.toString());
415: toReturn.append("' "); //NOI18N
416: }
417: }
418: for (Iterator it = ignoreList.iterator(); it.hasNext();) {
419: toReturn.append("-I "); //NOI18N
420: toReturn.append((String) it.next());
421: toReturn.append(" "); //NOI18N
422: }
423: return toReturn.toString();
424: }
425:
426: public boolean setCVSCommand(char opt, String optArg) {
427: if (opt == 'b') {
428: setVendorBranch(optArg);
429: } else if (opt == 'm') {
430: setLogMessage(optArg);
431: } else if (opt == 'k') {
432: setKeywordSubstitutionOptions(KeywordSubstitutionOptions
433: .findKeywordSubstOption(optArg));
434: } else if (opt == 'W') {
435: Map wrappers = WrapperSendResponse.parseWrappers(optArg);
436: for (Iterator it = wrappers.keySet().iterator(); it
437: .hasNext();) {
438: StringPattern pattern = (StringPattern) it.next();
439: KeywordSubstitutionOptions keywordOption = (KeywordSubstitutionOptions) wrappers
440: .get(pattern);
441: addWrapper(pattern, keywordOption);
442: }
443: } else if (opt == 'd') {
444: setUseFileModifTime(true);
445: } else if (opt == 'I') {
446: addIgnoredFile(optArg);
447: } else {
448: return false;
449: }
450: return true;
451: }
452:
453: public void resetCVSCommand() {
454: setLogMessage(null);
455: setModule(null);
456: setReleaseTag(null);
457: setVendorTag(null);
458: setVendorBranch(null);
459: setUseFileModifTime(false);
460: ignoreList.clear();
461: wrapperMap.clear();
462: }
463:
464: public String getOptString() {
465: return "m:W:b:k:dI:"; //NOI18N
466: }
467:
468: /**
469: * Adds requests for the specified logMessage to the specified requestList.
470: */
471: private void addMessageRequests(List requestList, String logMessage) {
472: requestList.add(new ArgumentRequest("-m")); //NOI18N
473:
474: StringTokenizer token = new StringTokenizer(logMessage, "\n",
475: false); //NOI18N
476: boolean first = true;
477: while (token.hasMoreTokens()) {
478: if (first) {
479: requestList.add(new ArgumentRequest(token.nextToken()));
480: first = false;
481: } else {
482: requestList
483: .add(new ArgumentxRequest(token.nextToken()));
484: }
485: }
486: }
487:
488: /**
489: * Adds requests for specified wrappers to the specified requestList.
490: */
491: private void addWrapperRequests(List requestList, Map wrapperMap) {
492: for (Iterator it = wrapperMap.keySet().iterator(); it.hasNext();) {
493: StringPattern pattern = (StringPattern) it.next();
494: KeywordSubstitutionOptions keywordSubstitutionOptions = (KeywordSubstitutionOptions) wrapperMap
495: .get(pattern);
496:
497: StringBuffer buffer = new StringBuffer();
498: buffer.append(pattern.toString());
499: buffer.append(" -k '"); //NOI18N
500: buffer.append(keywordSubstitutionOptions.toString());
501: buffer.append("'"); //NOI18N
502:
503: requestList.add(new ArgumentRequest("-W")); //NOI18N
504: requestList.add(new ArgumentRequest(buffer.toString()));
505: }
506: }
507:
508: /**
509: * Adds recursively all request for files and directories in the specified
510: * directory to the specified requestList.
511: */
512: private void addFileRequests(File directory, List requestList,
513: ClientServices clientServices) throws IOException {
514: String relativePath = getRelativeToLocalPathInUnixStyle(directory);
515: String repository = getRepositoryRoot(clientServices);
516: if (!relativePath.equals(".")) { //NOI18N
517: repository += '/' + relativePath;
518: }
519: requestList.add(new DirectoryRequest(relativePath, repository));
520:
521: File[] files = directory.listFiles();
522: if (files == null) {
523: return;
524: }
525:
526: List subdirectories = null;
527:
528: for (int i = 0; i < files.length; i++) {
529: File file = files[i];
530: String filename = file.getName();
531:
532: if (clientServices.shouldBeIgnored(directory, filename)) {
533: continue;
534: }
535:
536: if (file.isDirectory()) {
537: if (subdirectories == null) {
538: subdirectories = new LinkedList();
539: }
540: subdirectories.add(file);
541: } else {
542: boolean isBinary = isBinary(filename);
543: requestList.add(new ModifiedRequest(file, isBinary));
544: }
545: }
546:
547: if (subdirectories != null) {
548: for (Iterator it = subdirectories.iterator(); it.hasNext();) {
549: File subdirectory = (File) it.next();
550: addFileRequests(subdirectory, requestList,
551: clientServices);
552: }
553: }
554: }
555:
556: /**
557: * Returns the used root path in the repository.
558: * It's built from the repository stored in the clientService and the
559: * module.
560: */
561: private String getRepositoryRoot(ClientServices clientServices) {
562: String repository = clientServices.getRepository() + '/'
563: + getModule();
564: return repository;
565: }
566:
567: /**
568: * Returns true, if the file for the specified filename should be treated as
569: * a binary file.
570: *
571: * The information comes from the wrapper map and the set keywordsubstitution.
572: */
573: private boolean isBinary(String filename) {
574: KeywordSubstitutionOptions keywordSubstitutionOptions = getKeywordSubstitutionOptions();
575:
576: for (Iterator it = wrapperMap.keySet().iterator(); it.hasNext();) {
577: StringPattern pattern = (StringPattern) it.next();
578: if (pattern.doesMatch(filename)) {
579: keywordSubstitutionOptions = (KeywordSubstitutionOptions) wrapperMap
580: .get(pattern);
581: break;
582: }
583: }
584:
585: return keywordSubstitutionOptions == KeywordSubstitutionOptions.BINARY;
586: }
587:
588: /**
589: * Creates the ImportBuilder.
590: */
591: public Builder createBuilder(EventManager eventManager) {
592: return new ImportBuilder(eventManager, this);
593: }
594: }
|