scaffolding.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. # -*- coding: utf-8 -*-
  2. import os, re
  3. from shutil import copytree
  4. from toolset.utils.metadata import Metadata
  5. class Scaffolding:
  6. def __init__(self, benchmarker):
  7. print("""
  8. -------------------------------------------------------------------------------
  9. This wizard is intended to help build the scaffolding required for a new
  10. test to be benchmarked.
  11. From here, you will be prompted for values related to the test you
  12. wish to add.
  13. -------------------------------------------------------------------------------"""
  14. )
  15. self.benchmarker = benchmarker
  16. self.benchmarker_config = benchmarker.config
  17. try:
  18. self.__gather_display_name()
  19. self.__gather_language()
  20. self.__gather_approach()
  21. self.__gather_classification()
  22. self.__gather_database()
  23. self.__gather_orm()
  24. self.__gather_webserver()
  25. self.__gather_versus()
  26. self.__confirm_values()
  27. self.__print_success()
  28. except:
  29. print("")
  30. def __gather_display_name(self):
  31. print("""
  32. The name of your test as you wish it to be displayed on the results page.
  33. Example: Gemini, Gin, Express
  34. """)
  35. self.__prompt_display_name()
  36. while not self.display_name:
  37. self.__prompt_display_name()
  38. self.name = self.display_name.lower()
  39. def __prompt_display_name(self):
  40. self.display_name = raw_input("Name: ").strip()
  41. found = False
  42. for framework in self.benchmarker.metadata.gather_frameworks():
  43. if framework.lower() == self.display_name.lower():
  44. found = True
  45. if found:
  46. print("""
  47. It appears that there is already a '%s' framework in the test suite. You will
  48. have to pick a different name.
  49. """ % self.display_name)
  50. self.display_name = None
  51. def __gather_language(self):
  52. print("""
  53. The language in which your test implementation is written.
  54. Example: Java, Go, PHP
  55. """)
  56. self.language = None
  57. while not self.language:
  58. self.__prompt_language()
  59. def __prompt_language(self):
  60. self.language = raw_input("Language: ").strip()
  61. known_languages = self.benchmarker.metadata.gather_languages()
  62. language = None
  63. for lang in known_languages:
  64. if lang.lower() == self.language.lower():
  65. language = lang
  66. if not language:
  67. similar = []
  68. for lang in known_languages:
  69. if lang.lower()[:1] == self.language.lower()[:1]:
  70. similar.append(lang)
  71. similar = ', '.join(similar)
  72. print("""
  73. That language is not currently in our list of known languages.
  74. Here is a list of similar languages present in our benchmark suite that you
  75. may have meant:
  76. %s
  77. Did you mean to add the new language, '%s', to the benchmark suite?
  78. """ % (similar, self.language))
  79. valid = self.__prompt_confirm_new_language()
  80. while not valid:
  81. valid = self.__prompt_confirm_new_language()
  82. if self.confirm_new_lang == 'n':
  83. self.language = None
  84. else:
  85. self.language = self.language.title()
  86. return self.language
  87. def __prompt_confirm_new_language(self):
  88. self.confirm_new_lang = raw_input("Create New Language '%s' (y/n): " %
  89. self.language).strip().lower()
  90. return self.confirm_new_lang == 'y' or self.confirm_new_lang == 'n'
  91. def __gather_approach(self):
  92. print("""
  93. The approach of your test implementation.
  94. 1) Realistic: Uses the framework with most out-of-the-box functionality
  95. enabled. We consider this realistic because most applications
  96. built with the framework will leave these features enabled.
  97. 2) Stripped: Removes or outright avoids implementing features that are
  98. unnecessary for the particulars of the benchmark exercise. This
  99. might illuminate the marginal improvement available in fine-
  100. tuning a framework to your application's use-case.
  101. Note: If you are unsure, then your approach is probably Realistic. The
  102. Stripped approach is seldom used and will not have results displayed
  103. by default on the results website.
  104. """)
  105. valid = self.__prompt_approach()
  106. while not valid:
  107. valid = self.__prompt_approach()
  108. def __prompt_approach(self):
  109. self.approach = raw_input("Approach [1/2]: ").strip()
  110. if self.approach == '1':
  111. self.approach = 'Realistic'
  112. if self.approach == '2':
  113. self.approach = 'Stripped'
  114. return self.approach == 'Realistic' or self.approach == 'Stripped'
  115. def __gather_classification(self):
  116. print("""
  117. The classification of your test implementation.
  118. 1) Fullstack: Robust framework expected to provide high-level functionality
  119. for serving as a web application; for example, ability to
  120. compose views, provide functions for responding with several
  121. data types (json, html, etc), connecting to a database, form
  122. processing, etc.
  123. 2) Micro: Simple framework expected to provide enough middleware to build
  124. a robust web application such as request routing and some
  125. simple plumbing, but may not include built-in functionality
  126. such as, for example, server-composed views.
  127. 3) Platform: Barebones infrastructure for servicing HTTP requests, but does
  128. not include a framework at all.
  129. """)
  130. valid = self.__prompt_classification()
  131. while not valid:
  132. valid = self.__prompt_classification()
  133. if self.classification == 'Platform':
  134. self.platform = 'None'
  135. self.framework = 'None'
  136. else:
  137. self.framework = self.display_name
  138. self.__gather_platform()
  139. def __prompt_classification(self):
  140. self.classification = raw_input("Classification [1/2/3]: ").strip()
  141. if self.classification == '1':
  142. self.classification = 'Fullstack'
  143. if self.classification == '2':
  144. self.classification = 'Micro'
  145. if self.classification == '3':
  146. self.classification = 'Platform'
  147. return self.classification == 'Fullstack' or \
  148. self.classification == 'Micro' or \
  149. self.classification == 'Platform'
  150. def __gather_platform(self):
  151. print("""
  152. The platform of your test implementation.
  153. The platform is the low-level software or API used to host web applications
  154. for the framework; the platform provides an implementation of the HTTP
  155. fundamentals.
  156. Not all frameworks have a platform and if your programming language provides
  157. much of that by which we define a platform, leave black.
  158. Example: Servlet, Wai, .NET
  159. """)
  160. self.__prompt_platform()
  161. def __prompt_platform(self):
  162. self.platform = raw_input("Platform (optional): ").strip()
  163. if self.platform == '':
  164. self.platform = 'None'
  165. def __gather_database(self):
  166. print("""
  167. Which database will you be using for your test?
  168. """)
  169. i = 1
  170. prompt = "Database ["
  171. options = []
  172. for db in Metadata.supported_dbs:
  173. print(" {!s}) {!s}: {!s}".format(i, db[0], db[1]))
  174. prompt += "{!s}/".format(i)
  175. options.append(db[0])
  176. i += 1
  177. print(" {!s}) None: No database at this time{!s}".format(i, os.linesep))
  178. prompt += "{!s}]: ".format(i)
  179. options.append("None")
  180. valid = self.__prompt_database(prompt, options)
  181. while not valid:
  182. valid = self.__prompt_database(prompt, options)
  183. def __prompt_database(self, prompt, options):
  184. self.database = raw_input(prompt).strip()
  185. if 0 < int(self.database) <= len(options):
  186. self.database = options[int(self.database) - 1]
  187. return True
  188. else:
  189. return False
  190. def __gather_orm(self):
  191. if self.database == 'None':
  192. self.orm = 'None'
  193. return
  194. print("""
  195. How you would classify the ORM (object relational mapper) of your test?
  196. 1) Full: A feature-rich ORM which provides functionality for interacting
  197. with a database without writing a query in all but the most edge
  198. cases.
  199. 2) Micro: An ORM which provides functionality for interacting with a database
  200. for many trivial operations (querying, updating), but not more
  201. robust cases (for example, gathering relations).
  202. 3) Raw: No ORM; raw database access.
  203. """)
  204. valid = self.__prompt_orm()
  205. while not valid:
  206. valid = self.__prompt_orm()
  207. def __prompt_orm(self):
  208. self.orm = raw_input("ORM [1/2/3]: ").strip()
  209. if self.orm == '1':
  210. self.orm = 'Full'
  211. if self.orm == '2':
  212. self.orm = 'Micro'
  213. if self.orm == '3':
  214. self.orm = 'Raw'
  215. return self.orm == 'Full' or \
  216. self.orm == 'Micro' or \
  217. self.orm == 'Raw'
  218. def __gather_webserver(self):
  219. print("""
  220. Name of the front-end webserver sitting in front of your test implementation.
  221. Your test implementation may not use a web-server and may act as its own; you
  222. can leave this blank in this case.
  223. Example: nginx, Meinheld, httplight
  224. """)
  225. self.__prompt_webserver()
  226. def __prompt_webserver(self):
  227. self.webserver = raw_input("Webserver (optional): ").strip()
  228. if self.webserver == '':
  229. self.webserver = 'None'
  230. def __gather_versus(self):
  231. print("""
  232. The name of another test (elsewhere in this project) that is a subset of this
  233. framework.
  234. This allows for the generation of the framework efficiency chart in the
  235. results web site.
  236. For example, Compojure is compared to "servlet" since Compojure is built on
  237. the Servlet platform.
  238. Example: Servlet, Wai, Undertow
  239. """)
  240. self.__prompt_versus()
  241. def __prompt_versus(self):
  242. self.versus = raw_input("Versus (optional): ").strip()
  243. if self.versus == '':
  244. self.versus = 'None'
  245. def __confirm_values(self):
  246. print("""
  247. Name: %s
  248. Language: %s
  249. Approach: %s
  250. Classification: %s
  251. Platform: %s
  252. ORM: %s
  253. Webserver: %s
  254. Versus: %s
  255. Finalize the initialization of your test given the above values?
  256. Note: once you have initialized your test, you can change these values later.
  257. """ % (self.display_name, self.language, self.approach,
  258. self.classification, self.platform, self.orm, self.webserver,
  259. self.versus))
  260. valid = self.__prompt_confirmation()
  261. while not valid:
  262. valid = self.__prompt_confirmation()
  263. if self.confirmation == 'y':
  264. self.__build_scaffolding()
  265. else:
  266. print('Aborting')
  267. def __prompt_confirmation(self):
  268. self.confirmation = raw_input("Initialize [y/n]: ").strip().lower()
  269. return self.confirmation == 'y' or self.confirmation == 'n'
  270. def __build_scaffolding(self):
  271. if self.__create_test_folder():
  272. self.__copy_scaffold_files()
  273. self.__edit_scaffold_files()
  274. def __create_test_folder(self):
  275. self.language_dir = os.path.join(self.benchmarker_config.lang_root,
  276. self.language)
  277. self.test_dir = os.path.join(self.language_dir, self.name)
  278. if os.path.exists(self.test_dir):
  279. print("Test '%s' already exists; aborting." % self.name)
  280. return False
  281. return True
  282. def __copy_scaffold_files(self):
  283. copytree(self.benchmarker_config.scaffold_root, self.test_dir)
  284. def __edit_scaffold_files(self):
  285. for file in os.listdir(os.path.join(self.test_dir)):
  286. self.__replace_text(
  287. os.path.join(self.test_dir, file), "\$NAME", self.name)
  288. self.__replace_text(
  289. os.path.join(self.test_dir, file), "\$DISPLAY_NAME",
  290. self.display_name)
  291. self.__replace_text(
  292. os.path.join(self.test_dir, file), "\$APPROACH", self.approach)
  293. self.__replace_text(
  294. os.path.join(self.test_dir, file), "\$CLASSIFICATION",
  295. self.classification)
  296. self.__replace_text(
  297. os.path.join(self.test_dir, file), "\$FRAMEWORK",
  298. self.framework)
  299. self.__replace_text(
  300. os.path.join(self.test_dir, file), "\$LANGUAGE", self.language)
  301. self.__replace_text(
  302. os.path.join(self.test_dir, file), "\$DATABASE", self.database)
  303. self.__replace_text(
  304. os.path.join(self.test_dir, file), "\$ORM", self.orm)
  305. self.__replace_text(
  306. os.path.join(self.test_dir, file), "\$PLATFORM", self.platform)
  307. self.__replace_text(
  308. os.path.join(self.test_dir, file), "\$WEBSERVER",
  309. self.webserver)
  310. self.__replace_text(
  311. os.path.join(self.test_dir, file), "\$VERSUS", self.versus)
  312. def __print_success(self):
  313. print("""
  314. -------------------------------------------------------------------------------
  315. Success!
  316. Your new test structure has been built to the sepcifications of the suite.
  317. Here is a brief run-down of what has been built:
  318. frameworks
  319. └─── %s
  320. └─── %s
  321. ├─── benchmark_config.json
  322. ├─── README.md
  323. └─── source_code
  324. The next step is to read through your README.md and follow the instructions
  325. provided therein.
  326. -------------------------------------------------------------------------------"""
  327. % (self.language, self.name))
  328. # Replaces all text found using the regular expression to_replace with the supplied replacement.
  329. def __replace_text(self, file, to_replace, replacement):
  330. with open(file, "r") as conf:
  331. contents = conf.read()
  332. replaced_text = re.sub(to_replace, replacement, contents)
  333. with open(file, "w") as f:
  334. f.write(replaced_text)