Skip to content

Commit

Permalink
Merge pull request #14 from gooormmoon/feature/compile2/GRTEAM-7
Browse files Browse the repository at this point in the history
feat: compile & execute ( GRTEAM-132 )
  • Loading branch information
sshinylee authored Jun 14, 2024
2 parents 7276320 + 5e31def commit bb1b6d0
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 0 deletions.
39 changes: 39 additions & 0 deletions algofi-compile/Dockerfile.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 빌드 이미지로 OpenJDK 17 & Gradle을 지정
FROM gradle:7.6.1-jdk17 AS build

# 소스코드를 복사할 작업 디렉토리를 생성
WORKDIR /app

# 라이브러리 설치에 필요한 파일만 복사
COPY build.gradle settings.gradle ./

# gradle dependencies를 실행하여 의존성 설치
RUN gradle dependencies --no-daemon

# 호스트 머신의 소스코드를 작업 디렉토리로 복사
COPY . /app

# Gradle 빌드를 실행하여 JAR 파일 생성
RUN gradle clean build --no-daemon --stacktrace --info

# 런타임 이미지로 Amazon Corretto JDK 17 지정
FROM amazoncorretto:17

# 애플리케이션을 실행할 작업 디렉토리를 생성
WORKDIR /app

# 추가 패키지 설치 (컴파일 도구 포함)
RUN yum update -y && \
yum install -y gcc gcc-c++ make \
python3 python3-pip \
nodejs npm && \
yum clean all

# 빌드 이미지에서 생성된 JAR 파일을 런타임 이미지로 복사
COPY --from=build /app/build/libs/*.jar /app/algofi.jar

# 9999 포트를 외부에 노출
EXPOSE 9999

# 컨테이너 실행 시 자바 애플리케이션 실행
ENTRYPOINT ["java", "-jar", "algofi.jar"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package gooroommoon.algofi_compile.api;

public class CheckoutApiController {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package gooroommoon.algofi_compile.api;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import gooroommoon.algofi_compile.dto.CodeExecutionRequest;
import org.springframework.http.HttpStatus;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@RestController
@RequestMapping("/api/compile")
public class CompileApiController {
@PostMapping
public ResponseEntity<String> compile(@RequestBody CodeExecutionRequest request) {
try {
String result = runCode(request.getCode(), request.getLanguage());
return ResponseEntity.ok(result);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error in code execution: " + e.getMessage());
}
}

private String runCode(String code, String language) throws IOException, InterruptedException {
String fileName = "temp";
ProcessBuilder builder = new ProcessBuilder();

switch (language.toLowerCase()) {
case "c":
Path cFilePath = Paths.get("temp." + language.toLowerCase());
Files.write(cFilePath, code.getBytes());

builder.command("sh", "-c", "gcc " + cFilePath.toString() + " -o temp && ./temp"); //linux 버전
//builder.command("cmd.exe", "/c", "gcc " + cFilePath.toString() + " -o temp && temp"); //windows 버전
break;

case "java":
int classIndex = code.indexOf("public class ");
if (classIndex != -1) {
int startIndex = classIndex + "public class ".length();
int endIndex = code.indexOf(" ", startIndex);
if (endIndex != -1) {
fileName = code.substring(startIndex, endIndex);
}
}

Path javaFilePath = Paths.get(fileName + "." + language.toLowerCase());
Files.write(javaFilePath, code.getBytes());

String className = javaFilePath.toString().replace(".java", "");
//builder.command("cmd.exe", "/c", "javac " + javaFilePath.toString() + " && java " + className); //windows 버전
builder.command("sh", "-c", "javac " + javaFilePath.toString() + " && java " + className); //linux 버전
break;

case "javascript":
Path jsFilePath = Paths.get("temp." + language.toLowerCase());
Files.write(jsFilePath, code.getBytes());

//builder.command("cmd.exe", "/c", "node " + jsFilePath.toString()); //windows 버전
builder.command("sh", "-c", "node " + jsFilePath.toString()); //linux 버전

break;
case "python":
Path pyFilePath = Paths.get("temp." + language.toLowerCase());
Files.write(pyFilePath, code.getBytes());

//builder.command("cmd.exe", "/c", "python " + pyFilePath.toString()); //windows 버전
builder.command("sh", "-c", "python " + pyFilePath.toString()); //linux 버전

break;
default:
throw new IllegalArgumentException("Unsupported language: " + language);
}

builder.redirectErrorStream(true);
Process process = builder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
StringBuilder output = new StringBuilder();
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}

int exitCode = process.waitFor();
if (exitCode != 0) {
throw new RuntimeException("Execution failed with exit code " + exitCode);
}
return output.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package gooroommoon.algofi_compile.dto;

public class CodeExecutionRequest {
private String code; // 실행할 코드
private String language; // 코드의 프로그래밍 언어

// 기본 생성자
public CodeExecutionRequest() {
}

// 매개변수가 있는 생성자
public CodeExecutionRequest(String code, String language) {
this.code = code;
this.language = language;
}

// code 필드의 getter
public String getCode() {
return code;
}

// code 필드의 setter
public void setCode(String code) {
this.code = code;
}

// language 필드의 getter
public String getLanguage() {
return language;
}

// language 필드의 setter
public void setLanguage(String language) {
this.language = language;
}

@Override
public String toString() {
return "CodeExecutionRequest{" +
"code='" + code + '\'' +
", language='" + language + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package gooroommoon.algofi_compile.api;

import gooroommoon.algofi_compile.dto.CodeExecutionRequest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;

import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest
class CompileApiControllerTest {

@Autowired
private CompileApiController compileApiController;

@Test
public void testPythonExecution() throws Exception {
String pythonCode = "print('Hello, Python')";
ResponseEntity<String> response = compileApiController.compile(new CodeExecutionRequest(pythonCode, "python"));
assertEquals("Hello, Python\n", response.getBody());
}

@Test
public void testJavaExecution() throws Exception {
String javaCode = "public class Main { public static void main(String[] args) { System.out.println(\"Hello, Java\"); } }";
ResponseEntity<String> response = compileApiController.compile(new CodeExecutionRequest(javaCode, "java"));
assertEquals("Hello, Java\n", response.getBody());
}

@Test
public void testCExecution() throws Exception {
String cCode = "#include <stdio.h>\nint main() {\nprintf(\"Hello, C\\n\");\nreturn 0;\n}";
ResponseEntity<String> response = compileApiController.compile(new CodeExecutionRequest(cCode, "c"));
assertEquals("Hello, C\n", response.getBody());
}

@Test
public void testJavascriptExecution() throws Exception {
String javascriptCode = "console.log('Hello, JavaScript')";
ResponseEntity<String> response = compileApiController.compile(new CodeExecutionRequest(javascriptCode, "javascript"));
assertEquals("Hello, JavaScript\n", response.getBody());
}
}

0 comments on commit bb1b6d0

Please sign in to comment.