mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-10-26 11:19:16 +00:00
170 lines
6.0 KiB
Python
Executable File
170 lines
6.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Copyright 2021 The Mumble Developers. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license
|
|
# that can be found in the LICENSE file at the root of the
|
|
# Mumble source tree or at <https://www.mumble.info/LICENSE>.
|
|
|
|
|
|
import argparse
|
|
import os
|
|
import platform
|
|
import subprocess
|
|
import datetime
|
|
from string import Template
|
|
import re
|
|
|
|
def cmd(args):
|
|
shell = platform.system() == 'Windows'
|
|
p = subprocess.Popen(args, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
stdout, stderr = p.communicate()
|
|
if p.returncode != 0:
|
|
raise Exception('cmd(): {0} failed with status {1}: {2}'.format(args, p.returncode, stderr))
|
|
return stdout.decode('utf-8')
|
|
|
|
|
|
licenseHeaderTemplate = Template(
|
|
"""${commentChar} Copyright ${copyright} The Mumble Developers. All rights reserved.
|
|
${commentChar} Use of this source code is governed by a BSD-style license
|
|
${commentChar} that can be found in the LICENSE file at the root of the
|
|
${commentChar} Mumble source tree or at <https://www.mumble.info/LICENSE>.""")
|
|
|
|
blackListFiles = []
|
|
|
|
class InvalidFileError(Exception):
|
|
pass
|
|
|
|
class LicenseNotFoundError(Exception):
|
|
pass
|
|
|
|
def generateHeaderForFile(filePath):
|
|
if filePath in blackListFiles:
|
|
raise InvalidFileError("File is blacklisted: \"" + filePath + "\"")
|
|
|
|
fileName = os.path.basename(filePath)
|
|
extension = os.path.splitext(fileName)[-1]
|
|
|
|
commentChar = None
|
|
|
|
if extension in [".cpp", ".c", ".h", ".hpp", ".cs", ".ice", ".proto", ".mm", ".vs", ".m", ".ps", ".hlsl", ".fx"]:
|
|
commentChar = "//"
|
|
elif extension in [".bash", ".sh", ".py", ".yaml", ".yml", ".ps1", ".pl", ".cmake", ".rb", ".init"] or fileName == "CMakeLists.txt":
|
|
commentChar = "#"
|
|
elif extension in [".bat", ".cmd"]:
|
|
commentChar = "::"
|
|
|
|
if commentChar is None:
|
|
raise InvalidFileError("Can't handle extension: \"" + extension + "\"")
|
|
|
|
# Get file's creation date
|
|
creationDateStr = cmd(["git", "log", "--diff-filter=A", "--format=%ci", "-1", "--", filePath]).strip()
|
|
|
|
if not creationDateStr:
|
|
raise InvalidFileError("File not in git index: \"" + filePath + "\"")
|
|
|
|
# We only need the day, month and year
|
|
creationDate = datetime.datetime.fromisoformat(creationDateStr.split()[0])
|
|
|
|
copyright = None
|
|
if creationDate.year == datetime.datetime.today().year:
|
|
copyright = str(creationDate.year)
|
|
else:
|
|
copyright = str(creationDate.year) + "-" + str(datetime.datetime.today().year)
|
|
|
|
return licenseHeaderTemplate.substitute(commentChar=commentChar, copyright=copyright)
|
|
|
|
|
|
def findCopyright(content, pattern):
|
|
match = re.search(pattern, content)
|
|
|
|
if match:
|
|
return (match.start(), match.end())
|
|
else:
|
|
raise LicenseNotFoundError()
|
|
|
|
|
|
def exclude(path, excludes):
|
|
for current in excludes:
|
|
if path.startswith(current):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Updates (and adds) license headers of the Mumble source files")
|
|
parser.add_argument("-a", "--add-new", action="store_true", default=False, help="Also add license headers to files that did not contain one before")
|
|
|
|
args = parser.parse_args()
|
|
|
|
scriptDir = os.path.dirname(os.path.realpath(__file__))
|
|
rootDir = os.path.realpath(os.path.join(scriptDir, ".."))
|
|
|
|
excludePaths = ["build", "docs", "3rdparty", "3rdPartylLicenses", "themes", ".git", "man"]
|
|
for i in range(len(excludePaths)):
|
|
excludePaths[i] = os.path.join(rootDir, excludePaths[i])
|
|
|
|
for i in range(len(blackListFiles)):
|
|
blackListFiles[i] = os.path.join(rootDir, blackListFiles[i])
|
|
|
|
# Convert the license template into a pattern that matches the license declaration inside the source files
|
|
licensePattern = re.compile(licenseHeaderTemplate.substitute(copyright="\d+(-\d+)?", commentChar=".+?").strip().replace("\n", "\\r?\\n").replace(" ",
|
|
"\\s*"), re.IGNORECASE)
|
|
|
|
modifiedFiles = 0
|
|
for root, dirs, files in os.walk(rootDir, topdown = True):
|
|
for currentFile in files:
|
|
fullPath = os.path.join(root, currentFile)
|
|
|
|
if exclude(fullPath, excludePaths):
|
|
continue
|
|
|
|
try:
|
|
generatedCopyright = generateHeaderForFile(fullPath)
|
|
|
|
fileHandle = open(fullPath, "r")
|
|
fileContent = fileHandle.read()
|
|
|
|
try:
|
|
start,end = findCopyright(fileContent, licensePattern)
|
|
except LicenseNotFoundError:
|
|
# no license yet
|
|
if not args.add_new:
|
|
print("No license header found for", fullPath)
|
|
continue
|
|
else:
|
|
print("Adding license header to", fullPath)
|
|
if not fileContent.startswith("#!"):
|
|
# File does not start with shebang -> write license to the top
|
|
start = 0
|
|
end = 0
|
|
|
|
generatedCopyright += "\n\n"
|
|
else:
|
|
# File starts with shebang -> append license after the first line (and add
|
|
# an extra blank line)
|
|
start = fileContent.find("\n") + 1
|
|
assert start > 0
|
|
end = start
|
|
|
|
generatedCopyright = "\n" + generatedCopyright + "\n\n"
|
|
|
|
modifiedContent = fileContent[ : start] + generatedCopyright + fileContent[end : ]
|
|
|
|
if modifiedContent != fileContent:
|
|
fileHandle.close()
|
|
# Open for writing
|
|
fileHandle = open(fullPath, "w")
|
|
|
|
modifiedFiles += 1
|
|
|
|
fileHandle.write(modifiedContent)
|
|
except InvalidFileError:
|
|
continue
|
|
|
|
print("Modified {} files".format(modifiedFiles))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|