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