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); } }