1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 __authors__ = ["Mark Basham", "Olof Svensson", "Jérôme Kieffer"]
27 __license__ = "GPLv3"
28 __date__ = "2011-06-17"
29 __copyright__ = "DLS"
30 """
31
32 This creates an EDNA plugin template for use with the EDNA framework
33 It creates the whole directory framework needed, the core plugin code
34 and the core tests, which are all run as part of the generator
35
36 This creates the following directory structure and files::
37 ProjectName
38 |--plugins
39 | |--EDPluginName-v1.0
40 | | |--datamodel
41 | | | |--generateXSDataTemplate.sh
42 | | | |--XSDataExecTest3.xsd
43 | | |--plugins
44 | | | |--EDPluginNamev10.py
45 | | | |--XSDataPluginName.py
46 | | |--tests
47 | | | |--data
48 | | | | |--XSConfiguration_PluginName.xml
49 | | | | |--XSDataInputPluginName_reference.xml
50 | | | | |--XSDataResultPluginName_reference.xml
51 | | | |--testsuite
52 | | | | |--EDTestCasePluginNameExecuteTest.py
53 | | | | |--EDTestCasePluginNameUnitTest.py
54 | | | | |--EDTestSuitePluginNameTest.py
55
56 """
57 import optparse
58 import os
59 import sys
60 import shutil
61 import subprocess
62 import xml.dom.minidom
63
65 """
66 Class description
67 """
69
70 self._base_name = None
71
72 self._project_name = None
73
74 self._site_name = None
75
76
77 self._version = None
78 self._copyright = None
79 self._author = None
80
81
82 self._template_dir = None
83 self._root_directory = None
84
85
86 self._xsd_filename = None
87 self._xsd_name = None
88 self._xsd_data_input_name = None
89 self._xsd_data_result_name = None
90 self._xsd_input = None
91 self._xsd_result = None
92 self._xsd_general = None
93
94
95 self._plugin_name = None
96 self._plugin_base_directory = None
97 self._plugin_filename = None
98 self._plugin_test_filename = None
99
100
101 self._slave_plugin_name = None
102
103
104
105 self._valid_base_names = ["Exec", "Control"]
106
107
108 self._invalid_plugin_characters = [' ']
109
110
111 self._cache_dirname = None
112 self._cache_xsd_base_name = None
113 self._cache_replacements = None
114
115 return
116
118 """
119 Sets the root directory as well as checking that it exists
120 """
121
122 if not os.path.exists(root_directory):
123 raise RuntimeError("The directory '%s' is not present" % root_directory)
124 self._root_directory = root_directory
125 return
126
128 if not self._cache_xsd_base_name :
129 assert(self._plugin_name)
130 if (self._xsd_general == None):
131 self._cache_xsd_base_name = "XSData%s%s" % (self._base_name, self._plugin_name)
132
133 else:
134 (filepath, filename) = os.path.split(self._xsd_filename)
135 self._cache_xsd_base_name = filename.split('.')[0]
136 return self._cache_xsd_base_name
137
139 """
140 Sets the base name, and makes sure it is valid
141 """
142 for valid_name in self._valid_base_names:
143 if(base_name.upper() == valid_name.upper()):
144 self._base_name = valid_name
145 return
146
147
148 raise RuntimeError("Base plugin needs to be either a control or exec plugin you have specified a %s plugin" % base_name)
149
150
152 """
153 Set the plugin name throwing an error if there are any invalid characters
154 """
155 self._plugin_name = plugin_name.strip()
156 for token in self._invalid_plugin_characters:
157 if plugin_name.find(token) > 0:
158 raise RuntimeError("The plugin name contains the invalid character '%s' please remove this to continue" % token)
159
160 self._plugin_name = plugin_name
161 return
162
164
165 if version.find(".") == -1:
166 raise RuntimeError("""The plugin version must contain a ".", e.g. 1.0, 2.2 etc. Non valid version: %s""" % version)
167 (strMajorNumber, strMinorNumber) = version.split(".")
168 try:
169 iMajorNumber = int(strMajorNumber)
170 except Exception:
171 raise RuntimeError("""The plugin version major number not an integer: %s""" % strMajorNumber)
172 try:
173 iMinorNumber = int(strMinorNumber)
174 except Exception:
175 raise RuntimeError("""The plugin version minor number not an integer: %s""" % strMinorNumber)
176 self._version = version
177 return
178
180 self._copyright = copyright
181 return
182
184 self._author = author
185 return
186
188 if not os.path.exists(template_dir):
189 raise RuntimeError("The template directory '%s' does not exist" % template_dir)
190 self._template_dir = template_dir
191 return
192
194 """
195 Sets the filename and also works out the name part, i.e. XSDataFooBar.xsd
196 This now also pulls out the information and sets 2 other parameters :
197 _xsd_data_input_name
198 _xsd_data_result_name
199 """
200 if xsd_filename is not None:
201 if not os.path.exists(xsd_filename):
202 raise RuntimeError("The xsd filename '%s' does not exist" % xsd_filename)
203 self._xsd_filename = xsd_filename
204 self._xsd_name = os.path.split(xsd_filename)[-1]
205 self.check_xsd_input_and_result_with_xsd(xsd_filename)
206 return
207
211
213 self._xsd_result = xsd_result
214 return
215
217 self._xsd_general = xsd_general
218 return
219
221 self._project_name = project_name
222 return
223
225 self._generator_filename = generator_filename
226 return
227
229 if not self._cache_dirname :
230 assert(self._plugin_name)
231 assert(self._version)
232 self._cache_dirname = "EDPlugin%s%s-v%s" % (self._base_name, self._plugin_name, self._version)
233 return self._cache_dirname
234
237
239 self._plugin_filename = plugin_filename
240 return
241
243 self._plugin_test_filename = plugin_test_filename
244 return
245
247 self._slave_plugin_name = slave_plugin_name
248 return
249
251 self._site_name = site_name
252 return
253
255 self._plugin_base_directory = plugin_directory
256
258 """
259 This creates the file structure and populates some other parameters which are needed
260 """
261 assert(self._root_directory)
262 if not self._plugin_base_directory:
263 self._plugin_base_directory = os.path.join(self._root_directory, self.get_dir_name())
264
265
266
267
268 if not self._xsd_general:
269 if self._xsd_name:
270 os.makedirs(os.path.join(self._plugin_base_directory, "datamodel"))
271 plugin_dir = os.path.join(self._plugin_base_directory, "plugins")
272 for lmydir in [["plugins"], ["tests", "data"], ["tests", "testsuite"]]:
273 full_path = os.path.join(*([self._plugin_base_directory] + lmydir))
274 if not os.path.isdir(full_path):
275 os.makedirs(full_path)
276
277
278
279
280
282 if not self._cache_replacements :
283 assert(self._copyright)
284 assert(self._author)
285 assert(self._project_name)
286 assert(self._base_name)
287 self._cache_replacements = {}
288 self._cache_replacements['<copyright>'] = self._copyright
289 self._cache_replacements['<author>'] = self._author
290 self._cache_replacements['<xsDataBaseDir>'] = self.get_dir_name()
291 self._cache_replacements['<xsDataBaseName>'] = self.get_xsd_base_name()
292 self._cache_replacements['<xsDataName>'] = self.get_xsd_name()
293 self._cache_replacements['<projectName>'] = self._project_name
294 self._cache_replacements['<fileName>'] = "EDPlugin%s%s%sv%s" % (self._base_name, self._plugin_name, self._version.replace(".", "_"), '.py')
295 self._cache_replacements['<xsDataInputName>'] = self._xsd_data_input_name
296 self._cache_replacements['<xsDataResultName>'] = self._xsd_data_result_name
297
298 self._cache_replacements['<pluginName>'] = "%sv%s" % (self._plugin_name, self._version.replace(".", "_"))
299 self._cache_replacements['<controledPluginName>'] = self._slave_plugin_name
300 self._cache_replacements['<basePluginName>'] = self._plugin_name
301 self._cache_replacements['<pluginDir>'] = self.get_dir_name()
302 self._cache_replacements['<baseName>'] = self._base_name
303 self._cache_replacements['[pluginName]'] = "EDPlugin%s%sv%s" % (self._base_name, self._plugin_name, self._version.replace(".", "_"))
304 return self._cache_replacements
305
307 infile = open(templatefilename, "r")
308 outfile = open(outputfilename, "w")
309 for line in infile.readlines():
310 for key in replacement_dict.keys():
311 if replacement_dict[key] is not None:
312 line = line.replace(key, replacement_dict[key])
313 else:
314 line = line.replace(key, "None")
315 outfile.write(line)
316
318 print 'running create_xsd_converter_script()...'
319 assert(self._plugin_base_directory)
320 assert(self._xsd_filename)
321 assert(self._xsd_name)
322 assert(self._template_dir)
323 replacements = self.get_replacement_dictionary()
324
325 template_file = os.path.join(self._template_dir, "datamodel", "generateXSDataTemplate.sh")
326 new_file = os.path.join(self._plugin_base_directory, "datamodel", "generate%s.sh" % os.path.splitext(self._xsd_name)[0])
327 self.set_generator_filename(new_file)
328 self.create_template_replaced_file(template_file, new_file, replacements)
329
330
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
389 tree = xml.dom.minidom.parse(xsd_file_name)
390 input_and_result = tree.getElementsByTagName("xs:complexType")
391
392 order = 0
393 for part in input_and_result:
394 if not part.getElementsByTagName("xs:extension") == []:
395 if part.getElementsByTagName("xs:extension")[0].getAttribute("base") == "XSDataInput":
396 self._xsd_data_input_name = part.getAttribute("name")
397 print 'XSDataInput ' + str(order) + ' : ' + str(self._xsd_data_input_name)
398 order = order + 1
399
400 order = 0
401 for part in input_and_result:
402 if not part.getElementsByTagName("xs:extension") == []:
403 if part.getElementsByTagName("xs:extension")[0].getAttribute("base") == "XSDataResult":
404 self._xsd_data_input_name = part.getAttribute("name")
405 print 'XSDataResult ' + str(order) + ' : ' + str(self._xsd_data_input_name)
406 order = order + 1
407
409 assert(self._plugin_base_directory)
410 assert(self._xsd_filename)
411 new_path = os.path.join(self._plugin_base_directory, "datamodel", self.get_xsd_name())
412 shutil.copy(self._xsd_filename, new_path)
413 return
414
415
417 assert(self._generator_filename)
418 subprocess.call(["bash", self._generator_filename])
419 return
420
422 if os.path.exists(new_file):
423 raise RuntimeError("The file %s already exist, I stop NOW !!!" % new_file)
424 sys.exit(1)
425
426
428 assert(self._base_name)
429 replacements = self.get_replacement_dictionary()
430 template_file = os.path.join(self._template_dir, "plugins")
431 template_file = os.path.join(template_file, "EDPlugin%s.py.template" % self._base_name)
432 new_file = os.path.join(self._plugin_base_directory, "plugins")
433 new_file = os.path.join(new_file, "EDPlugin%s%sv%s.py" % (self._base_name, self._plugin_name, self._version.replace(".", "_")))
434 self.check_file_does_not_exist(new_file)
435 self.set_plugin_filename(new_file)
436 self.create_template_replaced_file(template_file, new_file, replacements)
437 return
438
440 assert(self._base_name)
441 assert(self._plugin_name)
442 replacements = self.get_replacement_dictionary()
443 template_dir = os.path.join(self._template_dir, "tests", "testsuite")
444 plugin_dir = os.path.join(self._plugin_base_directory, "tests", "testsuite")
445 template_file = os.path.join(template_dir, "EDTestCasePluginExecute%s.py.template" % self._base_name)
446 new_file = os.path.join(plugin_dir, "EDTestCasePluginExecute%s%sv%s.py" % (self._base_name, self._plugin_name, self._version.replace(".", "_")))
447 self.check_file_does_not_exist(new_file)
448 self.create_template_replaced_file(template_file, new_file, replacements)
449 template_file = os.path.join(template_dir, "EDTestCasePluginUnit%s.py.template" % self._base_name)
450 new_file = os.path.join(plugin_dir, "EDTestCasePluginUnit%s%sv%s.py" % (self._base_name, self._plugin_name, self._version.replace(".", "_")))
451 self.check_file_does_not_exist(new_file)
452 self.create_template_replaced_file(template_file, new_file, replacements)
453 template_file = os.path.join(template_dir, "EDTestSuitePlugin.py.template")
454 new_file = os.path.join(plugin_dir, "EDTestSuitePlugin%s%sv%s.py" % (self._base_name, self._plugin_name, self._version.replace(".", "_")))
455 self.check_file_does_not_exist(new_file)
456 self.create_template_replaced_file(template_file, new_file, replacements)
457 return
458
476
478 assert(self._base_name)
479 assert(self._plugin_name)
480 assert(self._version)
481 test_runner_location = os.path.join(os.environ['EDNA_HOME'], "kernel", "bin", "edna-test-launcher")
482 plugin_to_be_tested = "EDTestSuitePlugin%s%sv%s" % (self._base_name, self._plugin_name, self._version.replace(".", "_"))
483 print "Running the tests"
484 subprocess.call([test_runner_location, "--test", plugin_to_be_tested])
485 return
486
488 assert(self._site_name)
489 assert(self._root_directory)
490 assert(self._plugin_base_directory)
491 assert(self._plugin_name)
492
493 config_path = os.path.join(self._root_directory, "..", "conf")
494 config_filename = os.path.join(config_path, "XSConfiguration_%s.xml" % self._site_name)
495 config_testfile = os.path.join(self._plugin_base_directory, "tests", "data", "XSConfiguration_%s.xml" % (self._plugin_name))
496
497 if os.path.exists(config_filename):
498
499 main_tree = xml.dom.minidom.parse(config_filename)
500 add_tree = xml.dom.minidom.parse(config_testfile)
501
502 add_node = add_tree.getElementsByTagName("XSPluginItem")[0]
503 main_tree.getElementsByTagName("XSPluginList")[0].appendChild(add_node)
504
505 main_tree.writexml(open(config_filename, "w"))
506 return
507
508 else :
509 if not os.path.exists(config_path):
510 os.makedirs(config_path)
511
512 shutil.copy(config_testfile, config_filename)
513 return
514
534
552
554
555 parser = optparse.OptionParser(formatter=HelpFormatter(), description=
556 "This program is designed to allow the auto generation of an EDNA plugin."
557 "\nTo use this EDNA_HOME, and EDNA_CONFIG need to be set, where EDNA_CONFIG should be something "
558 "\nlike 'DLS' or 'ESRF' and EDNA_HOME should be set to the direcoty which contains the EDNA "
559 "\nkernel, it must also contain the base directory structure of the project you want to use."
560 "\nThe default project is EDNA_HOME/templatev1/plugin"
561 "\n\nUsage :"
562 "\nPluginGenerator.py"
563 "\n\tGenerates an example plugin in the default project"
564 "\nPluginGenerator.py -n MyPlugin -b Control -v 2.1 -i XSDataInputMTZDUMPUnitCellSpaceGroup -r XSDataResultMTZDUMPUnitCellSpaceGroup -a 'Mark Basham' -c DLS"
565 "\n\tGenerates a plugin called MyPlugin which is version 2.1 of a control plugin with the specified input and result"
566 "\n\tauthored by Mark Basham and with DLS as the copyright holder"
567 "\n\t"
568 )
569
570 parser.add_option("-n", "--plugin-name", dest="plugin_name", help="Specifies the name of the plugin you wish to create", default="Template")
571 parser.add_option("-b", "--base-plugin", dest="base_name", help="Specifies which plugin you want your new plugin to inherit from", default="Exec")
572 parser.add_option("-p", "--project-name", dest="project_name", help="Specifies the name of the project inside edna where this plugin will be i.e. the directory after EDNA_HOME, such as mxv1 or darcv1", default="templatev1")
573 parser.add_option("-x", "--xsd-location", dest="xsd_location", help="Specifies the location of the XSD, which is to be used for the plugin. This option is mandatory if the -g tag is not specified (using the local xsd).")
574
575 parser.add_option("-i", "--xsd-input", dest="xsd_input", help="Specifies the input XSData class, e.g. XSDataInputStrategy")
576 parser.add_option("-r", "--xsd-result", dest="xsd_result", help="Specifies the result XSData class, e.g. XSDataResultStrategy")
577
578
579 parser.add_option("-g", "--xsd-general", dest="xsd_general", action="store_true", help="Specifies that the plugin generator will be using the general datamodel")
580
581 parser.add_option("-e", "--emulate-plugin", dest="plugin_to_emulate", help="Specifies the location of the plugin which this plugin will replace, this is not curently implemented")
582 parser.add_option("-v", "--plugin-version", dest="plugin_version", help="Specifies version of the plugin, e.g. 1.0/1.2/2.3/3.10 etc", default="1.0")
583 parser.add_option("-a", "--author", dest="plugin_author", help="The principle author of the plugin i.e. you", default="Default Author")
584 parser.add_option("-c", "--copyright", dest="plugin_copyright", help="Specifies the copyright string which will be present in the plugin", default="2008-2009 - EDNA Default Copyright")
585 parser.add_option("-s", "--slave-plugin-name", dest="slave_plugin_name", help="If the plugin is a control plugin, this specifies which plugin will be controled", default="EDPluginExecTemplate")
586 parser.add_option("--site-name", dest="site_name", help="the name of the site, to decide which configuration file to add the plugin to, i.e. DLS/ESRF etc, default is DLS", default="DLS")
587 parser.add_option("--no-xsd", dest="generateDB", action="store_false", help="use this option to prevent the generation of the databindings ", default=True)
588 parser.add_option("--force_location", dest="plugin_root", help="use this option to enforce the location a plugin in EDNA's tree", default=None)
589
590 (options, args) = parser.parse_args()
591
592
593 if options.xsd_location is None and options.xsd_general is not None:
594 print "A mandatory option -x is missing as -g is present\n"
595 parser.print_help()
596 os.sys.exit(0)
597
598 pg = PluginGenerator()
599
600 if not 'EDNA_HOME' in os.environ:
601 pyStrProgramPath = os.path.abspath(sys.argv[0])
602 pyStrBinPath = os.path.split(pyStrProgramPath)[0]
603 pyStrKernelPath = os.path.split(pyStrBinPath)[0]
604 pyStrEdnaHomePath = os.path.split(pyStrKernelPath)[0]
605 os.environ["EDNA_HOME"] = pyStrEdnaHomePath
606 print ('EDNA_HOME not set, trying to guess it .... %s' % pyStrEdnaHomePath)
607 else:
608 pyStrEdnaHomePath = os.environ['EDNA_HOME']
609
610 if options.plugin_root:
611 root_dir = os.path.join(pyStrEdnaHomePath, options.plugin_root)
612 plugin_dir = os.path.join(pyStrEdnaHomePath, options.plugin_root)
613 else:
614 root_dir = os.path.join(pyStrEdnaHomePath, options.project_name, "plugins")
615
616 if not os.path.exists(root_dir):
617
618 os.makedirs(root_dir)
619
620 template_dir = os.path.join(os.environ['EDNA_HOME'], "template")
621
622 xsd_loc = options.xsd_location
623 if xsd_loc == None and options.generateDB:
624 xsd_loc = os.path.join(template_dir, "datamodel")
625 xsd_loc = os.path.join(xsd_loc, "XSDataTemplate.xsd")
626
627 pg.set_root_directory(root_dir)
628 pg.set_base_name(options.base_name)
629 pg.set_plugin_name(options.plugin_name)
630 pg.set_version(options.plugin_version)
631 pg.set_author(options.plugin_author)
632 pg.set_copyright(options.plugin_copyright)
633 pg.set_plugin_directory(plugin_dir)
634 if options.generateDB:
635 pg.set_xsd_input(options.xsd_input)
636 pg.set_xsd_result(options.xsd_result)
637 pg.set_xsd_general(options.xsd_general)
638 pg.set_xsd_filename(xsd_loc)
639 pg.set_template_dir(template_dir)
640 pg.set_project_name(options.project_name)
641 pg.set_slave_plugin_name(options.slave_plugin_name)
642 pg.set_site_name(options.site_name)
643
644 pg.create_plugin()
645
646 if __name__ == "__main__":
647 main()
648