blob: cda0e3a0815dc68ff95a9ba1b9cf44715a16e597 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2019 - The Android Open Source Project
#
# Licensed 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.
import filecmp
import logging
import os
import shutil
import tempfile
from acts.libs.proc import job
from acts.libs.proto import proto_utils
COMMIT_ID_ENV_KEY = 'PREUPLOAD_COMMIT'
GIT_FILE_NAMES_CMD = 'git diff-tree --no-commit-id --name-only -r %s'
def proto_generates_gen_file(proto_file, proto_gen_file):
"""Check that the proto_gen_file matches the compilation result of the
proto_file.
Params:
proto_file: The proto file.
proto_gen_file: The generated file.
Returns: True if the compiled proto matches the given proto_gen_file.
"""
with tempfile.TemporaryDirectory() as tmp_dir:
module_name = proto_utils.compile_proto(proto_file, tmp_dir)
if not module_name:
return False
tmp_proto_gen_file = os.path.join(tmp_dir, '%s.py' % module_name)
return filecmp.cmp(tmp_proto_gen_file, proto_gen_file)
def verify_protos_update_generated_files(proto_files, proto_gen_files):
"""For each proto file in proto_files, find the corresponding generated
file in either proto_gen_files, or in the directory tree of the proto.
Verify that the generated file matches the compilation result of the proto.
Params:
proto_files: List of proto files.
proto_gen_files: List of generated files.
"""
success = True
gen_files = set(proto_gen_files)
for proto_file in proto_files:
gen_filename = os.path.basename(proto_file).replace('.proto', '_pb2.py')
gen_file = ''
# search the gen_files set first
for path in gen_files:
if (os.path.basename(path) == gen_filename
and path.startswith(os.path.dirname(proto_file))):
gen_file = path
gen_files.remove(path)
break
else:
# search the proto file's directory
for root, _, filenames in os.walk(os.path.dirname(proto_file)):
for filename in filenames:
if filename == gen_filename:
gen_file = os.path.join(root, filename)
break
if gen_file:
break
# check that the generated file matches the compiled proto
if gen_file and not proto_generates_gen_file(proto_file, gen_file):
logging.error('Proto file %s does not compile to %s'
% (proto_file, gen_file))
protoc = shutil.which('protoc')
if protoc:
protoc_command = ' '.join([
protoc, '-I=%s' % os.path.dirname(proto_file),
'--python_out=%s' % os.path.dirname(gen_file), proto_file])
logging.error('Run this command to re-generate file from proto'
'\n%s' % protoc_command)
success = False
# fail if there are unpaired gen_files
if gen_files:
logging.error('Generated *_pb2.py files modified without updating '
'source .proto files: \n\t%s' % '\n\t'.join(gen_files))
success = False
return success
def main():
if COMMIT_ID_ENV_KEY not in os.environ:
logging.error('Missing commit id in environment.')
exit(1)
# get list of *.proto and *_pb2.py files from commit, then compare
proto_files = []
proto_gen_files = []
git_cmd = GIT_FILE_NAMES_CMD % os.environ[COMMIT_ID_ENV_KEY]
files = job.run(git_cmd).stdout.splitlines()
for f in files:
if f.endswith('.proto'):
proto_files.append(os.path.abspath(f))
if f.endswith('_pb2.py'):
proto_gen_files.append(os.path.abspath(f))
exit(not verify_protos_update_generated_files(proto_files, proto_gen_files))
if __name__ == '__main__':
main()