MultipleOutputHelper.ttinclude 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <#@ assembly name="System.Core"
  2. #><#@ assembly name="System.Data.Linq"
  3. #><#@ assembly name="EnvDTE"
  4. #><#@ assembly name="System.Xml"
  5. #><#@ assembly name="System.Xml.Linq"
  6. #><#@ import namespace="System"
  7. #><#@ import namespace="System.CodeDom"
  8. #><#@ import namespace="System.CodeDom.Compiler"
  9. #><#@ import namespace="System.Collections.Generic"
  10. #><#@ import namespace="System.Data.Linq"
  11. #><#@ import namespace="System.Data.Linq.Mapping"
  12. #><#@ import namespace="System.IO"
  13. #><#@ import namespace="System.Linq"
  14. #><#@ import namespace="System.Reflection"
  15. #><#@ import namespace="System.Text"
  16. #><#@ import namespace="System.Xml.Linq"
  17. #><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
  18. #><#+
  19. // Manager class records the various blocks so it can split them up
  20. class Manager {
  21. private class Block {
  22. public String Name;
  23. public int Start, Length;
  24. public bool IncludeInDefault;
  25. }
  26. private Block currentBlock;
  27. private List<Block> files = new List<Block>();
  28. private Block footer = new Block();
  29. private Block header = new Block();
  30. private ITextTemplatingEngineHost host;
  31. private StringBuilder template;
  32. protected List<String> generatedFileNames = new List<String>();
  33. public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
  34. return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
  35. }
  36. public void StartNewFile(String name) {
  37. if (name == null)
  38. throw new ArgumentNullException("name");
  39. CurrentBlock = new Block { Name = name };
  40. }
  41. public void StartFooter(bool includeInDefault = true) {
  42. CurrentBlock = footer;
  43. footer.IncludeInDefault = includeInDefault;
  44. }
  45. public void StartHeader(bool includeInDefault = true) {
  46. CurrentBlock = header;
  47. header.IncludeInDefault = includeInDefault;
  48. }
  49. public void EndBlock() {
  50. if (CurrentBlock == null)
  51. return;
  52. CurrentBlock.Length = template.Length - CurrentBlock.Start;
  53. if (CurrentBlock != header && CurrentBlock != footer)
  54. files.Add(CurrentBlock);
  55. currentBlock = null;
  56. }
  57. public virtual void Process(bool split, bool sync = true) {
  58. if (split) {
  59. EndBlock();
  60. String headerText = template.ToString(header.Start, header.Length);
  61. String footerText = template.ToString(footer.Start, footer.Length);
  62. String outputPath = Path.GetDirectoryName(host.TemplateFile);
  63. files.Reverse();
  64. if (!footer.IncludeInDefault)
  65. template.Remove(footer.Start, footer.Length);
  66. foreach(Block block in files) {
  67. String fileName = Path.Combine(outputPath, block.Name);
  68. String content = headerText + template.ToString(block.Start, block.Length) + footerText;
  69. generatedFileNames.Add(fileName);
  70. CreateFile(fileName, content);
  71. template.Remove(block.Start, block.Length);
  72. }
  73. if (!header.IncludeInDefault)
  74. template.Remove(header.Start, header.Length);
  75. }
  76. }
  77. protected virtual void CreateFile(String fileName, String content) {
  78. if (IsFileContentDifferent(fileName, content))
  79. File.WriteAllText(fileName, content);
  80. }
  81. public virtual String GetCustomToolNamespace(String fileName) {
  82. return null;
  83. }
  84. public virtual String DefaultProjectNamespace {
  85. get { return null; }
  86. }
  87. protected bool IsFileContentDifferent(String fileName, String newContent) {
  88. return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
  89. }
  90. private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
  91. this.host = host;
  92. this.template = template;
  93. }
  94. private Block CurrentBlock {
  95. get { return currentBlock; }
  96. set {
  97. if (CurrentBlock != null)
  98. EndBlock();
  99. if (value != null)
  100. value.Start = template.Length;
  101. currentBlock = value;
  102. }
  103. }
  104. private class VSManager: Manager {
  105. private EnvDTE.ProjectItem templateProjectItem;
  106. private EnvDTE.DTE dte;
  107. private Action<String> checkOutAction;
  108. private Action<IEnumerable<String>> projectSyncAction;
  109. public override String DefaultProjectNamespace {
  110. get {
  111. return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
  112. }
  113. }
  114. public override String GetCustomToolNamespace(string fileName) {
  115. return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
  116. }
  117. public override void Process(bool split, bool sync) {
  118. if (templateProjectItem.ProjectItems == null)
  119. return;
  120. base.Process(split, sync);
  121. if (sync)
  122. projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
  123. }
  124. protected override void CreateFile(String fileName, String content) {
  125. if (IsFileContentDifferent(fileName, content)) {
  126. CheckoutFileIfRequired(fileName);
  127. File.WriteAllText(fileName, content);
  128. }
  129. }
  130. internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)
  131. : base(host, template) {
  132. var hostServiceProvider = (IServiceProvider) host;
  133. if (hostServiceProvider == null)
  134. throw new ArgumentNullException("Could not obtain IServiceProvider");
  135. dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE));
  136. if (dte == null)
  137. throw new ArgumentNullException("Could not obtain DTE from host");
  138. templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
  139. checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName);
  140. projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames);
  141. }
  142. private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) {
  143. var keepFileNameSet = new HashSet<String>(keepFileNames);
  144. var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
  145. var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + ".";
  146. foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
  147. projectFiles.Add(projectItem.get_FileNames(0), projectItem);
  148. // Remove unused items from the project
  149. foreach(var pair in projectFiles)
  150. if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
  151. pair.Value.Delete();
  152. // Add missing files to the project
  153. foreach(String fileName in keepFileNameSet)
  154. if (!projectFiles.ContainsKey(fileName))
  155. templateProjectItem.ProjectItems.AddFromFile(fileName);
  156. }
  157. private void CheckoutFileIfRequired(String fileName) {
  158. var sc = dte.SourceControl;
  159. if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
  160. checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));
  161. }
  162. }
  163. } #>