Commit b0c3cee6 authored by David Trott's avatar David Trott

Updated to run the thrift compiler for each thrift file instead of processing...

Updated to run the thrift compiler for each thrift file instead of processing them all in a single execution.

This is because thift can only handle one file at a time.
Additionally added unit test for multiple files and invalid pre-conditions.
parent 143834a7
......@@ -63,17 +63,23 @@ final class Thrift {
* @throws CommandLineException
*/
public int compile() throws CommandLineException {
Commandline cl = new Commandline(executable);
cl.addArguments(buildThriftCommand().toArray(new String[]{}));
StreamConsumer output = new DefaultConsumer();
StreamConsumer error = new DefaultConsumer();
final int result = CommandLineUtils.executeCommandLine(cl, null, output, error);
if (result == 0) {
moveGeneratedFiles();
for (File thriftFile : thriftFiles) {
Commandline cl = new Commandline(executable);
cl.addArguments(buildThriftCommand(thriftFile).toArray(new String[]{}));
StreamConsumer output = new DefaultConsumer();
StreamConsumer error = new DefaultConsumer();
final int result = CommandLineUtils.executeCommandLine(cl, null, output, error);
if (result != 0) {
return result;
}
}
return result;
// result will always be 0 here.
moveGeneratedFiles();
return 0;
}
/**
......@@ -81,9 +87,10 @@ final class Thrift {
* <p/>
* This method has been made visible for testing only.
*
* @param thriftFile
* @return A list consisting of the executable followed by any arguments.
*/
ImmutableList<String> buildThriftCommand() {
ImmutableList<String> buildThriftCommand(final File thriftFile) {
final List<String> command = newLinkedList();
// add the executable
for (File thriftPathElement : thriftPathElements) {
......@@ -94,9 +101,7 @@ final class Thrift {
command.add(javaOutputDirectory.toString());
command.add("--gen");
command.add("java");
for (File thriftFile : thriftFiles) {
command.add(thriftFile.toString());
}
command.add(thriftFile.toString());
return ImmutableList.copyOf(command);
}
......
......@@ -4,14 +4,20 @@ import org.codehaus.plexus.util.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class TestThrift {
private File testRootDir;
private File testResourceDir;
private File idlDir;
private File genJavaDir;
private Thrift.Builder builder;
@Before
public void setup() throws Exception {
......@@ -21,21 +27,22 @@ public class TestThrift {
if (testRootDir.exists()) {
FileUtils.cleanDirectory(testRootDir);
} else {
assertTrue("Failed to create output directory for test: "+ testRootDir.getPath(), testRootDir.mkdir());
assertTrue("Failed to create output directory for test: " + testRootDir.getPath(), testRootDir.mkdir());
}
testResourceDir = new File("src/test/resources");
File testResourceDir = new File("src/test/resources");
assertTrue("Unable to find test resources", testRootDir.exists());
idlDir = new File(testResourceDir, "idl");
genJavaDir = new File(testRootDir, Thrift.GENERATED_JAVA);
builder = new Thrift.Builder("thrift", testRootDir);
builder.addThriftPathElement(idlDir);
}
@Test
public void testThriftCompile() throws Exception {
final File idlDir = new File(testResourceDir, "idl");
final File genJavaDir = new File(testRootDir, Thrift.GENERATED_JAVA);
final File thriftFile = new File(idlDir, "shared.thrift");
Thrift.Builder builder = new Thrift.Builder("thrift", testRootDir);
builder.addThriftPathElement(idlDir);
builder.addThriftFile(thriftFile);
final Thrift thrift = builder.build();
......@@ -52,11 +59,68 @@ public class TestThrift {
new File(testRootDir, "shared/SharedService.java").exists());
}
@Test
public void testThriftMultipleFileCompile() throws Exception {
final File sharedThrift = new File(idlDir, "shared.thrift");
final File tutorialThrift = new File(idlDir, "tutorial.thrift");
builder.addThriftFile(sharedThrift);
builder.addThriftFile(tutorialThrift);
final Thrift thrift = builder.build();
assertTrue("File not found: shared.thrift", sharedThrift.exists());
assertFalse("gen-java directory should not exist", genJavaDir.exists());
// execute the compile
final int result = thrift.compile();
assertEquals(0, result);
assertFalse("gen-java directory was not removed", genJavaDir.exists());
assertTrue("generated java code doesn't exist",
new File(testRootDir, "shared/SharedService.java").exists());
assertTrue("generated java code doesn't exist",
new File(testRootDir, "tutorial/InvalidOperation.java").exists());
}
@Test
public void testBadCompile() throws Exception {
final File thriftFile = new File(testRootDir, "missing.thrift");
builder.addThriftPathElement(testRootDir);
// Hacking around checks in addThrift file.
assertTrue(thriftFile.createNewFile());
builder.addThriftFile(thriftFile);
assertTrue(thriftFile.delete());
final Thrift thrift = builder.build();
assertTrue(!thriftFile.exists());
assertFalse("gen-java directory should not exist", genJavaDir.exists());
// execute the compile
final int result = thrift.compile();
assertEquals(1, result);
}
@Test
public void testFileInPathPreCondition() throws Exception {
final File thriftFile = new File(testRootDir, "missing.thrift");
// Hacking around checks in addThrift file.
assertTrue(thriftFile.createNewFile());
try {
builder.addThriftFile(thriftFile);
fail("Expected IllegalStateException");
} catch (IllegalStateException e) {
}
}
@After
public void cleanup() throws Exception {
if (testRootDir.exists()) {
FileUtils.cleanDirectory(testRootDir);
assertTrue("Failed to delete output directory for test: "+ testRootDir.getPath(), testRootDir.delete());
assertTrue("Failed to delete output directory for test: " + testRootDir.getPath(), testRootDir.delete());
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
# Thrift Tutorial
# Mark Slee (mcslee@facebook.com)
#
# This file aims to teach you how to use Thrift, in a .thrift file. Neato. The
# first thing to notice is that .thrift files support standard shell comments.
# This lets you make your thrift file executable and include your Thrift build
# step on the top line. And you can place comments like this anywhere you like.
#
# Before running this file, you will need to have installed the thrift compiler
# into /usr/local/bin.
/**
* The first thing to know about are types. The available types in Thrift are:
*
* bool Boolean, one byte
* byte Signed byte
* i16 Signed 16-bit integer
* i32 Signed 32-bit integer
* i64 Signed 64-bit integer
* double 64-bit floating point value
* string String
* binary Blob (byte array)
* map<t1,t2> Map from one type to another
* list<t1> Ordered list of one type
* set<t1> Set of unique elements of one type
*
* Did you also notice that Thrift supports C style comments?
*/
// Just in case you were wondering... yes. We support simple C comments too.
/**
* Thrift files can reference other Thrift files to include common struct
* and service definitions. These are found using the current path, or by
* searching relative to any paths specified with the -I compiler flag.
*
* Included objects are accessed using the name of the .thrift file as a
* prefix. i.e. shared.SharedObject
*/
include "shared.thrift"
/**
* Thrift files can namespace, package, or prefix their output in various
* target languages.
*/
namespace cpp tutorial
namespace java tutorial
namespace php tutorial
namespace perl tutorial
namespace smalltalk.category Thrift.Tutorial
/**
* Thrift lets you do typedefs to get pretty names for your types. Standard
* C style here.
*/
typedef i32 MyInteger
/**
* Thrift also lets you define constants for use across languages. Complex
* types and structs are specified using JSON notation.
*/
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
/**
* You can define enums, which are just 32 bit integers. Values are optional
* and start at 1 if not supplied, C style again.
*/
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}
/**
* Structs are the basic complex data structures. They are comprised of fields
* which each have an integer identifier, a type, a symbolic name, and an
* optional default value.
*
* Fields can be declared "optional", which ensures they will not be included
* in the serialized output if they aren't set. Note that this requires some
* manual management in some languages.
*/
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}
/**
* Structs can also be exceptions, if they are nasty.
*/
exception InvalidOperation {
1: i32 what,
2: string why
}
/**
* Ahh, now onto the cool part, defining a service. Services just need a name
* and can optionally inherit from another service using the extends keyword.
*/
service Calculator extends shared.SharedService {
/**
* A method definition looks like C code. It has a return type, arguments,
* and optionally a list of exceptions that it may throw. Note that argument
* lists and exception lists are specified using the exact same syntax as
* field lists in struct or exception definitions.
*/
void ping(),
i32 add(1:i32 num1, 2:i32 num2),
i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
/**
* This method has a oneway modifier. That means the client only makes
* a request and does not listen for any response at all. Oneway methods
* must be void.
*/
oneway void zip()
}
/**
* That just about covers the basics. Take a look in the test/ folder for more
* detailed examples. After you run this file, your generated code shows up
* in folders with names gen-<language>. The generated code isn't too scary
* to look at. It even has pretty indentation.
*/
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