Commit 4795760a authored by Peter Collingbourne's avatar Peter Collingbourne

Merge commit '37e9be01'

parents f5f62dc1 37e9be01
......@@ -100,6 +100,35 @@ not the AOT clojure compilation process emits reflection warnings:
<warnOnReflection>true</warnOnReflection>
</configuration>
The plugin can also copy source files to the output directory, filtered using the namespace mechanism
that is used to control compilation. If you want to copy all compiled source files to the output:
<configuration>
<copyAllCompiledNamespaces>true</copyAllCompiledNamespaces>
<configuration>
If you want to copy only a subset:
<configuration>
<copiedNamespaces>
<namespace>com.foo</namespace>
<namespace>!com.foo.private.*</namespace>
</copiedNamespaces>
<copyDeclaredNamespaceOnly>true</copyDeclaredNamespaceOnly>
<configuration>
If you want to do no compilation at all, but copy all source files:
<configuration>
<copyDeclaredNamespaceOnly>true</copyDeclaredNamespaceOnly>
<namespaces>
<namespace>!.*</namespace>
</namespaces>
<compileDeclaredNamespaceOnly>true</compileDeclaredNamespaceOnly>
<configuration>
Note that it will only copy clojure source files, which must a) end in .clj and b) contain a namespace declaration.
Enjoy.
## clojure:run, clojure:repl, clojure:swank and clojure:nailgun goals
......
......@@ -5,7 +5,7 @@
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>1.3.2</version>
<version>1.3.3</version>
<description>Maven plugin for compiling clojure source files</description>
<url>http://github.com/talios/clojure-maven-plugin</url>
<scm>
......@@ -41,6 +41,10 @@
<name>Jukka Zitting</name>
<email>jukka.zitting@gmail.com</email>
</contributor>
<contributor>
<name>Chas Emerick</name>
<email>cemerick@snowtide.com</email>
</contributor>
</contributors>
<licenses>
<license>
......
......@@ -12,6 +12,9 @@
package com.theoryinpractise.clojure;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.exec.*;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
......@@ -20,6 +23,8 @@ import org.apache.maven.toolchain.Toolchain;
import org.apache.maven.toolchain.ToolchainManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
......@@ -166,6 +171,28 @@ public abstract class AbstractClojureCompilerMojo extends AbstractMojo {
*/
private boolean runWithTests;
/**
* A list of namespaces whose source files will be copied to the output.
*
* @parameter
*/
protected String[] copiedNamespaces;
/**
* Should we copy the source of all namespaces or only those defined?
*
* @parameter default-value="false"
*/
protected boolean copyDeclaredNamespaceOnly;
/**
* Should the source files of all compiled namespaces be copied to the output?
* This overrides copiedNamespaces and copyDeclaredNamespaceOnly.
*
* @parameter default-value="false"
*/
private boolean copyAllCompiledNamespaces;
/**
* Should reflective invocations in Clojure source emit warnings? Corresponds with
* the *warn-on-reflection* var and the clojure.compile.warn-on-reflection system property.
......@@ -199,10 +226,17 @@ public abstract class AbstractClojureCompilerMojo extends AbstractMojo {
return files;
}
protected String[] discoverNamespaces() throws MojoExecutionException {
protected NamespaceInFile[] discoverNamespaces() throws MojoExecutionException {
return new NamespaceDiscovery(getLog(), compileDeclaredNamespaceOnly).discoverNamespacesIn(namespaces, translatePaths(sourceDirectories));
}
protected NamespaceInFile[] discoverNamespacesToCopy() throws MojoExecutionException {
if (copyAllCompiledNamespaces)
return discoverNamespaces();
else
return new NamespaceDiscovery(getLog(), copyDeclaredNamespaceOnly).discoverNamespacesIn(copiedNamespaces, translatePaths(sourceDirectories));
}
public enum SourceDirectory {
COMPILE, TEST
}
......@@ -229,6 +263,46 @@ public abstract class AbstractClojureCompilerMojo extends AbstractMojo {
return runWithTests ? testClasspathElements : classpathElements;
}
protected void copyNamespaceSourceFilesToOutput(File outputDirectory, NamespaceInFile[] discoveredNamespaces) throws MojoExecutionException {
for (NamespaceInFile ns : discoveredNamespaces) {
File outputFile = new File(outputDirectory, ns.getFilename());
outputFile.getParentFile().mkdirs();
try {
FileInputStream is = new FileInputStream(ns.getSourceFile());
try {
FileOutputStream os = new FileOutputStream(outputFile);
try {
int amountRead;
byte[] buffer = new byte[4096];
while ((amountRead = is.read(buffer)) >= 0) {
os.write(buffer, 0, amountRead);
}
is.close();
} finally {
is.close();
}
} finally {
is.close();
}
} catch (IOException ex) {
throw new MojoExecutionException("Couldn't copy the clojure source files to the output", ex);
}
}
}
protected void callClojureWith(
File[] sourceDirectory,
File outputDirectory,
List<String> compileClasspathElements,
String mainClass,
NamespaceInFile[] namespaceArgs) throws MojoExecutionException {
String[] stringArgs = new String[namespaceArgs.length];
for (int i = 0; i < namespaceArgs.length; i++) {
stringArgs[i] = namespaceArgs[i].getName();
}
callClojureWith(sourceDirectory, outputDirectory, compileClasspathElements, mainClass, stringArgs);
}
protected void callClojureWith(
File[] sourceDirectory,
File outputDirectory,
......
......@@ -26,6 +26,7 @@ public class ClojureCompilerMojo extends AbstractClojureCompilerMojo {
getSourceDirectories(SourceDirectory.COMPILE),
outputDirectory, classpathElements, "clojure.lang.Compile",
discoverNamespaces());
copyNamespaceSourceFilesToOutput(outputDirectory, discoverNamespacesToCopy());
}
}
......@@ -55,11 +55,11 @@ public class ClojureGenDocMojo extends AbstractClojureCompilerMojo {
sb.append(" \"").append(docsDir.getPath().replace('\\', '/')).append("/index.html\"\n");
sb.append(" [");
final String[] allNamespaces = new NamespaceDiscovery(getLog(), compileDeclaredNamespaceOnly)
final NamespaceInFile[] allNamespaces = new NamespaceDiscovery(getLog(), compileDeclaredNamespaceOnly)
.discoverNamespacesIn(namespaces, getSourceDirectories(SourceDirectory.COMPILE, SourceDirectory.TEST));
for (String namespace : allNamespaces) {
sb.append("'").append(namespace);
for (NamespaceInFile namespace : allNamespaces) {
sb.append("'").append(namespace.getName());
if (count++ < allNamespaces.length - 1) {
sb.append("\n ");
}
......
......@@ -16,6 +16,7 @@ import org.apache.maven.plugin.MojoExecutionException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -30,7 +31,7 @@ public class ClojureRunMojo extends AbstractClojureCompilerMojo {
/**
* The main clojure script to run
*
* @parameter
* @parameter expression="${clojure.script}"
* @required
*/
private String script;
......@@ -49,23 +50,29 @@ public class ClojureRunMojo extends AbstractClojureCompilerMojo {
*/
private String args;
public void execute() throws MojoExecutionException {
if (script == null) {
/**
* Returns either a path to a temp file that loads all of the provided scripts,
* or simply returns the singular <code>script</code> String (which therefore allows
* for @ classpath-loading paths to be passed in as a script).
*
* If multiple scripts are defined, they must all exist; otherwise an exception is thrown.
*/
private static String mergeScripts (String script, String[] scripts) throws MojoExecutionException {
if (script == null || script.trim().equals("")) {
throw new MojoExecutionException("<script> is undefined");
}
if (scripts != null && scripts.length == 0) {
if (scripts == null) {
return script;
} else if (scripts.length == 0) {
throw new MojoExecutionException("<scripts> is defined but has no <script> entries");
}
List<String> scriptFiles = new ArrayList<String>();
scriptFiles.add(script);
if (scripts != null) {
scriptFiles.addAll(Arrays.asList(scripts));
}
List<String> paths = new ArrayList<String>();
paths.add(script);
for (String scriptFile : scriptFiles) {
if (scriptFile == null || "".equals(scriptFile)) {
paths.addAll(Arrays.asList(scripts));
for (String scriptFile : paths) {
if (scriptFile == null || scriptFile.trim().equals("")) {
throw new MojoExecutionException("<script> entry cannot be empty");
}
if (!(new File(scriptFile).exists())) {
......@@ -75,22 +82,31 @@ public class ClojureRunMojo extends AbstractClojureCompilerMojo {
try {
File testFile = File.createTempFile("run", ".clj");
final PrintWriter writer = new PrintWriter(new FileWriter(testFile));
final FileWriter writer = new FileWriter(testFile);
for (String scriptFile : scriptFiles) {
writer.println("(load-file \"" + scriptFile + "\")");
for (String scriptFile : paths) {
writer.write("(load-file \"" + scriptFile + "\")");
writer.write(System.getProperty("line.separator"));
}
writer.close();
return testFile.getPath();
} catch (IOException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
public void execute() throws MojoExecutionException {
String path = mergeScripts(script, scripts);
try {
List<String> clojureArguments = new ArrayList<String>();
clojureArguments.add(testFile.getPath());
clojureArguments.add(path);
if (args != null) {
clojureArguments.addAll(Arrays.asList(args.split(" ")));
}
getLog().debug("Running clojure:run against " + testFile.getPath());
getLog().debug("Running clojure:run against " + path);
callClojureWith(
getSourceDirectories(SourceDirectory.COMPILE),
......@@ -101,6 +117,4 @@ public class ClojureRunMojo extends AbstractClojureCompilerMojo {
throw new MojoExecutionException(e.getMessage(), e);
}
}
}
......@@ -53,14 +53,14 @@ public class ClojureRunTestMojo extends AbstractClojureCompilerMojo {
// Generate test script
try {
String[] ns = new NamespaceDiscovery(getLog(), testDeclaredNamespaceOnly).discoverNamespacesIn(testNamespaces, testSourceDirectories);
NamespaceInFile[] ns = new NamespaceDiscovery(getLog(), testDeclaredNamespaceOnly).discoverNamespacesIn(testNamespaces, testSourceDirectories);
File testFile = File.createTempFile("run-test", ".clj");
final PrintWriter writer = new PrintWriter(new FileWriter(testFile));
for (String namespace : ns) {
writer.println("(require '" + namespace + ")");
for (NamespaceInFile namespace : ns) {
writer.println("(require '" + namespace.getName() + ")");
}
StringWriter testCljWriter = new StringWriter();
......@@ -68,8 +68,8 @@ public class ClojureRunTestMojo extends AbstractClojureCompilerMojo {
StringBuilder runTestLine = new StringBuilder();
runTestLine.append("(run-tests");
for (String namespace : ns) {
runTestLine.append(" '" + namespace);
for (NamespaceInFile namespace : ns) {
runTestLine.append(" '" + namespace.getName());
}
runTestLine.append(")");
......
......@@ -13,15 +13,18 @@
package com.theoryinpractise.clojure;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.IOException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* @goal swank
* @execute phase="compile"
* @requiresDependencyResolution compile
* @requiresDependencyResolution test
*/
public class ClojureSwankMojo extends AbstractClojureCompilerMojo {
......@@ -45,37 +48,21 @@ public class ClojureSwankMojo extends AbstractClojureCompilerMojo {
public void execute() throws MojoExecutionException {
File swankTempFile;
File tempFile;
try {
swankTempFile = File.createTempFile("swank", ".port");
} catch (java.io.IOException e) {
throw new MojoExecutionException("could not create SWANK port file", e);
tempFile = File.createTempFile("runswank", ".clj");
IOUtils.copy(this.getClass().getClassLoader().getResourceAsStream("runswank.clj"),new FileOutputStream(tempFile));
} catch (IOException e) {
throw new MojoExecutionException("unable to load runswank.clj into temporary file",e);
}
StringBuilder sb = new StringBuilder();
sb.append("(do ");
sb.append("(swank.swank/ignore-protocol-version \"");
sb.append(protocolVersion);
sb.append("\") ");
sb.append("(swank.swank/start-server \"");
sb.append(swankTempFile.getAbsolutePath());
sb.append("\" :port ");
sb.append(Integer.toString(port));
sb.append(" :dont-close true");
sb.append("))");
String swankLoader = sb.toString();
List<String> args = new ArrayList<String>();
if (replScript != null && new File(replScript).exists()) {
args.add("-i");
args.add(replScript);
}
args.add("-e");
args.add("(require (quote swank.swank))");
args.add("-e");
args.add(swankLoader);
args.add(tempFile.getAbsolutePath());
callClojureWith(
getSourceDirectories(SourceDirectory.TEST, SourceDirectory.COMPILE),
......
......@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
public class NamespaceDiscovery {
private final Pattern nsPattern = Pattern.compile("^\\s*\\(ns\\s.*");
private final Pattern nsPattern = Pattern.compile("^\\s*\\(ns(\\s.*|$)");
private Log log;
private boolean compileDeclaredNamespaceOnly;
......@@ -42,29 +42,29 @@ public class NamespaceDiscovery {
* @return
* @throws FileNotFoundException
*/
public String[] discoverNamespacesIn(String[] namespaceFilterRegexs, File... paths) throws MojoExecutionException {
public NamespaceInFile[] discoverNamespacesIn(String[] namespaceFilterRegexs, File... paths) throws MojoExecutionException {
if (namespaceFilterRegexs == null || namespaceFilterRegexs.length == 0) {
namespaceFilterRegexs = new String[]{".*"};
}
List<String> namespaces = new ArrayList<String>();
List<NamespaceInFile> namespaces = new ArrayList<NamespaceInFile>();
for (String namespace : discoverNamespacesInPath(paths)) {
for (NamespaceInFile namespace : discoverNamespacesInPath(paths)) {
boolean toAdd = !compileDeclaredNamespaceOnly;
for (String regex : namespaceFilterRegexs) {
if (regex.startsWith("!")) {
// exclude regex
if (Pattern.compile("^" + regex.substring(1)).matcher(namespace).matches()) {
if (Pattern.compile("^" + regex.substring(1)).matcher(namespace.getName()).matches()) {
toAdd = false;
break;
}
} else {
// include regex
if (Pattern.compile("^" + regex).matcher(namespace).matches()) {
if (Pattern.compile("^" + regex).matcher(namespace.getName()).matches()) {
toAdd = true;
}
}
......@@ -73,34 +73,36 @@ public class NamespaceDiscovery {
if (toAdd) {
namespaces.add(namespace);
} else if (log.isDebugEnabled()) {
log.debug("Filtered namespace " + namespace + " from clojure build.");
log.debug("Filtered namespace " + namespace.getName() + " from clojure build.");
}
}
return namespaces.toArray(new String[]{});
return namespaces.toArray(new NamespaceInFile[]{});
}
public List<String> discoverNamespacesInPath(File... paths) throws MojoExecutionException {
public List<NamespaceInFile> discoverNamespacesInPath(File... paths) throws MojoExecutionException {
List<String> namespaces = new ArrayList<String>();
List<NamespaceInFile> namespaces = new ArrayList<NamespaceInFile>();
for (File path : paths) {
namespaces.addAll(discoverNamespacesIn(path, path));
}
return namespaces;
}
public List<String> discoverNamespacesIn(File basePath, File scanPath) throws MojoExecutionException {
public List<NamespaceInFile> discoverNamespacesIn(File basePath, File scanPath) throws MojoExecutionException {
List<String> namespaces = new ArrayList<String>();
List<NamespaceInFile> namespaces = new ArrayList<NamespaceInFile>();
File[] files = scanPath.listFiles();
if (files != null && files.length != 0) {
for (File file : files) {
log.debug("Searching " + file.getPath() + " for clojure namespaces");
if (file.isDirectory()) {
namespaces.addAll(discoverNamespacesIn(basePath, file));
} else if (file.getName().endsWith(".clj")) {
namespaces.addAll(findNamespaceInFile(basePath, file));
if (!file.getName().startsWith(".")) {
log.debug("Searching " + file.getPath() + " for clojure namespaces");
if (file.isDirectory()) {
namespaces.addAll(discoverNamespacesIn(basePath, file));
} else if (file.getName().endsWith(".clj")) {
namespaces.addAll(findNamespaceInFile(basePath, file));
}
}
}
}
......@@ -109,10 +111,10 @@ public class NamespaceDiscovery {
return namespaces;
}
private List<String>
private List<NamespaceInFile>
findNamespaceInFile(File path, File file) throws MojoExecutionException {
List<String> namespaces = new ArrayList<String>();
List<NamespaceInFile> namespaces = new ArrayList<NamespaceInFile>();
Scanner scanner = null;
try {
......@@ -134,7 +136,7 @@ public class NamespaceDiscovery {
ns = ns.replace('_', '-');
log.debug("Found namespace " + ns + " in file " + file.getPath());
namespaces.add(ns);
namespaces.add(new NamespaceInFile(ns, file));
}
}
} catch (FileNotFoundException e) {
......
/*
* Copyright (c) Antony Blakey 2010.
*
* The use and distribution terms for this software are covered by the Eclipse Public License 1.0
* (http://opensource.org/licenses/eclipse-1.0.php) which can be found in the file epl-v10.html
* at the root of this distribution.
*
* By using this software in any fashion, you are agreeing to be bound by the terms of this license.
*
* You must not remove this notice, or any other, from this software.
*/
package com.theoryinpractise.clojure;
import java.io.File;
public class NamespaceInFile {
private String namespace;
private File sourceFile;
public NamespaceInFile(String namespace, File sourceFile) {
this.namespace = namespace;
this.sourceFile = sourceFile;
}
public String getName() {
return namespace;
}
public String getFilename() {
return namespace.replace('.', File.separatorChar).replace('-', '_') + ".clj";
}
public File getSourceFile() {
return sourceFile;
}
}
(require 'swank.swank)
(swank.swank/ignore-protocol-version "2009-09-14")
(do
(swank.swank/start-server (. (java.io.File/createTempFile "swank" ".port") getAbsolutePath) :dont-close true :port 4005))
\ No newline at end of file
......@@ -21,6 +21,7 @@ import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
......@@ -32,22 +33,23 @@ public class NamespaceDiscoveryTest {
@Test
public void testNamespaceDiscovery() throws MojoExecutionException {
NamespaceDiscovery namespaceDiscovery = new NamespaceDiscovery(mock(Log.class), true);
final NamespaceDiscovery namespaceDiscovery = new NamespaceDiscovery(mock(Log.class), true);
List<String> namespaces = namespaceDiscovery.discoverNamespacesInPath(new File("src/test/resources"));
for (String s: namespaces) {
System.out.println(s);
}
List<String> namespaces = new ArrayList<String> () {{
for (NamespaceInFile s: namespaceDiscovery.discoverNamespacesInPath(new File("src/test/resources"))) {
System.out.println(s.getName());
add(s.getName());
}
}};
assertThat(namespaces)
.isNotNull()
.isNotEmpty()
.hasSize(4)
.contains("test1")
.contains("test2")
.contains("test.test3")
.contains("nsmeta");
}
public static class NamespaceData {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment