Index: ant/freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java =================================================================== RCS file: /cvs/ant/freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java,v retrieving revision 1.12 diff -u -r1.12 FreeformSources.java --- ant/freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java 26 Sep 2007 21:14:52 -0000 1.12 +++ ant/freeform/src/org/netbeans/modules/ant/freeform/FreeformSources.java 4 Oct 2007 08:54:29 -0000 @@ -93,6 +93,8 @@ String location = Util.findText(locationE); if (folderE.getLocalName().equals("build-folder")) { // NOI18N h.addNonSourceRoot(location); + } else if (folderE.getLocalName().equals("build-file")) { + h.addOwnedFile(location); } else { assert folderE.getLocalName().equals("source-folder") : folderE; Element nameE = Util.findElement(folderE, "label", FreeformProjectType.NS_GENERAL); // NOI18N Index: ant/freeform/src/org/netbeans/modules/ant/freeform/resources/freeform-project-general-2.xsd =================================================================== RCS file: /cvs/ant/freeform/src/org/netbeans/modules/ant/freeform/resources/freeform-project-general-2.xsd,v retrieving revision 1.4 diff -u -r1.4 freeform-project-general-2.xsd --- ant/freeform/src/org/netbeans/modules/ant/freeform/resources/freeform-project-general-2.xsd 26 Sep 2007 21:14:54 -0000 1.4 +++ ant/freeform/src/org/netbeans/modules/ant/freeform/resources/freeform-project-general-2.xsd 5 Oct 2007 09:38:42 -0000 @@ -111,6 +111,7 @@ + Index: ant/project/apichanges.xml =================================================================== RCS file: /cvs/ant/project/apichanges.xml,v retrieving revision 1.20 diff -u -r1.20 apichanges.xml --- ant/project/apichanges.xml 26 Sep 2007 21:15:10 -0000 1.20 +++ ant/project/apichanges.xml 4 Oct 2007 10:04:23 -0000 @@ -104,7 +104,25 @@ - + + + + Support for adding + + + + + +

+ Added a method for registering external file that is supposed to be + owned by the project, typically used in freeform project to register + build products that are external to project dir. +

+
+ + +
+ Support for externally extending the project's build script Index: ant/project/src/org/netbeans/spi/project/support/ant/SourcesHelper.java =================================================================== RCS file: /cvs/ant/project/src/org/netbeans/spi/project/support/ant/SourcesHelper.java,v retrieving revision 1.22 diff -u -r1.22 SourcesHelper.java --- ant/project/src/org/netbeans/spi/project/support/ant/SourcesHelper.java 26 Sep 2007 21:15:32 -0000 1.22 +++ ant/project/src/org/netbeans/spi/project/support/ant/SourcesHelper.java 4 Oct 2007 10:04:36 -0000 @@ -289,6 +289,7 @@ private final PropertyEvaluator evaluator; private final List principalSourceRoots = new ArrayList(); private final List nonSourceRoots = new ArrayList(); + private final List ownedFiles = new ArrayList(); private final List typedSourceRoots = new ArrayList(); private int registeredRootAlgorithm; /** @@ -398,6 +399,29 @@ } /** + * Add any file that is supposed to be owned by a given project + * via FileOwnerQuery, affects only {@link #registerExternalRoots} + * and not {@link #createSources}. + *

+ * Useful for project type providers which have external paths holding build + * products. These should not appear in {@link Sources}, yet it may be useful + * for {@link FileOwnerQuery} to know the owning project (for example, in order + * for a project-specific SourceForBinaryQueryImplementation to work). + *

+ * @param location a project-relative or absolute path giving the location + * of a file; may contain Ant property substitutions + * @throws IllegalStateException if this method is called after + * {@link #registerExternalRoots} was called + * @since org.netbeans.modules.project.ant/1 1.17 + */ + public void addOwnedFile(String location) throws IllegalStateException { + if (lastRegisteredRoots != null) { + throw new IllegalStateException("registerExternalRoots was already called"); // NOI18N + } + ownedFiles.add(new Root(location)); + } + + /** * Add a typed source root which will be considered only in certain contexts. * @param location a project-relative or absolute path giving the location * of a source tree; may contain Ant property substitutions @@ -495,6 +519,7 @@ private void remarkExternalRoots() throws IllegalArgumentException { List allRoots = new ArrayList(principalSourceRoots); allRoots.addAll(nonSourceRoots); + allRoots.addAll(ownedFiles); Project p = getProject(); FileObject pdir = project.getProjectDirectory(); // First time: register roots and add to lastRegisteredRoots. @@ -511,22 +536,21 @@ // up calling APH.resolveFileObject repeatedly (for each property change) for (Root r : allRoots) { for (FileObject loc : r.getIncludeRoots()) { - if (!loc.isFolder()) { - continue; - } if (FileUtil.getRelativePath(pdir, loc) != null) { // Inside projdir already. Skip it. continue; } - try { - Project other = ProjectManager.getDefault().findProject(loc); - if (other != null) { - // This is a foreign project; we cannot own it. Skip it. + if (loc.isFolder()) { + try { + Project other = ProjectManager.getDefault().findProject(loc); + if (other != null) { + // This is a foreign project; we cannot own it. Skip it. + continue; + } + } catch (IOException e) { + // Assume it is a foreign project and skip it. continue; } - } catch (IOException e) { - // Assume it is a foreign project and skip it. - continue; } // It's OK to go. newRegisteredRoots.add(loc); Index: ant/project/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java =================================================================== RCS file: /cvs/ant/project/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java,v retrieving revision 1.14 diff -u -r1.14 SourcesHelperTest.java --- ant/project/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java 26 Sep 2007 21:15:41 -0000 1.14 +++ ant/project/test/unit/src/org/netbeans/spi/project/support/ant/SourcesHelperTest.java 4 Oct 2007 13:22:23 -0000 @@ -73,6 +73,8 @@ private FileObject src3dir; private FileObject src4dir; private FileObject builddir; + private FileObject extdir; + private FileObject ext2dir; private AntProjectHelper h; private Project project; private SourcesHelper sh; @@ -102,6 +104,8 @@ src4dir.createData("src4file"); builddir = scratch.createFolder("build"); builddir.createData("buildfile"); + extdir = scratch.createFolder("external"); + extdir.createData("extFile"); h = ProjectGenerator.createProject(projdir, "test"); project = ProjectManager.getDefault().findProject(projdir); assertNotNull("have a project", project); @@ -113,6 +117,7 @@ p.setProperty("src4.dir", ".."); p.setProperty("src5.dir", "../../nonesuch"); p.setProperty("build.dir", "../../build"); + p.setProperty("ext.file", "../../external/extFile"); h.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, p); ProjectManager.getDefault().saveProject(project); sh = new SourcesHelper(h, h.getStandardPropertyEvaluator()); @@ -123,6 +128,7 @@ sh.addPrincipalSourceRoot("${src4.dir}", "The Whole Shebang", null, null); // above proj dir sh.addPrincipalSourceRoot("${src5.dir}", "None such", null, null); // does not exist on disk sh.addNonSourceRoot("${build.dir}"); + sh.addOwnedFile("${ext.file}"); sh.addTypedSourceRoot("${src1.dir}", "java", "Packages #1", null, null); sh.addTypedSourceRoot("${src3.dir}", "java", "Packages #3", null, null); sh.addTypedSourceRoot("${src5.dir}", "java", "No Packages", null, null); @@ -136,6 +142,8 @@ proj2src1dir.createData("proj2src1file"); proj2src2dir = proj2dir.createFolder("src2"); proj2src2dir.createData("proj2src2file"); + ext2dir = scratch.createFolder("external2"); + FileObject ext2File = ext2dir.createData("ext2File"); h2 = ProjectGenerator.createProject(proj2dir, "test"); project2 = ProjectManager.getDefault().findProject(proj2dir); assertNotNull("have a project2", project2); @@ -143,6 +151,7 @@ sh2.addPrincipalSourceRoot("src1", "Sources #1", null, null); sh2.addPrincipalSourceRoot("src2", "Sources #2", null, null); sh2.addNonSourceRoot("build"); + sh2.addOwnedFile(FileUtil.toFile(ext2File).getAbsolutePath()); sh2.addTypedSourceRoot("src1", "java", "Packages #1", null, null); sh2.addTypedSourceRoot("src2", "java", "Packages #2", null, null); } @@ -204,6 +213,9 @@ assertEquals("src3file registered", project, FileOwnerQuery.getOwner(f)); f = builddir.getFileObject("buildfile"); assertEquals("buildfile registered", project, FileOwnerQuery.getOwner(f)); + f = extdir.getFileObject("extFile"); + assertEquals("extfile registered", project, FileOwnerQuery.getOwner(f)); + assertEquals("extdir not registered", null, FileOwnerQuery.getOwner(extdir)); f = scratch.getFileObject("otherfile"); assertEquals("otherfile not registered", null, FileOwnerQuery.getOwner(f)); // Test the simpler project type. @@ -214,6 +226,9 @@ assertEquals("proj2src1file registered", project2, FileOwnerQuery.getOwner(f)); f = proj2src2dir.getFileObject("proj2src2file"); assertEquals("proj2src2file registered", project2, FileOwnerQuery.getOwner(f)); + f = ext2dir.getFileObject("ext2File"); + assertEquals("ext2File registered", project2, FileOwnerQuery.getOwner(f)); + assertEquals("ext2dir not registered", null, FileOwnerQuery.getOwner(ext2dir)); } public void testSourceLocationChanges() throws Exception { Index: java/freeform/src/org/netbeans/modules/java/freeform/JavaProjectGenerator.java =================================================================== RCS file: /cvs/java/freeform/src/org/netbeans/modules/java/freeform/JavaProjectGenerator.java,v retrieving revision 1.13 diff -u -r1.13 JavaProjectGenerator.java --- java/freeform/src/org/netbeans/modules/java/freeform/JavaProjectGenerator.java 1 Oct 2007 14:22:19 -0000 1.13 +++ java/freeform/src/org/netbeans/modules/java/freeform/JavaProjectGenerator.java 2 Oct 2007 10:49:27 -0000 @@ -42,6 +42,7 @@ package org.netbeans.modules.java.freeform; import java.io.File; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; @@ -57,6 +58,7 @@ import org.netbeans.spi.project.support.ant.PropertyEvaluator; import org.netbeans.spi.project.support.ant.PropertyUtils; import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -74,7 +76,7 @@ private static final String[] viewElementsOrder = new String[]{"items", "context-menu"}; // NOI18N // this order is not required by schema, but follow it to minimize randomness a bit - private static final String[] folderElementsOrder = new String[]{"source-folder", "build-folder"}; // NOI18N + private static final String[] folderElementsOrder = new String[]{"source-folder", "build-folder", "build-file"}; // NOI18N private static final String[] viewItemElementsOrder = new String[]{"source-folder", "source-file"}; // NOI18N /** @@ -717,29 +719,23 @@ */ public static List guessBuildFolders(PropertyEvaluator evaluator, List javaCompilationUnits, File projectBase, File freeformBase) { - //assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess(); + List buildFolders = new ArrayList(); for (JavaCompilationUnit cu : javaCompilationUnits) { if (cu.output != null) { for (String output : cu.output) { File f = Util.resolveFile(evaluator, freeformBase, output); - if (f.exists()) { - if (f.isFile()) { - f = f.getParentFile(); - } - } else { - // guess: if name contains dot then it is probably file - if (f.getName().indexOf('.') != -1) { - f = f.getParentFile(); - } + // include only directories + if (!f.isDirectory()) { + continue; } - output = f.getAbsolutePath(); - if (!output.endsWith(File.separator)) { - output += File.separatorChar; + String absOutput = f.getAbsolutePath(); + if (!absOutput.endsWith(File.separator)) { + absOutput += File.separatorChar; } - if (output.startsWith(projectBase.getAbsolutePath()+File.separatorChar) || - output.startsWith(freeformBase.getAbsolutePath()+File.separatorChar)) { + if (absOutput.startsWith(projectBase.getAbsolutePath()+File.separatorChar) || + absOutput.startsWith(freeformBase.getAbsolutePath()+File.separatorChar)) { // ignore output which lies below project base or freeform base continue; } @@ -750,20 +746,20 @@ if (!path.endsWith(File.separator)) { path += File.separatorChar; } - if (path.equals(output)) { + if (path.equals(absOutput)) { // such a path is already there add = false; break; - } else if (output.startsWith(path)) { + } else if (absOutput.startsWith(path)) { // such a patch is already there add = false; break; - } else if (path.startsWith(output)) { + } else if (path.startsWith(absOutput)) { it.remove(); } } if (add) { - buildFolders.add(f.getAbsolutePath()); + buildFolders.add(output); } } } @@ -778,8 +774,10 @@ * @param buildFolders list of build folder locations */ public static void putBuildFolders(AntProjectHelper helper, List buildFolders) { - //assert ProjectManager.mutex().isWriteAccess(); - ArrayList list = new ArrayList(); + putBuildElement(helper, buildFolders, "build-folder"); + } + + private static void putBuildElement(AntProjectHelper helper, List buildFolders, String elemName) { Element data = Util.getPrimaryConfigurationData(helper); Document doc = data.getOwnerDocument(); Element foldersEl = Util.findElement(data, "folders", Util.NAMESPACE); // NOI18N @@ -791,7 +789,7 @@ Iterator it = folders.iterator(); while (it.hasNext()) { Element buildFolderEl = (Element)it.next(); - if (!buildFolderEl.getLocalName().equals("build-folder")) { // NOI18N + if (!buildFolderEl.getLocalName().equals(elemName)) { // NOI18N continue; } foldersEl.removeChild(buildFolderEl); @@ -800,7 +798,7 @@ Iterator it = buildFolders.iterator(); while (it.hasNext()) { String location = (String)it.next(); - Element buildFolderEl = doc.createElementNS(Util.NAMESPACE, "build-folder"); // NOI18N + Element buildFolderEl = doc.createElementNS(Util.NAMESPACE, elemName); // NOI18N Element locationEl = doc.createElementNS(Util.NAMESPACE, "location"); // NOI18N locationEl.appendChild(doc.createTextNode(location)); buildFolderEl.appendChild(locationEl); @@ -808,7 +806,51 @@ } Util.putPrimaryConfigurationData(helper, data); } - + + public static List getBuildFiles(PropertyEvaluator evaluator, + List compUnits, File projectBase, File freeformBase) { + + List buildFiles = new ArrayList(); + for (JavaCompilationUnit cu : compUnits) { + if (cu.output != null) { + for (String output : cu.output) { + File f = Util.resolveFile(evaluator, freeformBase, output); + try { + if (f.exists() && !FileUtil.isArchiveFile(f.toURL())) { + continue; + } + } catch (MalformedURLException murle) { + Exceptions.printStackTrace(murle); + } + String absOutput = f.getAbsolutePath(); + if (absOutput.startsWith(projectBase.getAbsolutePath() + File.separatorChar) || + absOutput.startsWith(freeformBase.getAbsolutePath() + File.separatorChar)) { + // ignore output which lies below project base or freeform base + continue; + } + boolean add = true; + Iterator it = buildFiles.iterator(); + while (it.hasNext()) { + String path = it.next(); + if (path.equals(absOutput)) { + // such a path is already there + add = false; + break; + } + } + if (add) { + buildFiles.add(output); + } + } + } + } + return buildFiles; + } + + public static void putBuildFiles(AntProjectHelper helper, List buildFiles) { + putBuildElement(helper, buildFiles, "build-file"); + } + // XXX: copy&pasted from FreeformProjectGenerator /** * Read target mappings from project. Index: java/freeform/src/org/netbeans/modules/java/freeform/ui/ProjectModel.java =================================================================== RCS file: /cvs/java/freeform/src/org/netbeans/modules/java/freeform/ui/ProjectModel.java,v retrieving revision 1.15 diff -u -r1.15 ProjectModel.java --- java/freeform/src/org/netbeans/modules/java/freeform/ui/ProjectModel.java 1 Oct 2007 14:22:22 -0000 1.15 +++ java/freeform/src/org/netbeans/modules/java/freeform/ui/ProjectModel.java 2 Oct 2007 10:49:28 -0000 @@ -222,6 +222,10 @@ model.javaCompilationUnitsList, model.baseFolder, model.nbProjectFolder); JavaProjectGenerator.putBuildFolders(helper, buildFolders); + List buildFiles = JavaProjectGenerator.getBuildFiles(model.getEvaluator(), + model.javaCompilationUnitsList, model.baseFolder, model.nbProjectFolder); + JavaProjectGenerator.putBuildFiles(helper, buildFiles); + return null; } }); Index: java/freeform/test/unit/src/org/netbeans/modules/java/freeform/JavaProjectGeneratorTest.java =================================================================== RCS file: /cvs/java/freeform/test/unit/src/org/netbeans/modules/java/freeform/JavaProjectGeneratorTest.java,v retrieving revision 1.13 diff -u -r1.13 JavaProjectGeneratorTest.java --- java/freeform/test/unit/src/org/netbeans/modules/java/freeform/JavaProjectGeneratorTest.java 1 Oct 2007 14:22:24 -0000 1.13 +++ java/freeform/test/unit/src/org/netbeans/modules/java/freeform/JavaProjectGeneratorTest.java 5 Oct 2007 09:37:52 -0000 @@ -1187,7 +1187,8 @@ File proj1 = new File(base, "proj1"); proj1.mkdir(); File base2 = new File(getWorkDir(), "folder2"); - + base2.mkdir(); + JavaProjectGenerator.JavaCompilationUnit cu = new JavaProjectGenerator.JavaCompilationUnit(); cu.output = new ArrayList(); cu.output.add("${outputfile}"); @@ -1200,27 +1201,11 @@ PropertyUtils.fixedPropertyProvider(m)}); List buildFolders = JavaProjectGenerator.guessBuildFolders(evaluator, units, proj1, proj1); assertEquals("no build folder", 0, buildFolders.size()); - - m.put("outputfile", "../proj1_diff/out.jar"); - evaluator = PropertyUtils.sequentialPropertyEvaluator(null, new PropertyProvider[]{ - PropertyUtils.fixedPropertyProvider(m)}); - buildFolders = JavaProjectGenerator.guessBuildFolders(evaluator, units, proj1, proj1); - assertEquals("one build-folder created", 1, buildFolders.size()); - assertEquals("export is properly configured", base.getAbsolutePath()+File.separator+"proj1_diff", buildFolders.get(0)); - - m.put("outputfile", "../out.jar"); - evaluator = PropertyUtils.sequentialPropertyEvaluator(null, new PropertyProvider[]{ - PropertyUtils.fixedPropertyProvider(m)}); - buildFolders = JavaProjectGenerator.guessBuildFolders(evaluator, units, proj1, proj1); - assertEquals("one build-folder created", 1, buildFolders.size()); - assertEquals("export is properly configured", base.getAbsolutePath(), buildFolders.get(0)); - + cu.output.add(base2.getAbsolutePath()); - cu.output.add("other.jar"); buildFolders = JavaProjectGenerator.guessBuildFolders(evaluator, units, proj1, proj1); - assertEquals("two build-folder created", 2, buildFolders.size()); - assertEquals("export is properly configured", base.getAbsolutePath(), buildFolders.get(0)); - assertEquals("export is properly configured", base2.getAbsolutePath(), buildFolders.get(1)); + assertEquals("one build-folder created", 1, buildFolders.size()); + assertEquals("export is properly configured", base2.getAbsolutePath(), buildFolders.get(0)); cu.output.add(getWorkDir().getAbsolutePath()); buildFolders = JavaProjectGenerator.guessBuildFolders(evaluator, units, proj1, proj1); @@ -1295,7 +1280,62 @@ validate(p); } - + + public void testPutBuildFiles() throws Exception { + AntProjectHelper helper = createEmptyProject("proj", "proj", false); + FileObject base = helper.getProjectDirectory(); + Project p = ProjectManager.getDefault().findProject(base); + assertNotNull("Project was not created", p); + assertEquals("Project folder is incorrect", base, p.getProjectDirectory()); + + List buildFiles = new ArrayList(); + buildFiles.add("/some/path/projA/archive.jar"); + buildFiles.add("C:\\dev\\projB\\library.jar"); + + JavaProjectGenerator.putBuildFiles(helper, buildFiles); + Element el = Util.getPrimaryConfigurationData(helper); + Element foldersEl = Util.findElement(el, "folders", Util.NAMESPACE); + assertNotNull(" element exists", foldersEl); + List subElements = Util.findSubElements(foldersEl); + assertEquals("project has two build-files", 2, subElements.size()); + Element el2 = (Element)subElements.get(0); + assertElement(el2, "build-file", null); + assertEquals("build-file has one subelement", 1, Util.findSubElements(el2).size()); + assertElement((Element)Util.findSubElements(el2).get(0), "location", "/some/path/projA/archive.jar"); + el2 = (Element)subElements.get(1); + assertElement(el2, "build-file", null); + assertEquals("build-file has one subelement", 1, Util.findSubElements(el2).size()); + assertElement((Element)Util.findSubElements(el2).get(0), "location", "C:\\dev\\projB\\library.jar"); + + // validate against schema: + ProjectManager.getDefault().saveAllProjects(); + validate(p); + + // now test updating + buildFiles = new ArrayList(); + buildFiles.add("/projC/dist/projC.jar"); + JavaProjectGenerator.putBuildFiles(helper, buildFiles); + el = Util.getPrimaryConfigurationData(helper); + foldersEl = Util.findElement(el, "folders", Util.NAMESPACE); + subElements = Util.findSubElements(foldersEl); + assertEquals("project has one build-file", 1, subElements.size()); + el2 = (Element)subElements.get(0); + assertElement(el2, "build-file", null); + assertEquals("build-file has one subelement", 1, Util.findSubElements(el2).size()); + assertElement((Element)Util.findSubElements(el2).get(0), "location", "/projC/dist/projC.jar"); + + buildFiles = new ArrayList(); + JavaProjectGenerator.putBuildFiles(helper, buildFiles); + el = Util.getPrimaryConfigurationData(helper); + foldersEl = Util.findElement(el, "folders", Util.NAMESPACE); + subElements = Util.findSubElements(foldersEl); + assertEquals("project has no build-file", 0, subElements.size()); + + // validate against schema: + ProjectManager.getDefault().saveAllProjects(); + validate(p); + } + private static class Listener implements ChangeListener { int count = 0; public void stateChanged(ChangeEvent ev) {