Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
a5f7bb8e
Commit
a5f7bb8e
authored
Mar 08, 2015
by
Paul Yang
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #193 from TeBoring/sb
Implement a feature to generate a dependency file
parents
88eda4d7
eb2ce029
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
215 additions
and
2 deletions
+215
-2
command_line_interface.cc
src/google/protobuf/compiler/command_line_interface.cc
+112
-2
command_line_interface.h
src/google/protobuf/compiler/command_line_interface.h
+12
-0
command_line_interface_unittest.cc
...ogle/protobuf/compiler/command_line_interface_unittest.cc
+84
-0
file.cc
src/google/protobuf/testing/file.cc
+4
-0
file.h
src/google/protobuf/testing/file.h
+3
-0
No files found.
src/google/protobuf/compiler/command_line_interface.cc
View file @
a5f7bb8e
...
...
@@ -48,7 +48,6 @@
#include <iostream>
#include <ctype.h>
#include <google/protobuf/stubs/hash.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
...
...
@@ -255,6 +254,9 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
// format, unless one has already been written.
void
AddJarManifest
();
// Get name of all output files.
void
GetOutputFilenames
(
vector
<
string
>*
output_filenames
);
// implements GeneratorContext --------------------------------------
io
::
ZeroCopyOutputStream
*
Open
(
const
string
&
filename
);
io
::
ZeroCopyOutputStream
*
OpenForAppend
(
const
string
&
filename
);
...
...
@@ -442,6 +444,14 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
}
}
void
CommandLineInterface
::
GeneratorContextImpl
::
GetOutputFilenames
(
vector
<
string
>*
output_filenames
)
{
for
(
map
<
string
,
string
*>::
iterator
iter
=
files_
.
begin
();
iter
!=
files_
.
end
();
++
iter
)
{
output_filenames
->
push_back
(
iter
->
first
);
}
}
io
::
ZeroCopyOutputStream
*
CommandLineInterface
::
GeneratorContextImpl
::
Open
(
const
string
&
filename
)
{
return
new
MemoryOutputStream
(
this
,
filename
,
false
);
...
...
@@ -673,7 +683,6 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
// We construct a separate GeneratorContext for each output location. Note
// that two code generators may output to the same location, in which case
// they should share a single GeneratorContext so that OpenForInsert() works.
typedef
hash_map
<
string
,
GeneratorContextImpl
*>
GeneratorContextMap
;
GeneratorContextMap
output_directories
;
// Generate output.
...
...
@@ -720,6 +729,13 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
}
}
if
(
!
dependency_out_name_
.
empty
())
{
if
(
!
GenerateDependencyManifestFile
(
parsed_files
,
output_directories
,
&
source_tree
))
{
return
1
;
}
}
STLDeleteValues
(
&
output_directories
);
if
(
!
descriptor_set_name_
.
empty
())
{
...
...
@@ -778,6 +794,7 @@ void CommandLineInterface::Clear() {
output_directives_
.
clear
();
codec_type_
.
clear
();
descriptor_set_name_
.
clear
();
dependency_out_name_
.
clear
();
mode_
=
MODE_COMPILE
;
print_mode_
=
PRINT_NONE
;
...
...
@@ -880,6 +897,15 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
std
::
cerr
<<
"Missing output directives."
<<
std
::
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
if
(
mode_
!=
MODE_COMPILE
&&
!
dependency_out_name_
.
empty
())
{
cerr
<<
"Can only use --dependency_out=FILE when generating code."
<<
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
if
(
!
dependency_out_name_
.
empty
()
&&
input_files_
.
size
()
>
1
)
{
cerr
<<
"Can only process one input file when using --dependency_out=FILE."
<<
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
if
(
imports_in_descriptor_set_
&&
descriptor_set_name_
.
empty
())
{
std
::
cerr
<<
"--include_imports only makes sense when combined with "
"--descriptor_set_out."
<<
std
::
endl
;
...
...
@@ -1026,6 +1052,17 @@ CommandLineInterface::InterpretArgument(const string& name,
}
descriptor_set_name_
=
value
;
}
else
if
(
name
==
"--dependency_out"
)
{
if
(
!
dependency_out_name_
.
empty
())
{
cerr
<<
name
<<
" may only be passed once."
<<
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
if
(
value
.
empty
())
{
cerr
<<
name
<<
" requires a non-empty value."
<<
endl
;
return
PARSE_ARGUMENT_FAIL
;
}
dependency_out_name_
=
value
;
}
else
if
(
name
==
"--include_imports"
)
{
if
(
imports_in_descriptor_set_
)
{
std
::
cerr
<<
name
<<
" may only be passed once."
<<
std
::
endl
;
...
...
@@ -1225,6 +1262,9 @@ void CommandLineInterface::PrintHelpText() {
" include information about the original
\n
"
" location of each decl in the source file as
\n
"
" well as surrounding comments.
\n
"
" --dependency_out=FILE Write a dependency output file in the format
\n
"
" expected by make. This writes the transitive
\n
"
" set of input file paths to FILE
\n
"
" --error_format=FORMAT Set the format in which to print errors.
\n
"
" FORMAT may be 'gcc' (the default) or 'msvs'
\n
"
" (Microsoft Visual Studio format).
\n
"
...
...
@@ -1301,6 +1341,76 @@ bool CommandLineInterface::GenerateOutput(
return
true
;
}
bool
CommandLineInterface
::
GenerateDependencyManifestFile
(
const
vector
<
const
FileDescriptor
*>&
parsed_files
,
const
GeneratorContextMap
&
output_directories
,
DiskSourceTree
*
source_tree
)
{
FileDescriptorSet
file_set
;
set
<
const
FileDescriptor
*>
already_seen
;
for
(
int
i
=
0
;
i
<
parsed_files
.
size
();
i
++
)
{
GetTransitiveDependencies
(
parsed_files
[
i
],
false
,
&
already_seen
,
file_set
.
mutable_file
());
}
vector
<
string
>
output_filenames
;
for
(
GeneratorContextMap
::
const_iterator
iter
=
output_directories
.
begin
();
iter
!=
output_directories
.
end
();
++
iter
)
{
const
string
&
location
=
iter
->
first
;
GeneratorContextImpl
*
directory
=
iter
->
second
;
vector
<
string
>
relative_output_filenames
;
directory
->
GetOutputFilenames
(
&
relative_output_filenames
);
for
(
int
i
=
0
;
i
<
relative_output_filenames
.
size
();
i
++
)
{
string
output_filename
=
location
+
relative_output_filenames
[
i
];
if
(
output_filename
.
compare
(
0
,
2
,
"./"
)
==
0
)
{
output_filename
=
output_filename
.
substr
(
2
);
}
output_filenames
.
push_back
(
output_filename
);
}
}
int
fd
;
do
{
fd
=
open
(
dependency_out_name_
.
c_str
(),
O_WRONLY
|
O_CREAT
|
O_TRUNC
|
O_BINARY
,
0666
);
}
while
(
fd
<
0
&&
errno
==
EINTR
);
if
(
fd
<
0
)
{
perror
(
dependency_out_name_
.
c_str
());
return
false
;
}
io
::
FileOutputStream
out
(
fd
);
io
::
Printer
printer
(
&
out
,
'$'
);
for
(
int
i
=
0
;
i
<
output_filenames
.
size
();
i
++
)
{
printer
.
Print
(
output_filenames
[
i
].
c_str
());
if
(
i
==
output_filenames
.
size
()
-
1
)
{
printer
.
Print
(
":"
);
}
else
{
printer
.
Print
(
"
\\\n
"
);
}
}
for
(
int
i
=
0
;
i
<
file_set
.
file_size
();
i
++
)
{
const
FileDescriptorProto
&
file
=
file_set
.
file
(
i
);
const
string
&
virtual_file
=
file
.
name
();
string
disk_file
;
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
;
}
}
return
true
;
}
bool
CommandLineInterface
::
GeneratePluginOutput
(
const
vector
<
const
FileDescriptor
*>&
parsed_files
,
const
string
&
plugin_name
,
...
...
src/google/protobuf/compiler/command_line_interface.h
View file @
a5f7bb8e
...
...
@@ -39,6 +39,7 @@
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/hash.h>
#include <string>
#include <vector>
#include <map>
...
...
@@ -190,6 +191,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
class
ErrorPrinter
;
class
GeneratorContextImpl
;
class
MemoryOutputStream
;
typedef
hash_map
<
string
,
GeneratorContextImpl
*>
GeneratorContextMap
;
// Clear state from previous Run().
void
Clear
();
...
...
@@ -247,6 +249,12 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// Implements the --descriptor_set_out option.
bool
WriteDescriptorSet
(
const
vector
<
const
FileDescriptor
*>
parsed_files
);
// Implements the --dependency_out option
bool
GenerateDependencyManifestFile
(
const
vector
<
const
FileDescriptor
*>&
parsed_files
,
const
GeneratorContextMap
&
output_directories
,
DiskSourceTree
*
source_tree
);
// Get all transitive dependencies of the given file (including the file
// itself), adding them to the given list of FileDescriptorProtos. The
// protos will be ordered such that every file is listed before any file that
...
...
@@ -353,6 +361,10 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// FileDescriptorSet should be written. Otherwise, empty.
string
descriptor_set_name_
;
// If --dependency_out was given, this is the path to the file where the
// dependency file will be written. Otherwise, empty.
string
dependency_out_name_
;
// True if --include_imports was given, meaning that we should
// write all transitive dependencies to the DescriptorSet. Otherwise, only
// the .proto files listed on the command-line are added.
...
...
src/google/protobuf/compiler/command_line_interface_unittest.cc
View file @
a5f7bb8e
...
...
@@ -115,6 +115,11 @@ class CommandLineInterfaceTest : public testing::Test {
// Create a subdirectory within temp_directory_.
void
CreateTempDir
(
const
string
&
name
);
// Change working directory to temp directory.
void
SwitchToTempDirectory
()
{
File
::
ChangeWorkingDirectory
(
temp_directory_
);
}
void
SetInputsAreProtoPathRelative
(
bool
enable
)
{
cli_
.
SetInputsAreProtoPathRelative
(
enable
);
}
...
...
@@ -179,6 +184,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_
;
...
...
@@ -459,6 +467,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
)
{
...
...
@@ -943,6 +962,71 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
EXPECT_TRUE
(
descriptor_set
.
file
(
1
).
has_source_code_info
());
}
TEST_F
(
CommandLineInterfaceTest
,
WriteDependencyManifestFileGivenTwoInputs
)
{
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_out=$tmpdir/manifest "
"--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto"
);
ExpectErrorText
(
"Can only process one input file when using --dependency_out=FILE.
\n
"
);
}
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
"
);
string
current_working_directory
=
get_current_dir_name
();
SwitchToTempDirectory
();
Run
(
"protocol_compiler --dependency_out=manifest --test_out=. "
"bar.proto"
);
ExpectNoErrors
();
ExpectFileContent
(
"manifest"
,
"bar.proto.MockCodeGenerator.test_generator: "
"foo.proto
\\\n
bar.proto"
);
File
::
ChangeWorkingDirectory
(
current_working_directory
);
}
TEST_F
(
CommandLineInterfaceTest
,
WriteDependencyManifestFileForAbsolutePath
)
{
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_out=$tmpdir/manifest "
"--test_out=$tmpdir --proto_path=$tmpdir bar.proto"
);
ExpectNoErrors
();
ExpectFileContent
(
"manifest"
,
"$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
"$tmpdir/foo.proto
\\\n
$tmpdir/bar.proto"
);
}
// -------------------------------------------------------------------
TEST_F
(
CommandLineInterfaceTest
,
ParseErrors
)
{
...
...
src/google/protobuf/testing/file.cc
View file @
a5f7bb8e
...
...
@@ -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
src/google/protobuf/testing/file.h
View file @
a5f7bb8e
...
...
@@ -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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment