001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM - Initial API and implementation
010: * Ben Pryor - Bug 148288
011: *******************************************************************************/package org.eclipse.pde.internal.build;
012:
013: import java.io.*;
014: import java.util.*;
015: import org.eclipse.core.runtime.*;
016: import org.eclipse.osgi.service.resolver.BundleDescription;
017: import org.eclipse.osgi.util.NLS;
018: import org.eclipse.pde.internal.build.builder.*;
019: import org.eclipse.pde.internal.build.packager.PackageScriptGenerator;
020: import org.eclipse.pde.internal.build.site.BuildTimeSiteFactory;
021: import org.eclipse.update.core.*;
022: import org.osgi.framework.Version;
023:
024: public class BuildScriptGenerator extends AbstractScriptGenerator {
025: /**
026: * Indicates whether the assemble script should contain the archive
027: * generation statement.
028: */
029: protected boolean generateArchive = true;
030: /**
031: * Indicates whether scripts for a feature's children should be generated.
032: */
033: protected boolean children = true;
034:
035: /**
036: * Indicates whether the resulting archive will contain a group of all the configurations
037: */
038: protected boolean groupConfigs = false;
039:
040: /**
041: * Source elements for script generation.
042: */
043: protected String[] elements;
044:
045: /**
046: * Additional dev entries for the compile classpath.
047: */
048: protected DevClassPathHelper devEntries;
049:
050: protected boolean recursiveGeneration = true;
051: protected boolean generateBuildScript = true;
052: protected boolean includePlatformIndependent = true;
053: protected boolean signJars = false;
054: protected boolean generateJnlp = false;
055: protected boolean generateFeatureVersionSuffix = false;
056: private String product;
057: //Map configuration with the expected output format: key: Config, value: string
058: private HashMap archivesFormat;
059:
060: private String archivesFormatAsString;
061:
062: /**
063: * flag indicating if the assemble script should be generated
064: */
065: private boolean generateAssembleScript = true;
066:
067: /** flag indicating if missing properties file should be logged */
068: private boolean ignoreMissingPropertiesFile = true;
069:
070: /** flag indicating if we should generate the plugin & feature versions lists */
071: private boolean generateVersionsList = false;
072:
073: private Properties antProperties = null;
074: private BundleDescription[] bundlesToBuild;
075:
076: private static final String PROPERTY_ARCHIVESFORMAT = "archivesFormat"; //$NON-NLS-1$
077:
078: /**
079: *
080: * @throws CoreException
081: */
082: public void generate() throws CoreException {
083:
084: if (archivesFormatAsString != null) {
085: realSetArchivesFormat(archivesFormatAsString);
086: archivesFormatAsString = null;
087: }
088:
089: List plugins = new ArrayList(5);
090: List features = new ArrayList(5);
091: try {
092: AbstractScriptGenerator
093: .setStaticAntProperties(antProperties);
094:
095: sortElements(features, plugins);
096: pluginsForFilterRoots = plugins;
097: featuresForFilterRoots = features;
098: getSite(true); //This forces the creation of the siteFactory which contains all the parameters necessary to initialize.
099: //TODO To avoid this. What would be necessary is use the BuildTimeSiteFactory to store the values that are stored in the AbstractScriptGenerator and to pass the parameters to a new BuildTimeSiteFacotry when created.
100: //More over this would allow us to remove some of the setters when creating a new featurebuildscriptgenerator.
101:
102: // It is not required to filter in the two first generateModels, since
103: // it is only for the building of a single plugin
104: generateModels(plugins);
105: generateFeatures(features);
106: flushState();
107: } finally {
108: AbstractScriptGenerator.setStaticAntProperties(null);
109: }
110: }
111:
112: /**
113: * Separate elements by kind.
114: */
115: protected void sortElements(List features, List plugins) {
116: if (elements == null)
117: return;
118: for (int i = 0; i < elements.length; i++) {
119: int index = elements[i].indexOf('@');
120: String type = elements[i].substring(0, index);
121: String element = elements[i].substring(index + 1);
122: if (type.equals("plugin") || type.equals("fragment")) //$NON-NLS-1$ //$NON-NLS-2$
123: plugins.add(element);
124: else if (type.equals("feature")) //$NON-NLS-1$
125: features.add(element);
126: }
127: }
128:
129: /**
130: *
131: * @param models
132: * @throws CoreException
133: */
134: protected void generateModels(List models) throws CoreException {
135: ModelBuildScriptGenerator generator = null;
136: try {
137: for (Iterator iterator = models.iterator(); iterator
138: .hasNext();) {
139: generator = new ModelBuildScriptGenerator();
140: generator
141: .setReportResolutionErrors(reportResolutionErrors);
142: generator
143: .setIgnoreMissingPropertiesFile(ignoreMissingPropertiesFile);
144: //Filtering is not required here, since we are only generating the build for a plugin or a fragment
145: String[] modelInfo = getNameAndVersion((String) iterator
146: .next());
147: generator.setBuildSiteFactory(siteFactory);
148: generator.setModelId(modelInfo[0], modelInfo[1]);
149:
150: generator.setPluginPath(pluginPath);
151: generator.setDevEntries(devEntries);
152: generator.setCompiledElements(generator
153: .getCompiledElements());
154: generator.setBuildingOSGi(isBuildingOSGi());
155: generator.setSignJars(signJars);
156: generator.generate();
157: }
158: if (bundlesToBuild != null)
159: for (int i = 0; i < bundlesToBuild.length; i++) {
160: generator = new ModelBuildScriptGenerator();
161: generator
162: .setReportResolutionErrors(reportResolutionErrors);
163: generator
164: .setIgnoreMissingPropertiesFile(ignoreMissingPropertiesFile);
165: //Filtering is not required here, since we are only generating the build for a plugin or a fragment
166: generator.setBuildSiteFactory(siteFactory);
167: generator.setModel(bundlesToBuild[i]);
168:
169: generator.setPluginPath(pluginPath);
170: generator.setDevEntries(devEntries);
171: generator.setCompiledElements(generator
172: .getCompiledElements());
173: generator.setBuildingOSGi(isBuildingOSGi());
174: generator.setSignJars(signJars);
175: generator.generate();
176: }
177: } finally {
178: if (generator != null)
179: generator.getSite(false).getRegistry()
180: .cleanupOriginalState();
181: }
182: }
183:
184: private String[] getNameAndVersion(String id) {
185: int versionPosition = id.indexOf(":"); //$NON-NLS-1$
186: String[] result = new String[2];
187: if (versionPosition != -1) {
188: result[1] = id.substring(versionPosition + 1);
189: result[0] = id.substring(0, versionPosition);
190: } else
191: result[0] = id;
192: return result;
193: }
194:
195: protected void generateFeatures(List features) throws CoreException {
196: AssemblyInformation assemblageInformation = null;
197: assemblageInformation = new AssemblyInformation();
198:
199: FeatureBuildScriptGenerator generator = null;
200: try {
201: for (Iterator i = features.iterator(); i.hasNext();) {
202: String[] featureInfo = getNameAndVersion((String) i
203: .next());
204: generator = new FeatureBuildScriptGenerator(
205: featureInfo[0], featureInfo[1],
206: assemblageInformation);
207: generator
208: .setGenerateIncludedFeatures(this .recursiveGeneration);
209: generator.setAnalyseChildren(this .children);
210: generator.setSourceFeatureGeneration(false);
211: generator.setBinaryFeatureGeneration(true);
212: generator.setScriptGeneration(generateBuildScript);
213: generator.setPluginPath(pluginPath);
214: generator.setBuildSiteFactory(siteFactory);
215: generator.setDevEntries(devEntries);
216: generator
217: .setSourceToGather(new SourceFeatureInformation());//
218: generator.setCompiledElements(generator
219: .getCompiledElements());
220: generator.setBuildingOSGi(isBuildingOSGi());
221: generator
222: .includePlatformIndependent(includePlatformIndependent);
223: generator
224: .setReportResolutionErrors(reportResolutionErrors);
225: generator
226: .setIgnoreMissingPropertiesFile(ignoreMissingPropertiesFile);
227: generator.setSignJars(signJars);
228: generator.setGenerateJnlp(generateJnlp);
229: generator
230: .setGenerateVersionSuffix(generateFeatureVersionSuffix);
231: generator.setProduct(product);
232: generator.generate();
233: }
234:
235: if (generator != null && generateAssembleScript == true) {
236: String[] featureInfo = null;
237: if (features.size() == 1)
238: featureInfo = getNameAndVersion((String) features
239: .get(0));
240: else
241: featureInfo = new String[] { "all" }; //$NON-NLS-1$
242:
243: generateAssembleScripts(assemblageInformation,
244: featureInfo, generator.siteFactory);
245:
246: if (features.size() == 1)
247: featureInfo = getNameAndVersion((String) features
248: .get(0));
249: else
250: featureInfo = new String[] { "" }; //$NON-NLS-1$
251:
252: generatePackageScripts(assemblageInformation,
253: featureInfo, generator.siteFactory);
254: }
255: if (generateVersionsList)
256: generateVersionsLists(assemblageInformation);
257: } finally {
258: if (generator != null)
259: generator.getSite(false).getRegistry()
260: .cleanupOriginalState();
261: }
262: }
263:
264: protected void generateVersionsLists(
265: AssemblyInformation assemblageInformation)
266: throws CoreException {
267: if (assemblageInformation == null)
268: return;
269: List configs = getConfigInfos();
270: Set features = new HashSet();
271: Set plugins = new HashSet();
272: Properties versions = new Properties();
273:
274: //For each configuration, save the version of all the features in a file
275: //and save the version of all the plug-ins in another file
276: for (Iterator iter = configs.iterator(); iter.hasNext();) {
277: Config config = (Config) iter.next();
278: String configString = config.toStringReplacingAny(
279: "_", ANY_STRING); //$NON-NLS-1$
280:
281: //Features
282: Collection list = assemblageInformation.getFeatures(config);
283: versions.clear();
284: features.addAll(list);
285: String featureFile = DEFAULT_FEATURE_VERSION_FILENAME_PREFIX
286: + '.' + configString + PROPERTIES_FILE_SUFFIX;
287: readVersions(versions, featureFile);
288: for (Iterator i = list.iterator(); i.hasNext();) {
289: IFeature feature = (IFeature) i.next();
290: VersionedIdentifier id = feature
291: .getVersionedIdentifier();
292: recordVersion(id.getIdentifier(), new Version(id
293: .getVersion().toString()), versions);
294: }
295: saveVersions(versions, featureFile);
296:
297: //Plugins
298: list = assemblageInformation.getPlugins(config);
299: versions.clear();
300: plugins.addAll(list);
301: String pluginFile = DEFAULT_PLUGIN_VERSION_FILENAME_PREFIX
302: + '.' + configString + PROPERTIES_FILE_SUFFIX;
303: readVersions(versions, pluginFile);
304: for (Iterator i = list.iterator(); i.hasNext();) {
305: BundleDescription bundle = (BundleDescription) i.next();
306: recordVersion(bundle.getSymbolicName(), bundle
307: .getVersion(), versions);
308: }
309: saveVersions(versions, pluginFile);
310: }
311:
312: //Create a file containing all the feature versions
313: versions.clear();
314: String featureFile = DEFAULT_FEATURE_VERSION_FILENAME_PREFIX
315: + PROPERTIES_FILE_SUFFIX;
316: readVersions(versions, featureFile);
317: for (Iterator i = features.iterator(); i.hasNext();) {
318: IFeature feature = (IFeature) i.next();
319: VersionedIdentifier id = feature.getVersionedIdentifier();
320: recordVersion(id.getIdentifier(), new Version(id
321: .getVersion().toString()), versions);
322: }
323: saveVersions(versions, featureFile);
324:
325: //Create a file containing all the plugin versions
326: versions.clear();
327: String pluginVersion = DEFAULT_PLUGIN_VERSION_FILENAME_PREFIX
328: + PROPERTIES_FILE_SUFFIX;
329: readVersions(versions, pluginVersion);
330: for (Iterator i = plugins.iterator(); i.hasNext();) {
331: BundleDescription bundle = (BundleDescription) i.next();
332: recordVersion(bundle.getSymbolicName(),
333: bundle.getVersion(), versions);
334: }
335: saveVersions(versions, pluginVersion);
336: }
337:
338: protected void recordVersion(String name, Version version,
339: Properties properties) {
340: String versionString = version.toString();
341: if (properties.containsKey(name)) {
342: Version existing = new Version((String) properties
343: .get(name));
344: if (version.compareTo(existing) >= 0) {
345: properties.put(name, versionString);
346: }
347: } else {
348: properties.put(name, versionString);
349: }
350: String suffix = '_' + String.valueOf(version.getMajor()) + '.'
351: + String.valueOf(version.getMinor()) + '.'
352: + String.valueOf(version.getMicro());
353: properties.put(name + suffix, versionString);
354: }
355:
356: private String getFilePath(String fileName) {
357: return workingDirectory + '/' + fileName;
358: }
359:
360: protected void readVersions(Properties properties, String fileName) {
361: String location = getFilePath(fileName);
362: try {
363: InputStream is = new BufferedInputStream(
364: new FileInputStream(location));
365: try {
366: properties.load(is);
367: } finally {
368: is.close();
369: }
370: } catch (IOException e) {
371: //Ignore
372: }
373: }
374:
375: protected void saveVersions(Properties properties, String fileName)
376: throws CoreException {
377: String location = getFilePath(fileName);
378: try {
379: OutputStream os = new BufferedOutputStream(
380: new FileOutputStream(location));
381: try {
382: properties.store(os, null);
383: } finally {
384: os.close();
385: }
386: } catch (IOException e) {
387: String message = NLS.bind(Messages.exception_writingFile,
388: location);
389: throw new CoreException(new Status(IStatus.ERROR,
390: PI_PDEBUILD, EXCEPTION_WRITING_FILE, message, null));
391: }
392: }
393:
394: protected void generatePackageScripts(
395: AssemblyInformation assemblageInformation,
396: String[] featureInfo, BuildTimeSiteFactory factory)
397: throws CoreException {
398: PackageScriptGenerator assembler = null;
399: assembler = new PackageScriptGenerator(workingDirectory,
400: assemblageInformation, featureInfo[0]);
401: assembler.setSignJars(signJars);
402: assembler.setGenerateJnlp(generateJnlp);
403: assembler.setArchivesFormat(getArchivesFormat());
404: assembler.setProduct(product);
405: assembler.setBuildSiteFactory(factory);
406: assembler.setGroupConfigs(groupConfigs);
407: assembler.generate();
408: }
409:
410: private void generateAssembleScripts(
411: AssemblyInformation assemblageInformation,
412: String[] featureInfo, BuildTimeSiteFactory factory)
413: throws CoreException {
414: AssembleScriptGenerator assembler = new AssembleScriptGenerator(
415: workingDirectory, assemblageInformation, featureInfo[0]);
416: assembler.setSignJars(signJars);
417: assembler.setGenerateJnlp(generateJnlp);
418: assembler.setArchivesFormat(getArchivesFormat());
419: assembler.setProduct(product);
420: assembler.setBuildSiteFactory(factory);
421: assembler.setGroupConfigs(groupConfigs);
422: assembler.generate();
423: }
424:
425: public void setGenerateArchive(boolean generateArchive) {
426: this .generateArchive = generateArchive;
427: }
428:
429: /**
430: *
431: * @param children
432: */
433: public void setChildren(boolean children) {
434: this .children = children;
435: }
436:
437: /**
438: *
439: * @param devEntries
440: */
441: public void setDevEntries(String devEntries) {
442: if (devEntries != null)
443: this .devEntries = new DevClassPathHelper(devEntries);
444: }
445:
446: /**
447: *
448: * @param elements
449: */
450: public void setElements(String[] elements) {
451: this .elements = elements;
452: }
453:
454: /**
455: * Sets the recursiveGeneration.
456: *
457: * @param recursiveGeneration
458: * The recursiveGeneration to set
459: */
460: public void setRecursiveGeneration(boolean recursiveGeneration) {
461: this .recursiveGeneration = recursiveGeneration;
462: }
463:
464: /**
465: * @param generateAssembleScript
466: * The generateAssembleScript to set.
467: */
468: public void setGenerateAssembleScript(boolean generateAssembleScript) {
469: this .generateAssembleScript = generateAssembleScript;
470: }
471:
472: /**
473: * Whether or not to generate plugin & feature versions lists
474: * @param generateVersionsList
475: */
476: public void setGenerateVersionsList(boolean generateVersionsList) {
477: this .generateVersionsList = generateVersionsList;
478: }
479:
480: /**
481: * @param value The reportResolutionErrors to set.
482: */
483: public void setReportResolutionErrors(boolean value) {
484: this .reportResolutionErrors = value;
485: }
486:
487: /**
488: * @param value The ignoreMissingPropertiesFile to set.
489: */
490: public void setIgnoreMissingPropertiesFile(boolean value) {
491: ignoreMissingPropertiesFile = value;
492: }
493:
494: public void setProduct(String value) {
495: product = value;
496: }
497:
498: public void setSignJars(boolean value) {
499: signJars = value;
500: }
501:
502: public void setGenerateJnlp(boolean value) {
503: generateJnlp = value;
504: }
505:
506: public void setGenerateFeatureVersionSuffix(boolean value) {
507: generateFeatureVersionSuffix = value;
508: }
509:
510: private class ArchiveTable extends HashMap {
511: private static final long serialVersionUID = -3063402400461435816L;
512:
513: public ArchiveTable(int size) {
514: super (size);
515: }
516:
517: public Object get(Object arg0) {
518: Object result = super .get(arg0);
519: if (result == null)
520: result = IXMLConstants.FORMAT_ANTZIP;
521: return result;
522: }
523: }
524:
525: public void setArchivesFormat(String archivesFormatAsString) {
526: this .archivesFormatAsString = archivesFormatAsString;
527: }
528:
529: public void realSetArchivesFormat(String archivesFormatAsString)
530: throws CoreException {
531: if (Utils.getPropertyFormat(PROPERTY_ARCHIVESFORMAT)
532: .equalsIgnoreCase(archivesFormatAsString)) {
533: archivesFormat = new ArchiveTable(0);
534: return;
535: }
536:
537: archivesFormat = new ArchiveTable(getConfigInfos().size());
538: String[] configs = Utils.getArrayFromStringWithBlank(
539: archivesFormatAsString, "&"); //$NON-NLS-1$
540: for (int i = 0; i < configs.length; i++) {
541: String[] configElements = Utils
542: .getArrayFromStringWithBlank(configs[i], ","); //$NON-NLS-1$
543: if (configElements.length != 3) {
544: IStatus error = new Status(IStatus.ERROR,
545: IPDEBuildConstants.PI_PDEBUILD,
546: IPDEBuildConstants.EXCEPTION_CONFIG_FORMAT, NLS
547: .bind(Messages.error_configWrongFormat,
548: configs[i]), null);
549: throw new CoreException(error);
550: }
551: String[] archAndFormat = Utils.getArrayFromStringWithBlank(
552: configElements[2], "-"); //$NON-NLS-1$
553: if (archAndFormat.length != 2) {
554: String message = NLS.bind(
555: Messages.invalid_archivesFormat,
556: archivesFormatAsString);
557: IStatus status = new Status(IStatus.ERROR,
558: IPDEBuildConstants.PI_PDEBUILD, message);
559: throw new CoreException(status);
560: }
561:
562: Config aConfig = new Config(configElements[0],
563: configElements[1], archAndFormat[0]);
564: if (getConfigInfos().contains(aConfig)) {
565: archivesFormat.put(aConfig, archAndFormat[1]);
566: }
567: }
568: }
569:
570: protected HashMap getArchivesFormat() {
571: if (archivesFormat == null) {
572: try {
573: //If not set, pass in the empty property to trigger the default value to be loaded
574: realSetArchivesFormat(Utils
575: .getPropertyFormat(PROPERTY_ARCHIVESFORMAT));
576: } catch (CoreException e) {
577: //ignore
578: }
579: }
580: return archivesFormat;
581: }
582:
583: public void includePlatformIndependent(boolean b) {
584: includePlatformIndependent = b;
585: }
586:
587: public void setGroupConfigs(boolean value) {
588: groupConfigs = value;
589: }
590:
591: public void setImmutableAntProperties(Properties properties) {
592: antProperties = properties;
593: }
594:
595: public void setBundles(BundleDescription[] bundles) {
596: bundlesToBuild = bundles;
597: }
598: }
|