validate_file_or_folder.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. import argparse
  9. import fnmatch
  10. import os
  11. import sys
  12. from typing import Dict, List
  13. import difflib
  14. from commit_validation.commit_validation import Commit, validate_commit, IsFileSkipped, SOURCE_AND_SCRIPT_FILE_EXTENSIONS, EXCLUDED_VALIDATION_PATTERNS
  15. class FolderBased(Commit):
  16. """An implementation of the :class:`Commit` which populates it from files and folders on disk"""
  17. def __init__(self, item_path: str = '.') -> None:
  18. """Creates a new instance of :class:`FolderBased`
  19. :param item_path - The file name or the folder to search (recursively)
  20. """
  21. self.item_path = os.path.abspath(item_path)
  22. self.files: List[str] = []
  23. self.removed_files: List[str] = []
  24. self.file_diffs: Dict[str, str] = {}
  25. self._load_files()
  26. def _load_files(self):
  27. self.files = []
  28. self.removed_files = []
  29. # if its a file, we just add that file.
  30. # if its a folder, we add it recursively
  31. if os.path.isfile(self.item_path):
  32. self.files.append(self.item_path)
  33. else:
  34. engine_root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
  35. for root, _, file_names in os.walk(self.item_path):
  36. for file_name in file_names:
  37. file_to_scan = os.path.abspath(os.path.join(root, file_name))
  38. skip = False
  39. for excluded_folder in EXCLUDED_VALIDATION_PATTERNS:
  40. matcher = os.path.abspath(os.path.join(engine_root_path, excluded_folder, '*'))
  41. if fnmatch.fnmatch(file_to_scan, matcher):
  42. skip = True
  43. break
  44. if not skip:
  45. self.files.append(file_to_scan)
  46. def get_file_diff(self, file) -> str:
  47. if file in self.file_diffs:
  48. return self.file_diffs[file]
  49. # we count the entire file as changed in this mode
  50. # we do not include diffs for things that are not source files
  51. # this also prevents us trying to decode binary files as utf8
  52. if IsFileSkipped(file):
  53. return ""
  54. diff_being_built = ""
  55. # We simulate every line having been changed by making a blank file
  56. # being the 'from' and the whole file being the 'to' part of the diff
  57. with open(file, "rt", encoding='utf8', errors='replace') as opened_file:
  58. data = opened_file.readlines()
  59. diffs = difflib.unified_diff([], data, fromfile=file, tofile=file)
  60. diff_being_built = ''.join(diffs)
  61. self.file_diffs[file] = diff_being_built
  62. return diff_being_built
  63. def get_files(self) -> List[str]:
  64. return self.files
  65. def get_removed_files(self) -> List[str]:
  66. return self.removed_files
  67. def get_description(self) -> str:
  68. raise NotImplementedError
  69. def get_author(self) -> str:
  70. raise NotImplementedError
  71. def init_parser():
  72. """Prepares the command line parser"""
  73. parser = argparse.ArgumentParser()
  74. parser.add_argument('--path', default='.', help='Filename of single file, or a folder path to scan recursively')
  75. return parser
  76. def main():
  77. parser = init_parser()
  78. args = parser.parse_args()
  79. change = FolderBased(item_path = args.path)
  80. validators_to_ignore = [
  81. "NewlineValidator",
  82. "WhitespaceValidator"
  83. ]
  84. if not validate_commit(commit=change, ignore_validators = validators_to_ignore):
  85. sys.exit(1)
  86. sys.exit(0)
  87. if __name__ == '__main__':
  88. main()