diff --git a/jps/jps.iml b/jps/jps.iml
index 130e80c5a3cb..265f640e5646 100644
--- a/jps/jps.iml
+++ b/jps/jps.iml
@@ -4,6 +4,7 @@
+
@@ -12,6 +13,7 @@
+
diff --git a/jps/src/jps.gdsl b/jps/src/jps.gdsl
index fceda7ebd7ce..849e4ae42792 100644
--- a/jps/src/jps.gdsl
+++ b/jps/src/jps.gdsl
@@ -3,6 +3,7 @@ def ctx = context(scope: scriptScope(), filetypes : ["gant"])
contributor ([ctx], {
property name:"project", type:"org.jetbrains.jps.Project"
method name:"jdk", type:"org.jetbrains.jps.JavaSdk", params:[name:"String", jdkPath:"String"]
+ method name:"jdk", type:"org.jetbrains.jps.JavaSdk", params:[name:"String", jdkPath:"String", initializer:{}]
method name:"globalLibrary", type:"org.jetbrains.jps.Library", params: [name:"String", initializer:{}]
method name:"library", type:"org.jetbrains.jps.Library", params: [name:"String", initializer:{}]
})
diff --git a/jps/src/org/jetbrains/jps/Jps.groovy b/jps/src/org/jetbrains/jps/Jps.groovy
index ffd4440039f5..dd9fbed29e6e 100644
--- a/jps/src/org/jetbrains/jps/Jps.groovy
+++ b/jps/src/org/jetbrains/jps/Jps.groovy
@@ -22,9 +22,12 @@ final class Jps {
return project.createGlobalLibrary(name, initializer)
})
- binding.setVariable("jdk", {String name, String path ->
- //todo[nik] support initializer parameter
- return project.createJavaSdk(name, path, {})
+ binding.setVariable("jdk", {Object[] args ->
+ if (!(args.length in [2,3])) {
+ project.error("expected 2 to 3 parameters for jdk() but ${args.length} found")
+ }
+ Closure initializer = args.length > 2 ? args[2] : {}
+ return project.createJavaSdk((String)args[0], (String)args[1], initializer)
})
binding.setVariable("moduleTests", {String name ->
diff --git a/jps/src/org/jetbrains/jps/ProjectBuilder.groovy b/jps/src/org/jetbrains/jps/ProjectBuilder.groovy
index 190264fc4b46..f2b29a220661 100644
--- a/jps/src/org/jetbrains/jps/ProjectBuilder.groovy
+++ b/jps/src/org/jetbrains/jps/ProjectBuilder.groovy
@@ -80,7 +80,7 @@ class ProjectBuilder {
if (currentOutput != null) return currentOutput
project.stage("Making module ${chunk.name}")
- def dst = folderForChunkOutput(chunk, classesDir(binding.project), false)
+ def dst = folderForChunkOutput(chunk, classesDir(project), false)
outputs[chunk] = dst
compile(chunk, dst, false)
diff --git a/jps/src/org/jetbrains/jps/artifacts/CompositeLayoutElement.groovy b/jps/src/org/jetbrains/jps/artifacts/CompositeLayoutElement.groovy
index fa4a4aa4770d..e0a6099fcf38 100644
--- a/jps/src/org/jetbrains/jps/artifacts/CompositeLayoutElement.groovy
+++ b/jps/src/org/jetbrains/jps/artifacts/CompositeLayoutElement.groovy
@@ -59,8 +59,15 @@ class ArchiveElement extends CompositeLayoutElement {
}
def build(Project project) {
- project.binding.jar.call([name, {
- buildChildren(project)
- }].toArray())
+ if (name.endsWith(".jar")) {
+ project.binding.ant.jar(name: name, filesetmanifest: "mergewithoutmain", duplicate: "preserve", {
+ buildChildren(project)
+ })
+ }
+ else {
+ project.binding.ant.zip(name: name, duplicate: "preserve", {
+ buildChildren(project)
+ })
+ }
}
}
diff --git a/jps/testData/iprProject/data/f.txt b/jps/testData/iprProject/data/f.txt
new file mode 100644
index 000000000000..4d1ae35ba2c8
--- /dev/null
+++ b/jps/testData/iprProject/data/f.txt
@@ -0,0 +1 @@
+f
\ No newline at end of file
diff --git a/jps/testData/iprProject/iprProject.iml b/jps/testData/iprProject/iprProject.iml
new file mode 100644
index 000000000000..dbf84a250f51
--- /dev/null
+++ b/jps/testData/iprProject/iprProject.iml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jps/testData/iprProject/iprProject.ipr b/jps/testData/iprProject/iprProject.ipr
new file mode 100644
index 000000000000..341eae6831cd
--- /dev/null
+++ b/jps/testData/iprProject/iprProject.ipr
@@ -0,0 +1,59 @@
+
+
+
+
+ $PROJECT_DIR$/out/artifacts/explodedWar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $PROJECT_DIR$/out/artifacts/archive
+
+
+
+
+
+
+
+
+
+
+ $PROJECT_DIR$/out/artifacts/files
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jps/testData/iprProject/lib/jdom.jar b/jps/testData/iprProject/lib/jdom.jar
new file mode 100644
index 000000000000..cea6f991b142
Binary files /dev/null and b/jps/testData/iprProject/lib/jdom.jar differ
diff --git a/jps/testData/iprProject/lib/junit.jar b/jps/testData/iprProject/lib/junit.jar
new file mode 100644
index 000000000000..cea6f991b142
Binary files /dev/null and b/jps/testData/iprProject/lib/junit.jar differ
diff --git a/jps/testData/iprProject/src/xxx/MyClass.java b/jps/testData/iprProject/src/xxx/MyClass.java
new file mode 100644
index 000000000000..faece7006c68
--- /dev/null
+++ b/jps/testData/iprProject/src/xxx/MyClass.java
@@ -0,0 +1,4 @@
+package xxx;
+
+public class MyClass {
+}
diff --git a/jps/testData/iprProject/web/WEB-INF/web.xml b/jps/testData/iprProject/web/WEB-INF/web.xml
new file mode 100644
index 000000000000..1369345e012a
--- /dev/null
+++ b/jps/testData/iprProject/web/WEB-INF/web.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/jps/testData/iprProject/web/index.jsp b/jps/testData/iprProject/web/index.jsp
new file mode 100644
index 000000000000..3bbf870a870b
--- /dev/null
+++ b/jps/testData/iprProject/web/index.jsp
@@ -0,0 +1,5 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+
+
Simple jsp page
+ Place your content here
+
\ No newline at end of file
diff --git a/jps/testSrc/org/jetbrains/jps/BuildFromIprTest.groovy b/jps/testSrc/org/jetbrains/jps/BuildFromIprTest.groovy
new file mode 100644
index 000000000000..1dd73a8b9522
--- /dev/null
+++ b/jps/testSrc/org/jetbrains/jps/BuildFromIprTest.groovy
@@ -0,0 +1,66 @@
+package org.jetbrains.jps
+
+/**
+ * @author nik
+ */
+class BuildFromIprTest extends JpsBuildTestCase {
+
+ public void testBuild() {
+ def globalLib = {Project project ->
+ project.createGlobalLibrary("jdom") {
+ classpath "testData/iprProject/lib/jdom.jar"
+ }
+ }
+ doTest("testData/iprProject/iprProject.ipr", globalLib) {
+ dir("artifacts") {
+ dir("archive") {
+ archive("archive.jar") {
+ dir("files") {
+ dir("dir") {
+ file("f.txt", "f")
+ }
+ file("f.txt", "f")
+ file("g.txt", "f")
+ }
+ archive("sources.zip") {
+ dir("xxx") {
+ file("MyClass.java")
+ }
+ }
+ dir("META-INF") { file("MANIFEST.MF") }
+ }
+ }
+ dir("files") {
+ dir("dir") {
+ file("f.txt", "f")
+ }
+ file("f.txt", "f")
+ file("g.txt", "f")
+ }
+ dir("explodedWar") {
+ dir("WEB-INF") {
+ dir("classes") {
+ dir("xxx") {
+ file("MyClass.class")
+ }
+ }
+ dir("lib") {
+ file("jdom.jar")
+ file("junit.jar")
+ }
+ file("web.xml")
+ }
+ file("index.jsp")
+ }
+ }
+ dir("production") {
+ dir("iprProject") {
+ dir("xxx") {
+ file("MyClass.class")
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/jps/testSrc/org/jetbrains/jps/FileSystemItem.groovy b/jps/testSrc/org/jetbrains/jps/FileSystemItem.groovy
new file mode 100644
index 000000000000..77e814f25164
--- /dev/null
+++ b/jps/testSrc/org/jetbrains/jps/FileSystemItem.groovy
@@ -0,0 +1,49 @@
+package org.jetbrains.jps
+
+import junit.framework.Assert
+
+/**
+ * @author nik
+ */
+class FileSystemItem {
+ boolean directory = false
+ boolean archive = false
+ String name
+ String content = null
+ private final Map children = [:]
+
+ FileSystemItem leftShift(FileSystemItem item) {
+ assert !children.containsKey(item.getName()) : "${item.name} already added"
+ children[item.name] = item
+ return this
+ }
+
+ def assertDirectoryEqual(File file, String relativePath) throws IOException {
+ Set notFound = new HashSet(children.keySet());
+ file.listFiles()?.each {File child ->
+ final def name = child.name
+ final def item = children[name]
+ Assert.assertNotNull("unexpected file: $relativePath$name", item)
+ item.assertFileEqual(child, relativePath + name + "/")
+ notFound.remove(name)
+ }
+ Assert.assertTrue("files $notFound not found in $relativePath", notFound.isEmpty());
+ }
+
+ def assertFileEqual(File file, String relativePath) throws IOException {
+ Assert.assertEquals("in $relativePath", name, file.name);
+ if (archive) {
+ final File dirForExtracted = FileUtil.createTempDirectory("extracted_archive");
+ ZipUtil.extract(file, dirForExtracted, null);
+ assertDirectoryEqual(dirForExtracted, relativePath);
+ }
+ else if (directory) {
+ Assert.assertTrue("$relativePath${file.name} is not a directory", file.isDirectory());
+ assertDirectoryEqual(file, relativePath);
+ }
+ else if (content != null) {
+ final String content = new String(FileUtil.loadFileText(file));
+ Assert.assertEquals("content mismatch for " + relativePath, content, content);
+ }
+ }
+}
diff --git a/jps/testSrc/org/jetbrains/jps/FileUtil.groovy b/jps/testSrc/org/jetbrains/jps/FileUtil.groovy
new file mode 100644
index 000000000000..951ad316100c
--- /dev/null
+++ b/jps/testSrc/org/jetbrains/jps/FileUtil.groovy
@@ -0,0 +1,132 @@
+package org.jetbrains.jps
+
+/**
+ * @author nik
+ */
+class FileUtil {
+ static String loadFileText(File file) throws IOException{
+ InputStream stream = new FileInputStream(file);
+ Reader reader = new InputStreamReader(stream);
+ try{
+ return new String(loadText(reader, (int)file.length()));
+ }
+ finally{
+ reader.close();
+ }
+ }
+
+ static char[] loadText(Reader reader, int length) throws IOException {
+ char[] chars = new char[length];
+ int count = 0;
+ while (count < chars.length) {
+ int n = reader.read(chars, count, chars.length - count);
+ if (n <= 0) break;
+ count += n;
+ }
+ if (count == chars.length){
+ return chars;
+ }
+ else{
+ char[] newChars = new char[count];
+ System.arraycopy(chars, 0, newChars, 0, count);
+ return newChars;
+ }
+ }
+
+ static boolean createParentDirs(File file) {
+ if (!file.exists()) {
+ String parentDirPath = file.getParent()
+ if (parentDirPath != null) {
+ final File parentFile = new File(parentDirPath)
+ return parentFile.exists() && parentFile.isDirectory() || parentFile.mkdirs()
+ }
+ }
+ return false
+ }
+
+ static boolean delete(File file){
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File file1 : files) {
+ if (!delete(file1)) return false;
+ }
+ }
+
+ for (int i = 0; i < 10; i++){
+ if (file.delete() || !file.exists()) return true;
+ try {
+ Thread.sleep(10);
+ }
+ catch (InterruptedException ignored) {
+
+ }
+ }
+ return false;
+ }
+
+ static def compareFiles(File file1, File file2, String relativePath) {
+ def name = file1.name
+ if (name.endsWith(".jar") || name.endsWith(".war") || name.endsWith(".zip")) {
+ def dir1 = ZipUtil.extractToTempDir(file1)
+ def dir2 = ZipUtil.extractToTempDir(file1)
+ compareDirectories(dir1, dir2, relativePath)
+ delete(dir1)
+ delete(dir2)
+ }
+ else {
+ def len1 = file1.length()
+ def len2 = file2.length()
+ if (len1 != len2) {
+ System.out.println("file length mismatch for $relativePath: #1.len=$len1, #2.len=$len2");
+ }
+ }
+ }
+
+ static def compareDirectories(File dir1, File dir2) {
+ if (!dir1.exists()) {
+ System.out.println("${dir1.absolutePath} doesn't exist");
+ return
+ }
+ if (!dir2.exists()) {
+ System.out.println("${dir2.absolutePath} doesn't exist");
+ return
+ }
+ System.out.println("Comparing ${dir1.absolutePath}(#1) and ${dir2.absolutePath}(#2)");
+ compareDirectories(dir1, dir2, "")
+ }
+
+ private static def compareDirectories(File dir1, File dir2, String relativePath) {
+// System.out.print(".");
+ Set dir2Files = dir2.listFiles()*.name as Set
+
+ dir1.listFiles().each {File child1 ->
+ File child2 = new File(dir2, child1.name)
+ if (!child2.exists()) {
+ System.out.println("#1: $relativePath/${child1.name}");
+ }
+ else {
+ if (child1.isFile() && child2.isFile()) {
+ compareFiles(child1, child2, relativePath + "/" + child1.name)
+ }
+ else if (child1.isDirectory() && child2.isDirectory()) {
+ compareDirectories(child1, child2, relativePath + "/" + child1.name)
+ }
+ else {
+ System.out.println("type mismatch for $relativePath: #1 is ${child1.isDirectory() ? "dir" : "file"}, #2 is ${child2.isDirectory() ? "dir" : "file"}");
+ }
+ }
+
+ dir2Files.remove(child1.name)
+ }
+ dir2Files.each {
+ System.out.println("#2: ${dir2.absolutePath}/$it");
+ }
+ }
+
+ static File createTempDirectory(String prefix) {
+ def output = File.createTempFile(prefix, "tmp")
+ output.delete()
+ output.mkdirs()
+ return output
+ }
+}
diff --git a/jps/testSrc/org/jetbrains/jps/JpsBuildTestCase.groovy b/jps/testSrc/org/jetbrains/jps/JpsBuildTestCase.groovy
new file mode 100644
index 000000000000..1695195745eb
--- /dev/null
+++ b/jps/testSrc/org/jetbrains/jps/JpsBuildTestCase.groovy
@@ -0,0 +1,50 @@
+package org.jetbrains.jps
+
+import junit.framework.TestCase
+import org.codehaus.gant.GantBinding
+import org.jetbrains.jps.idea.IdeaProjectLoader;
+
+/**
+ * @author nik
+ */
+class JpsBuildTestCase extends TestCase {
+
+ def doTest(String projectPath, Closure initProject, Closure expectedOutput) {
+ def binding = new GantBinding()
+ binding.includeTool << Jps
+ def project = new Project(binding)
+ new IdeaProjectLoader().loadFromPath(project, projectPath)
+ initProject(project)
+ def target = FileUtil.createTempDirectory("targetDir")
+ project.targetFolder = target.absolutePath
+ project.clean()
+ project.makeAll()
+ project.buildArtifacts()
+
+ def root = new FileSystemItem(name: "")
+ initFileSystemItem(root, expectedOutput)
+ root.assertDirectoryEqual(target, "");
+ }
+
+ def initFileSystemItem(FileSystemItem item, Closure initializer) {
+ def meta = new InitializingExpando()
+ meta.dir = {String name, Closure content ->
+ def dir = new FileSystemItem(name: name, directory: true)
+ initFileSystemItem(dir, content)
+ item << dir
+ }
+ meta.archive = {String name, Closure content ->
+ def archive = new FileSystemItem(name: name, archive: true)
+ initFileSystemItem(archive, content)
+ item << archive
+ }
+ meta.file = {Object[] args ->
+ item << new FileSystemItem(name: args[0], content: args.length > 1 ? args[1] : null)
+ }
+
+ initializer.delegate = meta
+ initializer.setResolveStrategy Closure.DELEGATE_FIRST
+ initializer()
+ }
+
+}
diff --git a/jps/testSrc/org/jetbrains/jps/ZipUtil.groovy b/jps/testSrc/org/jetbrains/jps/ZipUtil.groovy
new file mode 100644
index 000000000000..ddbf5c10b22e
--- /dev/null
+++ b/jps/testSrc/org/jetbrains/jps/ZipUtil.groovy
@@ -0,0 +1,57 @@
+package org.jetbrains.jps
+
+import java.util.zip.ZipEntry
+import java.util.zip.ZipFile
+
+/**
+ * @author nik
+ */
+class ZipUtil {
+ static File extractToTempDir(File file) throws IOException {
+ File output = FileUtil.createTempDirectory("extracted")
+ extract(file, output, null)
+ return output
+ }
+
+ static def extract(final File file, File outputDir, FilenameFilter filenameFilter) throws IOException {
+ ZipFile zipFile = new ZipFile(file)
+ try {
+ final Enumeration entries = zipFile.entries()
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = (ZipEntry) entries.nextElement()
+ final File entryFile = new File(outputDir, entry.getName())
+ if (filenameFilter == null || filenameFilter.accept(entryFile.getParentFile(), entryFile.getName())) {
+ extractEntry(entry, zipFile.getInputStream(entry), outputDir)
+ }
+ }
+ }
+ finally {
+ zipFile.close();
+ }
+ }
+
+ static def extractEntry(ZipEntry entry, final InputStream inputStream, File outputDir) throws IOException {
+ final boolean isDirectory = entry.isDirectory()
+ final String relativeName = entry.getName()
+ final File file = new File(outputDir, relativeName)
+ FileUtil.createParentDirs(file)
+ if (isDirectory) {
+ file.mkdir()
+ }
+ else {
+ final BufferedInputStream input = new BufferedInputStream(inputStream)
+ final BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file))
+ try {
+ final byte[] buffer = new byte[1024*20]
+ int len
+ while ((len = input.read(buffer)) >= 0) {
+ output.write(buffer, 0, len)
+ }
+ }
+ finally {
+ output.close()
+ input.close()
+ }
+ }
+ }
+}