| /******************************************************************************* |
| * 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 |
| *******************************************************************************/ |
| package org.eclipse.pde.internal.build; |
| |
| import java.io.*; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.*; |
| import java.util.Map.Entry; |
| import java.util.zip.ZipFile; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.p2.publisher.eclipse.FeatureEntry; |
| import org.eclipse.osgi.service.resolver.BundleDescription; |
| import org.eclipse.osgi.service.resolver.VersionRange; |
| import org.eclipse.osgi.util.ManifestElement; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.pde.internal.build.ant.AntScript; |
| import org.eclipse.pde.internal.build.site.BuildTimeFeature; |
| import org.eclipse.pde.internal.build.site.BuildTimeSite; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.Version; |
| |
| /** |
| * General utility class. |
| */ |
| public final class Utils implements IPDEBuildConstants, IBuildPropertiesConstants, IXMLConstants { |
| static class ArrayEnumeration implements Enumeration<Object> { |
| private final Object[] array; |
| int cur = 0; |
| |
| public ArrayEnumeration(Object[] array) { |
| this.array = new Object[array.length]; |
| System.arraycopy(array, 0, this.array, 0, this.array.length); |
| } |
| |
| @Override |
| public boolean hasMoreElements() { |
| return cur < array.length; |
| } |
| |
| @Override |
| public Object nextElement() { |
| return array[cur++]; |
| } |
| } |
| |
| // The 64 characters that are legal in a version qualifier, in lexicographical order. |
| private static final String BASE_64_ENCODING = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; //$NON-NLS-1$ |
| |
| // regex expressions and keys for parsing feature root properties |
| private static final String REGEX_ROOT_CONFIG = "^root((\\.[\\w-\\*]+){3})$"; //$NON-NLS-1$ |
| private static final String REGEX_ROOT_CONFIG_FOLDER = "^root((\\.[\\w-\\*]+){3})?\\.folder\\.(.*)$"; //$NON-NLS-1$ |
| private static final String REGEX_ROOT_CONFIG_PERMISSIONS = "^root((\\.[\\w-\\*]+){3})?\\.permissions\\.(.*)$"; //$NON-NLS-1$ |
| private static final String REGEX_ROOT_CONFIG_LINK = "^root((\\.[\\w-\\*]+){3})?\\.link$"; //$NON-NLS-1$ |
| public static final String ROOT_PERMISSIONS = "!!ROOT.PERMISSIONS!!"; //$NON-NLS-1$ |
| public static final String ROOT_LINK = "!!ROOT.LINK!!"; //$NON-NLS-1$ |
| public static final String ROOT_COMMON = "!!COMMON!!"; //$NON-NLS-1$ |
| |
| /** |
| * returns a value 1 - 64 for valid qualifier characters. Returns 0 for non-valid characters |
| */ |
| public static int qualifierCharValue(char c) { |
| int index = BASE_64_ENCODING.indexOf(c); |
| // The "+ 1" is very intentional. For a blank (or anything else that |
| // is not a legal character), we want to return 0. For legal |
| // characters, we want to return one greater than their position, so |
| // that a blank is correctly distinguished from '-'. |
| return index + 1; |
| } |
| |
| // Integer to character conversion in our base-64 encoding scheme. If the |
| // input is out of range, an illegal character will be returned. |
| public static char base64Character(int number) { |
| if (number < 0 || number > 63) { |
| return ' '; |
| } |
| return BASE_64_ENCODING.charAt(number); |
| } |
| |
| public static VersionRange createVersionRange(String versionId) { |
| VersionRange range = null; |
| if (versionId == null || versionId.length() == 0 || GENERIC_VERSION_NUMBER.equals(versionId)) |
| range = VersionRange.emptyRange; |
| else { |
| int qualifierIdx = versionId.indexOf(IBuildPropertiesConstants.PROPERTY_QUALIFIER); |
| if (qualifierIdx != -1) { |
| String newVersion = versionId.substring(0, qualifierIdx); |
| if (newVersion.endsWith(".")) //$NON-NLS-1$ |
| newVersion = newVersion.substring(0, newVersion.length() - 1); |
| |
| Version lower = new Version(newVersion); |
| Version upper = null; |
| String newQualifier = incrementQualifier(lower.getQualifier()); |
| if (newQualifier == null) |
| upper = new Version(lower.getMajor(), lower.getMinor(), lower.getMicro() + 1); |
| else |
| upper = new Version(lower.getMajor(), lower.getMinor(), lower.getMicro(), newQualifier); |
| range = new VersionRange(lower, true, upper, false); |
| } else { |
| range = new VersionRange(new Version(versionId), true, new Version(versionId), true); |
| } |
| } |
| return range; |
| } |
| |
| public static VersionRange createVersionRange(FeatureEntry entry) { |
| String versionSpec = entry.getVersion(); |
| if (versionSpec == null) |
| return VersionRange.emptyRange; |
| |
| Version version = new Version(versionSpec); |
| if (version.equals(Version.emptyVersion)) |
| return VersionRange.emptyRange; |
| |
| String match = entry.getMatch(); |
| if (!entry.isRequires() || match == null) { |
| return createVersionRange(versionSpec); |
| } |
| |
| if (match.equals("perfect")) //$NON-NLS-1$ |
| return new VersionRange(version, true, version, true); |
| if (match.equals("equivalent")) { //$NON-NLS-1$ |
| Version upper = new Version(version.getMajor(), version.getMinor() + 1, 0); |
| return new VersionRange(version, true, upper, false); |
| } |
| if (match.equals("compatible")) { //$NON-NLS-1$ |
| Version upper = new Version(version.getMajor() + 1, 0, 0); |
| return new VersionRange(version, true, upper, false); |
| } |
| if (match.equals("greaterOrEqual")) //$NON-NLS-1$ |
| return new VersionRange(version, true, new VersionRange(null).getMaximum(), true); |
| |
| return VersionRange.emptyRange; |
| } |
| |
| private static String incrementQualifier(String qualifier) { |
| int idx = qualifier.length() - 1; |
| |
| for (; idx >= 0; idx--) { |
| //finding last non-'z' character |
| if (qualifier.charAt(idx) != 'z') |
| break; |
| } |
| |
| if (idx >= 0) { |
| // qualifierCharValue returns 1 - 64, this is an implicit +1 over |
| // the characters returned by base64Character |
| int c = Utils.qualifierCharValue(qualifier.charAt(idx)); |
| String newQualifier = qualifier.substring(0, idx); |
| newQualifier += Utils.base64Character(c); |
| return newQualifier; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Convert a list of tokens into an array. The list separator has to be |
| * specified. |
| */ |
| public static String[] getArrayFromString(String list, String separator) { |
| if (list == null || list.trim().equals("")) //$NON-NLS-1$ |
| return new String[0]; |
| List<String> result = new ArrayList<>(); |
| for (StringTokenizer tokens = new StringTokenizer(list, separator); tokens.hasMoreTokens();) { |
| String token = tokens.nextToken().trim(); |
| if (!token.equals("")) //$NON-NLS-1$ |
| result.add(token); |
| } |
| return result.toArray(new String[result.size()]); |
| } |
| |
| /** |
| * Convert a list of tokens into an array. The list separator has to be |
| * specified. The spcecificity of this method is that it returns an empty |
| * element when to same separators are following each others. For example |
| * the string a,,b returns the following array [a, ,b] |
| * |
| */ |
| public static String[] getArrayFromStringWithBlank(String list, String separator) { |
| if (list == null || list.trim().length() == 0) |
| return new String[0]; |
| List<String> result = new ArrayList<>(); |
| boolean previousWasSeparator = true; |
| for (StringTokenizer tokens = new StringTokenizer(list, separator, true); tokens.hasMoreTokens();) { |
| String token = tokens.nextToken().trim(); |
| if (token.equals(separator)) { |
| if (previousWasSeparator) |
| result.add(""); //$NON-NLS-1$ |
| previousWasSeparator = true; |
| } else { |
| result.add(token); |
| previousWasSeparator = false; |
| } |
| } |
| return result.toArray(new String[result.size()]); |
| } |
| |
| /** |
| * Return a string array constructed from the given list of comma-separated |
| * tokens. |
| * |
| * @param list |
| * the list to convert |
| * @return the array of strings |
| */ |
| public static String[] getArrayFromString(String list) { |
| return getArrayFromString(list, ","); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Converts an array of strings into an array of URLs. |
| * |
| * @param target |
| * @return URL[] |
| * @throws CoreException |
| */ |
| public static URL[] asURL(String[] target) throws CoreException { |
| if (target == null) |
| return null; |
| try { |
| URL[] result = new URL[target.length]; |
| for (int i = 0; i < target.length; i++) |
| result[i] = new URL(target[i]); |
| return result; |
| } catch (MalformedURLException e) { |
| throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_MALFORMED_URL, e.getMessage(), e)); |
| } |
| } |
| |
| public static URL[] asURL(Collection<File> target) throws CoreException { |
| if (target == null) |
| return null; |
| try { |
| URL[] result = new URL[target.size()]; |
| int i = 0; |
| for (Iterator<File> iter = target.iterator(); iter.hasNext();) { |
| result[i++] = iter.next().toURL(); |
| } |
| return result; |
| } catch (MalformedURLException e) { |
| throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_MALFORMED_URL, e.getMessage(), e)); |
| } |
| } |
| |
| public static File[] asFile(String[] target) { |
| if (target == null) |
| return new File[0]; |
| File[] result = new File[target.length]; |
| for (int i = 0; i < result.length; i++) { |
| result[i] = new File(target[i]); |
| } |
| return result; |
| } |
| |
| public static File[] asFile(URL[] target) { |
| if (target == null) |
| return new File[0]; |
| File[] result = new File[target.length]; |
| for (int i = 0; i < result.length; i++) { |
| result[i] = new File(target[i].getFile()); |
| } |
| return result; |
| } |
| |
| public static File[] asFile(Collection<?> collection) { |
| if (collection.size() == 0) |
| return new File[0]; |
| Object first = collection.iterator().next(); |
| if (first instanceof String) |
| return asFile(collection.toArray(new String[collection.size()])); |
| else if (first instanceof URL) |
| return asFile(collection.toArray(new URL[collection.size()])); |
| else if (first instanceof File) |
| return collection.toArray(new File[collection.size()]); |
| throw new IllegalArgumentException(); |
| } |
| |
| /** |
| * Return a string which is a concatination of each member of the given |
| * collection, separated by the given separator. |
| * |
| * @param collection |
| * the collection to concatinate |
| * @param separator |
| * the separator to use |
| * @return String |
| */ |
| public static String getStringFromCollection(Collection<?> collection, String separator) { |
| StringBuffer result = new StringBuffer(); |
| boolean first = true; |
| for (Iterator<?> i = collection.iterator(); i.hasNext();) { |
| if (first) |
| first = false; |
| else |
| result.append(separator); |
| result.append(i.next()); |
| } |
| return result.toString(); |
| } |
| |
| /** |
| * Return a string which is a concatination of each member of the given |
| * array, separated by the given separator. |
| * |
| * @param values |
| * the array to concatinate |
| * @param separator |
| * the separator to use |
| * @return String |
| */ |
| public static String getStringFromArray(String[] values, String separator) { |
| StringBuffer result = new StringBuffer(); |
| for (int i = 0; i < values.length; i++) { |
| if (values[i] != null) { |
| if (i > 0) |
| result.append(separator); |
| result.append(values[i]); |
| } |
| } |
| return result.toString(); |
| } |
| |
| /** |
| * Return a path which is equivalent to the given location relative to the |
| * specified base path. |
| * |
| * @param location |
| * the location to convert |
| * @param base |
| * the base path |
| * @return IPath |
| */ |
| public static IPath makeRelative(IPath location, IPath base) { |
| //can't make relative if the devices don't match |
| if (location.getDevice() == null) { |
| if (base.getDevice() != null) |
| return location; |
| } else { |
| if (!location.getDevice().equalsIgnoreCase(base.getDevice())) |
| return location; |
| } |
| int baseCount = base.segmentCount(); |
| int count = base.matchingFirstSegments(location); |
| String temp = ""; //$NON-NLS-1$ |
| for (int j = 0; j < baseCount - count; j++) |
| temp += "../"; //$NON-NLS-1$ |
| return new Path(temp).append(location.removeFirstSegments(count)); |
| } |
| |
| /** |
| * Transfers all available bytes from the given input stream to the given |
| * output stream. Regardless of failure, this method closes both streams. |
| * |
| * @param source |
| * @param destination |
| * @throws IOException |
| */ |
| public static void transferStreams(InputStream source, OutputStream destination) throws IOException { |
| source = new BufferedInputStream(source); |
| destination = new BufferedOutputStream(destination); |
| try { |
| byte[] buffer = new byte[8192]; |
| while (true) { |
| int bytesRead = -1; |
| if ((bytesRead = source.read(buffer)) == -1) |
| break; |
| destination.write(buffer, 0, bytesRead); |
| } |
| } finally { |
| try { |
| source.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| try { |
| destination.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| } |
| } |
| |
| static public void copyFile(String src, String dest) throws IOException { |
| File source = new File(src); |
| if (!source.exists()) |
| return; |
| File destination = new File(dest); |
| File destDir = destination.getParentFile(); |
| if ((!destDir.exists() && !destDir.mkdirs()) || destDir.isFile()) |
| return; //we will fail trying to create the file, TODO log warning/error |
| |
| copy(source, destination); |
| } |
| |
| public static void copy(File source, File destination) throws IOException { |
| org.eclipse.pde.internal.publishing.Utils.copy(source, destination); |
| } |
| |
| public static void writeBuffer(StringBuffer buffer, File outputFile) throws IOException { |
| FileOutputStream stream = null; |
| try { |
| outputFile.getParentFile().mkdirs(); |
| stream = new FileOutputStream(outputFile); |
| stream.write(buffer.toString().getBytes()); |
| } finally { |
| close(stream); |
| } |
| } |
| |
| public static void writeProperties(Properties properites, File outputFile, String comment) throws IOException { |
| outputFile.getParentFile().mkdirs(); |
| OutputStream buildFile = new BufferedOutputStream(new FileOutputStream(outputFile)); |
| try { |
| properites.store(buildFile, comment); |
| } finally { |
| close(buildFile); |
| } |
| } |
| |
| public static FeatureEntry[] getPluginEntry(BuildTimeFeature feature, String pluginId, boolean raw) { |
| FeatureEntry[] plugins; |
| if (raw) |
| plugins = feature.getRawPluginEntries(); |
| else |
| plugins = feature.getPluginEntries(); |
| List<FeatureEntry> foundEntries = new ArrayList<>(5); |
| |
| for (int i = 0; i < plugins.length; i++) { |
| if (plugins[i].getId().equals(pluginId)) |
| foundEntries.add(plugins[i]); |
| } |
| return foundEntries.toArray(new FeatureEntry[foundEntries.size()]); |
| |
| } |
| |
| // Return a collection of File, the result can be null |
| public static Collection<File> findFiles(File from, String foldername, final String filename) { |
| // if from is a file which name match filename, then simply return the |
| // file |
| File root = from; |
| if (root.isFile() && root.getName().equals(filename)) { |
| Collection<File> coll = new ArrayList<>(1); |
| coll.add(root); |
| return coll; |
| } |
| |
| Collection<File> collectedElements = new ArrayList<>(10); |
| |
| File[] featureDirectoryContent = new File(from, foldername).listFiles(); |
| if (featureDirectoryContent == null) |
| return null; |
| |
| for (int i = 0; i < featureDirectoryContent.length; i++) { |
| if (featureDirectoryContent[i].isDirectory()) { |
| File[] featureFiles = featureDirectoryContent[i].listFiles(new FilenameFilter() { |
| @Override |
| public boolean accept(File dir, String name) { |
| return name.equals(filename); |
| } |
| }); |
| if (featureFiles.length != 0) |
| collectedElements.add(featureFiles[0]); |
| } |
| } |
| return collectedElements; |
| } |
| |
| public static boolean isIn(FeatureEntry[] array, FeatureEntry element) { |
| for (int i = 0; i < array.length; i++) { |
| if (array[i].getId().equals(element.getId()) && array[i].getVersion().equals(element.getVersion())) |
| return true; |
| } |
| return false; |
| } |
| |
| public static Collection<String> copyFiles(String fromDir, String toDir) throws CoreException { |
| File templateLocation = new File(fromDir); |
| Collection<String> copiedFiles = new ArrayList<>(); |
| if (templateLocation.exists()) { |
| File[] files = templateLocation.listFiles(); |
| if (files != null) { |
| for (int i = 0; i < files.length; i++) { |
| if (files[i].isDirectory()) { |
| File subDir = new File(toDir, files[i].getName()); |
| if (!subDir.exists()) |
| subDir.mkdirs(); |
| Collection<String> subFiles = copyFiles(fromDir + '/' + files[i].getName(), toDir + '/' + files[i].getName()); |
| for (Iterator<String> iter = subFiles.iterator(); iter.hasNext();) { |
| String sub = iter.next(); |
| copiedFiles.add(files[i].getName() + '/' + sub); |
| } |
| continue; |
| } |
| |
| FileInputStream inputStream = null; |
| FileOutputStream outputStream = null; |
| |
| try { |
| inputStream = new FileInputStream(files[i]); |
| } catch (FileNotFoundException e) { |
| String message = NLS.bind(Messages.exception_missingFile, files[i].getAbsolutePath()); |
| throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_READING_FILE, message, e)); |
| } |
| |
| String fileToCopy = toDir + '/' + files[i].getName(); |
| try { |
| outputStream = new FileOutputStream(fileToCopy); |
| } catch (FileNotFoundException e) { |
| try { |
| inputStream.close(); |
| } catch (IOException e1) { |
| // Ignored |
| } |
| String message = NLS.bind(Messages.exception_missingFile, fileToCopy); |
| throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_READING_FILE, message, e)); |
| } |
| |
| try { |
| Utils.transferStreams(inputStream, outputStream); |
| copiedFiles.add(files[i].getName()); |
| } catch (IOException e) { |
| String message = NLS.bind(Messages.exception_writingFile, fileToCopy); |
| throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_WRITING_FILE, message, e)); |
| } |
| } |
| } |
| } |
| return copiedFiles; |
| } |
| |
| public static List<BundleDescription> extractPlugins(List<BundleDescription> initialList, Set<BundleDescription> toExtract) { |
| //TODO This algorithm needs to be improved |
| if (initialList.size() == toExtract.size()) |
| return initialList; |
| List<BundleDescription> result = new ArrayList<>(toExtract.size()); |
| for (Iterator<BundleDescription> iter = initialList.iterator(); iter.hasNext();) { |
| BundleDescription element = iter.next(); |
| if (toExtract.contains(element)) { |
| result.add(element); |
| if (result.size() == toExtract.size()) |
| break; |
| } |
| } |
| return result; |
| } |
| |
| public static int isStringIn(String[] searched, String toSearch) { |
| if (searched == null || toSearch == null) |
| return -1; |
| for (int i = 0; i < searched.length; i++) { |
| if (toSearch.startsWith(searched[i])) |
| return i; |
| } |
| return -1; |
| } |
| |
| static public Properties getOldExecutableRootOverrides() { |
| Properties overrides = new Properties(); |
| overrides.put("root.win32.win32.x86", "file:bin/win32/win32/x86/launcher.exe"); //$NON-NLS-1$ //$NON-NLS-2$ |
| overrides.put("root.win32.win32.x86_64", "file:bin/win32/win32/x86_64/launcher.exe"); //$NON-NLS-1$ //$NON-NLS-2$ |
| overrides.put("root.win32.wpf.x86", "file:bin/wpf/win32/x86/launcher.exe"); //$NON-NLS-1$ //$NON-NLS-2$ |
| return overrides; |
| } |
| |
| /** |
| * Process root file properties. |
| * Resulting map is from config string to a property map. The format of the property map is: |
| * 1) folder -> fileset to copy. folder can be "" (the root) or an actual folder |
| * 2) ROOT_PERMISSIONS + rights -> fileset to set rights for |
| * 3) ROOT_LINK -> comma separated list: (target, link)* |
| * |
| * Properties that are common across all configs are available under the ROOT_COMMON key. |
| * They are also optionally merged into each individual config. |
| |
| * @param properties - build.properties for a feature |
| * @param mergeCommon - whether or not to merge the common properties into each config |
| * @return Map |
| */ |
| static public Map<String, Map<String, String>> processRootProperties(Properties properties, boolean mergeCommon) { |
| Map<String, Map<String, String>> map = new HashMap<>(); |
| Map<String, String> common = new HashMap<>(); |
| for (Enumeration<Object> keys = properties.keys(); keys.hasMoreElements();) { |
| String entry = (String) keys.nextElement(); |
| String config = null; |
| String entryKey = null; |
| |
| if (entry.equals(ROOT) || entry.matches(REGEX_ROOT_CONFIG)) { |
| config = entry.length() > 4 ? entry.substring(5) : ""; //$NON-NLS-1$ |
| entryKey = ""; //$NON-NLS-1$ |
| } else if (entry.matches(REGEX_ROOT_CONFIG_FOLDER)) { |
| int folderIdx = entry.indexOf(FOLDER_INFIX); |
| config = (folderIdx > 5) ? entry.substring(5, folderIdx) : ""; //$NON-NLS-1$ |
| entryKey = entry.substring(folderIdx + 8); |
| } else if (entry.matches(REGEX_ROOT_CONFIG_PERMISSIONS)) { |
| int permissionIdx = entry.indexOf(PERMISSIONS_INFIX); |
| config = (permissionIdx > 5) ? entry.substring(5, permissionIdx) : ""; //$NON-NLS-1$ |
| entryKey = ROOT_PERMISSIONS + entry.substring(permissionIdx + 13); |
| } else if (entry.matches(REGEX_ROOT_CONFIG_LINK)) { |
| int linkIdx = entry.indexOf(LINK_SUFFIX); |
| config = (linkIdx > 5) ? entry.substring(5, linkIdx) : ""; //$NON-NLS-1$ |
| entryKey = ROOT_LINK; |
| } |
| |
| if (config != null) { |
| Map<String, String> submap = (config.length() == 0) ? common : map.get(config); |
| if (submap == null) { |
| submap = new HashMap<>(); |
| map.put(config, submap); |
| } |
| if (submap.containsKey(entryKey)) { |
| String existing = submap.get(entryKey); |
| submap.put(entryKey, existing + "," + properties.getProperty(entry)); //$NON-NLS-1$ |
| } else { |
| submap.put(entryKey, (String) properties.get(entry)); |
| } |
| } |
| } |
| |
| //merge the common properties into each of the configs |
| if (common.size() > 0 && mergeCommon) { |
| for (Iterator<String> iterator = map.keySet().iterator(); iterator.hasNext();) { |
| String key = iterator.next(); |
| Map<String, String> submap = map.get(key); |
| for (Iterator<String> commonKeys = common.keySet().iterator(); commonKeys.hasNext();) { |
| String commonKey = commonKeys.next(); |
| if (submap.containsKey(commonKey)) { |
| String existing = submap.get(commonKey); |
| submap.put(commonKey, existing + "," + common.get(commonKey)); //$NON-NLS-1$ |
| } else { |
| submap.put(commonKey, common.get(commonKey)); |
| } |
| } |
| } |
| } |
| |
| //and also add the common properties independently |
| if (mergeCommon || common.size() > 0) |
| map.put(ROOT_COMMON, common); |
| return map; |
| } |
| |
| public static void generatePermissions(Properties featureProperties, Config aConfig, String targetRootProperty, AntScript script) { |
| if (featureProperties == null) |
| return; |
| String configInfix = aConfig.toString("."); //$NON-NLS-1$ |
| String configPath = aConfig.toStringReplacingAny(".", ANY_STRING); //$NON-NLS-1$ |
| String prefixPermissions = ROOT_PREFIX + configInfix + '.' + PERMISSIONS + '.'; |
| String prefixLinks = ROOT_PREFIX + configInfix + '.' + LINK; |
| String commonPermissions = ROOT_PREFIX + PERMISSIONS + '.'; |
| String commonLinks = ROOT_PREFIX + LINK; |
| for (Iterator<Entry<Object, Object>> iter = featureProperties.entrySet().iterator(); iter.hasNext();) { |
| Map.Entry<Object, Object> permission = iter.next(); |
| String instruction = (String) permission.getKey(); |
| String parameters = removeEndingSlashes((String) permission.getValue()); |
| if (instruction.startsWith(prefixPermissions)) { |
| generateChmodInstruction(script, getPropertyFormat(targetRootProperty) + '/' + configPath + '/' + getPropertyFormat(PROPERTY_COLLECTING_FOLDER), instruction.substring(prefixPermissions.length()), parameters); |
| continue; |
| } |
| if (instruction.startsWith(prefixLinks)) { |
| generateLinkInstruction(script, getPropertyFormat(targetRootProperty) + '/' + configPath + '/' + getPropertyFormat(PROPERTY_COLLECTING_FOLDER), parameters); |
| continue; |
| } |
| if (instruction.startsWith(commonPermissions)) { |
| generateChmodInstruction(script, getPropertyFormat(targetRootProperty) + '/' + configPath + '/' + getPropertyFormat(PROPERTY_COLLECTING_FOLDER), instruction.substring(commonPermissions.length()), parameters); |
| continue; |
| } |
| if (instruction.startsWith(commonLinks)) { |
| generateLinkInstruction(script, getPropertyFormat(targetRootProperty) + '/' + configPath + '/' + getPropertyFormat(PROPERTY_COLLECTING_FOLDER), parameters); |
| continue; |
| } |
| } |
| } |
| |
| public static String removeEndingSlashes(String value) { |
| String[] params = Utils.getArrayFromString(value, ","); //$NON-NLS-1$ |
| for (int i = 0; i < params.length; i++) { |
| if (params[i].endsWith("/")) //$NON-NLS-1$ |
| params[i] = params[i].substring(0, params[i].length() - 1); |
| } |
| return Utils.getStringFromArray(params, ","); //$NON-NLS-1$ |
| } |
| |
| private static void generateChmodInstruction(AntScript script, String dir, String rights, String files) { |
| if (rights.equals(EXECUTABLE)) { |
| rights = "755"; //$NON-NLS-1$ |
| } |
| script.printChmod(dir, rights, files); |
| } |
| |
| private static void generateLinkInstruction(AntScript script, String dir, String files) { |
| String[] links = Utils.getArrayFromString(files, ","); //$NON-NLS-1$ |
| List<String> arguments = new ArrayList<>(2); |
| for (int i = 0; i < links.length; i += 2) { |
| arguments.add("-sf"); //$NON-NLS-1$ |
| arguments.add(links[i]); |
| arguments.add(links[i + 1]); |
| script.printExecTask("ln", dir, arguments, "Linux"); //$NON-NLS-1$ //$NON-NLS-2$ |
| arguments.clear(); |
| } |
| } |
| |
| /** |
| * Return a string with the given property name in the format: |
| * <pre>${propertyName}</pre>. |
| * |
| * @param propertyName the name of the property |
| * @return String |
| */ |
| public static String getPropertyFormat(String propertyName) { |
| StringBuffer sb = new StringBuffer(); |
| sb.append(PROPERTY_ASSIGNMENT_PREFIX); |
| sb.append(propertyName); |
| sb.append(PROPERTY_ASSIGNMENT_SUFFIX); |
| return sb.toString(); |
| } |
| |
| public static String getMacroFormat(String propertyName) { |
| StringBuffer sb = new StringBuffer(); |
| sb.append(MACRO_ASSIGNMENT_PREFIX); |
| sb.append(propertyName); |
| sb.append(PROPERTY_ASSIGNMENT_SUFFIX); |
| return sb.toString(); |
| } |
| |
| public static boolean isBinary(BundleDescription bundle) { |
| Properties bundleProperties = ((Properties) bundle.getUserObject()); |
| if (bundleProperties == null || bundleProperties.get(IS_COMPILED) == null) { |
| File props = new File(bundle.getLocation(), PROPERTIES_FILE); |
| return !(props.exists() && props.isFile()); |
| } |
| return (Boolean.FALSE == bundleProperties.get(IS_COMPILED)); |
| } |
| |
| public static boolean isSourceBundle(BundleDescription bundle) { |
| Properties bundleProperties = (Properties) bundle.getUserObject(); |
| return (bundleProperties != null && bundleProperties.containsKey(ECLIPSE_SOURCE_BUNDLE)); |
| } |
| |
| public static boolean hasBundleShapeHeader(BundleDescription bundle) { |
| Properties bundleProperties = (Properties) bundle.getUserObject(); |
| return (bundleProperties != null && bundleProperties.containsKey(ECLIPSE_BUNDLE_SHAPE)); |
| } |
| |
| public static String getSourceBundleHeader(BundleDescription bundle) { |
| Properties bundleProperties = (Properties) bundle.getUserObject(); |
| if (bundleProperties == null || !bundleProperties.containsKey(ECLIPSE_SOURCE_BUNDLE)) |
| return ""; //$NON-NLS-1$ |
| |
| String header = bundleProperties.getProperty(ECLIPSE_SOURCE_BUNDLE); |
| return header; |
| } |
| |
| /** |
| * Given a newly generated old-style source bundle for which there was a previously existing |
| * version in the target, return the location of the src folder in that earlier version |
| * @param bundle |
| * @return the old version's src folder, or null |
| */ |
| public static File getOldSourceLocation(BundleDescription bundle) { |
| Properties props = (Properties) bundle.getUserObject(); |
| if (props == null || !props.containsKey(OLD_BUNDLE_LOCATION)) |
| return null; |
| |
| String oldBundleLocation = props.getProperty(OLD_BUNDLE_LOCATION); |
| if (oldBundleLocation != null) { |
| File previousSrcRoot = new File(oldBundleLocation, "src"); //$NON-NLS-1$ |
| if (previousSrcRoot.exists()) |
| return previousSrcRoot; |
| } |
| |
| return null; |
| } |
| |
| public static Map<String, Map<String, String>> parseSourceBundleEntry(BundleDescription bundle) { |
| String header = getSourceBundleHeader(bundle); |
| if (header.length() == 0) |
| return Collections.emptyMap(); |
| |
| HashMap<String, Map<String, String>> map = new HashMap<>(); |
| ManifestElement[] elements; |
| try { |
| elements = ManifestElement.parseHeader(ECLIPSE_SOURCE_BUNDLE, header); |
| } catch (BundleException e1) { |
| return Collections.emptyMap(); |
| } |
| for (int i = 0; i < elements.length; i++) { |
| String key = elements[i].getValue(); |
| HashMap<String, String> subMap = new HashMap<>(2); |
| map.put(key, subMap); |
| for (Enumeration<String> e = elements[i].getDirectiveKeys(); e != null && e.hasMoreElements();) { |
| String directive = e.nextElement(); |
| subMap.put(directive, elements[i].getDirective(directive)); |
| } |
| for (Enumeration<String> e = elements[i].getKeys(); e != null && e.hasMoreElements();) { |
| String attribute = e.nextElement(); |
| subMap.put(attribute, elements[i].getAttribute(attribute)); |
| } |
| } |
| return map; |
| } |
| |
| public static final String EXTRA_ID = "id"; //$NON-NLS-1$ |
| public static final String EXTRA_VERSION = "version"; //$NON-NLS-1$ |
| public static final String EXTRA_UNPACK = "unpack"; //$NON-NLS-1$ |
| public static final String EXTRA_OPTIONAL = "optional"; //$NON-NLS-1$ |
| public static final String EXTRA_OS = "os"; //$NON-NLS-1$ |
| public static final String EXTRA_WS = "ws"; //$NON-NLS-1$ |
| public static final String EXTRA_ARCH = "arch"; //$NON-NLS-1$ |
| |
| public static Map<String, Object> parseExtraBundlesString(String input, boolean onlyId) { |
| Map<String, Object> results = new HashMap<>(); |
| StringTokenizer tokenizer = null; |
| if (onlyId) |
| if (input.startsWith("plugin@")) //$NON-NLS-1$ |
| tokenizer = new StringTokenizer(input.substring(7), ";"); //$NON-NLS-1$ |
| else if (input.startsWith("exclude@") || input.startsWith("feature@")) //$NON-NLS-1$ //$NON-NLS-2$ |
| tokenizer = new StringTokenizer(input.substring(8), ";"); //$NON-NLS-1$ |
| else |
| tokenizer = new StringTokenizer(input, ";"); //$NON-NLS-1$ |
| else |
| tokenizer = new StringTokenizer(input, ";"); //$NON-NLS-1$ |
| |
| results.put(EXTRA_ID, tokenizer.nextToken()); |
| results.put(EXTRA_VERSION, Version.emptyVersion); |
| results.put(EXTRA_UNPACK, Boolean.TRUE); |
| |
| while (tokenizer.hasMoreTokens()) { |
| String token = tokenizer.nextToken(); |
| String value = null; |
| int idx = token.indexOf('='); |
| if (idx > 0 && idx < token.length() - 1) { |
| value = token.substring(idx + 1).trim(); |
| if (value.charAt(0) == '"' && value.charAt(value.length() - 1) == '"') |
| value = value.substring(1, value.length() - 1); |
| } |
| if (token.startsWith(EXTRA_VERSION)) |
| results.put(EXTRA_VERSION, new Version(value)); |
| else if (token.startsWith(EXTRA_UNPACK)) |
| results.put(EXTRA_UNPACK, Boolean.valueOf(value)); |
| else if (token.startsWith(EXTRA_OS)) |
| results.put(EXTRA_OS, value); |
| else if (token.startsWith(EXTRA_WS)) |
| results.put(EXTRA_WS, value); |
| else if (token.startsWith(EXTRA_ARCH)) |
| results.put(EXTRA_ARCH, value); |
| else if (token.startsWith(EXTRA_OPTIONAL)) |
| results.put(EXTRA_OPTIONAL, Boolean.valueOf(value)); |
| } |
| return results; |
| } |
| |
| static public boolean matchVersions(String version1, String version2) { |
| if (version1 == null) |
| version1 = GENERIC_VERSION_NUMBER; |
| if (version2 == null) |
| version2 = GENERIC_VERSION_NUMBER; |
| |
| if (version1.equals(version2) || version1.equals(GENERIC_VERSION_NUMBER) || version2.equals(GENERIC_VERSION_NUMBER)) |
| return true; |
| |
| if (version1.endsWith(PROPERTY_QUALIFIER) || version2.endsWith(PROPERTY_QUALIFIER)) { |
| int idx = version1.indexOf(PROPERTY_QUALIFIER); |
| if (idx > -1) |
| version1 = version1.substring(0, idx); |
| idx = version2.indexOf(PROPERTY_QUALIFIER); |
| |
| version1 = version1.substring(0, idx); |
| return (version1.length() > version2.length()) ? version1.startsWith(version2) : version2.startsWith(version1); |
| } |
| |
| return false; |
| } |
| |
| /** |
| * |
| * @param buf |
| * @param start |
| * @param target |
| * @return int |
| */ |
| static public int scan(StringBuffer buf, int start, String target) { |
| return scan(buf, start, new String[] {target}); |
| } |
| |
| /** |
| * |
| * @param buf |
| * @param start |
| * @param targets |
| * @return int |
| */ |
| static public int scan(StringBuffer buf, int start, String[] targets) { |
| for (int i = start; i < buf.length(); i++) { |
| for (int j = 0; j < targets.length; j++) { |
| if (i < buf.length() - targets[j].length()) { |
| String match = buf.substring(i, i + targets[j].length()); |
| if (targets[j].equals(match)) |
| return i; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Return a buffer containing the contents of the file at the specified location. |
| * |
| * @param target the file |
| * @return StringBuffer |
| * @throws IOException |
| */ |
| static public StringBuffer readFile(File target) throws IOException { |
| return readFile(new FileInputStream(target)); |
| } |
| |
| static public StringBuffer readFile(InputStream stream) throws IOException { |
| StringBuffer result = new StringBuffer(); |
| char[] buf = new char[4096]; |
| int count; |
| try (InputStreamReader reader = new InputStreamReader(new BufferedInputStream(stream))) { |
| count = reader.read(buf, 0, buf.length); |
| while (count != -1) { |
| result.append(buf, 0, count); |
| count = reader.read(buf, 0, buf.length); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Custom build scripts should have their version number matching the |
| * version number defined by the feature/plugin/fragment descriptor. |
| * This is a best effort job so do not worry if the expected tags were |
| * not found and just return without modifying the file. |
| * |
| * @param buildFile |
| * @param propertyName |
| * @param version |
| * @throws IOException |
| * |
| */ |
| public static void updateVersion(File buildFile, String propertyName, String version) throws IOException { |
| StringBuffer buffer = readFile(buildFile); |
| int pos = scan(buffer, 0, propertyName); |
| if (pos == -1) |
| return; |
| pos = scan(buffer, pos, "value"); //$NON-NLS-1$ |
| if (pos == -1) |
| return; |
| int begin = scan(buffer, pos, "\""); //$NON-NLS-1$ |
| if (begin == -1) |
| return; |
| begin++; |
| int end = scan(buffer, begin, "\""); //$NON-NLS-1$ |
| if (end == -1) |
| return; |
| String currentVersion = buffer.substring(begin, end); |
| String newVersion = version; |
| if (currentVersion.equals(newVersion)) |
| return; |
| buffer.replace(begin, end, newVersion); |
| transferStreams(new ByteArrayInputStream(buffer.toString().getBytes()), new FileOutputStream(buildFile)); |
| } |
| |
| public static Enumeration<Object> getArrayEnumerator(Object[] array) { |
| return new ArrayEnumeration(array); |
| } |
| |
| public static void close(Object obj) { |
| if (obj == null) |
| return; |
| try { |
| if (obj instanceof InputStream) |
| ((InputStream) obj).close(); |
| else if (obj instanceof ZipFile) |
| ((ZipFile) obj).close(); |
| else if (obj instanceof OutputStream) |
| ((OutputStream) obj).close(); |
| } catch (IOException e) { |
| //boo |
| } |
| } |
| |
| public static boolean guessUnpack(BundleDescription bundle, String[] classpath) { |
| return org.eclipse.pde.internal.publishing.Utils.guessUnpack(bundle, classpath); |
| } |
| |
| public static Version extract3Segments(String s) { |
| Version tmp = new Version(s); |
| return new Version(tmp.getMajor(), tmp.getMinor(), tmp.getMicro()); |
| } |
| |
| private static boolean needsReplacement(String s) { |
| if (s.equalsIgnoreCase(GENERIC_VERSION_NUMBER) || s.endsWith(PROPERTY_QUALIFIER)) |
| return true; |
| return false; |
| } |
| |
| public static String getEntryVersionMappings(FeatureEntry[] entries, BuildTimeSite site) { |
| return getEntryVersionMappings(entries, site, null); |
| } |
| |
| public static String getEntryVersionMappings(FeatureEntry[] entries, BuildTimeSite site, AssemblyInformation assembly) { |
| if (entries == null || site == null) |
| return null; |
| |
| StringBuffer result = new StringBuffer(); |
| for (int i = 0; i < entries.length; i++) { |
| String versionRequested = entries[i].getVersion(); |
| if (versionRequested == null) |
| versionRequested = GENERIC_VERSION_NUMBER; |
| String id = entries[i].getId(); |
| String newVersion = null; |
| |
| if (!needsReplacement(versionRequested)) |
| continue; |
| |
| try { |
| if (entries[i].isPlugin()) { |
| BundleDescription model = null; |
| if (assembly != null) |
| model = assembly.getPlugin(entries[i].getId(), versionRequested); |
| if (model == null) |
| model = site.getRegistry().getResolvedBundle(id, versionRequested); |
| if (model != null) |
| newVersion = model.getVersion().toString(); |
| } else { |
| BuildTimeFeature feature = site.findFeature(id, versionRequested, false); |
| if (feature != null) |
| newVersion = feature.getVersion(); |
| } |
| } catch (CoreException e) { |
| continue; |
| } |
| if (newVersion != null) { |
| result.append(id); |
| result.append(':'); |
| result.append(extract3Segments(versionRequested)); |
| result.append(','); |
| result.append(newVersion); |
| result.append(','); |
| } |
| } |
| return result.toString(); |
| } |
| } |