CompilerRunHandler.cs 5.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

namespace Microsoft.CodeAnalysis.CompilerServer
{
    public struct RunRequest
    {
        public string Language { get; }
        public string CurrentDirectory { get; }
        public string LibDirectory { get; }
        public string[] Arguments { get; }

        public RunRequest(string language, string currentDirectory, string libDirectory, string[] arguments)
        {
            Language = language;
            CurrentDirectory = currentDirectory;
            LibDirectory = libDirectory;
            Arguments = arguments;
        }
    }

    public enum RunResultKind
    {
        BadLanguage,
        BadAnalyzer,
        Run
    }

    public struct RunResult
    {
        public RunResultKind Kind { get; }
        public int ReturnCode { get; }
        public bool Utf8Output { get; }
        public string Output { get; }

        public RunResult(RunResultKind kind)
        {
            Debug.Assert(kind != RunResultKind.Run);
            Kind = kind;
            ReturnCode = 0;
            Utf8Output = false;
            Output = string.Empty;
        }

        public RunResult(int returnCode, bool utf8Output, string output)
        {
            Kind = RunResultKind.Run;
            ReturnCode = returnCode;
            Utf8Output = utf8Output;
            Output = output;
        }
    }

    public sealed class CompilerRunHandler
    {
        private readonly ICompilerServerHost _compilerServerHost;

65 66 67 68 69 70 71
        /// <summary>
        /// Directory holding the command line executable.  It will be the same directory as the
        /// response file.
        /// </summary>
        private readonly string _clientDirectory;

        public CompilerRunHandler(ICompilerServerHost compilerServerHost, string clientDirectory)
72 73
        {
            _compilerServerHost = compilerServerHost;
74
            _clientDirectory = clientDirectory;
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
        }

        /// <summary>
        /// An incoming request as occurred. This is called on a new thread to handle
        /// the request.
        /// </summary>
        public RunResult HandleRequest(RunRequest req, CancellationToken cancellationToken)
        {
            switch (req.Language)
            {
                case LanguageNames.CSharp:
                    _compilerServerHost.Log("Request to compile C#");
                    return RunCompile(req, CreateCSharpCompiler, cancellationToken);

                case LanguageNames.VisualBasic:
                    _compilerServerHost.Log("Request to compile VB");
                    return RunCompile(req, CreateBasicCompiler, cancellationToken);

                default:
                    // We can't do anything with a request we don't know about. 
                    _compilerServerHost.Log($"Got request with id '{req.Language}'");
                    return new RunResult(RunResultKind.BadLanguage);
            }
        }

        /// <summary>
        /// A request to compile C# files. Unpack the arguments and current directory and invoke
        /// the compiler, then create a response with the result of compilation.
        /// </summary>
        private RunResult RunCompile(RunRequest request, Func<RunRequest, CommonCompiler> func,  CancellationToken cancellationToken)
        {
            _compilerServerHost.Log($"CurrentDirectory = '{request.CurrentDirectory}'");
            _compilerServerHost.Log($"LIB = '{request.LibDirectory}'");
            for (int i = 0; i < request.Arguments.Length; ++i)
            {
                _compilerServerHost.Log($"Argument[{i}] = '{request.Arguments[i]}'");
            }

            var compiler = func(request);
            bool utf8output = compiler.Arguments.Utf8Output;
            if (!_compilerServerHost.CheckAnalyzers(request.CurrentDirectory, compiler.Arguments.AnalyzerReferences))
            {
                return new RunResult(RunResultKind.BadAnalyzer);
            }

            _compilerServerHost.Log($"****Running {request.Language} compiler...");
            TextWriter output = new StringWriter(CultureInfo.InvariantCulture);
            int returnCode = compiler.Run(output, cancellationToken);
            _compilerServerHost.Log($"****{request.Language} Compilation complete.\r\n****Return code: {returnCode}\r\n****Output:\r\n{output.ToString()}\r\n");
            return new RunResult(returnCode, utf8output, output.ToString());
        }

        private CommonCompiler CreateCSharpCompiler(RunRequest request)
        {
129 130 131 132 133 134 135 136
            return new CSharpCompilerServer(
                _compilerServerHost,
                request.Arguments,
                _clientDirectory,
                request.CurrentDirectory,
                _compilerServerHost.GetSdkDirectory(),
                request.LibDirectory,
                _compilerServerHost.AnalyzerAssemblyLoader);
137 138 139 140
        }

        private CommonCompiler CreateBasicCompiler(RunRequest request)
        {
141 142 143 144 145 146 147 148
            return new VisualBasicCompilerServer(
                _compilerServerHost,
                request.Arguments,
                _clientDirectory,
                request.CurrentDirectory,
                _compilerServerHost.GetSdkDirectory(),
                request.LibDirectory,
                _compilerServerHost.AnalyzerAssemblyLoader);
149 150 151
        }
    }
}