Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: d9a7e9c173b1f660b12b7928f7aaf35d56d0ff8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
/*******************************************************************************
 * Copyright (c) 2006, 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 - Initial API and implementation
 *******************************************************************************/
package org.eclipse.equinox.internal.p2.jarprocessor;

import java.io.*;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipException;
import org.eclipse.internal.provisional.equinox.p2.jarprocessor.JarProcessor;

/**
 * @author aniefer@ca.ibm.com
 *
 */
public class Utils {
	public static final String MARK_FILE_NAME = "META-INF/eclipse.inf"; //$NON-NLS-1$

	/*
	 * Properties found in outer pack.properties file
	 */
	// comma separated list of jars to exclude from sigining
	public static final String SIGN_EXCLUDES = "sign.excludes"; //$NON-NLS-1$
	// comma separated list of jars to exlclude from packing
	/**
	 * @noreference This field is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static final String PACK_EXCLUDES = "pack.excludes"; //$NON-NLS-1$
	// Suffix used when specifying arguments to use when running pack200 on a jar

	/**
	 * @noreference This field is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static final String PACK_ARGS_SUFFIX = ".pack.args"; //$NON-NLS-1$

	/*
	 * Properties found in both pack.properties and eclipse.inf
	 */
	// Default arguments to use when running pack200.
	// Affects all jars when specified in pack.properties, affects children when
	// specified in eclipse.inf
	/**
	 * @noreference This field is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static final String DEFAULT_PACK_ARGS = "pack200.default.args"; //$NON-NLS-1$

	/*
	 * Properties found in eclipse.inf file
	 */
	// This jar has been conditioned with pack200
	/**
	 * @noreference This field is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static final String MARK_PROPERTY = "pack200.conditioned"; //$NON-NLS-1$
	// Exclude this jar from processing
	public static final String MARK_EXCLUDE = "jarprocessor.exclude"; //$NON-NLS-1$
	// Exclude this jar from pack200
	public static final String MARK_EXCLUDE_PACK = "jarprocessor.exclude.pack"; //$NON-NLS-1$
	// Exclude this jar from signing
	public static final String MARK_EXCLUDE_SIGN = "jarprocessor.exclude.sign"; //$NON-NLS-1$
	// Exclude this jar's children from processing
	public static final String MARK_EXCLUDE_CHILDREN = "jarprocessor.exclude.children"; //$NON-NLS-1$
	// Exclude this jar's children from pack200
	public static final String MARK_EXCLUDE_CHILDREN_PACK = "jarprocessor.exclude.children.pack"; //$NON-NLS-1$
	// Exclude this jar's children from signing
	public static final String MARK_EXCLUDE_CHILDREN_SIGN = "jarprocessor.exclude.children.sign"; //$NON-NLS-1$
	// Arguments used in pack200 for this jar
	/**
	 * @noreference This field is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static final String PACK_ARGS = "pack200.args"; //$NON-NLS-1$
	/**
	 * @noreference This field is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static final String PACK200_PROPERTY = "org.eclipse.update.jarprocessor.pack200"; //$NON-NLS-1$
	public static final String JRE = "@jre"; //$NON-NLS-1$
	public static final String PATH = "@path"; //$NON-NLS-1$
	public static final String NONE = "@none"; //$NON-NLS-1$
	/**
	 * @noreference This field is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static final String PACKED_SUFFIX = ".pack.gz"; //$NON-NLS-1$
	public static final String JAR_SUFFIX = ".jar"; //$NON-NLS-1$

	public static final FileFilter JAR_FILTER = pathname -> pathname.isFile() && pathname.getName().endsWith(".jar"); //$NON-NLS-1$
	/**
	 * @noreference This field is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@SuppressWarnings("removal")
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static final FileFilter PACK_GZ_FILTER = pathname -> pathname.isFile()
			&& pathname.getName().endsWith(JarProcessor.PACKED_SUFFIX);

	public static void close(Object stream) {
		if (stream != null) {
			try {
				if (stream instanceof InputStream)
					((InputStream) stream).close();
				else if (stream instanceof OutputStream)
					((OutputStream) stream).close();
				else if (stream instanceof JarFile)
					((JarFile) stream).close();
			} catch (IOException e) {
				// ignore
			}
		}
	}

	/**
	 * get the set of commands to try to execute pack/unpack
	 * 
	 * @param cmd the command, either "pack200" or "unpack200"
	 * @return String [] or null
	 * 
	 * @noreference This method is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static String[] getPack200Commands(String cmd) {
		String[] locations = null;
		String prop = System.getProperty(PACK200_PROPERTY);
		String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
		if (null == prop) {
			locations = new String[] { javaHome + "/bin/" + cmd, cmd }; //$NON-NLS-1$
		} else
			switch (prop) {
			case NONE:
				return null;
			case JRE:
				locations = new String[] { javaHome + "/bin/" + cmd }; //$NON-NLS-1$
				break;
			case PATH:
				locations = new String[] { cmd };
				break;
			default:
				locations = new String[] { prop + "/" + cmd }; //$NON-NLS-1$
				break;
			}
		return locations;
	}

	/**
	 * Transfers all available bytes from the given input stream to the given output
	 * stream. Closes both streams if close == true, regardless of failure. Flushes
	 * the destination stream if close == false
	 * 
	 * @param source
	 * @param destination
	 * @param close
	 * @throws IOException
	 */
	public static void transferStreams(InputStream source, OutputStream destination, boolean close) 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 {
			if (close) {
				close(source);
				close(destination);
			} else {
				destination.flush();
			}
		}
	}

	/**
	 * Deletes all the files and directories from the given root down (inclusive).
	 * Returns false if we could not delete some file or an exception occurred at
	 * any point in the deletion. Even if an exception occurs, a best effort is made
	 * to continue deleting.
	 */
	public static boolean clear(java.io.File root) {
		boolean result = clearChildren(root);
		try {
			if (root.exists())
				result &= root.delete();
		} catch (Exception e) {
			result = false;
		}
		return result;
	}

	/**
	 * Deletes all the files and directories from the given root down, except for
	 * the root itself. Returns false if we could not delete some file or an
	 * exception occurred at any point in the deletion. Even if an exception occurs,
	 * a best effort is made to continue deleting.
	 */
	public static boolean clearChildren(java.io.File root) {
		boolean result = true;
		if (root.isDirectory()) {
			String[] list = root.list();
			// for some unknown reason, list() can return null.
			// Just skip the children If it does.
			if (list != null)
				for (String list1 : list) {
					result &= clear(new java.io.File(root, list1));
				}
		}
		return result;
	}

	/**
	 * @noreference This method is not intended to be referenced by clients.
	 * @deprecated See <a href=
	 *             "https://bugs.eclipse.org/bugs/show_bug.cgi?id=572043">bug</a>
	 *             for details.
	 */
	@Deprecated(forRemoval = true, since = "1.2.0")
	public static Set<String> getPackExclusions(Properties properties) {
		if (properties == null)
			return Collections.emptySet();

		String packExcludes = properties.getProperty(PACK_EXCLUDES);
		if (packExcludes != null) {
			String[] excludes = toStringArray(packExcludes, ","); //$NON-NLS-1$
			Set<String> packExclusions = new HashSet<>();
			for (String exclude : excludes) {
				packExclusions.add(exclude);
			}
			return packExclusions;
		}
		return Collections.emptySet();
	}

	public static Set<String> getSignExclusions(Properties properties) {
		if (properties == null)
			return Collections.emptySet();
		String signExcludes = properties.getProperty(SIGN_EXCLUDES);
		if (signExcludes != null) {
			String[] excludes = toStringArray(signExcludes, ","); //$NON-NLS-1$
			Set<String> signExclusions = new HashSet<>();
			for (String exclude : excludes) {
				signExclusions.add(exclude);
			}
			return signExclusions;
		}
		return Collections.emptySet();
	}

	public static String concat(String[] array) {
		StringBuilder buffer = new StringBuilder();
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				buffer.append(' ');
			buffer.append(array[i]);
		}
		return buffer.toString();
	}

	public static String[] toStringArray(String input, String separator) {
		StringTokenizer tokenizer = new StringTokenizer(input, separator);
		int count = tokenizer.countTokens();
		String[] result = new String[count];
		for (int i = 0; i < count; i++) {
			result[i] = tokenizer.nextToken().trim();
		}
		return result;
	}

	/**
	 * Get the properties from the eclipse.inf file from the given jar. If the file
	 * is not a jar, null is returned. If the file is a jar, but does not contain an
	 * eclipse.inf file, an empty Properties object is returned.
	 * 
	 * @param jarFile
	 * @return The eclipse.inf properties for the given jar file
	 */
	public static Properties getEclipseInf(File jarFile, boolean verbose) {
		if (jarFile == null || !jarFile.exists()) {
			if (verbose)
				System.out.println("Failed to obtain eclipse.inf due to missing jar file: " + jarFile); //$NON-NLS-1$
			return null;
		}
		JarFile jar = null;
		try {
			jar = new JarFile(jarFile, false);
			JarEntry mark = jar.getJarEntry(MARK_FILE_NAME);
			if (mark != null) {
				try (InputStream in = jar.getInputStream(mark)) {
					Properties props = new Properties();
					props.load(in);
					return props;
				}
			}
			return new Properties();
		} catch (ZipException e) {
			// not a jar, don't bother logging this.
			return null;
		} catch (IOException e) {
			if (verbose) {
				System.out.println("Failed to obtain eclipse.inf due to IOException: " + jarFile); //$NON-NLS-1$
				e.printStackTrace();
			}
			return null;
		} finally {
			close(jar);
		}
	}

	public static boolean shouldSkipJar(File input, boolean processAll, boolean verbose) {
		Properties inf = getEclipseInf(input, verbose);
		if (inf == null) {
			// not a jar, could be a pack.gz
			return false;
		}
		String exclude = inf.getProperty(MARK_EXCLUDE);

		// was marked as exclude, we should skip
		if (exclude != null && Boolean.parseBoolean(exclude))
			return true;

		// process all was set, don't skip
		if (processAll)
			return false;

		// otherwise, we skip if not marked marked
		String marked = inf.getProperty(MARK_PROPERTY);
		return !Boolean.parseBoolean(marked);
	}

	/**
	 * Stores the given properties in the output stream. We store the properties in
	 * sorted order so that the signing hash doesn't change if the properties didn't
	 * change.
	 * 
	 * @param props
	 * @param stream
	 */
	public static void storeProperties(Properties props, OutputStream stream) {
		PrintStream printStream = new PrintStream(stream);
		printStream.print("#Processed using Jarprocessor\n"); //$NON-NLS-1$
		SortedMap<Object, Object> sorted = new TreeMap<>(props);
		for (Object object : sorted.keySet()) {
			String key = (String) object;
			printStream.print(key);
			printStream.print(" = "); //$NON-NLS-1$
			printStream.print(sorted.get(key));
			printStream.print("\n"); //$NON-NLS-1$

		}
		printStream.flush();
	}
}

Back to the top