1 19 20 package org.netbeans.nbbuild; 21 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.InputStreamReader ; 28 import java.io.OutputStream ; 29 import java.io.OutputStreamWriter ; 30 import java.io.PrintWriter ; 31 import java.io.Reader ; 32 import java.net.URI ; 33 import java.util.ArrayList ; 34 import java.util.Collections ; 35 import java.util.Enumeration ; 36 import java.util.Iterator ; 37 import java.util.List ; 38 import java.util.Map ; 39 import java.util.Properties ; 40 import java.util.StringTokenizer ; 41 import java.util.Vector ; 42 import java.util.jar.Attributes ; 43 import java.util.jar.JarFile ; 44 import java.util.jar.Manifest ; 45 import java.util.zip.ZipEntry ; 46 import java.util.zip.ZipFile ; 47 import org.apache.tools.ant.BuildException; 48 import org.apache.tools.ant.Project; 49 import org.apache.tools.ant.taskdefs.Jar; 50 import org.apache.tools.ant.taskdefs.MatchingTask; 51 import org.apache.tools.ant.taskdefs.SignJar; 52 import org.apache.tools.ant.types.FileSet; 53 54 61 public class MakeLNBM extends MatchingTask { 62 63 69 public class Blurb { 70 75 public class FileInsert { 76 77 public void setLocation (File file) throws BuildException { 78 log("Including contents of " + file, Project.MSG_VERBOSE); 79 long lmod = file.lastModified (); 80 if (lmod > mostRecentInput) mostRecentInput = lmod; 81 addSeparator (); 82 try { 83 InputStream is = new FileInputStream (file); 84 try { 85 Reader r = new InputStreamReader (is, "UTF-8"); char[] buf = new char[4096]; 87 int len; 88 while ((len = r.read (buf)) != -1) 89 text.append (buf, 0, len); 90 } finally { 91 is.close (); 92 } 93 } catch (IOException ioe) { 94 throw new BuildException ("Exception reading blurb from " + file, ioe, getLocation ()); 95 } 96 } 97 } 98 private StringBuffer text = new StringBuffer (); 99 private String name = null; 100 101 public void addText (String t) { 102 addSeparator (); 103 t = getProject().replaceProperties(t.trim()); 109 int min = Integer.MAX_VALUE; 110 StringTokenizer tok = new StringTokenizer (t, "\n"); boolean first = true; 112 while (tok.hasMoreTokens ()) { 113 String line = tok.nextToken (); 114 if (first) { 115 first = false; 116 } else { 117 int i; 118 for (i = 0; 119 i < line.length () && 120 Character.isWhitespace (line.charAt (i)); 121 i++) 122 ; 123 if (i < min) min = i; 124 } 125 } 126 if (min == 0) { 127 text.append (t); 128 } else { 129 tok = new StringTokenizer (t, "\n"); first = true; 131 while (tok.hasMoreTokens ()) { 132 String line = tok.nextToken (); 133 if (first) { 134 first = false; 135 } else { 136 text.append ('\n'); line = line.substring (min); 138 } 139 text.append (line); 140 } 141 } 142 } 143 144 public FileInsert createFile () { 145 return new FileInsert (); 146 } 147 148 public class Text { 149 public void addText(String t) { 150 Blurb.this.addText(t); 151 } 152 } 153 156 public Text createText() { 157 return new Text(); 158 } 159 private void addSeparator () { 160 if (text.length () > 0) { 161 if (text.charAt (text.length () - 1) != '\n') text.append ('\n'); text.append ("-----------------------------------------------------\n"); } 166 } 167 public String getText () { 168 String nocdata = getProject().getProperty("makenbm.nocdata"); if (nocdata != null && Project.toBoolean(nocdata)) { 170 return xmlEscape(text.toString()); 171 } else { 172 return "<![CDATA[" + text.toString () + "]]>"; } 174 } 175 179 public void setName (String name) { 180 this.name = name; 181 } 182 public String getName () { 183 return name; 184 } 185 186 public void setFile (File file) { 187 new FileInsert ().setLocation (file); 189 if (name == null) name = file.getName (); 191 } 192 } 193 194 public class ExternalPackage { 195 String name = null; 196 String targetName = null; 197 String startUrl = null; 198 String description = null; 199 200 public void setName(String n) { 201 this.name = n; 202 } 203 204 public void setTargetName(String t) { 205 this.targetName = t; 206 } 207 208 public void setStartURL(String u) { 209 this.startUrl = u; 210 } 211 212 public void setDescription(String d) { 213 this.description = d; 214 } 215 216 } 217 218 private static String xmlEscape(String s) { 220 int max = s.length(); 221 StringBuffer s2 = new StringBuffer ((int)(max * 1.1 + 1)); 222 for (int i = 0; i < max; i++) { 223 char c = s.charAt(i); 224 switch (c) { 225 case '<': s2.append("<"); break; 228 case '>': s2.append(">"); break; 231 case '&': s2.append("&"); break; 234 case '"': s2.append("""); break; 237 default: 238 s2.append(c); 239 break; 240 } 241 } 242 return s2.toString(); 243 } 244 245 246 public class Signature { 247 public File keystore; 248 public String storepass, alias; 249 250 public void setKeystore (File f) { 251 keystore = f; 252 } 253 257 public void setStorepass (String s) { 258 storepass = s; 259 } 260 261 public void setAlias (String s) { 262 alias = s; 263 } 264 } 265 266 private File file = null; 267 private File topdir = null; 268 private File manifest = null; 269 270 private File module = null; 271 private String homepage = null; 272 private String distribution = null; 273 private String needsrestart = null; 274 private Blurb license = null; 275 private Blurb description = null; 276 private Blurb notification = null; 277 private Signature signature = null; 278 private long mostRecentInput = 0L; 279 private boolean isStandardInclude = true; 280 private Vector <ExternalPackage> externalPackages = null; 281 private boolean manOrModReq = true ; 282 private boolean manOrModReqSet = false ; 283 private String langCode = null ; 284 private String brandingCode = null ; 285 private String modInfo = null ; 286 private File locBundle = null ; 288 289 public void setIsStandardInclude(boolean isStandardInclude) { 290 this.isStandardInclude = isStandardInclude; 291 } 292 293 294 public void setFile (File file) { 295 this.file = file; 296 } 297 302 public void setTopdir (File topdir) { 303 this.topdir = topdir; 304 } 305 308 @Deprecated 309 public void setManifest (File manifest) { 310 this.manifest = manifest; 311 long lmod = manifest.lastModified (); 312 if (lmod > mostRecentInput) mostRecentInput = lmod; 313 log(getLocation() + "The 'manifest' attr on <makenbm> is deprecated, please use 'module' instead", Project.MSG_WARN); 314 } 315 326 public void setModule(File module) { 327 this.module = module; 328 } 330 331 public void setHomepage (String homepage) { 332 this.homepage = homepage; 333 } 334 335 public void setNeedsrestart (String needsrestart) { 336 this.needsrestart = needsrestart; 337 } 338 339 public void setDistribution (String distribution) throws BuildException { 340 if (distribution.startsWith("http://")) { this.distribution = distribution; 342 } else if (!(distribution.equals(""))) { 343 this.distribution = "http://" + distribution; } else { 346 throw new BuildException("Distribution URL is empty, check build.xml file", getLocation()); 347 } 348 try { 350 URI uri = java.net.URI.create(this.distribution); 351 } catch (IllegalArgumentException ile) { 352 throw new BuildException("Distribution URL \"" + this.distribution + "\" is not a valid URI", ile, getLocation()); 353 } 354 } 355 public Blurb createLicense () { 356 return (license = new Blurb ()); 357 } 358 public Blurb createNotification () { 359 return (notification = new Blurb ()); 360 } 361 public Blurb createDescription () { 362 log(getLocation() + "The <description> subelement in <makenbm> is deprecated except for emergency patches, please ensure your module has an OpenIDE-Module-Long-Description instead", Project.MSG_WARN); 363 return (description = new Blurb ()); 364 } 365 public Signature createSignature () { 366 return (signature = new Signature ()); 367 } 368 369 public ExternalPackage createExternalPackage(){ 370 ExternalPackage externalPackage = new ExternalPackage (); 371 if (externalPackages == null) 372 externalPackages = new Vector <ExternalPackage>(); 373 externalPackages.add( externalPackage ); 374 return externalPackage; 375 } 376 377 public void execute () throws BuildException { 378 if (file == null) { 379 throw new BuildException("must set file for makenbm", getLocation()); 380 } 381 if (manifest == null && module == null && reqManOrMod()) { 382 throw new BuildException("must set module for makenbm", getLocation()); 383 } 384 if (manifest != null && module != null) { 385 throw new BuildException("cannot set both manifest and module for makenbm", getLocation()); 386 } 387 File infodir = new File (topdir, "Info"); infodir.mkdirs (); 390 File infofile = new File (infodir, "info.xml"); if (infofile.exists ()) { 392 infofile.delete(); 393 } 394 Attributes attr = null; 395 if (module != null) { 396 long mMod = module.lastModified(); 398 if (mostRecentInput < mMod) mostRecentInput = mMod; 399 try { 400 JarFile modulejar = new JarFile (module); 401 try { 402 attr = modulejar.getManifest().getMainAttributes(); 403 String bundlename = attr.getValue("OpenIDE-Module-Localizing-Bundle"); if (bundlename != null) { 405 Properties p = new Properties (); 406 ZipEntry bundleentry = modulejar.getEntry(bundlename); 407 if (bundleentry != null) { 408 InputStream is = modulejar.getInputStream(bundleentry); 409 try { 410 p.load(is); 411 } finally { 412 is.close(); 413 } 414 } else { 415 File variant = new File (new File (module.getParentFile(), "locale"), module.getName()); if (!variant.isFile()) throw new BuildException(bundlename + " not found in " + module, getLocation()); 418 long vmMod = variant.lastModified(); 419 if (mostRecentInput < vmMod) mostRecentInput = vmMod; 420 ZipFile variantjar = new ZipFile (variant); 421 try { 422 bundleentry = variantjar.getEntry(bundlename); 423 if (bundleentry == null) throw new BuildException(bundlename + " not found in " + module + " nor in " + variant, getLocation()); 424 InputStream is = variantjar.getInputStream(bundleentry); 425 try { 426 p.load(is); 427 } finally { 428 is.close(); 429 } 430 } finally { 431 variantjar.close(); 432 } 433 } 434 Iterator it = p.entrySet().iterator(); 436 while (it.hasNext()) { 437 Map.Entry entry = (Map.Entry )it.next(); 438 String name = (String )entry.getKey(); 439 if (! name.startsWith("OpenIDE-Module-")) continue; attr.putValue(name, (String )entry.getValue()); 441 } 442 } } finally { 444 modulejar.close(); 445 } 446 } catch (IOException ioe) { 447 throw new BuildException("exception while reading " + module, ioe, getLocation()); 448 } 449 } boolean skipInfo = false; 451 if (infofile.exists ()) { 452 long iMod = infofile.lastModified (); 454 if (mostRecentInput < iMod) 455 skipInfo = true; 456 } 457 if (! skipInfo) { 458 log ("Creating NBM info file " + infofile); 459 if (manifest != null) { 460 try { 462 InputStream manifestStream = new FileInputStream (manifest); 463 try { 464 attr = new Manifest (manifestStream).getMainAttributes (); 465 } finally { 466 manifestStream.close (); 467 } 468 } catch (IOException e) { 469 throw new BuildException("exception when reading manifest " + manifest, e, getLocation()); 470 } 471 } try { 473 OutputStream infoStream = new FileOutputStream (infofile); 474 try { 475 PrintWriter ps = new PrintWriter (new OutputStreamWriter (infoStream, "UTF-8")); 476 ps.println ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); ps.println("<!DOCTYPE module PUBLIC \"-//NetBeans//DTD Autoupdate Module Info 2.4//EN\" \"http://www.netbeans.org/dtds/autoupdate-info-2_4.dtd\">"); if( attr != null) { 480 String codenamebase = attr.getValue ("OpenIDE-Module"); if (codenamebase == null) 482 throw new BuildException("invalid manifest, does not contain OpenIDE-Module", getLocation()); 483 codenamebase = getCodenameBase( codenamebase) ; 485 ps.println ("<module codenamebase=\"" + xmlEscape(codenamebase) + "\""); } 487 else { 488 ps.print( "<module "); if( modInfo != null && !modInfo.trim().equals( "")) { 490 String codenamebase = getCodenameBase( modInfo) ; 491 ps.println( "codenamebase=\"" + xmlEscape(codenamebase) + "\""); } 493 else { 494 ps.println( "") ; } 496 } 497 if (homepage != null) 498 ps.println (" homepage=\"" + xmlEscape(homepage) + "\""); if (distribution != null) { 500 ps.println (" distribution=\"" + xmlEscape(distribution) + "\""); } else { 502 throw new BuildException("NBM distribution URL is not set", getLocation()); 503 } 504 if (license != null) { 506 String name = license.getName (); 507 if (name == null) 508 throw new BuildException("Every license must have a name or file attribute", getLocation()); 509 ps.println (" license=\"" + xmlEscape(name) + "\""); } 511 ps.println (" downloadsize=\"0\""); if (needsrestart != null) 513 ps.println (" needsrestart=\"" + xmlEscape(needsrestart) + "\""); ps.println (">"); if (description != null) { 516 ps.print (" <description>"); ps.print (description.getText ()); 518 ps.println ("</description>"); } 520 521 if( attr != null) { 523 ps.print (" <manifest "); boolean firstline = true; 525 List <String > attrNames = new ArrayList <String >(attr.size()); 526 Iterator <Object > it = attr.keySet().iterator(); 527 while (it.hasNext()) { 528 attrNames.add(((Attributes.Name )it.next()).toString()); 529 } 530 Collections.sort(attrNames); 531 for (String name: attrNames) { 532 if (! name.startsWith("OpenIDE-Module")) continue; if (name.equals("OpenIDE-Module-Localizing-Bundle")) continue; if (name.equals("OpenIDE-Module-Install")) continue; if (name.equals("OpenIDE-Module-Layer")) continue; if (name.equals("OpenIDE-Module-Description")) continue; if (name.equals("OpenIDE-Module-Package-Dependency-Message")) continue; if (name.equals("OpenIDE-Module-Public-Packages")) continue; if (firstline) 542 firstline = false; 543 else 544 ps.print (" "); ps.println(name + "=\"" + xmlEscape(attr.getValue(name)) + "\""); } 547 ps.println (" />"); } 549 else if( modInfo != null && !modInfo.trim().equals( "")) { String specver, majorver ; 551 552 ps.println(" <l10n "); if( langCode != null && !langCode.trim().equals( "")) { ps.println( " langcode=\"" + xmlEscape(langCode) + "\"") ; } 557 if( brandingCode != null && !brandingCode.trim().equals( "")) { ps.println( " brandingcode=\"" + xmlEscape(brandingCode) + "\"") ; } 560 561 majorver = getMajorVer( modInfo) ; 563 if( majorver != null && !majorver.trim().equals( "")) { ps.println( " module_major_version=\"" + xmlEscape(majorver) + "\"") ; } 566 567 specver = getSpecVer( modInfo) ; 569 if( specver != null && !specver.trim().equals( "")) { ps.println( " module_spec_version=\"" + xmlEscape(specver) + "\"") ; } 572 573 if( locBundle != null) { 575 writeLocBundleAttrs( ps) ; 576 } 577 578 ps.println( " />") ; } 580 581 if (license != null) { 583 ps.print (" <license name=\"" + xmlEscape(license.getName ()) + "\">"); ps.print (license.getText ()); 585 ps.println ("</license>"); } 587 if (notification != null) { 588 ps.print(" <module_notification>"); ps.print(notification.getText()); 590 ps.println("</module_notification>"); } 592 if (externalPackages != null) { 593 Enumeration <ExternalPackage> exp = externalPackages.elements(); 594 while (exp.hasMoreElements()) { 595 ExternalPackage externalPackage = exp.nextElement(); 596 if (externalPackage.name == null || 597 externalPackage.targetName == null || 598 externalPackage.startUrl == null) 599 throw new BuildException("Must define name, targetname, starturl for external package"); 600 ps.print(" <external_package "); ps.print("name=\""+xmlEscape(externalPackage.name)+"\" "); ps.print("target_name=\""+xmlEscape(externalPackage.targetName)+"\" "); ps.print("start_url=\""+xmlEscape(externalPackage.startUrl)+"\""); if (externalPackage.description != null) 605 ps.print(" description=\""+xmlEscape(externalPackage.description)+"\""); ps.println("/>"); } 608 } 609 ps.println ("</module>"); ps.flush(); 611 } finally { 612 infoStream.close (); 613 } 614 } catch (IOException e) { 615 throw new BuildException("exception when creating Info/info.xml", e, getLocation()); 616 } 617 } 618 619 long jarModified = file.lastModified (); Jar jar = (Jar) getProject().createTask("jar"); jar.setDestFile(file); 624 jar.setCompress(true); 626 jar.addFileset (getFileSet()); 629 jar.setLocation(getLocation()); 630 jar.init (); 631 jar.execute (); 632 if (signature != null && file.lastModified () != jarModified) { 634 if (signature.keystore == null) 635 throw new BuildException ("must define keystore attribute on <signature/>"); 636 if (signature.storepass == null) 637 throw new BuildException ("must define storepass attribute on <signature/>"); 638 if (signature.alias == null) 639 throw new BuildException ("must define alias attribute on <signature/>"); 640 if (signature.storepass.equals ("?") || !signature.keystore.exists()) { 641 log ("Not signing NBM file " + file + "; no stored-key password provided or keystore (" 642 + signature.keystore.toString() + ") doesn't exist", Project.MSG_WARN); 643 } else { 644 log ("Signing NBM file " + file); 645 SignJar signjar = (SignJar) getProject().createTask("signjar"); try { 648 try { 649 Class [] paramsT = {String .class}; 650 Object [] paramsV1 = {signature.keystore.getAbsolutePath()}; 651 Object [] paramsV2 = {file.getAbsolutePath()}; 652 signjar.getClass().getDeclaredMethod( "setKeystore", paramsT ).invoke( signjar, paramsV1 ); signjar.getClass().getDeclaredMethod( "setJar", paramsT ).invoke( signjar, paramsV2 ); } catch (NoSuchMethodException ex1) { 655 try { 657 Class [] paramsT = {File .class}; 658 Object [] paramsV1 = {signature.keystore}; 659 Object [] paramsV2 = {file}; 660 signjar.getClass().getDeclaredMethod( "setKeystore", paramsT ).invoke( signjar, paramsV1 ); signjar.getClass().getDeclaredMethod( "setJar", paramsT ).invoke( signjar, paramsV2 ); } catch (NoSuchMethodException ex2) { 663 try { 665 Class [] paramsT1 = {File .class}; 666 Class [] paramsT2 = {String .class}; 667 Object [] paramsV1 = {signature.keystore.getAbsolutePath()}; 668 Object [] paramsV2 = {file}; 669 signjar.getClass().getDeclaredMethod( "setKeystore", paramsT2 ).invoke( signjar, paramsV1 ); signjar.getClass().getDeclaredMethod( "setJar", paramsT1 ).invoke( signjar, paramsV2 ); } catch (NoSuchMethodException ex3) { 672 throw new BuildException("Unknown Ant version, only Ant 1.6.5 is currently supported."); 673 } 674 } 675 } 676 } catch (IllegalAccessException ex4) { 677 throw new BuildException(ex4); 678 } catch (java.lang.reflect.InvocationTargetException ex5) { 679 throw new BuildException(ex5); 680 } 681 signjar.setStorepass (signature.storepass); 682 signjar.setAlias (signature.alias); 683 signjar.setLocation(getLocation()); 684 signjar.init (); 685 signjar.execute (); 686 } 687 } 688 } 689 690 692 public FileSet getFileSet() { 693 FileSet fs = fileset; fs.setDir (topdir); 695 696 if (isStandardInclude) { 697 fs.createInclude ().setName ("netbeans/"); fs.createExclude ().setName ("netbeans/update_tracking/*.xml"); } 700 701 fs.createInclude ().setName ("Info/info.xml"); return fs; 703 } 704 705 public Attributes getAttributes() throws IOException { 706 if (manifest != null) { 707 InputStream is = new FileInputStream (manifest); 708 try { 709 return new Manifest (is).getMainAttributes(); 710 } finally { 711 is.close(); 712 } 713 } else if (module != null) { 714 JarFile jar = new JarFile (module); 715 try { 716 return jar.getManifest().getMainAttributes(); 717 } finally { 718 jar.close(); 719 } 720 } else { 721 throw new IOException (getLocation() + "must give either 'manifest' or 'module' on <makenbm>"); 722 } 723 } 724 725 protected String getCodenameBase( String openide_module) { 726 String ret = openide_module ; 727 int idx = ret.indexOf ('/'); if (idx != -1) { 729 ret = ret.substring (0, idx); 730 } 731 return( ret) ; 732 } 733 734 protected String getSpecVer( String mod_info) { 735 String ret = null ; 736 int first_idx, second_idx ; 737 738 first_idx = mod_info.indexOf( '/') ; if( first_idx != -1) { 741 second_idx = mod_info.indexOf( '/', first_idx+1) ; if( second_idx != -1) { 743 744 ret = mod_info.substring( second_idx+1, mod_info.length()) ; 746 } 747 } 748 749 if( ret != null && ret.trim().equals( "")) { ret = null ; 752 } 753 return( ret) ; 754 } 755 756 protected String getMajorVer( String mod_info) { 757 String ret = null ; 758 int first_idx, second_idx ; 759 760 first_idx = mod_info.indexOf( '/') ; if( first_idx != -1) { 763 second_idx = mod_info.indexOf( '/', first_idx+1) ; if( second_idx != -1) { 765 766 ret = mod_info.substring( first_idx+1, second_idx) ; 768 } 769 770 else { 772 ret = mod_info.substring( first_idx+1, mod_info.length()) ; 773 } 774 } 775 776 if( ret != null && ret.trim().equals( "")) { ret = null ; 779 } 780 return( ret) ; 781 } 782 783 786 public void setLocBundle( File f) { 787 locBundle = f ; 788 } 789 790 791 public void setManOrModReq( boolean b) { 792 manOrModReq = b ; 793 manOrModReqSet = true ; 794 } 795 796 799 public void setModInfo( String s) { 800 modInfo = s ; 801 } 802 803 804 public void setLangCode( String s) { 805 langCode = s ; 806 } 807 808 809 public void setBrandingCode( String s) { 810 brandingCode = s ; 811 } 812 813 819 public boolean reqManOrMod() { 820 String s = null ; 821 boolean req = true ; 822 823 if( manOrModReqSet) { 824 req = manOrModReq ; 825 } 826 else { 827 s = getProject().getProperty("makenbm.manOrModReq"); if( s != null && !s.equals( "")) { req = getProject().toBoolean(s); 830 } 831 } 832 833 return( req) ; 834 } 835 836 protected void writeLocBundleAttrs( PrintWriter ps) { 837 FileInputStream fis ; 838 Properties p = new Properties () ; 839 String s ; 840 boolean hadone = false ; 841 842 try { 843 fis = new FileInputStream ( locBundle) ; 844 p.load( fis); 845 fis.close(); 846 } 847 catch( Exception e) { 848 System.out.println( "ERROR: " + e.getMessage()) ; 849 e.printStackTrace() ; 850 throw new BuildException() ; 851 } 852 853 s = p.getProperty( "OpenIDE-Module-Name") ; if( writeProp( "OpenIDE-Module-Name", s, ps)) { hadone = true ; 856 } 857 858 s = p.getProperty( "OpenIDE-Module-Long-Description") ; if( writeProp( "OpenIDE-Module-Long-Description", s, ps)) { hadone = true ; 861 } 862 863 if( !hadone) { 864 log( "WARNING: Localizing bundle had neither property: " + locBundle) ; 865 } 866 } 867 868 protected boolean writeProp( String name, 869 String val, 870 PrintWriter ps) { 871 boolean ret = false ; 872 if( val != null) { 873 ps.println( name + "=\"" + xmlEscape(val) +"\"") ; ret = true ; 875 } 876 return( ret) ; 877 } 878 879 } 880 | Popular Tags |