diff options
author | Bo Yang <paulyang1211@gmail.com> | 2015-02-03 21:35:50 -0800 |
---|---|---|
committer | Bo Yang <paulyang1211@gmail.com> | 2015-02-03 21:35:50 -0800 |
commit | 5914ce7a160a82db1490e99c45c95c69417b20ea (patch) | |
tree | fdd9219543de9caf2490a1bcc10ef62ffe27d254 /src | |
parent | 532c94145b6605361513682601f1d8e9f97a2497 (diff) | |
download | protobuf-5914ce7a160a82db1490e99c45c95c69417b20ea.tar.gz protobuf-5914ce7a160a82db1490e99c45c95c69417b20ea.tar.bz2 protobuf-5914ce7a160a82db1490e99c45c95c69417b20ea.zip |
Implement a feature to generate a dependency file. By giving protoc the flag
"--dependency_manifest_out=FILE", protoc will write dependencies of
input proto files into FILE. In FILE, the format will be
<full path to FILE>: <full path to 1st proto>\\\n <full path to 2nd proto> ...
This cl is based on https://github.com/google/protobuf/pull/178
Diffstat (limited to 'src')
-rw-r--r-- | src/google/protobuf/compiler/command_line_interface.cc | 55 | ||||
-rw-r--r-- | src/google/protobuf/compiler/command_line_interface.h | 2 | ||||
-rw-r--r-- | src/google/protobuf/compiler/command_line_interface_unittest.cc | 65 | ||||
-rw-r--r-- | src/google/protobuf/testing/file.cc | 4 | ||||
-rw-r--r-- | src/google/protobuf/testing/file.h | 3 |
5 files changed, 99 insertions, 30 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 649aa42d..1a182f73 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -726,7 +726,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { } } - if (!manifest_name_.empty()) { + if (!dependency_manifest_name_.empty()) { if (!GenerateDependencyManifestFile(parsed_files, &source_tree)) { return 1; } @@ -782,7 +782,7 @@ void CommandLineInterface::Clear() { output_directives_.clear(); codec_type_.clear(); descriptor_set_name_.clear(); - manifest_name_.clear(); + dependency_manifest_name_.clear(); mode_ = MODE_COMPILE; print_mode_ = PRINT_NONE; @@ -1020,8 +1020,8 @@ CommandLineInterface::InterpretArgument(const string& name, } descriptor_set_name_ = value; - } else if (name == "--manifest-file") { - if (!manifest_name_.empty()) { + } else if (name == "--dependency_manifest_out") { + if (!dependency_manifest_name_.empty()) { cerr << name << " may only be passed once." << endl; return PARSE_ARGUMENT_FAIL; } @@ -1034,7 +1034,7 @@ CommandLineInterface::InterpretArgument(const string& name, "same time." << endl; return PARSE_ARGUMENT_FAIL; } - manifest_name_ = value; + dependency_manifest_name_ = value; } else if (name == "--include_imports") { if (imports_in_descriptor_set_) { @@ -1323,48 +1323,45 @@ bool CommandLineInterface::GenerateDependencyManifestFile( int fd; do { - fd = open(manifest_name_.c_str(), + fd = open(dependency_manifest_name_.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); } while (fd < 0 && errno == EINTR); if (fd < 0) { - perror(manifest_name_.c_str()); + perror(dependency_manifest_name_.c_str()); return false; } - stringstream ss; - string output_filename = manifest_name_; - if (output_filename.compare(0, 2, "./") == 0) { - output_filename = output_filename.substr(2); + io::FileOutputStream out(fd); + io::Printer printer(&out, '$'); + + string output_filename = dependency_manifest_name_; + if (output_filename.compare(0, 1, "/") != 0) { + // Convert relative path to absolute path before print. + printer.Print("$working_directory$/$output_filename$:", + "working_directory", get_current_dir_name(), + "output_filename",output_filename); + } else { + printer.Print("$output_filename$:", + "output_filename",output_filename); } - ss << output_filename << ": "; - for (set<const FileDescriptor*>::const_iterator it = already_seen.begin(); it != already_seen.end(); ++it ) { - string virtual_file = (*it)->name(); + for (int i = 0; i < file_set.file_size(); i++) { + const FileDescriptorProto& file = file_set.file(i); + string virtual_file = file.name(); string disk_file; - if (source_tree && source_tree->VirtualFileToDiskFile(virtual_file, &disk_file) ) { - ss << " " << disk_file << " \\" << endl; + if (source_tree && + source_tree->VirtualFileToDiskFile(virtual_file, &disk_file)) { + printer.Print(" $disk_file$", "disk_file", disk_file); + if (i < file_set.file_size() - 1) printer.Print("\\\n"); } else { cerr << "Unable to identify path for file " << virtual_file << endl; return false; } } - - string manifest_contents = ss.str(); - if ( write(fd, manifest_contents.c_str(), manifest_contents.size()) != manifest_contents.size() ) { - cerr << "Error when writing to " << manifest_name_ << endl; - return false; - } - - int rv = ::close(fd); - if ( rv != 0 ) { - cerr << manifest_name_ << ": " << strerror(rv) << endl; - return false; - } return true; } - bool CommandLineInterface::GeneratePluginOutput( const vector<const FileDescriptor*>& parsed_files, const string& plugin_name, diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index 59d57fbf..1b657f5e 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -360,7 +360,7 @@ class LIBPROTOC_EXPORT CommandLineInterface { // If --manifest_file was given, this is the filename to which the input // file should be written. Otherwise, empty. - string manifest_name_; + string dependency_manifest_name_; // True if --include_imports was given, meaning that we should // write all transitive dependencies to the DescriptorSet. Otherwise, only diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index dbaaa405..e7cfff6b 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -116,6 +116,10 @@ class CommandLineInterfaceTest : public testing::Test { cli_.SetInputsAreProtoPathRelative(enable); } + string GetTempDirectory() { + return temp_directory_; + } + // ----------------------------------------------------------------- // Methods to check the test results (called after Run()). @@ -176,6 +180,9 @@ class CommandLineInterfaceTest : public testing::Test { void ReadDescriptorSet(const string& filename, FileDescriptorSet* descriptor_set); + void ExpectFileContent(const string& filename, + const string& content); + private: // The object we are testing. CommandLineInterface cli_; @@ -456,6 +463,17 @@ void CommandLineInterfaceTest::ExpectCapturedStdout( EXPECT_EQ(expected_text, captured_stdout_); } + +void CommandLineInterfaceTest::ExpectFileContent( + const string& filename, const string& content) { + string path = temp_directory_ + "/" + filename; + string file_contents; + GOOGLE_CHECK_OK(File::GetContents(path, &file_contents, true)); + + EXPECT_EQ(StringReplace(content, "$tmpdir", temp_directory_, true), + file_contents); +} + // =================================================================== TEST_F(CommandLineInterfaceTest, BasicOutput) { @@ -940,6 +958,53 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) { EXPECT_TRUE(descriptor_set.file(1).has_source_code_info()); } +TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --dependency_manifest_out=$tmpdir/manifest " + "--test_out=$tmpdir --proto_path=$tmpdir bar.proto"); + + ExpectNoErrors(); + + ExpectFileContent("manifest", + "$tmpdir/manifest: $tmpdir/foo.proto\\\n" + " $tmpdir/bar.proto"); +} + +TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForRelativePath) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + + string current_working_directory = get_current_dir_name(); + File::ChangeWorkingDirectory(GetTempDirectory()); + + Run("protocol_compiler --dependency_manifest_out=manifest " + "--test_out=$tmpdir --proto_path=$tmpdir bar.proto"); + + ExpectNoErrors(); + + ExpectFileContent("manifest", + "$tmpdir/manifest: $tmpdir/foo.proto\\\n" + " $tmpdir/bar.proto"); + + File::ChangeWorkingDirectory(current_working_directory); +} + // ------------------------------------------------------------------- TEST_F(CommandLineInterfaceTest, ParseErrors) { diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc index 5344ec15..3d07b127 100644 --- a/src/google/protobuf/testing/file.cc +++ b/src/google/protobuf/testing/file.cc @@ -192,5 +192,9 @@ void File::DeleteRecursively(const string& name, #endif } +bool File::ChangeWorkingDirectory(const string& new_working_directory) { + return chdir(new_working_directory.c_str()) == 0; +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/testing/file.h b/src/google/protobuf/testing/file.h index d2aeabf2..2f63f80e 100644 --- a/src/google/protobuf/testing/file.h +++ b/src/google/protobuf/testing/file.h @@ -77,6 +77,9 @@ class File { static void DeleteRecursively(const string& name, void* dummy1, void* dummy2); + // Change working directory to given directory. + static bool ChangeWorkingDirectory(const string& new_working_directory); + static bool GetContents( const string& name, string* output, bool /*is_default*/) { return ReadFileToString(name, output); |