1 19 20 package org.netbeans.modules.ruby.spi.project.support.rake; 21 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.net.URI ; 25 import java.net.URISyntaxException ; 26 import java.util.ArrayList ; 27 import java.util.Arrays ; 28 import java.util.Collection ; 29 import java.util.Collections ; 30 import java.util.HashMap ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.Map ; 35 import java.util.Properties ; 36 import java.util.Set ; 37 import java.util.TreeSet ; 38 import java.util.regex.Matcher ; 39 import java.util.regex.Pattern ; 40 import org.netbeans.api.project.Project; 41 import org.netbeans.api.project.ProjectManager; 42 import org.netbeans.api.project.ProjectUtils; 43 import org.netbeans.modules.ruby.api.project.rake.RakeArtifact; 44 import org.netbeans.modules.ruby.api.project.rake.RakeArtifactQuery; 45 import org.netbeans.api.queries.CollocationQuery; 46 import org.netbeans.modules.ruby.modules.project.rake.RakeBasedProjectFactorySingleton; 47 import org.netbeans.modules.ruby.modules.project.rake.Util; 48 import org.netbeans.spi.project.AuxiliaryConfiguration; 49 import org.netbeans.spi.project.SubprojectProvider; 50 import org.openide.ErrorManager; 51 import org.openide.filesystems.FileObject; 52 import org.openide.filesystems.FileUtil; 53 import org.openide.util.Mutex; 54 import org.openide.util.NbCollections; 55 import org.openide.xml.XMLUtil; 56 import org.w3c.dom.Document ; 57 import org.w3c.dom.Element ; 58 import org.w3c.dom.NodeList ; 59 60 62 84 public final class ReferenceHelper { 85 86 89 static final String REFS_NAME = "references"; 91 94 static final String REF_NAME = "reference"; 96 99 static final String REFS_NS = "http://www.netbeans.org/ns/rake-project-references/1"; 101 104 static final String REFS_NS2 = "http://www.netbeans.org/ns/rake-project-references/2"; 106 108 private Set <String > extraBaseDirectories = new HashSet <String >(); 109 110 private final RakeProjectHelper h; 111 final PropertyEvaluator eval; 112 private final AuxiliaryConfiguration aux; 113 114 134 public ReferenceHelper(RakeProjectHelper helper, AuxiliaryConfiguration aux, PropertyEvaluator eval) { 135 h = helper; 136 this.aux = aux; 137 this.eval = eval; 138 } 139 140 144 private Element loadReferences() { 145 assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess(); 146 Element references = aux.getConfigurationFragment(REFS_NAME, REFS_NS2, true); 147 if (references == null) { 148 references = aux.getConfigurationFragment(REFS_NAME, REFS_NS, true); 149 } 150 return references; 151 } 152 153 156 private void storeReferences(Element references) { 157 assert ProjectManager.mutex().isWriteAccess(); 158 assert references != null && references.getLocalName().equals(REFS_NAME) && 159 (REFS_NS.equals(references.getNamespaceURI()) || REFS_NS2.equals(references.getNamespaceURI())); 160 aux.putConfigurationFragment(references, true); 161 } 162 163 private void removeOldReferences() { 164 assert ProjectManager.mutex().isWriteAccess(); 165 aux.removeConfigurationFragment(REFS_NAME, REFS_NS, true); 166 } 167 168 180 @Deprecated 181 public boolean addReference(final RakeArtifact artifact) throws IllegalArgumentException { 182 Object ret[] = addReference0(artifact, artifact.getArtifactLocations()[0]); 183 return ((Boolean )ret[0]).booleanValue(); 184 } 185 186 private Object [] addReference0(final RakeArtifact artifact, final URI location) throws IllegalArgumentException { 188 return ProjectManager.mutex().writeAccess(new Mutex.Action<Object []>() { 189 public Object [] run() { 190 int index = findLocationIndex(artifact, location); 191 Project forProj = artifact.getProject(); 192 if (forProj == null) { 193 throw new IllegalArgumentException ("No project associated with " + artifact); } 195 File forProjDir = FileUtil.toFile(forProj.getProjectDirectory()); 197 assert forProjDir != null : forProj.getProjectDirectory(); 198 String projName = getUsableReferenceID(ProjectUtils.getInformation(forProj).getName()); 199 String forProjName = findReferenceID(projName, "project.", forProjDir.getAbsolutePath()); 200 if (forProjName == null) { 201 forProjName = generateUniqueID(projName, "project.", forProjDir.getAbsolutePath()); 202 } 203 RawReference ref; 204 File scriptFile = artifact.getScriptLocation(); 205 if (canUseVersion10(artifact, forProjDir)) { 206 String rel = PropertyUtils.relativizeFile(forProjDir, scriptFile); 207 URI scriptLocation; 208 try { 209 scriptLocation = new URI (null, null, rel, null); 210 } catch (URISyntaxException ex) { 211 scriptLocation = forProjDir.toURI().relativize(scriptFile.toURI()); 212 } 213 ref = new RawReference(forProjName, artifact.getType(), scriptLocation, artifact.getTargetName(), artifact.getCleanTargetName(), artifact.getID()); 214 } else { 215 String scriptLocation; 216 if (scriptFile.getAbsolutePath().startsWith(forProjDir.getAbsolutePath())) { 217 String rel = PropertyUtils.relativizeFile(forProjDir, scriptFile); 218 assert rel != null : "Relativization must succeed for files: "+forProjDir+ " "+scriptFile; 219 scriptLocation = "${project."+forProjName+"}/"+rel; 220 } else { 221 scriptLocation = "build.script.reference." + forProjName; 222 setPathProperty(forProjDir, scriptFile, scriptLocation); 223 scriptLocation = "${"+scriptLocation+"}"; 224 } 225 ref = new RawReference(forProjName, artifact.getType(), scriptLocation, 226 artifact.getTargetName(), artifact.getCleanTargetName(), 227 artifact.getID(), artifact.getProperties()); 228 } 229 boolean success = addRawReference0(ref); 230 FileObject myProjDirFO = RakeBasedProjectFactorySingleton.getProjectFor(h).getProjectDirectory(); 232 File myProjDir = FileUtil.toFile(myProjDirFO); 233 if (setPathProperty(myProjDir, forProjDir, "project." + forProjName)) { 234 success = true; 235 } 236 String propertiesFile; 238 String forProjPathProp = "project." + forProjName; URI artFile = location; 240 String refPath; 241 if (artFile.isAbsolute()) { 242 refPath = new File (artFile).getAbsolutePath(); 243 propertiesFile = RakeProjectHelper.PRIVATE_PROPERTIES_PATH; 244 } else { 245 refPath = "${" + forProjPathProp + "}/" + artFile.getPath(); propertiesFile = RakeProjectHelper.PROJECT_PROPERTIES_PATH; 247 } 248 EditableProperties props = h.getProperties(propertiesFile); 249 String refPathProp = "reference." + forProjName + '.' + getUsableReferenceID(artifact.getID()); if (index > 0) { 251 refPathProp += "."+index; 252 } 253 if (!refPath.equals(props.getProperty(refPathProp))) { 254 props.put(refPathProp, refPath); 255 h.putProperties(propertiesFile, props); 256 success = true; 257 } 258 return new Object [] {success, "${" + refPathProp + "}"}; } 260 }); 261 } 262 263 private int findLocationIndex(final RakeArtifact artifact, final URI location) throws IllegalArgumentException { 264 if (location == null) { 265 throw new IllegalArgumentException ("location cannot be null"); 266 } 267 URI uris[] = artifact.getArtifactLocations(); 268 for (int i=0; i<uris.length; i++) { 269 if (uris[i].equals(location)) { 270 return i; 271 } 272 } 273 throw new IllegalArgumentException ("location ("+location+") must be in RakeArtifact's locations ("+artifact+")"); 274 } 275 276 279 private static boolean canUseVersion10(RakeArtifact aa, File projectDirectory) { 280 if (aa.getArtifactLocations().length > 1) { 282 return false; 283 } 284 if (aa.getProperties().keySet().size() > 0) { 286 return false; 287 } 288 if (!aa.getScriptLocation().getAbsolutePath().startsWith(projectDirectory.getAbsolutePath())) { 290 return false; 291 } 292 return true; 293 } 294 295 301 private boolean setPathProperty(File base, File path, String propertyName) { 302 String [] values; 303 String [] propertiesFiles; 304 305 String relativePath = relativizeFileToExtraBaseFolders(path); 306 if (relativePath != null) { 308 propertiesFiles = new String [] { 309 RakeProjectHelper.PROJECT_PROPERTIES_PATH 310 }; 311 values = new String [] { 312 relativePath 313 }; 314 } 315 else if (CollocationQuery.areCollocated(base, path)) { 316 relativePath = PropertyUtils.relativizeFile(base, path); 318 assert relativePath != null : "These dirs are not really collocated: " + base + " & " + path; 319 values = new String [] { 320 relativePath, 321 path.getAbsolutePath() 322 }; 323 propertiesFiles = new String [] { 324 RakeProjectHelper.PROJECT_PROPERTIES_PATH, 325 RakeProjectHelper.PRIVATE_PROPERTIES_PATH, 326 }; 327 } else { 328 propertiesFiles = new String [] { 330 RakeProjectHelper.PRIVATE_PROPERTIES_PATH 331 }; 332 values = new String [] { 333 path.getAbsolutePath() 334 }; 335 } 336 337 boolean metadataChanged = false; 338 for (int i=0; i<propertiesFiles.length; i++) { 339 EditableProperties props = h.getProperties(propertiesFiles[i]); 340 if (!values[i].equals(props.getProperty(propertyName))) { 341 props.put(propertyName, values[i]); 342 h.putProperties(propertiesFiles[i], props); 343 metadataChanged = true; 344 } 345 } 346 347 if (propertiesFiles.length == 1) { 348 String propertiesFile = (propertiesFiles[0] == RakeProjectHelper.PROJECT_PROPERTIES_PATH ? 351 RakeProjectHelper.PRIVATE_PROPERTIES_PATH : RakeProjectHelper.PROJECT_PROPERTIES_PATH); 352 EditableProperties props = h.getProperties(propertiesFile); 353 if (props.remove(propertyName) != null) { 354 h.putProperties(propertiesFile, props); 355 } 356 } 357 return metadataChanged; 358 } 359 360 398 public String addReference(final RakeArtifact artifact, URI location) throws IllegalArgumentException { 399 Object ret[] = addReference0(artifact, location); 400 return (String )ret[1]; 401 } 402 403 417 public boolean isReferenced(final RakeArtifact artifact, final URI location) throws IllegalArgumentException { 418 return ProjectManager.mutex().readAccess(new Mutex.Action<Boolean >() { 419 public Boolean run() { 420 int index = findLocationIndex(artifact, location); 421 Project forProj = artifact.getProject(); 422 if (forProj == null) { 423 throw new IllegalArgumentException ("No project associated with " + artifact); } 425 File forProjDir = FileUtil.toFile(forProj.getProjectDirectory()); 426 assert forProjDir != null : forProj.getProjectDirectory(); 427 String projName = getUsableReferenceID(ProjectUtils.getInformation(forProj).getName()); 428 String forProjName = findReferenceID(projName, "project.", forProjDir.getAbsolutePath()); 429 if (forProjName == null) { 430 return false; 431 } 432 RawReference ref = getRawReference(forProjName, getUsableReferenceID(artifact.getID())); 433 if (ref == null) { 434 return false; 435 } 436 File script = h.resolveFile(eval.evaluate(ref.getScriptLocationValue())); 437 if (!artifact.getType().equals(ref.getArtifactType()) || 438 !artifact.getID().equals(ref.getID()) || 439 !artifact.getScriptLocation().equals(script) || 440 !artifact.getProperties().equals(ref.getProperties()) || 441 !artifact.getTargetName().equals(ref.getTargetName()) || 442 !artifact.getCleanTargetName().equals(ref.getCleanTargetName())) { 443 return false; 444 } 445 446 String reference = "reference." + forProjName + '.' + getUsableReferenceID(artifact.getID()); if (index > 0) { 448 reference += "."+index; 449 } 450 return eval.getProperty(reference) != null; 451 } 452 }); 453 } 454 455 474 public boolean addRawReference(final RawReference ref) { 475 return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean >() { 476 public Boolean run() { 477 try { 478 return addRawReference0(ref); 479 } catch (IllegalArgumentException e) { 480 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 481 return false; 482 } 483 } 484 }); 485 } 486 487 private boolean addRawReference0(final RawReference ref) throws IllegalArgumentException { 488 Element references = loadReferences(); 489 if (references == null) { 490 references = XMLUtil.createDocument("ignore", null, null, null).createElementNS(ref.getNS(), REFS_NAME); } 492 boolean modified = false; 493 if (references.getNamespaceURI().equals(REFS_NS) && ref.getNS().equals(REFS_NS2)) { 494 references = upgradeTo20(references); 496 removeOldReferences(); 497 modified = true; 498 } 499 modified = updateRawReferenceElement(ref, references); 500 if (modified) { 501 storeReferences(references); 502 } 503 return modified; 504 } 505 506 private Element upgradeTo20(Element references) { 507 Element references20 = XMLUtil.createDocument("ignore", null, null, null).createElementNS(REFS_NS2, REFS_NAME); RawReference rr[] = getRawReferences(references); 509 for (int i=0; i<rr.length; i++) { 510 rr[i].upgrade(); 511 updateRawReferenceElement(rr[i], references20); 512 } 513 return references20; 514 } 515 516 private static boolean updateRawReferenceElement(RawReference ref, Element references) throws IllegalArgumentException { 517 Element nextRefEl = null; 520 Iterator <Element > it = Util.findSubElements(references).iterator(); 521 while (it.hasNext()) { 522 Element testRefEl = it.next(); 523 RawReference testRef = RawReference.create(testRefEl); 524 if (testRef.getForeignProjectName().compareTo(ref.getForeignProjectName()) > 0) { 525 nextRefEl = testRefEl; 527 break; 528 } 529 if (testRef.getForeignProjectName().equals(ref.getForeignProjectName())) { 530 if (testRef.getID().compareTo(ref.getID()) > 0) { 531 nextRefEl = testRefEl; 533 break; 534 } 535 if (testRef.getID().equals(ref.getID())) { 536 if (testRef.getArtifactType().equals(ref.getArtifactType()) && 538 testRef.getScriptLocationValue().equals(ref.getScriptLocationValue()) && 539 testRef.getProperties().equals(ref.getProperties()) && 540 testRef.getTargetName().equals(ref.getTargetName()) && 541 testRef.getCleanTargetName().equals(ref.getCleanTargetName())) { 542 return false; 544 } 545 references.removeChild(testRefEl); 548 if (it.hasNext()) { 549 nextRefEl = it.next(); 550 } else { 551 nextRefEl = null; 552 } 553 break; 554 } 555 } 556 } 557 Element newRefEl = ref.toXml(references.getNamespaceURI(), references.getOwnerDocument()); 559 references.insertBefore(newRefEl, nextRefEl); 561 return true; 562 } 563 564 582 @Deprecated 583 public boolean removeReference(final String foreignProjectName, final String id) { 584 return removeReference(foreignProjectName, id, false, null); 585 } 586 587 591 private boolean isLastReference(String ref) { 592 Object ret[] = findArtifactAndLocation(ref); 593 if (ret[0] == null || ret[1] == null) { 594 return true; 595 } 596 RakeArtifact aa = (RakeArtifact)ret[0]; 597 URI uri = (URI )ret[1]; 598 URI uris[] = aa.getArtifactLocations(); 599 boolean lastReference = true; 600 for (int i=0; i<uris.length; i++) { 602 if (uris[i].equals(uri)) { 603 continue; 604 } 605 if (isReferenced(aa, uris[i])) { 606 lastReference = false; 607 break; 608 } 609 } 610 return lastReference; 611 } 612 613 private boolean removeReference(final String foreignProjectName, final String id, final boolean escaped, final String reference) { 614 return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean >() { 615 public Boolean run() { 616 boolean success = false; 617 try { 618 if (isLastReference("${"+reference+"}")) { 619 success = removeRawReference0(foreignProjectName, id, escaped); 620 } 621 } catch (IllegalArgumentException e) { 622 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 623 return false; 624 } 625 String [] PROPS_PATHS = { 628 RakeProjectHelper.PROJECT_PROPERTIES_PATH, 629 RakeProjectHelper.PRIVATE_PROPERTIES_PATH, 630 }; 631 if (success) { 633 RawReference[] refs = new RawReference[0]; 636 Element references = loadReferences(); 637 if (references != null) { 638 refs = getRawReferences(references); 639 } 640 boolean deleteProjProp = true; 641 for (int i = 0; i < refs.length; i++) { 642 if (refs[i].getForeignProjectName().equals(foreignProjectName)) { 643 deleteProjProp = false; 644 break; 645 } 646 } 647 if (deleteProjProp) { 648 String projProp = "project." + foreignProjectName; for (int i = 0; i < PROPS_PATHS.length; i++) { 650 EditableProperties props = h.getProperties(PROPS_PATHS[i]); 651 if (props.containsKey(projProp)) { 652 props.remove(projProp); 653 h.putProperties(PROPS_PATHS[i], props); 654 success = true; 655 } 656 } 657 } 658 } 659 660 String refProp = reference; 661 if (refProp == null) { 662 refProp = "reference." + foreignProjectName + '.' + getUsableReferenceID(id); } 664 String buildScriptProperty = "build.script.reference." + foreignProjectName; 666 for (String path : PROPS_PATHS) { 667 EditableProperties props = h.getProperties(path); 668 if (props.containsKey(refProp)) { 669 props.remove(refProp); 670 h.putProperties(path, props); 671 success = true; 672 } 673 if (props.containsKey(buildScriptProperty)) { 674 props.remove(buildScriptProperty); 675 h.putProperties(path, props); 676 success = true; 677 } 678 } 679 return success; 680 } 681 }); 682 } 683 684 695 @Deprecated 696 public boolean removeReference(final String fileReference) { 697 return removeFileReference(fileReference); 698 } 699 700 private boolean removeFileReference(final String fileReference) { 701 return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean >() { 702 public Boolean run() { 703 boolean success = false; 704 String [] PROPS_PATHS = { 707 RakeProjectHelper.PROJECT_PROPERTIES_PATH, 708 RakeProjectHelper.PRIVATE_PROPERTIES_PATH, 709 }; 710 String refProp = fileReference; 711 if (refProp.startsWith("${") && refProp.endsWith("}")) { 712 refProp = refProp.substring(2, refProp.length()-1); 713 } 714 for (String path : PROPS_PATHS) { 715 EditableProperties props = h.getProperties(path); 716 if (props.containsKey(refProp)) { 717 props.remove(refProp); 718 h.putProperties(path, props); 719 success = true; 720 } 721 } 722 return success; 723 } 724 }); 725 } 726 727 740 public boolean removeRawReference(final String foreignProjectName, final String id) { 741 return ProjectManager.mutex().writeAccess(new Mutex.Action<Boolean >() { 742 public Boolean run() { 743 try { 744 return removeRawReference0(foreignProjectName, id, false); 745 } catch (IllegalArgumentException e) { 746 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 747 return false; 748 } 749 } 750 }); 751 } 752 753 private boolean removeRawReference0(final String foreignProjectName, final String id, boolean escaped) throws IllegalArgumentException { 754 Element references = loadReferences(); 755 if (references == null) { 756 return false; 757 } 758 boolean success = removeRawReferenceElement(foreignProjectName, id, references, escaped); 759 if (success) { 760 storeReferences(references); 761 } 762 return success; 763 } 764 765 private static boolean removeRawReferenceElement(String foreignProjectName, String id, Element references, boolean escaped) throws IllegalArgumentException { 766 for (Element testRefEl : Util.findSubElements(references)) { 768 RawReference testRef = RawReference.create(testRefEl); 769 String refID = testRef.getID(); 770 String refName = testRef.getForeignProjectName(); 771 if (escaped) { 772 refID = getUsableReferenceID(testRef.getID()); 773 refName = getUsableReferenceID(testRef.getForeignProjectName()); 774 } 775 if (refName.compareTo(foreignProjectName) > 0) { 776 return false; 778 } 779 if (refName.equals(foreignProjectName)) { 780 if (refID.compareTo(id) > 0) { 781 return false; 783 } 784 if (refID.equals(id)) { 785 references.removeChild(testRefEl); 787 return true; 788 } 789 } 790 } 791 return false; 793 } 794 795 803 public RawReference[] getRawReferences() { 804 return ProjectManager.mutex().readAccess(new Mutex.Action<RawReference[]>() { 805 public RawReference[] run() { 806 Element references = loadReferences(); 807 if (references != null) { 808 try { 809 return getRawReferences(references); 810 } catch (IllegalArgumentException e) { 811 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 812 } 813 } 814 return new RawReference[0]; 815 } 816 }); 817 } 818 819 private static RawReference[] getRawReferences(Element references) throws IllegalArgumentException { 820 List <Element > subEls = Util.findSubElements(references); 821 List <RawReference> refs = new ArrayList <RawReference>(subEls.size()); 822 for (Element subEl : subEls) { 823 refs.add(RawReference.create(subEl)); 824 } 825 return refs.toArray(new RawReference[refs.size()]); 826 } 827 828 840 public RawReference getRawReference(final String foreignProjectName, final String id) { 841 return getRawReference(foreignProjectName, id, false); 842 } 843 844 RawReference getRawReference(final String foreignProjectName, final String id, final boolean escaped) { 846 return ProjectManager.mutex().readAccess(new Mutex.Action<RawReference>() { 847 public RawReference run() { 848 Element references = loadReferences(); 849 if (references != null) { 850 try { 851 return getRawReference(foreignProjectName, id, references, escaped); 852 } catch (IllegalArgumentException e) { 853 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 854 } 855 } 856 return null; 857 } 858 }); 859 } 860 861 private static RawReference getRawReference(String foreignProjectName, String id, Element references, boolean escaped) throws IllegalArgumentException { 862 for (Element subEl : Util.findSubElements(references)) { 863 RawReference ref = RawReference.create(subEl); 864 String refID = ref.getID(); 865 String refName = ref.getForeignProjectName(); 866 if (escaped) { 867 refID = getUsableReferenceID(ref.getID()); 868 refName = getUsableReferenceID(ref.getForeignProjectName()); 869 } 870 if (refName.equals(foreignProjectName) && refID.equals(id)) { 871 return ref; 872 } 873 } 874 return null; 875 } 876 877 893 public String createForeignFileReference(final File file, final String expectedArtifactType) { 894 if (!file.equals(FileUtil.normalizeFile(file))) { 895 throw new IllegalArgumentException ("Parameter file was not "+ "normalized. Was "+file+" instead of "+FileUtil.normalizeFile(file)); } 898 return ProjectManager.mutex().writeAccess(new Mutex.Action<String >() { 899 public String run() { 900 RakeArtifact art = RakeArtifactQuery.findArtifactFromFile(file); 901 if (art != null && art.getType().equals(expectedArtifactType) && art.getProject() != null) { 902 try { 903 return createForeignFileReference(art); 904 } catch (IllegalArgumentException iae) { 905 throw new AssertionError (iae); 906 } 907 } else { 908 String propertiesFile; 909 String path; 910 File myProjDir = FileUtil.toFile(RakeBasedProjectFactorySingleton.getProjectFor(h).getProjectDirectory()); 911 String fileID = file.getName(); 912 if (file.isDirectory() && file.getParentFile() != null) { 917 fileID = file.getParentFile().getName()+"-"+file.getName(); 918 } 919 fileID = PropertyUtils.getUsablePropertyName(fileID); 920 String prop = findReferenceID(fileID, "file.reference.", file.getAbsolutePath()); if (prop == null) { 922 prop = generateUniqueID(fileID, "file.reference.", file.getAbsolutePath()); } 924 setPathProperty(myProjDir, file, "file.reference." + prop); 925 return "${file.reference." + prop + '}'; } 927 } 928 }); 929 } 930 931 935 private String relativizeFileToExtraBaseFolders(File f) { 936 File base = FileUtil.toFile(h.getProjectDirectory()); 937 String fileToRelativize = f.getAbsolutePath(); 938 for (String prop : extraBaseDirectories) { 939 String path = eval.getProperty(prop); 940 File extraBase = PropertyUtils.resolveFile(base, path); 941 path = extraBase.getAbsolutePath(); 942 if (!path.endsWith(File.separator)) { 943 path += File.separator; 944 } 945 if (fileToRelativize.startsWith(path)) { 946 return "${"+prop+"}/"+fileToRelativize.substring(path.length()).replace('\\', '/'); } 948 } 949 return null; 950 } 951 952 966 public void addExtraBaseDirectory(final String propertyName) { 967 if (propertyName == null || eval.getProperty(propertyName) == null) { 968 throw new IllegalArgumentException ("propertyName is null or such a property does not exist: "+propertyName); } 970 ProjectManager.mutex().writeAccess(new Runnable () { 971 public void run() { 972 if (!extraBaseDirectories.add(propertyName)) { 973 throw new IllegalArgumentException ("Already extra base directory property: "+propertyName); } 975 } 976 }); 977 } 978 979 993 public void removeExtraBaseDirectory(final String propertyName) { 994 ProjectManager.mutex().writeAccess(new Runnable () { 995 public void run() { 996 if (!extraBaseDirectories.remove(propertyName)) { 997 throw new IllegalArgumentException ("Non-existing extra base directory property: "+propertyName); } 999 String tag = "${"+propertyName+"}"; boolean shared = h.getProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH).containsKey(propertyName); 1003 String value = eval.getProperty(propertyName); 1004 EditableProperties propProj = h.getProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH); 1005 EditableProperties propPriv = h.getProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH); 1006 boolean modifiedProj = false; 1007 boolean modifiedPriv = false; 1008 Iterator <Map.Entry <String ,String >> it = propProj.entrySet().iterator(); 1009 while (it.hasNext()) { 1010 Map.Entry <String ,String > entry = it.next(); 1011 String val = entry.getValue(); 1012 int index; 1013 if ((index = val.indexOf(tag)) != -1) { 1014 val = val.substring(0, index) +value + val.substring(index+tag.length()); 1015 if (shared) { 1016 entry.setValue(val); 1018 } else { 1019 it.remove(); 1021 propPriv.put(entry.getKey(), val); 1022 modifiedPriv = true; 1023 } 1024 modifiedProj = true; 1025 } 1026 } 1027 if (modifiedProj) { 1028 h.putProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH, propProj); 1029 } 1030 if (modifiedPriv) { 1031 h.putProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH, propPriv); 1032 } 1033 } 1034 }); 1035 } 1036 1037 1046 private String findReferenceID(String property, String prefix, String path) { 1047 Map <String ,String > m = h.getStandardPropertyEvaluator().getProperties(); 1048 for (Map.Entry <String ,String > e : m.entrySet()) { 1049 String key = e.getKey(); 1050 if (key.startsWith(prefix+property)) { 1051 String v = h.resolvePath(e.getValue()); 1052 if (path.equals(v)) { 1053 return key.substring(prefix.length()); 1054 } 1055 } 1056 } 1057 return null; 1058 } 1059 1060 1069 private String generateUniqueID(String property, String prefix, String value) { 1070 PropertyEvaluator pev = h.getStandardPropertyEvaluator(); 1071 if (pev.getProperty(prefix+property) == null) { 1072 return property; 1073 } 1074 int i = 1; 1075 while (pev.getProperty(prefix+property+"-"+i) != null) { 1076 i++; 1077 } 1078 return property+"-"+i; 1079 } 1080 1081 1092 @Deprecated 1093 public String createForeignFileReference(RakeArtifact artifact) throws IllegalArgumentException { 1094 Object ret[] = addReference0(artifact, artifact.getArtifactLocations()[0]); 1095 return (String )ret[1]; 1096 } 1097 1098 1102 private static String getUsableReferenceID(String ID) { 1103 return PropertyUtils.getUsablePropertyName(ID).replace('.', '_'); 1104 } 1105 1106 1107 private static final Pattern FOREIGN_FILE_REFERENCE = Pattern.compile("\\$\\{reference\\.([^.${}]+)\\.([^.${}]+)\\.([\\d&&[^.${}]]+)\\}"); private static final Pattern FOREIGN_FILE_REFERENCE_OLD = Pattern.compile("\\$\\{reference\\.([^.${}]+)\\.([^.${}]+)\\}"); private static final Pattern FOREIGN_PLAIN_FILE_REFERENCE = Pattern.compile("\\$\\{file\\.reference\\.([^${}]+)\\}"); 1111 1121 @Deprecated 1122 public RakeArtifact getForeignFileReferenceAsArtifact(final String reference) { 1123 Object ret[] = findArtifactAndLocation(reference); 1124 return (RakeArtifact)ret[0]; 1125 } 1126 1127 1140 public Object [] findArtifactAndLocation(final String reference) { 1141 return ProjectManager.mutex().readAccess(new Mutex.Action<Object []>() { 1142 public Object [] run() { 1143 RakeArtifact aa = null; 1144 Matcher m = FOREIGN_FILE_REFERENCE.matcher(reference); 1145 boolean matches = m.matches(); 1146 int index = 0; 1147 if (!matches) { 1148 m = FOREIGN_FILE_REFERENCE_OLD.matcher(reference); 1149 matches = m.matches(); 1150 } else { 1151 try { 1152 index = Integer.parseInt(m.group(3)); 1153 } catch (NumberFormatException ex) { 1154 ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, 1155 "Could not parse reference ("+reference+") for the jar index. " + "Expected number: "+m.group(3)); matches = false; 1158 } 1159 } 1160 if (matches) { 1161 RawReference ref = getRawReference(m.group(1), m.group(2), true); 1162 if (ref != null) { 1163 aa = ref.toRakeArtifact(ReferenceHelper.this); 1164 } 1165 } 1166 if (aa == null) { 1167 return new Object [] {null, null}; 1168 } 1169 if (index >= aa.getArtifactLocations().length) { 1170 return new Object [] {null, null}; 1172 } 1173 URI uri = aa.getArtifactLocations()[index]; 1174 return new Object [] {aa, uri}; 1175 } 1176 }); 1177 } 1178 1179 1188 @Deprecated 1189 public void destroyForeignFileReference(String reference) { 1190 destroyReference(reference); 1191 } 1192 1193 1213 public boolean destroyReference(String reference) { 1214 Matcher m = FOREIGN_FILE_REFERENCE.matcher(reference); 1215 boolean matches = m.matches(); 1216 if (!matches) { 1217 m = FOREIGN_FILE_REFERENCE_OLD.matcher(reference); 1218 matches = m.matches(); 1219 } 1220 if (matches) { 1221 String forProjName = m.group(1); 1222 String id = m.group(2); 1223 return removeReference(forProjName, id, true, reference.substring(2, reference.length()-1)); 1224 } 1225 m = FOREIGN_PLAIN_FILE_REFERENCE.matcher(reference); 1226 if (m.matches()) { 1227 return removeFileReference(reference); 1228 } 1229 return false; 1230 } 1231 1232 1238 public SubprojectProvider createSubprojectProvider() { 1239 return new SubprojectProviderImpl(this); 1240 } 1241 1242 1245 RakeProjectHelper getRakeProjectHelper() { 1246 return h; 1247 } 1248 1249 1257 public void fixReferences(File originalPath) { 1258 String [] prefixesToFix = new String [] {"file.reference.", "project."}; 1259 EditableProperties pub = h.getProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH); 1260 EditableProperties priv = h.getProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH); 1261 1262 File projectDir = FileUtil.toFile(h.getProjectDirectory()); 1263 1264 List <String > pubRemove = new ArrayList <String >(); 1265 List <String > privRemove = new ArrayList <String >(); 1266 Map <String ,String > pubAdd = new HashMap <String ,String >(); 1267 Map <String ,String > privAdd = new HashMap <String ,String >(); 1268 1269 for (Map.Entry <String ,String > e : pub.entrySet()) { 1270 String key = e.getKey(); 1271 boolean cont = false; 1272 1273 for (String prefix : prefixesToFix) { 1274 if (key.startsWith(prefix)) { 1275 cont = true; 1276 break; 1277 } 1278 } 1279 if (!cont) 1280 continue; 1281 1282 String value = e.getValue(); 1283 1284 File absolutePath = FileUtil.normalizeFile(PropertyUtils.resolveFile(originalPath, value)); 1285 1286 if (!CollocationQuery.areCollocated(absolutePath, projectDir)) { 1288 pubRemove.add(key); 1289 privAdd.put(key, absolutePath.getAbsolutePath()); 1290 } 1291 } 1292 1293 for (Map.Entry <String ,String > e : pub.entrySet()) { 1294 String key = e.getKey(); 1295 boolean cont = false; 1296 1297 for (String prefix : prefixesToFix) { 1298 if (key.startsWith(prefix)) { 1299 cont = true; 1300 break; 1301 } 1302 } 1303 if (!cont) 1304 continue; 1305 1306 String value = e.getValue(); 1307 1308 File absolutePath = FileUtil.normalizeFile(PropertyUtils.resolveFile(originalPath, value)); 1309 1310 if (absolutePath.getAbsolutePath().startsWith(originalPath.getAbsolutePath())) { 1311 String relative = PropertyUtils.relativizeFile(originalPath, absolutePath); 1313 1314 absolutePath = new File (projectDir, relative); 1315 1316 privRemove.add(key); 1317 privAdd.put(key, absolutePath.getAbsolutePath()); 1318 } 1319 1320 if (CollocationQuery.areCollocated(absolutePath, projectDir)) { 1322 pubAdd.put(key, PropertyUtils.relativizeFile(projectDir, absolutePath)); 1323 } 1324 } 1325 1326 for (String s : pubRemove) { 1327 pub.remove(s); 1328 } 1329 1330 for (String s : privRemove) { 1331 priv.remove(s); 1332 } 1333 1334 pub.putAll(pubAdd); 1335 priv.putAll(privAdd); 1336 1337 h.putProperties(RakeProjectHelper.PROJECT_PROPERTIES_PATH, pub); 1338 h.putProperties(RakeProjectHelper.PRIVATE_PROPERTIES_PATH, priv); 1339 } 1340 1341 1348 public static final class RawReference { 1349 1350 private final String foreignProjectName; 1351 private final String artifactType; 1352 private URI scriptLocation; 1353 private String newScriptLocation; 1355 private final String targetName; 1356 private final String cleanTargetName; 1357 private final String artifactID; 1358 private final Properties props; 1359 1360 1371 public RawReference(String foreignProjectName, String artifactType, URI scriptLocation, String targetName, String cleanTargetName, String artifactID) throws IllegalArgumentException { 1372 this(foreignProjectName, artifactType, scriptLocation, null, targetName, cleanTargetName, artifactID, new Properties ()); 1373 } 1374 1375 1388 public RawReference(String foreignProjectName, String artifactType, String newScriptLocation, String targetName, String cleanTargetName, String artifactID, Properties props) throws IllegalArgumentException { 1389 this(foreignProjectName, artifactType, null, newScriptLocation, targetName, cleanTargetName, artifactID, props); 1390 } 1391 1392 private RawReference(String foreignProjectName, String artifactType, URI scriptLocation, String newScriptLocation, String targetName, String cleanTargetName, String artifactID, Properties props) throws IllegalArgumentException { 1393 this.foreignProjectName = foreignProjectName; 1394 this.artifactType = artifactType; 1395 if (scriptLocation != null && scriptLocation.isAbsolute()) { 1396 throw new IllegalArgumentException ("Cannot use an absolute URI " + scriptLocation + " for script location"); } 1398 this.scriptLocation = scriptLocation; 1399 this.newScriptLocation = newScriptLocation; 1400 this.targetName = targetName; 1401 this.cleanTargetName = cleanTargetName; 1402 this.artifactID = artifactID; 1403 this.props = props; 1404 } 1405 1406 private static final List SUB_ELEMENT_NAMES = Arrays.asList(new String [] { 1407 "foreign-project", "artifact-type", "script", "target", "clean-target", "id", }); 1414 1415 1419 static RawReference create(Element xml) throws IllegalArgumentException { 1420 if (REFS_NS.equals(xml.getNamespaceURI())) { 1421 return create1(xml); 1422 } else { 1423 return create2(xml); 1424 } 1425 } 1426 1427 private static RawReference create1(Element xml) throws IllegalArgumentException { 1428 if (!REF_NAME.equals(xml.getLocalName()) || !REFS_NS.equals(xml.getNamespaceURI())) { 1429 throw new IllegalArgumentException ("bad element name: " + xml); } 1431 NodeList nl = xml.getElementsByTagNameNS("*", "*"); if (nl.getLength() != 6) { 1433 throw new IllegalArgumentException ("missing or extra data: " + xml); } 1435 String [] values = new String [nl.getLength()]; 1436 for (int i = 0; i < nl.getLength(); i++) { 1437 Element el = (Element )nl.item(i); 1438 if (!REFS_NS.equals(el.getNamespaceURI())) { 1439 throw new IllegalArgumentException ("bad subelement ns: " + el); } 1441 String elName = el.getLocalName(); 1442 int idx = SUB_ELEMENT_NAMES.indexOf(elName); 1443 if (idx == -1) { 1444 throw new IllegalArgumentException ("bad subelement name: " + elName); } 1446 String val = Util.findText(el); 1447 if (val == null) { 1448 throw new IllegalArgumentException ("empty subelement: " + el); } 1450 if (values[idx] != null) { 1451 throw new IllegalArgumentException ("duplicate " + elName + ": " + values[idx] + " and " + val); } 1453 values[idx] = val; 1454 } 1455 assert !Arrays.asList(values).contains(null); 1456 URI scriptLocation = URI.create(values[2]); return new RawReference(values[0], values[1], scriptLocation, values[3], values[4], values[5]); 1458 } 1459 1460 private static RawReference create2(Element xml) throws IllegalArgumentException { 1461 if (!REF_NAME.equals(xml.getLocalName()) || !REFS_NS2.equals(xml.getNamespaceURI())) { 1462 throw new IllegalArgumentException ("bad element name: " + xml); } 1464 List nl = Util.findSubElements(xml); 1465 if (nl.size() < 6) { 1466 throw new IllegalArgumentException ("missing or extra data: " + xml); } 1468 String [] values = new String [6]; 1469 for (int i = 0; i < 6; i++) { 1470 Element el = (Element )nl.get(i); 1471 if (!REFS_NS2.equals(el.getNamespaceURI())) { 1472 throw new IllegalArgumentException ("bad subelement ns: " + el); } 1474 String elName = el.getLocalName(); 1475 int idx = SUB_ELEMENT_NAMES.indexOf(elName); 1476 if (idx == -1) { 1477 throw new IllegalArgumentException ("bad subelement name: " + elName); } 1479 String val = Util.findText(el); 1480 if (val == null) { 1481 throw new IllegalArgumentException ("empty subelement: " + el); } 1483 if (values[idx] != null) { 1484 throw new IllegalArgumentException ("duplicate " + elName + ": " + values[idx] + " and " + val); } 1486 values[idx] = val; 1487 } 1488 Properties props = new Properties (); 1489 if (nl.size() == 7) { 1490 Element el = (Element )nl.get(6); 1491 if (!REFS_NS2.equals(el.getNamespaceURI())) { 1492 throw new IllegalArgumentException ("bad subelement ns: " + el); } 1494 if (!"properties".equals(el.getLocalName())) { throw new IllegalArgumentException ("bad subelement. expected 'properties': " + el); } 1497 for (Element el2 : Util.findSubElements(el)) { 1498 String key = el2.getAttribute("name"); 1499 String value = Util.findText(el2); 1500 if (value == null) { 1502 value = ""; } 1504 props.setProperty(key, value); 1505 } 1506 } 1507 assert !Arrays.asList(values).contains(null); 1508 return new RawReference(values[0], values[1], values[2], values[3], values[4], values[5], props); 1509 } 1510 1511 1514 Element toXml(String namespace, Document ownerDocument) { 1515 Element el = ownerDocument.createElementNS(namespace, REF_NAME); 1516 String [] values = { 1517 foreignProjectName, 1518 artifactType, 1519 newScriptLocation != null ? newScriptLocation : scriptLocation.toString(), 1520 targetName, 1521 cleanTargetName, 1522 artifactID, 1523 }; 1524 for (int i = 0; i < 6; i++) { 1525 Element subel = ownerDocument.createElementNS(namespace, (String )SUB_ELEMENT_NAMES.get(i)); 1526 subel.appendChild(ownerDocument.createTextNode(values[i])); 1527 el.appendChild(subel); 1528 } 1529 if (props.keySet().size() > 0) { 1530 assert namespace.equals(REFS_NS2) : "can happen only in /2"; Element propEls = ownerDocument.createElementNS(namespace, "properties"); el.appendChild(propEls); 1533 for (String key : new TreeSet <String >(NbCollections.checkedSetByFilter(props.keySet(), String .class, true))) { 1534 Element propEl = ownerDocument.createElementNS(namespace, "property"); propEl.appendChild(ownerDocument.createTextNode(props.getProperty(key))); 1536 propEl.setAttribute("name", key); propEls.appendChild(propEl); 1538 } 1539 } 1540 return el; 1541 } 1542 1543 private String getNS() { 1544 if (newScriptLocation != null) { 1545 return REFS_NS2; 1546 } else { 1547 return REFS_NS; 1548 } 1549 } 1550 1551 1559 public String getForeignProjectName() { 1560 return foreignProjectName; 1561 } 1562 1563 1568 public String getArtifactType() { 1569 return artifactType; 1570 } 1571 1572 1579 @Deprecated 1580 public URI getScriptLocation() { 1581 return scriptLocation; 1582 } 1583 1584 1589 public String getScriptLocationValue() { 1590 if (newScriptLocation != null) { 1591 return newScriptLocation; 1592 } else { 1593 return "${project."+foreignProjectName+"}/"+scriptLocation.toString(); 1594 } 1595 } 1596 1597 1601 public String getTargetName() { 1602 return targetName; 1603 } 1604 1605 1609 public String getCleanTargetName() { 1610 return cleanTargetName; 1611 } 1612 1613 1618 public String getID() { 1619 return artifactID; 1620 } 1621 1622 public Properties getProperties() { 1623 return props; 1624 } 1625 1626 1643 public RakeArtifact toRakeArtifact(final ReferenceHelper helper) { 1644 return ProjectManager.mutex().readAccess(new Mutex.Action<RakeArtifact>() { 1645 public RakeArtifact run() { 1646 RakeProjectHelper h = helper.h; 1647 String path = helper.eval.getProperty("project." + foreignProjectName); if (path == null) { 1649 return null; 1651 } 1652 FileObject foreignProjectDir = h.resolveFileObject(path); 1653 if (foreignProjectDir == null) { 1654 return null; 1656 } 1657 Project p; 1658 try { 1659 p = ProjectManager.getDefault().findProject(foreignProjectDir); 1660 } catch (IOException e) { 1661 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 1663 return null; 1664 } 1665 if (p == null) { 1666 return null; 1668 } 1669 return RakeArtifactQuery.findArtifactByID(p, artifactID); 1670 } 1671 }); 1672 } 1673 1674 private void upgrade() { 1675 assert newScriptLocation == null && scriptLocation != null : "was already upgraded "+this; 1676 newScriptLocation = "${project."+foreignProjectName+"}/" +scriptLocation.toString(); scriptLocation = null; 1678 } 1679 1680 public String toString() { 1681 return "ReferenceHelper.RawReference<" + foreignProjectName + "," + 1682 artifactType + "," + newScriptLocation != null ? newScriptLocation : scriptLocation + 1683 "," + targetName + "," + cleanTargetName + "," + artifactID + ">"; } 1685 1686 } 1687 1688} 1689 | Popular Tags |