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