feat: deploy support

This commit is contained in:
Paul Pan 2023-08-11 18:54:00 +08:00
parent 87d5506085
commit 1365e54aec
Signed by: Paul
GPG Key ID: D639BDF5BA578AF4
22 changed files with 405 additions and 244 deletions

8
.dockerignore Normal file
View File

@ -0,0 +1,8 @@
# top
/woj
# runner
resource/runner/.mark.container
resource/runner/problem/*
resource/runner/tmp/*
resource/runner/user/*

25
.idea/jsonSchemas.xml Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JsonSchemaMappingsProjectConfiguration">
<state>
<map>
<entry key="docker-compose.yml">
<value>
<SchemaInfo>
<option name="name" value="docker-compose.yml" />
<option name="relativePathToSchema" value="https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json" />
<option name="applicationDefined" value="true" />
<option name="patterns">
<list>
<Item>
<option name="path" value="docker-compose.yml" />
</Item>
</list>
</option>
</SchemaInfo>
</value>
</entry>
</map>
</state>
</component>
</project>

View File

@ -1,8 +1,12 @@
GO := go GO := go
LDFLAGS += -X cmd.BuildTime=$(shell date -u '+%Y-%m-%d-%I-%M-%S') PKG_BASE := $(shell head -n 1 go.mod | awk '{print $$2}')
LDFLAGS += -X cmd.Version=$(shell cat VERSION)+$(shell git rev-parse --short HEAD) BUILD_TIME := $(shell date -u '+%Y%m%d-%I%M%S')
LDFLAGS += -X cmd.SentryDSN=$(shell cat dsn.txt) VERSION := $(shell cat VERSION)+$(shell git rev-parse --short HEAD)
LDFLAGS += -X $(PKG_BASE)/cmd.BuildTime=$(BUILD_TIME)
LDFLAGS += -X $(PKG_BASE)/cmd.Version=$(VERSION)
LDFLAGS += -X $(PKG_BASE)/cmd.SentryDSN=$(shell cat dsn.txt)
LDFLAGS += -s -w LDFLAGS += -s -w
GOBUILD := $(GO) build -ldflags '$(LDFLAGS)' GOBUILD := $(GO) build -ldflags '$(LDFLAGS)'
@ -18,8 +22,7 @@ build: swagger dep
$(GOBUILD) -o woj ./cmd/woj $(GOBUILD) -o woj ./cmd/woj
clean: clean:
rm -f runner rm -f woj
rm -f server
dep: dep:
go mod download go mod download

35
Runner.Dockerfile Normal file
View File

@ -0,0 +1,35 @@
# builder
FROM docker.io/library/golang:alpine AS builder
ENV GOPROXY=https://goproxy.cn
WORKDIR /builder
RUN apk add --no-cache git make
RUN go install github.com/swaggo/swag/cmd/swag@latest
COPY go.mod /builder/go.mod
COPY go.sum /builder/go.sum
RUN go mod download
COPY . /builder
RUN make build
# main image
FROM quay.io/podman/stable
# pkill
RUN yum -y install jq procps-ng && yum -y clean all && rm -rf /var/cache
WORKDIR /app
# prepare images
COPY --from=builder /builder/resource/runner /app/resource/runner
RUN bash -c "cd /app/resource/runner/scripts && ./prepare_images.sh save"
# sources
COPY --from=builder /builder/config.docker.yaml /app
COPY --from=builder /builder/docker-entrypoint.sh /app
COPY --from=builder /builder/woj /app
ENTRYPOINT ["/app/docker-entrypoint.sh"]

View File

@ -1,5 +1,5 @@
# builder # builder
FROM golang:alpine AS builder FROM docker.io/library/golang:alpine AS builder
ENV GOPROXY=https://goproxy.cn ENV GOPROXY=https://goproxy.cn
WORKDIR /builder WORKDIR /builder
@ -16,16 +16,14 @@ RUN make build
# main image # main image
FROM alpine:latest FROM docker.io/library/alpine
WORKDIR /app WORKDIR /app
RUN apk --no-cache add tzdata ca-certificates libc6-compat RUN apk --no-cache add tzdata ca-certificates libc6-compat bash
COPY --from=builder /builder/config.docker.yaml /app COPY --from=builder /builder/config.docker.yaml /app
COPY --from=builder /builder/docker-entrypoint.sh /app COPY --from=builder /builder/docker-entrypoint.sh /app
COPY --from=builder /builder/resource/frontend /app/resource/frontend COPY --from=builder /builder/resource/frontend /app/resource/frontend
COPY --from=builder /builder/resource/runner /app/resource/runner
COPY --from=builder /builder/woj /app COPY --from=builder /builder/woj /app
ENTRYPOINT ["/app/docker-entrypoint.sh"] ENTRYPOINT ["/app/docker-entrypoint.sh"]

57
build_image.sh Executable file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env bash
. resource/runner/scripts/common.sh
# version
VERSION="$(cat VERSION)"
log_info "VERSION: $VERSION"
function build_base() {
log_info "[+] Building Base Images"
pushd resource/runner/scripts || exit 1
$DOCKER build -t git.0x7f.app/woj/ubuntu-full:latest -f scripts/ubuntu-full.Dockerfile . ||
(log_error "Build Full Image failed" && exit 1)
$DOCKER build -t git.0x7f.app/woj/ubuntu-run:latest -f scripts/ubuntu-run.Dockerfile . ||
(log_error "Build Tiny Image failed" && exit 1)
popd
}
function push_base() {
log_info "[+] Pushing Base Images"
$DOCKER push "git.0x7f.app/woj/ubuntu-full:latest"
$DOCKER push "git.0x7f.app/woj/ubuntu-run:latest"
}
function build_server() {
log_info "[+] Building Server"
$DOCKER build -t "git.0x7f.app/woj/woj-server:$VERSION" -f Server.Dockerfile . ||
(log_error "[!] Failed to build Server" && exit 1)
}
function build_runner() {
log_info "[+] Building Runner"
$DOCKER build \
--cap-add=sys_admin,mknod \
--device=/dev/fuse \
--security-opt label=disable \
-t "git.0x7f.app/woj/woj-runner:$VERSION" \
-f Runner.Dockerfile . ||
(log_error "[!] Failed to build Runner" && exit 1)
}
function push_server() {
log_info "[+] Pushing Server Images"
$DOCKER push "git.0x7f.app/woj/woj-server:$VERSION"
}
function push_runner() {
log_info "[+] Pushing Runner Images"
$DOCKER push "git.0x7f.app/woj/woj-runner:$VERSION"
}
# build_base
# push_base
build_server
push_server
build_runner
push_runner

View File

@ -59,7 +59,7 @@ func init() {
} }
func getBuildTime() time.Time { func getBuildTime() time.Time {
build, err := time.Parse("2006-01-02-15-04-05", BuildTime) build, err := time.Parse("20060102-150405", BuildTime)
if err != nil { if err != nil {
log.Printf("failed to parse build time: %v", err) log.Printf("failed to parse build time: %v", err)
build = time.Now() build = time.Now()

View File

@ -1,11 +1,9 @@
version: "3"
services: services:
server: server:
build: . image: git.0x7f.app/woj/woj-server:1.1.0
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: [ "CMD", "wget", "-q", "http://127.0.0.1:8000/health" ] test: [ "CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8000/health" ]
interval: 5s interval: 5s
command: web command: web
environment: environment:
@ -14,7 +12,7 @@ services:
- DATABASE_USER=dev - DATABASE_USER=dev
- DATABASE_PASSWORD=password - DATABASE_PASSWORD=password
- DATABASE_NAME=dev - DATABASE_NAME=dev
- STORAGE_ENDPOINT=minio:9000 - STORAGE_ENDPOINT=storage:9000
- STORAGE_ACCESS_KEY=access_key - STORAGE_ACCESS_KEY=access_key
- STORAGE_SECRET_KEY=secret_key - STORAGE_SECRET_KEY=secret_key
- STORAGE_BUCKET=woj - STORAGE_BUCKET=woj
@ -23,6 +21,8 @@ services:
- /etc/timezone:/etc/timezone:ro - /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
depends_on: depends_on:
runner:
condition: service_started
storage: storage:
condition: service_healthy condition: service_healthy
cache: cache:
@ -32,22 +32,36 @@ services:
ports: ports:
- "8000:8000" - "8000:8000"
#runner: runner:
# build: . image: git.0x7f.app/woj/woj-runner:1.1.0
# restart: unless-stopped restart: unless-stopped
# command: runner command: runner
# environment: security_opt:
# - REDIS_ADDRESS_PORT=cache:6379 - "label=disable"
# - DEVELOPMENT=true cap_add:
# volumes: - SYS_ADMIN
# - runner:/app/resource/runner/user - MKNOD
# - /etc/timezone:/etc/timezone:ro devices:
# - /etc/localtime:/etc/localtime:ro - "/dev/fuse"
# depends_on: environment:
# - cache - REDIS_ADDRESS_PORT=cache:6379
- STORAGE_ENDPOINT=storage:9000
- STORAGE_ACCESS_KEY=access_key
- STORAGE_SECRET_KEY=secret_key
- STORAGE_BUCKET=woj
- DEVELOPMENT=true
volumes:
- runner:/app/resource/runner/user
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
storage:
condition: service_healthy
cache:
condition: service_healthy
storage: storage:
image: minio/minio:latest image: quay.io/minio/minio:latest
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: [ "CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live" ] test: [ "CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live" ]
@ -55,13 +69,13 @@ services:
entrypoint: sh entrypoint: sh
command: -c 'mkdir -p /data/woj && minio server /data' command: -c 'mkdir -p /data/woj && minio server /data'
environment: environment:
MINIO_ACCESS_KEY: "access_key" MINIO_ROOT_USER: "access_key"
MINIO_SECRET_KEY: "secret_key" MINIO_ROOT_PASSWORD: "secret_key"
volumes: volumes:
- storage:/data - storage:/data
cache: cache:
image: redis:alpine image: docker.io/library/redis:alpine
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: [ "CMD", "redis-cli", "ping" ] test: [ "CMD", "redis-cli", "ping" ]
@ -70,7 +84,7 @@ services:
- cache:/data - cache:/data
db: db:
image: postgres:alpine image: docker.io/library/postgres:alpine
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: [ "CMD", "pg_isready", "-U", "dev" ] test: [ "CMD", "pg_isready", "-U", "dev" ]
@ -86,4 +100,4 @@ volumes:
runner: runner:
storage: storage:
cache: cache:
db: db:

View File

@ -1,4 +1,4 @@
#!/bin/ash #!/bin/bash
set -eo pipefail set -eo pipefail
COLOR_RED="\e[0;31m" COLOR_RED="\e[0;31m"

View File

@ -18,7 +18,7 @@ func (s *service) EnsureDeps(force bool) e.Status {
return e.Success return e.Success
} }
script := filepath.Join(ScriptsDir, "prepare_container.sh") script := filepath.Join(ScriptsDir, "prepare_images.sh")
cmd := exec.Command(script) cmd := exec.Command(script)
cmd.Dir = ScriptsDir cmd.Dir = ScriptsDir
err := cmd.Run() err := cmd.Run()

View File

@ -1,7 +1,4 @@
# docker image mark # docker image mark
.mark.* .mark.*
# tmp dockerfile
ubuntu-full.Dockerfile
ubuntu-run.Dockerfile
# other tmp files # other tmp files
*.zip *.zip

View File

@ -10,5 +10,8 @@ function log_warn() { echo -e "${COLOR_YELLOW}$*${COLOR_NONE}" 1>&2; }
function log_error() { echo -e "${COLOR_RED}$*${COLOR_NONE}" 1>&2; } function log_error() { echo -e "${COLOR_RED}$*${COLOR_NONE}" 1>&2; }
# Docker or Podman # Docker or Podman
DOCKER="docker" DOCKER="podman"
if [ "$USE_PODMAN" ]; then DOCKER="podman"; fi if [ "$USE_DOCKER" ]; then
log_error "docker is deprecated"
log_info "Use podman instead"
fi

View File

@ -1,59 +0,0 @@
#!/usr/bin/env bash
. common.sh
cd "$(dirname "$0")"/../ || exit 1
# Check Mark
if [ -f ./.mark.container ]; then
log_warn "Docker containers already prepared"
log_warn "If you want to re-prepare the containers, please remove the file $(pwd)/.mark.container"
exit 1
fi
log_info "Preparing container..."
log_info "Using $DOCKER - $($DOCKER --version)"
# Full
log_info "Building Full Image"
cat <<EOF >ubuntu-full.Dockerfile
FROM docker.io/library/ubuntu:22.04
WORKDIR /woj/
# Install dependencies
RUN apt-get update && apt-get upgrade -y && apt-get install -y gcc g++ clang make cmake autoconf m4 libtool gperf git parallel python3 && apt-get clean && rm -rf /var/lib/apt/lists
# Copy source code
RUN mkdir -p /woj/framework && mkdir -p /woj/problem
COPY framework /woj/framework
# Build
RUN cd /woj/framework/template && ./setup.sh
RUN cd /woj/framework/scripts && ./setup.sh
# Environment
ENV WOJ_LAUNCHER=/woj/framework/scripts/woj_launcher
ENV WOJ_SANDBOX=/woj/framework/scripts/libwoj_sandbox.so
ENV TEMPLATE=/woj/framework/template
ENV TESTLIB=/woj/framework/template/testlib
ENV PREFIX=/woj/problem
EOF
$DOCKER build -t woj/ubuntu-full -f ubuntu-full.Dockerfile . || exit 1
rm ubuntu-full.Dockerfile
# Tiny
log_info "Building Tiny Image"
cat <<EOF >ubuntu-run.Dockerfile
FROM woj/ubuntu-full:latest AS builder
FROM docker.io/library/ubuntu:22.04
WORKDIR /woj/problem
RUN mkdir -p /woj/framework/scripts
COPY --from=builder /woj/framework/scripts/libwoj_sandbox.so /woj/framework/scripts/
COPY --from=builder /woj/framework/scripts/woj_launcher /woj/framework/scripts/
EOF
$DOCKER build -t woj/ubuntu-run -f ubuntu-run.Dockerfile . || exit 1
rm ubuntu-run.Dockerfile
touch ./.mark.container
log_info "Done"

View File

@ -0,0 +1,52 @@
#!/usr/bin/env bash
. common.sh
cd "$(dirname "$0")"/../ || exit 1
# Check Mark
if [ -f ./.mark.image ]; then
log_warn "Docker images already prepared"
log_warn "If you want to re-prepare the images, please remove the file $(pwd)/.mark.image"
exit 1
fi
log_info "Preparing image..."
log_info "Checking $DOCKER - $($DOCKER --version)"
# Full
if [ -f ./tmp/ubuntu-full.tar.gz ]; then
log_info "Importing Full Image"
gzip -d -c ./tmp/ubuntu-full.tar.gz | $DOCKER load || (log_error "Import Full Image failed" && exit 1)
else
log_info "Pulling Full Image"
if ! $DOCKER pull git.0x7f.app/woj/ubuntu-full:latest; then
log_warn "Pull failed, building from scratch"
log_info "Building Full Image"
$DOCKER build -t git.0x7f.app/woj/ubuntu-full:latest -f scripts/ubuntu-full.Dockerfile . || (log_error "Build Full Image failed" && exit 1)
fi
fi
# Tiny
if [ -f ./tmp/ubuntu-tiny.tar.gz ]; then
log_info "Importing Tiny Image"
gzip -d -c ./tmp/ubuntu-tiny.tar.gz | $DOCKER load || (log_error "Import Tiny Image failed" && exit 1)
else
log_info "Pulling Tiny Image"
if ! $DOCKER pull git.0x7f.app/woj/ubuntu-run:latest; then
log_warn "Pull failed, building from scratch"
log_info "Building Tiny Image"
$DOCKER build -t git.0x7f.app/woj/ubuntu-run:latest -f scripts/ubuntu-run.Dockerfile . || (log_error "Build Tiny Image failed" && exit 1)
fi
fi
# Mark
if [ "$1" == "save" ]; then
log_info "Saving Images"
$DOCKER save git.0x7f.app/woj/ubuntu-full:latest | gzip -9 >./tmp/ubuntu-full.tar.gz
$DOCKER save git.0x7f.app/woj/ubuntu-run:latest | gzip -9 >./tmp/ubuntu-tiny.tar.gz
else
touch ./.mark.image
fi
log_info "Done"

View File

@ -9,67 +9,67 @@
# $3: language # $3: language
# exports: Info_Script, Info_Cmp, Info_Num, Info_Limit_Time, Info_Limit_Memory, Info_Limit_NProc # exports: Info_Script, Info_Cmp, Info_Num, Info_Limit_Time, Info_Limit_Memory, Info_Limit_NProc
function get_problem_info() { function get_problem_info() {
local err local err
if [ ! -f "$1/problem/$2/config.json" ]; then if [ ! -f "$1/problem/$2/config.json" ]; then
log_error "problem $2 not found" log_error "problem $2 not found"
return 1 return 1
fi fi
parse_language_info "$1" "$2" "$3" parse_language_info "$1" "$2" "$3"
err=$? err=$?
if [ "$err" -ne 0 ]; then if [ "$err" -ne 0 ]; then
return "$err" return "$err"
fi fi
parse_limits "$1" "$2" parse_limits "$1" "$2"
err=$? err=$?
if [ "$err" -ne 0 ]; then if [ "$err" -ne 0 ]; then
return "$err" return "$err"
fi fi
} }
function parse_language_info() { function parse_language_info() {
export Info_Script export Info_Script
export Info_Cmp export Info_Cmp
local lang_config local lang_config
local lang_type local lang_type
local lang_script local lang_script
lang_config=$(jq ".Languages[] | select(.Lang == \"$3\")" "$1/problem/$2/config.json") lang_config=$(jq ".Languages[] | select(.Lang == \"$3\")" "$1/problem/$2/config.json")
if [ -z "$lang_config" ]; then if [ -z "$lang_config" ]; then
log_error "language $3 is not supported" log_error "language $3 is not supported"
return 1 return 1
fi fi
Info_Cmp=$(echo "$lang_config" | jq -r ".Cmp") Info_Cmp=$(echo "$lang_config" | jq -r ".Cmp")
lang_type=$(echo "$lang_config" | jq -r ".Type") lang_type=$(echo "$lang_config" | jq -r ".Type")
lang_script=$(echo "$lang_config" | jq -r ".Script") lang_script=$(echo "$lang_config" | jq -r ".Script")
if [ "$lang_type" == "custom" ]; then if [ "$lang_type" == "custom" ]; then
Info_Script="/woj/problem/judge/$lang_script" Info_Script="/woj/problem/judge/$lang_script"
elif [ "$lang_type" == "default" ]; then elif [ "$lang_type" == "default" ]; then
Info_Script="/woj/framework/template/default/$3.Makefile" Info_Script="/woj/framework/template/default/$3.Makefile"
else else
log_warn "Config file might be corrupted!" log_warn "Config file might be corrupted!"
log_error "Unknown language type: $lang_type" log_error "Unknown language type: $lang_type"
return 1 return 1
fi fi
} }
function parse_limits() { function parse_limits() {
export Info_Limit_Time export Info_Limit_Time
export Info_Limit_Memory export Info_Limit_Memory
export Info_Limit_NProc export Info_Limit_NProc
export Info_Num export Info_Num
local cfg local cfg
cfg="$1/problem/$2/config.json" cfg="$1/problem/$2/config.json"
Info_Limit_Time=$(jq ".Runtime.TimeLimit" "$cfg") Info_Limit_Time=$(jq ".Runtime.TimeLimit" "$cfg")
Info_Limit_Memory=$(jq ".Runtime.MemoryLimit" "$cfg") Info_Limit_Memory=$(jq ".Runtime.MemoryLimit" "$cfg")
Info_Limit_NProc=$(jq ".Runtime.NProcLimit" "$cfg") Info_Limit_NProc=$(jq ".Runtime.NProcLimit" "$cfg")
Info_Num=$(jq ".Tasks | length" "$1/problem/$2/config.json") Info_Num=$(jq ".Tasks | length" "$1/problem/$2/config.json")
} }

View File

@ -6,8 +6,8 @@ WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
. "$WORKSPACE"/scripts/problem.sh . "$WORKSPACE"/scripts/problem.sh
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then
log_warn "Usage: $0 <problem> <user_dir> <language> <timeout>" log_warn "Usage: $0 <problem> <user_dir> <language> <timeout>"
exit 1 exit 1
fi fi
get_problem_info "$WORKSPACE" "$1" "$3" get_problem_info "$WORKSPACE" "$1" "$3"
@ -20,11 +20,11 @@ rm -f "$EXE_FILE" && touch "$EXE_FILE"
export TIMEOUT=${4:-60} export TIMEOUT=${4:-60}
docker_run \ docker_run \
-v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \ -v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \
-v "$SRC_FILE":/woj/problem/user/"$2"."$3":ro \ -v "$SRC_FILE":/woj/problem/user/"$2"."$3":ro \
-v "$EXE_FILE":/woj/problem/user/"$2".out \ -v "$EXE_FILE":/woj/problem/user/"$2".out \
-e USER_PROG="$2" \ -e USER_PROG="$2" \
-e LANG="$3" \ -e LANG="$3" \
woj/ubuntu-full \ git.0x7f.app/woj/ubuntu-full \
sh -c \ sh -c \
"cd /woj/problem/user && make -f $Info_Script compile" "cd /woj/problem/user && make -f $Info_Script compile"

View File

@ -6,35 +6,35 @@ WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
. "$WORKSPACE"/scripts/problem.sh . "$WORKSPACE"/scripts/problem.sh
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then
log_warn "Usage: $0 <problem> <user_dir> <language> <timeout>" log_warn "Usage: $0 <problem> <user_dir> <language> <timeout>"
exit 1 exit 1
fi fi
get_problem_info "$WORKSPACE" "$1" "$3" get_problem_info "$WORKSPACE" "$1" "$3"
export TIMEOUT=${4:-60} export TIMEOUT=${4:-60}
for test_num in $(seq "$Info_Num"); do for test_num in $(seq "$Info_Num"); do
std_file="$WORKSPACE/problem/$1/data/output/$test_num.output" std_file="$WORKSPACE/problem/$1/data/output/$test_num.output"
ans_file="$WORKSPACE/user/$2/$test_num.out.usr" ans_file="$WORKSPACE/user/$2/$test_num.out.usr"
jdg_file="$WORKSPACE/user/$2/$test_num.judge" jdg_file="$WORKSPACE/user/$2/$test_num.judge"
if [ ! -f "$std_file" ] || [ ! -f "$ans_file" ]; then if [ ! -f "$std_file" ] || [ ! -f "$ans_file" ]; then
log_error "Missing test case $test_num" log_error "Missing test case $test_num"
exit 1 exit 1
fi fi
log_info "Judging test case $test_num" log_info "Judging test case $test_num"
touch "$jdg_file" touch "$jdg_file"
docker_run \ docker_run \
-v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \ -v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \
-v "$WORKSPACE"/problem/"$1"/data:/woj/problem/data:ro \ -v "$WORKSPACE"/problem/"$1"/data:/woj/problem/data:ro \
-v "$ans_file":/woj/problem/user/"$test_num".out.usr \ -v "$ans_file":/woj/problem/user/"$test_num".out.usr \
-v "$jdg_file":/woj/problem/user/"$test_num".judge \ -v "$jdg_file":/woj/problem/user/"$test_num".judge \
-e TEST_NUM="$test_num" \ -e TEST_NUM="$test_num" \
-e CMP="$Info_Cmp" \ -e CMP="$Info_Cmp" \
woj/ubuntu-full \ git.0x7f.app/woj/ubuntu-full \
sh -c \ sh -c \
"cd /woj/problem/user && make -f $Info_Script judge" "cd /woj/problem/user && make -f $Info_Script judge"
done done

View File

@ -5,28 +5,28 @@ WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
. "$WORKSPACE"/scripts/common.sh . "$WORKSPACE"/scripts/common.sh
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ]; then if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ]; then
log_warn "Usage: $0 <problem> <timeout>" log_warn "Usage: $0 <problem> <timeout>"
exit 1 exit 1
fi fi
if [ -f "$WORKSPACE/problem/$1/.mark.prebuild" ]; then if [ -f "$WORKSPACE/problem/$1/.mark.prebuild" ]; then
log_warn "Problem $1 already prebuilt" log_warn "Problem $1 already prebuilt"
log_warn "If you want to re-prebuild the problem, please remove the file $WORKSPACE/problem/$1/.mark.prebuild" log_warn "If you want to re-prebuild the problem, please remove the file $WORKSPACE/problem/$1/.mark.prebuild"
exit 0 exit 0
fi fi
if [ ! -f "$WORKSPACE/problem/$1/judge/prebuild.Makefile" ]; then if [ ! -f "$WORKSPACE/problem/$1/judge/prebuild.Makefile" ]; then
log_warn "Problem $1 does not have prebuild scripts" log_warn "Problem $1 does not have prebuild scripts"
log_warn "$WORKSPACE/problem/$1/.mark.prebuild" log_warn "$WORKSPACE/problem/$1/.mark.prebuild"
exit 0 exit 0
fi fi
export TIMEOUT=${2:-300} export TIMEOUT=${2:-300}
docker_run \ docker_run \
-v "$WORKSPACE/problem/$1/data":/woj/problem/data \ -v "$WORKSPACE/problem/$1/data":/woj/problem/data \
-v "$WORKSPACE/problem/$1/judge":/woj/problem/judge \ -v "$WORKSPACE/problem/$1/judge":/woj/problem/judge \
-e PREFIX=/woj/problem \ -e PREFIX=/woj/problem \
woj/ubuntu-full \ git.0x7f.app/woj/ubuntu-full \
sh -c "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild" sh -c "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild"
mv "$WORKSPACE/problem/$1/judge/.mark.prebuild" "$WORKSPACE/problem/$1/.mark.prebuild" || exit 1 mv "$WORKSPACE/problem/$1/judge/.mark.prebuild" "$WORKSPACE/problem/$1/.mark.prebuild" || exit 1

View File

@ -6,20 +6,20 @@ WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
. "$WORKSPACE"/scripts/problem.sh . "$WORKSPACE"/scripts/problem.sh
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then
log_warn "Usage: $0 <problem> <user_dir> <language>" log_warn "Usage: $0 <problem> <user_dir> <language>"
exit 1 exit 1
fi fi
if [ ! -f "$WORKSPACE/problem/$1/.mark.prebuild" ]; then if [ ! -f "$WORKSPACE/problem/$1/.mark.prebuild" ]; then
log_warn "Problem $1 has not been prebuilt" log_warn "Problem $1 has not been prebuilt"
log_warn "Please run 'problem_prebuild.sh $1' first" log_warn "Please run 'problem_prebuild.sh $1' first"
exit 1 exit 1
fi fi
if [ ! -f "$WORKSPACE/user/$2/$2.out" ]; then if [ ! -f "$WORKSPACE/user/$2/$2.out" ]; then
log_warn "User $2 has not been compiled" log_warn "User $2 has not been compiled"
log_warn "Please run 'problem_compile.sh ...' first" log_warn "Please run 'problem_compile.sh ...' first"
exit 1 exit 1
fi fi
parse_limits "$WORKSPACE" "$1" parse_limits "$WORKSPACE" "$1"
@ -35,37 +35,37 @@ TIMEOUT=$(((LIMIT_TIME + 1000) / 1000 + 4))
log_info "Timeout: $TIMEOUT" log_info "Timeout: $TIMEOUT"
for test_num in $(seq "$Info_Num"); do for test_num in $(seq "$Info_Num"); do
test_case="$WORKSPACE/problem/$1/data/input/$test_num.input" test_case="$WORKSPACE/problem/$1/data/input/$test_num.input"
exe_file="$WORKSPACE/user/$2/$2.out" exe_file="$WORKSPACE/user/$2/$2.out"
ans_file="$WORKSPACE/user/$2/$test_num.out.usr" ans_file="$WORKSPACE/user/$2/$test_num.out.usr"
ifo_file="$WORKSPACE/user/$2/$test_num.info" ifo_file="$WORKSPACE/user/$2/$test_num.info"
if [ ! -f "$test_case" ]; then if [ ! -f "$test_case" ]; then
log_error "Test case $test_num does not exist" log_error "Test case $test_num does not exist"
exit 1 exit 1
fi fi
log_info "Running test case $test_num" log_info "Running test case $test_num"
rm -f "$ans_file" && touch "$ans_file" rm -f "$ans_file" && touch "$ans_file"
rm -f "$ifo_file" && touch "$ifo_file" rm -f "$ifo_file" && touch "$ifo_file"
docker_run \ docker_run \
--cpus 1 \ --cpus 1 \
--network none \ --network none \
-v "$test_case":/woj/problem/data/input/"$test_num".input:ro \ -v "$test_case":/woj/problem/data/input/"$test_num".input:ro \
-v "$exe_file":/woj/user/"$2".out:ro \ -v "$exe_file":/woj/user/"$2".out:ro \
-v "$ans_file":/woj/user/"$test_num".out.usr \ -v "$ans_file":/woj/user/"$test_num".out.usr \
-v "$ifo_file":/woj/user/"$test_num".info \ -v "$ifo_file":/woj/user/"$test_num".info \
woj/ubuntu-run \ git.0x7f.app/woj/ubuntu-run \
sh -c \ sh -c \
"cd /woj/user && /woj/framework/scripts/woj_launcher \ "cd /woj/user && /woj/framework/scripts/woj_launcher \
--memory_limit=$Info_Limit_Memory \ --memory_limit=$Info_Limit_Memory \
--nproc_limit=$Info_Limit_NProc \ --nproc_limit=$Info_Limit_NProc \
--time_limit=$Info_Limit_Time \ --time_limit=$Info_Limit_Time \
--sandbox_path=/woj/framework/scripts/libwoj_sandbox.so \ --sandbox_path=/woj/framework/scripts/libwoj_sandbox.so \
--sandbox_template=$3 \ --sandbox_template=$3 \
--sandbox_action=nothing \ --sandbox_action=nothing \
--file_input=/woj/problem/data/input/$test_num.input \ --file_input=/woj/problem/data/input/$test_num.input \
--file_output=/woj/user/$test_num.out.usr \ --file_output=/woj/user/$test_num.out.usr \
--file_info=/woj/user/$test_num.info \ --file_info=/woj/user/$test_num.info \
--program=/woj/user/$2.out" --program=/woj/user/$2.out"
done done

View File

@ -3,17 +3,17 @@
. common.sh . common.sh
function docker_run() { function docker_run() {
local timeout=${TIMEOUT:-10} local timeout=${TIMEOUT:-10}
local log_file=${LOG_FILE:-"/dev/stderr"} local log_file=${LOG_FILE:-"/dev/stderr"}
local log_limit=${LOG_LIMIT:-4K} local log_limit=${LOG_LIMIT:-4K}
log_info "$DOCKER run with timeout $timeout" log_info "$DOCKER run with timeout $timeout"
CONTAINER_NAME=$(uuidgen) CONTAINER_NAME=$(uuidgen)
( (
sleep "$timeout" sleep "$timeout"
$DOCKER kill "$CONTAINER_NAME" $DOCKER kill "$CONTAINER_NAME"
) & ) &
$DOCKER run --rm --name "$CONTAINER_NAME" "$@" 2>&1 | head -c "$log_limit" >"$log_file" $DOCKER run --rm --name "$CONTAINER_NAME" "$@" 2>&1 | head -c "$log_limit" >"$log_file"
pkill -P $$ pkill -P $$
$DOCKER kill "$CONTAINER_NAME" >/dev/null 2>&1 $DOCKER kill "$CONTAINER_NAME" >/dev/null 2>&1
return 0 return 0
} }

View File

@ -0,0 +1,20 @@
FROM docker.io/library/ubuntu:22.04
WORKDIR /woj/
# Install dependencies
RUN apt-get update && apt-get upgrade -y && apt-get install -y gcc g++ clang make cmake autoconf m4 libtool gperf git parallel python3 && apt-get clean && rm -rf /var/lib/apt/lists
# Copy source code
RUN mkdir -p /woj/framework && mkdir -p /woj/problem
COPY framework /woj/framework
# Build
RUN cd /woj/framework/template && ./setup.sh
RUN cd /woj/framework/scripts && ./setup.sh
# Environment
ENV WOJ_LAUNCHER=/woj/framework/scripts/woj_launcher
ENV WOJ_SANDBOX=/woj/framework/scripts/libwoj_sandbox.so
ENV TEMPLATE=/woj/framework/template
ENV TESTLIB=/woj/framework/template/testlib
ENV PREFIX=/woj/problem

View File

@ -0,0 +1,8 @@
FROM woj/ubuntu-full:latest AS builder
FROM docker.io/library/ubuntu:22.04
WORKDIR /woj/problem
RUN mkdir -p /woj/framework/scripts
COPY --from=builder /woj/framework/scripts/libwoj_sandbox.so /woj/framework/scripts/
COPY --from=builder /woj/framework/scripts/woj_launcher /woj/framework/scripts/