build-addon-index.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #!/usr/bin/env python3
  2. #
  3. # SuperTux
  4. # Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. import argparse
  19. import glob
  20. import hashlib
  21. import os
  22. import subprocess
  23. import sys
  24. import sexpr
  25. def escape_str(string):
  26. return "\"%s\"" % string.replace("\"", "\\\"")
  27. class Addon:
  28. def __init__(self, filename):
  29. lst = sexpr.parse(filename)
  30. if lst[0][0] != "supertux-addoninfo":
  31. raise Exception("not a supertux-addoninfo: %s" % lst[0][0])
  32. else:
  33. for k, v in lst[0][1:]:
  34. if k == "id":
  35. self.id = v
  36. elif k == "version":
  37. self.version = int(v)
  38. elif k == "type":
  39. self.type = v
  40. elif k == "title":
  41. self.title = v
  42. elif k == "author":
  43. self.author = v
  44. elif k == "license":
  45. self.license = v
  46. else:
  47. raise Exception("unknown tag: %s" % k)
  48. self.md5 = ""
  49. self.url = ""
  50. def write(self, fout):
  51. fout.write(" (supertux-addoninfo\n")
  52. fout.write(" (id %s)\n" % escape_str(self.id))
  53. fout.write(" (version %d)\n" % self.version)
  54. fout.write(" (type %s)\n" % escape_str(self.type))
  55. fout.write(" (title %s)\n" % escape_str(self.title))
  56. fout.write(" (author %s)\n" % escape_str(self.author))
  57. fout.write(" (license %s)\n" % escape_str(self.license))
  58. fout.write(" (url %s)\n" % escape_str(self.url))
  59. fout.write(" (md5 %s)\n" % escape_str(self.md5))
  60. fout.write(" )\n")
  61. def process_addon(fout, addon_dir, nfo, base_url, zipdir):
  62. # print addon_dir, nfo
  63. with open(nfo) as fin:
  64. addon = Addon(fin.read())
  65. zipfile = addon.id + "_v" + str(addon.version) + ".zip"
  66. # see http://pivotallabs.com/barriers-deterministic-reproducible-zip-files/
  67. os.remove(os.path.join(zipdir, zipfile))
  68. zipout = os.path.relpath(os.path.join(zipdir, zipfile), addon_dir)
  69. subprocess.call(["zip", "-X", "-r", "--quiet", zipout, "."], cwd=addon_dir)
  70. with open(os.path.join(zipdir, zipfile), 'rb') as fin:
  71. addon.md5 = hashlib.md5(fin.read()).hexdigest()
  72. addon.url = base_url + zipfile
  73. addon.write(fout)
  74. def generate_index(fout, directory, base_url, zipdir):
  75. fout.write(";; automatically generated by build-addon-index.py\n")
  76. fout.write("(supertux-addons\n")
  77. for addon_dir in os.listdir(directory):
  78. addon_dir = os.path.join(directory, addon_dir)
  79. if os.path.isdir(addon_dir):
  80. # print(addon_dir)
  81. nfos = glob.glob(os.path.join(addon_dir, "*.nfo"))
  82. if len(nfos) == 0:
  83. raise Exception(".nfo file missing from %s" % addon_dir)
  84. elif len(nfos) > 1:
  85. raise Exception("to many .nfo files in %s" % addon_dir)
  86. else:
  87. try:
  88. process_addon(fout, addon_dir, nfos[0], base_url, zipdir)
  89. except Exception as e:
  90. sys.stderr.write("%s: ignoring addon because: %s\n" % (addon_dir, e))
  91. fout.write(")\n\n;; EOF ;;\n")
  92. EXAMPLE_TEXT="""Example:
  93. ./build-addon-index.py -z ../../addons/repository/ ../../addons/src/"""
  94. if __name__ == "__main__":
  95. parser = argparse.ArgumentParser(description="Addon Index/Zip Generator",
  96. epilog=EXAMPLE_TEXT,
  97. formatter_class=argparse.RawDescriptionHelpFormatter)
  98. parser.add_argument('DIRECTORY', type=str, nargs=1,
  99. help="directory containing the mods")
  100. parser.add_argument('-o', '--output', metavar='FILE', type=str, required=False,
  101. help="output file")
  102. parser.add_argument('-z', '--zipdir', metavar="DIR", type=str, required=True,
  103. help="generate zip files")
  104. parser.add_argument('-u', '--url', metavar='FILE', type=str,
  105. default="https://raw.githubusercontent.com/SuperTux/addons/master/repository/",
  106. help="base url")
  107. args = parser.parse_args()
  108. if args.output is None:
  109. fout = sys.stdout
  110. generate_index(fout, args.DIRECTORY[0], args.url, args.zipdir)
  111. else:
  112. with open(args.output, "w") as fout:
  113. generate_index(fout, args.DIRECTORY[0], args.url, args.zipdir)
  114. # EOF #