Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:09:26

0001 #!/usr/bin/env python3
0002 import argparse
0003 import os
0004 import sys
0005 from subprocess import check_output
0006 import re
0007 import difflib
0008 from datetime import datetime
0009 from fnmatch import fnmatch
0010 
0011 EXCLUDE = []
0012 
0013 
0014 class bcolors:
0015     HEADER = "\033[95m"
0016     OKBLUE = "\033[94m"
0017     OKGREEN = "\033[92m"
0018     WARNING = "\033[93m"
0019     FAIL = "\033[91m"
0020     ENDC = "\033[0m"
0021     BOLD = "\033[1m"
0022     UNDERLINE = "\033[4m"
0023 
0024 
0025 CROSS_SYMBOL = "\u2717"
0026 
0027 
0028 def err(string):
0029     if sys.stdout.isatty():
0030         return bcolors.FAIL + bcolors.BOLD + string + bcolors.ENDC
0031     else:
0032         return string
0033 
0034 
0035 class CommitInfo:
0036     date = None
0037     year = None
0038     author = None
0039     subject = None
0040     body = None
0041 
0042 
0043 def check_git_dates(src):
0044     output = (
0045         check_output(["git", "log", "--format={{{%an|%ad|%s|%b}}}", "--", src])
0046         .decode("utf-8")
0047         .strip()
0048     )
0049 
0050     # find single outputs
0051     commits = re.findall(r"{{{((?:.|\n)*?)}}}", output)
0052     commits = [c for c in commits if "[ignore-license]" not in c]
0053     commits = [c.split("|") for c in commits]
0054 
0055     # print(output)
0056     mod = commits[0]
0057     add = commits[-1]
0058 
0059     madd = re.match(r".*\d{2}:\d{2}:\d{2} (\d{4})", add[1])
0060     assert madd != None, "Regex did not match git log output"
0061     mmod = re.match(r".*\d{2}:\d{2}:\d{2} (\d{4})", mod[1])
0062     assert mmod != None, "Regex did not match git log output"
0063 
0064     addcommit = CommitInfo()
0065     addcommit.date = add[1]
0066     addcommit.year = int(madd.group(1))
0067     addcommit.author = add[0]
0068     addcommit.subject = add[2]
0069     addcommit.body = add[3]
0070 
0071     modcommit = CommitInfo()
0072     modcommit.date = mod[1]
0073     modcommit.year = int(mmod.group(1))
0074     modcommit.author = mod[0]
0075     modcommit.subject = mod[2]
0076     modcommit.body = mod[3]
0077 
0078     return addcommit, modcommit
0079 
0080 
0081 def main():
0082     p = argparse.ArgumentParser()
0083     p.add_argument("input")
0084     p.add_argument(
0085         "--fix", action="store_true", help="Attempt to fix any license issues found."
0086     )
0087     p.add_argument(
0088         "--check-years",
0089         action="store_true",
0090         help="Check the license year info using git info for each file.",
0091     )
0092     p.add_argument(
0093         "--fail-year-mismatch",
0094         action="store_true",
0095         help="Fail if year in license statement is not valid.",
0096     )
0097     p.add_argument("--exclude", "-e", action="append", default=EXCLUDE)
0098 
0099     args = p.parse_args()
0100     print(args.exclude)
0101 
0102     if os.path.isdir(args.input):
0103         srcs = (
0104             str(
0105                 check_output(
0106                     [
0107                         "find",
0108                         args.input,
0109                         "-iname",
0110                         "*.cpp",
0111                         "-or",
0112                         "-iname",
0113                         "*.hpp",
0114                         "-or",
0115                         "-iname",
0116                         "*.ipp",
0117                     ]
0118                 ),
0119                 "utf-8",
0120             )
0121             .strip()
0122             .split("\n")
0123         )
0124         srcs = filter(lambda p: not p.startswith("./build"), srcs)
0125     else:
0126         srcs = [args.input]
0127 
0128     year = int(datetime.now().strftime("%Y"))
0129 
0130     raw = """// This file is part of the Acts project.
0131 //
0132 // Copyright (C) {year} CERN for the benefit of the Acts project
0133 //
0134 // This Source Code Form is subject to the terms of the Mozilla Public
0135 // License, v. 2.0. If a copy of the MPL was not distributed with this
0136 // file, You can obtain one at http://mozilla.org/MPL/2.0/."""
0137 
0138     reg = (
0139         r"\A// This file is part of the Acts project.\n"
0140         + r"//\n"
0141         + r"// Copyright \(C\) (?P<year>.*) CERN for the benefit of the Acts project\n"
0142         + r"//\n"
0143         + r"// This Source Code Form is subject to the terms of the Mozilla Public\n"
0144         + r"// License, v\. 2\.0\. If a copy of the MPL was not distributed with this\n"
0145         + r"// file, You can obtain one at http://mozilla.org/MPL/2.0/.\Z"
0146     )
0147 
0148     ref = re.compile(reg, re.M)
0149     clean_re = re.compile(r"(\(C\)) (.*) (CERN)", re.M)
0150     year_re = re.compile(r"^(?P<year1>20\d{2}|(?P<year2>20\d{2})-(?P<year3>20\d{2}))$")
0151     extract_re = re.compile(r"(20\d{2})-?(20\d{2})?")
0152 
0153     def clean(s):
0154         return clean_re.sub(r"\1 XXXX \3", s)
0155 
0156     def get_clean_lines(s):
0157         return [clean(l) + "\n" for l in s.split("\n")]
0158 
0159     def validate_years(year1, year2):
0160         if year1 and year2:
0161             year1 = int(year1)
0162             year2 = int(year2)
0163             if year1 >= year2:
0164                 return False
0165             if year1 > year or year2 > year:
0166                 return False
0167         else:
0168             theyear = int(year1 if year1 else year2)
0169             if theyear > year:
0170                 return False
0171         return True
0172 
0173     error_summary = ""
0174     info_summary = ""
0175 
0176     def eprint(*args):
0177         nonlocal error_summary
0178         error_summary += " ".join(map(str, args)) + "\n"
0179 
0180     def year_print(*pargs):
0181         nonlocal error_summary
0182         nonlocal info_summary
0183         string = " ".join(map(str, pargs)) + "\n"
0184         if args.fail_year_mismatch:
0185             error_summary += string
0186         else:
0187             info_summary += string
0188 
0189     exit = 0
0190     srcs = list(srcs)
0191     nsrcs = len(srcs)
0192     step = int(nsrcs / 20)
0193     for i, src in enumerate(srcs):
0194         if any([fnmatch(src, e) for e in args.exclude]):
0195             continue
0196 
0197         if nsrcs > 1 and i % step == 0:
0198             string = "{}/{} -> {:.2f}%".format(i, nsrcs, i / float(nsrcs) * 100.0)
0199             if sys.stdout.isatty():
0200                 sys.stdout.write(string + "\r")
0201             else:
0202                 print(string)
0203 
0204         with open(src, "r+") as f:
0205             license = ""
0206             for x in range(len(raw)):
0207                 line = f.readline()
0208                 if not line.startswith("//"):
0209                     break
0210                 license += line
0211             license = ("".join(license)).strip()
0212             m = ref.search(license)
0213 
0214             if m == None:
0215                 eprint("Invalid / missing license in " + src + "")
0216 
0217                 exp = [l + "\n" for l in raw.format(year="XXXX").split("\n")]
0218                 act = get_clean_lines(license)
0219 
0220                 diff = difflib.unified_diff(exp, act)
0221                 eprint("".join(diff))
0222                 eprint()
0223 
0224                 if args.fix:
0225                     eprint("-> fixing file (prepend)")
0226                     f.seek(0)
0227                     file_content = f.read()
0228                     f.seek(0)
0229                     stmnt = raw.format(year=year)
0230                     f.write(stmnt + "\n\n")
0231                     f.write(file_content)
0232 
0233                 exit = 1
0234             else:
0235                 # we have a match, need to verify year string is right
0236 
0237                 if args.check_years:
0238                     git_add_commit, git_mod_commit = check_git_dates(src)
0239                     git_add_year = git_add_commit.year
0240                     git_mod_year = git_mod_commit.year
0241                 year_act = m.group("year")
0242                 ym = year_re.match(year_act)
0243                 valid = True
0244                 if not ym:
0245                     eprint("Year string does not match format in {}".format(src))
0246                     eprint("Expected: YYYY or YYYY-YYYY (year or year range)")
0247                     eprint("Actual:   {}\n".format(year_act))
0248 
0249                     if args.fix:
0250                         extract = extract_re.search(year_act)
0251                         year1 = extract.group(1)
0252                         year2 = extract.group(2)
0253 
0254                     exit = 1
0255                     valid = False
0256 
0257                 else:
0258                     extract = extract_re.search(year_act)
0259                     year1 = extract.group(1)
0260                     year2 = extract.group(2)
0261 
0262                     if not validate_years(year1, year2):
0263                         eprint("Year string is not valid in {}".format(src))
0264                         eprint("Year string is: " + year_act + "\n")
0265                         exit = 1
0266                         valid = False
0267 
0268                     if args.check_years:
0269                         if git_add_year != git_mod_year:
0270                             # need year range in licence
0271                             if not (year1 and year2):
0272                                 year_print("File: {}".format(src))
0273                                 # year_print("o File was modified in a different year ({}) than it was added ({})."
0274                                 # .format(git_mod_year, git_add_year))
0275                                 year_print(
0276                                     "- File was added in {}".format(git_add_year)
0277                                 )
0278                                 year_print(
0279                                     "- File was modified on {} by {}:\n{}".format(
0280                                         git_mod_commit.date,
0281                                         git_mod_commit.author,
0282                                         git_mod_commit.subject + git_mod_commit.body,
0283                                     )
0284                                 )
0285                                 year_print(
0286                                     "=> License should say {}-{}".format(
0287                                         git_add_year, git_mod_year
0288                                     )
0289                                 )
0290 
0291                                 act_year = year1 if year1 else year2
0292                                 year_print(
0293                                     err(
0294                                         "{} But says: {}".format(CROSS_SYMBOL, act_year)
0295                                     )
0296                                 )
0297 
0298                                 if args.fail_year_mismatch:
0299                                     exit = 1
0300                                     year_print("\n")
0301                                 else:
0302                                     year_print("This is not treated as an error\n")
0303                                 valid = False
0304                             else:
0305                                 if (
0306                                     int(year1) != git_add_year
0307                                     or int(year2) != git_mod_year
0308                                 ):
0309                                     year_print("File: {}".format(src))
0310                                     year_print(
0311                                         "Year range {}-{} does not match range from git {}-{}".format(
0312                                             year1, year2, git_add_year, git_mod_year
0313                                         )
0314                                     )
0315                                     year_print(
0316                                         "- File was added in {}".format(git_add_year)
0317                                     )
0318                                     year_print(
0319                                         "- File was modified on {} by {}:\n{}".format(
0320                                             git_mod_commit.date,
0321                                             git_mod_commit.author,
0322                                             git_mod_commit.subject
0323                                             + git_mod_commit.body,
0324                                         )
0325                                     )
0326                                     year_print(
0327                                         "=> License should say {}-{}".format(
0328                                             git_add_year, git_mod_year
0329                                         )
0330                                     )
0331                                     year_print(
0332                                         err(
0333                                             "{} But says: {}-{}".format(
0334                                                 CROSS_SYMBOL, year1, year2
0335                                             )
0336                                         )
0337                                     )
0338                                     if args.fail_year_mismatch:
0339                                         exit = 1
0340                                         year_print("\n")
0341                                     else:
0342                                         year_print("This is not treated as an error\n")
0343                                     valid = False
0344 
0345                         else:
0346                             if int(year1) < git_mod_year:
0347                                 year_print("File: {}".format(src))
0348                                 year_print(
0349                                     "- Year {} does not match git modification year {}".format(
0350                                         year1, git_mod_year
0351                                     )
0352                                 )
0353                                 year_print(
0354                                     "- File was modified on {} by {}:\n{}".format(
0355                                         git_mod_commit.date,
0356                                         git_mod_commit.author,
0357                                         git_mod_commit.subject + git_mod_commit.body,
0358                                     )
0359                                 )
0360                                 year_print(
0361                                     "=> License should say {}".format(git_mod_year)
0362                                 )
0363                                 year_print(
0364                                     err("{} But says: {}".format(CROSS_SYMBOL, year1))
0365                                 )
0366                                 if args.fail_year_mismatch:
0367                                     exit = 1
0368                                     year_print("\n")
0369                                 else:
0370                                     year_print("This is not treated as an error\n")
0371                                 valid = False
0372 
0373                 if args.fix and not valid:
0374                     eprint("-> fixing file (patch year)")
0375                     year_str = "2016-{}".format(year)
0376                     if args.check_years:
0377                         if git_add_year == git_mod_year:
0378                             year_str = "{}".format(git_add_year)
0379                         else:
0380                             year_str = "{}-{}".format(git_add_year, git_mod_year)
0381                     new_license = raw.format(year=year_str)
0382 
0383                     # preserve rest of file as is
0384                     if args.check_years:
0385                         old_license_len = len(license)
0386                         f.seek(old_license_len)
0387                         file_body = f.read()
0388                         f.seek(0)
0389                         f.truncate()
0390 
0391                     f.seek(0)
0392                     f.write(new_license)
0393 
0394                     if args.check_years:
0395                         f.write(file_body)
0396 
0397     print("\n--- INFO ---\n")
0398     print(info_summary)
0399     print("\n--- ERROR ---\n")
0400     print(error_summary)
0401 
0402     if exit != 0 and not args.fix:
0403         print("License problems found. You can try running again with --fix")
0404 
0405     sys.exit(exit)
0406 
0407 
0408 if "__main__" == __name__:
0409     main()