ViewVC Help
View File | Revision Log | View Changeset | Root Listing
root/Oni2/xmlTools/trunk/posUpdate/XmlPatch.cs
(Generate patch)

Comparing:
xmlTools/posUpdate/XmlPatch.cs (file contents), Revision 711 by s10k, Thu Mar 21 10:40:39 2013 UTC vs.
xmlTools/trunk/posUpdate/XmlPatch.cs (file contents), Revision 874 by s10k, Sat May 25 21:53:39 2013 UTC

# Line 1 | Line 1
1   using System;
2   using System.Collections.Generic;
3   using System.Diagnostics;
4 + using System.IO;
5   using System.Text;
6   using System.Xml;
7 + using IronJS;
8  
9   namespace xmlTools
10   {
# Line 13 | Line 15 | namespace xmlTools
15      {
16          String fileName;
17          String forceFiles = "";
18 +        bool globalNoBackups = false;
19 +        IronJS.Hosting.CSharp.Context jsEngine = null; // initialize only when necessary
20  
21 <        public XmlPatch(String file)
21 >        public XmlPatch(String file, bool noBackups)
22          {
23              fileName = file;
24 +            globalNoBackups = noBackups;
25          }
26  
27 <        public XmlPatch(String file, String forceInFiles)
27 >        public XmlPatch(String file, String forceInFiles, bool noBackups)
28          {
29              fileName = file;
30              forceFiles = forceInFiles; //We support apply the operation in diverse forced files (NameOfFile parameter will be ignored)
31 +            globalNoBackups = noBackups;
32          }
33  
34          /// <summary>
# Line 46 | Line 52 | namespace xmlTools
52                      file.ReadLine(); //ignore <xml> start header
53                      while ((line = file.ReadLine()) != "</xml>")
54                      {
55 <                        xmlToInject += line + "\n"; //get all the xml that will be injected
55 >                        xmlToInject += line + System.Environment.NewLine; //get all the xml that will be injected
56                      }
57                      if (!addOperation(operation, xmlToInject))
58                      {
# Line 70 | Line 76 | namespace xmlTools
76                          return false;
77                      }
78                  }
79 +                else if (line.StartsWith("@CUSTOMCODE "))
80 +                {
81 +                    string operation = line;
82 +                    string jsCode = "";
83 +
84 +                    file.ReadLine(); //ignore <xml> start header
85 +                    while ((line = file.ReadLine()) != "</code>")
86 +                    {
87 +                        jsCode += line + System.Environment.NewLine; //get all the xml that will be injected
88 +                    }
89 +                    if (!executeCode(operation, jsCode))
90 +                    {
91 +                        Program.printAppError(Program.appErrors.PATCH_CODE_PROCESS_ERROR, "Error while performing code operation in patch file. Aborting...");
92 +                        return false;
93 +                    }
94 +                }
95              }
96  
97              file.Close();
# Line 87 | Line 109 | namespace xmlTools
109          {
110              //@ADDTO File "example.xml" ParentElement "Animation" Element "Lookup"
111  
112 <            string File = "", ParentElement = "", Element = "";
112 >            string FileParam = "", ParentElementParam = "", ElementParam = "";
113  
114              //---------------------------------------------------Parse Operation command (start)
115              try
116              {
117 <                if (forceFiles == null)
117 >                if (String.IsNullOrEmpty(forceFiles))
118                  {
119 <                    File = getPatchParameter(operation, "File");
119 >                    FileParam = getPatchParameter(operation, "File");
120                  }
121                  else
122                  {
123 <                    File = forceFiles;
123 >                    FileParam = forceFiles;
124                  }
125  
126 <                ParentElement = getPatchParameter(operation, "ParentElement"); //Get the ParentElement
126 >                ParentElementParam = getPatchParameter(operation, "ParentElement"); //Get the ParentElement
127  
128 <                Element = getPatchParameter(operation, "Element"); //Get the Element
128 >                ElementParam = getPatchParameter(operation, "Element"); //Get the Element
129              }
130              catch (Exception e)
131              {
# Line 111 | Line 133 | namespace xmlTools
133                  return false;
134              }
135  
136 <            if (Element == "")
136 >            if (String.IsNullOrEmpty(ElementParam))
137              {
138                  return false;
139              }
140  
141              //---------------------------------------------------Parse Operation command (end)
142              List<String> filesToProcess = new List<String>();
143 <            if (File == "")
143 >            if (String.IsNullOrEmpty(FileParam))
144              {
145                  filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder
146              }
147 <            else if (Util.containsWildcard(File))
147 >            else if (Util.containsWildcard(FileParam))
148              {
149 <                filesToProcess = Util.getXmlFilesWildcard(File);
149 >                filesToProcess = Util.getXmlFilesWildcard(FileParam);
150              }
151              else
152              {
153 <                filesToProcess.Add(File);
153 >                filesToProcess.Add(FileParam);
154              }
155  
156              //---------------------------------------------------XML Injection (start)
157              foreach (String currFile in filesToProcess)
158              {
159 <
160 <                Util.backupFile(currFile);
159 >                if (!this.globalNoBackups && !Util.ContainsIgnoreCase(operation, "NoBackups")) // only skip backup if specified via global parameter or in patch file
160 >                {
161 >                    Util.backupFile(currFile);
162 >                }
163  
164                  XmlDocument xdoc = new XmlDocument();
165                  xdoc.Load(currFile);
166  
167                  List<XmlNode> myElements = new List<XmlNode>();
168 <                Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, Element, ParentElement); //Returns all after "Oni" element
168 >                Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, ElementParam, ParentElementParam); //Returns all after "Oni" element
169  
170                  if (myElements.Count == 0)
171                  {
# Line 177 | Line 201 | namespace xmlTools
201          {
202              //@REMOVE File "example.xml" ParentElement "Particles" Element "Particle"
203  
204 <            string File = "", ParentElement = "", Element = "";
204 >            string FileParam = "", ParentElementParam = "", ElementParam = "";
205  
206              //---------------------------------------------------Parse Operation command (start)
207              try
208              {
209 <                if (forceFiles == null)
209 >                if (String.IsNullOrEmpty(forceFiles))
210                  {
211 <                    File = getPatchParameter(operation, "File");
211 >                    FileParam = getPatchParameter(operation, "File");
212                  }
213                  else
214                  {
215 <                    File = forceFiles;
215 >                    FileParam = forceFiles;
216                  }
217  
218 <                ParentElement = getPatchParameter(operation, "ParentElement"); //Get the ParentElement
218 >                ParentElementParam = getPatchParameter(operation, "ParentElement"); //Get the ParentElement
219  
220 <                Element = getPatchParameter(operation, "Element"); //Get the Element
220 >                ElementParam = getPatchParameter(operation, "Element"); //Get the Element
221              }
222              catch (Exception e)
223              {
# Line 201 | Line 225 | namespace xmlTools
225                  return false;
226              }
227  
228 <            if (Element == "")
228 >            if (String.IsNullOrEmpty(ElementParam))
229              {
230                  return false;
231              }
# Line 209 | Line 233 | namespace xmlTools
233              //---------------------------------------------------Parse Operation command (end)
234  
235              List<String> filesToProcess = new List<String>();
236 <            if (File == "")
236 >            if (String.IsNullOrEmpty(FileParam))
237              {
238                  filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder
239              }
240 <            else if (Util.containsWildcard(File))
240 >            else if (Util.containsWildcard(FileParam))
241              {
242 <                filesToProcess = Util.getXmlFilesWildcard(File);
242 >                filesToProcess = Util.getXmlFilesWildcard(FileParam);
243              }
244              else
245              {
246 <                filesToProcess.Add(File);
246 >                filesToProcess.Add(FileParam);
247              }
248  
249              //---------------------------------------------------XML Remove (start)
# Line 227 | Line 251 | namespace xmlTools
251              foreach (String currFile in filesToProcess)
252              {
253  
254 <                Util.backupFile(currFile);
254 >                if (!this.globalNoBackups && !Util.ContainsIgnoreCase(operation, "NoBackups")) // only skip backup if specified via global parameter or in patch file
255 >                {
256 >                    Util.backupFile(currFile);
257 >                }
258  
259                  XmlDocument xdoc = new XmlDocument();
260                  xdoc.Load(currFile);
261  
262                  List<XmlNode> myElements = new List<XmlNode>();
263 <                Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, Element, ParentElement); //Returns all after "Oni" element
263 >                Util.getAllSpecificElements(xdoc.DocumentElement, ref myElements, ElementParam, ParentElementParam); //Returns all after "Oni" element
264  
265                  if (myElements.Count == 0)
266                  {
# Line 253 | Line 280 | namespace xmlTools
280          }
281  
282          /// <summary>
283 <        ///
283 >        ///  Executes a command for xmlTools
284          /// </summary>
285          /// <param name="command"></param>
286          /// <returns>true or false depending if succeed or not</returns>
# Line 263 | Line 290 | namespace xmlTools
290  
291              command = command.Replace("@COMMAND ", ""); //get only the command to process
292  
293 <            if (command.Trim() == "")
293 >            if (String.IsNullOrEmpty(command.Trim()))
294              {
295                  Program.printAppError(Program.appErrors.PATCH_COMMAND_NOT_FOUND, "Error parsing commandOperation in Patch file: Command is empty.");
296                  return false;
# Line 271 | Line 298 | namespace xmlTools
298  
299              try
300              {
301 <                if (forceFiles != null)
301 >                if (!String.IsNullOrEmpty(forceFiles))
302                  {
303                      string paramType = "";
304  
305                      // Filename already exists?
306 <                    if (command.IndexOf("filename:") != -1)
306 >                    if (Util.ContainsIgnoreCase(command, "filename:"))
307                      {
308                          paramType = "filename:";
309                      }
310 <                    else if (command.IndexOf("filename=") != -1)
310 >                    else if (Util.ContainsIgnoreCase(command, "filename="))
311                      {
312                          paramType = "filename=";
313                      }
314                      // Add the filename if it doesn't exists
315                      else
316                      {
317 <                        command = command.Insert(command.Length-1," -filename:" + this.forceFiles); // -2 to be inside quotes
317 >                        command = command.Insert(command.Length, " -filename:" + this.forceFiles);
318                      }
319  
320 <                    if (paramType != "")
320 >                    if (!String.IsNullOrEmpty(paramType))
321                      {
322                          int startIdx = command.IndexOf(paramType) + paramType.Length;
323                          int endIdx = command.IndexOf(" ", startIdx); // it may end with space
324                          if (endIdx == -1)
325                          {
326 <                            endIdx = command.IndexOf("\"", startIdx); // or with quotes
326 >                            endIdx = command.IndexOf("\n", startIdx); // or with endline
327 >                            if (endIdx == -1)
328 >                            { // Filename parameters is the last one in the file (file ends with this parameter)
329 >                                endIdx = command.Length - 1;
330 >                            }
331                          }
332                          string currFilename = command.Substring(startIdx, endIdx - startIdx);
333                          command = command.Replace(currFilename, this.forceFiles);
# Line 304 | Line 335 | namespace xmlTools
335  
336                  }
337  
338 <                command = command.Replace("\"", ""); // remove quotes
308 <
309 <                ProcessStartInfo startInfo = new ProcessStartInfo();
310 <                if (!Util.IsRunningOnMono())
338 >                if (this.globalNoBackups && !Util.ContainsIgnoreCase(command, "nobackups")) // add noBackup flag if provided as global parameter
339                  {
340 <                    startInfo.FileName = Util.getExeFileName();
313 <                }
314 <                else{
315 <                    startInfo.FileName = "mono";
340 >                    command = command.Insert(command.Length, " -nobackups");
341                  }
317                if (!Util.IsRunningOnMono())
318                {
319                    startInfo.Arguments = command;
320                }
321                else{
322                    startInfo.Arguments = Util.getExeFileName() + " " + command;
323                }
324                startInfo.UseShellExecute = false; // necessary to redirect output
325                startInfo.RedirectStandardOutput = true;
326                startInfo.RedirectStandardError = true;
327                startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // hide new process window
342  
343 <                Process p = System.Diagnostics.Process.Start(startInfo);
330 <                p.OutputDataReceived += commandStdOutputReceived;
331 <                p.ErrorDataReceived += commandStdErrorReceived;
332 <                p.BeginOutputReadLine();
333 <                p.BeginErrorReadLine();
334 <                p.WaitForExit();
343 >                Program.Main(Util.stringToArgsArray(command)); // use the current process is more efficient than start a new one
344              }
345              catch (Exception e)
346              {
# Line 343 | Line 352 | namespace xmlTools
352          }
353  
354          /// <summary>
355 <        /// Reads asynchronously output from the new process where the command will be executed
355 >        /// Executes custom Javascript code over the xml file specified. Uses .NET JINT library.
356          /// </summary>
357 <        /// <param name="sender"></param>
358 <        /// <param name="e"></param>
359 <        private void commandStdOutputReceived(object sender, DataReceivedEventArgs e)
357 >        /// <param name="command"></param>
358 >        /// <returns></returns>
359 >        private bool executeCode(string operation, string jsCode)
360          {
361 +            string FileParam = "";
362  
363 <            string myData = e.Data;
364 <
355 <            if (myData != null)
363 >            //---------------------------------------------------Parse Operation command (start)
364 >            try
365              {
366 <                if (myData.EndsWith("\n"))
366 >                if (String.IsNullOrEmpty(forceFiles))
367                  {
368 <                    Console.Write(myData);
368 >                    FileParam = getPatchParameter(operation, "File");
369                  }
370                  else
371                  {
372 <                    Console.WriteLine(myData);
372 >                    FileParam = forceFiles;
373                  }
374 +
375 +            }
376 +            catch (Exception e)
377 +            {
378 +                Program.printAppError(Program.appErrors.PATCH_CODE_PROCESS_ERROR, "Error parsing codeOperation in Patch file.\n" + e.ToString());
379 +                return false;
380              }
381  
382 <        }
382 >            //---------------------------------------------------Parse Operation command (end)
383 >            List<String> filesToProcess = new List<String>();
384 >            if (String.IsNullOrEmpty(FileParam))
385 >            {
386 >                filesToProcess = Util.getAllXmlFiles(); //no file specified, use all xml files found in same folder
387 >            }
388 >            else if (Util.containsWildcard(FileParam))
389 >            {
390 >                filesToProcess = Util.getXmlFilesWildcard(FileParam);
391 >            }
392 >            else
393 >            {
394 >                filesToProcess.Add(FileParam);
395 >            }
396  
397 <        private void commandStdErrorReceived(object sender, DataReceivedEventArgs e)
398 <        {
397 >            //---------------------------------------------------JS Code Proccess (start)
398 >            foreach (String currXMLFile in filesToProcess)
399 >            {
400 >                if (!this.globalNoBackups && !Util.ContainsIgnoreCase(operation, "NoBackups")) // only skip backup if specified via global parameter or in patch file
401 >                {
402 >                    Util.backupFile(currXMLFile);
403 >                }
404  
405 <            string myData = e.Data;
405 >                string xmlFileContent = File.ReadAllText(currXMLFile);
406  
407 <            if (myData != null)
408 <            {
376 <                if (myData.EndsWith("\n"))
407 >                // Initialize Jint Engine
408 >                if (jsEngine == null)
409                  {
410 <                    Console.Error.Write(myData);
410 >                    jsEngine = new IronJS.Hosting.CSharp.Context();
411 >
412 >                    // Load XML libraries
413 >                    jsEngine.Execute(xmlTools.Properties.Resources.tinyxmlsax);
414 >                    jsEngine.Execute(xmlTools.Properties.Resources.tinyxmlw3cdom);
415                  }
416 <                else
416 >
417 >                // Construct code to execute
418 >                StringBuilder sourceCode = new StringBuilder();
419 >
420 >                // give user the xml we needs to edit...
421 >                sourceCode.Append("var $xmlData='").Append(xmlFileContent.Replace(System.Environment.NewLine, " \\" + System.Environment.NewLine)).Append("';").AppendLine(); // replace is for multine string in javascript (http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript)
422 >                // append the user js code...
423 >                sourceCode.Append(jsCode).AppendLine();
424 >                // return to .NET the new xml data
425 >                sourceCode.Append("$xmlData;");
426 >
427 >                try
428 >                {
429 >                    xmlFileContent = jsEngine.Execute(sourceCode.ToString()).ToString();
430 >                }
431 >                catch (Exception e)
432 >                {
433 >                    Program.printAppError(Program.appErrors.PATCH_CODE_PROCESS_ERROR, "Error parsing code in customCodeOperation in Patch file.\n" + e.ToString());
434 >                    return false;
435 >                }
436 >
437 >                // Let's see if the returned result is valid xml...
438 >                try
439 >                {
440 >                    XmlDocument xmlDoc = new XmlDocument();
441 >
442 >                    xmlDoc.LoadXml(xmlFileContent);
443 >
444 >                    xmlDoc.Save(currXMLFile); //saving the new xml with this method will auto ident it.
445 >
446 >                }
447 >                catch (Exception e)
448                  {
449 <                    Console.Error.WriteLine(myData);
449 >                    Program.printAppError(Program.appErrors.PATCH_CODE_PARSE_XML_OUTPUT_ERROR, "Error parsing result xml to customCodeOperation in Patch file.\n" + e.ToString());
450 >                    return false;
451                  }
452              }
453 +            //---------------------------------------------------JS Code Proccess (end)
454  
455 +            return true;
456          }
457  
458          private string getPatchParameter(string line, string parameterName)

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)