diff --git a/src/LiquidCode.Tester.Worker/Services/KotlinCompilationServiceIsolate.cs b/src/LiquidCode.Tester.Worker/Services/KotlinCompilationServiceIsolate.cs index 781ec9a..a3160a6 100644 --- a/src/LiquidCode.Tester.Worker/Services/KotlinCompilationServiceIsolate.cs +++ b/src/LiquidCode.Tester.Worker/Services/KotlinCompilationServiceIsolate.cs @@ -15,7 +15,7 @@ public class KotlinCompilationServiceIsolate : ICompilationService private readonly IsolateBoxPool _boxPool; private const int CompilationTimeLimitSeconds = 30; - private const int CompilationMemoryLimitMb = 512; + private const int CompilationMemoryLimitMb = 1024; // Kotlin uses JVM, needs more memory public KotlinCompilationServiceIsolate( ILogger logger, @@ -39,7 +39,21 @@ public class KotlinCompilationServiceIsolate : ICompilationService try { - await File.WriteAllTextAsync(sourceFilePath, sourceCode); + // Normalize line endings + var normalizedSourceCode = sourceCode + .Replace("\\r\\n", "\n") // Handle escaped \r\n (literal text "\\r\\n") + .Replace("\\n", "\n") // Handle escaped \n (literal text "\\n") + .Replace("\\r", "\n") // Handle escaped \r (literal text "\\r") + .Replace("\r\n", "\n") // Handle actual Windows line endings + .Replace("\r", "\n"); // Handle actual Mac line endings + + _logger.LogDebug("Source code length: {Length}, normalized length: {NormalizedLength}, line count: {LineCount}", + sourceCode.Length, normalizedSourceCode.Length, normalizedSourceCode.Split('\n').Length); + + _logger.LogDebug("First 200 chars of source: {Preview}", + normalizedSourceCode.Length > 200 ? normalizedSourceCode.Substring(0, 200) : normalizedSourceCode); + + await File.WriteAllTextAsync(sourceFilePath, normalizedSourceCode); return await CompileFileInIsolateAsync(sourceFilePath, jarFilePath, version); } catch (Exception ex) @@ -89,6 +103,7 @@ public class KotlinCompilationServiceIsolate : ICompilationService arguments.Add($"/box/{jarFileName}"); var stderrFilePath = Path.Combine(boxDir, "compile_stderr.txt"); + var stdoutFilePath = Path.Combine(boxDir, "compile_stdout.txt"); var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions { @@ -98,9 +113,10 @@ public class KotlinCompilationServiceIsolate : ICompilationService TimeLimitSeconds = CompilationTimeLimitSeconds, WallTimeLimitSeconds = CompilationTimeLimitSeconds * 2, MemoryLimitKb = CompilationMemoryLimitMb * 1024, - StackLimitKb = 256 * 1024, - ProcessLimit = 10, + StackLimitKb = 128 * 1024, // 128MB stack per process + ProcessLimit = 64, // Kotlin uses JVM, needs many threads/processes EnableNetwork = false, + StdoutFile = stdoutFilePath, StderrFile = stderrFilePath, WorkingDirectory = "/box", DirectoryBindings = new List @@ -120,13 +136,34 @@ public class KotlinCompilationServiceIsolate : ICompilationService }); var compilerOutput = string.Empty; + + // Read stdout (kotlinc may output errors there) + if (File.Exists(stdoutFilePath)) + { + var stdoutContent = await File.ReadAllTextAsync(stdoutFilePath); + if (!string.IsNullOrWhiteSpace(stdoutContent)) + { + compilerOutput = stdoutContent; + } + } + + // Read stderr if (File.Exists(stderrFilePath)) { - compilerOutput = await File.ReadAllTextAsync(stderrFilePath); + var stderrContent = await File.ReadAllTextAsync(stderrFilePath); + if (!string.IsNullOrWhiteSpace(stderrContent)) + { + compilerOutput = string.IsNullOrEmpty(compilerOutput) + ? stderrContent + : $"{compilerOutput}\n{stderrContent}"; + } } + if (!string.IsNullOrEmpty(isolateResult.ErrorOutput)) { - compilerOutput = $"{compilerOutput}\n{isolateResult.ErrorOutput}".Trim(); + compilerOutput = string.IsNullOrEmpty(compilerOutput) + ? isolateResult.ErrorOutput + : $"{compilerOutput}\n{isolateResult.ErrorOutput}"; } if (isolateResult.TimeLimitExceeded)