blob: e2a6401080045f2f73d1087f33f4445a42e070f9 [file] [log] [blame]
Jimi Chendcbe9b42025-05-28 09:33:18 +00001#!/usr/bin/env python3
2# Copyright 2025, The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""Preupload hook to perform necessary checks and formatting on python files."""
17
18import argparse
19import concurrent.futures
20import multiprocessing
21import pathlib
22import shlex
23import subprocess
24import sys
25
26
27def _filter_python_files(files: list[pathlib.Path]) -> list[pathlib.Path]:
28 """Filter a list of files and return a new list of python files only."""
29 return [file for file in files if file.suffix == '.py']
30
31
32def _check_run_shell_command(cmd: str, cwd: str = None) -> None:
33 """Run a shell command and raise error if failed."""
34 if subprocess.run(shlex.split(cmd), cwd=cwd, check=False).returncode:
35 print('Preupload files did not pass Connectivity preupload hook script.')
36 sys.exit(1)
37
38
39def _run_pyformat(files: list[pathlib.Path]) -> None:
40 """Run pyformat on certain projects."""
41 if subprocess.run(
42 shlex.split('which pyformat'),
43 check=False,
44 ).returncode:
45 print('pyformat not available. Please run sudo apt install pyformat.')
46 sys.exit(1)
47
48 def _run_pyformat_on_file(file):
49 completed_process = subprocess.run(
50 shlex.split('pyformat --force_quote_type single ' + file.as_posix()),
51 capture_output=True,
52 check=False,
53 )
54
55 if completed_process.stdout:
56 subprocess.run(
57 shlex.split(
58 'pyformat -i --force_quote_type single ' + file.as_posix()
59 ),
60 check=False,
61 )
62 return True
63 return False
64
65 cpu_count = multiprocessing.cpu_count()
66 with concurrent.futures.ThreadPoolExecutor(max_workers=cpu_count) as executor:
67 need_reformat = executor.map(
68 _run_pyformat_on_file, _filter_python_files(files)
69 )
70
71 if any(need_reformat):
72 print(
73 'Reformatting completed. Please add the modified files to git and rerun'
74 ' the repo preupload hook.'
75 )
76 sys.exit(1)
77
78
79def get_preupload_files() -> list[pathlib.Path]:
80 """Get the list of files to be uploaded."""
81 parser = argparse.ArgumentParser()
82 parser.add_argument('preupload_files', nargs='*', help='Files to upload.')
83 args = parser.parse_args()
84 files_to_upload = args.preupload_files
85 file_paths_to_upload = [
86 pathlib.Path(file).resolve() for file in files_to_upload
87 ]
88 return [file for file in file_paths_to_upload if file.exists()]
89
90
91if __name__ == '__main__':
92 preupload_files = get_preupload_files()
93 _run_pyformat(preupload_files)