merge_files.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 # @file: GaudiPolicy/cmt/fragments/merge_files.py
4 # @purpose: merge_files <fragment> file into a 'per-project' <merged> file
5 # @author: Sebastien Binet <binet@cern.ch>
6 
7 import os
8 import sys
9 from datetime import datetime
10 import fcntl
11 
12 def mergeFiles( fragFileNames, mergedFileName, commentChar, doMerge, ignoreMissing ):
13 
14  startMark = "%s --Beg " % commentChar
15  timeMark = "%s --Date inserted: %s" % (commentChar, datetime.now())
16  endMark = "%s --End " % commentChar
17  nameOffset = len(startMark)
18 
19  basenames = map(os.path.basename, fragFileNames)
20 
21  isNewFile = not os.path.exists(mergedFileName)
22 
23  # create an empty file if it does not exist
24  # "append mode" ensures that, in case of two processes trying to
25  # create the file, they do not truncate each other file
26  if isNewFile:
27  # check if the destination directory exists
28  path_to_file = os.path.split(mergedFileName)[0]
29  if path_to_file and not os.path.isdir(path_to_file):
30  # if doesn't exist, create it
31  os.makedirs(path_to_file)
32  open(mergedFileName,'a')
33 
34  lockFile = open( mergedFileName + '.lock', 'a' )
35 
36  # locking file, gaining exclusive access to it
37  # code from locker.py, only posix relevant part - we don't support NT - did we ever ??
38  # Lock with a simple call to lockf() - this blocks until the lock is aquired
39  try:
40  fcntl.lockf( lockFile, fcntl.LOCK_EX )
41  except IOError, exc_value:
42  print "Problem when trying to lock {0}, IOError {1}".format(mergedFile, exc_value[0])
43  raise
44 
45  mergedFile = open( mergedFileName, 'r' )
46 
47  try:
48 
49  newLines = [ ]
50  skipBlock = ""
51  for line in mergedFile.readlines():
52  if line.startswith(startMark) and line[nameOffset:].strip() in basenames:
53  skipBlock = endMark + line[nameOffset:].strip()
54  # remove all the empty lines occurring before the start mark
55  while (len(newLines) > 0) and (newLines[-1].strip() == ''):
56  newLines.pop()
57  if not skipBlock:
58  newLines.append(line)
59  if line.startswith(skipBlock):
60  skipBlock = ""
61  if skipBlock:
62  print "WARNING: missing end mark ('%s')" % skipBlock
63 
64  if doMerge:
65  for f in fragFileNames:
66  if ignoreMissing and not os.path.exists(f):
67  print "WARNING: '%s' does not exist, I'm ignoring it" % f
68  continue
69  # I do not want to add 2 empty lines at the beginning of a file
70  if newLines:
71  newLines.append('\n\n')
72  bf = os.path.basename(f)
73  newLines.append(startMark + bf + '\n')
74  newLines.append(timeMark + '\n')
75  fileData = open(f, 'r').read()
76  newLines.append(fileData)
77  if fileData and fileData[-1] != '\n':
78  newLines.append('\n')
79  newLines.append(endMark + bf + '\n')
80 
81  #mergedFile.seek(0)
82  #mergedFile.truncate(0)
83  #mergedFile.writelines(newLines)
84 
85  newFile = open( mergedFileName + ".new" , 'w' )
86  newFile.writelines(newLines)
87  newFile.close()
88  os.rename(mergedFileName + ".new",mergedFileName)
89 
90  finally:
91  # unlock file
92  fcntl.lockf( lockFile, fcntl.LOCK_UN )
93 
94  return 0
95 
96 if __name__ == "__main__":
97 
98  from optparse import OptionParser
99  parser = OptionParser(usage="usage: %prog [options]")
100  parser.add_option(
101  "-i",
102  "--input-file",
103  action = "append",
104  dest = "fragFileNames",
105  default = [],
106  help = "The path and name of the file one wants to merge into the 'master' one"
107  )
108  parser.add_option(
109  "-m",
110  "--merged-file",
111  dest = "mergedFileName",
112  default = None,
113  help = "The path and name of the 'master' file which will hold the content of all the other fragment files"
114  )
115  parser.add_option(
116  "-c",
117  "--comment-char",
118  dest = "commentChar",
119  default = "#",
120  help = "The type of the commenting character for the type of files at hand (this is an attempt at handling the largest possible use cases)"
121  )
122  parser.add_option(
123  "--do-merge",
124  dest = "doMerge",
125  action = "store_true",
126  default = True,
127  help = "Switch to actually carry on with the merging procedure"
128  )
129  parser.add_option(
130  "--un-merge",
131  dest = "unMerge",
132  action = "store_true",
133  default = False,
134  help = "Switch to remove our fragment file from the 'master' file"
135  )
136  parser.add_option(
137  "--stamp-dir",
138  dest = "stampDir",
139  action = "store",
140  default = None,
141  help = "Create the stamp file in the specified directory. If not specified"
142  +" the directory of the source file is used."
143  )
144  parser.add_option(
145  "--no-stamp",
146  action = "store_true",
147  help = "Do no create stamp files."
148  )
149  parser.add_option(
150  "--ignore-missing",
151  dest = "ignoreMissing",
152  action = "store_true",
153  help = "Print a warning if a fragment file is missing, but do not fail."
154  )
155 
156  (options, args) = parser.parse_args()
157 
158  # ensure consistency...
159  options.doMerge = not options.unMerge
160 
161  # allow command line syntax as
162  # merge_files.py [options] <fragment file1> [<fragment file2>...] <merged file>
163  if args:
164  options.mergedFileName = args[-1]
165  options.fragFileNames += args[:-1]
166 
167  sc = 1
168  if not options.fragFileNames or \
169  not options.mergedFileName :
170  str(parser.print_help() or "")
171  print "*** ERROR ***",sys.argv
172  sys.exit(sc)
173  pass
174 
175  if options.stampDir is None:
176  stampFileName = lambda x: x + ".stamp"
177  else:
178  stampFileName = lambda x: os.path.join(options.stampDir,
179  os.path.basename(x)
180  + ".stamp")
181  # Configure Python logging
182  import logging
183  logging.basicConfig(level = logging.INFO)
184 
185  if "GAUDI_BUILD_LOCK" in os.environ:
186  globalLock = locker.LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
187  else:
188  globalLock = None
189 
190  if True: #try:
191  sc = mergeFiles( options.fragFileNames, options.mergedFileName,
192  options.commentChar,
193  doMerge = options.doMerge,
194  ignoreMissing = options.ignoreMissing)
195  if not options.no_stamp:
196  for stamp in map(stampFileName, options.fragFileNames):
197  open(stamp, 'w')
198  #except IOError, err:
199  # print "ERROR:",err
200  #except Exception, err:
201  # print "ERROR:",err
202  #except:
203  # print "ERROR: unknown error !!"
204 
205  del globalLock
206 
207  sys.exit( sc )
def mergeFiles(fragFileNames, mergedFileName, commentChar, doMerge, ignoreMissing)
Definition: merge_files.py:12
struct GAUDI_API map
Parametrisation class for map-like implementation.
Lock a file.
Definition: locker.py:63
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:120