Example #1
0
            private void HandleMessage(string message)
            {
                if (!((message.StartsWith("{", StringComparison.Ordinal) &&
                       message.EndsWith("}", StringComparison.Ordinal)) || //For object
                      (message.StartsWith("[", StringComparison.Ordinal) &&
                       message.EndsWith("]", StringComparison.Ordinal))))  //For array
                {
                    return;
                }

                CMakeMessage parsed = CMakeMessage.Parse <CMakeMessage>(message, throwJsonException: false);

                if (parsed is CMakeMessageMessage messageMessage)
                {
                    if (messageMessage.Title.Contains("warning", StringComparison.OrdinalIgnoreCase))
                    {
                        wrappedUserInterface.WriteWarning(messageMessage.Message);
                    }
                    else if (messageMessage.Title.Contains("error", StringComparison.OrdinalIgnoreCase) ||
                             messageMessage.Title.Contains("exception", StringComparison.OrdinalIgnoreCase))
                    {
                        wrappedUserInterface.WriteError(messageMessage.Message);
                    }
                }

                log.LogVerbose($"Received message from cmake server:{Environment.NewLine}" +
                               $"{message}");
            }
        public static async Task <CMakeConversation> Start(IProcessManager processManager,
                                                           IBinariesLocator binariesLocator,
                                                           IOutputFormatterPool formatterPool,
                                                           VirtualDirectory tempDirectory, bool isWindowsSystem,
                                                           ExecutionContext executionContext,
                                                           VirtualDirectory sourceDirectory,
                                                           VirtualDirectory binaryDirectory)
        {
            IProcess process = null;
            NamedPipeClientStream pipeClient = null;

            try
            {
                string pipeName = isWindowsSystem
                                      ? $"{tempDirectory.FullName}\\.cmakeserver"
                                      : $"/tmp/cmake-server-{Guid.NewGuid().ToByteString()}";
                string serverCommand = isWindowsSystem
                                           ? $"-E server --experimental --pipe=\"\\\\?\\pipe\\{pipeName}\""
                                           : $"-E server --experimental --pipe={pipeName}";
                process    = processManager.StartProcess(binariesLocator.GetExecutableCommand("cmake"), serverCommand, executionContext);
                pipeClient = new NamedPipeClientStream(".", pipeName,
                                                       PipeDirection.InOut, PipeOptions.Asynchronous,
                                                       TokenImpersonationLevel.Impersonation);
                pipeClient.Connect(CMakeServerTimeout);
                if (!pipeClient.IsConnected)
                {
                    throw new FormattableException("Could not connect to server");
                }

                FormatterParameters parameters = new FormatterParameters();
                parameters.Add("cmake-json", MessageFormat);
                IUserInterface jsonCmakeInterface = formatterPool.GetFormatter(parameters, executionContext);

                CMakeServerStream serverStream = new CMakeServerStream(pipeClient, executionContext);
                CMakeHelloMessage hello        = null;
                do
                {
                    foreach (string singleMessage in await serverStream.ReadMessage()
                             .TimeoutAfter(CMakeServerTimeout)
                             .ConfigureAwait(false))
                    {
                        hello = CMakeMessage.Parse <CMakeMessage>(singleMessage, jsonCmakeInterface) as CMakeHelloMessage;
                    }
                } while (hello == null);

                if (hello.SupportedProtocolVersions.All(v => v.Major != 1))
                {
                    throw new FormattableException("CMake server does not support the protocol version 1.X. " +
                                                   $"Supported versions are {string.Join(", ", hello.SupportedProtocolVersions)}");
                }

                CMakeConversation conversation = new CMakeConversation(process, pipeClient, serverStream, jsonCmakeInterface);

                await conversation.Handshake(sourceDirectory.FullName.Replace('\\', '/'),
                                             binaryDirectory.FullName.Replace('\\', '/'))
                .ConfigureAwait(false);

                await conversation.Configure().ConfigureAwait(false);

                return(conversation);
            }
            catch (Exception)
            {
                pipeClient?.Dispose();
                process?.Dispose();
                throw;
            }
        }
        private async Task <CMakeReplyMessage> WaitForReply(string type)
        {
            CMakeProgressMessage progressMessage = null;
            CMakeMessageMessage  messageMessage  = null;
            CMakeMessage         message         = null;

            do
            {
                foreach (string singleMessage in await serverStream.ReadMessage()
                         .TimeoutAfter(CMakeServerTimeout)
                         .ConfigureAwait(false))
                {
                    //Expect at least a progress message after default timeout
                    message = ParseMessage(singleMessage);
                    if (message is CMakeReplyMessage replyMessage)
                    {
                        CheckCookieAndType(replyMessage);
                        return(replyMessage);
                    }
                }
            } while (progressMessage != null ||
                     messageMessage != null ||
                     message == null);

            throw new InvalidOperationException("This is not possible.");

            void CheckCookieAndType(CMakeBaseResponseMessage responseMessage)
            {
                if (!string.IsNullOrEmpty(cookie) &&
                    responseMessage.Cookie != cookie)
                {
                    throw new FormattableException($"Expected a message with the cookie {cookie}, " +
                                                   $"but got a message with the cookie {responseMessage.Cookie}. " +
                                                   "Someone else is taking to the server unexpectedly.");
                }

                if (responseMessage.ResponseType != type)
                {
                    throw new FormattableException($"Expected a message in response to {type}, " +
                                                   $"but got a message in response to {responseMessage.ResponseType}. " +
                                                   "Someone else is taking to the server unexpectedly " +
                                                   "or the server is confusing.");
                }
            }

            CMakeMessage ParseMessage(string singleMessage)
            {
                CMakeMessage parsedMessage = CMakeMessage.Parse <CMakeMessage>(singleMessage, userInterface);

                progressMessage = parsedMessage as CMakeProgressMessage;
                messageMessage  = parsedMessage as CMakeMessageMessage;
                if (messageMessage != null)
                {
                    CheckCookieAndType(messageMessage);
                    if (messageMessage.Title.Contains("error", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new FormattableException($"CMake discovered an error.{Environment.NewLine}" +
                                                       $"{messageMessage.Title}{Environment.NewLine}" +
                                                       $"==================================={Environment.NewLine}" +
                                                       $"{messageMessage.Message}");
                    }
                }

                return(parsedMessage);
            }
        }