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