protected override Expression VisitBinary(BinaryExpression node) { // Change equality comparisons on Version to normalized comparisons on NormalizedVersion if (node.NodeType == ExpressionType.Equal) { // Figure out which side is the target ConstantExpression constSide = (node.Left as ConstantExpression) ?? (node.Right as ConstantExpression); if (constSide != null && constSide.Type == typeof(string)) { MemberExpression memberSide = (node.Right as MemberExpression) ?? (node.Left as MemberExpression); if (memberSide != null && memberSide.Member == _versionMember) { // We have a "Package.Version == <constant>" expression! // Transform the constant version into a normalized version string newVersion = NuGetVersionNormalizer.Normalize((string)constSide.Value); // Create a new expression that checks the new constant against NormalizedVersion instead return(Expression.MakeBinary( ExpressionType.Equal, left: Expression.Constant(newVersion), right: Expression.MakeMemberAccess(memberSide.Expression, _normalizedVersionMember))); } } } return(node); }
public override string GetPath() { return(String.Format( "{0}/{1}", Id.ToLowerInvariant(), NuGetVersionNormalizer.Normalize(Version).ToLowerInvariant())); }
public override void ExecuteCommand() { WithConnection((c, db) => { Log.Trace("Collecting list of packages..."); var packages = db.Query <Package>(@" SELECT pr.Id, p.[Key], p.Version FROM Packages p INNER JOIN PackageRegistrations pr ON pr.[Key] = p.PackageRegistrationKey WHERE p.NormalizedVersion IS NULL") .ToList(); Log.Trace("Collected {0} packages", packages.Count); DataTable output; int count = 0; WithTableType(c, "Temp_NormalizePackageVersionsInputType", "PackageKey int, NormalizedVersion nvarchar(64)", () => { // Build a table to hold the new data var updateTable = new DataTable(); updateTable.Columns.Add(new DataColumn("PackageKey", typeof(int))); updateTable.Columns.Add(new DataColumn("NormalizedVersion", typeof(string))); foreach (var package in packages) { string normalized = NuGetVersionNormalizer.Normalize(package.Version); var row = updateTable.NewRow(); row.SetField("PackageKey", package.Key); row.SetField("NormalizedVersion", normalized); updateTable.Rows.Add(row); } // Run the query with the table parameter var cmd = c.CreateCommand(); cmd.CommandType = CommandType.Text; cmd.CommandText = WhatIf ? WhatIfQuery : CommitQuery; cmd.Parameters.Add(new SqlParameter("@updateTable", SqlDbType.Structured) { TypeName = "Temp_NormalizePackageVersionsInputType", Value = updateTable }); Log.Trace("Updating Database..."); var reader = cmd.ExecuteReader(); Log.Trace("Database Update Complete"); // Load the results into a datatable and render them output = new DataTable(); output.Load(reader); foreach (var row in output.Rows.Cast <DataRow>()) { string version = row.Field <string>("Version"); string normalized = row.Field <string>("NormalizedVersion"); if (!String.Equals(version, normalized, StringComparison.Ordinal)) { count++; } } Log.Info("Updated {0} packages", count); }); }); }
private static Tuple <Target, string> ExtractComparison(BinaryExpression binExpr) { // p => <constant> == p.<property> if (binExpr.NodeType != ExpressionType.Equal) { return(null); } // Get the two sides, we don't care which side is left and which is right. ConstantExpression constSide = (binExpr.Left as ConstantExpression) ?? (binExpr.Right as ConstantExpression); if (constSide == null || constSide.Type != typeof(string)) { return(null); } MemberExpression memberSide = (binExpr.Right as MemberExpression) ?? (binExpr.Left as MemberExpression); if (memberSide == null) { // That did not work... This may be Web API OData wrapping our expression UnaryExpression temp = binExpr.Left as UnaryExpression; if (temp != null) { memberSide = temp.Operand as MemberExpression; } // Not found - for real. if (memberSide == null) { return(null); } } // Check if it's a known member comparison if (memberSide.Member == NormalizedVersionMember) { return(Tuple.Create(Target.Version, (string)constSide.Value)); } else if (memberSide.Member == VersionMember) { return(Tuple.Create(Target.Version, NuGetVersionNormalizer.Normalize((string)constSide.Value))); } else if (memberSide.Member == IdMember) { return(Tuple.Create(Target.Id, (string)constSide.Value)); } return(null); }
private static Tuple <Target, string> ExtractComparison(MethodCallExpression outerWhere) { // We expect to see an expression that looks like this: // Queryable.Where(<nested expression>, p => <constant> == p.<property>); var arg = Unquote(outerWhere.Arguments[1]); if (arg.NodeType != ExpressionType.Lambda) { return(null); } var lambda = arg as LambdaExpression; // p => <constant> == p.<property> if (lambda.Body.NodeType != ExpressionType.Equal) { return(null); } var binExpr = lambda.Body as BinaryExpression; // <constant> == p.<property> // Get the two sides, we don't care which side is left and which is right. ConstantExpression constSide = (binExpr.Left as ConstantExpression) ?? (binExpr.Right as ConstantExpression); if (constSide == null || constSide.Type != typeof(string)) { return(null); } MemberExpression memberSide = (binExpr.Right as MemberExpression) ?? (binExpr.Left as MemberExpression); if (memberSide == null) { return(null); } // Check if it's a known member comparison if (memberSide.Member == _normalizedVersionMember) { return(Tuple.Create(Target.Version, (string)constSide.Value)); } else if (memberSide.Member == _versionMember) { return(Tuple.Create(Target.Version, NuGetVersionNormalizer.Normalize((string)constSide.Value))); } else if (memberSide.Member == _idMember) { return(Tuple.Create(Target.Id, (string)constSide.Value)); } return(null); }
public override void ExecuteCommand() { using (var sqlConnection = new SqlConnection(ConnectionString.ConnectionString)) using (var dbExecutor = new SqlExecutor(sqlConnection)) { sqlConnection.Open(); // Query for packages Log.Info("Gathering list of packages..."); var packages = dbExecutor.Query <PackageSummary>(@" SELECT p.[Key], p.PackageRegistrationKey, r.Id, p.Version, p.Hash, p.LastUpdated, p.Published, p.Listed, p.IsLatestStable FROM Packages p INNER JOIN PackageRegistrations r ON p.PackageRegistrationKey = r.[Key]"); // Group by Id and and SemVer Log.Info("Grouping by Package ID and Actual Version..."); var groups = packages.GroupBy(p => new { p.Id, Version = NuGetVersionNormalizer.Normalize(p.Version) }); // Find any groups with more than one entry Log.Info("Finding Duplicates..."); var dups = groups.Where(g => g.Count() > 1); // Print them out int dupsUnlistedCount = 0; int latestCount = 0; foreach (var dup in dups) { ProcessDuplicate(dup.Key.Id, dup.Key.Version, dup.ToList(), ref dupsUnlistedCount, ref latestCount); } var totalDupes = dups.Count(); Log.Info("Found {0} Packages with duplicates.", totalDupes); Log.Info(" {0} of them have no listed duplicates.", dupsUnlistedCount); Log.Info(" {0} of them have multiple listed duplicates.", totalDupes - dupsUnlistedCount); if (latestCount > 0) { Log.Warn(" {0} of them are the latest version of the relevant package", latestCount); } else { Log.Info(" NONE of them are the latest version of the relevant package"); } } }
public override string GetPath() { return($"{Id}/{NuGetVersionNormalizer.Normalize(Version)}" .ToLowerInvariant()); }