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-2006 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.*;
045: import java.util.*;
046:
047: import org.apache.tools.ant.*;
048: import org.apache.tools.ant.taskdefs.*;
049: import org.apache.tools.ant.types.*;
050:
051: /** Runs the makenbm task for each locale specified in the
052: * global property locmakenbm.locales.
053: * NOTE: Currently this runs makelnbm, since the new
054: * functionality in that hasn't been merged into makenbm
055: * yet.
056: *
057: * @author Jerry Huth (email: jerry@solidstep.com)
058: */
059: public class LocMakeNBM extends Task {
060:
061: protected String locales = null;
062: protected String mainDir = null;
063: protected File topDir = null;
064: protected String fileName = null;
065: protected String moduleName = null;
066: protected String baseFileName = null;
067: protected boolean deleteInfo = false;
068: protected String nbmIncludes = null;
069: protected String modInfo = null;
070: protected String findLocBundle = "."; // relative to the directory
071: // corresponding to the module's
072: // codename
073: protected File locBundle = null; // path to localizing bundle - overrides
074: // findLocBundle
075: protected String locIncludes = null; // comma-separated list of
076:
077: // "<locale>:<pattern>" elements
078:
079: public void setLocales(String s) {
080: locales = s;
081: }
082:
083: public void setMainDir(String s) {
084: mainDir = s;
085: }
086:
087: public void setTopDir(File f) {
088: topDir = f;
089: }
090:
091: public void setModule(String module) {
092: this .moduleName = module;
093: log("Setting moduleName = '" + moduleName + "'",
094: Project.MSG_VERBOSE);
095: }
096:
097: public void setFile(String s) {
098: fileName = s;
099: log("Setting fileName = '" + fileName + "'",
100: Project.MSG_VERBOSE);
101: if (!fileName.substring(fileName.length() - 4).equals(".nbm")) { //NOI18N
102: throw new BuildException("Incorrect NBM file name \"" + s
103: + "\". NBM file name must end in '.nbm'");
104: }
105: baseFileName = fileName.substring(0, fileName.length() - 4);
106: }
107:
108: public void setDeleteInfo(boolean b) {
109: deleteInfo = b;
110: }
111:
112: public void setNbmIncludes(String s) {
113: nbmIncludes = s;
114: }
115:
116: public void setModInfo(String s) {
117: modInfo = s;
118: }
119:
120: public void setLocBundle(File f) {
121: locBundle = f;
122: }
123:
124: public void setFindLocBundle(String s) {
125: findLocBundle = s;
126: }
127:
128: public void setLocIncludes(String s) {
129: locIncludes = s;
130: }
131:
132: public void execute() throws BuildException {
133: try {
134: really_execute();
135:
136: } catch (BuildException be) {
137: be.printStackTrace();
138: throw be;
139: }
140: }
141:
142: public void really_execute() throws BuildException {
143: String locs, loc;
144: StringTokenizer stok;
145: LinkedList<String> build_locales = new LinkedList<String>();
146:
147: // Set default values. //
148: if (mainDir == null) {
149: mainDir = new String("netbeans"); //NOI18N
150: }
151: if (topDir == null) {
152: topDir = getProject().getBaseDir();
153: }
154:
155: if ((modInfo == null) && (moduleName != null)) {
156: // load module info frommodule jarfile
157: File f = new File(topDir, moduleName.replace('/',
158: File.separatorChar));
159: java.util.jar.JarFile jf;
160: try {
161: jf = new java.util.jar.JarFile(f);
162: } catch (java.io.IOException ioe) {
163: throw new BuildException(
164: "I/O error during opening module jarfile", ioe,
165: this .getLocation());
166: }
167: java.util.jar.Manifest mani;
168: try {
169: mani = jf.getManifest();
170: } catch (java.io.IOException ioe) {
171: throw new BuildException(
172: "I/O error getting manifest from file '"
173: + f.getAbsolutePath() + "'", ioe, this
174: .getLocation());
175: }
176: if (mani != null) {
177: java.util.jar.Attributes attr = mani
178: .getMainAttributes();
179: String cname = attr.getValue("OpenIDE-Module");
180: String sver = attr
181: .getValue("OpenIDE-Module-Specification-Version");
182: if ((cname != null) && (!(cname.equals("")))
183: && (sver != null) && (!(sver.equals("")))) {
184: modInfo = cname + '/' + sver;
185: log(
186: "Gathered module information from module jarfile. Codename = '"
187: + cname
188: + "' and specification version = '"
189: + sver + "'", Project.MSG_VERBOSE);
190: } else {
191: throw new BuildException(
192: "Module in file '"
193: + f.getAbsolutePath()
194: + "' does not have either OpenIDE-Module attribute or OpenIDE-Module-Specification-Version attributes or missing both.",
195: this .getLocation());
196: }
197: }
198: }
199:
200: // Print a warning and stop if the topDir doesn't exist. //
201: if (printMissingDirWarning()) {
202: return;
203: }
204:
205: locs = getLocales();
206: if (locs == null || locs.trim().equals("")) { //NOI18N
207: throw new BuildException("Must specify 1 or more locales.");
208: }
209: if (fileName == null) {
210: throw new BuildException("Must specify the file attribute.");
211: }
212:
213: // I couldn't get it to work unless I explicitly added the task def here. //
214: getProject().addTaskDefinition("makelnbm", MakeLNBM.class); //NOI18N
215:
216: // Get a list of the locales for which localized files exist. //
217: stok = new StringTokenizer(locs, ","); //NOI18N
218: while (stok.hasMoreTokens()) {
219: loc = stok.nextToken();
220: log("Checking if module has files in locale '" + loc + "'",
221: Project.MSG_VERBOSE);
222: if (hasFilesInLocale(loc)) {
223: build_locales.add(loc);
224: log("Module has files in locale '" + loc + "'",
225: Project.MSG_VERBOSE);
226: } else {
227: log("Module has no files in locale '" + loc + "'",
228: Project.MSG_VERBOSE);
229: }
230: }
231:
232: // For each locale that we need to build an NBM for. //
233: ListIterator<String> iterator = build_locales.listIterator();
234: while (iterator.hasNext()) {
235:
236: // Build the NBM for this locale. //
237: buildNbm(iterator.next());
238: }
239: }
240:
241: /** Build the NBM for this locale. */
242: protected void buildNbm(String locale) throws BuildException {
243: MakeLNBM makenbm;
244: LinkedList<String> list = new LinkedList<String>();
245: String includes = new String();
246: File licenseFile;
247: boolean first_time;
248: Delete del;
249:
250: // Delete the Info directory if desired. //
251: if (deleteInfo) {
252: del = (Delete) getProject().createTask("delete"); //NOI18N
253: del.init();
254: del.setDir(new File(topDir.getAbsolutePath()
255: + File.separator + "Info")); //NOI18N
256: del.execute();
257: del.setDir(new File(topDir.getAbsolutePath()
258: + File.separator + "Info_" + //NOI18N
259: locale));
260: del.execute();
261: } else {
262:
263: // Move the Info_<locale> dir to Info. //
264: switchInfo(true, locale);
265: }
266:
267: makenbm = (MakeLNBM) getProject().createTask("makelnbm"); //NOI18N
268: makenbm.init();
269:
270: makenbm.setModInfo(modInfo);
271: makenbm.setLangCode(locale);
272: String fname = getLocalizedFileName(locale);
273: makenbm.setFile(new File(getProject().getBaseDir()
274: .getAbsolutePath()
275: + File.separator + fname));
276: makenbm.setTopdir(topDir);
277: makenbm.setIsStandardInclude(false);
278: String distbase = getProject().getProperty("dist.base"); //NOI18N
279: if (distbase != null) {
280: // try {
281: int idx = fname.lastIndexOf('/');
282: makenbm.setDistribution(distbase + "/"
283: + fname.substring(idx + 1)); //NOI18N
284: // } catch (MalformedURLException e) {
285: // throw new BuildException(e, getLocation());
286: // }
287: }
288: licenseFile = getLicenseFile(locale);
289: if (licenseFile != null) {
290: MakeLNBM.Blurb blurb = makenbm.createLicense();
291: blurb.setFile(licenseFile);
292: }
293:
294: // Set the localizing bundle specified, or look for it. //
295: if (locBundle != null) {
296: setLocBundle(makenbm, getSpecificLocBundleFile(locBundle,
297: locale));
298: } else {
299: setLocBundle(makenbm, findLocBundle(makenbm, locale));
300: }
301:
302: // Set up the signing data if it's specified. //
303: if (getKeystore() != null && getStorepass() != null
304: && getAlias() != null) {
305: MakeLNBM.Signature sign = makenbm.createSignature();
306: sign.setKeystore(new File(getKeystore()));
307: sign.setStorepass(getStorepass());
308: sign.setAlias(getAlias());
309: }
310:
311: // Get the list of include patterns for this locale. //
312: addLocalePatterns(list, locale);
313:
314: // Create a comma-separated list of include patterns. //
315: first_time = true;
316: for (String s1 : list) {
317: if (!first_time) {
318: includes += ","; //NOI18N
319: }
320: includes += s1;
321: first_time = false;
322: }
323: // Add any extra includes that were specified. //
324: if (nbmIncludes != null && !nbmIncludes.trim().equals("")) { //NOI18N
325: if (!first_time) {
326: includes += ","; //NOI18N
327: }
328: includes += nbmIncludes;
329: }
330: makenbm.setIncludes(includes);
331:
332: makenbm.execute();
333:
334: // Move the Info dir to Info_<locale>. //
335: switchInfo(false, locale);
336: }
337:
338: /** Return the license file associated with this locale if there is
339: * one.
340: */
341: protected File getLicenseFile(String locale) {
342: String license_prop_name = locale + ".license.file"; //NOI18N
343: String license_prop = getProject().getProperty(
344: license_prop_name);
345: File license = null;
346: if (license_prop != null) {
347: license = new File(license_prop);
348: }
349: return (license);
350: }
351:
352: protected void switchInfo(boolean to_info, String locale) {
353: File dir;
354:
355: if (to_info) {
356: dir = new File(topDir.getAbsolutePath() + File.separator
357: + "Info_" + locale); //NOI18N
358: dir.renameTo(new File(topDir.getAbsolutePath()
359: + File.separator + "Info")); //NOI18N
360: } else {
361: dir = new File(topDir.getAbsolutePath() + File.separator
362: + "Info"); //NOI18N
363: dir.renameTo(new File(topDir.getAbsolutePath()
364: + File.separator + "Info_" + //NOI18N
365: locale));
366: }
367: }
368:
369: /** Get the localized version of the NBM filename. */
370: protected String getLocalizedFileName(String locale) {
371: return (baseFileName + "_" + locale + ".nbm"); //NOI18N
372: }
373:
374: protected String getLocales() {
375: if (locales != null) {
376: return (locales);
377: }
378: return (getGlobalProp("locmakenbm.locales")); //NOI18N
379: }
380:
381: /** See if there are any files for the given locale. */
382: protected boolean hasFilesInLocale(String loc) {
383: FileSet fs;
384: boolean ret = true;
385:
386: // Setup a fileset to find files in this locale. //
387: fs = new FileSet();
388: fs.setDir(topDir);
389: addLocalePatterns(fs, loc);
390:
391: // See if there are any localized files for this locale. //
392: String[] inc_files = fs.getDirectoryScanner(getProject())
393: .getIncludedFiles();
394: if (inc_files.length == 0) {
395: ret = false;
396: }
397:
398: return (ret);
399: }
400:
401: /** Add the patterns to include the localized files for the given locale. */
402: protected void addLocalePatterns(FileSet fs, String loc) {
403: LinkedList<String> list = new LinkedList<String>();
404:
405: // Get the list of patterns for this locale. //
406: addLocalePatterns(list, loc);
407:
408: for (String s : list) {
409: // Add it to the includes list. //
410: fs.createInclude().setName(s);
411: }
412:
413: }
414:
415: protected void addLocalePatterns(LinkedList<String> list, String loc) {
416: // String dir = new String() ;
417: String re = new String();
418:
419: // dir = mainDir ; // modified for clusterization
420: // re = dir + "/**/*_" + loc + ".*" ; // pattern is: ${dir}/**/*_${locale}.* //NOI18N
421: // list.add( new String( re)) ;
422: // re = dir + "/**/" + loc + "/" ; // pattern is: ${dir}/${locale}/ //NOI18N
423: // list.add( new String( re)) ;
424:
425: re = "**/*_" + loc + ".*"; // pattern is: ${dir}/**/*_${locale}.* //NOI18N
426: list.add(re);
427: re = "**/" + loc + "/"; // pattern is: ${dir}/${locale}/ //NOI18N
428: list.add(re);
429:
430: addLocIncludes(list, loc);
431:
432: // For ja locale, include these other variants. //
433: if (loc.equals("ja")) { //NOI18N
434: addLocalePatterns(list, "ja_JP.PCK"); //NOI18N
435: addLocalePatterns(list, "ja_JP.eucJP"); //NOI18N
436: addLocalePatterns(list, "ja_JP.SJIS"); //NOI18N
437: addLocalePatterns(list, "ja_JP.UTF-8"); //NOI18N
438: addLocalePatterns(list, "ja_JP.UTF8"); //NOI18N
439: }
440: }
441:
442: protected void addLocIncludes(LinkedList<String> list, String loc) {
443: StringTokenizer tkzr;
444: String locInc, incLocale, incPattern;
445: int idx;
446:
447: if (locIncludes == null) {
448: return;
449: }
450:
451: // For each locale-specific include. //
452: tkzr = new StringTokenizer(locIncludes, ",\n\t "); //NOI18N
453: while (tkzr.hasMoreTokens()) {
454: locInc = tkzr.nextToken();
455: idx = locInc.indexOf(":"); //NOI18N
456: if (idx != -1) {
457: incLocale = locInc.substring(0, idx);
458: incPattern = locInc.substring(idx + 1);
459: if (incLocale.equals(loc)) {
460: list.add(incPattern);
461: }
462: } else {
463: list.add(locInc);
464: }
465: }
466: }
467:
468: protected String getGlobalProp(String name) {
469: String ret;
470: ret = getProject().getProperty(name);
471:
472: // Don't return empty strings or strings whose value contains a //
473: // property that isn't set. //
474: if (ret != null) {
475: if (ret.trim().equals("")) { //NOI18N
476: ret = null;
477: } else if (ret.indexOf("${") != -1) { //NOI18N
478: ret = null;
479: }
480: }
481: return (ret);
482: }
483:
484: protected String getKeystore() {
485: return (getGlobalProp("locmakenbm.keystore")); //NOI18N
486: }
487:
488: protected String getStorepass() {
489: return (getGlobalProp("locmakenbm.storepass")); //NOI18N
490: }
491:
492: protected String getAlias() {
493: return (getGlobalProp("locmakenbm.alias")); //NOI18N
494: }
495:
496: /** If the topDir doesn't exist, warn the user and return true. */
497: protected boolean printMissingDirWarning() {
498: boolean ret = false;
499: if (!topDir.exists()) {
500: log("WARNING: Skipping this task: Directory "
501: + topDir.getPath() + " doesn't exist.");
502: ret = true;
503: }
504: return (ret);
505: }
506:
507: /** If the localizing bundle is there, use it. */
508: protected void setLocBundle(MakeLNBM makenbm, File bundle) {
509: if (bundle != null && bundle.exists()) {
510: makenbm.setLocBundle(bundle);
511: } else {
512: log("WARNING: Localizing bundle not found: "
513: + ((bundle == null) ? ("") : (bundle.getPath()))); //NOI18N
514: }
515: }
516:
517: protected String getSrcDir(File file) {
518: InputStreamReader isr;
519: FileInputStream fis;
520: char[] buf = new char[200];
521: String s = null;
522: int idx, len;
523:
524: try {
525:
526: // Read the srcdir from the file that locjar wrote. //
527: fis = new FileInputStream(file);
528: isr = new InputStreamReader(fis);
529: len = isr.read(buf);
530: if (len != -1) {
531: if (buf[len - 1] == '\n') { //NOI18N
532: len--;
533: }
534: s = new String(buf, 0, len);
535: idx = s.indexOf("="); //NOI18N
536: if (idx != -1) {
537: s = s.substring(idx + 1);
538: s.trim();
539: } else {
540: s = null;
541: }
542: }
543: } catch (Exception e) {
544: System.out.println("ERROR: " + e.getMessage());
545: e.printStackTrace();
546: throw new BuildException();
547: }
548: return (s);
549: }
550:
551: protected File findLocBundle(MakeLNBM makenbm, String locale) {
552: File srcdirfile, locdir;
553: int index;
554: String s, srcdir = null;
555:
556: // See if the file containing the srcdir is there. //
557: srcdirfile = new File(topDir.getAbsolutePath() + File.separator
558: + "srcdir.properties"); //NOI18N
559: if (srcdirfile.exists()) {
560: srcdir = getSrcDir(srcdirfile);
561: }
562: // if( srcdir == null) {
563: // throw new BuildException( "ERROR: Could not get source dir from: " + srcdirfile.getPath()) ;
564: // }
565:
566: // Get the codename of this module. //
567: index = modInfo.indexOf("/"); //NOI18N
568: if (index != -1) {
569: s = modInfo.substring(0, index);
570: } else {
571: s = new String(modInfo);
572: }
573:
574: // Convert to pathname and set the loc bundle. //
575: s = s.replace('.', '/'); //NOI18N
576: locdir = new File(getRelPath(srcdir + "/" + s, findLocBundle). //NOI18N
577: replace('/', File.separatorChar)); //NOI18N
578: return (getDefaultLocBundleFile(locdir, locale));
579: }
580:
581: protected File getDefaultLocBundleFile(File dir, String locale) {
582: return (new File(dir.getPath() + File.separator + "Bundle_"
583: + locale + ".properties")); //NOI18N
584: }
585:
586: protected File getSpecificLocBundleFile(File enBundle, String locale) {
587: String path = enBundle.getPath();
588: int idx = path.lastIndexOf('.'); //NOI18N
589: if (idx != -1) {
590: return (new File(path.substring(0, idx) + "_" + locale
591: + path.substring(idx))); //NOI18N
592: } else {
593: return (new File(path + "_" + locale)); //NOI18N
594: }
595: }
596:
597: /** This supports ".." path elements at the start of path2. */
598: protected String getRelPath(String path1, String path2) {
599: int idx1, idx2;
600:
601: if (path2.equals(".")) { //NOI18N
602: return (path1);
603: }
604:
605: // For each ".." element in path2. //
606: while (true) {
607: idx2 = path2.indexOf(".."); //NOI18N
608: if (idx2 == -1) {
609: break;
610: }
611:
612: // Strip off the ".." //
613: path2 = path2.substring(2);
614:
615: // Strip off the slash if it starts with slash. //
616: idx2 = path2.indexOf("/"); //NOI18N
617: if (idx2 == 0) {
618: path2 = path2.substring(1);
619: }
620:
621: // Strip off the last element of path1. //
622: idx1 = path1.lastIndexOf("/"); //NOI18N
623: if (idx1 != -1) {
624: path1 = path1.substring(0, idx1);
625: }
626: }
627:
628: return (path1 + "/" + path2); //NOI18N
629: }
630:
631: }
|