Skip to content

Commit 2f89abd

Browse files
committed
Adding Makefile to generate pb2 files from Bigtable protos.
1 parent 09b3580 commit 2f89abd

4 files changed

Lines changed: 289 additions & 0 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,7 @@ pylintrc_reduced
5252

5353
# Travis build directories.
5454
gcloud-python-wheels/
55+
56+
# Directories used for creating generated PB2 files
57+
generated_python/
58+
cloud-bigtable-client/

Makefile

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
GENERATED_DIR=$(shell pwd)/generated_python
2+
FINAL_DIR=gcloud/bigtable/_generated
3+
BREW_PREFIX=$(shell brew --prefix)
4+
LD_LIBRARY_PATH=$(BREW_PREFIX)/lib
5+
GRPC_PLUGIN=$(BREW_PREFIX)/bin/grpc_python_plugin
6+
7+
help:
8+
@echo 'Makefile for gcloud-python Bigtable protos '
9+
@echo ' '
10+
@echo ' make generate Generates the protobuf modules '
11+
@echo ' make check_generate Checks that generate succeeded '
12+
@echo ' make clean Clean generated files '
13+
14+
generate:
15+
[ -d cloud-bigtable-client ] || git clone https://github.com/GoogleCloudPlatform/cloud-bigtable-client
16+
cd cloud-bigtable-client && git pull origin master
17+
mkdir -p $(GENERATED_DIR)
18+
# Data API
19+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
20+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
21+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) google/bigtable/v1/*.proto
22+
mv $(GENERATED_DIR)/google/bigtable/v1/* $(FINAL_DIR)
23+
# Cluster API
24+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
25+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
26+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
27+
google/bigtable/admin/cluster/v1/*.proto
28+
mv $(GENERATED_DIR)/google/bigtable/admin/cluster/v1/* $(FINAL_DIR)
29+
# Table API
30+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
31+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
32+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
33+
google/bigtable/admin/table/v1/*.proto
34+
mv $(GENERATED_DIR)/google/bigtable/admin/table/v1/* $(FINAL_DIR)
35+
# Auxiliary protos
36+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
37+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
38+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
39+
google/api/*.proto
40+
mv $(GENERATED_DIR)/google/api/* $(FINAL_DIR)
41+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
42+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
43+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
44+
google/protobuf/any.proto
45+
mv $(GENERATED_DIR)/google/protobuf/any_pb2.py $(FINAL_DIR)
46+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
47+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
48+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
49+
google/protobuf/duration.proto
50+
mv $(GENERATED_DIR)/google/protobuf/duration_pb2.py $(FINAL_DIR)
51+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
52+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
53+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
54+
google/protobuf/empty.proto
55+
mv $(GENERATED_DIR)/google/protobuf/empty_pb2.py $(FINAL_DIR)
56+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
57+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
58+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
59+
google/protobuf/timestamp.proto
60+
mv $(GENERATED_DIR)/google/protobuf/timestamp_pb2.py $(FINAL_DIR)
61+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
62+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
63+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
64+
google/longrunning/operations.proto
65+
mv $(GENERATED_DIR)/google/longrunning/operations_pb2.py $(FINAL_DIR)
66+
cd cloud-bigtable-client/bigtable-protos/src/main/proto && \
67+
protoc --python_out=$(GENERATED_DIR) --grpc_out=$(GENERATED_DIR) \
68+
--plugin=protoc-gen-grpc=$(GRPC_PLUGIN) \
69+
google/rpc/status.proto
70+
mv $(GENERATED_DIR)/google/rpc/status_pb2.py $(FINAL_DIR)
71+
python scripts/rewrite_imports.py
72+
73+
check_generate:
74+
python scripts/check_generate.py
75+
76+
clean:
77+
rm -fr cloud-bigtable-client $(GENERATED_DIR)
78+
79+
.PHONY: generate check_generate clean

scripts/check_generate.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Checking that protobuf generated modules import correctly."""
16+
17+
from __future__ import print_function
18+
19+
import glob
20+
import os
21+
22+
23+
def main():
24+
"""Import all PB2 files."""
25+
print('>>> import gcloud.bigtable._generated')
26+
_ = __import__('gcloud.bigtable._generated')
27+
pb2_files = sorted(glob.glob('gcloud/bigtable/_generated/*pb2.py'))
28+
for filename in pb2_files:
29+
basename = os.path.basename(filename)
30+
module_name, _ = os.path.splitext(basename)
31+
32+
print('>>> from gcloud.bigtable._generated import ' + module_name)
33+
_ = __import__('gcloud.bigtable._generated', fromlist=[module_name])
34+
35+
36+
if __name__ == '__main__':
37+
main()

scripts/rewrite_imports.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Build script for rewriting imports for protobuf generated modules.
16+
17+
Intended to be used for Google Cloud Bigtable protos (google/bigtable/v1)
18+
and the dependent modules (google/api and google/protobuf).
19+
"""
20+
21+
import glob
22+
23+
24+
IMPORT_TEMPLATE = 'import %s'
25+
IMPORT_FROM_TEMPLATE = 'from %s import '
26+
PROTOBUF_IMPORT_TEMPLATE = 'from google.protobuf import %s '
27+
REPLACE_PROTOBUF_IMPORT_TEMPLATE = 'from gcloud.bigtable._generated import %s '
28+
REPLACEMENTS = {
29+
'google.api': 'gcloud.bigtable._generated',
30+
'google.bigtable.admin.cluster.v1': 'gcloud.bigtable._generated',
31+
'google.bigtable.admin.table.v1': 'gcloud.bigtable._generated',
32+
'google.bigtable.v1': 'gcloud.bigtable._generated',
33+
'google.longrunning': 'gcloud.bigtable._generated',
34+
'google.rpc': 'gcloud.bigtable._generated',
35+
}
36+
GOOGLE_PROTOBUF_CUSTOM = (
37+
'any_pb2',
38+
'duration_pb2',
39+
'empty_pb2',
40+
'timestamp_pb2',
41+
)
42+
43+
44+
def transform_old_to_new(line, old_module, new_module,
45+
ignore_import_from=False):
46+
"""Transforms from an old module to a new one.
47+
48+
First checks if a line starts with
49+
"from {old_module} import ..."
50+
then checks if the line contains
51+
"import {old_module} ..."
52+
and finally checks if the line starts with (ignoring whitespace)
53+
"{old_module} ..."
54+
55+
In any of these cases, "{old_module}" is replaced with "{new_module}".
56+
If none match, nothing is returned.
57+
58+
:type line: str
59+
:param line: The line to be transformed.
60+
61+
:type old_module: str
62+
:param old_module: The import to be re-written.
63+
64+
:type new_module: str
65+
:param new_module: The new location of the re-written import.
66+
67+
:type ignore_import_from: bool
68+
:param ignore_import_from: Flag to determine if the "from * import"
69+
statements should be ignored.
70+
71+
:rtype: :class:`str` or :data:`NoneType <types.NoneType>`
72+
:returns: The transformed line if the old module was found, otherwise
73+
does nothing.
74+
"""
75+
if not ignore_import_from:
76+
import_from_statement = IMPORT_FROM_TEMPLATE % (old_module,)
77+
if line.startswith(import_from_statement):
78+
new_import_from_statement = IMPORT_FROM_TEMPLATE % (new_module,)
79+
# Only replace the first instance of the import statement.
80+
return line.replace(import_from_statement,
81+
new_import_from_statement, 1)
82+
83+
# If the line doesn't start with a "from * import *" statement, it
84+
# may still contain a "import * ..." statement.
85+
import_statement = IMPORT_TEMPLATE % (old_module,)
86+
if import_statement in line:
87+
new_import_statement = IMPORT_TEMPLATE % (new_module,)
88+
# Only replace the first instance of the import statement.
89+
return line.replace(import_statement,
90+
new_import_statement, 1)
91+
92+
# Also need to change references to the standalone imports. As a
93+
# stop-gap we fix references to them at the beginning of a line
94+
# (ignoring whitespace).
95+
if line.lstrip().startswith(old_module):
96+
# Only replace the first instance of the old_module.
97+
return line.replace(old_module, new_module, 1)
98+
99+
100+
def transform_line(line):
101+
"""Transforms an import line in a PB2 module.
102+
103+
If the line is not an import of one of the packages in
104+
``REPLACEMENTS`` or ``GOOGLE_PROTOBUF_CUSTOM``, does nothing and returns
105+
the original. Otherwise it replaces the package matched with our local
106+
package or directly rewrites the custom ``google.protobuf`` import
107+
statement.
108+
109+
:type line: str
110+
:param line: The line to be transformed.
111+
112+
:rtype: str
113+
:returns: The transformed line.
114+
"""
115+
for old_module, new_module in REPLACEMENTS.iteritems():
116+
result = transform_old_to_new(line, old_module, new_module)
117+
if result is not None:
118+
return result
119+
120+
for custom_protobuf_module in GOOGLE_PROTOBUF_CUSTOM:
121+
# We don't use the "from * import" check in transform_old_to_new
122+
# because part of `google.protobuf` comes from the installed
123+
# `protobuf` library.
124+
import_from_statement = PROTOBUF_IMPORT_TEMPLATE % (
125+
custom_protobuf_module,)
126+
if line.startswith(import_from_statement):
127+
new_import_from_statement = REPLACE_PROTOBUF_IMPORT_TEMPLATE % (
128+
custom_protobuf_module,)
129+
# Only replace the first instance of the import statement.
130+
return line.replace(import_from_statement,
131+
new_import_from_statement, 1)
132+
133+
old_module = 'google.protobuf.' + custom_protobuf_module
134+
new_module = 'gcloud.bigtable._generated.' + custom_protobuf_module
135+
result = transform_old_to_new(line, old_module, new_module,
136+
ignore_import_from=True)
137+
if result is not None:
138+
return result
139+
140+
# If no matches, there is nothing to transform.
141+
return line
142+
143+
144+
def rewrite_file(filename):
145+
"""Rewrites a given PB2 modules.
146+
147+
:type filename: str
148+
:param filename: The name of the file to be rewritten.
149+
"""
150+
with open(filename, 'rU') as file_obj:
151+
content_lines = file_obj.read().split('\n')
152+
153+
new_content = []
154+
for line in content_lines:
155+
new_content.append(transform_line(line))
156+
157+
with open(filename, 'w') as file_obj:
158+
file_obj.write('\n'.join(new_content))
159+
160+
161+
def main():
162+
"""Rewrites all PB2 files."""
163+
pb2_files = glob.glob('gcloud/bigtable/_generated/*pb2.py')
164+
for filename in pb2_files:
165+
rewrite_file(filename)
166+
167+
168+
if __name__ == '__main__':
169+
main()

0 commit comments

Comments
 (0)