2022-04-23 18:41:14 +02:00
|
|
|
import { execaCommand } from 'execa'
|
2021-06-09 20:31:45 +02:00
|
|
|
import ora from 'ora'
|
2021-12-07 11:35:47 +01:00
|
|
|
import ms from 'ms'
|
2021-06-09 20:31:45 +02:00
|
|
|
|
2021-12-07 11:35:47 +01:00
|
|
|
export class Docker {
|
2021-11-30 21:42:43 +01:00
|
|
|
static CONTAINER_TAG = 'programming-challenges'
|
2021-12-06 19:04:16 +01:00
|
|
|
static SIGSEGV_EXIT_CODE = 139
|
2021-12-07 11:35:47 +01:00
|
|
|
static MAXIMUM_TIMEOUT = '1 minute'
|
|
|
|
static MAXIMUM_TIMEOUT_MILLISECONDS = ms(Docker.MAXIMUM_TIMEOUT)
|
2021-11-30 21:42:43 +01:00
|
|
|
|
2022-04-24 20:27:51 +02:00
|
|
|
public async build(): Promise<void> {
|
2021-06-09 20:31:45 +02:00
|
|
|
const loader = ora('Building the Docker image').start()
|
|
|
|
try {
|
2022-04-23 18:41:14 +02:00
|
|
|
await execaCommand(`docker build --tag=${Docker.CONTAINER_TAG} ./`)
|
2021-06-09 20:31:45 +02:00
|
|
|
loader.stop()
|
|
|
|
} catch (error) {
|
|
|
|
loader.fail()
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-24 20:27:51 +02:00
|
|
|
public async run(input: string): Promise<string> {
|
2022-04-23 18:41:14 +02:00
|
|
|
const subprocess = execaCommand(
|
2021-11-30 21:42:43 +01:00
|
|
|
`docker run --interactive --rm ${Docker.CONTAINER_TAG}`,
|
2021-06-09 20:31:45 +02:00
|
|
|
{
|
|
|
|
input
|
|
|
|
}
|
|
|
|
)
|
2021-12-07 11:35:47 +01:00
|
|
|
let isValid = true
|
|
|
|
const timeout = setTimeout(() => {
|
|
|
|
subprocess.kill()
|
|
|
|
isValid = false
|
|
|
|
}, Docker.MAXIMUM_TIMEOUT_MILLISECONDS)
|
2021-12-06 19:04:16 +01:00
|
|
|
try {
|
|
|
|
const { stdout, stderr } = await subprocess
|
|
|
|
if (stderr.length !== 0) {
|
|
|
|
throw new Error(stderr)
|
|
|
|
}
|
2021-12-07 11:35:47 +01:00
|
|
|
clearTimeout(timeout)
|
2021-12-06 19:04:16 +01:00
|
|
|
return stdout
|
|
|
|
} catch (error: any) {
|
2021-12-07 11:35:47 +01:00
|
|
|
if (!isValid) {
|
2022-04-24 20:27:51 +02:00
|
|
|
throw new Error(
|
|
|
|
`Timeout: time limit exceeded (${Docker.MAXIMUM_TIMEOUT}), try to optimize your solution.`
|
|
|
|
)
|
2021-12-07 11:35:47 +01:00
|
|
|
}
|
2021-12-06 19:04:16 +01:00
|
|
|
if (error.exitCode === Docker.SIGSEGV_EXIT_CODE) {
|
2022-04-24 20:27:51 +02:00
|
|
|
throw new Error(
|
|
|
|
"Docker run failed: SIGSEGV indicates a segmentation fault (attempts to access a memory location that it's not allowed to access)."
|
|
|
|
)
|
2021-12-06 19:04:16 +01:00
|
|
|
}
|
|
|
|
throw new Error(`Docker run failed: ${error.message as string}`)
|
2021-06-09 20:31:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const docker = new Docker()
|