github.com/RedHatInsights/insights-content-service@v1.0.0/utils/json_check.py (about)

     1  # Copyright © 2020 Pavel Tisnovsky
     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  """
    16  Simple checker of all JSONs in the given directory (usually repository).
    17  
    18  Usage:
    19  -----
    20      json_check.py [-h] [-v] [-n] -d DIRECTORY
    21  
    22  Optional arguments:
    23  ------------------
    24      -h, --help       show this help message and exit
    25      -v, --verbose    make it verbose
    26      -n, --no-colors  disable color output
    27      -d DIRECTORY--directory DIRECTORY
    28                       directory with JSON files to check
    29  """
    30  
    31  # Link to generated documentation for this script:
    32  # -----------------------------------------------
    33  # <https://redhatinsights.github.io/insights-results-aggregator/json_check.html>
    34  
    35  from pathlib import Path
    36  from json import load
    37  from sys import exit
    38  from os import popen
    39  from argparse import ArgumentParser
    40  
    41  
    42  def read_control_code(operation):
    43      """Try to execute tput to read control code for selected operation."""
    44      return popen("tput " + operation, "r").readline()
    45  
    46  
    47  def check_jsons(verbose, directory):
    48      """Check all JSON files found in current directory and all subdirectories."""
    49      # Reset counters with number of passes and number of failures.
    50      passes = 0
    51      failures = 0
    52  
    53      # Find all files in current directory and subdirectories with `*.json`
    54      # extension. Files are found recursivelly.
    55      files = list(Path(directory).rglob("*.json"))
    56  
    57      # Iterate over all files found by previous command.
    58      for file in files:
    59          try:
    60              # If the file can be opened and loaded as JSON, everything is fine.
    61              with file.open() as fin:
    62                  # Try to load and parse the content of JSON file.
    63                  obj = load(fin)
    64                  # At this point the JSON has been loaded and parsed correctly.
    65                  if verbose is not None:
    66                      print("{} is valid".format(file))
    67  
    68                  passes += 1
    69          except ValueError as e:
    70              # There are several reasons and possibilities why the file can not
    71              # be read as JSON, so we just print the error message taken from
    72              # exception object.
    73              print("{} is invalid".format(file))
    74              failures += 1
    75              print(e)
    76  
    77      # Just the counters needs to be returned because all other informations
    78      # about problems have been displayed already.
    79      return passes, failures
    80  
    81  
    82  def display_report(passes, failures, nocolors):
    83      """Display report about number of passes and failures."""
    84      # First of all, we need to setup colors to be displayed on terminal. Colors
    85      # are displayed by using terminal escape control codes. When color output
    86      # are not enabled on command line, we can simply use empty strings in
    87      # output instead of real color escape codes.
    88      red_background = green_background = magenta_background = no_color = ""
    89  
    90      # If colors are enabled by command line parameter, use control sequence
    91      # returned by `tput` command.
    92      if not nocolors:
    93          red_background = read_control_code("setab 1")
    94          green_background = read_control_code("setab 2")
    95          magenta_background = read_control_code("setab 5")
    96          no_color = read_control_code("sgr0")
    97  
    98      # There are four possible outcomes of JSON check:
    99      # 1. no JSON files has been found
   100      # 2. all files are ok
   101      # 3. none of JSON files can be read and parsed
   102      # 4. some files can be read and parsed, some can not
   103      if failures == 0:
   104          # If there are no failures, then check if any JSON file has been found at all.
   105          if passes == 0:
   106              print("{}[WARN]{}: no JSON files detected".format(magenta_background, no_color))
   107          else:
   108              print("{}[OK]{}: all JSONs have proper format".format(green_background, no_color))
   109      else:
   110          print("{}[FAIL]{}: invalid JSON(s) detected".format(red_background, no_color))
   111  
   112      # Print just number of passes and failures at the end, as this information
   113      # can be processed on CI.
   114      print("{} passes".format(passes))
   115      print("{} failures".format(failures))
   116  
   117  
   118  def main():
   119      """Entry point to this tool."""
   120      # First of all, we need to specify all command line flags that are
   121      # recognized by this tool.
   122      parser = ArgumentParser()
   123      parser.add_argument("-v", "--verbose", dest="verbose", help="make it verbose",
   124                          action="store_true", default=None)
   125      parser.add_argument("-n", "--no-colors", dest="nocolors", help="disable color output",
   126                          action="store_true", default=None)
   127      parser.add_argument("-d", "--directory", dest="directory",
   128                          help="directory with JSON files to check",
   129                          action="store", default=".")
   130  
   131      # Now it is time to parse flags, check the actual content of command line
   132      # and fill in the object stored in variable named `args`.
   133      args = parser.parse_args()
   134  
   135      # Check all JSON files, display problems, and get counters with number of
   136      # passes and failures.
   137      passes, failures = check_jsons(args.verbose, args.directory)
   138  
   139      # Display detailed report and summary as well.
   140      display_report(passes, failures, args.nocolors)
   141  
   142      # If any error is found, return with exit code check to non-zero value.
   143      if failures > 0:
   144          exit(1)
   145  
   146  
   147  # If this script is started from command line, run the `main` function
   148  # which represents entry point to the processing.
   149  if __name__ == "__main__":
   150      """Entry point to this tool."""
   151      main()