/ SPDX.py
SPDX.py
  1  # SPDX-FileCopyrightText: 2022 Eva Herrada for Adafruit Industries
  2  #
  3  # SPDX-License-Identifier: MIT
  4  
  5  import os
  6  import subprocess
  7  import sys
  8  
  9  print("Starting SPDX Check")
 10  
 11  # add user bin to path!
 12  BUILD_DIR = ""
 13  # add user bin to path!
 14  try:
 15      # If we're on actions
 16      BUILD_DIR = os.environ["GITHUB_WORKSPACE"]
 17  except KeyError:
 18      try:
 19          # If we're on travis
 20          BUILD_DIR = os.environ["TRAVIS_BUILD_DIR"]
 21      except KeyError:
 22          # If we're running on local machine
 23          BUILD_DIR = os.path.abspath(".")
 24  
 25  print(f"Running in {BUILD_DIR}\n")
 26  files = []
 27  missing_file = []
 28  
 29  fail = False
 30  
 31  
 32  def compare(file_, line_, correct):
 33      old = line_[:-1]
 34      try:
 35          right = line_.split(":")[1][:-1]
 36      except IndexError:
 37          print(f'{file_.split("_Guides/")[1]} may have an SPDX format issue:')
 38          print("The following line:")
 39          print(old)
 40          print("May be missing a colon.\nIt should look like this:")
 41          print(correct, "\n")
 42          return True
 43  
 44      new = f"{correct}{right.strip()}"
 45      cmd = f'CMD="diff <(echo \\"{old}\\") <(echo \\"{new}\\")"; /bin/bash -c "$CMD"'
 46      output = subprocess.getoutput(cmd).split("\n")
 47  
 48      if output:
 49          print(f'{file_.split("_Guides/")[1]} may have an SPDX format issue:')
 50          print("Change this:")
 51          print(output[1][2:])
 52          print("To this:")
 53          print(output[3][2:], "\n")
 54          return True
 55  
 56      return False
 57  
 58  
 59  for r, d, f in os.walk(BUILD_DIR):
 60      for file in f:
 61          if file.split(".")[-1] in ("py", "cpp", "ino", "h"):
 62              files.append(os.path.join(r, file))
 63  
 64  for file in files:
 65      with open(file, "r") as F:
 66          lines = []
 67          for line in F.readlines():
 68              if line[0] != "#" and line[:2] != "//":
 69                  break
 70              lines.append(line)
 71          status = {"copyright": False, "license": False, "licensefile": False}
 72          for line in lines:
 73              if "SPDX-FileCopyrightText" in line:
 74                  status["copyright"] = True
 75                  if (
 76                      "# SPDX-FileCopyrightText: " not in line
 77                      and "// SPDX-FileCopyrightText: " not in line
 78                  ):
 79                      if file.endswith(".py"):
 80                          if compare(file, line, "# SPDX-FileCopyrightText: "):
 81                              fail = True
 82                      else:
 83                          if compare(file, line, "// SPDX-FileCopyrightText: "):
 84                              fail = True
 85  
 86              if "SPDX-License-Identifier" in line:
 87                  failed = False
 88                  if (
 89                      "# SPDX-License-Identifier: " not in line
 90                      and "// SPDX-License-Identifier: " not in line
 91                  ):
 92                      if file.endswith(".py"):
 93                          if compare(file, line, "# SPDX-License-Identifier: "):
 94                              fail = True
 95                              failed = True
 96                      else:
 97                          if compare(file, line, "// SPDX-License-Identifier: "):
 98                              fail = True
 99                              failed = True
100                  if not failed:
101                      license_name = line.split("SPDX-License-Identifier: ")[1][:-1]
102                      status["license"] = True
103                      if os.path.isfile(BUILD_DIR + f"/LICENSES/{license_name}.txt"):
104                          status["licensefile"] = True
105                      elif license_name not in missing_file:
106                          missing_file.append(f"LICENSES/{license_name}.txt")
107  
108          if not all(status.values()):
109              fail = True
110              print(f"{file} is missing SPDX\n")
111              continue
112          if not status["copyright"]:
113              fail = True
114              print(f"{file}: SPDX-FileCopyrightText line is missing")
115          if not status["license"]:
116              fail = True
117              print(f"{file}: SPDX-License-Identifier line is missing")
118          if not status["licensefile"] and status["license"]:
119              fail = True
120              print(f"{file}: {license_name}.txt is missing from LICENSES/")
121          if (
122              not status["copyright"]
123              or not status["license"]
124              or not status["licensefile"]
125          ):
126              print("\n")
127  
128  if fail:
129      if missing_file:
130          print("Missing files:", missing_file)
131      sys.exit(-1)
132  sys.exit(0)