/buildtools/CustomTasks/FxCop.cs
C# | 226 lines | 165 code | 39 blank | 22 comment | 8 complexity | f09313dbce098be8ac712b819d7ab0f0 MD5 | raw file
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6using Microsoft.Build.Utilities;
7using System.IO;
8using System.Xml;
9using System.Reflection;
10
11namespace CustomTasks
12{
13 public class UpdateFxCopProject : Task
14 {
15 public string Assemblies { get; set; }
16 public string FxCopProject { get; set; }
17 public string BinSuffix { get; set; }
18
19 public override bool Execute()
20 {
21 if (string.IsNullOrEmpty(Assemblies))
22 throw new ArgumentNullException("Assemblies");
23 if (string.IsNullOrEmpty(FxCopProject))
24 throw new ArgumentNullException("FxCopProject");
25 if (string.IsNullOrEmpty(BinSuffix))
26 throw new ArgumentNullException("BinSuffix");
27
28 Assemblies = Path.GetFullPath(Assemblies);
29 Log.LogMessage("Assemblies = " + Assemblies);
30
31 FxCopProject = Path.GetFullPath(FxCopProject);
32 Log.LogMessage("FxCopProject = " + FxCopProject);
33
34 Log.LogMessage("Updating project...");
35 FxCop.UpdateFxCopProject(Assemblies, FxCopProject, BinSuffix);
36 Log.LogMessage("Project updated");
37
38 return true;
39 }
40 }
41
42 public static class FxCop
43 {
44 public static void UpdateFxCopProject(string assembliesFolder, string fxCopProjectPath, string binSuffix)
45 {
46 var allAssemblies = Directory.GetFiles(assembliesFolder, "*.dll").ToList();
47
48 // move core assembly to the end of the list
49 var coreAssembly = allAssemblies.Single(a => a.IndexOf(CoreAssemblyName, StringComparison.OrdinalIgnoreCase) >= 0);
50 allAssemblies.Remove(coreAssembly);
51 allAssemblies.Add(coreAssembly);
52
53 var doc = new XmlDocument();
54 doc.Load(fxCopProjectPath);
55
56 var referenceDirectoriesNode = doc.SelectSingleNode(AssemblyReferenceDirectoriesXpath);
57
58 var targetsNode = doc.SelectSingleNode(TargetsXpath);
59 RemoveAllNodes(doc, targetsNode, TargetXpath);
60 ResetReferenceDirectories(doc, referenceDirectoriesNode, DirectoriesXpath);
61
62 foreach (var assembly in allAssemblies)
63 {
64 var assemblyName = Path.GetFileName(assembly).ToLower();
65 var assemblyFolderName = assemblyName.Split('.')[1];
66 var isCore = string.Equals(CoreAssemblyName, assemblyName, StringComparison.OrdinalIgnoreCase);
67
68 var newTarget = AddChildNode(targetsNode, "Target");
69 AddAttribute(newTarget, "Name", MakeRelativePath(assembly));
70 AddAttribute(newTarget, "Analyze", "True");
71
72 var dirNode = AddChildNode(referenceDirectoriesNode, "Directory");
73 if (isCore)
74 {
75 AddCoreAssembly(coreAssembly, newTarget);
76
77 // Add assembly reference directory for Core
78 // <Directory>$(ProjectDir)/src/Core/bin/Release/net35/</Directory>
79 dirNode.InnerText = string.Format("$(ProjectDir)/src/Core/bin/Release/{0}/", binSuffix);
80
81 }
82 else
83 {
84 /*
85 <Target Name="$(ProjectDir)/Deployment/assemblies/net35/AWSSDK.AutoScaling.dll" Analyze="True" AnalyzeAllChildren="True" />
86 */
87 AddAttribute(newTarget, "AnalyzeAllChildren", "True");
88
89 // Add assembly reference directory for each service
90 // <Directory>$(ProjectDir)/src/Services/MobileAnalytics/bin/Release/net35/</Directory>
91 dirNode.InnerText = string.Format("$(ProjectDir)/src/Services/{0}/bin/Release/{1}/",
92 assemblyFolderName, binSuffix);
93 }
94 }
95 doc.Save(fxCopProjectPath);
96 }
97
98 private static void AddCoreAssembly(string coreAssemblyPath, XmlNode newTarget)
99 {
100 AddAttribute(newTarget, "AnalyzeAllChildren", "False");
101
102 var assemblyName = Path.GetFileName(coreAssemblyPath).ToLower();
103 var coreAssembly = Assembly.LoadFrom(coreAssemblyPath);
104 /*
105 <Target Name="$(ProjectDir)/Deployment/assemblies/net35/AWSSDK.Core.dll" Analyze="True" AnalyzeAllChildren="False">
106 <Modules AnalyzeAllChildren="False">
107 <Module Name="awssdk.core.dll" Analyze="True" AnalyzeAllChildren="False">
108 <Namespaces AnalyzeAllChildren="False">
109 <Namespace Name="" Analyze="True" AnalyzeAllChildren="True" />
110 */
111
112 var modulesNode = AddChildNode(newTarget, "Modules");
113 AddAttribute(modulesNode, "AnalyzeAllChildren", "False");
114
115 var moduleNode = AddChildNode(modulesNode, "Module");
116 AddAttribute(moduleNode, "Name", assemblyName);
117 AddAttribute(moduleNode, "Analyze", "True");
118 AddAttribute(moduleNode, "AnalyzeAllChildren", "False");
119
120 var namespacesNode = AddChildNode(moduleNode, "Namespaces");
121 AddAttribute(namespacesNode, "AnalyzeAllChildren", "False");
122
123 var namespaces = GetNamespacesToExamine(coreAssembly);
124 foreach (var ns in namespaces.OrderBy(k => k, StringComparer.Ordinal))
125 {
126 var namespaceNode = AddChildNode(namespacesNode, "Namespace");
127 AddAttribute(namespaceNode, "Name", ns);
128 AddAttribute(namespaceNode, "Analyze", "True");
129 AddAttribute(namespaceNode, "AnalyzeAllChildren", "True");
130 }
131 var resourcesNode = AddChildNode(moduleNode, "Resources");
132 AddAttribute(resourcesNode, "AnalyzeAllChildren", "True");
133 }
134
135
136 public static HashSet<string> NamespacePrefixesToSkip = new HashSet<string>(StringComparer.Ordinal)
137 {
138 "ThirdParty.BouncyCastle",
139 "ThirdParty.Ionic.Zlib",
140 "ThirdParty.Json",
141 };
142 public const string NamespacesXpath = "FxCopProject/Targets/Target/Modules/Module/Namespaces";
143 public const string TargetsXpath = "FxCopProject/Targets";
144 public const string AssemblyReferenceDirectoriesXpath = "FxCopProject/Targets/AssemblyReferenceDirectories";
145 public const string DirectoriesXpath = "FxCopProject/Targets/AssemblyReferenceDirectories/Directory";
146 public const string TargetXpath = "FxCopProject/Targets/Target";
147 public const string CoreAssemblyName = "AWSSDK.Core.dll";
148
149 public const string DeploymentPath = @"Deployment\assemblies";
150 public const string ProjectDirRelative = @"$(ProjectDir)\..\";
151
152 public static IEnumerable<string> GetNamespacesToExamine(Assembly assembly)
153 {
154 HashSet<string> namespaces = new HashSet<string>(StringComparer.Ordinal);
155
156 var allTypes = assembly.GetTypes().ToList();
157 foreach (var type in allTypes)
158 {
159 var ns = type.Namespace;
160 if (ShouldSkip(ns))
161 continue;
162
163 namespaces.Add(ns);
164 }
165
166 return namespaces;
167 }
168
169 private static bool ShouldSkip(string ns)
170 {
171 if (ns == null)
172 return false;
173
174 foreach (var toSkip in NamespacePrefixesToSkip)
175 if (ns.StartsWith(toSkip, StringComparison.Ordinal))
176 return true;
177 return false;
178 }
179 private static string MakeRelativePath(string assemblyPath)
180 {
181 var fullPath = Path.GetFullPath(assemblyPath);
182 var deploymentIndex = fullPath.IndexOf(DeploymentPath, StringComparison.OrdinalIgnoreCase);
183 var partialPath = fullPath.Substring(deploymentIndex);
184
185 var relativePath = string.Concat(ProjectDirRelative, partialPath);
186 return relativePath;
187 }
188
189 private static void AddAttribute(XmlNode node, string name, string value)
190 {
191 var doc = node.OwnerDocument;
192 var attribute = doc.CreateAttribute(name);
193 attribute.Value = value;
194 node.Attributes.Append(attribute);
195 }
196 private static XmlNode AddChildNode(XmlNode parent, string name)
197 {
198 var doc = parent.OwnerDocument;
199 var node = doc.CreateElement(name);
200 parent.AppendChild(node);
201 return node;
202 }
203 private static void RemoveAllNodes(XmlDocument doc, XmlNode targetsNode, string xpath)
204 {
205 var matchingNodes = doc.SelectNodes(xpath);
206 foreach (XmlNode node in matchingNodes)
207 targetsNode.RemoveChild(node);
208 }
209
210 private static void ResetReferenceDirectories(XmlDocument doc,
211 XmlNode referenceDirectoriesNode, string xpath)
212 {
213 RemoveAllNodes(doc, referenceDirectoriesNode, xpath);
214
215 //// Add default reference paths
216 //var wp8DirNode = AddChildNode(referenceDirectoriesNode, "Directory");
217 //wp8DirNode.InnerText = "$(ProjectDir)/Deployment/wp8/";
218
219 //var winrtDirNode = AddChildNode(referenceDirectoriesNode, "Directory");
220 //winrtDirNode.InnerText = "$(ProjectDir)/Deployment/winrt/";
221
222 //var dotnet45DirNode = AddChildNode(referenceDirectoriesNode, "Directory");
223 //dotnet45DirNode.InnerText = "$(ProjectDir)/Deployment/dotnet45/";
224 }
225 }
226}