Esempio n. 1
0
        private void GenerateForCollection(HostCollection collection)
        {
            (SourceGeneratorHostWrapper Wrapper, AppDomain Domain)hostEntry = (null, null);

            try
            {
                if (!collection.Hosts.TryTake(out hostEntry))
                {
                    hostEntry = CreateDomain(collection);
                }
                else
                {
                    // Try pinging the remote appdomain, as it may throw a RemotingException exception with this error:
                    // Error : Object '/b612ce25_b538_486d_882a_28a019c782ed/p6lmd0em_mrlqpchbk5gh2mk_10.rem' has been disconnected or does not exist at the server.
                    try
                    {
                        if (hostEntry.Wrapper.Ping())
                        {
                            Log.LogMessage($"Reusing generation host ({collection.Entry.OwnerFile}, {string.Join(", ", collection.Entry.Analyzers)})");
                        }
                    }
                    catch (System.Runtime.Remoting.RemotingException /*e*/)
                    {
                        Log.LogMessage($"Discarding disconnected generation host for ({collection.Entry.OwnerFile}, {string.Join(", ", collection.Entry.Analyzers)})");

                        hostEntry = CreateDomain(collection);
                    }
                }

                Logger.RemotableLogger2 remotableLogger = new Logger.RemotableLogger2(_taskLogger.CreateLogger("Logger.RemotableLogger"));

                var environment = new BuildEnvironment(
                    Configuration,
                    Platform,
                    ProjectFile,
                    OutputPath,
                    TargetFramework,
                    VisualStudioVersion,
                    TargetFrameworkRootPath,
                    BinLogOutputPath,
                    BinLogEnabled
                    );

                GenereratedFiles = hostEntry.Wrapper.Generate(remotableLogger, environment);
            }
            finally
            {
                if (collection != null)
                {
                    collection.Hosts.Add(hostEntry);
                }
            }
        }
Esempio n. 2
0
 private void UnloadHosts(HostCollection collection)
 {
     foreach (var host in collection.Hosts)
     {
         try
         {
             Log.LogMessage($"Unloading generation host {host.Domain.FriendlyName}");
             AppDomain.Unload(host.Domain);
         }
         catch (Exception /*e*/)
         {
             Log.LogWarning($"Failed to unload generation host {host.Domain.FriendlyName}");
         }
     }
 }
Esempio n. 3
0
        private (SourceGeneratorHostWrapper Wrapper, AppDomain Domain) CreateDomain(HostCollection collection)
        {
            (SourceGeneratorHostWrapper Wrapper, AppDomain Domain)hostEntry;
            Log.LogMessage($"Creating generation host ({collection.Entry.OwnerFile}, {string.Join(", ", collection.Entry.Analyzers)}, {Environment.OSVersion.Platform})");

            var generatorLocations = SourceGenerators.Select(Path.GetFullPath).Select(Path.GetDirectoryName).Distinct();
            var wrapperBasePath    = Path.GetDirectoryName(new Uri(typeof(SourceGeneratorHostWrapper).Assembly.CodeBase).LocalPath);

            // We can create an app domain per OwnerFile and all Analyzers files
            // so that if those change, we can spin off another one, and still avoid
            // locking these assemblies.
            //
            // If the domain exists, keep it and continue generating content with it.

            var setup = new AppDomainSetup();

            setup.ApplicationBase       = wrapperBasePath;
            setup.ShadowCopyFiles       = "true";
            setup.ShadowCopyDirectories = string.Join(";", generatorLocations) + ";" + wrapperBasePath;
            setup.PrivateBinPath        = setup.ShadowCopyDirectories;
            setup.ConfigurationFile     = Path.Combine(wrapperBasePath, typeof(SourceGeneratorHostWrapper).Assembly.GetName().Name + ".dll.config");

            // Loader optimization must not use MultiDomainHost, otherwise MSBuild assemblies may
            // be shared incorrectly when multiple versions are loaded in different domains.
            // The loader must specify SingleDomain, otherwise in contexts where devenv.exe is the
            // current process, the default optimization is "MultiDomain" and assemblies are
            // incorrectly reused.
            setup.LoaderOptimization = LoaderOptimization.SingleDomain;

            var domain = AppDomain.CreateDomain("Generators-" + Guid.NewGuid(), null, setup);

            Log.LogMessage($"[{Process.GetCurrentProcess().ProcessName}] Creating object {typeof(SourceGeneratorHostWrapper).Assembly.CodeBase} with {typeof(SourceGeneratorHostWrapper).FullName}. wrapperBasePath {wrapperBasePath} ");

            var newHost = domain.CreateInstanceFromAndUnwrap(
                typeof(SourceGeneratorHostWrapper).Assembly.CodeBase,
                typeof(SourceGeneratorHostWrapper).FullName
                ) as SourceGeneratorHostWrapper;

            var msbuildBasePath = Path.GetDirectoryName(new Uri(typeof(Microsoft.Build.Logging.ConsoleLogger).Assembly.CodeBase).LocalPath);

            newHost.MSBuildBasePath      = msbuildBasePath;
            newHost.AdditionalAssemblies = AdditionalAssemblies;

            newHost.Initialize();

            hostEntry = (newHost, domain);
            return(hostEntry);
        }
Esempio n. 4
0
        private HostCollection GetCollection()
        {
            var entry = new DomainEntry(this.BuildEngine4.ProjectFileOfTaskNode, Platform, SourceGenerators.Select(Path.GetFullPath).ToArray());

            HostCollection collection = GetHost(entry);

            if (collection.IsInvalid)
            {
                Log.LogMessage("Discarding source generation host, generators files have been modified");

                _domains.TryRemove(entry, out collection);

                UnloadHosts(collection);

                collection = GetHost(entry);
            }

            return(collection);
        }
Esempio n. 5
0
 private static HostCollection GetHost(DomainEntry entry)
 => _domains.TryGetValue(entry, out var hosts)
                 ? hosts
                 : _domains[entry] = new HostCollection(entry);