├── src ├── test │ ├── resources │ │ └── idl │ │ │ ├── shared.thrift │ │ │ └── tutorial.thrift │ └── java │ │ └── org │ │ └── apache │ │ └── thrift │ │ └── maven │ │ └── TestThrift.java └── main │ └── java │ └── org │ └── apache │ └── thrift │ └── maven │ ├── ThriftTestCompileMojo.java │ ├── ThriftCompileMojo.java │ ├── Thrift.java │ └── AbstractThriftMojo.java ├── pom.xml └── README /src/test/resources/idl/shared.thrift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /** 21 | * This Thrift file can be included by other Thrift files that want to share 22 | * these definitions. 23 | */ 24 | 25 | namespace cpp shared 26 | namespace java shared 27 | namespace perl shared 28 | 29 | struct SharedStruct { 30 | 1: i32 key 31 | 2: string value 32 | } 33 | 34 | service SharedService { 35 | SharedStruct getStruct(1: i32 key) 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/apache/thrift/maven/ThriftTestCompileMojo.java: -------------------------------------------------------------------------------- 1 | package org.apache.thrift.maven; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import org.apache.maven.artifact.Artifact; 24 | 25 | import java.io.File; 26 | import java.util.List; 27 | 28 | /** 29 | * @phase generate-test-sources 30 | * @goal testCompile 31 | * @requiresDependencyResolution test 32 | */ 33 | public final class ThriftTestCompileMojo extends AbstractThriftMojo { 34 | 35 | /** 36 | * The source directories containing the sources to be compiled. 37 | * 38 | * @parameter default-value="${basedir}/src/test/thrift" 39 | * @required 40 | */ 41 | private File thriftTestSourceRoot; 42 | 43 | /** 44 | * This is the directory into which the {@code .java} will be created. 45 | * 46 | * @parameter default-value="${project.build.directory}/generated-test-sources/thrift" 47 | * @required 48 | */ 49 | private File outputDirectory; 50 | 51 | @Override 52 | protected void attachFiles() { 53 | project.addTestCompileSourceRoot(outputDirectory.getAbsolutePath()); 54 | projectHelper.addTestResource(project, thriftTestSourceRoot.getAbsolutePath(), 55 | ImmutableList.of("**/*.thrift"), ImmutableList.of()); 56 | } 57 | 58 | @Override 59 | protected List getDependencyArtifacts() { 60 | // TODO(gak): maven-project needs generics 61 | @SuppressWarnings("unchecked") 62 | List testArtifacts = project.getTestArtifacts(); 63 | return testArtifacts; 64 | } 65 | 66 | @Override 67 | protected File getOutputDirectory() { 68 | return outputDirectory; 69 | } 70 | 71 | @Override 72 | protected File getThriftSourceRoot() { 73 | return thriftTestSourceRoot; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/apache/thrift/maven/ThriftCompileMojo.java: -------------------------------------------------------------------------------- 1 | package org.apache.thrift.maven; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import org.apache.maven.artifact.Artifact; 24 | 25 | import java.io.File; 26 | import java.util.List; 27 | 28 | /** 29 | * This mojo executes the {@code thrift} compiler for generating java sources 30 | * from thrift definitions. It also searches dependency artifacts for 31 | * thrift files and includes them in the thriftPath so that they can be 32 | * referenced. Finally, it adds the thrift files to the project as resources so 33 | * that they are included in the final artifact. 34 | * 35 | * @phase generate-sources 36 | * @goal compile 37 | * @requiresDependencyResolution compile 38 | */ 39 | 40 | public final class ThriftCompileMojo extends AbstractThriftMojo { 41 | 42 | /** 43 | * The source directories containing the sources to be compiled. 44 | * 45 | * @parameter default-value="${basedir}/src/main/thrift" 46 | * @required 47 | */ 48 | private File thriftSourceRoot; 49 | 50 | /** 51 | * This is the directory into which the {@code .java} will be created. 52 | * 53 | * @parameter default-value="${project.build.directory}/generated-sources/thrift" 54 | * @required 55 | */ 56 | private File outputDirectory; 57 | 58 | @Override 59 | protected List getDependencyArtifacts() { 60 | // TODO(gak): maven-project needs generics 61 | @SuppressWarnings("unchecked") 62 | List compileArtifacts = project.getCompileArtifacts(); 63 | return compileArtifacts; 64 | } 65 | 66 | @Override 67 | protected File getOutputDirectory() { 68 | return outputDirectory; 69 | } 70 | 71 | @Override 72 | protected File getThriftSourceRoot() { 73 | return thriftSourceRoot; 74 | } 75 | 76 | @Override 77 | protected void attachFiles() { 78 | project.addCompileSourceRoot(outputDirectory.getAbsolutePath()); 79 | projectHelper.addResource(project, thriftSourceRoot.getAbsolutePath(), 80 | ImmutableList.of("**/*.thrift"), ImmutableList.of()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.apache.thrift.tools 5 | thrift-maven-plugin 6 | maven-plugin 7 | Maven Thrift Plugin 8 | 0.1.13-SNAPSHOT 9 | Maven Thrift Plugin that executes the thrift code generator 10 | https://github.com/dtrott/maven-thrift-plugin 11 | 12 | 13 | 2.0.6 14 | 15 | 16 | 17 | 18 | The Apache Software License, Version 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.txt 20 | repo 21 | 22 | 23 | 24 | 25 | https://github.com/dtrott/maven-thrift-plugin 26 | scm:git:git@github.com:dtrott/maven-thrift-plugin.git 27 | HEAD 28 | 29 | 30 | 31 | 32 | drott 33 | David Trott 34 | github@davidtrott.com 35 | 36 | 37 | 38 | 39 | http://maven.davidtrott.com/repository 40 | 41 | dtrott-public 42 | David Trott's Public Repository 43 | file:///repositories/maven.davidtrott.com/release 44 | 45 | 46 | dtrott-public 47 | David Trott's Public Snapshot Repository 48 | file:///repositories/maven.davidtrott.com/snapshot 49 | 50 | 51 | 52 | 53 | UTF-8 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-compiler-plugin 61 | 2.3.2 62 | 63 | 1.6 64 | 1.6 65 | 66 | 67 | 68 | 69 | 70 | 71 | org.apache.maven.wagon 72 | wagon-ftp 73 | 1.0-beta-6 74 | 75 | 76 | 77 | 78 | 79 | 80 | junit 81 | junit 82 | 4.5 83 | test 84 | 85 | 86 | org.apache.maven 87 | maven-plugin-api 88 | 3.0.4 89 | 90 | 91 | com.google.guava 92 | guava 93 | 15.0 94 | 95 | 96 | org.codehaus.plexus 97 | plexus-utils 98 | 3.0.8 99 | 100 | 101 | org.apache.maven 102 | maven-project 103 | 2.2.0 104 | 105 | 106 | org.slf4j 107 | slf4j-api 108 | 1.5.8 109 | 110 | 111 | org.slf4j 112 | slf4j-simple 113 | 1.5.8 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /src/test/resources/idl/tutorial.thrift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | # Thrift Tutorial 21 | # Mark Slee (mcslee@facebook.com) 22 | # 23 | # This file aims to teach you how to use Thrift, in a .thrift file. Neato. The 24 | # first thing to notice is that .thrift files support standard shell comments. 25 | # This lets you make your thrift file executable and include your Thrift build 26 | # step on the top line. And you can place comments like this anywhere you like. 27 | # 28 | # Before running this file, you will need to have installed the thrift compiler 29 | # into /usr/local/bin. 30 | 31 | /** 32 | * The first thing to know about are types. The available types in Thrift are: 33 | * 34 | * bool Boolean, one byte 35 | * byte Signed byte 36 | * i16 Signed 16-bit integer 37 | * i32 Signed 32-bit integer 38 | * i64 Signed 64-bit integer 39 | * double 64-bit floating point value 40 | * string String 41 | * binary Blob (byte array) 42 | * map Map from one type to another 43 | * list Ordered list of one type 44 | * set Set of unique elements of one type 45 | * 46 | * Did you also notice that Thrift supports C style comments? 47 | */ 48 | 49 | // Just in case you were wondering... yes. We support simple C comments too. 50 | 51 | /** 52 | * Thrift files can reference other Thrift files to include common struct 53 | * and service definitions. These are found using the current path, or by 54 | * searching relative to any paths specified with the -I compiler flag. 55 | * 56 | * Included objects are accessed using the name of the .thrift file as a 57 | * prefix. i.e. shared.SharedObject 58 | */ 59 | include "shared.thrift" 60 | 61 | /** 62 | * Thrift files can namespace, package, or prefix their output in various 63 | * target languages. 64 | */ 65 | namespace cpp tutorial 66 | namespace java tutorial 67 | namespace php tutorial 68 | namespace perl tutorial 69 | namespace smalltalk.category Thrift.Tutorial 70 | 71 | /** 72 | * Thrift lets you do typedefs to get pretty names for your types. Standard 73 | * C style here. 74 | */ 75 | typedef i32 MyInteger 76 | 77 | /** 78 | * Thrift also lets you define constants for use across languages. Complex 79 | * types and structs are specified using JSON notation. 80 | */ 81 | const i32 INT32CONSTANT = 9853 82 | const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} 83 | 84 | /** 85 | * You can define enums, which are just 32 bit integers. Values are optional 86 | * and start at 1 if not supplied, C style again. 87 | */ 88 | enum Operation { 89 | ADD = 1, 90 | SUBTRACT = 2, 91 | MULTIPLY = 3, 92 | DIVIDE = 4 93 | } 94 | 95 | /** 96 | * Structs are the basic complex data structures. They are comprised of fields 97 | * which each have an integer identifier, a type, a symbolic name, and an 98 | * optional default value. 99 | * 100 | * Fields can be declared "optional", which ensures they will not be included 101 | * in the serialized output if they aren't set. Note that this requires some 102 | * manual management in some languages. 103 | */ 104 | struct Work { 105 | 1: i32 num1 = 0, 106 | 2: i32 num2, 107 | 3: Operation op, 108 | 4: optional string comment, 109 | } 110 | 111 | /** 112 | * Structs can also be exceptions, if they are nasty. 113 | */ 114 | exception InvalidOperation { 115 | 1: i32 what, 116 | 2: string why 117 | } 118 | 119 | /** 120 | * Ahh, now onto the cool part, defining a service. Services just need a name 121 | * and can optionally inherit from another service using the extends keyword. 122 | */ 123 | service Calculator extends shared.SharedService { 124 | 125 | /** 126 | * A method definition looks like C code. It has a return type, arguments, 127 | * and optionally a list of exceptions that it may throw. Note that argument 128 | * lists and exception lists are specified using the exact same syntax as 129 | * field lists in struct or exception definitions. 130 | */ 131 | 132 | void ping(), 133 | 134 | i32 add(1:i32 num1, 2:i32 num2), 135 | 136 | i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), 137 | 138 | /** 139 | * This method has a oneway modifier. That means the client only makes 140 | * a request and does not listen for any response at all. Oneway methods 141 | * must be void. 142 | */ 143 | oneway void zip() 144 | 145 | } 146 | 147 | /** 148 | * That just about covers the basics. Take a look in the test/ folder for more 149 | * detailed examples. After you run this file, your generated code shows up 150 | * in folders with names gen-. The generated code isn't too scary 151 | * to look at. It even has pretty indentation. 152 | */ 153 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | *************************** 2 | *** ONGOING MAINTENANCE *** 3 | *************************** 4 | 5 | PLEASE NOTE: THIS CODE HAS BEEN CONTRIBUTED BACK TO ASF. 6 | 7 | https://issues.apache.org/jira/browse/THRIFT-1536 8 | 9 | Any future work I do on this plugin, will be as patches submitted to their version. 10 | I am not planning to perform any further maintenance on this fork (or accept any patches / pull requests). 11 | 12 | *********************** 13 | *** VERSION WARNING *** 14 | *********************** 15 | 16 | Drop to the command line and type: 17 | 18 | thrift -version 19 | 20 | To find out what version of the compiler you are using. 21 | 22 | 23 | Older Compiler Versions (Less than 0.7.0) 24 | === 25 | You must use version 0.1.10 of this plugin. 26 | + Check out the source. 27 | + Switch to the old branch: git checkout -b old maven-thrift-plugin-0.1.10 28 | 29 | And build/use that version. 30 | 31 | 32 | 33 | Newer Compiler Versions (0.7.0 or newer) 34 | === 35 | 0.7.0 should work fine with the latest version of this plugin. 36 | However I have seen incompatibilities between the compiler and libthrift. 37 | 38 | To resolve these check out the source for the compiler from the 0.7.0 branch (Do not trust the TAR BALLS) 39 | 40 | svn co http://svn.apache.org/repos/asf/thrift/tags/thrift-0.7.0 41 | 42 | That version should work fine with the maven version of lib thrift: 43 | 44 | 45 | org.apache.thrift 46 | libthrift 47 | 0.7.0 48 | 49 | 50 | 51 | Note: If you have problems building on OSX you might want to look at this article: 52 | 53 | http://lueb.be/2009/02/23/installing-apache-thrift-on-mac-os-x-105-leopard/ 54 | 55 | The fastest way to build the compiler is: 56 | 57 | $ svn co http://svn.apache.org/repos/asf/thrift/tags/thrift-0.7.0 58 | $ cd thrift-0.7.0 59 | $ cp /usr/X11/share/aclocal/pkg.m4 aclocal/ 60 | $ ./bootstrap.sh 61 | $ ./configure 62 | $ cd compiler/cpp/ 63 | $ make 64 | 65 | 66 | 67 | *************************** 68 | *** Maven Thrift Plugin *** 69 | *************************** 70 | 71 | A minimal configuration to invoke this plugin would be: 72 | 73 | 76 | 77 | 4.0.0 78 | com.mycompany.example 79 | example-thrift 80 | jar 81 | 1.0-SNAPSHOT 82 | thrift-example 83 | 84 | 85 | 86 | 87 | org.apache.maven.plugins 88 | maven-compiler-plugin 89 | 90 | 1.5 91 | 1.5 92 | 93 | 94 | 95 | org.apache.thrift.tools 96 | maven-thrift-plugin 97 | 0.1.10 98 | 99 | /usr/local/bin/thrift 100 | 101 | 102 | 103 | thrift-sources 104 | generate-sources 105 | 106 | compile 107 | 108 | 109 | 110 | thrift-test-sources 111 | generate-test-sources 112 | 113 | testCompile 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | org.apache.hadoop 124 | libthrift 125 | 0.5.0.0 126 | 127 | 128 | 129 | org.slf4j 130 | slf4j-api 131 | 1.5.8 132 | 133 | 134 | 135 | log4j 136 | log4j 137 | 1.2.14 138 | 139 | 140 | 141 | 142 | 143 | You must: 144 | + Use Java 1.5 or newer due to the usage of Generics 145 | + Either ensure the "thrift" executable is in your PATH or set the 146 | parameter to the correct location. 147 | + Define the executions you want (you probably don't need the testCompile 148 | unless you have custom thrift objects in your tests. 149 | + Include the dependencies on libthrift and slf4j or your compile will fail. 150 | 151 | 152 | Once this is all done add your *.thrift files to the directory: src/main/thrift 153 | 154 | Everything should then build with a: mvn clean install 155 | 156 | 157 | 158 | 159 | You may also need to add the following to your settings.xml to download the 160 | plugin: 161 | 162 | 163 | 164 | dtrott 165 | http://maven.davidtrott.com/repository 166 | 167 | 168 | -------------------------------------------------------------------------------- /src/test/java/org/apache/thrift/maven/TestThrift.java: -------------------------------------------------------------------------------- 1 | package org.apache.thrift.maven; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.codehaus.plexus.util.FileUtils; 23 | import org.codehaus.plexus.util.cli.CommandLineException; 24 | import org.junit.After; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | 28 | import java.io.File; 29 | 30 | import static org.junit.Assert.assertEquals; 31 | import static org.junit.Assert.assertFalse; 32 | import static org.junit.Assert.assertTrue; 33 | import static org.junit.Assert.fail; 34 | 35 | public class TestThrift { 36 | 37 | private File testRootDir; 38 | private File idlDir; 39 | private File genJavaDir; 40 | private Thrift.Builder builder; 41 | 42 | @Before 43 | public void setup() throws Exception { 44 | final File tmpDir = new File(System.getProperty("java.io.tmpdir")); 45 | testRootDir = new File(tmpDir, "thrift-test"); 46 | 47 | if (testRootDir.exists()) { 48 | FileUtils.cleanDirectory(testRootDir); 49 | } else { 50 | assertTrue("Failed to create output directory for test: " + testRootDir.getPath(), testRootDir.mkdir()); 51 | } 52 | 53 | File testResourceDir = new File("src/test/resources"); 54 | assertTrue("Unable to find test resources", testRootDir.exists()); 55 | 56 | idlDir = new File(testResourceDir, "idl"); 57 | genJavaDir = new File(testRootDir, Thrift.GENERATED_JAVA); 58 | builder = new Thrift.Builder("thrift", testRootDir); 59 | builder 60 | .setGenerator("java") 61 | .addThriftPathElement(idlDir); 62 | } 63 | 64 | @Test 65 | public void testThriftCompile() throws Exception { 66 | executeThriftCompile(); 67 | } 68 | 69 | @Test 70 | public void testThriftCompileWithGeneratorOption() throws Exception { 71 | builder.setGenerator("java:private-members,hashcode"); 72 | executeThriftCompile(); 73 | } 74 | 75 | private void executeThriftCompile() throws CommandLineException { 76 | final File thriftFile = new File(idlDir, "shared.thrift"); 77 | 78 | builder.addThriftFile(thriftFile); 79 | 80 | final Thrift thrift = builder.build(); 81 | 82 | assertTrue("File not found: shared.thrift", thriftFile.exists()); 83 | assertFalse("gen-java directory should not exist", genJavaDir.exists()); 84 | 85 | // execute the compile 86 | final int result = thrift.compile(); 87 | assertEquals(0, result); 88 | 89 | assertFalse("gen-java directory was not removed", genJavaDir.exists()); 90 | assertTrue("generated java code doesn't exist", 91 | new File(testRootDir, "shared/SharedService.java").exists()); 92 | } 93 | 94 | @Test 95 | public void testThriftMultipleFileCompile() throws Exception { 96 | final File sharedThrift = new File(idlDir, "shared.thrift"); 97 | final File tutorialThrift = new File(idlDir, "tutorial.thrift"); 98 | 99 | builder.addThriftFile(sharedThrift); 100 | builder.addThriftFile(tutorialThrift); 101 | 102 | final Thrift thrift = builder.build(); 103 | 104 | assertTrue("File not found: shared.thrift", sharedThrift.exists()); 105 | assertFalse("gen-java directory should not exist", genJavaDir.exists()); 106 | 107 | // execute the compile 108 | final int result = thrift.compile(); 109 | assertEquals(0, result); 110 | 111 | assertFalse("gen-java directory was not removed", genJavaDir.exists()); 112 | assertTrue("generated java code doesn't exist", 113 | new File(testRootDir, "shared/SharedService.java").exists()); 114 | assertTrue("generated java code doesn't exist", 115 | new File(testRootDir, "tutorial/InvalidOperation.java").exists()); 116 | } 117 | 118 | @Test 119 | public void testBadCompile() throws Exception { 120 | final File thriftFile = new File(testRootDir, "missing.thrift"); 121 | builder.addThriftPathElement(testRootDir); 122 | 123 | // Hacking around checks in addThrift file. 124 | assertTrue(thriftFile.createNewFile()); 125 | builder.addThriftFile(thriftFile); 126 | assertTrue(thriftFile.delete()); 127 | 128 | final Thrift thrift = builder.build(); 129 | 130 | assertTrue(!thriftFile.exists()); 131 | assertFalse("gen-java directory should not exist", genJavaDir.exists()); 132 | 133 | // execute the compile 134 | final int result = thrift.compile(); 135 | assertEquals(1, result); 136 | } 137 | 138 | @Test 139 | public void testFileInPathPreCondition() throws Exception { 140 | final File thriftFile = new File(testRootDir, "missing.thrift"); 141 | 142 | // Hacking around checks in addThrift file. 143 | assertTrue(thriftFile.createNewFile()); 144 | try { 145 | builder.addThriftFile(thriftFile); 146 | fail("Expected IllegalStateException"); 147 | } catch (IllegalStateException e) { 148 | } 149 | } 150 | 151 | @After 152 | public void cleanup() throws Exception { 153 | if (testRootDir.exists()) { 154 | FileUtils.cleanDirectory(testRootDir); 155 | assertTrue("Failed to delete output directory for test: " + testRootDir.getPath(), testRootDir.delete()); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/org/apache/thrift/maven/Thrift.java: -------------------------------------------------------------------------------- 1 | package org.apache.thrift.maven; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import com.google.common.collect.ImmutableSet; 24 | import org.codehaus.plexus.util.cli.CommandLineException; 25 | import org.codehaus.plexus.util.cli.CommandLineUtils; 26 | import org.codehaus.plexus.util.cli.Commandline; 27 | 28 | import java.io.File; 29 | import java.util.List; 30 | import java.util.Set; 31 | 32 | import static com.google.common.base.Preconditions.checkArgument; 33 | import static com.google.common.base.Preconditions.checkNotNull; 34 | import static com.google.common.base.Preconditions.checkState; 35 | import static com.google.common.collect.Lists.newLinkedList; 36 | import static com.google.common.collect.Sets.newHashSet; 37 | 38 | /** 39 | * This class represents an invokable configuration of the {@code thrift} 40 | * compiler. The actual executable is invoked using the plexus 41 | * {@link Commandline}. 42 | *

43 | * This class currently only supports generating java source files. 44 | * 45 | * @author gak@google.com (Gregory Kick) 46 | */ 47 | final class Thrift { 48 | 49 | final static String GENERATED_JAVA = "gen-java"; 50 | 51 | private final String executable; 52 | private final String generator; 53 | private final ImmutableSet thriftPathElements; 54 | private final ImmutableSet thriftFiles; 55 | private final File javaOutputDirectory; 56 | private final CommandLineUtils.StringStreamConsumer output; 57 | private final CommandLineUtils.StringStreamConsumer error; 58 | 59 | /** 60 | * Constructs a new instance. This should only be used by the {@link Builder}. 61 | * 62 | * @param executable The path to the {@code thrift} executable. 63 | * @param generator The value for the {@code --gen} option. 64 | * @param thriftPath The directories in which to search for imports. 65 | * @param thriftFiles The thrift source files to compile. 66 | * @param javaOutputDirectory The directory into which the java source files 67 | * will be generated. 68 | */ 69 | private Thrift(String executable, String generator, ImmutableSet thriftPath, 70 | ImmutableSet thriftFiles, File javaOutputDirectory) { 71 | this.executable = checkNotNull(executable, "executable"); 72 | this.generator = checkNotNull(generator, "generator"); 73 | this.thriftPathElements = checkNotNull(thriftPath, "thriftPath"); 74 | this.thriftFiles = checkNotNull(thriftFiles, "thriftFiles"); 75 | this.javaOutputDirectory = checkNotNull(javaOutputDirectory, "javaOutputDirectory"); 76 | this.error = new CommandLineUtils.StringStreamConsumer(); 77 | this.output = new CommandLineUtils.StringStreamConsumer(); 78 | } 79 | 80 | /** 81 | * Invokes the {@code thrift} compiler using the configuration specified at 82 | * construction. 83 | * 84 | * @return The exit status of {@code thrift}. 85 | * @throws CommandLineException 86 | */ 87 | public int compile() throws CommandLineException { 88 | 89 | for (File thriftFile : thriftFiles) { 90 | Commandline cl = new Commandline(); 91 | cl.setExecutable(executable); 92 | cl.addArguments(buildThriftCommand(thriftFile).toArray(new String[]{})); 93 | final int result = CommandLineUtils.executeCommandLine(cl, null, output, error); 94 | 95 | if (result != 0) { 96 | return result; 97 | } 98 | } 99 | 100 | // result will always be 0 here. 101 | return 0; 102 | } 103 | 104 | /** 105 | * Creates the command line arguments. 106 | *

107 | * This method has been made visible for testing only. 108 | * 109 | * @param thriftFile 110 | * @return A list consisting of the executable followed by any arguments. 111 | */ 112 | ImmutableList buildThriftCommand(final File thriftFile) { 113 | final List command = newLinkedList(); 114 | // add the executable 115 | for (File thriftPathElement : thriftPathElements) { 116 | command.add("-I"); 117 | command.add(thriftPathElement.toString()); 118 | } 119 | command.add("-out"); 120 | command.add(javaOutputDirectory.toString()); 121 | command.add("--gen"); 122 | command.add(generator); 123 | command.add(thriftFile.toString()); 124 | return ImmutableList.copyOf(command); 125 | } 126 | 127 | /** 128 | * @return the output 129 | */ 130 | public String getOutput() { 131 | return output.getOutput(); 132 | } 133 | 134 | /** 135 | * @return the error 136 | */ 137 | public String getError() { 138 | return error.getOutput(); 139 | } 140 | 141 | /** 142 | * This class builds {@link Thrift} instances. 143 | * 144 | * @author gak@google.com (Gregory Kick) 145 | */ 146 | static final class Builder { 147 | private final String executable; 148 | private final File javaOutputDirectory; 149 | private Set thriftPathElements; 150 | private Set thriftFiles; 151 | private String generator; 152 | 153 | /** 154 | * Constructs a new builder. The two parameters are present as they are 155 | * required for all {@link Thrift} instances. 156 | * 157 | * @param executable The path to the {@code thrift} executable. 158 | * @param javaOutputDirectory The directory into which the java source files 159 | * will be generated. 160 | * @throws NullPointerException If either of the arguments are {@code null}. 161 | * @throws IllegalArgumentException If the {@code javaOutputDirectory} is 162 | * not a directory. 163 | */ 164 | public Builder(String executable, File javaOutputDirectory) { 165 | this.executable = checkNotNull(executable, "executable"); 166 | this.javaOutputDirectory = checkNotNull(javaOutputDirectory); 167 | checkArgument(javaOutputDirectory.isDirectory()); 168 | this.thriftFiles = newHashSet(); 169 | this.thriftPathElements = newHashSet(); 170 | } 171 | 172 | /** 173 | * Adds a thrift file to be compiled. Thrift files must be on the thriftpath 174 | * and this method will fail if a thrift file is added without first adding a 175 | * parent directory to the thriftpath. 176 | * 177 | * @param thriftFile 178 | * @return The builder. 179 | * @throws IllegalStateException If a thrift file is added without first 180 | * adding a parent directory to the thriftpath. 181 | * @throws NullPointerException If {@code thriftFile} is {@code null}. 182 | */ 183 | public Builder addThriftFile(File thriftFile) { 184 | checkNotNull(thriftFile); 185 | checkArgument(thriftFile.isFile()); 186 | checkArgument(thriftFile.getName().endsWith(".thrift")); 187 | checkThriftFileIsInThriftPath(thriftFile); 188 | thriftFiles.add(thriftFile); 189 | return this; 190 | } 191 | 192 | /** 193 | * Adds the option string for the Thrift executable's {@code --gen} parameter. 194 | * 195 | * @param generator 196 | * @return The builder 197 | * @throws NullPointerException If {@code generator} is {@code null}. 198 | */ 199 | public Builder setGenerator(String generator) { 200 | checkNotNull(generator); 201 | this.generator = generator; 202 | return this; 203 | } 204 | 205 | private void checkThriftFileIsInThriftPath(File thriftFile) { 206 | assert thriftFile.isFile(); 207 | checkState(checkThriftFileIsInThriftPathHelper(thriftFile.getParentFile())); 208 | } 209 | 210 | private boolean checkThriftFileIsInThriftPathHelper(File directory) { 211 | assert directory.isDirectory(); 212 | if (thriftPathElements.contains(directory)) { 213 | return true; 214 | } else { 215 | final File parentDirectory = directory.getParentFile(); 216 | return (parentDirectory == null) ? false 217 | : checkThriftFileIsInThriftPathHelper(parentDirectory); 218 | } 219 | } 220 | 221 | /** 222 | * @see #addThriftFile(File) 223 | */ 224 | public Builder addThriftFiles(Iterable thriftFiles) { 225 | for (File thriftFile : thriftFiles) { 226 | addThriftFile(thriftFile); 227 | } 228 | return this; 229 | } 230 | 231 | /** 232 | * Adds the {@code thriftPathElement} to the thriftPath. 233 | * 234 | * @param thriftPathElement A directory to be searched for imported thrift message 235 | * buffer definitions. 236 | * @return The builder. 237 | * @throws NullPointerException If {@code thriftPathElement} is {@code null}. 238 | * @throws IllegalArgumentException If {@code thriftPathElement} is not a 239 | * directory. 240 | */ 241 | public Builder addThriftPathElement(File thriftPathElement) { 242 | checkNotNull(thriftPathElement); 243 | checkArgument(thriftPathElement.isDirectory()); 244 | thriftPathElements.add(thriftPathElement); 245 | return this; 246 | } 247 | 248 | /** 249 | * @see #addThriftPathElement(File) 250 | */ 251 | public Builder addThriftPathElements(Iterable thriftPathElements) { 252 | for (File thriftPathElement : thriftPathElements) { 253 | addThriftPathElement(thriftPathElement); 254 | } 255 | return this; 256 | } 257 | 258 | /** 259 | * @return A configured {@link Thrift} instance. 260 | * @throws IllegalStateException If no thrift files have been added. 261 | */ 262 | public Thrift build() { 263 | checkState(!thriftFiles.isEmpty()); 264 | return new Thrift(executable, generator, ImmutableSet.copyOf(thriftPathElements), 265 | ImmutableSet.copyOf(thriftFiles), javaOutputDirectory); 266 | } 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/main/java/org/apache/thrift/maven/AbstractThriftMojo.java: -------------------------------------------------------------------------------- 1 | package org.apache.thrift.maven; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import com.google.common.base.Joiner; 23 | import com.google.common.collect.ImmutableSet; 24 | import org.apache.maven.artifact.Artifact; 25 | import org.apache.maven.artifact.repository.ArtifactRepository; 26 | import org.apache.maven.plugin.AbstractMojo; 27 | import org.apache.maven.plugin.MojoExecutionException; 28 | import org.apache.maven.plugin.MojoFailureException; 29 | import org.apache.maven.project.MavenProject; 30 | import org.apache.maven.project.MavenProjectHelper; 31 | import org.codehaus.plexus.util.cli.CommandLineException; 32 | import org.codehaus.plexus.util.io.RawInputStreamFacade; 33 | 34 | import java.io.File; 35 | import java.io.FilenameFilter; 36 | import java.io.IOException; 37 | import java.security.MessageDigest; 38 | import java.security.NoSuchAlgorithmException; 39 | import java.util.List; 40 | import java.util.Set; 41 | import java.util.jar.JarEntry; 42 | import java.util.jar.JarFile; 43 | 44 | import static com.google.common.base.Preconditions.checkArgument; 45 | import static com.google.common.base.Preconditions.checkNotNull; 46 | import static com.google.common.base.Preconditions.checkState; 47 | import static com.google.common.collect.Sets.newHashSet; 48 | import static java.lang.String.format; 49 | import static java.util.Arrays.asList; 50 | import static java.util.Collections.list; 51 | import static org.codehaus.plexus.util.FileUtils.cleanDirectory; 52 | import static org.codehaus.plexus.util.FileUtils.copyStreamToFile; 53 | import static org.codehaus.plexus.util.FileUtils.getFiles; 54 | 55 | /** 56 | * Abstract Mojo implementation. 57 | *

58 | * This class is extended by {@link org.apache.thrift.maven.ThriftCompileMojo} and 59 | * {@link org.apache.thrift.maven.ThriftTestCompileMojo} in order to override the specific configuration for 60 | * compiling the main or test classes respectively. 61 | * 62 | * @author Gregory Kick 63 | * @author David Trott 64 | * @author Brice Figureau 65 | */ 66 | abstract class AbstractThriftMojo extends AbstractMojo { 67 | 68 | private static final String THRIFT_FILE_SUFFIX = ".thrift"; 69 | 70 | private static final String DEFAULT_INCLUDES = "**/*" + THRIFT_FILE_SUFFIX; 71 | 72 | /** 73 | * The current Maven project. 74 | * 75 | * @parameter default-value="${project}" 76 | * @readonly 77 | * @required 78 | */ 79 | protected MavenProject project; 80 | 81 | /** 82 | * A helper used to add resources to the project. 83 | * 84 | * @component 85 | * @required 86 | */ 87 | protected MavenProjectHelper projectHelper; 88 | 89 | /** 90 | * This is the path to the {@code thrift} executable. By default it will search the {@code $PATH}. 91 | * 92 | * @parameter default-value="thrift" 93 | * @required 94 | */ 95 | private String thriftExecutable; 96 | 97 | /** 98 | * This string is passed to the {@code --gen} option of the {@code thrift} parameter. By default 99 | * it will generate Java output. The main reason for this option is to be able to add options 100 | * to the Java generator - if you generate something else, you're on your own. 101 | * 102 | * @parameter default-value="java:hashcode" 103 | */ 104 | private String generator; 105 | 106 | /** 107 | * @parameter 108 | */ 109 | private File[] additionalThriftPathElements = new File[]{}; 110 | 111 | /** 112 | * Since {@code thrift} cannot access jars, thrift files in dependencies are extracted to this location 113 | * and deleted on exit. This directory is always cleaned during execution. 114 | * 115 | * @parameter expression="${project.build.directory}/thrift-dependencies" 116 | * @required 117 | */ 118 | private File temporaryThriftFileDirectory; 119 | 120 | /** 121 | * This is the path to the local maven {@code repository}. 122 | * 123 | * @parameter default-value="${localRepository}" 124 | * @required 125 | */ 126 | private ArtifactRepository localRepository; 127 | 128 | /** 129 | * Set this to {@code false} to disable hashing of dependent jar paths. 130 | *

131 | * This plugin expands jars on the classpath looking for embedded .thrift files. 132 | * Normally these paths are hashed (MD5) to avoid issues with long file names on windows. 133 | * However if this property is set to {@code false} longer paths will be used. 134 | * 135 | * @parameter default-value="true" 136 | * @required 137 | */ 138 | private boolean hashDependentPaths; 139 | 140 | /** 141 | * @parameter 142 | */ 143 | private Set includes = ImmutableSet.of(DEFAULT_INCLUDES); 144 | 145 | /** 146 | * @parameter 147 | */ 148 | private Set excludes = ImmutableSet.of(); 149 | 150 | /** 151 | * @parameter 152 | */ 153 | private long staleMillis = 0; 154 | 155 | /** 156 | * @parameter 157 | */ 158 | private boolean checkStaleness = false; 159 | 160 | /** 161 | * Executes the mojo. 162 | */ 163 | public void execute() throws MojoExecutionException, MojoFailureException { 164 | checkParameters(); 165 | final File thriftSourceRoot = getThriftSourceRoot(); 166 | if (thriftSourceRoot.exists()) { 167 | try { 168 | ImmutableSet thriftFiles = findThriftFilesInDirectory(thriftSourceRoot); 169 | final File outputDirectory = getOutputDirectory(); 170 | ImmutableSet outputFiles = findGeneratedFilesInDirectory(getOutputDirectory()); 171 | 172 | if (thriftFiles.isEmpty()) { 173 | getLog().info("No thrift files to compile."); 174 | } else if (checkStaleness && ((lastModified(thriftFiles) + staleMillis) < lastModified(outputFiles))) { 175 | getLog().info("Skipping compilation because target directory newer than sources."); 176 | attachFiles(); 177 | } else { 178 | ImmutableSet derivedThriftPathElements = 179 | makeThriftPathFromJars(temporaryThriftFileDirectory, getDependencyArtifactFiles()); 180 | outputDirectory.mkdirs(); 181 | 182 | // Quick fix to fix issues with two mvn installs in a row (ie no clean) 183 | cleanDirectory(outputDirectory); 184 | 185 | Thrift thrift = new Thrift.Builder(thriftExecutable, outputDirectory) 186 | .setGenerator(generator) 187 | .addThriftPathElement(thriftSourceRoot) 188 | .addThriftPathElements(derivedThriftPathElements) 189 | .addThriftPathElements(asList(additionalThriftPathElements)) 190 | .addThriftFiles(thriftFiles) 191 | .build(); 192 | final int exitStatus = thrift.compile(); 193 | if (exitStatus != 0) { 194 | getLog().error("thrift failed output: " + thrift.getOutput()); 195 | getLog().error("thrift failed error: " + thrift.getError()); 196 | throw new MojoFailureException( 197 | "thrift did not exit cleanly. Review output for more information."); 198 | } 199 | attachFiles(); 200 | } 201 | } catch (IOException e) { 202 | throw new MojoExecutionException("An IO error occured", e); 203 | } catch (IllegalArgumentException e) { 204 | throw new MojoFailureException("thrift failed to execute because: " + e.getMessage(), e); 205 | } catch (CommandLineException e) { 206 | throw new MojoExecutionException("An error occurred while invoking thrift.", e); 207 | } 208 | } else { 209 | getLog().info(format("%s does not exist. Review the configuration or consider disabling the plugin.", 210 | thriftSourceRoot)); 211 | } 212 | } 213 | 214 | ImmutableSet findGeneratedFilesInDirectory(File directory) throws IOException { 215 | if (directory == null || !directory.isDirectory()) 216 | return ImmutableSet.of(); 217 | 218 | // TODO(gak): plexus-utils needs generics 219 | @SuppressWarnings("unchecked") 220 | List javaFilesInDirectory = getFiles(directory, "**/*.java", null); 221 | return ImmutableSet.copyOf(javaFilesInDirectory); 222 | } 223 | 224 | private long lastModified(ImmutableSet files) { 225 | long result = 0; 226 | for (File file : files) { 227 | if (file.lastModified() > result) 228 | result = file.lastModified(); 229 | } 230 | return result; 231 | } 232 | 233 | private void checkParameters() { 234 | checkNotNull(project, "project"); 235 | checkNotNull(projectHelper, "projectHelper"); 236 | checkNotNull(thriftExecutable, "thriftExecutable"); 237 | checkNotNull(generator, "generator"); 238 | final File thriftSourceRoot = getThriftSourceRoot(); 239 | checkNotNull(thriftSourceRoot); 240 | checkArgument(!thriftSourceRoot.isFile(), "thriftSourceRoot is a file, not a diretory"); 241 | checkNotNull(temporaryThriftFileDirectory, "temporaryThriftFileDirectory"); 242 | checkState(!temporaryThriftFileDirectory.isFile(), "temporaryThriftFileDirectory is a file, not a directory"); 243 | final File outputDirectory = getOutputDirectory(); 244 | checkNotNull(outputDirectory); 245 | checkState(!outputDirectory.isFile(), "the outputDirectory is a file, not a directory"); 246 | } 247 | 248 | protected abstract File getThriftSourceRoot(); 249 | 250 | protected abstract List getDependencyArtifacts(); 251 | 252 | protected abstract File getOutputDirectory(); 253 | 254 | protected abstract void attachFiles(); 255 | 256 | /** 257 | * Gets the {@link File} for each dependency artifact. 258 | * 259 | * @return A set of all dependency artifacts. 260 | */ 261 | private ImmutableSet getDependencyArtifactFiles() { 262 | Set dependencyArtifactFiles = newHashSet(); 263 | for (Artifact artifact : getDependencyArtifacts()) { 264 | dependencyArtifactFiles.add(artifact.getFile()); 265 | } 266 | return ImmutableSet.copyOf(dependencyArtifactFiles); 267 | } 268 | 269 | /** 270 | * @throws IOException 271 | */ 272 | ImmutableSet makeThriftPathFromJars(File temporaryThriftFileDirectory, Iterable classpathElementFiles) 273 | throws IOException, MojoExecutionException { 274 | checkNotNull(classpathElementFiles, "classpathElementFiles"); 275 | // clean the temporary directory to ensure that stale files aren't used 276 | if (temporaryThriftFileDirectory.exists()) { 277 | cleanDirectory(temporaryThriftFileDirectory); 278 | } 279 | Set thriftDirectories = newHashSet(); 280 | for (File classpathElementFile : classpathElementFiles) { 281 | // for some reason under IAM, we receive poms as dependent files 282 | // I am excluding .xml rather than including .jar as there may be other extensions in use (sar, har, zip) 283 | if (classpathElementFile.isFile() && classpathElementFile.canRead() && 284 | !classpathElementFile.getName().endsWith(".xml")) { 285 | 286 | // create the jar file. the constructor validates. 287 | JarFile classpathJar; 288 | try { 289 | classpathJar = new JarFile(classpathElementFile); 290 | } catch (IOException e) { 291 | throw new IllegalArgumentException(format( 292 | "%s was not a readable artifact", classpathElementFile)); 293 | } 294 | for (JarEntry jarEntry : list(classpathJar.entries())) { 295 | final String jarEntryName = jarEntry.getName(); 296 | if (jarEntry.getName().endsWith(THRIFT_FILE_SUFFIX)) { 297 | final File uncompressedCopy = 298 | new File(new File(temporaryThriftFileDirectory, 299 | truncatePath(classpathJar.getName())), jarEntryName); 300 | uncompressedCopy.getParentFile().mkdirs(); 301 | copyStreamToFile(new RawInputStreamFacade(classpathJar 302 | .getInputStream(jarEntry)), uncompressedCopy); 303 | thriftDirectories.add(uncompressedCopy.getParentFile()); 304 | } 305 | } 306 | } else if (classpathElementFile.isDirectory()) { 307 | File[] thriftFiles = classpathElementFile.listFiles(new FilenameFilter() { 308 | public boolean accept(File dir, String name) { 309 | return name.endsWith(THRIFT_FILE_SUFFIX); 310 | } 311 | }); 312 | 313 | if (thriftFiles.length > 0) { 314 | thriftDirectories.add(classpathElementFile); 315 | } 316 | } 317 | } 318 | return ImmutableSet.copyOf(thriftDirectories); 319 | } 320 | 321 | ImmutableSet findThriftFilesInDirectory(File directory) throws IOException { 322 | checkNotNull(directory); 323 | checkArgument(directory.isDirectory(), "%s is not a directory", directory); 324 | 325 | final Joiner joiner = Joiner.on(','); 326 | 327 | // TODO(gak): plexus-utils needs generics 328 | @SuppressWarnings("unchecked") 329 | List thriftFilesInDirectory = getFiles(directory, joiner.join(includes), joiner.join(excludes)); 330 | return ImmutableSet.copyOf(thriftFilesInDirectory); 331 | } 332 | 333 | ImmutableSet findThriftFilesInDirectories(Iterable directories) throws IOException { 334 | checkNotNull(directories); 335 | Set thriftFiles = newHashSet(); 336 | for (File directory : directories) { 337 | thriftFiles.addAll(findThriftFilesInDirectory(directory)); 338 | } 339 | return ImmutableSet.copyOf(thriftFiles); 340 | } 341 | 342 | /** 343 | * Truncates the path of jar files so that they are relative to the local repository. 344 | * 345 | * @param jarPath the full path of a jar file. 346 | * @return the truncated path relative to the local repository or root of the drive. 347 | */ 348 | String truncatePath(final String jarPath) throws MojoExecutionException { 349 | 350 | if (hashDependentPaths) { 351 | try { 352 | return toHexString(MessageDigest.getInstance("MD5").digest(jarPath.getBytes())); 353 | } catch (NoSuchAlgorithmException e) { 354 | throw new MojoExecutionException("Failed to expand dependent jar", e); 355 | } 356 | } 357 | 358 | String repository = localRepository.getBasedir().replace('\\', '/'); 359 | if (!repository.endsWith("/")) { 360 | repository += "/"; 361 | } 362 | 363 | String path = jarPath.replace('\\', '/'); 364 | int repositoryIndex = path.indexOf(repository); 365 | if (repositoryIndex != -1) { 366 | path = path.substring(repositoryIndex + repository.length()); 367 | } 368 | 369 | // By now the path should be good, but do a final check to fix windows machines. 370 | int colonIndex = path.indexOf(':'); 371 | if (colonIndex != -1) { 372 | // 2 = :\ in C:\ 373 | path = path.substring(colonIndex + 2); 374 | } 375 | 376 | return path; 377 | } 378 | 379 | private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray(); 380 | 381 | public static String toHexString(byte[] byteArray) { 382 | final StringBuilder hexString = new StringBuilder(2 * byteArray.length); 383 | for (final byte b : byteArray) { 384 | hexString.append(HEX_CHARS[(b & 0xF0) >> 4]).append(HEX_CHARS[b & 0x0F]); 385 | } 386 | return hexString.toString(); 387 | } 388 | } 389 | --------------------------------------------------------------------------------