using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Build.Utilities; using System.IO; using System.Xml; using System.Reflection; namespace CustomTasks { public class UpdateFxCopProject : Task { public string Assemblies { get; set; } public string FxCopProject { get; set; } public string BinSuffix { get; set; } public override bool Execute() { if (string.IsNullOrEmpty(Assemblies)) throw new ArgumentNullException("Assemblies"); if (string.IsNullOrEmpty(FxCopProject)) throw new ArgumentNullException("FxCopProject"); if (string.IsNullOrEmpty(BinSuffix)) throw new ArgumentNullException("BinSuffix"); Assemblies = Path.GetFullPath(Assemblies); Log.LogMessage("Assemblies = " + Assemblies); FxCopProject = Path.GetFullPath(FxCopProject); Log.LogMessage("FxCopProject = " + FxCopProject); Log.LogMessage("Updating project..."); FxCop.UpdateFxCopProject(Assemblies, FxCopProject, BinSuffix); Log.LogMessage("Project updated"); return true; } } public static class FxCop { public static void UpdateFxCopProject(string assembliesFolder, string fxCopProjectPath, string binSuffix) { var allAssemblies = Directory.GetFiles(assembliesFolder, "*.dll").ToList(); var doc = new XmlDocument(); doc.Load(fxCopProjectPath); var referenceDirectoriesNode = doc.SelectSingleNode(AssemblyReferenceDirectoriesXpath); var targetsNode = doc.SelectSingleNode(TargetsXpath); RemoveAllNodes(doc, targetsNode, TargetXpath); ResetReferenceDirectories(doc, referenceDirectoriesNode, DirectoriesXpath); foreach (var assembly in allAssemblies) { var assemblyName = Path.GetFileName(assembly).ToLower(); var assemblyFolderName = assemblyName.Split('.')[1]; var newTarget = AddChildNode(targetsNode, "Target"); AddAttribute(newTarget, "Name", MakeRelativePath(assembly)); AddAttribute(newTarget, "Analyze", "True"); var dirNode = AddChildNode(referenceDirectoriesNode, "Directory"); /* */ AddAttribute(newTarget, "AnalyzeAllChildren", "True"); // Add assembly reference directory for each service // $(ProjectDir)/src/bin/Release/net35/ dirNode.InnerText = string.Format("$(ProjectDir)/src/bin/Release/{0}/", binSuffix); } doc.Save(fxCopProjectPath); } public static HashSet NamespacePrefixesToSkip = new HashSet(StringComparer.Ordinal) { "ThirdParty.BouncyCastle", "ThirdParty.Ionic.Zlib", "ThirdParty.Json", }; public const string NamespacesXpath = "FxCopProject/Targets/Target/Modules/Module/Namespaces"; public const string TargetsXpath = "FxCopProject/Targets"; public const string AssemblyReferenceDirectoriesXpath = "FxCopProject/Targets/AssemblyReferenceDirectories"; public const string DirectoriesXpath = "FxCopProject/Targets/AssemblyReferenceDirectories/Directory"; public const string TargetXpath = "FxCopProject/Targets/Target"; public const string CoreAssemblyName = "AWSSDK.Core.dll"; public const string DeploymentPath = @"Deployment\assemblies"; public const string ProjectDirRelative = @"$(ProjectDir)\..\"; public static IEnumerable GetNamespacesToExamine(Assembly assembly) { HashSet namespaces = new HashSet(StringComparer.Ordinal); var allTypes = assembly.GetTypes().ToList(); foreach (var type in allTypes) { var ns = type.Namespace; if (ShouldSkip(ns)) continue; namespaces.Add(ns); } return namespaces; } private static bool ShouldSkip(string ns) { if (ns == null) return false; foreach (var toSkip in NamespacePrefixesToSkip) if (ns.StartsWith(toSkip, StringComparison.Ordinal)) return true; return false; } private static string MakeRelativePath(string assemblyPath) { var fullPath = Path.GetFullPath(assemblyPath); var deploymentIndex = fullPath.IndexOf(DeploymentPath, StringComparison.OrdinalIgnoreCase); var partialPath = fullPath.Substring(deploymentIndex); var relativePath = string.Concat(ProjectDirRelative, partialPath); return relativePath; } private static void AddAttribute(XmlNode node, string name, string value) { var doc = node.OwnerDocument; var attribute = doc.CreateAttribute(name); attribute.Value = value; node.Attributes.Append(attribute); } private static XmlNode AddChildNode(XmlNode parent, string name) { var doc = parent.OwnerDocument; var node = doc.CreateElement(name); parent.AppendChild(node); return node; } private static void RemoveAllNodes(XmlDocument doc, XmlNode targetsNode, string xpath) { var matchingNodes = doc.SelectNodes(xpath); foreach (XmlNode node in matchingNodes) targetsNode.RemoveChild(node); } private static void ResetReferenceDirectories(XmlDocument doc, XmlNode referenceDirectoriesNode, string xpath) { RemoveAllNodes(doc, referenceDirectoriesNode, xpath); } } }