diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c339b3e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.classpath +.project +target +.settings diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8e9ef6c --- /dev/null +++ b/pom.xml @@ -0,0 +1,68 @@ + + 4.0.0 + org.fitnesse.plugins + maven-classpath-plugin + Maven Classpath Plugin + 1.0-SNAPSHOT + + + org.apache.maven + maven-embedder + 3.0-alpha-2 + compile + + + org.fitnesse + fitnesse + 20090818 + + + junit + junit + 4.6 + test + + + + + neuri + http://maven.neuri.com/ + + true + + + false + + + + + + + maven-assembly-plugin + 2.2-beta-4 + + + jar-with-dependencies + + + + + make-jar + package + + single + + + + + + maven-compiler-plugin + + 1.5 + 1.5 + + + + + diff --git a/src/main/java/fitnesse/wikitext/widgets/MavenClasspathWidget.java b/src/main/java/fitnesse/wikitext/widgets/MavenClasspathWidget.java new file mode 100644 index 0000000..b080297 --- /dev/null +++ b/src/main/java/fitnesse/wikitext/widgets/MavenClasspathWidget.java @@ -0,0 +1,142 @@ +package fitnesse.wikitext.widgets; + +import static org.apache.maven.embedder.MavenEmbedder.validateConfiguration; + +import java.io.File; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.maven.artifact.DependencyResolutionRequiredException; +import org.apache.maven.embedder.Configuration; +import org.apache.maven.embedder.ConfigurationValidationResult; +import org.apache.maven.embedder.DefaultConfiguration; +import org.apache.maven.embedder.MavenEmbedder; +import org.apache.maven.embedder.MavenEmbedderConsoleLogger; +import org.apache.maven.embedder.MavenEmbedderException; +import org.apache.maven.execution.DefaultMavenExecutionRequest; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.execution.MavenExecutionResult; + +import fitnesse.html.HtmlUtil; +import fitnesse.wiki.PageData; + +public class MavenClasspathWidget extends ParentWidget implements WidgetWithTextArgument { + + static { + PageData.classpathWidgetBuilder.addWidgetClass(MavenClasspathWidget.class); + } + + private String pomFile; + public static final String REGEXP = "^!pomFile [^\r\n]*"; + private static final Pattern pattern = Pattern.compile("^!pomFile (.*)"); + + public MavenClasspathWidget(ParentWidget parent, String text) { + super(parent); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) { + this.pomFile = matcher.group(1); + ensurePomFileExists(); + } else { + throw new IllegalArgumentException("no pom file specified."); + } + } + + private void ensurePomFileExists() { + if(!new File(pomFile).exists()) { + throw new IllegalArgumentException(pomFile + " does not exist"); + } + } + + @Override + public String asWikiText() throws Exception { + return "!pomFile " + pomFile; + } + + public String getText() throws Exception { + List classpathElements = getMavenClasspath(); + return createClasspath(classpathElements); + } + + private List getMavenClasspath() throws MavenEmbedderException, + DependencyResolutionRequiredException { + Configuration configuration = mavenConfiguration(); + ensureMavenConfigurationIsValid(configuration); + MavenExecutionRequest request = createExecutionRequest(projectRootDirectory()); + List classpathElements = getClasspathElements(configuration, request); + return classpathElements; + } + + @Override + public String render() throws Exception { + List classpathElements = getMavenClasspath(); + + String classpathForRender = ""; + for (String element : classpathElements) { + classpathForRender += HtmlUtil.metaText("classpath: " + element) + HtmlUtil.BRtag; + + } + return classpathForRender; + + } + + private void ensureMavenConfigurationIsValid(Configuration configuration) { + ConfigurationValidationResult validationResult = validateConfiguration(configuration); + if (!validationResult.isValid()) { + throw new IllegalStateException("Unable to create valid Maven Configuration."); + } + } + + private String createClasspath(List classpathElements) { + String classpath = ""; + for (String element : classpathElements) { + classpath += element + File.pathSeparator; + } + return removeTrailingPathSeparator(classpath); + } + + private String removeTrailingPathSeparator(String classpath) { + return classpath.substring(0, classpath.length() - 1); + } + + private List getClasspathElements(Configuration configuration, MavenExecutionRequest request) + throws MavenEmbedderException, DependencyResolutionRequiredException { + MavenEmbedder embedder = new MavenEmbedder(configuration); + MavenExecutionResult executionResult = embedder.readProjectWithDependencies(request); + List classpathElements = executionResult.getProject().getCompileClasspathElements(); + return classpathElements; + } + + private File projectRootDirectory() { + String root = pomFile.substring(0, pomFile.lastIndexOf("/")); + File projectDirectory = new File(root); + return projectDirectory; + } + + private MavenExecutionRequest createExecutionRequest(File projectDirectory) { + MavenExecutionRequest request = new DefaultMavenExecutionRequest().setBaseDirectory(projectDirectory).setPomFile( + pomFile); + return request; + } + + private Configuration mavenConfiguration() { + Configuration configuration = new DefaultConfiguration().setClassLoader(Thread.currentThread() + .getContextClassLoader()).setMavenEmbedderLogger(new MavenEmbedderConsoleLogger()); + if(hasNonDefaultLocalRepository()) { + configuration.setLocalRepository(getLocalRepository()); + } + return configuration; + } + + private boolean hasNonDefaultLocalRepository() { + return getLocalRepository() != null; + } + /* + * can be overridden for test purposes. + */ + protected File getLocalRepository() { + return null; + } + + +} diff --git a/src/test/java/fitnesse/wikitext/widgets/MavenClasspathWidgetTest.java b/src/test/java/fitnesse/wikitext/widgets/MavenClasspathWidgetTest.java new file mode 100644 index 0000000..8a6ebe9 --- /dev/null +++ b/src/test/java/fitnesse/wikitext/widgets/MavenClasspathWidgetTest.java @@ -0,0 +1,92 @@ +package fitnesse.wikitext.widgets; + +import static fitnesse.html.HtmlUtil.BRtag; +import static fitnesse.html.HtmlUtil.metaText; + +import java.io.File; + +import org.codehaus.plexus.util.FileUtils; + +import fitnesse.wiki.PageData; + +public class MavenClasspathWidgetTest extends WidgetTestCase { + private static final String TEST_PROJECT_ROOT = new File("src/test/resources/MavenClasspathWidget").getAbsolutePath(); + private final static String TEST_POM_FILE = "src/test/resources/MavenClasspathWidget/pom.xml"; + private File mavenLocalRepo = new File(System.getProperty("java.io.tmpdir"), "MavenClasspathWidgetTest/m2/repo"); + private String path = mavenLocalRepo.getAbsolutePath(); + + private MavenClasspathWidget widget; + @Override + protected void setUp() throws Exception { + super.setUp(); + widget = new MavenClasspathWidget(new MockWidgetRoot(), "!pomFile " + TEST_POM_FILE) { + @Override + protected File getLocalRepository() { + return mavenLocalRepo; + } + }; + mavenLocalRepo.mkdirs(); + FileUtils.copyDirectoryStructure(new File(TEST_PROJECT_ROOT, "repository"), mavenLocalRepo); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + FileUtils.deleteDirectory(mavenLocalRepo); + } + + @Override + protected String getRegexp() { + return MavenClasspathWidget.REGEXP; + } + + + public void testThatMavenClasspathWidgetIsAddedToTheClasspathWidgetBuilder() throws Exception { + assertEquals(MavenClasspathWidget.class, PageData.classpathWidgetBuilder.findWidgetClassMatching("!pomFile pom.xml")); + } + + public void testRegexp() throws Exception { + assertMatchEquals("!pomFile pom.xml", "!pomFile pom.xml"); + } + + public void testAsWikiText() throws Exception { + assertEquals("!pomFile " + TEST_POM_FILE, widget.asWikiText()); + } + + public void testRender() throws Exception { + String actual = widget.render(); + String expected = metaText("classpath: " + TEST_PROJECT_ROOT + "/target/classes") + BRtag + + metaText(classpathElementForRender("/fitnesse/fitnesse-dep/1.0/fitnesse-dep-1.0.jar")) + BRtag + + metaText(classpathElementForRender("/fitnesse/fitnesse-subdep/1.0/fitnesse-subdep-1.0.jar")) + BRtag; + assertEquals(expected, actual); + } + + public void testGetText() throws Exception { + String actual = widget.getText(); + String expected = TEST_PROJECT_ROOT + "/target/classes" + + classpathElementForText("/fitnesse/fitnesse-dep/1.0/fitnesse-dep-1.0.jar") + + classpathElementForText("/fitnesse/fitnesse-subdep/1.0/fitnesse-subdep-1.0.jar"); + assertEquals(expected, actual); + } + + public void testFailFastWhenPomFileDoesNotExist() throws Exception { + try { + new MavenClasspathWidget(new MockWidgetRoot(), "!pomFile /non/existing/pom.xml"); + fail("should have thrown IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + } + + public void testFailFastWhenPomFileIsNotSpecified() throws Exception { + try { + new MavenClasspathWidget(new MockWidgetRoot(), "!pomFile"); + fail("should have thrown IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + } + + private String classpathElementForRender(String file) { + return "classpath: " + path + file; + } + private String classpathElementForText(String file) { + return File.pathSeparator + path + file; + } +} diff --git a/src/test/resources/MavenClasspathWidget/pom.xml b/src/test/resources/MavenClasspathWidget/pom.xml new file mode 100644 index 0000000..4ea9c7b --- /dev/null +++ b/src/test/resources/MavenClasspathWidget/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + fitnesse + fitnesse-maven-widget + 1.0 + + + fitnesse + fitnesse-dep + 1.0 + + + + + local + file://./test-resources/MavenClasspathWidget/repository + + true + + + false + + + + diff --git a/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-dep/1.0/fitnesse-dep-1.0.jar b/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-dep/1.0/fitnesse-dep-1.0.jar new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-dep/1.0/fitnesse-dep-1.0.pom b/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-dep/1.0/fitnesse-dep-1.0.pom new file mode 100644 index 0000000..ef26a6a --- /dev/null +++ b/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-dep/1.0/fitnesse-dep-1.0.pom @@ -0,0 +1,14 @@ + + 4.0.0 + fitnesse + fitnesse-dep + 1.0 + + + fitnesse + fitnesse-subdep + 1.0 + + + diff --git a/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-subdep/1.0/fitnesse-subdep-1.0.jar b/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-subdep/1.0/fitnesse-subdep-1.0.jar new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-subdep/1.0/fitnesse-subdep-1.0.pom b/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-subdep/1.0/fitnesse-subdep-1.0.pom new file mode 100644 index 0000000..2818c70 --- /dev/null +++ b/src/test/resources/MavenClasspathWidget/repository/fitnesse/fitnesse-subdep/1.0/fitnesse-subdep-1.0.pom @@ -0,0 +1,7 @@ + + 4.0.0 + fitnesse + fitnesse-subdep + 1.0 +