CMS 3D CMS Logo

pkg.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 #-*- coding: utf-8 -*-
3 #pylint: disable-msg=W0122,R0914,R0912
4 
5 """
6 File : pkg.py
7 Author : Valentin Kuznetsov <vkuznet@gmail.com>
8 Description: AbstractGenerator class provides basic functionality
9 to generate CMSSW class from given template
10 """
11 from __future__ import print_function
12 
13 # system modules
14 import os
15 import sys
16 import time
17 import pprint
18 
19 # package modules
20 from FWCore.Skeletons.utils import parse_word, functor, user_info, tree, template_directory
21 
23  """
24  AbstractPkg takes care how to generate code from template/PKG
25  package area. The PKG can be any directory which may include
26  any types of files, e.g. C++ (.cc), python (.py), etc.
27  This class relies on specific logic which we outline here:
28 
29  - each template may use tags defined with double underscores
30  enclosure, e.g. __class__, __record__, etc.
31  - each template may have example tags, such tags should
32  start with @example_. While processing template user may
33  choose to strip them off or keep the code behind those tags
34  - in addition user may specify pure python code which can
35  operate with user defined tags. This code snipped should
36  be enclosed with #python_begin and #python_end lines
37  which declares start and end of python block
38  """
39  def __init__(self, config=None):
40  super(AbstractPkg, self).__init__()
41  if not config:
42  self.config = {}
43  else:
44  self.config = config
45  self.pname = self.config.get('pname', None)
46  self.tmpl = self.config.get('tmpl', None)
47  self.debug = self.config.get('debug', 0)
49  self.author = user_info(self.config.get('author', None))
50  self.date = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
51  self.not_in_dir = self.config.get('not_in_dir', [])
52  self.working_dir = self.config.get('working_dir')
53 
54  def tmpl_etags(self):
55  "Scan template files and return example tags"
56  keys = []
57  sdir = '%s/%s' % (self.tdir, self.tmpl)
58  for name in os.listdir(sdir):
59  if name[-1] == '~':
60  continue
61  if name == 'CVS':
62  continue
63  fname = os.path.join(sdir, name)
64  with open(fname, 'r') as stream:
65  for line in stream.readlines():
66  if line.find('@example_') != -1: # possible tag
67  keys += [k for k in line.split() if \
68  k.find('@example_') != -1]
69  return set(keys)
70 
71  def print_etags(self):
72  "Print out template example tags"
73  for key in self.tmpl_etags():
74  print(key)
75 
76  def tmpl_tags(self):
77  "Scan template files and return template tags"
78  keys = []
79  sdir = '%s/%s' % (self.tdir, self.tmpl)
80  for name in os.listdir(sdir):
81  if name[-1] == '~':
82  continue
83  if name == 'CVS':
84  continue
85  fname = os.path.join(sdir, name)
86  with open(fname, 'r') as stream:
87  for line in stream.readlines():
88  if line.find('__') != -1: # possible key
89  keys += [k for k in parse_word(line)]
90  return set(keys)
91 
92  def print_tags(self):
93  "Print out template keys"
94  for key in self.tmpl_tags():
95  print(key)
96 
97  def parse_etags(self, line):
98  """
99  Determine either skip or keep given line based on class tags
100  meta-strings
101  """
102  tmpl_etags = self.tmpl_etags()
103  keep_etags = self.config.get('tmpl_etags', [])
104  for tag in tmpl_etags:
105  for valid_tag in keep_etags:
106  if line.find(valid_tag) != -1:
107  line = line.replace(valid_tag, '')
108  return line
109  if line.find(tag) != -1:
110  line = ''
111  return line
112  if len(keep_etags) == 0:
113  return line.replace('@default', '')
114  if '@default' in line:
115  return ''
116  return line
117 
118  def write(self, fname, tmpl_name, kwds):
119  "Create new file from given template name and set of arguments"
120  code = ""
121  read_code = False
122  if os.path.exists(fname):
123  return
124  with open(fname, 'w') as stream:
125  for line in open(tmpl_name, 'r').readlines():
126  line = self.parse_etags(line)
127  if not line:
128  continue
129  if line.find('#python_begin') != -1:
130  read_code = True
131  continue
132  if line.find('#python_end') != -1:
133  read_code = False
134  if read_code:
135  code += line
136  if code and not read_code:
137  res = functor(code, kwds, self.debug)
138  stream.write(res)
139  code = ""
140  continue
141  if not read_code:
142  for key, val in kwds.items():
143  if isinstance(val, str):
144  line = line.replace(key, val)
145  stream.write(line)
146 
147  def get_kwds(self):
148  "Return keyword arguments to be used in methods"
149  kwds = {'__pkgname__': self.config.get('pkgname', 'Package'),
150  '__author__': self.author,
151  '__date__': self.date,
152  '__class__': self.pname,
153  '__class_lowercase__': self.pname.lower(),
154  '__class_space__': " "*len(self.pname),
155  '__name__': self.pname,
156  '__subsys__': self.config.get('subsystem', 'Subsystem')}
157  args = self.config.get('args', None)
158  kwds.update(args)
159  if self.debug:
160  print("Template tags:")
161  pprint.pprint(kwds)
162  return kwds
163 
164  def generate(self):
165  "Generate package templates in a given directory"
166 
167  # keep current location, since generate will switch directories
168  cdir = os.getcwd()
169 
170  # read from configutation which template files to create
171  tmpl_files = self.config.get('tmpl_files', 'all')
172 
173  # setup keyword arguments which we'll pass to write method
174  kwds = self.get_kwds()
175 
176  # create template package dir and cd into it
177  if tmpl_files == 'all' and self.tmpl not in self.not_in_dir:
178  if os.path.isdir(self.pname):
179  msg = "Can't create package '%s'\n" % self.pname
180  msg += "Directory %s is already exists" % self.pname
181  print(msg)
182  sys.exit(1)
183  os.makedirs(self.pname)
184  os.chdir(self.pname)
185 
186  # read directory driver information and create file list to generate
187  sdir = os.path.join(self.tdir, self.tmpl)
188  sources = [s for s in os.listdir(sdir) \
189  if s != 'Driver.dir' and s.find('~') == -1]
190  driver = os.path.join(sdir, 'Driver.dir')
191  if os.path.isfile(driver):
192  sources = [s.replace('\n', '') for s in open(driver, 'r').readlines()]
193  if 'CVS' in sources:
194  sources.remove('CVS')
195 
196  # special case of Skeleton, which requires to generate only given
197  # file type if self.pname has extension of that type
198  names = set([s.split('.')[0] for s in sources])
199  if names == set(['Skeleton']):
200  if self.pname.find('.') != -1:
201  _, ext = os.path.splitext(self.pname)
202  sources = [s for s in sources if s.rfind(ext) != -1]
203  self.pname = self.pname.replace(ext, '')
204  kwds = self.get_kwds()
205  if not sources:
206  msg = 'Unable to find skeleton for extension "%s"' % ext
207  print(msg)
208  sys.exit(1)
209  bdir = os.environ.get('CMSSW_BASE', '')
210  dirs = os.getcwd().replace(bdir, '').split('/')
211  ldir = os.getcwd().split('/')[-1]
212  idir = ''
213  subsys = kwds['__subsys__']
214  pkgname = kwds['__pkgname__']
215  if sources == ['Skeleton.cc', 'Skeleton.h']:
216  if ldir == 'interface' and os.getcwd().find(bdir) != -1:
217  idir = '%s/%s/interface/' % (subsys, pkgname)
218  # run within some directory of the Sybsystem/Pkg area
219  # and only for mkskel <file>.cc
220  elif sources == ['Skeleton.cc'] and \
221  len(dirs) == 5 and dirs[0] == '' and dirs[1] == 'src':
222  idir = '%s/%s/interface/' % (subsys, pkgname)
223  elif sources == ['Skeleton.h'] and ldir == 'interface' and \
224  len(dirs) == 5 and dirs[0] == '' and dirs[1] == 'src':
225  idir = '%s/%s/interface/' % (subsys, pkgname)
226  kwds.update({'__incdir__': idir})
227 
228  # loop over source files, create dirs as necessary and generate files
229  # names for writing templates
230  gen_files = []
231  for src in sources:
232  if tmpl_files != 'all':
233  fname, ext = os.path.splitext(src)
234  if tmpl_files != ext:
235  continue
236  #also reject if this is the wrong directory
237  if self.working_dir and src.split('/')[-2] != self.working_dir:
238  continue
239  src = src.split('/')[-1]
240  if self.debug:
241  print("Read", src)
242  items = src.split('/')
243  if items[-1] == '/':
244  items = items[:-1]
245  tname = items[-1] # template file name
246  tmpl_name = os.path.join(sdir, items[-1]) # full tmpl file name
247  if os.path.isfile(tmpl_name):
248  ftype = 'file'
249  else:
250  ftype = 'dir'
251  name2gen = src # new file we'll create
252  if items[-1] == 'testBuildFile.xml':
253  name2gen = '/'.join(src.split('/')[:-1])+'/BuildFile.xml'
254  if -1 !=tname.split('.')[0].find(self.tmpl): # need to substitute
255  name2gen = name2gen.replace(self.tmpl, self.pname)
256  name2gen = os.path.join(os.getcwd(), name2gen)
257  if self.debug:
258  print("Create", name2gen)
259  if ftype == 'dir':
260  if not os.path.isdir(name2gen):
261  os.makedirs(name2gen)
262  continue # we're done with dir
263  fdir = os.path.dirname(name2gen)
264  if not os.path.isdir(fdir):
265  os.makedirs(fdir)
266  self.write(name2gen, tmpl_name, kwds)
267  gen_files.append(name2gen.split('/')[-1])
268  if tmpl_files == 'all' and self.tmpl not in self.not_in_dir:
269  msg = 'New package "%s" of %s type is successfully generated' \
270  % (self.pname, self.tmpl)
271  else:
272  msg = 'Generated %s file' % ', '.join(gen_files)
273  if len(gen_files) > 1:
274  msg += 's'
275  print(msg)
276  # return back where we started
277  os.chdir(cdir)
278  if msg.find('New package') != -1:
279  tree(self.pname)
def get_kwds(self)
Definition: pkg.py:147
def __init__(self, config=None)
Definition: pkg.py:39
def user_info(ainput=None)
Definition: utils.py:112
def replace(string, replacements)
def print_etags(self)
Definition: pkg.py:71
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
def generate(self)
Definition: pkg.py:164
def parse_etags(self, line)
Definition: pkg.py:97
def tmpl_etags(self)
Definition: pkg.py:54
def print_tags(self)
Definition: pkg.py:92
def template_directory()
Definition: utils.py:23
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def tmpl_tags(self)
Definition: pkg.py:76
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def parse_word(word)
Definition: utils.py:37
def write(self, fname, tmpl_name, kwds)
Definition: pkg.py:118
def functor(code, kwds, debug=0)
Definition: utils.py:70
Definition: tree.py:1