/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.netbeans.lib.cvsclient.command.importcmd; import java.io.EOFException; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.netbeans.lib.cvsclient.ClientServices; import org.netbeans.lib.cvsclient.command.BuildableCommand; import org.netbeans.lib.cvsclient.command.Builder; import org.netbeans.lib.cvsclient.command.CommandException; import org.netbeans.lib.cvsclient.command.KeywordSubstitutionOptions; import org.netbeans.lib.cvsclient.connection.AuthenticationException; import org.netbeans.lib.cvsclient.event.EventManager; import org.netbeans.lib.cvsclient.request.ArgumentRequest; import org.netbeans.lib.cvsclient.request.ArgumentxRequest; import org.netbeans.lib.cvsclient.request.CommandRequest; import org.netbeans.lib.cvsclient.request.DirectoryRequest; import org.netbeans.lib.cvsclient.request.ModifiedRequest; import org.netbeans.lib.cvsclient.response.WrapperSendResponse; import org.netbeans.lib.cvsclient.util.SimpleStringPattern; import org.netbeans.lib.cvsclient.util.StringPattern; /** * The import command imports local directory structures into the repository. * * @author Thomas Singer */ public class ImportCommand extends BuildableCommand { private Map wrapperMap = new HashMap(); private String logMessage; private String module; private String releaseTag; private String vendorBranch; private String vendorTag; private String importDirectory; private KeywordSubstitutionOptions keywordSubstitutionOptions; private boolean useFileModifTime; private List ignoreList = new LinkedList(); public ImportCommand() { resetCVSCommand(); } public void addWrapper(String filenamePattern, KeywordSubstitutionOptions keywordSubstitutionOptions) { if (keywordSubstitutionOptions == null) { throw new IllegalArgumentException("keywordSubstitutionOptions must not be null"); } wrapperMap.put(new SimpleStringPattern(filenamePattern), keywordSubstitutionOptions); } public void addWrapper(StringPattern filenamePattern, KeywordSubstitutionOptions keywordSubstitutionOptions) { if (keywordSubstitutionOptions == null) { throw new IllegalArgumentException("keywordSubstitutionOptions must not be null"); } wrapperMap.put(filenamePattern, keywordSubstitutionOptions); } /** * Compliant method to addWrapper. It replaces the whole list of cvswrappers. The Map's structure should be following: Key: instance of * StringPattern(fileName wildpattern) Value: instance of KeywordSubstitutionOptions */ public void setWrappers(Map wrapperMap) { this.wrapperMap = wrapperMap; } /** * Returns a map with all wrappers. For map descriptions see setWrapper() */ public Map getWrappers() { return wrapperMap; } /** * Returns the keyword substitution option. */ public KeywordSubstitutionOptions getKeywordSubstitutionOptions() { return keywordSubstitutionOptions; } /** * Sets the keywords substitution option. */ public void setKeywordSubstitutionOptions(KeywordSubstitutionOptions keywordSubstitutionOptions) { this.keywordSubstitutionOptions = keywordSubstitutionOptions; } /** * Returns the release tag. */ public String getReleaseTag() { return releaseTag; } /** * Sets the necessary release tag. */ public void setReleaseTag(String releaseTag) { this.releaseTag = getTrimmedString(releaseTag); } /** * Returns the log message. */ public String getLogMessage() { return logMessage; } /** * Sets the log message. */ public void setLogMessage(String logMessage) { this.logMessage = getTrimmedString(logMessage); } /** * Returns the module (the in-repository path, where the files should be stored. */ public String getModule() { return module; } /** * Sets the module (the in-repository path, where the files should be stored). */ public void setModule(String module) { this.module = getTrimmedString(module); } /** * Pints to directoty to import. */ public void setImportDirectory(String directory) { importDirectory = directory; } public String getImportDirectory() { return importDirectory; } /** * Returns the vendor branch. */ public String getVendorBranch() { return vendorBranch; } /** * Returns the vendor branch. If not set, then 1.1.1 is returned. */ private String getVendorBranchNotNull() { if (vendorBranch == null) { return "1.1.1"; // NOI18N } return vendorBranch; } /** * Sets the vendor branch. If null is set, the default branch 1.1.1 is used automatically. */ public void setVendorBranch(String vendorBranch) { this.vendorBranch = getTrimmedString(vendorBranch); } /** * Returns the vendor tag. */ public String getVendorTag() { return vendorTag; } /** * Sets the necessary vendor tag. */ public void setVendorTag(String vendorTag) { this.vendorTag = getTrimmedString(vendorTag); } /** * Tells, whether the file modification time is to be used as the time of the import. */ public boolean isUseFileModifTime() { return useFileModifTime; } /** * Sets whether the file modification time is to be used as the time of the import. */ public void setUseFileModifTime(boolean useFileModifTime) { this.useFileModifTime = useFileModifTime; } /** * Get a list of files that are ignored by import. */ public List getIgnoreFiles() { return Collections.unmodifiableList(ignoreList); } /** * Add a file name that is to be ignored by the import. */ public void addIgnoredFile(String ignoredFileName) { ignoreList.add(ignoredFileName); } /** * Executes thiz command using the set options. */ @Override public void execute(ClientServices client, EventManager eventManager) throws CommandException, AuthenticationException { // check necessary fields if (getLogMessage() == null) { String localizedMsg = CommandException.getLocalMessage("ImportCommand.messageEmpty"); // NOI18N throw new CommandException("message may not be null nor empty", // NOI18N localizedMsg); } if (getModule() == null) { String localizedMsg = CommandException.getLocalMessage("ImportCommand.moduleEmpty"); // NOI18N throw new CommandException("module may not be null nor empty", // NOI18N localizedMsg); } if (getReleaseTag() == null) { String localizedMsg = CommandException.getLocalMessage("ImportCommand.releaseTagEmpty"); // NOI18N throw new CommandException("release tag may not be null nor empty", // NOI18N localizedMsg); } if (getVendorTag() == null) { String localizedMsg = CommandException.getLocalMessage("ImportCommand.vendorTagEmpty"); // NOI18N throw new CommandException("vendor tag may not be null nor empty", // NOI18N localizedMsg); } client.ensureConnection(); // get the connection wrappers here Map allWrappersMap = new HashMap(client.getWrappersMap()); allWrappersMap.putAll(getWrappers()); setWrappers(allWrappersMap); // start working super.execute(client, eventManager); assert getLocalDirectory() != null : "local directory may not be null"; List requestList = new ArrayList(); try { // add requests requestList.add(new ArgumentRequest("-b")); // NOI18N requestList.add(new ArgumentRequest(getVendorBranchNotNull())); if (getKeywordSubstitutionOptions() != null) { requestList.add(new ArgumentRequest("-k")); // NOI18N requestList.add(new ArgumentRequest(getKeywordSubstitutionOptions().toString())); } addMessageRequests(requestList, getLogMessage()); addWrapperRequests(requestList, this.wrapperMap); if (isUseFileModifTime()) { requestList.add(new ArgumentRequest("-d")); // NOI18N } for (int i = 0; i < ignoreList.size(); i++) { requestList.add(new ArgumentRequest("-I")); // NOI18N requestList.add(new ArgumentRequest((String) ignoreList.get(i))); } requestList.add(new ArgumentRequest(getModule())); requestList.add(new ArgumentRequest(getVendorTag())); requestList.add(new ArgumentRequest(getReleaseTag())); addFileRequests(new File(getLocalDirectory()), requestList, client); requestList.add(new DirectoryRequest(".", getRepositoryRoot(client))); // NOI18N requestList.add(CommandRequest.IMPORT); // process the requests client.processRequests(requestList); } catch (CommandException ex) { throw ex; } catch (EOFException ex) { String localizedMsg = CommandException.getLocalMessage("CommandException.EndOfFile", null); // NOI18N throw new CommandException(ex, localizedMsg); } catch (Exception ex) { throw new CommandException(ex, ex.getLocalizedMessage()); } } @Override public String getCVSCommand() { StringBuffer toReturn = new StringBuffer("import "); // NOI18N toReturn.append(getCVSArguments()); if (getModule() != null) { toReturn.append(" "); // NOI18N toReturn.append(getModule()); } else { String localizedMsg = CommandException.getLocalMessage("ImportCommand.moduleEmpty.text"); // NOI18N toReturn.append(" "); // NOI18N toReturn.append(localizedMsg); } if (getVendorTag() != null) { toReturn.append(" "); // NOI18N toReturn.append(getVendorTag()); } else { String localizedMsg = CommandException.getLocalMessage("ImportCommand.vendorTagEmpty.text"); // NOI18N toReturn.append(" "); // NOI18N toReturn.append(localizedMsg); } if (getReleaseTag() != null) { toReturn.append(" "); // NOI18N toReturn.append(getReleaseTag()); } else { String localizedMsg = CommandException.getLocalMessage("ImportCommand.releaseTagEmpty.text"); // NOI18N toReturn.append(" "); // NOI18N toReturn.append(localizedMsg); } return toReturn.toString(); } @Override public String getCVSArguments() { StringBuffer toReturn = new StringBuffer(""); // NOI18N if (getLogMessage() != null) { toReturn.append("-m \""); // NOI18N toReturn.append(getLogMessage()); toReturn.append("\" "); // NOI18N } if (getKeywordSubstitutionOptions() != null) { toReturn.append("-k"); // NOI18N toReturn.append(getKeywordSubstitutionOptions().toString()); toReturn.append(" "); // NOI18N } if (getVendorBranch() != null) { toReturn.append("-b "); // NOI18N toReturn.append(getVendorBranch()); toReturn.append(" "); // NOI18N } if (isUseFileModifTime()) { toReturn.append("-d "); // NOI18N } if (wrapperMap.size() > 0) { Iterator it = wrapperMap.keySet().iterator(); while (it.hasNext()) { StringPattern pattern = (StringPattern) it.next(); KeywordSubstitutionOptions keywordSubstitutionOptions = (KeywordSubstitutionOptions) wrapperMap.get(pattern); toReturn.append("-W "); // NOI18N toReturn.append(pattern.toString()); toReturn.append(" -k '"); // NOI18N toReturn.append(keywordSubstitutionOptions.toString()); toReturn.append("' "); // NOI18N } } for (Iterator it = ignoreList.iterator(); it.hasNext();) { toReturn.append("-I "); // NOI18N toReturn.append((String) it.next()); toReturn.append(" "); // NOI18N } return toReturn.toString(); } @Override public boolean setCVSCommand(char opt, String optArg) { if (opt == 'b') { setVendorBranch(optArg); } else if (opt == 'm') { setLogMessage(optArg); } else if (opt == 'k') { setKeywordSubstitutionOptions(KeywordSubstitutionOptions.findKeywordSubstOption(optArg)); } else if (opt == 'W') { Map wrappers = WrapperSendResponse.parseWrappers(optArg); for (Iterator it = wrappers.keySet().iterator(); it.hasNext();) { StringPattern pattern = (StringPattern) it.next(); KeywordSubstitutionOptions keywordOption = (KeywordSubstitutionOptions) wrappers.get(pattern); addWrapper(pattern, keywordOption); } } else if (opt == 'd') { setUseFileModifTime(true); } else if (opt == 'I') { addIgnoredFile(optArg); } else { return false; } return true; } @Override public void resetCVSCommand() { setLogMessage(null); setModule(null); setReleaseTag(null); setVendorTag(null); setVendorBranch(null); setUseFileModifTime(false); ignoreList.clear(); wrapperMap.clear(); } @Override public String getOptString() { return "m:W:b:k:dI:"; // NOI18N } /** * Adds requests for the specified logMessage to the specified requestList. */ private void addMessageRequests(List requestList, String logMessage) { requestList.add(new ArgumentRequest("-m")); // NOI18N StringTokenizer token = new StringTokenizer(logMessage, "\n", false); // NOI18N boolean first = true; while (token.hasMoreTokens()) { if (first) { requestList.add(new ArgumentRequest(token.nextToken())); first = false; } else { requestList.add(new ArgumentxRequest(token.nextToken())); } } } /** * Adds requests for specified wrappers to the specified requestList. */ private void addWrapperRequests(List requestList, Map wrapperMap) { for (Iterator it = wrapperMap.keySet().iterator(); it.hasNext();) { StringPattern pattern = (StringPattern) it.next(); KeywordSubstitutionOptions keywordSubstitutionOptions = (KeywordSubstitutionOptions) wrapperMap.get(pattern); StringBuffer buffer = new StringBuffer(); buffer.append(pattern.toString()); buffer.append(" -k '"); // NOI18N buffer.append(keywordSubstitutionOptions.toString()); buffer.append("'"); // NOI18N requestList.add(new ArgumentRequest("-W")); // NOI18N requestList.add(new ArgumentRequest(buffer.toString())); } } /** * Adds recursively all request for files and directories in the specified directory to the specified requestList. */ private void addFileRequests(File directory, List requestList, ClientServices clientServices) throws IOException { String relativePath = getRelativeToLocalPathInUnixStyle(directory); String repository = getRepositoryRoot(clientServices); if (!relativePath.equals(".")) { // NOI18N repository += '/' + relativePath; } requestList.add(new DirectoryRequest(relativePath, repository)); File[] files = directory.listFiles(); if (files == null) { return; } List subdirectories = null; for (int i = 0; i < files.length; i++) { File file = files[i]; String filename = file.getName(); if (clientServices.shouldBeIgnored(directory, filename)) { continue; } if (file.isDirectory()) { if (subdirectories == null) { subdirectories = new LinkedList(); } subdirectories.add(file); } else { boolean isBinary = isBinary(filename); requestList.add(new ModifiedRequest(file, isBinary)); } } if (subdirectories != null) { for (Iterator it = subdirectories.iterator(); it.hasNext();) { File subdirectory = (File) it.next(); addFileRequests(subdirectory, requestList, clientServices); } } } /** * Returns the used root path in the repository. It's built from the repository stored in the clientService and the module. */ private String getRepositoryRoot(ClientServices clientServices) { String repository = clientServices.getRepository() + '/' + getModule(); return repository; } /** * Returns true, if the file for the specified filename should be treated as a binary file. * * The information comes from the wrapper map and the set keywordsubstitution. */ private boolean isBinary(String filename) { KeywordSubstitutionOptions keywordSubstitutionOptions = getKeywordSubstitutionOptions(); for (Iterator it = wrapperMap.keySet().iterator(); it.hasNext();) { StringPattern pattern = (StringPattern) it.next(); if (pattern.doesMatch(filename)) { keywordSubstitutionOptions = (KeywordSubstitutionOptions) wrapperMap.get(pattern); break; } } return keywordSubstitutionOptions == KeywordSubstitutionOptions.BINARY; } /** * Creates the ImportBuilder. */ @Override public Builder createBuilder(EventManager eventManager) { return new ImportBuilder(eventManager, this); } }