File: DiffConfigurationExtensions.cs
Web Access
Project: src\src\Microsoft.DotNet.AsmDiff\Microsoft.DotNet.AsmDiff.csproj (Microsoft.DotNet.AsmDiff)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Linq;
using Microsoft.Cci;
 
namespace Microsoft.DotNet.AsmDiff
{
    public static class DiffConfigurationExtensions
    {
        // Options
 
        public static DiffConfiguration UpdateOptions(this DiffConfiguration configuration, DiffConfigurationOptions options)
        {
            var left = configuration.Left;
            var right = configuration.Right;
            return new DiffConfiguration(left, right, options);
        }
 
        public static bool IsOptionSet(this DiffConfiguration configuration, DiffConfigurationOptions option)
        {
            return option == DiffConfigurationOptions.None
                       ? configuration.Options == DiffConfigurationOptions.None
                       : (configuration.Options & option) == option;
        }
 
        public static DiffConfiguration SetOption(this DiffConfiguration configuration, DiffConfigurationOptions option, bool set)
        {
            var newOptions = set
                                 ? configuration.Options | option
                                 : configuration.Options & ~option;
            return configuration.UpdateOptions(newOptions);
        }
 
        // Add assemblies
 
        public static DiffConfiguration AddLeftAssemblies(this DiffConfiguration configuration, IEnumerable<string> addedPaths)
        {
            return configuration.AddAssemblies(true, addedPaths);
        }
 
        public static DiffConfiguration AddRightAssemblies(this DiffConfiguration configuration, IEnumerable<string> addedPaths)
        {
            return configuration.AddAssemblies(false, addedPaths);
        }
 
        private static DiffConfiguration AddAssemblies(this DiffConfiguration configuration, bool isLeft, IEnumerable<string> addedPaths)
        {
            var existingSet = isLeft
                                  ? configuration.Left
                                  : configuration.Right;
            var existingAssemblyPaths = from a in existingSet.Assemblies
                                        select a.Location;
 
            var totalAssemblyPaths = existingAssemblyPaths.Concat(addedPaths).ToArray();
            var newName = existingSet.IsEmpty ? null : existingSet.Name;
 
            return configuration.UpdateAssemblies(isLeft, totalAssemblyPaths, newName);
        }
 
        // Remove assemblies
 
        public static DiffConfiguration RemoveLeftAssemblies(this DiffConfiguration configuration, IEnumerable<IAssembly> removals)
        {
            return configuration.RemoveAssemblies(true, removals);
        }
 
        public static DiffConfiguration RemoveRightAssemblies(this DiffConfiguration configuration, IEnumerable<IAssembly> removals)
        {
            return configuration.RemoveAssemblies(false, removals);
        }
 
        private static DiffConfiguration RemoveAssemblies(this DiffConfiguration configuration, bool isLeft, IEnumerable<IAssembly> removals)
        {
            var existingSet = isLeft
                                  ? configuration.Left
                                  : configuration.Right;
            var newSet = existingSet.Remove(removals);
            return configuration.UpdateAssemblies(isLeft, newSet);
        }
 
        // Update assemblies
 
        public static DiffConfiguration UpdateLeftAssemblies(this DiffConfiguration configuration, IEnumerable<string> paths)
        {
            return configuration.UpdateLeftAssemblies(paths, null);
        }
 
        public static DiffConfiguration UpdateLeftAssemblies(this DiffConfiguration configuration, IEnumerable<string> paths, string name)
        {
            return configuration.UpdateAssemblies(true, paths, name);
        }
 
        public static DiffConfiguration UpdateLeftAssemblies(this DiffConfiguration configuration, AssemblySet assemblySet)
        {
            return configuration.UpdateAssemblies(true, assemblySet);
        }
 
        public static DiffConfiguration UpdateRightAssemblies(this DiffConfiguration configuration, IEnumerable<string> paths)
        {
            return configuration.UpdateRightAssemblies(paths, null);
        }
 
        public static DiffConfiguration UpdateRightAssemblies(this DiffConfiguration configuration, IEnumerable<string> paths, string name)
        {
            return configuration.UpdateAssemblies(false, paths, name);
        }
 
        public static DiffConfiguration UpdateRightAssemblies(this DiffConfiguration configuration, AssemblySet assemblySet)
        {
            return configuration.UpdateAssemblies(false, assemblySet);
        }
 
        private static DiffConfiguration UpdateAssemblies(this DiffConfiguration configuration, bool isLeft, IEnumerable<string> newPaths, string newName)
        {
            var assemblySet = AssemblySet.FromPaths(newPaths, newName);
            return configuration.UpdateAssemblies(isLeft, assemblySet);
        }
 
        private static DiffConfiguration UpdateAssemblies(this DiffConfiguration configuration, bool isLeft, AssemblySet assemblySet)
        {
            var isRight = !isLeft;
            var existingSet = isLeft
                                  ? configuration.Left
                                  : configuration.Right;
 
            // This is the a debatible thing here.
            //
            // Without Dipose(), instances of DiffConfiguration would be fully immutable, which means
            // we could pass it around to different threads and you could be sure that no than is stepping
            // on your toes.
            //
            // However, this also means we would only unlock the files on disk when the GC collects the
            // the underlying metadata reader host. This means, nobody can open the files exlusively or
            // deleting them until they are collected.
            //
            // A workaround for the user is to simply close the app but I feel the workaround feels really
            // bad. Especially because most of the assemblies being added to the tool will come from temp
            // folders on the desktop.
            //
            // Since our apps is blocking adding/removing files when an analysis is running, there are
            // no real advantages of full immutable sharing.
 
            existingSet.Dispose();
 
            var newLeft = isLeft ? assemblySet : configuration.Left;
            var newRight = isRight ? assemblySet : configuration.Right;
 
            return new DiffConfiguration(newLeft, newRight, configuration.Options);
        }
    }
}