Пример #1
0
        public override void Execute()
        {
            using (Tracer t = new Tracer(myType, "Execute"))
            {
                base.Execute();
                if (!IsValid)
                {
                    Help();
                    return;
                }

                Out.WriteLine("Compare from {0} against {1}", myParsedArgs.Queries1.GetSearchDirs(), myParsedArgs.Queries2.GetSearchDirs());
                int removedTypes = 0;
                int changedTypes = 0;

                List <string> removedFiles = myParsedArgs.Queries1.GetNotExistingFilesInOtherQuery(myParsedArgs.Queries2);
                if (removedFiles.Count > 0)
                {
                    Out.WriteLine("Removed {0} files", removedFiles.Count);
                    foreach (string str in removedFiles)
                    {
                        Console.WriteLine("\t{0}", Path.GetFileName(str));
                    }
                }

                HashSet <string> query1 = new HashSet <string>(myParsedArgs.Queries1.GetFiles(), new FileNameComparer());
                HashSet <string> query2 = new HashSet <string>(myParsedArgs.Queries2.GetFiles(), new FileNameComparer());

                // Get files which are present in one set and the other
                query1.IntersectWith(query2);
                DiffPrinter printer = new DiffPrinter(Out);

                foreach (string fileName1 in query1)
                {
                    if (fileName1.EndsWith(".XmlSerializers.dll", StringComparison.OrdinalIgnoreCase))
                    {
                        t.Info("Ignore xml serializer dll {0}", fileName1);
                        continue;
                    }

                    string fileName2 = myParsedArgs.Queries2.GetMatchingFileByName(fileName1);

                    var assemblyV1 = AssemblyLoader.LoadCecilAssembly(fileName1);
                    var assemblyV2 = AssemblyLoader.LoadCecilAssembly(fileName2);

                    if (assemblyV1 != null && assemblyV2 != null)
                    {
                        AssemblyDiffer         differ = new AssemblyDiffer(assemblyV1, assemblyV2);
                        AssemblyDiffCollection diff   = differ.GenerateTypeDiff(QueryAggregator.PublicApiQueries);
                        removedTypes += diff.AddedRemovedTypes.RemovedCount;
                        changedTypes += diff.ChangedTypes.Count;

                        if (diff.AddedRemovedTypes.Count > 0 || diff.ChangedTypes.Count > 0)
                        {
                            Out.WriteLine("{0} has {1} changes", Path.GetFileName(fileName1), diff.AddedRemovedTypes.Count +
                                          diff.ChangedTypes.Sum(type => type.Events.Count + type.Fields.Count + type.Interfaces.Count + type.Methods.Count));

                            printer.Print(diff);
                        }
                    }
                }

                Out.WriteLine("From {0} assemblies were {1} types removed and {2} changed.",
                              myParsedArgs.Queries1.GetFiles().Count(), removedTypes, changedTypes);
            }
        }
Пример #2
0
        public override void Execute()
        {
            base.Execute();
            if (!IsValid)
            {
                Help();
                return;
            }

            List <AssemblyDiffCollection> assemblyDiffs = new List <AssemblyDiffCollection>();
            DiffPrinter printer = new DiffPrinter(Out);

            foreach (string newFile in myParsedArgs.NewFiles.GetFiles())
            {
                string oldFile = myParsedArgs.OldFiles.GetMatchingFileByName(newFile);
                if (oldFile == null)
                {
                    oldFile = myParsedArgs.OldFiles2.GetMatchingFileByName(newFile);
                }

                if (oldFile == null)
                {
                    Out.WriteLine("Warning: {0} seems to be a new file. Cannot diff.", Path.GetFileName(newFile));
                    continue;
                }


                try
                {
                    AssemblyDiffer         differ = new AssemblyDiffer(oldFile, newFile);
                    AssemblyDiffCollection diff   = differ.GenerateTypeDiff(QueryAggregator.AllExternallyVisibleApis);
                    if (diff.AddedRemovedTypes.Count > 0 ||
                        diff.ChangedTypes.Count > 0)
                    {
                        Out.WriteLine("Changes of {0}", Path.GetFileName(newFile));
                        printer.Print(diff);
                        assemblyDiffs.Add(diff);
                    }
                }
                catch (ArgumentException)
                {
                    // ignore C++ and other targets in diff
                }
            }

            UsageQueryAggregator usage = new UsageQueryAggregator();

            BreakingChangeSearcher breaking = new BreakingChangeSearcher(assemblyDiffs, usage);

            foreach (string fileV2 in myParsedArgs.SearchInQuery.GetFiles())
            {
                AssemblyDefinition aV2 = AssemblyLoader.LoadCecilAssembly(fileV2);
                if (aV2 != null)
                {
                    usage.Analyze(aV2);
                }
            }

            Out.WriteLine("Detected {0} assemblies which need a recompilation", usage.AssemblyMatches.Count);

            foreach (var needsRecompilation in usage.AssemblyMatches)
            {
                Out.WriteLine("{0}", Path.GetFileName(needsRecompilation));
            }
        }
Пример #3
0
        /// <summary>
        /// Marked as internal for unit test purpose. In charge of fetching all the version of an assembly and analyze the public
        /// API to know if there were breaking change or not
        /// </summary>
        internal Tuple <SemanticVersion, string> ResolveConflictingDependancy(IEnumerable <DllReference> conflictingAssembliesVersions, DllReference parentAssembly)
        {
            var         diffs       = new List <AssemblyDiffCollection>();
            DiffPrinter diffPrinter = new DiffPrinter();

            //Skip SemanticVersion until we reach the official SemanticVersion supported
            var asms = conflictingAssembliesVersions.Reverse();

            asms = asms.Reverse();

            //We start to next one as we already set PreviousAPI...
            var previousAPIAssembly = asms.FirstOrDefault();

            asms = asms.Skip(1);
            DllReference selectedVersion = previousAPIAssembly;

            foreach (var apiAssembly in asms)
            {
                diffs = new List <AssemblyDiffCollection>();
                AssemblyDiffCollection diff = null;
                try
                {
                    if (previousAPIAssembly.Path != null && apiAssembly.Path != null)
                    {
                        diff =
                            new AssemblyDiffer(previousAPIAssembly.Path, apiAssembly.Path).GenerateTypeDiff(
                                QueryAggregator.AllExternallyVisibleApis);
                    }
                    //The previous assembly doesn't have any path we can compare with let's forget it
                    else if (previousAPIAssembly.Path == null && apiAssembly.Path != null)
                    {
                        previousAPIAssembly = apiAssembly;
                        continue;
                    }
                    //Current assembly doesn't have any path we can use to compare, ignore it
                    else
                    {
                        continue;
                    }

                    //Nothing Was added between those 2 versions...Strange but let's go ahead
                    if (diff.AddedRemovedTypes.Count <= 0 && diff.ChangedTypes.Count <= 0)
                    {
                        previousAPIAssembly = apiAssembly;
                        continue;
                    }


                    diffs.Add(diff);

                    var aggregator = new UsageQueryAggregator();

                    var breakingChangeSearcher =
                        AppDomain.CurrentDomain.CreateInstanceAndUnwrap(
                            "ApiChange.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
                            "ApiChange.Api.Introspection.Diff.BreakingChangeSearcher", true,
                            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null,
                            new object[] { diffs, aggregator }, null, null);
                    AssemblyDefinition assembly =
                        AssemblyLoader.LoadCecilAssembly(parentAssembly.Path, false);

                    if (assembly != null)
                    {
                        aggregator.Analyze(assembly);
                    }

                    //None of New Types, methods, fields etc. are used in assembly
                    //So we stop here and return the previous one
                    if (aggregator.AssemblyMatches.Count != 0 ||
                        aggregator.TypeMatches.Count != 0 ||
                        aggregator.MethodMatches.Count != 0 ||
                        aggregator.FieldMatches.Count != 0)
                    {
                        selectedVersion = apiAssembly;
                    }
                }
                catch (Exception exc)
                {
                    Trace.TraceError(exc.Message);
                    Trace.TraceError(exc.StackTrace);
                    Trace.TraceError(String.Format("Unable to diff assembly from {0} to {1}", previousAPIAssembly, apiAssembly));
                    //We don't set the prevous assembly because the current raised an exception, let's ignore it totally
                    continue;
                }
                previousAPIAssembly = apiAssembly;
            }
            return(new Tuple <SemanticVersion, string>(selectedVersion.Id.Item1, selectedVersion.Id.Item2));
        }
        /// <summary>
        /// Marked as internal for unit test purpose. In charge of fetching all the version of an assembly and analyze the public
        /// API to know if there were breaking change or not
        /// </summary>
        internal Tuple<SemanticVersion, string> ResolveConflictingDependancy(IEnumerable<DllReference> conflictingAssembliesVersions , DllReference parentAssembly)
        {
            var diffs = new List<AssemblyDiffCollection>();
            DiffPrinter diffPrinter = new DiffPrinter();

            //Skip SemanticVersion until we reach the official SemanticVersion supported
            var asms = conflictingAssembliesVersions.Reverse();
            asms = asms.Reverse();

            //We start to next one as we already set PreviousAPI...
            var previousAPIAssembly = asms.FirstOrDefault();
            asms = asms.Skip(1);
            DllReference selectedVersion = previousAPIAssembly;

            foreach (var apiAssembly in asms)
            {
                diffs = new List<AssemblyDiffCollection>();
                AssemblyDiffCollection diff = null;
                try
                {
                    if (previousAPIAssembly.Path != null && apiAssembly.Path != null)
                        diff =
                            new AssemblyDiffer(previousAPIAssembly.Path, apiAssembly.Path).GenerateTypeDiff(
                                QueryAggregator.AllExternallyVisibleApis);
                    //The previous assembly doesn't have any path we can compare with let's forget it
                    else if (previousAPIAssembly.Path == null && apiAssembly.Path != null)
                    {
                        previousAPIAssembly = apiAssembly;
                        continue;
                    }
                    //Current assembly doesn't have any path we can use to compare, ignore it
                    else
                        continue;
                    
                    //Nothing Was added between those 2 versions...Strange but let's go ahead
                    if (diff.AddedRemovedTypes.Count <= 0 && diff.ChangedTypes.Count <= 0)
                    {
                        previousAPIAssembly = apiAssembly;
                        continue;
                    }


                    diffs.Add(diff);

                    var aggregator = new UsageQueryAggregator();

                    var breakingChangeSearcher =
                        AppDomain.CurrentDomain.CreateInstanceAndUnwrap(
                            "ApiChange.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
                            "ApiChange.Api.Introspection.Diff.BreakingChangeSearcher", true,
                            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null,
                            new object[] {diffs, aggregator}, null, null);
                    AssemblyDefinition assembly =
                        AssemblyLoader.LoadCecilAssembly(parentAssembly.Path, false);

                    if (assembly != null)
                        aggregator.Analyze(assembly);

                    //None of New Types, methods, fields etc. are used in assembly
                    //So we stop here and return the previous one
                    if (aggregator.AssemblyMatches.Count != 0
                        || aggregator.TypeMatches.Count != 0
                        || aggregator.MethodMatches.Count != 0
                        || aggregator.FieldMatches.Count != 0)
                    {
                        selectedVersion = apiAssembly;
                    }

                }
                catch (Exception exc)
                {
                    Trace.TraceError(exc.Message);
                    Trace.TraceError(exc.StackTrace);
                    Trace.TraceError(String.Format("Unable to diff assembly from {0} to {1}", previousAPIAssembly, apiAssembly));
                    //We don't set the prevous assembly because the current raised an exception, let's ignore it totally
                    continue;
                }
                previousAPIAssembly = apiAssembly;
            }
            return new Tuple<SemanticVersion, string>(selectedVersion.Id.Item1, selectedVersion.Id.Item2);
        }