PageRenderTime 58ms CodeModel.GetById 30ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 1ms

/main/src/addins/TextTemplating/Mono.TextTemplating/Mono.TextTemplating/TemplateGenerator.cs

https://github.com/jfcantin/monodevelop
C# | 373 lines | 279 code | 61 blank | 33 comment | 34 complexity | 78069013fe1ac5ed274e65a71dceba81 MD5 | raw file
  1// 
  2// TemplatingHost.cs
  3//  
  4// Author:
  5//       Michael Hutchinson <mhutchinson@novell.com>
  6// 
  7// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
  8// 
  9// Permission is hereby granted, free of charge, to any person obtaining a copy
 10// of this software and associated documentation files (the "Software"), to deal
 11// in the Software without restriction, including without limitation the rights
 12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 13// copies of the Software, and to permit persons to whom the Software is
 14// furnished to do so, subject to the following conditions:
 15// 
 16// The above copyright notice and this permission notice shall be included in
 17// all copies or substantial portions of the Software.
 18// 
 19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 25// THE SOFTWARE.
 26
 27using System;
 28using System.Collections.Generic;
 29using System.CodeDom.Compiler;
 30using System.IO;
 31using System.Text;
 32using Microsoft.VisualStudio.TextTemplating;
 33
 34namespace Mono.TextTemplating
 35{
 36	public class TemplateGenerator : MarshalByRefObject, ITextTemplatingEngineHost
 37	{
 38		//re-usable
 39		TemplatingEngine engine;
 40		
 41		//per-run variables
 42		string inputFile, outputFile;
 43		Encoding encoding;
 44		
 45		//host fields
 46		CompilerErrorCollection errors = new CompilerErrorCollection ();
 47		List<string> refs = new List<string> ();
 48		List<string> imports = new List<string> ();
 49		List<string> includePaths = new List<string> ();
 50		List<string> referencePaths = new List<string> ();
 51		
 52		//host properties for consumers to access
 53		public CompilerErrorCollection Errors { get { return errors; } }
 54		public List<string> Refs { get { return refs; } }
 55		public List<string> Imports { get { return imports; } }
 56		public List<string> IncludePaths { get { return includePaths; } }
 57		public List<string> ReferencePaths { get { return referencePaths; } }
 58		public string OutputFile { get { return outputFile; } }
 59		
 60		public TemplateGenerator ()
 61		{
 62			Refs.Add (typeof (TextTransformation).Assembly.Location);
 63			Refs.Add (typeof(System.Uri).Assembly.Location);
 64			Imports.Add ("System");
 65		}
 66		
 67		public CompiledTemplate CompileTemplate (string content)
 68		{
 69			if (String.IsNullOrEmpty (content))
 70				throw new ArgumentNullException ("content");
 71
 72			errors.Clear ();
 73			encoding = Encoding.UTF8;
 74			
 75			return Engine.CompileTemplate (content, this);
 76		}
 77		
 78		protected TemplatingEngine Engine {
 79			get {
 80				if (engine == null)
 81					engine = new TemplatingEngine ();
 82				return engine;
 83			}
 84		}
 85		
 86		public bool ProcessTemplate (string inputFile, string outputFile)
 87		{
 88			if (String.IsNullOrEmpty (inputFile))
 89				throw new ArgumentNullException ("inputFile");
 90			if (String.IsNullOrEmpty (outputFile))
 91				throw new ArgumentNullException ("outputFile");
 92			
 93			string content;
 94			try {
 95				content = File.ReadAllText (inputFile);
 96			} catch (IOException ex) {
 97				errors.Clear ();
 98				AddError ("Could not read input file '" + inputFile + "':\n" + ex.ToString ());
 99				return false;
100			}
101			
102			string output;
103			ProcessTemplate (inputFile, content, ref outputFile, out output);
104			
105			try {
106				if (!errors.HasErrors)
107					File.WriteAllText (outputFile, output, encoding);
108			} catch (IOException ex) {
109				AddError ("Could not write output file '" + outputFile + "':\n" + ex.ToString ());
110			}
111			
112			return !errors.HasErrors;
113		}
114		
115		public bool ProcessTemplate (string inputFileName, string inputContent, ref string outputFileName, out string outputContent)
116		{
117			errors.Clear ();
118			encoding = Encoding.UTF8;
119			
120			this.outputFile = outputFileName;
121			this.inputFile = inputFileName;
122			outputContent = Engine.ProcessTemplate (inputContent, this);
123			outputFileName = this.outputFile;
124			
125			return !errors.HasErrors;
126		}
127		
128		public bool PreprocessTemplate (string inputFile, string className, string classNamespace, 
129			string outputFile, System.Text.Encoding encoding, out string language, out string[] references)
130		{
131			language = null;
132			references = null;
133
134			if (string.IsNullOrEmpty (inputFile))
135				throw new ArgumentNullException ("inputFile");
136			if (string.IsNullOrEmpty (outputFile))
137				throw new ArgumentNullException ("outputFile");
138			
139			string content;
140			try {
141				content = File.ReadAllText (inputFile);
142			} catch (IOException ex) {
143				errors.Clear ();
144				AddError ("Could not read input file '" + inputFile + "':\n" + ex.ToString ());
145				return false;
146			}
147			
148			string output;
149			PreprocessTemplate (inputFile, className, classNamespace, content, out language, out references, out output);
150			
151			try {
152				if (!errors.HasErrors)
153					File.WriteAllText (outputFile, output, encoding);
154			} catch (IOException ex) {
155				AddError ("Could not write output file '" + outputFile + "':\n" + ex.ToString ());
156			}
157			
158			return !errors.HasErrors;
159		}
160		
161		public bool PreprocessTemplate (string inputFileName, string className, string classNamespace, string inputContent, 
162			out string language, out string[] references, out string outputContent)
163		{
164			errors.Clear ();
165			encoding = Encoding.UTF8;
166			
167			this.inputFile = inputFileName;
168			outputContent = Engine.PreprocessTemplate (inputContent, this, className, classNamespace, out language, out references);
169			
170			return !errors.HasErrors;
171		}
172		
173		CompilerError AddError (string error)
174		{
175			CompilerError err = new CompilerError ();
176			err.ErrorText = error;
177			Errors.Add (err);
178			return err;
179		}
180		
181		#region Virtual members
182		
183		public virtual object GetHostOption (string optionName)
184		{
185			return null;
186		}
187		
188		public virtual AppDomain ProvideTemplatingAppDomain (string content)
189		{
190			return null;
191		}
192		
193		//FIXME: implement
194		protected virtual string ResolveAssemblyReference (string assemblyReference)
195		{
196			//foreach (string referencePath in ReferencePaths) {
197			//	
198			//}
199			return assemblyReference;
200		}
201		
202		protected virtual string ResolveParameterValue (string directiveId, string processorName, string parameterName)
203		{
204			var key = new ParameterKey (processorName, directiveId, parameterName);
205			string value;
206			if (parameters.TryGetValue (key, out value))
207				return value;
208			if (processorName != null || directiveId != null)
209				return ResolveParameterValue (null, null, parameterName);
210			return null;
211		}
212		
213		protected virtual Type ResolveDirectiveProcessor (string processorName)
214		{
215			KeyValuePair<string,string> value;
216			if (!directiveProcessors.TryGetValue (processorName, out value))
217				throw new Exception (string.Format ("No directive processor registered as '{0}'", processorName));
218			var asmPath = ResolveAssemblyReference (value.Value);
219			if (asmPath == null)
220				throw new Exception (string.Format ("Could not resolve assembly '{0}' for directive processor '{1}'", value.Value, processorName));
221			var asm = System.Reflection.Assembly.LoadFrom (asmPath);
222			return asm.GetType (value.Key, true);
223		}
224		
225		protected virtual string ResolvePath (string path)
226		{
227			path = System.Environment.ExpandEnvironmentVariables (path);
228			if (Path.IsPathRooted (path))
229				return path;
230			var dir = Path.GetDirectoryName (inputFile);
231			var test = Path.Combine (dir, path);
232			if (File.Exists (test))
233				return test;
234			return null;
235		}
236		
237		#endregion
238		
239		Dictionary<ParameterKey,string> parameters = new Dictionary<ParameterKey, string> ();
240		Dictionary<string,KeyValuePair<string,string>> directiveProcessors = new Dictionary<string, KeyValuePair<string,string>> ();
241		
242		public void AddDirectiveProcessor (string name, string klass, string assembly)
243		{
244			directiveProcessors.Add (name, new KeyValuePair<string,string> (klass,assembly));
245		}
246		
247		public void AddParameter (string processorName, string directiveName, string parameterName, string value)
248		{
249			parameters.Add (new ParameterKey (processorName, directiveName, parameterName), value);
250		}
251		
252		protected virtual bool LoadIncludeText (string requestFileName, out string content, out string location)
253		{
254			content = "";
255			location = ResolvePath (requestFileName);
256			
257			if (location == null) {
258				foreach (string path in includePaths) {
259					string f = Path.Combine (path, requestFileName);
260					if (File.Exists (f)) {
261						location = f;
262						break;
263					}
264				}
265			}
266			
267			if (location == null)
268				return false;
269			
270			try {
271				content = File.ReadAllText (location);
272				return true;
273			} catch (IOException ex) {
274				AddError ("Could not read included file '" + location +  "':\n" + ex.ToString ());
275			}
276			return false;
277		}
278		
279		#region Explicit ITextTemplatingEngineHost implementation
280		
281		bool ITextTemplatingEngineHost.LoadIncludeText (string requestFileName, out string content, out string location)
282		{
283			return LoadIncludeText (requestFileName, out content, out location);
284		}
285		
286		void ITextTemplatingEngineHost.LogErrors (CompilerErrorCollection errors)
287		{
288			this.errors.AddRange (errors);
289		}
290		
291		string ITextTemplatingEngineHost.ResolveAssemblyReference (string assemblyReference)
292		{
293			return ResolveAssemblyReference (assemblyReference);
294		}
295		
296		string ITextTemplatingEngineHost.ResolveParameterValue (string directiveId, string processorName, string parameterName)
297		{
298			return ResolveParameterValue (directiveId, processorName, parameterName);
299		}
300		
301		Type ITextTemplatingEngineHost.ResolveDirectiveProcessor (string processorName)
302		{
303			return ResolveDirectiveProcessor (processorName);
304		}
305		
306		string ITextTemplatingEngineHost.ResolvePath (string path)
307		{
308			return ResolvePath (path);
309		}
310		
311		void ITextTemplatingEngineHost.SetFileExtension (string extension)
312		{
313			extension = extension.TrimStart ('.');
314			if (Path.HasExtension (outputFile)) {
315				outputFile = Path.ChangeExtension (outputFile, extension);
316			} else {
317				outputFile = outputFile + "." + extension;
318			}
319		}
320		
321		void ITextTemplatingEngineHost.SetOutputEncoding (System.Text.Encoding encoding, bool fromOutputDirective)
322		{
323			this.encoding = encoding;
324		}
325		
326		IList<string> ITextTemplatingEngineHost.StandardAssemblyReferences {
327			get { return refs; }
328		}
329		
330		IList<string> ITextTemplatingEngineHost.StandardImports {
331			get { return imports; }
332		}
333		
334		string ITextTemplatingEngineHost.TemplateFile {
335			get { return inputFile; }
336		}
337		
338		#endregion
339		
340		struct ParameterKey : IEquatable<ParameterKey>
341		{
342			public ParameterKey (string processorName, string directiveName, string parameterName)
343			{
344				this.processorName = processorName ?? "";
345				this.directiveName = directiveName ?? "";
346				this.parameterName = parameterName ?? "";
347				unchecked {
348					hashCode = this.processorName.GetHashCode ()
349						^ this.directiveName.GetHashCode ()
350						^ this.parameterName.GetHashCode ();
351				}
352			}
353			
354			string processorName, directiveName, parameterName;
355			int hashCode;
356			
357			public override bool Equals (object obj)
358			{
359				return obj != null && obj is ParameterKey && Equals ((ParameterKey)obj);
360			}
361			
362			public bool Equals (ParameterKey other)
363			{
364				return processorName == other.processorName && directiveName == other.directiveName && parameterName == other.parameterName;
365			}
366			
367			public override int GetHashCode ()
368			{
369				return hashCode;
370			}
371		}
372	}
373}