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