private async Task UploadCompiledFiles( int number, CompilationRequest request ) { Log.Info("Uploading compiled files..."); string[] filesToUpload = { "backend.dll", "backend.pdb" }; string ga = request.GameId.Substring(0, 2); foreach (string file in filesToUpload) { Log.Debug($"Uploading '{file}'..."); await s3Client.PutObjectAsync( new PutObjectRequest { FilePath = $"compilation/{number}/{file}", BucketName = bucket, Key = $"games/{ga}/{request.GameId}/backends/" + $"{request.BackendId}/{file}" } ); } }
private async Task UploadCompilerOutput( CompilationRequest request, string compilerOutput ) { Log.Info("Uploading compiler output..."); string ga = request.GameId.Substring(0, 2); byte[] buffer = Encoding.UTF8.GetBytes(compilerOutput); var stream = new MemoryStream(buffer); await s3Client.PutObjectAsync( new PutObjectRequest { InputStream = stream, BucketName = bucket, Key = $"games/{ga}/{request.GameId}/backends/" + $"{request.BackendId}/compiler-output.log" } ); }
private async Task <CompilationResponse> CompileBackend( CompilationRequest request, HttpListenerRequest _ ) { request.Validate(); try { var response = await compiler.CompileBackend(request); compilationCrashesInRow = 0; return(response); } catch { // validation errors don't count as they go around compilationCrashesInRow++; throw; } }
public async Task <CompilationResponse> CompileBackend( CompilationRequest request ) { var sw = new Stopwatch(); sw.Start(); int number = counter.GetNext(); Log.Info($"Starting compilation number {number}, of backend " + $"{request.BackendId} for game {request.GameId}..."); await frameworkRepository.PrepareFramework(request.FrameworkVersion); PrepareCompilationDirectory(number); await DownloadBackendFiles(number, request.GameId, request.Files); var response = await RunTheCscCompiler(number, request); await UploadCompilerOutput(request, response.Output); if (response.Success) { await UploadCompiledFiles(number, request); } RemoveCompilationDirectory(number); sw.Stop(); double secs = Math.Round(sw.Elapsed.TotalSeconds, 3); Log.Info($"Compilation number {number} has finished in {secs} seconds!"); return(response); }
private Task <CompilationResponse> RunTheCscCompiler( int number, CompilationRequest request ) { // === prepare process parameters === string cscArguments = string.Join( " ", GetCompilerArguments(number, request) ); var proc = new Process { EnableRaisingEvents = true, StartInfo = { UseShellExecute = false, FileName = "csc", Arguments = cscArguments, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true } }; // === compiler output logging === const int maxCompilerOutput = 1024 * 1024; // 1 MB var compilerOutput = new StringBuilder( capacity: 1024 * 10, // 10 KB maxCapacity: maxCompilerOutput ); proc.OutputDataReceived += (s, e) => { compilerOutput.AppendLine(e.Data); }; proc.ErrorDataReceived += (s, e) => { compilerOutput.AppendLine(e.Data); }; // === result handling === var tcs = new TaskCompletionSource <CompilationResponse>(); proc.Exited += (sender, args) => { bool success = proc.ExitCode == 0; var output = new CompilationResponse { Success = success, Output = compilerOutput.ToString(), Message = success ? "Compilation was successful." : "Compilation error." }; proc.Dispose(); tcs.SetResult(output); }; // === bootstrap === proc.Start(); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); return(tcs.Task); }
private IEnumerable <string> GetCompilerArguments( int number, CompilationRequest request ) { string compilationPath = $"compilation/{number}"; // === constant flags === yield return("-target:library"); yield return("-platform:anycpu"); yield return("-optimize+"); yield return("-utf8output"); // output file yield return($"-out:{compilationPath}/backend.dll"); // generate .pdb file yield return("-debug+"); yield return($"-pdb:{compilationPath}/backend.pdb"); // source code path mapping yield return("-fullpaths"); yield return($"-pathmap:{compilationPath}=[Server]"); // === user-specified flags === // TODO: .NET version stuff // (see the README.md section to learn more) yield return("-checked" + (request.Checked ? '+' : '-')); yield return("-unsafe" + (request.Unsafe ? '+' : '-')); yield return("-langversion:" + request.LangVersion); // Possible extensions in the future: // - warn as error // - disable specific warns // - other compiler flags // === #define preprocessor symbols === foreach (string symbol in request.DefineSymbols) { yield return("-define:" + symbol); } // === references === // Unisave Framework references var frameworkRefs = frameworkRepository.GetFrameworkReferences( request.FrameworkVersion ); foreach (string r in frameworkRefs) { yield return(r); } // .dll libraries within the backend files foreach (var file in request.Files) { if (Path.GetExtension(file.path)?.ToLowerInvariant() == ".dll") { yield return($"-reference:{compilationPath}/{file.path}"); } } // === source code files === foreach (var file in request.Files) { if (Path.GetExtension(file.path)?.ToLowerInvariant() == ".cs") { yield return($"{compilationPath}/{file.path}"); } } }