001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.nbbuild;
043:
044: import java.io.File;
045: import java.io.FileInputStream;
046: import java.io.IOException;
047: import java.util.ArrayList;
048: import java.util.Arrays;
049: import java.util.StringTokenizer;
050: import java.util.jar.Attributes;
051: import java.util.jar.JarFile;
052: import java.util.zip.CRC32;
053: import org.apache.tools.ant.BuildException;
054: import org.apache.tools.ant.DirectoryScanner;
055: import org.apache.tools.ant.Project;
056: import org.apache.tools.ant.Task;
057: import org.apache.tools.ant.types.FileSet;
058:
059: /**
060: * Create an update tracking file automatically.
061: * @author Michal Zlamal
062: */
063: public class MakeListOfNBM extends Task {
064: File outputFile = null;
065: String moduleName = null;
066: boolean pok = true;
067: FileSet fs = null;
068: private ArrayList<String> locales;
069: private ArrayList<String> brandings;
070:
071: public MakeListOfNBM() {
072: // initialize locales and brandings lists, add empty value at beginning
073: locales = new ArrayList<String>();
074: locales.add("");
075: brandings = new ArrayList<String>();
076: brandings.add("");
077: }
078:
079: /** Sets the directory used to create the NBM list file */
080: public void setOutputfiledir(File s) {
081: outputFile = s;
082: log("Setting outputfile to " + s, Project.MSG_DEBUG);
083: }
084:
085: public FileSet createFileSet() {
086: return (fs = new FileSet());
087: }
088:
089: /** Sets the module file */
090: public void setModule(String s) {
091: moduleName = s;
092: log("Setting moduleName to " + s, Project.MSG_DEBUG);
093: }
094:
095: public void setTargetName(String t) {
096: pok = false;
097: log("<" + this .getTaskName()
098: + "> attribute targetname has been DEPRECATED");
099: }
100:
101: /** Sets the list of locales in multilanguage build */
102: public void setLocales(String s) {
103: for (String st : s.split("[, ]+")) {
104: locales.add(st);
105: }
106: }
107:
108: public ArrayList getLocales() {
109: return this .locales;
110: }
111:
112: /** Sets the list of brandings in multilanguage build */
113: public void setBrandings(String s) {
114: if (s.startsWith("${"))
115: return;
116: StringTokenizer st = new StringTokenizer(s, ", ");
117: while (st.hasMoreTokens()) {
118: brandings.add(st.nextToken());
119: }
120: }
121:
122: public ArrayList getBrandings() {
123: return this .brandings;
124: }
125:
126: @Override
127: public void execute() throws BuildException {
128: if (!pok)
129: throw new BuildException(
130: "Use the fileset to specify the content of the NBM");
131: if (outputFile == null)
132: throw new BuildException(
133: "You have to specify output directoty");
134: if (moduleName == null)
135: throw new BuildException(
136: "You have to specify the main module's file");
137: if (fs == null)
138: throw new BuildException(
139: "You have to specify the fileset of files included in this module");
140:
141: log("Generating information for Auto Update...");
142:
143: UpdateTracking track = new UpdateTracking(outputFile
144: .getAbsolutePath());
145: Attributes attr;
146: JarFile jar = null;
147: File module = new File(outputFile, moduleName);
148: try {
149: jar = new JarFile(module);
150: attr = jar.getManifest().getMainAttributes();
151: } catch (IOException ex) {
152: throw new BuildException(
153: "Can't get manifest attributes for module jar file "
154: + module.getAbsolutePath(), ex,
155: getLocation());
156: } finally {
157: try {
158: if (jar != null)
159: jar.close();
160: } catch (IOException ex1) {
161: String exmsg = ex1.getMessage();
162: if (exmsg == null)
163: exmsg = "Unknown error";
164: log("Caught I/O Exception (msg:\"" + exmsg
165: + "\") when trying to close jar file "
166: + module.getAbsolutePath(), Project.MSG_WARN);
167: }
168: }
169:
170: String codename = attr.getValue("OpenIDE-Module"); //NOI18N
171: if (codename == null) {
172: throw new BuildException("Manifest in jar file "
173: + module.getAbsolutePath()
174: + " does not contain OpenIDE-Module", getLocation());
175: }
176:
177: String versionSpecNum = attr
178: .getValue("OpenIDE-Module-Specification-Version"); //NOI18N
179: if (versionSpecNum == null) {
180: log("Manifest in jar file "
181: + module.getAbsolutePath()
182: + " does not contain tag OpenIDE-Module-Specification-Version");
183: versionSpecNum = "0";
184: }
185:
186: UpdateTracking.Version version = track.addNewModuleVersion(
187: codename, versionSpecNum);
188:
189: fs.createInclude().setName(
190: "config" + File.separator + "Modules" + File.separator
191: + track.getTrackingFileName()); //NOI18N
192:
193: updateFileSetForLorB(fs);
194: // get directory scanner for "default" files
195: DirectoryScanner ds = fs.getDirectoryScanner(this .getProject());
196: ds.scan();
197:
198: // check if we need also localized and branded files
199: String lmnl = this .getProject().getProperty(
200: "locmakenbm.locales"); // NOI18N
201: String lmnb = this .getProject()
202: .getProperty("locmakenbm.brands"); // NOI18N
203:
204: if ((!(lmnl == null)) && (!(lmnl.trim().equals("")))) { // NOI18N
205: // property locmakenbm.locales is set, let's update the included fileset for locales
206: // defined in that property
207:
208: java.util.StringTokenizer tokenizer = new StringTokenizer(
209: lmnl, ", "); //NOI18N
210: int cntTok = tokenizer.countTokens();
211: String[] lmnLocales = new String[cntTok];
212: for (int j = 0; j < cntTok; j++) {
213: String s = tokenizer.nextToken();
214: lmnLocales[j] = s;
215: log(" lmnLocales[j] == " + lmnLocales[j],
216: Project.MSG_DEBUG); // NOI18N
217: }
218:
219: // handle brandings
220: String[] lmnBrands = null;
221: if ((!(lmnb == null)) && (!(lmnb.trim().equals("")))) { // NOI18N
222: tokenizer = new StringTokenizer(lmnb, ", "); //NOI18N
223: cntTok = tokenizer.countTokens();
224: lmnBrands = new String[cntTok];
225: for (int j = 0; j < cntTok; j++) {
226: String s = tokenizer.nextToken();
227: lmnBrands[j] = s;
228: log(" lmnBrands[j] == " + lmnBrands[j],
229: Project.MSG_DEBUG); // NOI18N
230: }
231: }
232:
233: // update fileset for localized/branded files
234:
235: String[] englishFiles = ds.getIncludedFiles();
236: int sepPos, extPos;
237: String dirName, fname, filename, fext, newinc, ei_codename;
238: String moduleJar = null;
239: boolean skipLocaleDir = false;
240: for (int k = 0; k < englishFiles.length; k++) {
241: // skip records for already localized/branded files
242: if ((englishFiles[k].lastIndexOf("/locale/") >= 0) || // NOI18N
243: (englishFiles[k].lastIndexOf(File.separator
244: + "locale" + File.separator) >= 0)) { // NOI18N
245: skipLocaleDir = true;
246: } else {
247: skipLocaleDir = false;
248: }
249: log("Examining file " + englishFiles[k],
250: Project.MSG_DEBUG);
251: sepPos = englishFiles[k].lastIndexOf(File.separator);
252: if (sepPos < 0) {
253: dirName = ""; //NOI18N
254: filename = englishFiles[k];
255: } else {
256: dirName = englishFiles[k].substring(0, sepPos);
257: filename = englishFiles[k].substring(sepPos
258: + File.separator.length());
259: }
260: extPos = filename.lastIndexOf('.'); //NOI18N
261: if (extPos < 0) {
262: fname = filename;
263: fext = ""; //NOI18N
264: } else {
265: fname = filename.substring(0, extPos);
266: fext = filename.substring(extPos);
267: }
268: for (int j = 0; j < lmnLocales.length; j++) {
269: // localized files
270: if (skipLocaleDir) {
271: newinc = dirName + File.separator + fname + "_"
272: + lmnLocales[j] + "*" + fext; //NOI18N
273: } else {
274: newinc = dirName + File.separator + "locale"
275: + File.separator + fname + "_"
276: + lmnLocales[j] + "*" + fext; //NOI18N
277: }
278: log(" adding include mask \"" + newinc + "\"",
279: Project.MSG_DEBUG);
280: fs.setIncludes(newinc);
281: // localized & branded files
282: if (!(lmnBrands == null)) {
283: for (int i = 0; i < lmnBrands.length; i++) {
284: if (skipLocaleDir) {
285: newinc = dirName + File.separator
286: + fname + "_" + lmnBrands[i]
287: + "_" + lmnLocales[j] + "*"
288: + fext; //NOI18N
289: } else {
290: newinc = dirName + File.separator
291: + "locale" + File.separator
292: + fname + "_" + lmnBrands[i]
293: + "_" + lmnLocales[j] + "*"
294: + fext; //NOI18N
295: }
296: log(" adding include mask \"" + newinc
297: + "\"", Project.MSG_DEBUG);
298: fs.setIncludes(newinc);
299: }
300: }
301: }
302: }
303: // update directory scanner
304: ds = fs.getDirectoryScanner(this .getProject());
305: ds.scan();
306: }
307:
308: String include[] = ds.getIncludedFiles();
309: log("Including files " + Arrays.toString(include),
310: Project.MSG_VERBOSE);
311: for (int j = 0; j < include.length; j++) {
312: try {
313: File inFile = new File(ds.getBasedir(), include[j]);
314: FileInputStream inFileStream = new FileInputStream(
315: inFile);
316: byte array[] = new byte[(int) inFile.length()];
317: CRC32 crc = new CRC32();
318: inFileStream.read(array);
319: inFileStream.close();
320: crc.update(array);
321: String abs = inFile.getAbsolutePath();
322: String prefix = ds.getBasedir().getAbsolutePath()
323: + File.separatorChar;
324: if (!abs.startsWith(prefix))
325: throw new IllegalStateException(abs);
326: version.addFileWithCrc(abs.substring(prefix.length())
327: .replace(File.separatorChar, '/'), Long
328: .toString(crc.getValue()));
329: } catch (IOException ex) {
330: log(ex.toString());
331: }
332: }
333: track.write();
334: }
335:
336: private void updateFileSetForLorB(FileSet fs) {
337: if ((locales.size() == 1) && (brandings.size() == 1))
338: return;
339: // update the fileset only if we have got at least one locale or one branding
340: DirectoryScanner ds = fs.getDirectoryScanner();
341: String[] included = ds.getIncludedFiles();
342: ArrayList<String> newIncludes = new ArrayList<String>();
343: String dirName;
344: String filename;
345: String fname;
346: String fext;
347: String newinc;
348:
349: for (String include : included) {
350: include = include.replace(File.separatorChar, '/');
351: int sepPos = include.lastIndexOf('/');
352: if (sepPos < 0) {
353: dirName = ""; //NOI18N
354: filename = include;
355: } else {
356: dirName = include.substring(0, sepPos);
357: filename = include.substring(sepPos + 1);
358: }
359: int extPos = filename.lastIndexOf('.'); //NOI18N
360: if (extPos < 0) {
361: fname = filename;
362: fext = ""; //NOI18N
363: } else {
364: fname = filename.substring(0, extPos);
365: fext = filename.substring(extPos);
366: }
367: for (String branding : brandings) {
368: for (String loc : locales) {
369: newinc = dirName + "/locale/" + fname;
370: if (branding.length() > 0)
371: newinc += "_" + branding;
372: if (loc.length() > 0)
373: newinc += "_" + loc;
374: newinc += fext;
375: if (newinc.startsWith("/"))
376: newinc = newinc.substring(1); //avoid root referring masks on unix boxes
377: newIncludes.add(newinc);
378: log("Added include mask: " + newinc,
379: Project.MSG_VERBOSE);
380: if (dirName.length() == 0) {
381: // if file is located in root of the cluster, add also
382: // a mask without "locale/" subdirectory
383: newinc = fname;
384: if (branding.length() > 0)
385: newinc += "_" + branding;
386: if (loc.length() > 0)
387: newinc += "_" + loc;
388: newinc += fext;
389: newIncludes.add(newinc);
390: log("Added cluster-root include mask: "
391: + newinc, Project.MSG_VERBOSE);
392: }
393: }
394: }
395: }
396: for (String inc : newIncludes) {
397: fs.setIncludes(inc);
398: }
399: }
400: }
|