gen_template.py 13 KB

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