/ scripts / fix_headers.py
fix_headers.py
  1  #!/usr/bin/env python
  2  
  3  ############################ Copyrights and license ############################
  4  #                                                                              #
  5  # Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net>                 #
  6  # Copyright 2014 Vincent Jacques <vincent@vincent-jacques.net>                 #
  7  # Copyright 2016 Peter Buckley <dx-pbuckley@users.noreply.github.com>          #
  8  # Copyright 2018 sfdye <tsfdye@gmail.com>                                      #
  9  # Copyright 2019 Steve Kowalik <steven@wedontsleep.org>                        #
 10  # Copyright 2019 Wan Liuyang <tsfdye@gmail.com>                                #
 11  # Copyright 2020 Steve Kowalik <steven@wedontsleep.org>                        #
 12  # Copyright 2020 Wan Liuyang <tsfdye@gmail.com>                                #
 13  #                                                                              #
 14  # This file is part of PyGithub.                                               #
 15  # http://pygithub.readthedocs.io/                                              #
 16  #                                                                              #
 17  # PyGithub is free software: you can redistribute it and/or modify it under    #
 18  # the terms of the GNU Lesser General Public License as published by the Free  #
 19  # Software Foundation, either version 3 of the License, or (at your option)    #
 20  # any later version.                                                           #
 21  #                                                                              #
 22  # PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY  #
 23  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    #
 24  # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #
 25  # details.                                                                     #
 26  #                                                                              #
 27  # You should have received a copy of the GNU Lesser General Public License     #
 28  # along with PyGithub. If not, see <http://www.gnu.org/licenses/>.             #
 29  #                                                                              #
 30  ################################################################################
 31  
 32  import os
 33  import subprocess
 34  
 35  eightySharps = "#" * 80
 36  
 37  
 38  def generateLicenseSection(filename):
 39      yield "############################ Copyrights and license ############################"
 40      yield "#                                                                              #"
 41      for year, name in sorted(listContributors(filename)):
 42          line = "# Copyright " + year + " " + name
 43          line += (79 - len(line)) * " " + "#"
 44          yield line
 45      yield "#                                                                              #"
 46      yield "# This file is part of PyGithub.                                               #"
 47      yield "# http://pygithub.readthedocs.io/                                              #"
 48      yield "#                                                                              #"
 49      yield "# PyGithub is free software: you can redistribute it and/or modify it under    #"
 50      yield "# the terms of the GNU Lesser General Public License as published by the Free  #"
 51      yield "# Software Foundation, either version 3 of the License, or (at your option)    #"
 52      yield "# any later version.                                                           #"
 53      yield "#                                                                              #"
 54      yield "# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY  #"
 55      yield "# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    #"
 56      yield "# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #"
 57      yield "# details.                                                                     #"
 58      yield "#                                                                              #"
 59      yield "# You should have received a copy of the GNU Lesser General Public License     #"
 60      yield "# along with PyGithub. If not, see <http://www.gnu.org/licenses/>.             #"
 61      yield "#                                                                              #"
 62      yield "################################################################################"
 63  
 64  
 65  def listContributors(filename):
 66      contributors = set()
 67      result = subprocess.check_output(
 68          ["git", "log", "--format=format:%ad %an <%ae>", "--date=short", "--", filename],
 69          text=True,
 70      )
 71      for line in result.split("\n"):
 72          year = line[0:4]
 73          name = line[11:]
 74          contributors.add((year, name))
 75      return contributors
 76  
 77  
 78  def extractBodyLines(lines):
 79      bodyLines = []
 80  
 81      seenEndOfHeader = False
 82  
 83      for line in lines:
 84          if len(line) > 0 and line[0] != "#":
 85              seenEndOfHeader = True
 86          if seenEndOfHeader:
 87              bodyLines.append(line)
 88          # else:
 89          #     print "HEAD:", line
 90          if line == eightySharps:
 91              seenEndOfHeader = True
 92  
 93      # print "BODY:", "\nBODY: ".join(bodyLines)
 94  
 95      return bodyLines
 96  
 97  
 98  class PythonHeader:
 99      def fix(self, filename, lines):
100          isExecutable = lines[0].startswith("#!")
101          newLines = []
102  
103          if isExecutable:
104              newLines.append("#!/usr/bin/env python")
105          newLines.append("# -*- coding: utf-8 -*-")
106          newLines.append("")
107  
108          for line in generateLicenseSection(filename):
109              newLines.append(line)
110  
111          bodyLines = extractBodyLines(lines)
112  
113          if len(bodyLines) > 0 and bodyLines[0] != "":
114              newLines.append("")
115              if "import " not in bodyLines[0] and bodyLines[0] != '"""' and not bodyLines[0].startswith("##########"):
116                  newLines.append("")
117          newLines += bodyLines
118  
119          return newLines
120  
121  
122  class StandardHeader:
123      def fix(self, filename, lines):
124          newLines = []
125  
126          for line in generateLicenseSection(filename):
127              newLines.append(line)
128  
129          bodyLines = extractBodyLines(lines)
130  
131          if len(bodyLines) > 0 and bodyLines[0] != "":
132              newLines.append("")
133          newLines += bodyLines
134  
135          return newLines
136  
137  
138  def findHeadersAndFiles():
139      for root, dirs, files in os.walk(".", topdown=True):
140          if ".git" in dirs:
141              dirs.remove(".git")
142          if "developer.github.com" in dirs:
143              dirs.remove("developer.github.com")
144          if "build" in dirs:
145              dirs.remove("build")
146          if ".tox" in dirs:
147              dirs.remove(".tox")
148          if ".venv" in dirs:
149              dirs.remove(".venv")
150          if "PyGithub.egg-info" in dirs:
151              dirs.remove("PyGithub.egg-info")
152  
153          for filename in files:
154              fullname = os.path.join(root, filename)
155              if filename == "GithubCredentials.py":
156                  pass
157              elif filename.endswith(".py"):
158                  yield (PythonHeader(), fullname)
159              elif filename in ["COPYING", "COPYING.LESSER"]:
160                  pass
161              elif filename.endswith(".rst") or filename.endswith(".md"):
162                  pass
163              elif filename == ".gitignore":
164                  yield (StandardHeader(), fullname)
165              elif "ReplayData" in fullname:
166                  pass
167              elif fullname.endswith(".pyc"):
168                  pass
169              else:
170                  print("Don't know what to do with", filename)
171  
172  
173  def main():
174      for header, filename in findHeadersAndFiles():
175          print("Analyzing", filename)
176          with open(filename) as f:
177              lines = list(line.rstrip() for line in f)
178          newLines = header.fix(filename, lines)
179          if newLines != lines:
180              print(" => actually modifying", filename)
181              with open(filename, "w") as f:
182                  for line in newLines:
183                      f.write(line + "\n")
184  
185  
186  if __name__ == "__main__":
187      main()