Commit 5f12164f authored by kenton@google.com's avatar kenton@google.com

Refactor the way output is handled in CommandLineInterface -- now it will be…

Refactor the way output is handled in CommandLineInterface -- now it will be stored in-memory until all code generators have completed, then dumped to disk all at once.  While this means that protoc uses more memory, the code is much simpler, and handles insertions much faster.  Also, this made it easier to implement a useful feature:  insertions will be indented to match the insertion point line.  Therefore, when inserting into Python code, you don't have to figure out how much to indent your inserted code.  The refactoring should also make it easier to implement output-to-jar at some point.
parent 46ed74e8
...@@ -174,9 +174,9 @@ class LIBPROTOC_EXPORT CommandLineInterface { ...@@ -174,9 +174,9 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// ----------------------------------------------------------------- // -----------------------------------------------------------------
class ErrorPrinter; class ErrorPrinter;
class DiskOutputDirectory; class MemoryOutputDirectory;
class ErrorReportingFileOutput; class SubOutputDirectory;
class InsertionOutputStream; class MemoryOutputStream;
// Clear state from previous Run(). // Clear state from previous Run().
void Clear(); void Clear();
...@@ -212,7 +212,8 @@ class LIBPROTOC_EXPORT CommandLineInterface { ...@@ -212,7 +212,8 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// Generate the given output file from the given input. // Generate the given output file from the given input.
struct OutputDirective; // see below struct OutputDirective; // see below
bool GenerateOutput(const vector<const FileDescriptor*>& parsed_files, bool GenerateOutput(const vector<const FileDescriptor*>& parsed_files,
const OutputDirective& output_directive); const OutputDirective& output_directive,
OutputDirectory* parent_output_directory);
bool GeneratePluginOutput(const vector<const FileDescriptor*>& parsed_files, bool GeneratePluginOutput(const vector<const FileDescriptor*>& parsed_files,
const string& plugin_name, const string& plugin_name,
const string& parameter, const string& parameter,
......
...@@ -933,7 +933,10 @@ TEST_F(CommandLineInterfaceTest, OutputWriteError) { ...@@ -933,7 +933,10 @@ TEST_F(CommandLineInterfaceTest, OutputWriteError) {
Run("protocol_compiler --test_out=$tmpdir " Run("protocol_compiler --test_out=$tmpdir "
"--proto_path=$tmpdir foo.proto"); "--proto_path=$tmpdir foo.proto");
ExpectErrorSubstring("MockCodeGenerator detected write error."); // MockCodeGenerator no longer detects an error because we actually write to
// an in-memory location first, then dump to disk at the end. This is no
// big deal.
// ExpectErrorSubstring("MockCodeGenerator detected write error.");
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
// Windows with MSVCRT.dll produces EPERM instead of EISDIR. // Windows with MSVCRT.dll produces EPERM instead of EISDIR.
......
...@@ -50,7 +50,7 @@ static const char* kSecondInsertionPointName = "second_mock_insertion_point"; ...@@ -50,7 +50,7 @@ static const char* kSecondInsertionPointName = "second_mock_insertion_point";
static const char* kFirstInsertionPoint = static const char* kFirstInsertionPoint =
"# @@protoc_insertion_point(first_mock_insertion_point) is here\n"; "# @@protoc_insertion_point(first_mock_insertion_point) is here\n";
static const char* kSecondInsertionPoint = static const char* kSecondInsertionPoint =
"# @@protoc_insertion_point(second_mock_insertion_point) is here\n"; " # @@protoc_insertion_point(second_mock_insertion_point) is here\n";
MockCodeGenerator::MockCodeGenerator(const string& name) MockCodeGenerator::MockCodeGenerator(const string& name)
: name_(name) {} : name_(name) {}
...@@ -94,7 +94,9 @@ void MockCodeGenerator::ExpectGenerated( ...@@ -94,7 +94,9 @@ void MockCodeGenerator::ExpectGenerated(
EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert", EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
file, first_message_name), file, first_message_name),
lines[1 + i]); lines[1 + i]);
EXPECT_EQ(GetOutputFileContent(insertion_list[i], "second_insert", // Second insertion point is indented, so the inserted text should
// automatically be indented too.
EXPECT_EQ(" " + GetOutputFileContent(insertion_list[i], "second_insert",
file, first_message_name), file, first_message_name),
lines[2 + insertion_list.size() + i]); lines[2 + insertion_list.size() + i]);
} }
......
...@@ -123,6 +123,13 @@ message CodeGeneratorResponse { ...@@ -123,6 +123,13 @@ message CodeGeneratorResponse {
// insertion_point "package_level_decls" to generate additional classes or // insertion_point "package_level_decls" to generate additional classes or
// other declarations that should be placed in this scope. // other declarations that should be placed in this scope.
// //
// Note that if the line containing the insertion point begins with
// whitespace, the same whitespace will be added to every line of the
// inserted text. This is useful for languages like Python, where
// indentation matters. In these languages, the insertion point comment
// should be indented the same amount as any inserted code will need to be
// in order to work correctly in that context.
//
// If |insertion_point| is present, |name| must also be present. // If |insertion_point| is present, |name| must also be present.
optional string insertion_point = 2; optional string insertion_point = 2;
......
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