github.com/iDigitalFlame/xmt@v0.5.4/tools/crypt_generator.py (about)

     1  #!/usr/bin/python3
     2  # Copyright (C) 2020 - 2023 iDigitalFlame
     3  #
     4  # This program is free software: you can redistribute it and/or modify
     5  # it under the terms of the GNU General Public License as published by
     6  # the Free Software Foundation, either version 3 of the License, or
     7  # any later version.
     8  #
     9  # This program is distributed in the hope that it will be useful,
    10  # but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  # GNU General Public License for more details.
    13  #
    14  # You should have received a copy of the GNU General Public License
    15  # along with this program.  If not, see <https://www.gnu.org/licenses/>.
    16  #
    17  
    18  from glob import glob
    19  from json import dumps
    20  from os.path import join
    21  from sys import argv, exit
    22  
    23  OS_ARCH_TAGS = [
    24      "386",
    25      "aix",
    26      "amd64",
    27      "amd64p32",
    28      "android",
    29      "arm",
    30      "arm64",
    31      "darwin",
    32      "dragonfly",
    33      "freebsd",
    34      "illumos",
    35      "ios",
    36      "js",
    37      "linux",
    38      "loong64",
    39      "mips",
    40      "mips64",
    41      "mips64le",
    42      "mipsle",
    43      "nacl",
    44      "netbsd",
    45      "openbsd",
    46      "plan9",
    47      "ppc64",
    48      "ppc64le",
    49      "riscv64",
    50      "s390x",
    51      "solaris",
    52      "wasm",
    53      "windows",
    54  ]
    55  
    56  
    57  def _make_tags(v):
    58      s = v.strip()
    59      if s == "crypt":
    60          return None
    61      e = s.split(" ")
    62      if len(e) == 0:
    63          return None
    64      if len(e) == 1 and e[0] == "crypt":
    65          return None
    66      r = list()
    67      for i in e:
    68          # Remove operators and any go version tags
    69          if i == "||" or i == "&&" or i == "crypt" or "go1." in i:
    70              continue
    71          r.append(i.replace("(", "").replace(")", ""))
    72      r.sort()
    73      return r
    74  
    75  
    76  def _merge_tags(one, two):
    77      if one is None or two is None:
    78          return None
    79      if len(one) == 0 or len(two) == 0:
    80          return None
    81      if one == two:
    82          return one
    83      y, z = False, False
    84      for i in one:
    85          if len(i) == 0:
    86              continue
    87          if i[0] != "!":
    88              break
    89          z = True
    90      for i in two:
    91          if len(i) == 0:
    92              continue
    93          if i[0] != "!":
    94              break
    95          y = True
    96      r = one.copy()
    97      for i in two:
    98          if i[0] == "!":  # We have a negate
    99              if i[1:] in r:  # We have a negative but theres a positive in the list
   100                  r.remove(i[1:])  # Remove the positive
   101                  continue  # Skip the negative
   102              if i in r:  # Already exists
   103                  continue
   104              if y and not z:  # Only add if "two" is all negative and "one" is not.
   105                  r.append(i)  # Add it since we don't care.
   106              continue
   107          # It's a positive
   108          if f"!{i}" in r:  # Is a negative of that in the current?
   109              r.remove(f"!{i}")  # Remove it
   110              continue  # Skip the positive, so we can have both
   111          if i in r:  # Already exists
   112              continue
   113          # Skip if we are all negatives and its an OS/ARCH name.
   114          if z and i in OS_ARCH_TAGS:
   115              continue
   116          r.append(i)
   117      if len(r) == 0:
   118          return None
   119      return r
   120  
   121  
   122  class CryptGenerator(object):
   123      __slots__ = ("text", "_count")
   124  
   125      def __init__(self):
   126          self.text = dict()
   127          self._count = list()
   128  
   129      def _add(self, value, tags):
   130          t = _make_tags(tags)
   131          if "\\n" in value:
   132              value = value.replace("\\n", "\n")
   133          if value in self.text:
   134              n = self.text[value]
   135              n[1] = _merge_tags(n[1], t)
   136              return n[0]
   137          i = str(len(self._count))
   138          self._count.append((i))
   139          self.text[value] = [i, t]
   140          return i
   141  
   142      def _index(self, p, d, tags):
   143          if "crypt.Get(" not in d:
   144              return None
   145          s = d.find("crypt.Get(")
   146          if s <= 0:
   147              raise ValueError(f'{p}: Invalid crypt entry "{d.strip()}"')
   148          e = d.find(")", s + 1)
   149          if e <= s:
   150              raise ValueError(f'{p}: Invalid crypt entry "{d.strip()}"')
   151          c = d.find(" // ")
   152          if c <= e:
   153              raise ValueError(f'{p}: Crypt entry lacks comment entry "{d.strip()}"')
   154          return (
   155              d[:s]
   156              + "crypt.Get("
   157              + self._add(d[c + 3 :].strip(), tags)
   158              + ")"
   159              + d[e + 1 :]
   160          )
   161  
   162      def start(self, out, path=""):
   163          m = list()
   164          for i in glob(join(path, "**/**.go"), recursive=True):
   165              if i.startswith("unit_tests") or i.endswith(".test"):
   166                  continue
   167              with open(i) as f:
   168                  d = f.read()
   169              if len(d) == 0:
   170                  continue
   171              if "package main\n" in d:
   172                  continue
   173              if 'xmt/util/crypt"' not in d:
   174                  continue
   175              if "crypt.Get(" not in d:
   176                  continue
   177              m.append((i, d, d.split("\n")))
   178          if len(m) == 0:
   179              return
   180          print(f"Examining {len(m)} files..")
   181          for i in m:
   182              r, t = False, None
   183              f = open(i[0], "w")
   184              for x in range(0, len(i[2])):
   185                  if t is None and i[2][x].startswith("//go:build"):
   186                      t = i[2][x][10:].strip().lower()
   187                  o = self._index(i[0], i[2][x], t)
   188                  if o is not None:
   189                      r = o != i[2][x]
   190                      f.write(o)
   191                  else:
   192                      f.write(i[2][x])
   193                  if len(i[2][x]) == 0 and x + 1 >= len(i[2]):
   194                      continue
   195                  f.write("\n")
   196                  del o
   197              f.close()
   198              if not r:
   199                  continue
   200              print(f'Reformatted "{i[0]}"')
   201          del m
   202          z = dict()
   203          for k, v in self.text.items():
   204              z[v[0]] = {"value": k}
   205              if v[1] is not None and len(v[1]) > 0:
   206                  z[v[0]]["tags"] = v[1]
   207          with open(out, "w") as f:
   208              f.write(dumps(z, indent=4, sort_keys=False))
   209          del z
   210  
   211  
   212  if __name__ == "__main__":
   213      if len(argv) < 2:
   214          print(f"{argv[0]} <json> [dir]")
   215          exit(1)
   216  
   217      d = ""
   218      if len(argv) == 3:
   219          d = argv[2]
   220  
   221      v = CryptGenerator()
   222      v.start(argv[1], d)
   223      del d, v