fork(2) download
  1. <#
  2. /*
  3. imaginarydevelopment.blogspot.com
  4. use envDte to retrieve class info, create an interface for that class
  5.   ?consider updating class to implement the interface?
  6.   ?and mapper for that interface?
  7. */
  8. #>
  9. <#@ template language="C#" debug="true" hostspecific="true" #>
  10. <#@ assembly name="System.Core" #>
  11. <#@ assembly name="System.Xml" #>
  12. <#@ assembly name="Microsoft.CSharp" #>
  13. <#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
  14. <#@ assembly name="EnvDTE" #>
  15. <#@ assembly name="EnvDTE80" #>
  16. <#@ assembly name="VSLangProj" #>
  17. <#@ import namespace="System.Collections.Generic" #>
  18. <#@ import namespace="System.IO" #>
  19. <#@ import namespace="System.Linq" #>
  20. <#@ import namespace="System.Text" #>
  21. <#@ import namespace="System.Text.RegularExpressions" #>
  22. <#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
  23. <#@ import namespace="EnvDTE" #>
  24. <#@ import namespace="EnvDTE80" #>
  25. <#@ import namespace="Microsoft.VisualStudio.TextTemplating"#>
  26. <# // To debug, uncomment the next two lines !!
  27. // System.Diagnostics.Debugger.Launch();
  28. // System.Diagnostics.Debugger.Break();
  29. #>
  30. <#PrepareDataToRender(this); #>
  31. <#var manager = Manager.Create(Host, GenerationEnvironment); #>
  32. <#manager.StartHeader(); #>// <auto-generated />
  33. // This file was generated by a T4 template.
  34. // Don't change it directly as your change would get overwritten. Instead, make changes
  35. // to the .tt file (i.e. the T4 template) and save it to regenerate this file.
  36.  
  37. // Make sure the compiler doesn't complain about missing Xml comments
  38. #pragma warning disable 1591
  39. using System;
  40. <# manager.EndBlock();#>
  41. <#
  42.  
  43.  
  44. var rootNamespace = Project.Properties.Item("RootNamespace").Value.ToString();
  45. #>
  46. //Project:<#=Project.Name#>
  47. //rootNamespace=<#= rootNamespace #>
  48. <# RecurseProjectItems(manager,Project.ProjectItems);
  49.  
  50. if(string.IsNullOrEmpty(CurrentNamespaceGenerating)==false)
  51. WriteLine("} //end namespace2");
  52.  
  53.  
  54. #>
  55.  
  56. <#manager.Process(SplitIntoMultipleFiles);#>
  57. <#@ Include File="DTOGenerator.tt.settings.t4" #>
  58. <#+
  59. string CurrentNamespaceGenerating=null;
  60. void RecurseProjectItems(Manager manager,ProjectItems container)
  61. {
  62. foreach(var item in container.Cast<ProjectItem>())
  63. {
  64. if(item.FileCodeModel==null)
  65. {
  66. if(IncludeDiagnostics)WriteLine("//opening container:"+item.Name);
  67. RecurseProjectItems(manager,item.ProjectItems);
  68. continue;
  69. }
  70. DateTime lastWriteTime=File.GetLastWriteTime(item.get_FileNames(0));
  71.  
  72. if(IncludeDiagnostics)WriteLine("//Found CodeModel:"+item.FileCodeModel.GetType().FullName);
  73. var interfaces=RecurseForInterfaces(manager,item.FileCodeModel.CodeElements,string.Empty);
  74. foreach(var i in interfaces)
  75. {
  76. if(IncludeDiagnostics)
  77. WriteLine("//Found Interface:"+i.Item1.Name);
  78. var properties=RecurseForProperties(i.Item1);
  79. if(properties.Count()>0)
  80. WriteInterface(manager,i.Item1,properties,i.Item2);
  81. }
  82. //RecurseFindElements(manager,item.FileCodeModel.CodeElements,string.Empty);
  83.  
  84.  
  85. }
  86. }
  87.  
  88.  
  89. IEnumerable<Action> RecurseForProperties(CodeInterface2 codeInterface)
  90. {
  91. if(codeInterface.Bases !=null)
  92. foreach(var baseInterface in codeInterface.Bases.Cast<CodeElement>())
  93. {
  94. if(IncludeDiagnostics) WriteLine("//found base:"+baseInterface.Name);
  95. foreach(var item in RecurseForProperties(((CodeInterface2)baseInterface)))
  96. yield return item;
  97. }
  98. foreach( CodeProperty item in codeInterface.Members.OfType<CodeProperty>())
  99. {
  100. yield return ()=> WriteMapping(item);
  101. }
  102. }
  103.  
  104. IEnumerable<Tuple<CodeInterface2,string>> RecurseForInterfaces(Manager manager, CodeElements codeElements,string currentNamespace )
  105. {
  106.  
  107. var q=codeElements.Cast<CodeElement>( )
  108. //.Where(x =>x is CodeInterface||x is CodeClass || x is CodeNamespace) //&& ((CodeInterface)x).Attributes.Count>0)
  109. //.Where(x => x.Name.StartsWith("System")==false)
  110. //.Where(x => x.Name.StartsWith("Infragistics")==false)
  111. //.Where(x => x.Name.StartsWith("Microsoft")==false)
  112. //.Where(x => x.Name.StartsWith("ICSharpCode")==false)
  113. ;
  114. var interfaces=new List<string>();
  115.  
  116. foreach (CodeElement element in q)
  117. {
  118.  
  119. if (element is CodeInterface && interfaces.Contains(element.Name)==false)
  120. {
  121. var c = (CodeInterface2)element;
  122. //verify element is a project element not an external
  123. if (c.InfoLocation!=vsCMInfoLocation.vsCMInfoLocationProject)
  124. continue;
  125. yield return Tuple.Create<CodeInterface2,string>(c,currentNamespace);
  126.  
  127. }
  128.  
  129. if (element is CodeNamespace)
  130. {
  131. var ns=(CodeNamespace)element;
  132. if(SkippedNamespaces.Contains( ns.Name)==false)
  133. foreach(var find in RecurseForInterfaces(manager,ns.Members,ns.Name))
  134. yield return find;
  135. }
  136. }
  137.  
  138.  
  139. }
  140.  
  141. void WriteMapping(CodeProperty codeProperty)
  142. {
  143. WriteLine("");
  144. WriteLine("///CodeProperty");
  145. WriteLine("///<summary>");
  146. WriteLine("///"+codeProperty.FullName);
  147. WriteLine("///</summary>");
  148. if(codeProperty.Getter==null && codeProperty.Setter==null)
  149. return;
  150. if(codeProperty.Attributes!=null){
  151. foreach(CodeAttribute a in codeProperty.Attributes)
  152. {
  153. Write("["+a.FullName);
  154. if(a.Children!=null && a.Children.Count>0)
  155. {
  156. var start=a.Children.Cast<CodeElement>().First().GetStartPoint();
  157. var finish= a.GetEndPoint();
  158. string wholeAttributeLine=start.CreateEditPoint().GetText(finish);
  159.  
  160. Write("("+wholeAttributeLine);
  161. }
  162. WriteLine("]");
  163. }
  164. }
  165. Write("public "+GetFullName(codeProperty.Type) +" "+codeProperty.Prototype);
  166.  
  167. Write(" {");
  168. //if(codeProperty.Getter!=null && codeProperty.Getter.Access!=vsCMAccess.vsCMAccessPrivate)
  169. Write("get;");
  170. //if(codeProperty.Setter!=null)
  171. Write("set;");
  172. WriteLine("}");
  173.  
  174. //WriteLine("public static string MetaBinding"+MakeIntoValidIdentifier(codeProperty.Name)+"{ get{ return \""
  175. //+codeProperty.Parent.Name+"."+codeProperty.Name+"\";}}");
  176. }
  177. string GetFullName(CodeTypeRef codeType)
  178. {
  179. string fullName;
  180.  
  181. if (codeType.TypeKind == vsCMTypeRef.vsCMTypeRefArray)
  182. {
  183. CodeTypeRef arrayType = codeType.ElementType;
  184. fullName = arrayType.AsFullName + "[]";
  185. }
  186. else
  187. {
  188. fullName = codeType.AsFullName;
  189. }
  190. return fullName;
  191. }
  192. void WriteInterface(Manager manager,CodeInterface2 codeInterface, IEnumerable<Action> writeProperties,string parentNamespace)
  193. {
  194.  
  195. if(IncludeDiagnostics)WriteLine("//CodeInterface parentNamespace:"+parentNamespace);
  196. var xmlBlock="\t//CodeInterface";
  197.  
  198. var start=codeInterface.GetStartPoint();
  199.  
  200. var finish=codeInterface.Children!=null && codeInterface.Children.Count>0? codeInterface.Children.Cast<CodeElement>().First().GetStartPoint() : codeInterface.GetEndPoint();//.GetEndPoint();
  201. string wholeInterfaceLine=start.CreateEditPoint().GetText(finish);
  202. var classLine=wholeInterfaceLine.ToString();
  203. var justProto=wholeInterfaceLine.Contains("{")?classLine.Substring(0,classLine.IndexOf("{")):classLine;
  204.  
  205. if(IncludeDiagnostics && justProto.Length<100 && justProto.Contains("*/")==false ){WriteLine("/* justProto: "+justProto); WriteLine(" */");}
  206.  
  207. manager.EndBlock();
  208.  
  209. var fullName=codeInterface.FullName;
  210. var name=fullName.Contains(".")?fullName.Substring(fullName.LastIndexOf('.')+1):fullName;
  211. if(name.StartsWith("I")) name=name.Substring(1);
  212. name=name+"DTO";
  213. manager.StartNewFile(name+".generated.cs");
  214. if(IncludeDiagnostics) WriteLine("//fullName:"+fullName);
  215. if(IncludeDiagnostics)WriteLine("//name:"+name);
  216. var targetNamespace=GetTargetNamespace(codeInterface.Namespace.Name);
  217. if(codeInterface!=null && codeInterface.Namespace!=null && (targetNamespace != CurrentNamespaceGenerating|| SplitIntoMultipleFiles)){
  218.  
  219. if(string.IsNullOrEmpty(CurrentNamespaceGenerating)==false && SplitIntoMultipleFiles==false)
  220. WriteLine("} //namespace end1");
  221. CurrentNamespaceGenerating=GetTargetNamespace(codeInterface.Namespace.Name);
  222.  
  223. if(IncludeDiagnostics)WriteLine("//end namespace:"+CurrentNamespaceGenerating+":begin:"+codeInterface.Namespace.Name);
  224. #>
  225.  
  226. namespace <#=codeInterface.Namespace.Name#> {<#+} #>
  227.  
  228. ///<seealso cref="<#=codeInterface.FullName#>"/>
  229. public class <#=name#>:<#=codeInterface.Name #>{
  230. <#+
  231. PushIndent("\t");
  232. PushIndent("\t");
  233. foreach(var item in writeProperties)
  234. item();
  235. PopIndent();
  236. PopIndent();
  237. if(SplitIntoMultipleFiles)
  238. WriteLine("}");
  239. #>
  240. } //end class <#=name #>
  241.  
  242. <#+
  243.  
  244. }
  245. string ConvertFullName(CodeModel cm, string fullName)
  246. {
  247. // Convert a .NET type name into a C++ type name.
  248. if ((cm.Language == CodeModelLanguageConstants.vsCMLanguageVC) ||
  249. (cm.Language == CodeModelLanguageConstants.vsCMLanguageMC))
  250. return fullName.Replace(".", "::");
  251. else
  252. return fullName;
  253. }
  254. #>
  255. <#+
  256.  
  257. static DTE Dte;
  258. static Project Project;
  259.  
  260. static TextTransformation TT;
  261. static string T4FileName;
  262. static string T4Folder;
  263. static string AppRoot;
  264. static string GeneratedCode = @"GeneratedCode(""InterfaceT4"", ""2.0"")";
  265. static Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
  266.  
  267. void PrepareDataToRender(TextTransformation tt) {
  268. TT = tt;
  269. T4FileName = Path.GetFileName(Host.TemplateFile);
  270. T4Folder = Path.GetDirectoryName(Host.TemplateFile);
  271.  
  272. // Get the DTE service from the host
  273. var serviceProvider = Host as IServiceProvider;
  274. if (serviceProvider != null) {
  275. Dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
  276. }
  277.  
  278. // Fail if we couldn't get the DTE. This can happen when trying to run in TextTransform.exe
  279. if (Dte == null) {
  280. throw new Exception("InterfaceT4 can only execute through the Visual Studio host");
  281. }
  282.  
  283. Project = GetProjectContainingT4File(Dte);
  284.  
  285. if (Project == null) {
  286. Error("Could not find the VS Project containing the T4 file.");
  287. return;
  288. }
  289.  
  290. // Get the path of the root folder of the app
  291. AppRoot = Path.GetDirectoryName(Project.FullName) + '\\';
  292.  
  293. }
  294.  
  295. Project GetProjectContainingT4File(DTE dte) {
  296.  
  297. // Find the .tt file's ProjectItem
  298. ProjectItem projectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
  299.  
  300. // If the .tt file is not opened, open it
  301. if (projectItem.Document == null)
  302. projectItem.Open(Constants.vsViewKindCode);
  303.  
  304. if (AlwaysKeepTemplateDirty) {
  305. // Mark the .tt file as unsaved. This way it will be saved and update itself next time the
  306. // project is built. Basically, it keeps marking itself as unsaved to make the next build work.
  307. // Note: this is certainly hacky, but is the best I could come up with so far.
  308. projectItem.Document.Saved = false;
  309. }
  310.  
  311. return projectItem.ContainingProject;
  312. }
  313.  
  314.  
  315. #region Manager
  316. /*
  317.   Manager.tt from Damien Guard: http://d...content-available-to-author-only...g.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited
  318. */
  319.  
  320.  
  321. // Manager class records the various blocks so it can split them up
  322. class Manager {
  323. private class Block {
  324. public String Name;
  325. public int Start, Length;
  326. }
  327.  
  328. private Block currentBlock;
  329. private List<Block> files = new List<Block>();
  330. private Block footer = new Block();
  331. private Block header = new Block();
  332. private ITextTemplatingEngineHost host;
  333. private StringBuilder template;
  334. protected List<String> generatedFileNames = new List<String>();
  335.  
  336. public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
  337. return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
  338. }
  339.  
  340. public void KeepGeneratedFile(String name) {
  341. name = Path.Combine(Path.GetDirectoryName(host.TemplateFile), name);
  342. generatedFileNames.Add(name);
  343. }
  344.  
  345. public void StartNewFile(String name) {
  346. if (name == null)
  347. throw new ArgumentNullException("name");
  348. CurrentBlock = new Block { Name = name };
  349. }
  350.  
  351. public void StartFooter() {
  352. CurrentBlock = footer;
  353. }
  354.  
  355. public void StartHeader() {
  356. CurrentBlock = header;
  357. }
  358.  
  359. public void EndBlock() {
  360. if (CurrentBlock == null)
  361. return;
  362. CurrentBlock.Length = template.Length - CurrentBlock.Start;
  363. if (CurrentBlock != header && CurrentBlock != footer)
  364. files.Add(CurrentBlock);
  365. currentBlock = null;
  366. }
  367.  
  368. public virtual void Process(bool split) {
  369. if (split) {
  370. EndBlock();
  371. String headerText = template.ToString(header.Start, header.Length);
  372. String footerText = template.ToString(footer.Start, footer.Length);
  373. String outputPath = Path.GetDirectoryName(host.TemplateFile);
  374. files.Reverse();
  375. foreach (Block block in files) {
  376. String fileName = Path.Combine(outputPath, block.Name);
  377. String content = headerText + template.ToString(block.Start, block.Length) + footerText;
  378. generatedFileNames.Add(fileName);
  379. CreateFile(fileName, content);
  380. template.Remove(block.Start, block.Length);
  381. }
  382. }
  383. }
  384.  
  385. protected virtual void CreateFile(String fileName, String content) {
  386. if (IsFileContentDifferent(fileName, content))
  387. File.WriteAllText(fileName, content);
  388. }
  389.  
  390. public virtual String GetCustomToolNamespace(String fileName) {
  391. return null;
  392. }
  393.  
  394. public virtual String DefaultProjectNamespace {
  395. get { return null; }
  396. }
  397.  
  398. protected bool IsFileContentDifferent(String fileName, String newContent) {
  399. return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
  400. }
  401.  
  402. private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
  403. this.host = host;
  404. this.template = template;
  405. }
  406.  
  407. private Block CurrentBlock {
  408. get { return currentBlock; }
  409. set {
  410. if (CurrentBlock != null)
  411. EndBlock();
  412. if (value != null)
  413. value.Start = template.Length;
  414. currentBlock = value;
  415. }
  416. }
  417.  
  418. private class VSManager : Manager {
  419. private EnvDTE.ProjectItem templateProjectItem;
  420. private EnvDTE.DTE dte;
  421. private Action<String> checkOutAction;
  422. private Action<IEnumerable<String>> projectSyncAction;
  423.  
  424. public override String DefaultProjectNamespace {
  425. get {
  426. return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
  427. }
  428. }
  429.  
  430. public override String GetCustomToolNamespace(string fileName) {
  431. return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
  432. }
  433.  
  434. public override void Process(bool split) {
  435. if (templateProjectItem.ProjectItems == null)
  436. return;
  437. base.Process(split);
  438. projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
  439. }
  440.  
  441. protected override void CreateFile(String fileName, String content) {
  442. if (IsFileContentDifferent(fileName, content)) {
  443. CheckoutFileIfRequired(fileName);
  444. File.WriteAllText(fileName, content);
  445. }
  446. }
  447.  
  448. internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)
  449. : base(host, template) {
  450. var hostServiceProvider = (IServiceProvider)host;
  451. if (hostServiceProvider == null)
  452. throw new ArgumentNullException("Could not obtain IServiceProvider");
  453. dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
  454. if (dte == null)
  455. throw new ArgumentNullException("Could not obtain DTE from host");
  456. templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
  457. checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName);
  458. projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames);
  459. }
  460.  
  461. private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) {
  462. var keepFileNameSet = new HashSet<String>(keepFileNames);
  463. var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
  464. var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + ".";
  465. foreach (EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
  466. projectFiles.Add(projectItem.get_FileNames(0), projectItem);
  467.  
  468. // Remove unused items from the project
  469. foreach (var pair in projectFiles)
  470. if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
  471. pair.Value.Delete();
  472.  
  473. // Add missing files to the project
  474. foreach (String fileName in keepFileNameSet)
  475. if (!projectFiles.ContainsKey(fileName))
  476. templateProjectItem.ProjectItems.AddFromFile(fileName);
  477. }
  478.  
  479. private void CheckoutFileIfRequired(String fileName) {
  480. var sc = dte.SourceControl;
  481. if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
  482. checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));
  483. }
  484. }
  485. }
  486.  
  487. /*
  488.   End of Manager.tt
  489. */
  490. #endregion
  491. #>
Not running #stdin #stdout 0s 0KB
stdin
<#+
/*

This file contains settings used by DTOGenerator.tt The main goal is to avoid the need for users
to fork the 'official' template in order to achieve what they want.

*/

IEnumerable<string> SkippedNamespaces=new[]{"Shared.CrossCutting","Shared.Behaviors"};

/// <remarks>Must be static so that GetTargetNamespace can reference it</remarks>
static bool IncludeDiagnostics=false;

Func<string,string> GetTargetNamespace=sourceNamespace=> {
	if(string.IsNullOrEmpty(sourceNamespace))
	{
		if(IncludeDiagnostics)
			System.Diagnostics.Debug.WriteLine("No Sourcenamespace found");
		return sourceNamespace;
	}
	if(sourceNamespace.Contains(".")==false){
		if(IncludeDiagnostics)
			System.Diagnostics.Debug.WriteLine("Sourcenamespace found");
		return sourceNamespace+".DTO";}
	return sourceNamespace.Substring(0,sourceNamespace.LastIndexOf('.'))+"DTO";
};
bool SplitIntoMultipleFiles = false;
bool AlwaysKeepTemplateDirty = false;

void RenderAdditionalCode() {
}
#>
stdout
Standard output is empty