| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Gunnar Wagenknecht - adaption to new fetch script builder API |
| *******************************************************************************/ |
| package org.eclipse.pde.internal.build.fetch; |
| |
| import java.util.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.pde.build.*; |
| import org.eclipse.pde.internal.build.*; |
| |
| /** |
| * An <code>FetchTaskFactory</code> for building fetch scripts that will |
| * fetch content from a CVS repository (id: <code>CVS</code>). |
| * <p> |
| * <code><pre> |
| * Map file format: |
| * type@id,[version]=CVS,args |
| * args is a comma-separated list of key/value pairs |
| * Accepted args include: |
| * cvsPassFile - optional password file |
| * cvsRoot - mandatory repo location |
| * password - optional password |
| * path - optional path relative to the cvsRoot |
| * prebuilt - optional boolean value indicating that the entry points to a pre-built bundle in the repository |
| * tag - mandatory CVS tag |
| * </pre></code> |
| * </p> |
| */ |
| public class CVSFetchTaskFactory implements IFetchFactory { |
| public static final String ID = "CVS"; //$NON-NLS-1$ |
| |
| private static final String TARGET_GET_FROM_CVS = "FetchFromCVS"; //$NON-NLS-1$ |
| private static final String SEPARATOR = ","; //$NON-NLS-1$ |
| public static final String OVERRIDE_TAG = ID; |
| |
| //CVS specific keys used in the map being passed around. |
| private static final String KEY_CVSROOT = "cvsRoot"; //$NON-NLS-1$ |
| private static final String KEY_CVSPASSFILE = "cvsPassFile"; //$NON-NLS-1$ |
| private static final String KEY_PASSWORD = "password"; //$NON-NLS-1$ |
| private static final String KEY_PATH = "path"; //$NON-NLS-1$ |
| private static final String KEY_PREBUILT = "prebuilt"; //$NON-NLS-1$ |
| |
| //Properties used in the CVS part of the scripts |
| private static final String PROP_DESTINATIONFOLDER = "destinationFolder"; //$NON-NLS-1$ |
| private static final String PROP_CVSROOT = "cvsRoot"; //$NON-NLS-1$ |
| private static final String PROP_MODULE = "module"; //$NON-NLS-1$ |
| private static final String PROP_TAG = "tag"; //$NON-NLS-1$ |
| private static final String PROP_QUIET = "quiet"; //$NON-NLS-1$ |
| private static final String PROP_REALLYQUIET = "reallyquiet"; //$NON-NLS-1$ |
| private static final String PROP_FILETOCHECK = "fileToCheck"; //$NON-NLS-1$ |
| private static final String PROP_ELEMENTNAME = "elementName"; //$NON-NLS-1$ |
| |
| private void generateAuthentificationAntTask(Map<String, Object> entryInfos, IAntScript script) { |
| String password = (String) entryInfos.get(KEY_PASSWORD); |
| String cvsPassFileLocation = (String) entryInfos.get(KEY_CVSPASSFILE); |
| if (password != null) |
| printCVSPassTask((String) entryInfos.get(KEY_CVSROOT), password, cvsPassFileLocation, script); |
| } |
| |
| @Override |
| public void generateRetrieveElementCall(Map<String, Object> entryInfos, IPath destination, IAntScript script) { |
| String type = (String) entryInfos.get(KEY_ELEMENT_TYPE); |
| String element = (String) entryInfos.get(KEY_ELEMENT_NAME); |
| boolean prebuilt = Boolean.valueOf((String) entryInfos.get(KEY_PREBUILT)).booleanValue(); |
| |
| Map<String, String> params = new HashMap<>(5); |
| // we directly export the CVS content into the destination. if we have a pre-built JAR then |
| // we want to put it right in the /plugins directory and not a sub-directory so strip off 2 segments |
| // to leave us with the build directory (/plugins will be added by the "element" attribute) |
| int remove = prebuilt ? 2 : 1; |
| String suggestedPath = destination.lastSegment(); |
| params.put(PROP_DESTINATIONFOLDER, destination.removeLastSegments(remove).toString()); |
| params.put(PROP_TAG, (String) entryInfos.get(IFetchFactory.KEY_ELEMENT_TAG)); |
| params.put(PROP_CVSROOT, (String) entryInfos.get(KEY_CVSROOT)); |
| params.put(PROP_QUIET, "${cvs.quiet}"); //$NON-NLS-1$ |
| params.put(PROP_REALLYQUIET, "${cvs.reallyquiet}"); //$NON-NLS-1$ |
| // the call to CVS requires us to pass a destination directory for the files that we are |
| // retrieving, so give it the /plugins dir here |
| if (prebuilt) { |
| if (type.equals(ELEMENT_TYPE_PLUGIN)) |
| element = IPDEBuildConstants.DEFAULT_PLUGIN_LOCATION; |
| else if (type.equals(ELEMENT_TYPE_FEATURE)) |
| element = IPDEBuildConstants.DEFAULT_FEATURE_LOCATION; |
| } else { |
| if (suggestedPath != null) |
| element = suggestedPath; |
| } |
| params.put(PROP_ELEMENTNAME, element); |
| String module = entryInfos.get(KEY_PATH) == null ? element : (String) entryInfos.get(KEY_PATH); |
| params.put(PROP_MODULE, module); |
| |
| IPath locationToCheck = (IPath) destination.clone(); |
| // if we have a pre-built plug-in then we want to check the existence of the JAR file |
| // rather than the plug-in manifest. |
| if (prebuilt) { |
| locationToCheck = locationToCheck.removeLastSegments(1); |
| locationToCheck = locationToCheck.append(new Path(module).lastSegment()); |
| } else { |
| if (type.equals(ELEMENT_TYPE_FEATURE)) { |
| locationToCheck = locationToCheck.append(Constants.FEATURE_FILENAME_DESCRIPTOR); |
| } else if (type.equals(ELEMENT_TYPE_PLUGIN)) { |
| locationToCheck = locationToCheck.append(Constants.PLUGIN_FILENAME_DESCRIPTOR); |
| } else if (type.equals(ELEMENT_TYPE_FRAGMENT)) { |
| locationToCheck = locationToCheck.append(Constants.FRAGMENT_FILENAME_DESCRIPTOR); |
| } else if (type.equals(ELEMENT_TYPE_BUNDLE)) { |
| locationToCheck = locationToCheck.append(Constants.BUNDLE_FILENAME_DESCRIPTOR); |
| } |
| } |
| params.put(PROP_FILETOCHECK, locationToCheck.toString()); |
| |
| printAvailableTask(locationToCheck.toString(), locationToCheck.toString(), script); |
| if (!prebuilt && (type.equals(IFetchFactory.ELEMENT_TYPE_PLUGIN) || type.equals(IFetchFactory.ELEMENT_TYPE_FRAGMENT))) { |
| printAvailableTask(locationToCheck.toString(), locationToCheck.removeLastSegments(1).append(Constants.BUNDLE_FILENAME_DESCRIPTOR).toString(), script); |
| } |
| |
| generateAuthentificationAntTask(entryInfos, script); |
| script.printAntCallTask(TARGET_GET_FROM_CVS, true, params); |
| } |
| |
| @Override |
| public void generateRetrieveFilesCall(final Map<String, Object> entryInfos, IPath destination, final String[] files, IAntScript script) { |
| generateAuthentificationAntTask(entryInfos, script); |
| String path = (String) entryInfos.get(KEY_PATH); |
| for (int i = 0; i < files.length; i++) { |
| String file = files[i]; |
| IPath filePath; |
| if (path != null) { |
| filePath = new Path(path).append(file); |
| } else { |
| filePath = new Path((String) entryInfos.get(KEY_ELEMENT_NAME)).append(file); |
| } |
| String tag = (String) entryInfos.get(IFetchFactory.KEY_ELEMENT_TAG); |
| String cvsRoot = (String) entryInfos.get(KEY_CVSROOT); |
| String dest = "true".equalsIgnoreCase((String) entryInfos.get(KEY_PREBUILT)) ? destination.removeLastSegments(1).toString() : destination.toString(); //$NON-NLS-1$ |
| printCVSTask("export -r " + tag + ' ' + filePath.toString(), cvsRoot, dest, null, null, "true", Utils.getPropertyFormat(PROP_REALLYQUIET), null, null, "${fetch.failonerror}", script); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ |
| script.println("<move file=\"" + destination + '/' + filePath + "\"" + " tofile=\"" + destination.append(file) + "\" failonerror=\"false\" />"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| } |
| |
| @Override |
| public void addTargets(IAntScript script) { |
| script.printTargetDeclaration(TARGET_GET_FROM_CVS, null, null, "${fileToCheck}", null); //$NON-NLS-1$ |
| printCVSTask("export -d " + Utils.getPropertyFormat(PROP_ELEMENTNAME), Utils.getPropertyFormat(PROP_CVSROOT), Utils.getPropertyFormat(PROP_DESTINATIONFOLDER), Utils.getPropertyFormat(PROP_MODULE), Utils.getPropertyFormat(PROP_TAG), Utils.getPropertyFormat(PROP_QUIET), Utils.getPropertyFormat(PROP_REALLYQUIET), null, "CVS - " + Utils.getPropertyFormat(PROP_MODULE), script); //$NON-NLS-1$ //$NON-NLS-2$ |
| script.printTargetEnd(); |
| } |
| |
| /* |
| * Handle the old file format: |
| * Map file arguments: |
| * <code><TAG>,<CVSROOT>[,<PASSWORD>[,<PATH>[,<CVSPASSFILE>]]]</code> |
| */ |
| private void legacyParseMapFileEntry(String[] arguments, Properties overrideTags, Map<String, Object> entryInfos) { |
| String overrideTag = overrideTags != null ? overrideTags.getProperty(OVERRIDE_TAG) : null; |
| entryInfos.put(KEY_CVSPASSFILE, (arguments.length > 4 && !arguments[4].equals("")) ? arguments[4] : null); //$NON-NLS-1$ |
| entryInfos.put(IFetchFactory.KEY_ELEMENT_TAG, (overrideTag != null && overrideTag.trim().length() != 0 ? overrideTag : arguments[0])); |
| entryInfos.put(KEY_CVSROOT, arguments[1]); |
| entryInfos.put(KEY_PASSWORD, (arguments.length > 2 && !arguments[2].equals("")) ? arguments[2] : null); //$NON-NLS-1$ |
| entryInfos.put(KEY_PATH, (arguments.length > 3 && !arguments[3].equals("")) ? arguments[3] : null); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void parseMapFileEntry(String repoSpecificentry, Properties overrideTags, Map<String, Object> entryInfos) throws CoreException { |
| String[] arguments = Utils.getArrayFromStringWithBlank(repoSpecificentry, SEPARATOR); |
| if (arguments.length < 2) { |
| String message = NLS.bind(Messages.error_incorrectDirectoryEntry, entryInfos.get(KEY_ELEMENT_NAME)); |
| throw new CoreException(new Status(IStatus.ERROR, IPDEBuildConstants.PI_PDEBUILD, 1, message, null)); //TODO Need to fix this |
| } |
| |
| // build up the table of arguments in the map file entry |
| Map<String, String> table = new HashMap<>(); |
| for (int i = 0; i < arguments.length; i++) { |
| String arg = arguments[i]; |
| // if we have at least one arg without an equals sign, then |
| // revert back to the legacy parsing |
| int index = arg.indexOf('='); |
| if (index == -1) { |
| legacyParseMapFileEntry(arguments, overrideTags, entryInfos); |
| addProjectReference(entryInfos); |
| return; |
| } |
| String key = arg.substring(0, index); |
| String value = arg.substring(index + 1); |
| table.put(key, value); |
| } |
| |
| // add entries to the entryInfo map here instead of inside the loop |
| // in case we revert to legacy parsing in the middle of the loop (we |
| // don't want to contaminate entryInfos |
| entryInfos.put(KEY_CVSPASSFILE, table.get(KEY_CVSPASSFILE)); |
| String overrideTag = overrideTags != null ? overrideTags.getProperty(OVERRIDE_TAG) : null; |
| entryInfos.put(IFetchFactory.KEY_ELEMENT_TAG, (overrideTag != null && overrideTag.trim().length() != 0 ? overrideTag : table.get(IFetchFactory.KEY_ELEMENT_TAG))); |
| entryInfos.put(KEY_CVSROOT, table.get(KEY_CVSROOT)); |
| entryInfos.put(KEY_PASSWORD, table.get(KEY_PASSWORD)); |
| entryInfos.put(KEY_PATH, table.get(KEY_PATH)); |
| entryInfos.put(KEY_PREBUILT, table.get(KEY_PREBUILT)); |
| addProjectReference(entryInfos); |
| } |
| |
| private void addProjectReference(Map<String, Object> entryInfos) { |
| String repoLocation = (String) entryInfos.get(KEY_CVSROOT); |
| String module = (String) entryInfos.get(KEY_PATH); |
| String projectName = (String) entryInfos.get(KEY_ELEMENT_NAME); |
| String tag = (String) entryInfos.get(IFetchFactory.KEY_ELEMENT_TAG); |
| |
| if (repoLocation != null && projectName != null) { |
| String sourceURLs = asReference(repoLocation, module != null ? module : projectName, projectName, tag); |
| if (sourceURLs != null) { |
| entryInfos.put(Constants.KEY_SOURCE_REFERENCES, sourceURLs); |
| } |
| } |
| } |
| |
| /** |
| * Creates an SCMURL reference to the associated source. |
| * |
| * @param repoLocation |
| * @param module |
| * @param projectName |
| * @return project reference string or <code>null</code> if none |
| */ |
| private String asReference(String repoLocation, String module, String projectName, String tagName) { |
| // parse protocol, host, repository root from repoLocation |
| String protocol = null; |
| String host = null; |
| String root = null; |
| |
| int at = repoLocation.indexOf('@'); |
| if (at < 0) { |
| // should be a local protocol |
| if (repoLocation.startsWith(":local:")) { //$NON-NLS-1$ |
| protocol = "local"; //$NON-NLS-1$ |
| root = repoLocation.substring(7); |
| } |
| } else if (at < (repoLocation.length() - 2)) { |
| String serverRoot = repoLocation.substring(at + 1); |
| String protocolUserPass = repoLocation.substring(0, at); |
| int colon = serverRoot.indexOf(':'); |
| if (colon > 0) { |
| host = serverRoot.substring(0, colon); |
| if (colon < (serverRoot.length() - 2)) { |
| root = serverRoot.substring(colon + 1); |
| } |
| if (protocolUserPass.startsWith(":")) { //$NON-NLS-1$ |
| colon = protocolUserPass.indexOf(':', 1); |
| if (colon > 0) { |
| protocol = protocolUserPass.substring(1, colon); |
| } |
| } else { |
| // missing protocol, assume p-server |
| protocol = "pserver"; //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| if (protocol == null || root == null) { |
| return null; // invalid syntax |
| } |
| |
| // use '|' as separator if the root location uses a colon for a Windows path |
| String sep = ":"; //$NON-NLS-1$ |
| if (root.indexOf(':') >= 0) { |
| sep = "|"; //$NON-NLS-1$ |
| } |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append("scm:cvs"); //$NON-NLS-1$ |
| buffer.append(sep); |
| buffer.append(protocol); |
| buffer.append(sep); |
| if (host != null) { |
| buffer.append(host); |
| buffer.append(sep); |
| } |
| buffer.append(root); |
| buffer.append(sep); |
| buffer.append(module); |
| |
| Path modulePath = new Path(module); |
| if (!modulePath.lastSegment().equals(projectName)) { |
| buffer.append(";project=\""); //$NON-NLS-1$ |
| buffer.append(projectName); |
| buffer.append('"'); |
| } |
| |
| if (tagName != null && !tagName.equals("HEAD")) { //$NON-NLS-1$ |
| buffer.append(";tag="); //$NON-NLS-1$ |
| buffer.append(tagName); |
| } |
| return buffer.toString(); |
| } |
| |
| /** |
| * Print a <code>cvs</code> task to the Ant script. |
| * |
| * @param command the CVS command to run |
| * @param cvsRoot value for the CVSROOT variable |
| * @param dest the destination directory for the checked out resources |
| * @param module the module name to check out |
| * @param tag the tag of the module to check out |
| * @param quiet whether or not to print informational messages to the output |
| * @param reallyquiet whether or not to print any messages to the output |
| * @param passFile the name of the password file |
| */ |
| private void printCVSTask(String command, String cvsRoot, String dest, String module, String tag, String quiet, String reallyquiet, String passFile, String taskname, IAntScript script) { |
| printCVSTask(command, cvsRoot, dest, module, tag, quiet, reallyquiet, passFile, taskname, null, script); |
| } |
| |
| /** |
| * Print a <code>cvs</code> task to the Ant script. |
| * |
| * @param command the CVS command to run |
| * @param cvsRoot value for the CVSROOT variable |
| * @param dest the destination directory for the checked out resources |
| * @param module the module name to check out |
| * @param tag the tag of the module to check out |
| * @param quiet whether or not to print informational messages to the output |
| * @param reallyquiet whether or not to print any messages to the output |
| * @param passFile the name of the password file |
| * @param failOnError whether or not to throw an exception if something goes wrong |
| */ |
| private void printCVSTask(String command, String cvsRoot, String dest, String module, String tag, String quiet, String reallyquiet, String passFile, String taskname, String failOnError, IAntScript script) { |
| script.printTabs(); |
| script.print("<cvs"); //$NON-NLS-1$ |
| script.printAttribute("command", command, false); //$NON-NLS-1$ |
| script.printAttribute("cvsRoot", cvsRoot, false); //$NON-NLS-1$ |
| script.printAttribute("dest", dest, false); //$NON-NLS-1$ |
| script.printAttribute("package", module, false); //$NON-NLS-1$ |
| script.printAttribute("tag", tag, false); //$NON-NLS-1$ |
| script.printAttribute("quiet", quiet, false); //$NON-NLS-1$ |
| script.printAttribute("reallyquiet", reallyquiet, false); //$NON-NLS-1$ |
| script.printAttribute("passfile", passFile, false); //$NON-NLS-1$ |
| script.printAttribute("taskname", taskname, false); //$NON-NLS-1$ |
| script.printAttribute("failonerror", failOnError, false); //$NON-NLS-1$ |
| script.println("/>"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Print a <code>cvspass</code> task to the Ant script. |
| * |
| * @param cvsRoot the name of the repository |
| * @param password the password |
| * @param passFile the name of the password file |
| */ |
| private void printCVSPassTask(String cvsRoot, String password, String passFile, IAntScript script) { |
| script.printTabs(); |
| script.print("<cvspass"); //$NON-NLS-1$ |
| script.printAttribute("cvsRoot", cvsRoot, true); //$NON-NLS-1$ |
| script.printAttribute("password", password, true); //$NON-NLS-1$ |
| script.printAttribute("passfile", passFile, false); //$NON-NLS-1$ |
| script.println("/>"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Print the <code>available</code> Ant task to this script. This task sets a property |
| * value if the given file exists at runtime. |
| * |
| * @param property the property to set |
| * @param file the file to look for |
| */ |
| private void printAvailableTask(String property, String file, IAntScript script) { |
| script.printTabs(); |
| script.print("<available"); //$NON-NLS-1$ |
| script.printAttribute("property", property, true); //$NON-NLS-1$ |
| script.printAttribute("file", file, false); //$NON-NLS-1$ |
| script.println("/>"); //$NON-NLS-1$ |
| } |
| } |