1
2 """
3 Application class that implements pyFoamUpdateDictionary.py
4 """
5
6 import re
7 from os import path
8
9 from PyFoamApplication import PyFoamApplication
10
11 from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile
12 from PyFoam.Basics.DataStructures import DictProxy,TupleProxy
13
14 from PyFoam.Error import error,warning
15
16 from CommonParserOptions import CommonParserOptions
17
18 from PyFoam.Basics.TerminalFormatter import TerminalFormatter
19
20 f=TerminalFormatter()
21 f.getConfigFormat("source",shortName="src")
22 f.getConfigFormat("destination",shortName="dst")
23 f.getConfigFormat("difference",shortName="diff")
24 f.getConfigFormat("question",shortName="ask")
25 f.getConfigFormat("input")
26
30 description="""
31 Takes two dictionary and modifies the second one after the example of
32 the first. If the dictionaries do not have the same name, it looks for
33 the destination file by searching the equivalent place in the destination
34 case
35 """
36
37 PyFoamApplication.__init__(self,
38 args=args,
39 description=description,
40 usage="%prog [options] <source> <destination-case>",
41 nr=2,
42 changeVersion=False,
43 interspersed=True)
44
46 self.parser.add_option("--interactive",
47 action="store_true",
48 default=True,
49 dest="interactive",
50 help="Asks the user before applying changes")
51
52 self.parser.add_option("--batch",
53 action="store_false",
54 default=True,
55 dest="interactive",
56 help="Don't ask the user before applying changes")
57
58 self.parser.add_option("--clear-unused",
59 action="store_true",
60 default=False,
61 dest="clear",
62 help="Removes all the dictionary entries that are not in the source")
63
64 self.parser.add_option("--add-missing",
65 action="store_true",
66 default=False,
67 dest="add",
68 help="Add all the dictionary entries that are not in the destination")
69
70 self.parser.add_option("--append-lists",
71 action="store_true",
72 default=False,
73 dest="append",
74 help="Append to lists if they are shorter than the original")
75
76 self.parser.add_option("--shorten-lists",
77 action="store_true",
78 default=False,
79 dest="shorten",
80 help="Shortens lists if they are longer than the original")
81
82 self.parser.add_option("--all",
83 action="store_true",
84 default=False,
85 dest="all",
86 help="Do all the editing commands: clear, add, shorten and append")
87
88 self.parser.add_option("--test",
89 action="store_true",
90 default=False,
91 dest="test",
92 help="Does not write the file but only prints it to the screen")
93
94 self.parser.add_option("--not-equal",
95 action="store_true",
96 default=False,
97 dest="notequal",
98 help="Allow source and destination to have different names")
99
100 self.parser.add_option("--verbose",
101 action="store_true",
102 default=False,
103 dest="verbose",
104 help="Print every change that is being made")
105
106 self.parser.add_option("--min-recursion",
107 action="store",
108 default=0,
109 type="int",
110 dest="min",
111 help="Minimum depth of the recursive decent into dictionaries at which 'editing' should start (default: %default)")
112
113 self.parser.add_option("--max-recursion",
114 action="store",
115 default=100,
116 type="int",
117 dest="max",
118 help="Maximum depth of the recursive decent into dictionaries (default: %default)")
119
120 CommonParserOptions.addOptions(self)
121
122 - def ask(self,*question):
123 if not self.opts.interactive:
124 return False
125 else:
126 print f.ask,"QUESTION:",
127 for q in question:
128 print q,
129
130 answer=None
131 while answer!="y" and answer!="n":
132 answer=raw_input(f.reset+f.ask+" [Y]es or [N]no ? "+f.input).strip()[0].lower()
133 print f.reset,
134 return answer=="y"
135
137 if depth>self.opts.max:
138 if self.opts.verbose:
139 print "- "*depth,"Recursion ended"
140 return
141
142 for i in range(min(len(source),len(dest))):
143 if type(source[i])==type(dest[i]) and type(source[i]) in [dict,DictProxy]:
144 if self.opts.verbose:
145 print "- "*depth,"Entering dict nr.",i
146 self.workDict(source[i],dest[i],depth+1)
147 if self.opts.verbose:
148 print "- "*depth,"Leaving dict nr.",i
149 elif type(source[i])==type(dest[i]) and type(source[i]) in [tuple,TupleProxy,list]:
150 if self.opts.verbose:
151 print "- "*depth,"Entering tuple nr.",i
152 self.workList(source[i],dest[i],depth+1)
153 if self.opts.verbose:
154 print "- "*depth,"Leaving tuple nr.",i
155 elif self.opts.interactive:
156 if source[i]!=dest[i]:
157 if self.ask("Replace for index",i,"the value",dest[i],"with the value",source[i]):
158 dest[i]=source[i]
159
160 if len(source)<len(dest) and self.opts.shorten:
161 if self.ask("Clip [",len(source),":] with the values ",dest[len(source):],"from the list"):
162 if self.opts.verbose:
163 print "- "*depth,"Clipping",len(dest)-len(source),"entries starting with",len(source)
164 dest=dest[0:len(source)]
165 elif len(source)>len(dest) and self.opts.append:
166 if self.ask("Append [",len(dest),":] with the values ",source[len(dest):],"to the list"):
167 if self.opts.verbose:
168 print "- "*depth,"Appending",len(source)-len(dest),"entries starting with",len(dest)
169 dest+=source[len(dest):]
170
172 if depth>self.opts.max:
173 if self.opts.verbose:
174 print "- "*depth,"Recursion ended"
175 return
176
177 if depth>=self.opts.min:
178 doIt=True
179 else:
180 doIt=False
181
182 for name in source:
183 if name not in dest:
184 if self.opts.add and doIt:
185 if self.ask("Add the key",name,"with value",source[name]):
186 if self.opts.verbose:
187 print "- "*depth,"Adding",name
188 dest[name]=source[name]
189 elif type(source[name]) in [dict,DictProxy]:
190 if type(dest[name]) not in [dict,DictProxy]:
191 error("Entry",name,"is not a dictionary in destination (but in source)")
192 if self.opts.verbose:
193 print "- "*depth,"Entering dict ",name
194 self.workDict(source[name],dest[name],depth+1)
195 if self.opts.verbose:
196 print "- "*depth,"Leaving dict ",name
197 elif type(source[name])==type(dest[name]) and type(dest[name]) in [tuple,TupleProxy,list]:
198 if self.opts.verbose:
199 print "- "*depth,"Entering tuple ",name
200 self.workList(source[name],dest[name],depth+1)
201 if self.opts.verbose:
202 print "- "*depth,"Leaving tuple ",name
203 elif self.opts.interactive:
204 if source[name]!=dest[name]:
205 if self.ask("Replace for key",name,"the value",dest[name],"with the value",source[name]):
206 dest[name]=source[name]
207 else:
208 if self.opts.verbose:
209 print "- "*depth,"Nothing done for",name
210
211 if self.opts.clear and doIt:
212 weg=[]
213 for name in dest:
214 if name not in source:
215 weg.append(name)
216
217 for name in weg:
218 if self.ask("Remove the key",name,"with the value",dest[name]):
219 if self.opts.verbose:
220 print "- "*depth,"Removing",name
221 del dest[name]
222
224 sName=path.abspath(self.parser.getArgs()[0])
225 dName=path.abspath(self.parser.getArgs()[1])
226
227 if self.opts.all:
228 self.opts.append=True
229 self.opts.shorten=True
230 self.opts.add=True
231 self.opts.clear=True
232
233 try:
234 source=ParsedParameterFile(sName,
235 backup=False,
236 debug=self.opts.debugParser,
237 noBody=self.opts.noBody,
238 noHeader=self.opts.noHeader,
239 boundaryDict=self.opts.boundaryDict,
240 listDict=self.opts.listDict,
241 listDictWithHeader=self.opts.listDictWithHeader)
242 except IOError,e:
243 self.error("Problem with file",sName,":",e)
244
245 if not self.opts.notequal and path.basename(sName)!=path.basename(dName):
246 found=False
247 parts=sName.split(path.sep)
248 for i in range(len(parts)):
249 tmp=apply(path.join,[dName]+parts[-(i+1):])
250
251 if path.exists(tmp):
252 found=True
253 dName=tmp
254 warning("Found",dName,"and using this")
255 break
256
257 if not found:
258 error("Could not find a file named",path.basename(sName),"in",dName)
259
260 if path.samefile(sName,dName):
261 error("Source",sName,"and destination",dName,"are the same")
262
263 try:
264 dest=ParsedParameterFile(dName,
265 backup=False,
266 debug=self.opts.debugParser,
267 noBody=self.opts.noBody,
268 noHeader=self.opts.noHeader,
269 boundaryDict=self.opts.boundaryDict,
270 listDict=self.opts.listDict,
271 listDictWithHeader=self.opts.listDictWithHeader)
272 except IOError,e:
273 self.error("Problem with file",dName,":",e)
274
275 dCase=dest.getCaseDir()
276
277 if self.opts.interactive:
278 self.opts.verbose=True
279
280 if not self.opts.boundaryDict and not self.opts.listDict and not self.opts.listDictWithHeader:
281 self.workDict(source.content,dest.content,1)
282 else:
283 self.workList(source.content,dest.content,1)
284
285 if self.opts.test or self.opts.interactive:
286 print str(dest)
287
288 if not self.opts.test and self.ask("\n Write this file to disk"):
289 dest.writeFile()
290 if dCase!=None:
291 self.addToCaseLog(dCase,"Source",sName,"Destination:",dName)
292