1 13 14 package org.netbeans.nbbuild; 15 16 import java.io.*; 17 import java.util.*; 18 import java.util.jar.*; 19 import java.util.zip.*; 20 import java.net.*; 21 22 import org.apache.tools.ant.BuildException; 23 import org.apache.tools.ant.Location; 24 import org.apache.tools.ant.Project; 25 import org.apache.tools.ant.taskdefs.MatchingTask; 26 import org.apache.tools.ant.taskdefs.Jar; 27 import org.apache.tools.ant.taskdefs.Zip; 28 import org.apache.tools.ant.taskdefs.SignJar; 29 import org.apache.tools.ant.types.FileSet; 30 31 35 public class MakeNBM extends MatchingTask { 36 37 43 public class Blurb { 44 49 public class FileInsert { 50 51 public void setLocation (File file) throws BuildException { 52 log("Including contents of " + file, Project.MSG_VERBOSE); 53 long lmod = file.lastModified (); 54 if (lmod > mostRecentInput) mostRecentInput = lmod; 55 addSeparator (); 56 try { 57 InputStream is = new FileInputStream (file); 58 try { 59 Reader r = new InputStreamReader (is); 60 char[] buf = new char[4096]; 61 int len; 62 while ((len = r.read (buf)) != -1) 63 text.append (buf, 0, len); 64 } finally { 65 is.close (); 66 } 67 } catch (IOException ioe) { 68 throw new BuildException ("Exception reading blurb from " + file, ioe, getLocation ()); 69 } 70 } 71 } 72 private StringBuffer text = new StringBuffer (); 73 private String name = null; 74 75 public void addText (String t) { 76 addSeparator (); 77 t = t.trim (); 83 int min = Integer.MAX_VALUE; 84 StringTokenizer tok = new StringTokenizer (t, "\n"); 85 boolean first = true; 86 while (tok.hasMoreTokens ()) { 87 String line = tok.nextToken (); 88 if (first) { 89 first = false; 90 } else { 91 int i; 92 for (i = 0; 93 i < line.length () && 94 Character.isWhitespace (line.charAt (i)); 95 i++) 96 ; 97 if (i < min) min = i; 98 } 99 } 100 if (min == 0) { 101 text.append (t); 102 } else { 103 tok = new StringTokenizer (t, "\n"); 104 first = true; 105 while (tok.hasMoreTokens ()) { 106 String line = tok.nextToken (); 107 if (first) { 108 first = false; 109 } else { 110 text.append ('\n'); 111 line = line.substring (min); 112 } 113 text.append (line); 114 } 115 } 116 } 117 118 public FileInsert createFile () { 119 return new FileInsert (); 120 } 121 122 public class Text { 123 public void addText(String t) { 124 Blurb.this.addText(t); 125 } 126 } 127 130 public Text createText() { 131 return new Text(); 132 } 133 private void addSeparator () { 134 if (text.length () > 0) { 135 if (text.charAt (text.length () - 1) != '\n') 137 text.append ('\n'); 138 text.append ("-----------------------------------------------------\n"); 139 } 140 } 141 public String getText () { 142 String nocdata = getProject().getProperty("makenbm.nocdata"); 143 if (nocdata != null && Project.toBoolean(nocdata)) { 144 return xmlEscape(text.toString()); 145 } else { 146 return "<![CDATA[" + text.toString () + "]]>"; 147 } 148 } 149 153 public void setName (String name) { 154 this.name = name; 155 } 156 public String getName () { 157 return name; 158 } 159 160 public void setFile (File file) { 161 new FileInsert ().setLocation (file); 163 if (name == null) name = file.getName (); 165 } 166 } 167 168 public class ExternalPackage { 169 String name = null; 170 String targetName = null; 171 String startUrl = null; 172 String description = null; 173 174 public void setName(String n) { 175 this.name = n; 176 } 177 178 public void setTargetName(String t) { 179 this.targetName = t; 180 } 181 182 public void setStartURL(String u) { 183 this.startUrl = u; 184 } 185 186 public void setDescription(String d) { 187 this.description = d; 188 } 189 190 } 191 192 private static String xmlEscape(String s) { 194 int max = s.length(); 195 StringBuffer s2 = new StringBuffer ((int)(max * 1.1 + 1)); 196 for (int i = 0; i < max; i++) { 197 char c = s.charAt(i); 198 switch (c) { 199 case '<': 200 s2.append("<"); 201 break; 202 case '>': 203 s2.append(">"); 204 break; 205 case '&': 206 s2.append("&"); 207 break; 208 case '"': 209 s2.append("""); 210 break; 211 default: 212 s2.append(c); 213 break; 214 } 215 } 216 return s2.toString(); 217 } 218 219 220 public class Signature { 221 public File keystore; 222 public String storepass, alias; 223 224 public void setKeystore (File f) { 225 keystore = f; 226 } 227 231 public void setStorepass (String s) { 232 storepass = s; 233 } 234 235 public void setAlias (String s) { 236 alias = s; 237 } 238 } 239 240 private File file = null; 241 private File topdir = null; 242 private File manifest = null; 243 244 private File module = null; 245 private String homepage = null; 246 private String distribution = null; 247 private String needsrestart = null; 248 private Blurb license = null; 249 private Blurb description = null; 250 private Blurb notification = null; 251 private Signature signature = null; 252 private long mostRecentInput = 0L; 253 private boolean isStandardInclude = true; 254 private Vector externalPackages = null; 255 256 257 public void setIsStandardInclude(boolean isStandardInclude) { 258 this.isStandardInclude = isStandardInclude; 259 } 260 261 262 public void setFile (File file) { 263 this.file = file; 264 } 265 270 public void setTopdir (File topdir) { 271 this.topdir = topdir; 272 } 273 276 public void setManifest (File manifest) { 277 this.manifest = manifest; 278 long lmod = manifest.lastModified (); 279 if (lmod > mostRecentInput) mostRecentInput = lmod; 280 log(getLocation() + "The 'manifest' attr on <makenbm> is deprecated, please use 'module' instead", Project.MSG_WARN); 281 } 282 293 public void setModule(File module) { 294 this.module = module; 295 } 297 298 public void setHomepage (String homepage) { 299 this.homepage = homepage; 300 } 301 302 public void setNeedsrestart (String needsrestart) { 303 this.needsrestart = needsrestart; 304 } 305 306 public void setDistribution (String distribution) throws MalformedURLException { 307 if (distribution.startsWith("http://")) { 308 this.distribution = distribution; 309 } else { 310 this.distribution = "http://" + distribution; 312 } 313 } 314 public Blurb createLicense () { 315 return (license = new Blurb ()); 316 } 317 public Blurb createNotification () { 318 return (notification = new Blurb ()); 319 } 320 public Blurb createDescription () { 321 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); 322 return (description = new Blurb ()); 323 } 324 public Signature createSignature () { 325 return (signature = new Signature ()); 326 } 327 328 public ExternalPackage createExternalPackage(){ 329 ExternalPackage externalPackage = new ExternalPackage (); 330 if (externalPackages == null) 331 externalPackages = new Vector(); 332 externalPackages.add( externalPackage ); 333 return externalPackage; 334 } 335 336 public void execute () throws BuildException { 337 if (file == null) 338 throw new BuildException ("must set file for makenbm", location); 339 if (manifest == null && module == null) 340 throw new BuildException ("must set module for makenbm", location); 341 if (manifest != null && module != null) 342 throw new BuildException("cannot set both manifest and module for makenbm", location); 343 File infodir = new File (topdir, "Info"); 345 infodir.mkdirs (); 346 File infofile = new File (infodir, "info.xml"); 347 Attributes attr = null; 348 if (module != null) { 349 long mMod = module.lastModified(); 351 if (mostRecentInput < mMod) mostRecentInput = mMod; 352 try { 353 JarFile modulejar = new JarFile(module); 354 try { 355 attr = modulejar.getManifest().getMainAttributes(); 356 String bundlename = attr.getValue("OpenIDE-Module-Localizing-Bundle"); 357 if (bundlename != null) { 358 Properties p = new Properties(); 359 ZipEntry bundleentry = modulejar.getEntry(bundlename); 360 if (bundleentry != null) { 361 InputStream is = modulejar.getInputStream(bundleentry); 362 try { 363 p.load(is); 364 } finally { 365 is.close(); 366 } 367 } else { 368 File variant = new File(new File(module.getParentFile(), "locale"), module.getName()); 370 if (! variant.isFile()) throw new BuildException(bundlename + " not found in " + module, location); 371 long vmMod = variant.lastModified(); 372 if (mostRecentInput < vmMod) mostRecentInput = vmMod; 373 ZipFile variantjar = new ZipFile(variant); 374 try { 375 bundleentry = variantjar.getEntry(bundlename); 376 if (bundleentry == null) throw new BuildException(bundlename + " not found in " + module + " nor in " + variant, location); 377 InputStream is = variantjar.getInputStream(bundleentry); 378 try { 379 p.load(is); 380 } finally { 381 is.close(); 382 } 383 } finally { 384 variantjar.close(); 385 } 386 } 387 Iterator it = p.entrySet().iterator(); 389 while (it.hasNext()) { 390 Map.Entry entry = (Map.Entry)it.next(); 391 String name = (String )entry.getKey(); 392 if (! name.startsWith("OpenIDE-Module-")) continue; 393 attr.putValue(name, (String )entry.getValue()); 394 } 395 } } finally { 397 modulejar.close(); 398 } 399 } catch (IOException ioe) { 400 throw new BuildException("exception while reading " + module, ioe, location); 401 } 402 } boolean skipInfo = false; 404 if (infofile.exists ()) { 405 long iMod = infofile.lastModified (); 407 if (mostRecentInput < iMod) 408 skipInfo = true; 409 } 410 if (! skipInfo) { 411 log ("Creating NBM info file " + infofile); 412 if (manifest != null) { 413 try { 415 InputStream manifestStream = new FileInputStream (manifest); 416 try { 417 attr = new Manifest (manifestStream).getMainAttributes (); 418 } finally { 419 manifestStream.close (); 420 } 421 } catch (IOException e) { 422 throw new BuildException ("exception when reading manifest " + manifest, e, location); 423 } 424 } try { 426 OutputStream infoStream = new FileOutputStream (infofile); 427 try { 428 PrintWriter ps = new PrintWriter(new OutputStreamWriter(infoStream, "UTF-8")); 429 ps.println ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 431 ps.println("<!DOCTYPE module PUBLIC \"-//NetBeans//DTD Autoupdate Module Info 2.0//EN\" \"http://www.netbeans.org/dtds/autoupdate-info-2_0.dtd\">"); 432 String codenamebase = attr.getValue ("OpenIDE-Module"); 433 if (codenamebase == null) 434 throw new BuildException ("invalid manifest, does not contain OpenIDE-Module", location); 435 int idx = codenamebase.lastIndexOf ('/'); 437 if (idx != -1) codenamebase = codenamebase.substring (0, idx); 438 ps.println ("<module codenamebase=\"" + codenamebase + "\""); 439 if (homepage != null) 440 ps.println (" homepage=\"" + xmlEscape(homepage) + "\""); 441 if (distribution != null) 442 ps.println (" distribution=\"" + xmlEscape(distribution) + "\""); 443 if (license != null) { 445 String name = license.getName (); 446 if (name == null) 447 throw new BuildException ("Every license must have a name or file attribute", location); 448 ps.println (" license=\"" + xmlEscape(name) + "\""); 449 } 450 ps.println (" downloadsize=\"0\""); 451 if (needsrestart != null) 452 ps.println (" needsrestart=\"" + needsrestart + "\""); 453 ps.println (">"); 454 if (description != null) { 455 ps.print (" <description>"); 456 ps.print (description.getText ()); 457 ps.println ("</description>"); 458 } 459 460 if (notification != null) { 461 ps.print(" <module_notification>"); 462 ps.print(notification.getText()); 463 ps.println("</module_notification>"); 464 } 465 466 if (externalPackages != null) { 467 Enumeration exp = externalPackages.elements(); 468 while (exp.hasMoreElements()) { 469 ExternalPackage externalPackage = (ExternalPackage) exp.nextElement(); 470 if (externalPackage.name == null || 471 externalPackage.targetName == null || 472 externalPackage.startUrl == null) 473 throw new BuildException("Must define name, targetname, starturl for external package"); 474 ps.print(" <external_package "); 475 ps.print("name=\""+externalPackage.name+"\" "); 476 ps.print("target_name=\""+externalPackage.targetName+"\" "); 477 ps.print("start_url=\""+externalPackage.startUrl+"\""); 478 if (externalPackage.description != null) 479 ps.print(" description=\""+externalPackage.description+"\""); 480 ps.println("/>"); 481 } 482 } 483 ps.print (" <manifest "); 485 boolean firstline = true; 486 List attrNames = new ArrayList(attr.size()); Iterator it = attr.keySet().iterator(); 488 while (it.hasNext()) { 489 attrNames.add(((Attributes.Name)it.next()).toString()); 490 } 491 Collections.sort(attrNames); 492 it = attrNames.iterator(); 493 while (it.hasNext()) { 494 String name = (String )it.next(); 495 if (! name.startsWith("OpenIDE-Module")) continue; 498 if (name.equals("OpenIDE-Module-Localizing-Bundle")) continue; 499 if (name.equals("OpenIDE-Module-Install")) continue; 500 if (name.equals("OpenIDE-Module-Layer")) continue; 501 if (name.equals("OpenIDE-Module-Description")) continue; 502 if (name.equals("OpenIDE-Module-Package-Dependency-Message")) continue; 503 if (name.equals("OpenIDE-Module-Public-Packages")) continue; 504 if (firstline) 505 firstline = false; 506 else 507 ps.print (" "); 508 ps.println(name + "=\"" + xmlEscape(attr.getValue(name)) + "\""); 509 } 510 ps.println (" />"); 511 if (license != null) { 513 ps.print (" <license name=\"" + xmlEscape(license.getName ()) + "\">"); 514 ps.print (license.getText ()); 515 ps.println ("</license>"); 516 } 517 ps.println ("</module>"); 518 ps.flush(); 519 } finally { 520 infoStream.close (); 521 } 522 } catch (IOException e) { 523 throw new BuildException ("exception when creating Info/info.xml", e, location); 524 } 525 } 526 long jarModified = file.lastModified (); Jar jar = (Jar) project.createTask ("jar"); 530 jar.setJarfile (file); 531 jar.setCompress(true); 533 jar.addFileset (getFileSet()); 536 jar.setLocation (location); 537 jar.init (); 538 jar.execute (); 539 if (signature != null && file.lastModified () != jarModified) { 541 if (signature.keystore == null) 542 throw new BuildException ("must define keystore attribute on <signature/>"); 543 if (signature.storepass == null) 544 throw new BuildException ("must define storepass attribute on <signature/>"); 545 if (signature.alias == null) 546 throw new BuildException ("must define alias attribute on <signature/>"); 547 if (signature.storepass.equals ("?") || !signature.keystore.exists()) { 548 log ("Not signing NBM file " + file + "; no stored-key password provided or keystore (" 549 + signature.keystore.toString() + ") doesn't exist", Project.MSG_WARN); 550 } else { 551 log ("Signing NBM file " + file); 552 SignJar signjar = (SignJar) project.createTask ("signjar"); 553 try { 555 try { 556 Class [] paramsT = {String .class}; 557 Object [] paramsV1 = {signature.keystore.getAbsolutePath()}; 558 Object [] paramsV2 = {file.getAbsolutePath()}; 559 signjar.getClass().getDeclaredMethod( "setKeystore", paramsT ).invoke( signjar, paramsV1 ); 560 signjar.getClass().getDeclaredMethod( "setJar", paramsT ).invoke( signjar, paramsV2 ); 561 } catch (NoSuchMethodException ex1) { 562 try { 564 Class [] paramsT = {File.class}; 565 Object [] paramsV1 = {signature.keystore}; 566 Object [] paramsV2 = {file}; 567 signjar.getClass().getDeclaredMethod( "setKeystore", paramsT ).invoke( signjar, paramsV1 ); 568 signjar.getClass().getDeclaredMethod( "setJar", paramsT ).invoke( signjar, paramsV2 ); 569 } 570 catch (NoSuchMethodException ex2) { 571 try { 573 Class [] paramsFile = {File.class}; 574 Class [] paramsString = {String .class}; 575 Object [] paramsV1 = {signature.keystore.getAbsolutePath()}; 576 Object [] paramsV2 = {file}; 577 signjar.getClass().getDeclaredMethod( "setKeystore", paramsString ).invoke( signjar, paramsV1 ); 578 signjar.getClass().getDeclaredMethod( "setJar", paramsFile ).invoke( signjar, paramsV2 ); 579 } 580 catch (NoSuchMethodException ex3) { 581 ex3.printStackTrace(System.err); 582 throw new BuildException("Unknown ANT version, only ANT 1.4.1 is currently supported and ANT 1.4.1+ is acceptable."); 583 } 584 } 585 } 586 } catch (IllegalAccessException ex3) { 587 throw new BuildException(ex3); 588 } catch (java.lang.reflect.InvocationTargetException ex4) { 589 throw new BuildException(ex4); 590 } 591 signjar.setStorepass (signature.storepass); 592 signjar.setAlias (signature.alias); 593 signjar.setLocation (location); 594 signjar.init (); 595 signjar.execute (); 596 } 597 } 598 } 599 600 602 FileSet getFileSet() { 603 FileSet fs = fileset; fs.setDir (topdir); 605 606 if (isStandardInclude) 607 fs.createInclude ().setName ("netbeans/"); 608 609 fs.createInclude ().setName ("Info/info.xml"); 610 return fs; 611 } 612 613 Attributes getAttributes() throws IOException { 614 if (manifest != null) { 615 InputStream is = new FileInputStream(manifest); 616 try { 617 return new Manifest(is).getMainAttributes(); 618 } finally { 619 is.close(); 620 } 621 } else if (module != null) { 622 JarFile jar = new JarFile(module); 623 try { 624 return jar.getManifest().getMainAttributes(); 625 } finally { 626 jar.close(); 627 } 628 } else { 629 throw new IOException(location + "must give either 'manifest' or 'module' on <makenbm>"); 630 } 631 } 632 } 633 | Popular Tags |