gen_template.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import os
  4. import io
  5. import glob
  6. import shutil
  7. import random
  8. import argparse
  9. import sys
  10. from string import Template
  11. from mimetypes import add_type, guess_type
  12. if sys.version_info[0] >= 3:
  13. unicode = str
  14. platforms = ("win32", "android", "macosx", "ios", "cmake", "all")
  15. def relpath(a, b):
  16. try:
  17. return os.path.relpath(a, b)
  18. except ValueError:
  19. pass
  20. return a
  21. def unixpath(path):
  22. return path.replace("\\", "/")
  23. def run(args):
  24. if args.hello:
  25. dest = args.dest
  26. local = os.path.dirname(__file__)
  27. if not local:
  28. local = "."
  29. src = local + "/../examples/HelloWorld/src"
  30. data = local + "/../examples/HelloWorld/data"
  31. try:
  32. shutil.copytree(src, dest + "/src")
  33. except OSError:
  34. pass
  35. try:
  36. shutil.copytree(data, dest + "/data")
  37. except OSError:
  38. pass
  39. for p in platforms:
  40. if p == "all":
  41. continue
  42. args.type = p
  43. args.src = dest + "/src"
  44. args.dest = dest + "/proj." + p
  45. _run(args)
  46. else:
  47. _run(args)
  48. def _run(args):
  49. name = args.name
  50. project = "proj." + args.type + "/"
  51. values = {"PROJECT": name}
  52. text = (".properties", ".cmd", ".mk", ".java", ".sln", ".vcxproj",
  53. ".filters", ".user", ".plist", ".pch", ".json", ".pbxproj")
  54. for t in text:
  55. add_type("text/plain", t)
  56. try:
  57. os.makedirs(args.dest)
  58. except OSError:
  59. # print "folder already exists"
  60. # return
  61. pass
  62. templates_path = os.path.dirname(__file__)
  63. if not templates_path:
  64. templates_path = "."
  65. templates_path += "/templates/"
  66. ox_path = templates_path + "/../../"
  67. root_path = ox_path + "../"
  68. root_path = os.path.abspath(root_path)
  69. ox_path = os.path.abspath(ox_path)
  70. dest_path = os.path.abspath(args.dest) + "/"
  71. root_path = relpath(root_path, dest_path) + "/"
  72. ox_path = relpath(ox_path, dest_path) + "/"
  73. values["OXYGINE"] = unixpath(ox_path)
  74. values["ROOT"] = unixpath(root_path)
  75. values["PROJECT_LC"] = name.lower()
  76. def process(template, relto, path, gl, fn=None):
  77. res = ""
  78. for src in gl:
  79. ext = os.path.splitext(src)[1]
  80. if ext in (".icf", ".orig"):
  81. continue
  82. rel_src_path = relpath(src, relto)
  83. data = {"FILE": unixpath(rel_src_path), "FULLFILE": src}
  84. if fn:
  85. data = fn(data)
  86. t = Template(template)
  87. res += t.safe_substitute(data)
  88. return res
  89. SRC = ""
  90. INCLUDE = ""
  91. data = "../data"
  92. abs_data = os.path.normpath(args.dest + "/" + data)
  93. data_files_ = sorted(glob.glob(abs_data + "/*"))
  94. data_files = []
  95. for d in data_files_:
  96. if os.path.splitext(d)[1] in (".dll", ".lib"):
  97. continue
  98. data_files.append(d)
  99. cpp_files = sorted(glob.glob(args.src + "/*.cpp"))
  100. h_files = sorted(glob.glob(args.src + "/*.h"))
  101. values["PBXBuildFile"] = ""
  102. values["PBXFileReference"] = ""
  103. values["PBXGroup_src"] = ""
  104. values["PBXGroupSupporting"] = ""
  105. values["PBXResourcesBuildPhase"] = ""
  106. values["PBXSourcesBuildPhase"] = ""
  107. if args.src:
  108. relto = dest_path
  109. if args.type == "android":
  110. tmsrc = "${FILE} "
  111. relto = dest_path + "/jni/src/"
  112. SRC = process(tmsrc, relto, args.src, cpp_files)
  113. # INCLUDE = process(tminc, relto, args.src, h_files)
  114. if args.type == "cmake" or args.type == "emscripten":
  115. tmsrc = "${FILE} "
  116. relto = dest_path
  117. SRC = process(tmsrc, relto, args.src, cpp_files)
  118. INCLUDE = process(tmsrc, relto, args.src, h_files)
  119. if args.type == "win32":
  120. tmsrc = """<ClCompile Include="${FILE}" />"""
  121. tminc = """<ClInclude Include="${FILE}" />"""
  122. SRC = process(tmsrc, relto, args.src, cpp_files)
  123. INCLUDE = process(tminc, relto, args.src, h_files)
  124. if args.type in ("macosx", "ios"):
  125. r = random.Random()
  126. r.seed(1)
  127. class Refs(object):
  128. def __init__(self):
  129. self._refs = []
  130. def getObject(self, file):
  131. for ref in self._refs:
  132. if ref[0] == file:
  133. return ref[1]
  134. obj = ""
  135. for i in range(24):
  136. obj += r.choice("0123456789ABCDEF")
  137. self._refs.append((file, obj))
  138. return obj
  139. def getFile(self, obj):
  140. for ref in self._refs:
  141. if ref[1] == obj:
  142. return ref[0]
  143. raise KeyError
  144. globalRefs = Refs()
  145. fileRefs = Refs()
  146. def fn(values):
  147. FILE = values["FILE"]
  148. values["GREF"] = globalRefs.getObject(FILE)
  149. values["FREF"] = fileRefs.getObject(FILE)
  150. values["NAME"] = os.path.split(FILE)[1]
  151. FULL_FILE = values["FULLFILE"]
  152. tp = "wtf"
  153. if os.path.isdir(FULL_FILE):
  154. tp = "folder"
  155. else:
  156. ext = os.path.splitext(FULL_FILE)[1]
  157. if ext == ".cpp":
  158. tp = "sourcecode.cpp.cpp"
  159. if ext == ".h":
  160. tp = "sourcecode.c.h"
  161. values["TYPE"] = tp
  162. return values
  163. # 0405A0061872139000BA6557 /* demo in Resources */ = {isa = PBXBuildFile; fileRef = 0405A0021872139000BA6557 /* demo */; };
  164. # 0405A0071872139000BA6557 /* ext in Resources */ = {isa = PBXBuildFile; fileRef = 0405A0031872139000BA6557 /* ext */; };
  165. # 0405A0081872139000BA6557 /* images in Resources */ = {isa = PBXBuildFile; fileRef = 0405A0041872139000BA6557 /* images */; };
  166. # 0405A0091872139000BA6557 /* xmls in Resources */ = {isa =
  167. # PBXBuildFile; fileRef = 0405A0051872139000BA6557 /* xmls */; };
  168. # 04A57D601871FF9F0068B1E5 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 04A57D3A1871FF9F0068B1E5 /* main.cpp */; };
  169. # 04A57D621871FF9F0068B1E5 /* example.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 04A57D3C1871FF9F0068B1E5 /* example.cpp */; };
  170. # 04A57D651871FF9F0068B1E5 /* test.cpp in Sources */ = {isa =
  171. # PBXBuildFile; fileRef = 04A57D401871FF9F0068B1E5 /* test.cpp */;
  172. # };
  173. tm = "\t\t${GREF} /* ${FILE} in Sources */ = {isa = PBXBuildFile; fileRef = ${FREF} /* ${FILE} */; };\n"
  174. values["PBXBuildFile"] = process(
  175. tm, relto, args.src, cpp_files, fn)
  176. values[
  177. "PBXBuildFile"] += process(tm, relto, abs_data, data_files, fn)
  178. # 04A57D3A1871FF9F0068B1E5 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../../src/main.cpp; sourceTree = "<group>"; };
  179. # 04A57D3C1871FF9F0068B1E5 /* example.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = example.cpp; path = ../../src/example.cpp; sourceTree = "<group>"; };
  180. # 04A57D3E1871FF9F0068B1E5 /* example.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = example.h; path = ../../src/example.h; sourceTree = "<group>"; };
  181. # 04A57D401871FF9F0068B1E5 /* test.cpp */ = {isa =
  182. # PBXFileReference; fileEncoding = 4; lastKnownFileType =
  183. # sourcecode.cpp.cpp; name = test.cpp; path = ../../src/test.cpp;
  184. # sourceTree = "<group>"; };
  185. # 0405A0021872139000BA6557 /* demo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = demo; path = ../../data/demo; sourceTree = "<group>"; };
  186. # 0405A0031872139000BA6557 /* ext */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ext; path = ../../data/ext; sourceTree = "<group>"; };
  187. # 0405A0041872139000BA6557 /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../data/images; sourceTree = "<group>"; };
  188. # 0405A0051872139000BA6557 /* xmls */ = {isa = PBXFileReference;
  189. # lastKnownFileType = folder; name = xmls; path = ../../data/xmls;
  190. # sourceTree = "<group>"; };
  191. files = []
  192. files.extend(cpp_files)
  193. files.extend(h_files)
  194. files.extend(data_files)
  195. tm = """\t\t${FREF} /* ${FILE} */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = ${TYPE}; name = ${NAME}; path = ${FILE}; sourceTree = "<group>"; };""" + "\n"
  196. values["PBXFileReference"] = process(
  197. tm, relto, args.src, files, fn)
  198. # 04A57D3A1871FF9F0068B1E5 /* main.cpp */,
  199. # 04A57D3C1871FF9F0068B1E5 /* example.cpp */,
  200. # 04A57D3E1871FF9F0068B1E5 /* example.h */,
  201. # 04A57D401871FF9F0068B1E5 /* test.cpp */,
  202. tm = "\t\t\t\t${FREF} /* ${NAME} */, \n"
  203. files = []
  204. files.extend(cpp_files)
  205. files.extend(h_files)
  206. values["PBXGroup_src"] = process(tm, relto, args.src, files, fn)
  207. # 0405A0021872139000BA6557 /* demo */,
  208. # 0405A0031872139000BA6557 /* ext */,
  209. # 0405A0041872139000BA6557 /* images */,
  210. # 0405A0051872139000BA6557 /* xmls */,
  211. values["PBXGroupSupporting"] = process(
  212. tm, relto, abs_data, data_files, fn)
  213. # 0405A0081872139000BA6557 /* images in Resources */,
  214. # 0405A0071872139000BA6557 /* ext in Resources */,
  215. # 0405A0061872139000BA6557 /* demo in Resources */,
  216. # 0405A0091872139000BA6557 /* xmls in Resources */,
  217. tm = "\t\t\t\t${GREF} /* ${NAME} */, \n"
  218. values["PBXResourcesBuildPhase"] = process(
  219. tm, relto, abs_data, data_files, fn)
  220. # 04A57D621871FF9F0068B1E5 /* example.cpp in Sources */,
  221. # 04A57D601871FF9F0068B1E5 /* main.cpp in Sources */,
  222. # 04A57D651871FF9F0068B1E5 /* test.cpp in Sources */,
  223. values["PBXSourcesBuildPhase"] = process(
  224. tm, relto, args.src, cpp_files, fn)
  225. values["SRC"] = SRC
  226. values["INCLUDE"] = INCLUDE
  227. values["DATA"] = "../data"
  228. def process_folder(path, dest):
  229. try:
  230. os.mkdir(dest)
  231. except OSError:
  232. pass
  233. for src in os.listdir(path):
  234. src_path = path + src
  235. t = Template(src)
  236. dest_local = t.substitute(**values)
  237. if os.path.isdir(src_path):
  238. process_folder(src_path + "/", dest + dest_local + "/")
  239. continue
  240. dest_path = dest + dest_local
  241. ext = os.path.splitext(dest_path)[1]
  242. print("src " + src_path)
  243. tp = guess_type(src_path)
  244. if ext in (".storyboard", ".gradle"):
  245. tp = ("text", "")
  246. if not tp[0]:
  247. print(">>>>>>>>>>" + str(tp))
  248. continue
  249. print(tp[0])
  250. q = tp[0].split("/")
  251. if q[0] == "text" or q[1] in ("xml", "x-msdos-program", "x-sh"):
  252. print("creating file: " + dest_path)
  253. src_data = open(src_path, "r").read()
  254. t = Template(src_data)
  255. dest_data = t.safe_substitute(**values)
  256. ext = os.path.splitext(dest_path)[1]
  257. if args.type == "ios" or args.type == "macosx" or ext == ".sh":
  258. dest_file = io.open(dest_path, "w", newline="\n")
  259. try:
  260. dest_file.write(dest_data)
  261. except TypeError:
  262. dest_file.write(unicode(dest_data, encoding='utf-8'))
  263. else:
  264. dest_file = open(dest_path, "w")
  265. dest_file.write(dest_data)
  266. shutil.copystat(src_path, dest_path)
  267. else:
  268. print("copying file: " + dest_path)
  269. shutil.copyfile(src_path, dest_path)
  270. top_path = templates_path + project + "/"
  271. process_folder(top_path, args.dest + "/")
  272. if __name__ == "__main__":
  273. parser = argparse.ArgumentParser(
  274. description="Oxygine project generator")
  275. parser.add_argument("-t", "--type", help="Target platform",
  276. choices=platforms, default="win32")
  277. parser.add_argument(
  278. "-s", "--src", help="folder with already created source files", default="")
  279. parser.add_argument(
  280. "-d", "--dest", help="Destination folder", default=".")
  281. parser.add_argument("--hello", help="Generates a full copy of the HelloWorld example targeting all platforms",
  282. action="store_true", default=False)
  283. parser.add_argument("name", help="Name of the project")
  284. args = parser.parse_args()
  285. run(args)