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 locker
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  mergedFile = open( mergedFileName, 'r+' )
35 
36  # locking file, gaining exclusive access to it
37  lock = locker.lock( mergedFile )
38  try:
39 
40  newLines = [ ]
41  skipBlock = ""
42  for line in mergedFile.readlines():
43  if line.startswith(startMark) and line[nameOffset:].strip() in basenames:
44  skipBlock = endMark + line[nameOffset:].strip()
45  # remove all the empty lines occurring before the start mark
46  while (len(newLines) > 0) and (newLines[-1].strip() == ''):
47  newLines.pop()
48  if not skipBlock:
49  newLines.append(line)
50  if line.startswith(skipBlock):
51  skipBlock = ""
52  if skipBlock:
53  print "WARNING: missing end mark ('%s')" % skipBlock
54 
55  if doMerge:
56  for f in fragFileNames:
57  if ignoreMissing and not os.path.exists(f):
58  print "WARNING: '%s' does not exist, I'm ignoring it" % f
59  continue
60  # I do not want to add 2 empty lines at the beginning of a file
61  if newLines:
62  newLines.append('\n\n')
63  bf = os.path.basename(f)
64  newLines.append(startMark + bf + '\n')
65  newLines.append(timeMark + '\n')
66  fileData = open(f, 'r').read()
67  newLines.append(fileData)
68  if fileData and fileData[-1] != '\n':
69  newLines.append('\n')
70  newLines.append(endMark + bf + '\n')
71 
72  mergedFile.seek(0)
73  mergedFile.truncate(0)
74  mergedFile.writelines(newLines)
75 
76  finally:
77  # unlock file
78  locker.unlock( mergedFile )
79 
80  return 0
81 
82 if __name__ == "__main__":
83 
84  from optparse import OptionParser
85  parser = OptionParser(usage="usage: %prog [options]")
86  parser.add_option(
87  "-i",
88  "--input-file",
89  action = "append",
90  dest = "fragFileNames",
91  default = [],
92  help = "The path and name of the file one wants to merge into the 'master' one"
93  )
94  parser.add_option(
95  "-m",
96  "--merged-file",
97  dest = "mergedFileName",
98  default = None,
99  help = "The path and name of the 'master' file which will hold the content of all the other fragment files"
100  )
101  parser.add_option(
102  "-c",
103  "--comment-char",
104  dest = "commentChar",
105  default = "#",
106  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)"
107  )
108  parser.add_option(
109  "--do-merge",
110  dest = "doMerge",
111  action = "store_true",
112  default = True,
113  help = "Switch to actually carry on with the merging procedure"
114  )
115  parser.add_option(
116  "--un-merge",
117  dest = "unMerge",
118  action = "store_true",
119  default = False,
120  help = "Switch to remove our fragment file from the 'master' file"
121  )
122  parser.add_option(
123  "--stamp-dir",
124  dest = "stampDir",
125  action = "store",
126  default = None,
127  help = "Create the stamp file in the specified directory. If not specified"
128  +" the directory of the source file is used."
129  )
130  parser.add_option(
131  "--no-stamp",
132  action = "store_true",
133  help = "Do no create stamp files."
134  )
135  parser.add_option(
136  "--ignore-missing",
137  dest = "ignoreMissing",
138  action = "store_true",
139  help = "Print a warning if a fragment file is missing, but do not fail."
140  )
141 
142  (options, args) = parser.parse_args()
143 
144  # ensure consistency...
145  options.doMerge = not options.unMerge
146 
147  # allow command line syntax as
148  # merge_files.py [options] <fragment file1> [<fragment file2>...] <merged file>
149  if args:
150  options.mergedFileName = args[-1]
151  options.fragFileNames += args[:-1]
152 
153  sc = 1
154  if not options.fragFileNames or \
155  not options.mergedFileName :
156  str(parser.print_help() or "")
157  print "*** ERROR ***",sys.argv
158  sys.exit(sc)
159  pass
160 
161  if options.stampDir is None:
162  stampFileName = lambda x: x + ".stamp"
163  else:
164  stampFileName = lambda x: os.path.join(options.stampDir,
165  os.path.basename(x)
166  + ".stamp")
167  # Configure Python logging
168  import logging
169  logging.basicConfig(level = logging.INFO)
170 
171  if "GAUDI_BUILD_LOCK" in os.environ:
172  globalLock = locker.LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
173  else:
174  globalLock = None
175 
176  if True: #try:
177  sc = mergeFiles( options.fragFileNames, options.mergedFileName,
178  options.commentChar,
179  doMerge = options.doMerge,
180  ignoreMissing = options.ignoreMissing)
181  if not options.no_stamp:
182  for stamp in map(stampFileName, options.fragFileNames):
183  open(stamp, 'w')
184  #except IOError, err:
185  # print "ERROR:",err
186  #except Exception, err:
187  # print "ERROR:",err
188  #except:
189  # print "ERROR: unknown error !!"
190 
191  del globalLock
192 
193  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
def lock(file)
Definition: locker.py:16
def unlock(file)
Definition: locker.py:34