From 7e65590a55ba575d0086bdfc25addaf1051d799b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 11 Sep 2010 01:13:08 +0100 Subject: Update Prebuild.exe with Prebuild r323 + an existing OpenSim specific nant hack to correctly clean up chosen OpenSim exes and dlls in bin/ on a "nant clean" Source code is included for reference. This can go away again once Prebuild is updated with a more general mechanism for cleaning up files. The Prebuild source code here can be built with nant, or regnerated for other tools using the prebuild at {root}/bin/Prebuild.exe --- Prebuild/src/Core/Kernel.cs | 832 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 832 insertions(+) create mode 100644 Prebuild/src/Core/Kernel.cs (limited to 'Prebuild/src/Core/Kernel.cs') diff --git a/Prebuild/src/Core/Kernel.cs b/Prebuild/src/Core/Kernel.cs new file mode 100644 index 0000000..67051d5 --- /dev/null +++ b/Prebuild/src/Core/Kernel.cs @@ -0,0 +1,832 @@ +#region BSD License +/* +Copyright (c) 2004-2008 +Matthew Holmes (matthew@wildfiregames.com), +Dan Moorehead (dan05a@gmail.com), +Rob Loach (http://www.robloach.net), +C.J. Adams-Collier (cjac@colliertech.org) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ +#endregion + +#define NO_VALIDATE + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using Prebuild.Core.Attributes; +using Prebuild.Core.Interfaces; +using Prebuild.Core.Nodes; +using Prebuild.Core.Utilities; + +namespace Prebuild.Core +{ + /// + /// + /// + public class Kernel : IDisposable + { + #region Inner Classes + + private struct NodeEntry + { + public Type Type; + public DataNodeAttribute Attribute; + } + + #endregion + + #region Fields + + private static readonly Kernel m_Instance = new Kernel(); + + /// + /// This must match the version of the schema that is embeeded + /// + private const string m_SchemaVersion = "1.9"; + private const string m_Schema = "prebuild-" + m_SchemaVersion + ".xsd"; + private const string m_SchemaURI = "http://dnpb.sourceforge.net/schemas/" + m_Schema; + bool disposed; + private Version m_Version; + private const string m_Revision = ""; + private CommandLineCollection m_CommandLine; + private Log m_Log; + private CurrentDirectory m_CurrentWorkingDirectory; + private XmlSchemaCollection m_Schemas; + + private readonly Dictionary m_Targets = new Dictionary(); + private readonly Dictionary m_Nodes = new Dictionary(); + + readonly List m_Solutions = new List(); + string m_Target; + string m_Clean; + string[] m_RemoveDirectories; + XmlDocument m_CurrentDoc; + bool m_PauseAfterFinish; + string[] m_ProjectGroups; + + #endregion + + #region Constructors + + private Kernel() + { + } + + #endregion + + #region Properties + + /// + /// Gets a value indicating whether [pause after finish]. + /// + /// true if [pause after finish]; otherwise, false. + public bool PauseAfterFinish + { + get + { + return m_PauseAfterFinish; + } + } + + /// + /// Gets the instance. + /// + /// The instance. + public static Kernel Instance + { + get + { + return m_Instance; + } + } + + /// + /// Gets the version. + /// + /// The version. + public string Version + { + get + { + return String.Format("{0}.{1}.{2}{3}", m_Version.Major, m_Version.Minor, m_Version.Build, m_Revision); + } + } + + /// + /// Gets the command line. + /// + /// The command line. + public CommandLineCollection CommandLine + { + get + { + return m_CommandLine; + } + } + + /// + /// Gets the targets. + /// + /// The targets. + public Dictionary Targets + { + get + { + return m_Targets; + } + } + + /// + /// Gets the log. + /// + /// The log. + public Log Log + { + get + { + return m_Log; + } + } + + /// + /// Gets the current working directory. + /// + /// The current working directory. + public CurrentDirectory CurrentWorkingDirectory + { + get + { + return m_CurrentWorkingDirectory; + } + } + + /// + /// Gets the solutions. + /// + /// The solutions. + public List Solutions + { + get + { + return m_Solutions; + } + } + + /// + /// Gets the XmlDocument object representing the prebuild.xml + /// being processed + /// + /// The XmlDocument object + public XmlDocument CurrentDoc + { + get + { + return m_CurrentDoc; + } + } + + #endregion + + #region Private Methods + + private static void RemoveDirectories(string rootDir, string[] dirNames) + { + foreach(string dir in Directory.GetDirectories(rootDir)) + { + string simpleName = Path.GetFileName(dir); + + if(Array.IndexOf(dirNames, simpleName) != -1) + { + //delete if the name matches one of the directory names to delete + string fullDirPath = Path.GetFullPath(dir); + Directory.Delete(fullDirPath,true); + } + else//not a match, so check children + { + RemoveDirectories(dir,dirNames); + //recurse, checking children for them + } + } + } + +// private void RemoveDirectoryMatches(string rootDir, string dirPattern) +// { +// foreach(string dir in Directory.GetDirectories(rootDir)) +// { +// foreach(string match in Directory.GetDirectories(dir)) +// {//delete all child directories that match +// Directory.Delete(Path.GetFullPath(match),true); +// } +// //recure through the rest checking for nested matches to delete +// RemoveDirectoryMatches(dir,dirPattern); +// } +// } + + private void LoadSchema() + { + Assembly assembly = GetType().Assembly; + Stream stream = assembly.GetManifestResourceStream("Prebuild.data." + m_Schema); + if(stream == null) + { + //try without the default namespace prepending to it in case was compiled with SharpDevelop or MonoDevelop instead of Visual Studio .NET + stream = assembly.GetManifestResourceStream(m_Schema); + if(stream == null) + { + throw new System.Reflection.TargetException(string.Format("Could not find the scheme embedded resource file '{0}'.", m_Schema)); + } + } + XmlReader schema = new XmlTextReader(stream); + + m_Schemas = new XmlSchemaCollection(); + m_Schemas.Add(m_SchemaURI, schema); + } + + private void CacheVersion() + { + m_Version = Assembly.GetEntryAssembly().GetName().Version; + } + + private void CacheTargets(Assembly assm) + { + foreach(Type t in assm.GetTypes()) + { + TargetAttribute ta = (TargetAttribute)Helper.CheckType(t, typeof(TargetAttribute), typeof(ITarget)); + + if(ta == null) + continue; + + if (t.IsAbstract) + continue; + + ITarget target = (ITarget)assm.CreateInstance(t.FullName); + if (target == null) + { + throw new MissingMethodException("Could not create ITarget instance"); + } + + m_Targets[ta.Name] = target; + } + } + + private void CacheNodeTypes(Assembly assm) + { + foreach(Type t in assm.GetTypes()) + { + foreach (DataNodeAttribute dna in t.GetCustomAttributes(typeof(DataNodeAttribute), true)) + { + NodeEntry ne = new NodeEntry(); + ne.Type = t; + ne.Attribute = dna; + m_Nodes[dna.Name] = ne; + } + } + } + + private void LogBanner() + { + m_Log.Write("Prebuild v" + Version); + m_Log.Write("Copyright (c) 2004-2010"); + m_Log.Write("Matthew Holmes (matthew@wildfiregames.com),"); + m_Log.Write("Dan Moorehead (dan05a@gmail.com),"); + m_Log.Write("David Hudson (jendave@yahoo.com),"); + m_Log.Write("Rob Loach (http://www.robloach.net),"); + m_Log.Write("C.J. Adams-Collier (cjac@colliertech.org),"); + m_Log.Write("John Hurliman (john.hurliman@intel.com),"); + + m_Log.Write("See 'prebuild /usage' for help"); + m_Log.Write(); + } + + + + private void ProcessFile(string file) + { + ProcessFile(file, m_Solutions); + } + + public void ProcessFile(ProcessNode node, SolutionNode parent) + { + if (node.IsValid) + { + List list = new List(); + ProcessFile(node.Path, list); + + foreach (SolutionNode solution in list) + parent.SolutionsTable[solution.Name] = solution; + } + } + + /// + /// + /// + /// + /// + /// + public void ProcessFile(string file, IList solutions) + { + m_CurrentWorkingDirectory.Push(); + + string path = file; + try + { + try + { + path = Helper.ResolvePath(path); + } + catch(ArgumentException) + { + m_Log.Write("Could not open Prebuild file: " + path); + m_CurrentWorkingDirectory.Pop(); + return; + } + + Helper.SetCurrentDir(Path.GetDirectoryName(path)); + + XmlTextReader reader = new XmlTextReader(path); + + Core.Parse.Preprocessor pre = new Core.Parse.Preprocessor(); + + //register command line arguments as XML variables + IEnumerator> dict = m_CommandLine.GetEnumerator(); + while (dict.MoveNext()) + { + string name = dict.Current.Key.Trim(); + if (name.Length > 0) + pre.RegisterVariable(name, dict.Current.Value); + } + + string xml = pre.Process(reader);//remove script and evaulate pre-proccessing to get schema-conforming XML + + // See if the user put into a pseudo target of "prebuild:preprocessed-input" to indicate they want to see the + // output before the system processes it. + if (m_CommandLine.WasPassed("ppi")) + { + // Get the filename if there is one, otherwise use a default. + string ppiFile = m_CommandLine["ppi"]; + if (ppiFile == null || ppiFile.Trim().Length == 0) + { + ppiFile = "preprocessed-input.xml"; + } + + // Write out the string to the given stream. + try + { + using (StreamWriter ppiWriter = new StreamWriter(ppiFile)) + { + ppiWriter.WriteLine(xml); + } + } + catch(IOException ex) + { + Console.WriteLine("Could not write PPI file '{0}': {1}", ppiFile, ex.Message); + } + + // Finish processing this special tag. + return; + } + + m_CurrentDoc = new XmlDocument(); + try + { +#if NO_VALIDATE + XmlReader validator = XmlReader.Create(new StringReader(xml)); + m_CurrentDoc.Load(validator); +#else + XmlValidatingReader validator = new XmlValidatingReader(new XmlTextReader(new StringReader(xml))); + + //validate while reading from string into XmlDocument DOM structure in memory + foreach(XmlSchema schema in m_Schemas) + { + validator.Schemas.Add(schema); + } + m_CurrentDoc.Load(validator); +#endif + } + catch(XmlException e) + { + throw new XmlException(e.ToString()); + } + + //is there a purpose to writing it? An syntax/schema problem would have been found during pre.Process() and reported with details + if(m_CommandLine.WasPassed("ppo")) + { + string ppoFile = m_CommandLine["ppo"]; + if(ppoFile == null || ppoFile.Trim().Length < 1) + { + ppoFile = "preprocessed.xml"; + } + + StreamWriter writer = null; + try + { + writer = new StreamWriter(ppoFile); + writer.Write(xml); + } + catch(IOException ex) + { + Console.WriteLine("Could not write PPO file '{0}': {1}", ppoFile, ex.Message); + } + finally + { + if(writer != null) + { + writer.Close(); + } + } + return; + } + //start reading the xml config file + XmlElement rootNode = m_CurrentDoc.DocumentElement; + //string suggestedVersion = Helper.AttributeValue(rootNode,"version","1.0"); + Helper.CheckForOSVariables = Helper.ParseBoolean(rootNode,"checkOsVars",false); + + foreach(XmlNode node in rootNode.ChildNodes)//solutions or if pre-proc instructions + { + IDataNode dataNode = ParseNode(node, null); + if(dataNode is ProcessNode) + { + ProcessNode proc = (ProcessNode)dataNode; + if(proc.IsValid) + { + ProcessFile(proc.Path); + } + } + else if(dataNode is SolutionNode) + { + solutions.Add((SolutionNode)dataNode); + } + } + } + catch(XmlSchemaException xse) + { + m_Log.Write("XML validation error at line {0} in {1}:\n\n{2}", + xse.LineNumber, path, xse.Message); + } + finally + { + m_CurrentWorkingDirectory.Pop(); + } + } + + #endregion + + #region Public Methods + + /// + /// Allows the project. + /// + /// The project groups flags. + /// + public bool AllowProject(string projectGroupsFlags) + { + if(m_ProjectGroups != null && m_ProjectGroups.Length > 0) + { + if(projectGroupsFlags != null && projectGroupsFlags.Length == 0) + { + foreach(string group in projectGroupsFlags.Split('|')) + { + if(Array.IndexOf(m_ProjectGroups, group) != -1) //if included in the filter list + { + return true; + } + } + } + return false;//not included in the list or no groups specified for the project + } + return true;//no filter specified in the command line args + } + + /// + /// Gets the type of the node. + /// + /// The node. + /// + public Type GetNodeType(XmlNode node) + { + if( node == null ) + { + throw new ArgumentNullException("node"); + } + if(!m_Nodes.ContainsKey(node.Name)) + { + return null; + } + + NodeEntry ne = m_Nodes[node.Name]; + return ne.Type; + } + + /// + /// + /// + /// + /// + /// + public IDataNode ParseNode(XmlNode node, IDataNode parent) + { + return ParseNode(node, parent, null); + } + + //Create an instance of the data node type that is mapped to the name of the xml DOM node + /// + /// Parses the node. + /// + /// The node. + /// The parent. + /// The pre node. + /// + public IDataNode ParseNode(XmlNode node, IDataNode parent, IDataNode preNode) + { + IDataNode dataNode; + + try + { + if( node == null ) + { + throw new ArgumentNullException("node"); + } + if(preNode == null) + { + if(!m_Nodes.ContainsKey(node.Name)) + { + Console.WriteLine("WARNING: Unknown XML node: " + node.Name); + return null; + } + + NodeEntry ne = m_Nodes[node.Name]; + Type type = ne.Type; + //DataNodeAttribute dna = ne.Attribute; + + dataNode = (IDataNode)type.Assembly.CreateInstance(type.FullName); + if(dataNode == null) + { + throw new System.Reflection.TargetException("Could not create new parser instance: " + type.FullName); + } + } + else + dataNode = preNode; + + dataNode.Parent = parent; + dataNode.Parse(node); + } + catch(WarningException wex) + { + m_Log.Write(LogType.Warning, wex.Message); + return null; + } + catch(FatalException fex) + { + m_Log.WriteException(LogType.Error, fex); + throw; + } + catch(Exception ex) + { + m_Log.WriteException(LogType.Error, ex); + throw; + } + + return dataNode; + } + + /// + /// Initializes the specified target. + /// + /// The target. + /// The args. + public void Initialize(LogTargets target, string[] args) + { + CacheTargets(GetType().Assembly); + CacheNodeTypes(GetType().Assembly); + CacheVersion(); + + m_CommandLine = new CommandLineCollection(args); + + string logFile = null; + if(m_CommandLine.WasPassed("log")) + { + logFile = m_CommandLine["log"]; + + if(logFile != null && logFile.Length == 0) + { + logFile = "Prebuild.log"; + } + } + else + { + target = target & ~LogTargets.File; //dont output to a file + } + + m_Log = new Log(target, logFile); + LogBanner(); + + m_CurrentWorkingDirectory = new CurrentDirectory(); + + m_Target = m_CommandLine["target"]; + m_Clean = m_CommandLine["clean"]; + string removeDirs = m_CommandLine["removedir"]; + if(removeDirs != null && removeDirs.Length == 0) + { + m_RemoveDirectories = removeDirs.Split('|'); + } + + string flags = m_CommandLine["allowedgroups"];//allows filtering by specifying a pipe-delimited list of groups to include + if(flags != null && flags.Length == 0) + { + m_ProjectGroups = flags.Split('|'); + } + m_PauseAfterFinish = m_CommandLine.WasPassed("pause"); + + LoadSchema(); + } + + /// + /// Processes this instance. + /// + public void Process() + { + bool perfomedOtherTask = false; + if(m_RemoveDirectories != null && m_RemoveDirectories.Length > 0) + { + try + { + RemoveDirectories(".",m_RemoveDirectories); + } + catch(IOException e) + { + m_Log.Write("Failed to remove directories named {0}",m_RemoveDirectories); + m_Log.WriteException(LogType.Error,e); + } + catch(UnauthorizedAccessException e) + { + m_Log.Write("Failed to remove directories named {0}",m_RemoveDirectories); + m_Log.WriteException(LogType.Error,e); + } + perfomedOtherTask = true; + } + + if(m_Target != null && m_Clean != null) + { + m_Log.Write(LogType.Error, "The options /target and /clean cannot be passed together"); + return; + } + + if(m_Target == null && m_Clean == null) + { + if(perfomedOtherTask) //finished + { + return; + } + m_Log.Write(LogType.Error, "Must pass either /target or /clean to process a Prebuild file"); + return; + } + + string file = "./prebuild.xml"; + if(m_CommandLine.WasPassed("file")) + { + file = m_CommandLine["file"]; + } + + ProcessFile(file); + + string target = (m_Target != null ? m_Target.ToLower() : m_Clean.ToLower()); + bool clean = (m_Target == null); + if(clean && target != null && target.Length == 0) + { + target = "all"; + } + if(clean && target == "all")//default to all if no target was specified for clean + { + //check if they passed yes + if (!m_CommandLine.WasPassed("yes")) + { + Console.WriteLine("WARNING: This operation will clean ALL project files for all targets, are you sure? (y/n):"); + string ret = Console.ReadLine(); + if(ret == null) + { + return; + } + ret = ret.Trim().ToLower(); + if((ret.ToLower() != "y" && ret.ToLower() != "yes")) + { + return; + } + } + //clean all targets (just cleaning vs2002 target didn't clean nant) + foreach(ITarget targ in m_Targets.Values) + { + targ.Clean(this); + } + } + else + { + if (!m_Targets.ContainsKey(target)) { + m_Log.Write(LogType.Error, "Unknown Target \"{0}\"", target); + return; + } + ITarget targ = m_Targets[target]; + + if(clean) + { + targ.Clean(this); + } + else + { + targ.Write(this); + } + } + + m_Log.Flush(); + } + + #endregion + + #region IDisposable Members + + /// + /// + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose objects + /// + /// + /// If true, it will dispose close the handle + /// + /// + /// Will dispose managed and unmanaged resources. + /// + protected virtual void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + GC.SuppressFinalize(this); + if (m_Log != null) + { + m_Log.Close(); + m_Log = null; + } + } + } + disposed = true; + } + + /// + /// + /// + ~Kernel() + { + Dispose(false); + } + + /// + /// Closes and destroys this object + /// + /// + /// Same as Dispose(true) + /// + public void Close() + { + Dispose(); + } + + #endregion + } +} -- cgit v1.1