1 19 package org.netbeans.modules.ruby.rubyproject.api; 20 21 import java.awt.Dialog ; 22 import java.beans.PropertyChangeListener ; 23 import java.io.File ; 24 import java.io.IOException ; 25 import java.lang.String ; 26 import java.net.MalformedURLException ; 27 import java.net.URL ; 28 import java.util.ArrayList ; 29 import java.util.HashMap ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.prefs.Preferences ; 33 import java.util.regex.Matcher ; 34 import java.util.regex.Pattern ; 35 import javax.swing.JButton ; 36 import org.netbeans.api.java.classpath.ClassPath; 37 import org.netbeans.api.options.OptionsDisplayer; 38 import org.netbeans.modules.retouche.source.usages.ClassIndexManager; 39 import org.netbeans.spi.java.classpath.ClassPathFactory; 40 import org.netbeans.spi.java.classpath.ClassPathImplementation; 41 import org.netbeans.spi.java.classpath.PathResourceImplementation; 42 import org.openide.DialogDescriptor; 43 import org.openide.DialogDisplayer; 44 import org.openide.NotifyDescriptor; 45 import org.openide.modules.InstalledFileLocator; 46 import org.openide.util.Exceptions; 47 import org.openide.util.HelpCtx; 48 import org.openide.util.NbBundle; 49 import org.openide.util.NbPreferences; 50 import org.openide.util.Utilities; 51 52 53 58 public class RubyInstallation { 59 60 private static final String JRUBY_RELEASE = "0.9.8"; 62 public static final String RUBY_RELEASE = "1.8"; 64 private static final String JRUBY_RELEASEDIR = "jruby-" + JRUBY_RELEASE; 69 public static final String RUBY_MIME_TYPE = "text/x-ruby"; private static final String KEY_RUBY = "ruby"; private static final String KEY_RAKE = "rake"; private static final String KEY_RDOC = "rdoc"; private static final String KEY_RAILS = "rails"; private static final String KEY_IRB = "irb"; private static final String KEY_RAILS_PORT = "rails-port"; private static final RubyInstallation INSTANCE = new RubyInstallation(); 77 private String ruby; 78 private String gem; 79 private String rake; 80 private String rails; 81 private String rdoc; 82 private String irb; 83 private String jrubyHome; 84 85 private RubyInstallation() { 86 } 87 88 public static RubyInstallation getInstance() { 89 return INSTANCE; 90 } 91 92 public void setJRubyLoadPaths() { 94 System.setProperty("jruby.home", getJRubyHome()); 95 } 96 97 public String getRuby() { 98 if (ruby == null) { 99 String binary = org.openide.util.Utilities.isWindows() ? "jruby.bat" : "jruby"; 100 String defaultRuby = getJRubyBin() + File.separator + binary; 101 102 try { 104 defaultRuby = new File (defaultRuby).getCanonicalFile().getAbsolutePath(); 105 } catch (IOException ioe) { 106 Exceptions.printStackTrace(ioe); 107 } 108 109 ruby = getPreferences().get(KEY_RUBY, defaultRuby); 110 } 111 112 return ruby; 113 } 114 115 public boolean isValidRuby(boolean warn) { 116 File file = new File (getRuby()); 117 boolean valid = file.exists(); 118 119 if (warn && !valid) { 120 String msg = 121 NbBundle.getMessage(RubyInstallation.class, "NotInstalled", file.getPath()); 122 javax.swing.JButton closeButton = new javax.swing.JButton (NbBundle.getMessage(RubyInstallation.class,"CTL_Close")); 123 closeButton.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(RubyInstallation.class,"AD_Close")); 124 final JButton optionsButton = new JButton (NbBundle.getMessage (RubyInstallation.class, "EditOptions")); 125 Object [] options = new Object [] { 126 optionsButton, 127 closeButton 128 }; 129 DialogDescriptor descriptor = new DialogDescriptor (msg, 130 NbBundle.getMessage (RubyInstallation.class, "MissingRuby"), 131 true, options, optionsButton, DialogDescriptor.DEFAULT_ALIGN, new HelpCtx (RubyInstallation.class),null); 133 descriptor.setMessageType(NotifyDescriptor.Message.ERROR_MESSAGE); 134 Dialog dlg = null; 135 descriptor.setModal(true); 136 try { 137 dlg = DialogDisplayer.getDefault().createDialog (descriptor); 138 dlg.setVisible(true); 139 } finally { 140 if (dlg != null) 141 dlg.dispose(); 142 } 143 144 if (descriptor.getValue() == optionsButton) { 145 OptionsDisplayer.getDefault().open("Advanced"); } 147 } 148 149 return valid; 150 } 151 152 public String getGem() { 153 if (gem == null) { 154 File f = new File (getRuby()); 155 gem = new File (f.getParentFile(), Utilities.isWindows() ? "gem.bat" : "gem").getAbsolutePath(); } 158 159 return gem; 160 } 161 162 public String getRake() { 163 if (rake == null) { 164 String binary = "rake"; 166 String defaultRake = getJRubyBin() + File.separator + binary; 167 168 try { 170 defaultRake = new File (defaultRake).getCanonicalFile().getAbsolutePath(); 171 } catch (IOException ioe) { 172 Exceptions.printStackTrace(ioe); 173 } 174 175 rake = getPreferences().get(KEY_RAKE, defaultRake); 176 } 177 178 return rake; 179 } 180 181 public boolean isValidRake(boolean warn) { 182 File file = new File (getRake()); 183 boolean valid = file.exists(); 184 185 if (warn && !valid) { 186 String msg = 187 NbBundle.getMessage(RubyInstallation.class, "NotInstalled", file.getPath()); 188 NotifyDescriptor nd = 189 new NotifyDescriptor.Message(msg, NotifyDescriptor.Message.ERROR_MESSAGE); 190 DialogDisplayer.getDefault().notify(nd); 191 } 192 193 return valid; 194 } 195 196 public String getIrb() { 197 if (irb == null) { 198 String binary = "jirb"; 199 String defaultIrb = getJRubyBin() + File.separator + binary; 200 201 try { 203 defaultIrb = new File (defaultIrb).getCanonicalFile().getAbsolutePath(); 204 } catch (IOException ioe) { 205 Exceptions.printStackTrace(ioe); 206 } 207 208 irb = getPreferences().get(KEY_IRB, defaultIrb); 209 } 210 211 return irb; 212 } 213 214 public boolean isValidIrb(boolean warn) { 215 File file = new File (getIrb()); 216 boolean valid = file.exists(); 217 218 if (warn && !valid) { 219 String msg = 220 NbBundle.getMessage(RubyInstallation.class, "NotInstalled", file.getPath()); 221 NotifyDescriptor nd = 222 new NotifyDescriptor.Message(msg, NotifyDescriptor.Message.ERROR_MESSAGE); 223 DialogDisplayer.getDefault().notify(nd); 224 } 225 226 return valid; 227 } 228 229 public String getJRubyHome() { 230 if (jrubyHome == null) { 231 File f = 232 InstalledFileLocator.getDefault() 233 .locate("modules/org-netbeans-modules-ruby-project.jar", null, false); 235 if (f == null) { 236 throw new RuntimeException ("Can't find cluster"); 237 } 238 239 f = new File (f.getParentFile().getAbsolutePath() + File.separator + ".." + File.separator + JRUBY_RELEASEDIR); try { 241 f = f.getCanonicalFile(); 242 } catch (IOException ioe) { 243 Exceptions.printStackTrace(ioe); 244 } 245 jrubyHome = f.getPath(); 246 } 247 248 return jrubyHome; 249 } 250 251 private String getJRubyBin() { 252 return getJRubyHome() + File.separator + "bin"; 253 } 254 255 private String getJRubyLib() { 256 return getJRubyHome() + File.separator + "lib"; 257 } 258 259 260 public String getRubyLib() { 261 File rubyLib = new File (new File (getRuby()).getParentFile().getParent(), "lib"); if (rubyLib.exists() && new File (rubyLib, "ruby").exists()) { try { 264 return rubyLib.getCanonicalPath(); 265 } catch (IOException ioe) { 266 Exceptions.printStackTrace(ioe); 267 } 268 } 269 return getJRubyLib(); 270 } 271 272 public String getRDoc() { 273 if (rdoc == null) { 274 String binary = "rdoc"; 276 String defaultRDoc = getJRubyBin() + File.separator + binary; 277 278 try { 280 defaultRDoc = new File (defaultRDoc).getCanonicalFile().getAbsolutePath(); 281 } catch (IOException ioe) { 282 Exceptions.printStackTrace(ioe); 283 } 284 285 rdoc = getPreferences().get(KEY_RDOC, defaultRDoc); 286 } 287 288 return rdoc; 289 } 290 291 public boolean isValidRDoc(boolean warn) { 292 File file = new File (getRDoc()); 293 boolean valid = file.exists(); 294 295 if (warn && !valid) { 296 String msg = 297 NbBundle.getMessage(RubyInstallation.class, "NotInstalled", file.getPath()); 298 NotifyDescriptor nd = 299 new NotifyDescriptor.Message(msg, NotifyDescriptor.Message.ERROR_MESSAGE); 300 DialogDisplayer.getDefault().notify(nd); 301 } 302 303 return valid; 304 } 305 306 public String getRails() { 307 if (rails == null) { 308 String binary = "rails"; 310 String defaultRails = getJRubyBin() + File.separator + binary; 311 312 try { 314 defaultRails = new File (defaultRails).getCanonicalFile().getAbsolutePath(); 315 } catch (IOException ioe) { 316 Exceptions.printStackTrace(ioe); 317 } 318 319 rails = getPreferences().get(KEY_RAILS, defaultRails); 320 } 321 322 return rails; 323 } 324 325 public boolean isValidRails(boolean warn) { 326 File file = new File (getRails()); 327 boolean valid = file.exists(); 328 329 if (warn && !valid) { 330 String msg = 331 NbBundle.getMessage(RubyInstallation.class, "NotInstalled", file.getPath()); 332 NotifyDescriptor nd = 333 new NotifyDescriptor.Message(msg, NotifyDescriptor.Message.ERROR_MESSAGE); 334 DialogDisplayer.getDefault().notify(nd); 335 } 336 337 return valid; 338 } 339 340 public boolean isValid(File home) { 341 if (org.openide.util.Utilities.isWindows()) { 343 if (new File (home + File.separator + "bin" + File.separator + "jruby.bat").exists()) { 344 return true; 345 } 346 347 if (new File (home + File.separator + "bin" + File.separator + "ruby.exe").exists()) { 348 return true; 349 } 350 } else { 351 if (new File (home + File.separator + "bin" + File.separator + "jruby").exists()) { 352 return true; 353 } 354 355 if (new File (home + File.separator + "bin" + File.separator + "ruby").exists()) { 356 return true; 357 } 358 } 359 360 return false; 361 } 362 363 private static Preferences getPreferences() { 364 return NbPreferences.forModule(RubyInstallation.class); 365 } 366 367 public void setRuby(final String ruby) { 368 if (!ruby.equals(getRuby())) { 369 getPreferences().put(KEY_RUBY, ruby); 370 this.ruby = ruby; 371 recomputeRoots(); 372 } 373 } 374 375 public void setRake(final String rake) { 376 if (!rake.equals(getRake())) { 377 getPreferences().put(KEY_RAKE, rake); 378 this.rake = rake; 379 } 380 } 381 382 public void setRDoc(final String rdoc) { 383 if (!rdoc.equals(getRDoc())) { 384 getPreferences().put(KEY_RDOC, rdoc); 385 this.rdoc = rdoc; 386 } 387 } 388 389 public void setIrb(final String irb) { 390 if (!irb.equals(getIrb())) { 391 getPreferences().put(KEY_IRB, irb); 392 this.irb = irb; 393 } 394 } 395 396 public void setRails(final String rails) { 397 if (!rails.equals(getRails())) { 398 getPreferences().put(KEY_RAILS, rails); 399 this.rails = rails; 400 } 401 } 402 403 public void setRailsPort(final int port) { 404 getPreferences().putInt(KEY_RAILS_PORT, port); 405 } 406 407 public int getRailsPort() { 408 return getPreferences().getInt(KEY_RAILS_PORT, 3000); 409 } 410 411 412 public void ensureExecutable() { 413 if (Utilities.isWindows()) { 415 return; 416 } 417 418 File binDir = new File (getJRubyBin()); 419 420 File chmod = new File ("/bin/chmod"); if (!chmod.isFile()) { 424 chmod = new File ("/usr/bin/chmod"); } 427 if (chmod.isFile()) { 428 try { 429 List <String > argv = new ArrayList <String >(); 430 argv.add(chmod.getAbsolutePath()); 431 argv.add("u+rx"); String [] files = binDir.list(); 433 for (String file : files) { 434 argv.add(file); 435 } 436 ProcessBuilder pb = new ProcessBuilder (argv); 437 pb.directory(binDir); 438 Process process = pb.start(); 439 440 int chmoded = process.waitFor(); 441 if (chmoded != 0) { 442 throw new IOException ("could not run " + argv); } 444 } catch (InterruptedException e) { 445 Exceptions.printStackTrace(e); 446 } catch (IOException e) { 447 Exceptions.printStackTrace(e); 448 } 449 } 450 } 451 452 454 public void recomputeRoots() { 455 this.cp = null; 456 getClassPathEntries(); 458 459 463 } 464 465 private Pattern pattern = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)"); 466 467 468 private int compareGemVersions(String version1, String version2) { 469 if (version1.equals(version2)) { 470 return 0; 471 } 472 473 Matcher matcher1 = pattern.matcher(version1); 474 if (matcher1.matches()) { 475 int major1 = Integer.parseInt(matcher1.group(1)); 476 int minor1 = Integer.parseInt(matcher1.group(2)); 477 int micro1 = Integer.parseInt(matcher1.group(3)); 478 479 Matcher matcher2 = pattern.matcher(version2); 480 if (matcher2.matches()) { 481 int major2 = Integer.parseInt(matcher2.group(1)); 482 int minor2 = Integer.parseInt(matcher2.group(2)); 483 int micro2 = Integer.parseInt(matcher2.group(3)); 484 485 if (major1 != major2) { 486 return major1-major2; 487 } 488 if (minor1 != minor2) { 489 return minor1-minor2; 490 } 491 if (micro1 != micro2) { 492 return micro1-micro2; 493 } 494 } else { 495 } 498 } else { 499 } 501 502 return version1.compareTo(version2); 504 } 505 506 public String getVersion(String gemName) { 507 if (gemFiles == null) { 508 return null; 509 } 510 511 Map <String ,File > highestVersion = gemFiles.get(gemName); 512 if (highestVersion == null || highestVersion.size() == 0) { 513 return null; 514 } 515 516 return highestVersion.keySet().iterator().next(); 517 } 518 519 Map <String ,Map <String ,File >> gemFiles = new HashMap <String ,Map <String ,File >>(); 520 521 522 524 private File [] chooseGems(File [] gems) { 525 for (File f : gems) { 526 String n = f.getName(); 528 int dashIndex = n.indexOf('-'); 529 if (dashIndex != -1) { 530 String name = n.substring(0, dashIndex); 531 String version = n.substring(dashIndex+1); 532 533 Map <String ,File > nameMap = gemFiles.get(name); 534 if (nameMap == null) { 535 nameMap = new HashMap <String ,File >(); 536 gemFiles.put(name, nameMap); 537 nameMap.put(version, f); 538 } else { 539 String oldVersion = nameMap.keySet().iterator().next(); 541 if (compareGemVersions(version, oldVersion) > 0) { 542 nameMap.clear(); 544 nameMap.put(version, f); 545 } 546 } 547 } 548 } 549 550 List <File > result = new ArrayList <File >(); 551 for (Map <String ,File > map : gemFiles.values()) { 552 for (File f : map.values()) { 553 result.add(f); 554 } 555 } 556 557 return result.toArray(new File [result.size()]); 558 } 559 560 private static boolean SKIP_INDEX_LIBS = System.getProperty("ruby.index.nolibs") != null; 561 private static boolean SKIP_INDEX_GEMS = System.getProperty("ruby.index.nogems") != null; 562 563 static ClassPath cp; 565 public List <ClassPath.Entry> getClassPathEntries() { 566 if (cp == null) { 567 cp = ClassPathFactory.createClassPath(new ClassPathImplementation() { 568 public List <? extends PathResourceImplementation> getResources() { 569 try { 570 List <PathResourceImplementation> list = new ArrayList <PathResourceImplementation>(); 571 List <URL > urls = new ArrayList <URL >(); 572 575 File builtin = new File (getJRubyHome()+File.separator+"rubystubs"); 577 assert builtin.exists() && builtin.isDirectory(); 578 urls.add(builtin.toURI().toURL()); 579 580 String rubyLib = getRubyLib(); 581 582 if (!SKIP_INDEX_LIBS) { 585 File libs = new File (rubyLib+File.separator+"ruby"+File.separator+RUBY_RELEASE); 586 assert libs.exists() && libs.isDirectory(); 587 urls.add(libs.toURI().toURL()); 588 } 589 590 if (!SKIP_INDEX_GEMS) { 592 File gemDir = new File (rubyLib+File.separator+"ruby"+File.separator+"gems"+File.separator+ 593 RUBY_RELEASE+File.separator+"gems"+File.separator); 594 if (gemDir.exists()) { 595 File [] gems = gemDir.listFiles(); 597 gems = chooseGems(gems); 598 for (File gem : gems) { 599 File lib = new File (gem, "lib"); 601 if (lib.exists() && lib.isDirectory()) { 602 URL url = lib.toURI().toURL(); 603 urls.add(url); 604 } 605 } 606 } 607 } 608 609 if (!SKIP_INDEX_LIBS) { 611 File siteruby = new File (rubyLib+File.separator+"ruby"+File.separator+"site_ruby"+File.separator+RUBY_RELEASE); 612 if (siteruby.exists() && siteruby.isDirectory()) { 613 urls.add(siteruby.toURI().toURL()); 614 } 615 } 616 617 ClassIndexManager mgr = ClassIndexManager.getDefault(); 621 mgr.setBootRoots(urls); 622 623 final URL [] roots = urls.toArray(new URL [urls.size()]); 624 PathResourceImplementation pri = new PathResourceImplementation() { 625 public URL [] getRoots() { 626 return roots; 627 } 628 629 public ClassPathImplementation getContent() { 630 return null; 631 } 632 public void addPropertyChangeListener(PropertyChangeListener listener) { 633 } 635 public void removePropertyChangeListener(PropertyChangeListener listener) { 636 } 638 }; 639 list.add(pri); 640 return list; 641 } catch (MalformedURLException mue) { 642 Exceptions.printStackTrace(mue); 643 } 644 645 return null; 646 } 647 648 public void addPropertyChangeListener(PropertyChangeListener listener) { 649 } 652 653 public void removePropertyChangeListener(PropertyChangeListener listener) { 654 } 657 }); 658 } 659 660 return cp.entries(); 661 } 662 } 663 | Popular Tags |