File indexing completed on 2023-03-17 11:03:46
0001
0002
0003
0004
0005 """
0006 File : pkg.py
0007 Author : Valentin Kuznetsov <vkuznet@gmail.com>
0008 Description: AbstractGenerator class provides basic functionality
0009 to generate CMSSW class from given template
0010 """
0011 from __future__ import print_function
0012
0013
0014 import os
0015 import sys
0016 import time
0017 import pprint
0018
0019
0020 from FWCore.Skeletons.utils import parse_word, functor, user_info, tree, template_directory
0021
0022 class AbstractPkg(object):
0023 """
0024 AbstractPkg takes care how to generate code from template/PKG
0025 package area. The PKG can be any directory which may include
0026 any types of files, e.g. C++ (.cc), python (.py), etc.
0027 This class relies on specific logic which we outline here:
0028
0029 - each template may use tags defined with double underscores
0030 enclosure, e.g. __class__, __record__, etc.
0031 - each template may have example tags, such tags should
0032 start with @example_. While processing template user may
0033 choose to strip them off or keep the code behind those tags
0034 - in addition user may specify pure python code which can
0035 operate with user defined tags. This code snipped should
0036 be enclosed with #python_begin and #python_end lines
0037 which declares start and end of python block
0038 """
0039 def __init__(self, config=None):
0040 super(AbstractPkg, self).__init__()
0041 if not config:
0042 self.config = {}
0043 else:
0044 self.config = config
0045 self.pname = self.config.get('pname', None)
0046 self.tmpl = self.config.get('tmpl', None)
0047 self.debug = self.config.get('debug', 0)
0048 self.tdir = template_directory()
0049 self.author = user_info(self.config.get('author', None))
0050 self.date = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
0051 self.not_in_dir = self.config.get('not_in_dir', [])
0052 self.working_dir = self.config.get('working_dir')
0053
0054 def tmpl_etags(self):
0055 "Scan template files and return example tags"
0056 keys = []
0057 sdir = '%s/%s' % (self.tdir, self.tmpl)
0058 for name in os.listdir(sdir):
0059 if name[-1] == '~':
0060 continue
0061 if name == 'CVS':
0062 continue
0063 fname = os.path.join(sdir, name)
0064 with open(fname, 'r') as stream:
0065 for line in stream.readlines():
0066 if line.find('@example_') != -1:
0067 keys += [k for k in line.split() if \
0068 k.find('@example_') != -1]
0069 return set(keys)
0070
0071 def print_etags(self):
0072 "Print out template example tags"
0073 for key in self.tmpl_etags():
0074 print(key)
0075
0076 def tmpl_tags(self):
0077 "Scan template files and return template tags"
0078 keys = []
0079 sdir = '%s/%s' % (self.tdir, self.tmpl)
0080 for name in os.listdir(sdir):
0081 if name[-1] == '~':
0082 continue
0083 if name == 'CVS':
0084 continue
0085 fname = os.path.join(sdir, name)
0086 with open(fname, 'r') as stream:
0087 for line in stream.readlines():
0088 if line.find('__') != -1:
0089 keys += [k for k in parse_word(line)]
0090 return set(keys)
0091
0092 def print_tags(self):
0093 "Print out template keys"
0094 for key in self.tmpl_tags():
0095 print(key)
0096
0097 def parse_etags(self, line):
0098 """
0099 Determine either skip or keep given line based on class tags
0100 meta-strings
0101 """
0102 tmpl_etags = self.tmpl_etags()
0103 keep_etags = self.config.get('tmpl_etags', [])
0104 for tag in tmpl_etags:
0105 for valid_tag in keep_etags:
0106 if line.find(valid_tag) != -1:
0107 line = line.replace(valid_tag, '')
0108 return line
0109 if line.find(tag) != -1:
0110 line = ''
0111 return line
0112 if len(keep_etags) == 0:
0113 return line.replace('@default', '')
0114 if '@default' in line:
0115 return ''
0116 return line
0117
0118 def write(self, fname, tmpl_name, kwds):
0119 "Create new file from given template name and set of arguments"
0120 code = ""
0121 read_code = False
0122 if os.path.exists(fname):
0123 return
0124 with open(fname, 'w') as stream:
0125 for line in open(tmpl_name, 'r').readlines():
0126 line = self.parse_etags(line)
0127 if not line:
0128 continue
0129 if line.find('#python_begin') != -1:
0130 read_code = True
0131 continue
0132 if line.find('#python_end') != -1:
0133 read_code = False
0134 if read_code:
0135 code += line
0136 if code and not read_code:
0137 res = functor(code, kwds, self.debug)
0138 stream.write(res)
0139 code = ""
0140 continue
0141 if not read_code:
0142 for key, val in kwds.items():
0143 if isinstance(val, str):
0144 line = line.replace(key, val)
0145 stream.write(line)
0146
0147 def get_kwds(self):
0148 "Return keyword arguments to be used in methods"
0149 kwds = {'__pkgname__': self.config.get('pkgname', 'Package'),
0150 '__author__': self.author,
0151 '__date__': self.date,
0152 '__class__': self.pname,
0153 '__class_lowercase__': self.pname.lower(),
0154 '__class_space__': " "*len(self.pname),
0155 '__name__': self.pname,
0156 '__subsys__': self.config.get('subsystem', 'Subsystem')}
0157 args = self.config.get('args', None)
0158 kwds.update(args)
0159 if self.debug:
0160 print("Template tags:")
0161 pprint.pprint(kwds)
0162 return kwds
0163
0164 def generate(self):
0165 "Generate package templates in a given directory"
0166
0167
0168 cdir = os.getcwd()
0169
0170
0171 tmpl_files = self.config.get('tmpl_files', 'all')
0172
0173
0174 kwds = self.get_kwds()
0175
0176
0177 if tmpl_files == 'all' and self.tmpl not in self.not_in_dir:
0178 if os.path.isdir(self.pname):
0179 msg = "Can't create package '%s'\n" % self.pname
0180 msg += "Directory %s is already exists" % self.pname
0181 print(msg)
0182 sys.exit(1)
0183 os.makedirs(self.pname)
0184 os.chdir(self.pname)
0185
0186
0187 sdir = os.path.join(self.tdir, self.tmpl)
0188 sources = [s for s in os.listdir(sdir) \
0189 if s != 'Driver.dir' and s.find('~') == -1]
0190 driver = os.path.join(sdir, 'Driver.dir')
0191 if os.path.isfile(driver):
0192 sources = [s.replace('\n', '') for s in open(driver, 'r').readlines()]
0193 if 'CVS' in sources:
0194 sources.remove('CVS')
0195
0196
0197
0198 names = set([s.split('.')[0] for s in sources])
0199 if names == set(['Skeleton']):
0200 if self.pname.find('.') != -1:
0201 _, ext = os.path.splitext(self.pname)
0202 sources = [s for s in sources if s.rfind(ext) != -1]
0203 self.pname = self.pname.replace(ext, '')
0204 kwds = self.get_kwds()
0205 if not sources:
0206 msg = 'Unable to find skeleton for extension "%s"' % ext
0207 print(msg)
0208 sys.exit(1)
0209 bdir = os.environ.get('CMSSW_BASE', '')
0210 dirs = os.getcwd().replace(bdir, '').split('/')
0211 ldir = os.getcwd().split('/')[-1]
0212 idir = ''
0213 subsys = kwds['__subsys__']
0214 pkgname = kwds['__pkgname__']
0215 if sources == ['Skeleton.cc', 'Skeleton.h']:
0216 if ldir == 'interface' and os.getcwd().find(bdir) != -1:
0217 idir = '%s/%s/interface/' % (subsys, pkgname)
0218
0219
0220 elif sources == ['Skeleton.cc'] and \
0221 len(dirs) == 5 and dirs[0] == '' and dirs[1] == 'src':
0222 idir = '%s/%s/interface/' % (subsys, pkgname)
0223 elif sources == ['Skeleton.h'] and ldir == 'interface' and \
0224 len(dirs) == 5 and dirs[0] == '' and dirs[1] == 'src':
0225 idir = '%s/%s/interface/' % (subsys, pkgname)
0226 kwds.update({'__incdir__': idir})
0227
0228
0229
0230 gen_files = []
0231 for src in sources:
0232 if tmpl_files != 'all':
0233 fname, ext = os.path.splitext(src)
0234 if tmpl_files != ext:
0235 continue
0236
0237 if self.working_dir and src.split('/')[-2] != self.working_dir:
0238 continue
0239 src = src.split('/')[-1]
0240 if self.debug:
0241 print("Read", src)
0242 items = src.split('/')
0243 if items[-1] == '/':
0244 items = items[:-1]
0245 tname = items[-1]
0246 tmpl_name = os.path.join(sdir, items[-1])
0247 if os.path.isfile(tmpl_name):
0248 ftype = 'file'
0249 else:
0250 ftype = 'dir'
0251 name2gen = src
0252 if items[-1] == 'testBuildFile.xml':
0253 name2gen = '/'.join(src.split('/')[:-1])+'/BuildFile.xml'
0254 if -1 !=tname.split('.')[0].find(self.tmpl):
0255 name2gen = name2gen.replace(self.tmpl, self.pname)
0256 name2gen = os.path.join(os.getcwd(), name2gen)
0257 if self.debug:
0258 print("Create", name2gen)
0259 if ftype == 'dir':
0260 if not os.path.isdir(name2gen):
0261 os.makedirs(name2gen)
0262 continue
0263 fdir = os.path.dirname(name2gen)
0264 if not os.path.isdir(fdir):
0265 os.makedirs(fdir)
0266 self.write(name2gen, tmpl_name, kwds)
0267 gen_files.append(name2gen.split('/')[-1])
0268 if tmpl_files == 'all' and self.tmpl not in self.not_in_dir:
0269 msg = 'New package "%s" of %s type is successfully generated' \
0270 % (self.pname, self.tmpl)
0271 else:
0272 msg = 'Generated %s file' % ', '.join(gen_files)
0273 if len(gen_files) > 1:
0274 msg += 's'
0275 print(msg)
0276
0277 os.chdir(cdir)
0278 if msg.find('New package') != -1:
0279 tree(self.pname)