aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Prebuild/src/Core/Kernel.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Prebuild/src/Core/Kernel.cs')
-rw-r--r--Prebuild/src/Core/Kernel.cs831
1 files changed, 0 insertions, 831 deletions
diff --git a/Prebuild/src/Core/Kernel.cs b/Prebuild/src/Core/Kernel.cs
deleted file mode 100644
index 95ef04e..0000000
--- a/Prebuild/src/Core/Kernel.cs
+++ /dev/null
@@ -1,831 +0,0 @@
1#region BSD License
2/*
3Copyright (c) 2004-2008
4Matthew Holmes (matthew@wildfiregames.com),
5Dan Moorehead (dan05a@gmail.com),
6Rob Loach (http://www.robloach.net),
7C.J. Adams-Collier (cjac@colliertech.org)
8
9Redistribution and use in source and binary forms, with or without
10modification, are permitted provided that the following conditions are
11met:
12
13* Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16* Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in the
18 documentation and/or other materials provided with the distribution.
19
20* The name of the author may not be used to endorse or promote
21 products derived from this software without specific prior written
22 permission.
23
24THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
28INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34POSSIBILITY OF SUCH DAMAGE.
35
36*/
37#endregion
38
39using System;
40using System.Collections.Generic;
41using System.Diagnostics;
42using System.Collections;
43using System.Collections.Specialized;
44using System.IO;
45using System.Reflection;
46using System.Xml;
47using System.Xml.Schema;
48using System.Text;
49
50using Prebuild.Core.Attributes;
51using Prebuild.Core.Interfaces;
52using Prebuild.Core.Nodes;
53using Prebuild.Core.Parse;
54using Prebuild.Core.Utilities;
55
56namespace Prebuild.Core
57{
58 /// <summary>
59 ///
60 /// </summary>
61 public class Kernel : IDisposable
62 {
63 #region Inner Classes
64
65 private struct NodeEntry
66 {
67 public Type Type;
68 public DataNodeAttribute Attribute;
69 }
70
71 #endregion
72
73 #region Fields
74
75 private static readonly Kernel m_Instance = new Kernel();
76
77 /// <summary>
78 /// This must match the version of the schema that is embeeded
79 /// </summary>
80 private const string m_SchemaVersion = "1.7";
81 private const string m_Schema = "prebuild-" + m_SchemaVersion + ".xsd";
82 private const string m_SchemaURI = "http://dnpb.sourceforge.net/schemas/" + m_Schema;
83 bool disposed;
84 private Version m_Version;
85 private const string m_Revision = "";
86 private CommandLineCollection m_CommandLine;
87 private Log m_Log;
88 private CurrentDirectory m_CurrentWorkingDirectory;
89 private XmlSchemaCollection m_Schemas;
90
91 private Hashtable m_Targets;
92 private Hashtable m_Nodes;
93
94 readonly List<SolutionNode> m_Solutions = new List<SolutionNode>();
95 string m_Target;
96 string m_Clean;
97 string[] m_RemoveDirectories;
98 XmlDocument m_CurrentDoc;
99 bool m_PauseAfterFinish;
100 string[] m_ProjectGroups;
101
102 #endregion
103
104 #region Constructors
105
106 private Kernel()
107 {
108 }
109
110 #endregion
111
112 #region Properties
113
114 /// <summary>
115 /// Gets a value indicating whether [pause after finish].
116 /// </summary>
117 /// <value><c>true</c> if [pause after finish]; otherwise, <c>false</c>.</value>
118 public bool PauseAfterFinish
119 {
120 get
121 {
122 return m_PauseAfterFinish;
123 }
124 }
125
126 /// <summary>
127 /// Gets the instance.
128 /// </summary>
129 /// <value>The instance.</value>
130 public static Kernel Instance
131 {
132 get
133 {
134 return m_Instance;
135 }
136 }
137
138 /// <summary>
139 /// Gets the version.
140 /// </summary>
141 /// <value>The version.</value>
142 public string Version
143 {
144 get
145 {
146 return String.Format("{0}.{1}.{2}{3}", m_Version.Major, m_Version.Minor, m_Version.Build, m_Revision);
147 }
148 }
149
150 /// <summary>
151 /// Gets the command line.
152 /// </summary>
153 /// <value>The command line.</value>
154 public CommandLineCollection CommandLine
155 {
156 get
157 {
158 return m_CommandLine;
159 }
160 }
161
162 /// <summary>
163 /// Gets the targets.
164 /// </summary>
165 /// <value>The targets.</value>
166 public Hashtable Targets
167 {
168 get
169 {
170 return m_Targets;
171 }
172 }
173
174 /// <summary>
175 /// Gets the log.
176 /// </summary>
177 /// <value>The log.</value>
178 public Log Log
179 {
180 get
181 {
182 return m_Log;
183 }
184 }
185
186 /// <summary>
187 /// Gets the current working directory.
188 /// </summary>
189 /// <value>The current working directory.</value>
190 public CurrentDirectory CurrentWorkingDirectory
191 {
192 get
193 {
194 return m_CurrentWorkingDirectory;
195 }
196 }
197
198 /// <summary>
199 /// Gets the solutions.
200 /// </summary>
201 /// <value>The solutions.</value>
202 public List<SolutionNode> Solutions
203 {
204 get
205 {
206 return m_Solutions;
207 }
208 }
209
210 /// <summary>
211 /// Gets the XmlDocument object representing the prebuild.xml
212 /// being processed
213 /// </summary>
214 /// <value>The XmlDocument object</value>
215 public XmlDocument CurrentDoc
216 {
217 get
218 {
219 return m_CurrentDoc;
220 }
221 }
222
223 #endregion
224
225 #region Private Methods
226
227 private static void RemoveDirectories(string rootDir, string[] dirNames)
228 {
229 foreach(string dir in Directory.GetDirectories(rootDir))
230 {
231 string simpleName = Path.GetFileName(dir);
232
233 if(Array.IndexOf(dirNames, simpleName) != -1)
234 {
235 //delete if the name matches one of the directory names to delete
236 string fullDirPath = Path.GetFullPath(dir);
237 Directory.Delete(fullDirPath,true);
238 }
239 else//not a match, so check children
240 {
241 RemoveDirectories(dir,dirNames);
242 //recurse, checking children for them
243 }
244 }
245 }
246
247// private void RemoveDirectoryMatches(string rootDir, string dirPattern)
248// {
249// foreach(string dir in Directory.GetDirectories(rootDir))
250// {
251// foreach(string match in Directory.GetDirectories(dir))
252// {//delete all child directories that match
253// Directory.Delete(Path.GetFullPath(match),true);
254// }
255// //recure through the rest checking for nested matches to delete
256// RemoveDirectoryMatches(dir,dirPattern);
257// }
258// }
259
260 private void LoadSchema()
261 {
262 Assembly assembly = this.GetType().Assembly;
263 Stream stream = assembly.GetManifestResourceStream("Prebuild.data." + m_Schema);
264 if(stream == null)
265 {
266 //try without the default namespace prepending to it in case was compiled with SharpDevelop or MonoDevelop instead of Visual Studio .NET
267 stream = assembly.GetManifestResourceStream(m_Schema);
268 if(stream == null)
269 {
270 throw new System.Reflection.TargetException(string.Format("Could not find the scheme embedded resource file '{0}'.", m_Schema));
271 }
272 }
273 XmlReader schema = new XmlTextReader(stream);
274
275 m_Schemas = new XmlSchemaCollection();
276 m_Schemas.Add(m_SchemaURI, schema);
277 }
278
279 private void CacheVersion()
280 {
281 m_Version = Assembly.GetEntryAssembly().GetName().Version;
282 }
283
284 private void CacheTargets(Assembly assm)
285 {
286 foreach(Type t in assm.GetTypes())
287 {
288 TargetAttribute ta = (TargetAttribute)Helper.CheckType(t, typeof(TargetAttribute), typeof(ITarget));
289
290 if(ta == null)
291 continue;
292
293 if (t.IsAbstract)
294 continue;
295
296 ITarget target = (ITarget)assm.CreateInstance(t.FullName);
297 if (target == null)
298 {
299 throw new MissingMethodException("Could not create ITarget instance");
300 }
301
302 m_Targets[ta.Name] = target;
303 }
304 }
305
306 private void CacheNodeTypes(Assembly assm)
307 {
308 foreach(Type t in assm.GetTypes())
309 {
310 foreach (DataNodeAttribute dna in t.GetCustomAttributes(typeof(DataNodeAttribute), true))
311 {
312 NodeEntry ne = new NodeEntry();
313 ne.Type = t;
314 ne.Attribute = dna;
315 m_Nodes[dna.Name] = ne;
316 }
317 }
318 }
319
320 private void LogBanner()
321 {
322 m_Log.Write("Prebuild v" + this.Version);
323 m_Log.Write("Copyright (c) 2004-2008");
324 m_Log.Write("Matthew Holmes (matthew@wildfiregames.com),");
325 m_Log.Write("Dan Moorehead (dan05a@gmail.com),");
326 m_Log.Write("David Hudson (jendave@yahoo.com),");
327 m_Log.Write("Rob Loach (http://www.robloach.net),");
328 m_Log.Write("C.J. Adams-Collier (cjac@colliertech.org),");
329
330 m_Log.Write("See 'prebuild /usage' for help");
331 m_Log.Write();
332 }
333
334
335
336 private void ProcessFile(string file)
337 {
338 ProcessFile(file, this.m_Solutions);
339 }
340
341 public void ProcessFile(ProcessNode node, SolutionNode parent)
342 {
343 if (node.IsValid)
344 {
345 List<SolutionNode> list = new List<SolutionNode>();
346 ProcessFile(node.Path, list);
347
348 foreach (SolutionNode solution in list)
349 parent.SolutionsTable[solution.Name] = solution;
350 }
351 }
352
353 /// <summary>
354 ///
355 /// </summary>
356 /// <param name="file"></param>
357 /// <param name="solutions"></param>
358 /// <returns></returns>
359 public void ProcessFile(string file, IList<SolutionNode> solutions)
360 {
361 m_CurrentWorkingDirectory.Push();
362
363 string path = file;
364 try
365 {
366 try
367 {
368 path = Helper.ResolvePath(path);
369 }
370 catch(ArgumentException)
371 {
372 m_Log.Write("Could not open Prebuild file: " + path);
373 m_CurrentWorkingDirectory.Pop();
374 return;
375 }
376
377 Helper.SetCurrentDir(Path.GetDirectoryName(path));
378
379 XmlTextReader reader = new XmlTextReader(path);
380
381 Core.Parse.Preprocessor pre = new Core.Parse.Preprocessor();
382
383 //register command line arguments as XML variables
384 IDictionaryEnumerator dict = m_CommandLine.GetEnumerator();
385 while (dict.MoveNext())
386 {
387 string name = dict.Key.ToString().Trim();
388 if (name.Length > 0)
389 pre.RegisterVariable(name, dict.Value.ToString());
390 }
391
392 string xml = pre.Process(reader);//remove script and evaulate pre-proccessing to get schema-conforming XML
393
394 // See if the user put into a pseudo target of "prebuild:preprocessed-input" to indicate they want to see the
395 // output before the system processes it.
396 if (m_CommandLine.WasPassed("ppi"))
397 {
398 // Get the filename if there is one, otherwise use a default.
399 string ppiFile = m_CommandLine["ppi"];
400 if (ppiFile == null || ppiFile.Trim().Length == 0)
401 {
402 ppiFile = "preprocessed-input.xml";
403 }
404
405 // Write out the string to the given stream.
406 try
407 {
408 using (StreamWriter ppiWriter = new StreamWriter(ppiFile))
409 {
410 ppiWriter.WriteLine(xml);
411 }
412 }
413 catch(IOException ex)
414 {
415 Console.WriteLine("Could not write PPI file '{0}': {1}", ppiFile, ex.Message);
416 }
417
418 // Finish processing this special tag.
419 return;
420 }
421
422 m_CurrentDoc = new XmlDocument();
423 try
424 {
425 XmlValidatingReader validator = new XmlValidatingReader(new XmlTextReader(new StringReader(xml)));
426
427 //validate while reading from string into XmlDocument DOM structure in memory
428 foreach(XmlSchema schema in m_Schemas)
429 {
430 validator.Schemas.Add(schema);
431 }
432 m_CurrentDoc.Load(validator);
433 }
434 catch(XmlException e)
435 {
436 throw new XmlException(e.ToString());
437 }
438
439 //is there a purpose to writing it? An syntax/schema problem would have been found during pre.Process() and reported with details
440 if(m_CommandLine.WasPassed("ppo"))
441 {
442 string ppoFile = m_CommandLine["ppo"];
443 if(ppoFile == null || ppoFile.Trim().Length < 1)
444 {
445 ppoFile = "preprocessed.xml";
446 }
447
448 StreamWriter writer = null;
449 try
450 {
451 writer = new StreamWriter(ppoFile);
452 writer.Write(xml);
453 }
454 catch(IOException ex)
455 {
456 Console.WriteLine("Could not write PPO file '{0}': {1}", ppoFile, ex.Message);
457 }
458 finally
459 {
460 if(writer != null)
461 {
462 writer.Close();
463 }
464 }
465 return;
466 }
467 //start reading the xml config file
468 XmlElement rootNode = m_CurrentDoc.DocumentElement;
469 //string suggestedVersion = Helper.AttributeValue(rootNode,"version","1.0");
470 Helper.CheckForOSVariables = Helper.ParseBoolean(rootNode,"checkOsVars",false);
471
472 foreach(XmlNode node in rootNode.ChildNodes)//solutions or if pre-proc instructions
473 {
474 IDataNode dataNode = ParseNode(node, null);
475 if(dataNode is ProcessNode)
476 {
477 ProcessNode proc = (ProcessNode)dataNode;
478 if(proc.IsValid)
479 {
480 ProcessFile(proc.Path);
481 }
482 }
483 else if(dataNode is SolutionNode)
484 {
485 solutions.Add((SolutionNode)dataNode);
486 }
487 }
488 }
489 catch(XmlSchemaException xse)
490 {
491 m_Log.Write("XML validation error at line {0} in {1}:\n\n{2}",
492 xse.LineNumber, path, xse.Message);
493 }
494 finally
495 {
496 m_CurrentWorkingDirectory.Pop();
497 }
498 }
499
500 #endregion
501
502 #region Public Methods
503
504 /// <summary>
505 /// Allows the project.
506 /// </summary>
507 /// <param name="projectGroupsFlags">The project groups flags.</param>
508 /// <returns></returns>
509 public bool AllowProject(string projectGroupsFlags)
510 {
511 if(m_ProjectGroups != null && m_ProjectGroups.Length > 0)
512 {
513 if(projectGroupsFlags != null && projectGroupsFlags.Length == 0)
514 {
515 foreach(string group in projectGroupsFlags.Split('|'))
516 {
517 if(Array.IndexOf(m_ProjectGroups, group) != -1) //if included in the filter list
518 {
519 return true;
520 }
521 }
522 }
523 return false;//not included in the list or no groups specified for the project
524 }
525 return true;//no filter specified in the command line args
526 }
527
528 /// <summary>
529 /// Gets the type of the node.
530 /// </summary>
531 /// <param name="node">The node.</param>
532 /// <returns></returns>
533 public Type GetNodeType(XmlNode node)
534 {
535 if( node == null )
536 {
537 throw new ArgumentNullException("node");
538 }
539 if(!m_Nodes.ContainsKey(node.Name))
540 {
541 return null;
542 }
543
544 NodeEntry ne = (NodeEntry)m_Nodes[node.Name];
545 return ne.Type;
546 }
547
548 /// <summary>
549 ///
550 /// </summary>
551 /// <param name="node"></param>
552 /// <param name="parent"></param>
553 /// <returns></returns>
554 public IDataNode ParseNode(XmlNode node, IDataNode parent)
555 {
556 return ParseNode(node, parent, null);
557 }
558
559 //Create an instance of the data node type that is mapped to the name of the xml DOM node
560 /// <summary>
561 /// Parses the node.
562 /// </summary>
563 /// <param name="node">The node.</param>
564 /// <param name="parent">The parent.</param>
565 /// <param name="preNode">The pre node.</param>
566 /// <returns></returns>
567 public IDataNode ParseNode(XmlNode node, IDataNode parent, IDataNode preNode)
568 {
569 IDataNode dataNode;
570
571 try
572 {
573 if( node == null )
574 {
575 throw new ArgumentNullException("node");
576 }
577 if(preNode == null)
578 {
579 if(!m_Nodes.ContainsKey(node.Name))
580 {
581 //throw new XmlException("Unknown XML node: " + node.Name);
582 return null;
583 }
584
585 NodeEntry ne = (NodeEntry)m_Nodes[node.Name];
586 Type type = ne.Type;
587 //DataNodeAttribute dna = ne.Attribute;
588
589 dataNode = (IDataNode)type.Assembly.CreateInstance(type.FullName);
590 if(dataNode == null)
591 {
592 throw new System.Reflection.TargetException("Could not create new parser instance: " + type.FullName);
593 }
594 }
595 else
596 dataNode = preNode;
597
598 dataNode.Parent = parent;
599 dataNode.Parse(node);
600 }
601 catch(WarningException wex)
602 {
603 m_Log.Write(LogType.Warning, wex.Message);
604 return null;
605 }
606 catch(FatalException fex)
607 {
608 m_Log.WriteException(LogType.Error, fex);
609 throw;
610 }
611 catch(Exception ex)
612 {
613 m_Log.WriteException(LogType.Error, ex);
614 throw;
615 }
616
617 return dataNode;
618 }
619
620 /// <summary>
621 /// Initializes the specified target.
622 /// </summary>
623 /// <param name="target">The target.</param>
624 /// <param name="args">The args.</param>
625 public void Initialize(LogTargets target, string[] args)
626 {
627 m_Targets = new Hashtable();
628 CacheTargets(this.GetType().Assembly);
629 m_Nodes = new Hashtable();
630 CacheNodeTypes(this.GetType().Assembly);
631 CacheVersion();
632
633 m_CommandLine = new CommandLineCollection(args);
634
635 string logFile = null;
636 if(m_CommandLine.WasPassed("log"))
637 {
638 logFile = m_CommandLine["log"];
639
640 if(logFile != null && logFile.Length == 0)
641 {
642 logFile = "Prebuild.log";
643 }
644 }
645 else
646 {
647 target = target & ~LogTargets.File; //dont output to a file
648 }
649
650 m_Log = new Log(target, logFile);
651 LogBanner();
652
653 m_CurrentWorkingDirectory = new CurrentDirectory();
654
655 m_Target = m_CommandLine["target"];
656 m_Clean = m_CommandLine["clean"];
657 string removeDirs = m_CommandLine["removedir"];
658 if(removeDirs != null && removeDirs.Length == 0)
659 {
660 m_RemoveDirectories = removeDirs.Split('|');
661 }
662
663 string flags = m_CommandLine["allowedgroups"];//allows filtering by specifying a pipe-delimited list of groups to include
664 if(flags != null && flags.Length == 0)
665 {
666 m_ProjectGroups = flags.Split('|');
667 }
668 m_PauseAfterFinish = m_CommandLine.WasPassed("pause");
669
670 LoadSchema();
671 }
672
673 /// <summary>
674 /// Processes this instance.
675 /// </summary>
676 public void Process()
677 {
678 bool perfomedOtherTask = false;
679 if(m_RemoveDirectories != null && m_RemoveDirectories.Length > 0)
680 {
681 try
682 {
683 RemoveDirectories(".",m_RemoveDirectories);
684 }
685 catch(IOException e)
686 {
687 m_Log.Write("Failed to remove directories named {0}",m_RemoveDirectories);
688 m_Log.WriteException(LogType.Error,e);
689 }
690 catch(UnauthorizedAccessException e)
691 {
692 m_Log.Write("Failed to remove directories named {0}",m_RemoveDirectories);
693 m_Log.WriteException(LogType.Error,e);
694 }
695 perfomedOtherTask = true;
696 }
697
698 if(m_Target != null && m_Clean != null)
699 {
700 m_Log.Write(LogType.Error, "The options /target and /clean cannot be passed together");
701 return;
702 }
703
704 if(m_Target == null && m_Clean == null)
705 {
706 if(perfomedOtherTask) //finished
707 {
708 return;
709 }
710 m_Log.Write(LogType.Error, "Must pass either /target or /clean to process a Prebuild file");
711 return;
712 }
713
714 string file = "./prebuild.xml";
715 if(m_CommandLine.WasPassed("file"))
716 {
717 file = m_CommandLine["file"];
718 }
719
720 ProcessFile(file);
721
722 string target = (m_Target != null ? m_Target.ToLower() : m_Clean.ToLower());
723 bool clean = (m_Target == null);
724 if(clean && target != null && target.Length == 0)
725 {
726 target = "all";
727 }
728 if(clean && target == "all")//default to all if no target was specified for clean
729 {
730 //check if they passed yes
731 if (!m_CommandLine.WasPassed("yes"))
732 {
733 Console.WriteLine("WARNING: This operation will clean ALL project files for all targets, are you sure? (y/n):");
734 string ret = Console.ReadLine();
735 if(ret == null)
736 {
737 return;
738 }
739 ret = ret.Trim().ToLower();
740 if((ret.ToLower() != "y" && ret.ToLower() != "yes"))
741 {
742 return;
743 }
744 }
745 //clean all targets (just cleaning vs2002 target didn't clean nant)
746 foreach(ITarget targ in m_Targets.Values)
747 {
748 targ.Clean(this);
749 }
750 }
751 else
752 {
753 if (!m_Targets.Contains(target)) {
754 m_Log.Write(LogType.Error, "Unknown Target \"{0}\"", target);
755 return;
756 }
757 ITarget targ = (ITarget)m_Targets[target];
758
759 if(clean)
760 {
761 targ.Clean(this);
762 }
763 else
764 {
765 targ.Write(this);
766 }
767 }
768
769 m_Log.Flush();
770 }
771
772 #endregion
773
774 #region IDisposable Members
775
776 /// <summary>
777 ///
778 /// </summary>
779 public void Dispose()
780 {
781 Dispose(true);
782 GC.SuppressFinalize(this);
783 }
784
785 /// <summary>
786 /// Dispose objects
787 /// </summary>
788 /// <param name="disposing">
789 /// If true, it will dispose close the handle
790 /// </param>
791 /// <remarks>
792 /// Will dispose managed and unmanaged resources.
793 /// </remarks>
794 protected virtual void Dispose(bool disposing)
795 {
796 if (!this.disposed)
797 {
798 if (disposing)
799 {
800 if (this.m_Log != null)
801 {
802 this.m_Log.Close();
803 this.m_Log = null;
804 }
805 }
806 }
807 this.disposed = true;
808 }
809
810 /// <summary>
811 ///
812 /// </summary>
813 ~Kernel()
814 {
815 this.Dispose(false);
816 }
817
818 /// <summary>
819 /// Closes and destroys this object
820 /// </summary>
821 /// <remarks>
822 /// Same as Dispose(true)
823 /// </remarks>
824 public void Close()
825 {
826 Dispose();
827 }
828
829 #endregion
830 }
831}