From 108379310ddaa4892ba3db95220b302c62c8b79a Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Thu, 30 Mar 2023 21:48:05 +0000 Subject: [PATCH] Create a python script to list files given a directory as an input The script will be used in generating a file that lists generated stub files from metalava, which will be passed to soong_zip to extract selected stub files when generating stubs from java_api_library modules with incomplete api surface text files. Test: build java_api_library modules in aosp/2487335 Change-Id: I36b830f14c714315f81e3fd8608d84c29f673f83 --- tools/Android.bp | 8 ++++ tools/list_files.py | 102 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 tools/list_files.py diff --git a/tools/Android.bp b/tools/Android.bp index c5c02c6215..f170336fab 100644 --- a/tools/Android.bp +++ b/tools/Android.bp @@ -85,3 +85,11 @@ python_binary_host { "libprotobuf-python", ], } + +python_binary_host { + name: "list_files", + main: "list_files.py", + srcs: [ + "list_files.py", + ], +} diff --git a/tools/list_files.py b/tools/list_files.py new file mode 100644 index 0000000000..3afa81faae --- /dev/null +++ b/tools/list_files.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# +# Copyright (C) 2023 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. + +from typing import List +from glob import glob +from pathlib import Path +from os.path import join, relpath +import argparse + +class FileLister: + def __init__(self, args) -> None: + self.out_file = args.out_file + + self.folder_dir = args.dir + self.extensions = [e if e.startswith(".") else "." + e for e in args.extensions] + self.root = args.root + self.files_list = list() + + def get_files(self) -> None: + """Get all files directory in the input directory including the files in the subdirectories + + Recursively finds all files in the input directory. + Set file_list as a list of file directory strings, + which do not include directories but only files. + List is sorted in alphabetical order of the file directories. + + Args: + dir: Directory to get the files. String. + + Raises: + FileNotFoundError: An error occurred accessing the non-existing directory + """ + + if not dir_exists(self.folder_dir): + raise FileNotFoundError(f"Directory {self.folder_dir} does not exist") + + if self.folder_dir[:-2] != "**": + self.folder_dir = join(self.folder_dir, "**") + + self.files_list = list() + for file in sorted(glob(self.folder_dir, recursive=True)): + if Path(file).is_file(): + if self.root: + file = join(self.root, relpath(file, self.folder_dir[:-2])) + self.files_list.append(file) + + + def list(self) -> None: + self.get_files() + self.files_list = [f for f in self.files_list if not self.extensions or Path(f).suffix in self.extensions] + self.write() + + def write(self) -> None: + if self.out_file == "": + pprint(self.files_list) + else: + write_lines(self.out_file, self.files_list) + +### +# Helper functions +### +def pprint(l: List[str]) -> None: + for line in l: + print(line) + +def dir_exists(dir: str) -> bool: + return Path(dir).exists() + +def write_lines(out_file: str, lines: List[str]) -> None: + with open(out_file, "w+") as f: + f.writelines(line + '\n' for line in lines) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('dir', action='store', type=str, + help="directory to list all subdirectory files") + parser.add_argument('--out', dest='out_file', + action='store', default="", type=str, + help="optional directory to write subdirectory files. If not set, will print to console") + parser.add_argument('--root', dest='root', + action='store', default="", type=str, + help="optional directory to replace the root directories of output.") + parser.add_argument('--extensions', nargs='*', default=list(), dest='extensions', + help="Extensions to include in the output. If not set, all files are included") + + args = parser.parse_args() + + file_lister = FileLister(args) + file_lister.list()