From 57c2e6a32fd9b85e2037cf4f690f041a8c73386b Mon Sep 17 00:00:00 2001 From: unknown <86871862+minhnhatnoe@users.noreply.github.com> Date: Fri, 12 May 2023 16:31:34 +0700 Subject: [PATCH 01/23] Added script to generate cert for windows --- scripts/windows/gen_cert.ps1 | 100 +++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 scripts/windows/gen_cert.ps1 diff --git a/scripts/windows/gen_cert.ps1 b/scripts/windows/gen_cert.ps1 new file mode 100644 index 00000000..d856686b --- /dev/null +++ b/scripts/windows/gen_cert.ps1 @@ -0,0 +1,100 @@ +<# +.SYNOPSIS + Generate self-signed SSL certificate +.DESCRIPTION + cert generation environment variables: + - OPENSSL_PATH [openssl] Path to openssl.exe + - RSA_BITS [4096] Strength of the RSA key. + - CERT_C [JP] Certificate country code + - CERT_ST [Moonland] Certificate State + - CERT_L [Kagamitown] Certificate Locality + - CERT_O [nki inc.] Certificate Organization Name + - CERT_CN [kjudge] Certificate Common name + - CERT_EMAIL [not@nkagami.me] Certificate Email address + - CERT_ALTNAMES [IP:127.0.0.1,DNS:localhost] A list of hosts that kjudge will be listening on, either by IP (as 'IP:1.2.3.4') or DNS (as 'DNS:google.com'), separated by ','" +.PARAMETER TargetDir + Target directory to export generated SSL certificate +#> + +Param ( + [Parameter( + Mandatory, + HelpMessage = "Target directory to export generated SSL certificate", + Position = 0 + )] [System.IO.FileInfo] $TargetDir +) + +# Break on first error +$ErrorActionPreference = "Stop" + +$OPENSSL_PATH = $Env:OPENSSL_PATH ?? "openssl" +Write-Host "OpenSSL Path: $OPENSSL_PATH" + +$CERT_C = $Env:CERT_C ?? "JP" # Country code +$CERT_ST = $Env:CERT_ST ?? "Moonland" # State +$CERT_L = $Env:CERT_L ?? "Kagamitown" # Locality +$CERT_O = $Env:CERT_O ?? "nki inc." # Organization Name +$CERT_CN = $Env:CERT_CN ?? "kjudge" # Common name +$CERT_EMAIL = $Env:CERT_EMAIL ?? "not@nkagami.me" # Email address +$CERT_ALTNAMES = $Env:CERT_ALTNAMES ?? "IP:127.0.0.1,DNS:localhost" # Alt hosts + +# All information +$CERT_SUBJ = "/C=$CERT_C/ST=$CERT_ST/L=$CERT_L/O=$CERT_O/CN=$CERT_CN/emailAddress=$CERT_EMAIL" +$CERT_EXT = "subjectAltName = $CERT_ALTNAMES" + +$RSA_BITS = $Env:RSA_BITS ?? 4096 # RSA bits + +# Paths +$ROOT_DIR = $TargetDir + +$CERT_GPATH = [IO.Path]::Combine($ROOT_DIR, '.certs_generated') +$ROOT_KEY = [IO.Path]::Combine($ROOT_DIR, "root.key") +$ROOT_CERT = [IO.Path]::Combine($ROOT_DIR, "root.pem") + +$KJUDGE_KEY = [IO.Path]::Combine($ROOT_DIR, "kjudge.key") +$KJUDGE_CERT = [IO.Path]::Combine($ROOT_DIR, "kjudge.crt") +$KJUDGE_CSR = [IO.Path]::Combine($ROOT_DIR, "kjudge.csr") + +Write-Host "Key info:" +Write-Host "- Country code = $CERT_C" +Write-Host "- State = $CERT_ST" +Write-Host "- Locality = $CERT_L" +Write-Host "- Organization Name = $CERT_O" +Write-Host "- Common name = $CERT_CN" +Write-Host "- Email address = $CERT_EMAIL" +Write-Host "- Alt hosts = $CERT_ALTNAMES" + +Function generateKey { + If ([System.IO.File]::Exists([IO.Path]::Combine($ROOT_DIR, ".certs_generated"))){ + Write-Host "Certificate has already been generated." + return 0 + } + Write-Host "Generating root private key to $ROOT_KEY" + openssl genrsa -out "$ROOT_KEY" "$RSA_BITS" + + Write-Host "Generating a root certificate authority to $ROOT_CERT" + openssl req -x509 -new -key "$ROOT_KEY" -days 1285 -out "$ROOT_CERT" ` + -subj "$CERT_SUBJ" + + Write-Host "Generating a sub-key for kjudge to $KJUDGE_KEY" + openssl genrsa -out "$KJUDGE_KEY" "$RSA_BITS" + + Write-Host "Generating a certificate signing request to $KJUDGE_CSR" + openssl req -new -key "$KJUDGE_KEY" -out "$KJUDGE_CSR" ` + -subj "$CERT_SUBJ" -addext "$CERT_EXT" + + Write-Host "Generating a certificate signature to $KJUDGE_CERT" + Write-Output "[v3_ca]\n%s\n" "$CERT_EXT" | openssl x509 -req -days 730 ` + -in "$KJUDGE_CSR" ` + -CA "$ROOT_CERT" -CAkey "$ROOT_KEY" -CAcreateserial ` + -extensions v3_ca -extfile - ` + -out "$KJUDGE_CERT" + + Write-Host "Certificate generation complete." + Out-File -FilePath "$CERT_GPATH" +} +generateKey + +Write-Host "To re-generate the keys, delete " "$CERT_GPATH" +Write-Host "Please keep $ROOT_KEY and $KJUDGE_KEY secret, while distributing" ` + "$ROOT_CERT as the certificate authority." From d24a3feb6916e3c14c75e9c0d300bd5eae82416d Mon Sep 17 00:00:00 2001 From: unknown <86871862+minhnhatnoe@users.noreply.github.com> Date: Fri, 12 May 2023 17:38:30 +0700 Subject: [PATCH 02/23] Script for build --- frontend/package.json | 1 + scripts/windows/build.ps1 | 3 +++ scripts/windows/generate.ps1 | 9 +++++++++ 3 files changed, 13 insertions(+) create mode 100644 scripts/windows/build.ps1 create mode 100644 scripts/windows/generate.ps1 diff --git a/frontend/package.json b/frontend/package.json index 0fd89f21..acdfd833 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,6 +30,7 @@ "fmt": "prettier \"css/**/*\" \"ts/**/*\" \"*.json\" \"*.js\"", "dev": "parcel watch \"html/**/*.html\"", "build": "mkdir -p ../embed/templates && rm -rf ../embed/templates/* && parcel build --no-source-maps --no-cache \"html/**/*.html\"" + "build:windows": "pwsh --command ../scripts/windows/build.ps1" }, "alias": { "react": "preact/compat", diff --git a/scripts/windows/build.ps1 b/scripts/windows/build.ps1 new file mode 100644 index 00000000..3b87f620 --- /dev/null +++ b/scripts/windows/build.ps1 @@ -0,0 +1,3 @@ +New-Item -Type Directory -Force ../embed/templates +Remove-Item ../embed/templates/* +parcel build --no-source-maps --no-cache "html/**/*.html" diff --git a/scripts/windows/generate.ps1 b/scripts/windows/generate.ps1 new file mode 100644 index 00000000..c49ac51b --- /dev/null +++ b/scripts/windows/generate.ps1 @@ -0,0 +1,9 @@ +Set-PSDebug -Trace 1 +$ErrorActionPreference = "Stop" + +Set-Location .\frontend +yarn +yarn run --prod build +Set-Location .. + +go generate From 0eaf19cb6865ee42ad04bf36c16067130bc54cfa Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Fri, 12 May 2023 21:20:08 +0700 Subject: [PATCH 03/23] Use filepath and os.remove to remove leftover generated files --- frontend/package.json | 2 +- models/generate/main.go | 19 ++++++++++++++++--- .../windows/{build.ps1 => frontend_build.ps1} | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) rename scripts/windows/{build.ps1 => frontend_build.ps1} (96%) diff --git a/frontend/package.json b/frontend/package.json index acdfd833..e6a33a0e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,7 +30,7 @@ "fmt": "prettier \"css/**/*\" \"ts/**/*\" \"*.json\" \"*.js\"", "dev": "parcel watch \"html/**/*.html\"", "build": "mkdir -p ../embed/templates && rm -rf ../embed/templates/* && parcel build --no-source-maps --no-cache \"html/**/*.html\"" - "build:windows": "pwsh --command ../scripts/windows/build.ps1" + "build:windows": "pwsh --command ../scripts/windows/frontend_build.ps1" }, "alias": { "react": "preact/compat", diff --git a/models/generate/main.go b/models/generate/main.go index 8d631413..dc935156 100644 --- a/models/generate/main.go +++ b/models/generate/main.go @@ -7,6 +7,7 @@ import ( "log" "os" "os/exec" + "path/filepath" "sort" "strings" "text/template" @@ -331,14 +332,26 @@ func init() { template.Must(t.Parse(FileTemplate)) } +func removeLeftoverGeneratedFiles() { + files, err := filepath.Glob("models/*_generated.go") + if err != nil { + log.Fatal(err) + } + + for _, file := range files { + if err := os.Remove(file); err != nil { + log.Fatal(err); + } + } +} + func main() { var tables TomlTables if _, err := toml.DecodeFile("models/models.toml", &tables); err != nil { log.Fatal(err) } - if err := exec.Command("rm", "-fv", "models/*_generated.go").Run(); err != nil { - log.Fatal(err) - } + removeLeftoverGeneratedFiles() + files := []string{"-w"} // This is actually goimports's parameters. for name, fields := range tables { table := TableFromToml(tables, name, fields) diff --git a/scripts/windows/build.ps1 b/scripts/windows/frontend_build.ps1 similarity index 96% rename from scripts/windows/build.ps1 rename to scripts/windows/frontend_build.ps1 index 3b87f620..f79a644c 100644 --- a/scripts/windows/build.ps1 +++ b/scripts/windows/frontend_build.ps1 @@ -1,3 +1,4 @@ + New-Item -Type Directory -Force ../embed/templates Remove-Item ../embed/templates/* parcel build --no-source-maps --no-cache "html/**/*.html" From 89c9d64e8172690eb8fb092fe64bc99de0a563b6 Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Fri, 12 May 2023 23:08:56 +0700 Subject: [PATCH 04/23] A barely running version for windows --- .gitignore | 1 + scripts/windows/frontend_build.ps1 | 5 +++-- scripts/windows/generate.ps1 | 3 +-- scripts/windows/production_build.ps1 | 6 ++++++ 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 scripts/windows/production_build.ps1 diff --git a/.gitignore b/.gitignore index 67266ed6..676ed009 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ kjudge.db.bak kjudge.db-* /kjudge +/kjudge.exe /templates /keys /embed/templates diff --git a/scripts/windows/frontend_build.ps1 b/scripts/windows/frontend_build.ps1 index f79a644c..148c7049 100644 --- a/scripts/windows/frontend_build.ps1 +++ b/scripts/windows/frontend_build.ps1 @@ -1,4 +1,5 @@ +$ErrorActionPreference = "Stop" -New-Item -Type Directory -Force ../embed/templates -Remove-Item ../embed/templates/* +New-Item -Type Directory -Force ../embed/templates | Out-Null +Remove-Item -Recurse -Force ../embed/templates/* parcel build --no-source-maps --no-cache "html/**/*.html" diff --git a/scripts/windows/generate.ps1 b/scripts/windows/generate.ps1 index c49ac51b..a0575713 100644 --- a/scripts/windows/generate.ps1 +++ b/scripts/windows/generate.ps1 @@ -1,9 +1,8 @@ -Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" Set-Location .\frontend yarn -yarn run --prod build +yarn run --prod build:windows Set-Location .. go generate diff --git a/scripts/windows/production_build.ps1 b/scripts/windows/production_build.ps1 new file mode 100644 index 00000000..f6cb602e --- /dev/null +++ b/scripts/windows/production_build.ps1 @@ -0,0 +1,6 @@ +$ErrorActionPreference = "Stop" + +& "scripts\windows\generate.ps1" + +# Build +go build -tags "production" -o kjudge.exe cmd/kjudge/main.go From 5a27de534855eb81a31bb5975ebcb5850164598d Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Sun, 14 May 2023 21:58:38 +0700 Subject: [PATCH 05/23] Extend sandbox choices --- cmd/kjudge/main.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cmd/kjudge/main.go b/cmd/kjudge/main.go index 5e513530..3564a2b2 100644 --- a/cmd/kjudge/main.go +++ b/cmd/kjudge/main.go @@ -18,7 +18,7 @@ import ( var ( dbfile = flag.String("file", "kjudge.db", "Path to the database file.") - sandboxImpl = flag.String("sandbox", "isolate", "The sandbox implementation to be used (isolate, raw). If anything other than 'raw' is given, isolate is used.") + sandboxImpl = flag.String("sandbox", "isolate", "The sandbox implementation to be used (isolate, raw). Defaults to isolate.") port = flag.Int("port", 8088, "The port for the server to listen on.") httpsDir = flag.String("https", "", "Path to the directory where the HTTPS private key (kjudge.key) and certificate (kjudge.crt) is located. If omitted or empty, HTTPS is disabled.") @@ -34,11 +34,17 @@ func main() { defer db.Close() var sandbox worker.Sandbox - if *sandboxImpl == "raw" { - log.Println("'raw' sandbox selected. WE ARE NOT RESPONSIBLE FOR ANY BREAKAGE CAUSED BY FOREIGN CODE.") - sandbox = &raw.Sandbox{} - } else { - sandbox = isolate.New() + switch *sandboxImpl { + case "raw": { + log.Println("'raw' sandbox selected. WE ARE NOT RESPONSIBLE FOR ANY BREAKAGE CAUSED BY FOREIGN CODE.") + sandbox = &raw.Sandbox{} + } + case "isolate": { + sandbox = isolate.New() + } + default: { + log.Fatalf("Sandbox %s doesn't exists or not yet implemented.", *sandboxImpl); + } } // Start the queue From 197d75881302249318698753ae939593f6f389bf Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Sun, 14 May 2023 22:16:22 +0700 Subject: [PATCH 06/23] Print signal on abort --- cmd/kjudge/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/kjudge/main.go b/cmd/kjudge/main.go index 3564a2b2..9cf767af 100644 --- a/cmd/kjudge/main.go +++ b/cmd/kjudge/main.go @@ -64,9 +64,9 @@ func main() { go queue.Start() go startServer(server) - <-stop + received_signal := <- stop - log.Println("Shutting down") + log.Printf("Shutting down on receiving %s", received_signal) } func startServer(server *server.Server) { From 3142d3e39594683e53ebcf91d29c9598c0ccd334 Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Mon, 15 May 2023 22:45:55 +0700 Subject: [PATCH 07/23] Remove {} in main.go switch case --- cmd/kjudge/main.go | 9 +++------ db/migrations.go | 4 ++-- embed/embed_dev.go | 6 +++--- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cmd/kjudge/main.go b/cmd/kjudge/main.go index 9cf767af..bf074220 100644 --- a/cmd/kjudge/main.go +++ b/cmd/kjudge/main.go @@ -35,16 +35,13 @@ func main() { var sandbox worker.Sandbox switch *sandboxImpl { - case "raw": { + case "raw": log.Println("'raw' sandbox selected. WE ARE NOT RESPONSIBLE FOR ANY BREAKAGE CAUSED BY FOREIGN CODE.") sandbox = &raw.Sandbox{} - } - case "isolate": { + case "isolate": sandbox = isolate.New() - } - default: { + default: log.Fatalf("Sandbox %s doesn't exists or not yet implemented.", *sandboxImpl); - } } // Start the queue diff --git a/db/migrations.go b/db/migrations.go index 9fb3b7dc..6156d266 100644 --- a/db/migrations.go +++ b/db/migrations.go @@ -4,7 +4,7 @@ import ( "database/sql" "io/fs" "log" - "path" + "path/filepath" "regexp" "sort" @@ -44,7 +44,7 @@ func (db *DB) migrate() error { // Do migrations one by one for _, name := range versions { - sqlFile := path.Join(assetsSql, name+".sql") + sqlFile := filepath.Join(assetsSql, name+".sql") file, err := fs.ReadFile(embed.Content, sqlFile) if err != nil { return errors.Wrapf(err, "File %s", sqlFile) diff --git a/embed/embed_dev.go b/embed/embed_dev.go index 2a9c5c08..4d868d7d 100644 --- a/embed/embed_dev.go +++ b/embed/embed_dev.go @@ -16,16 +16,16 @@ var Content fs.FS func init() { wd, err := os.Getwd() if err != nil { - log.Panicf("cannot get current directory: %v", err) + log.Panicf("Cannot get current directory: %v", err) } embedDir := filepath.Join(wd, "embed") stat, err := os.Stat(embedDir) if err != nil { - log.Panicf("cannot stat embed directory: %v", err) + log.Panicf("Cannot stat embed directory: %v", err) } if !stat.IsDir() { - log.Panicf("embed directory is not a directory: %s", embedDir) + log.Panicf("Embed directory is not a directory: %s", embedDir) } log.Printf("[dev] serving embedded content from %s", embedDir) From b8e88c648a04939f610b3d6cf047cd2d5a0189b8 Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Mon, 15 May 2023 23:04:51 +0700 Subject: [PATCH 08/23] Panic if contesttype is invalid, not sure how it can be done but still --- models/scoreboard.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/models/scoreboard.go b/models/scoreboard.go index a29d6d1c..1c2671fd 100644 --- a/models/scoreboard.go +++ b/models/scoreboard.go @@ -4,6 +4,7 @@ import ( "encoding/csv" "fmt" "io" + "log" "sort" "time" @@ -143,7 +144,7 @@ func compareUserRanking(userResult []*UserResult, contestType ContestType, i, j return a.TotalPenalty < b.TotalPenalty, false } return a.User.ID < b.User.ID, true - } else { + } else if contestType == ContestTypeUnweighted { // sort based on solvedProblems if two users have same solvedProblems sort based on totalPenalty in an ascending order if a.SolvedProblems != b.SolvedProblems { return a.SolvedProblems > b.SolvedProblems, false @@ -152,6 +153,11 @@ func compareUserRanking(userResult []*UserResult, contestType ContestType, i, j return a.TotalPenalty < b.TotalPenalty, false } return a.User.ID < b.User.ID, true + } else { + // in no case should this path be reached + // this just stays here in case someone implements a custom contest type + log.Panicf("Contest type %s does not exists or not yet implemented", contestType) + return true, true } } From 67d04123f24e6429a08c178712396cbb30736d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nh=E1=BA=ADt=20Nguy=E1=BB=85n?= <86871862+minhnhatnoe@users.noreply.github.com> Date: Tue, 16 May 2023 16:30:39 +0700 Subject: [PATCH 09/23] use switch case for contesttype in scoreboard --- models/scoreboard.go | 46 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/models/scoreboard.go b/models/scoreboard.go index 1c2671fd..cfc48cc4 100644 --- a/models/scoreboard.go +++ b/models/scoreboard.go @@ -135,30 +135,30 @@ func (s *Scoreboard) JSON() JSONScoreboard { // Returns (comparison, is it just tie-breaking) func compareUserRanking(userResult []*UserResult, contestType ContestType, i, j int) (bool, bool) { a, b := userResult[i], userResult[j] - if contestType == ContestTypeWeighted { - // sort based on totalScore if two users have same totalScore sort based on totalPenalty in an ascending order - if a.TotalScore != b.TotalScore { - return a.TotalScore > b.TotalScore, false - } - if a.TotalPenalty != b.TotalPenalty { - return a.TotalPenalty < b.TotalPenalty, false - } - return a.User.ID < b.User.ID, true - } else if contestType == ContestTypeUnweighted { - // sort based on solvedProblems if two users have same solvedProblems sort based on totalPenalty in an ascending order - if a.SolvedProblems != b.SolvedProblems { - return a.SolvedProblems > b.SolvedProblems, false - } - if a.TotalPenalty != b.TotalPenalty { - return a.TotalPenalty < b.TotalPenalty, false - } - return a.User.ID < b.User.ID, true - } else { - // in no case should this path be reached - // this just stays here in case someone implements a custom contest type - log.Panicf("Contest type %s does not exists or not yet implemented", contestType) - return true, true + switch contestType { + case ContestTypeWeighted: + // sort based on totalScore if two users have same totalScore sort based on totalPenalty in an ascending order + if a.TotalScore != b.TotalScore { + return a.TotalScore > b.TotalScore, false + } + if a.TotalPenalty != b.TotalPenalty { + return a.TotalPenalty < b.TotalPenalty, false + } + return a.User.ID < b.User.ID, true + case ContestTypeUnweighted: + // sort based on solvedProblems if two users have same solvedProblems sort based on totalPenalty in an ascending order + if a.SolvedProblems != b.SolvedProblems { + return a.SolvedProblems > b.SolvedProblems, false + } + if a.TotalPenalty != b.TotalPenalty { + return a.TotalPenalty < b.TotalPenalty, false + } + return a.User.ID < b.User.ID, true } + // in no case should this path be reached + // this just stays here in case someone implements a custom contest type + log.Panicf("Contest type %s does not exists or not yet implemented", contestType) + return true, true } // Get scoreboard given problems and contest From 8af461664a4e6664859508aa63f0618be5dc7b7e Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Tue, 16 May 2023 19:45:13 +0700 Subject: [PATCH 10/23] Leave VerdictIsInQueue in pkg worker for readability --- worker/score.go | 1 + 1 file changed, 1 insertion(+) diff --git a/worker/score.go b/worker/score.go index 695b0260..17427467 100644 --- a/worker/score.go +++ b/worker/score.go @@ -14,6 +14,7 @@ const ( VerdictCompileError = "Compile Error" VerdictScored = "Scored" VerdictAccepted = "Accepted" + VerdictIsInQueue = "..." ) // ScoreContext is a context for calculating a submission's score From c2913f638671aeea4ed670729558f3a017fe9271 Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Tue, 16 May 2023 20:25:28 +0700 Subject: [PATCH 11/23] Move position of Verdict constants --- models/rejudge.go | 2 +- models/submissions.go | 7 +++++++ server/admin/submission.go | 3 +-- server/contests/problem.go | 2 +- server/contests/submission.go | 3 +-- worker/compile.go | 4 ++-- worker/score.go | 23 ++++++++--------------- 7 files changed, 21 insertions(+), 23 deletions(-) diff --git a/models/rejudge.go b/models/rejudge.go index 19b7cd95..8e741627 100644 --- a/models/rejudge.go +++ b/models/rejudge.go @@ -20,7 +20,7 @@ func batchScoreJobs(subIDs ...int) []*Job { // Remove the submission's `score`, `penalty` and `verdict`. func resetScore(db db.DBContext, subIDs ...int) error { - query, params, err := sqlx.In(`UPDATE submissions SET score = NULL, penalty = NULL, verdict = "..." WHERE id IN (?)`, subIDs) + query, params, err := sqlx.In(`UPDATE submissions SET score = NULL, penalty = NULL, verdict = `+VerdictIsInQueue+`WHERE id IN (?)`, subIDs) if err != nil { return errors.WithStack(err) } diff --git a/models/submissions.go b/models/submissions.go index fcf09b2b..5a49b9a4 100644 --- a/models/submissions.go +++ b/models/submissions.go @@ -24,6 +24,13 @@ const ( LanguageRust Language = "rustc" ) +const ( + VerdictCompileError = "Compile Error" + VerdictScored = "Scored" + VerdictAccepted = "Accepted" + VerdictIsInQueue = "..." +) + var availableLanguages []string // LanguageByExt returns a language based on the file extension. diff --git a/server/admin/submission.go b/server/admin/submission.go index 8fa8a8e5..a690891f 100644 --- a/server/admin/submission.go +++ b/server/admin/submission.go @@ -11,7 +11,6 @@ import ( "github.com/natsukagami/kjudge/db" "github.com/natsukagami/kjudge/models" "github.com/natsukagami/kjudge/server/httperr" - "github.com/natsukagami/kjudge/worker" "github.com/pkg/errors" ) @@ -104,7 +103,7 @@ func (g *Group) SubmissionVerdictGet(c echo.Context) error { if err != nil { return err } - if ctx.Submission.Verdict == "..." || ctx.Submission.Verdict == worker.VerdictCompileError { + if ctx.Submission.Verdict == models.VerdictIsInQueue || ctx.Submission.Verdict == models.VerdictCompileError { return c.JSON(http.StatusOK, map[string]interface{}{ "verdict": ctx.Submission.Verdict, }) diff --git a/server/contests/problem.go b/server/contests/problem.go index 5014764d..7092f0e4 100644 --- a/server/contests/problem.go +++ b/server/contests/problem.go @@ -164,7 +164,7 @@ func (g *Group) SubmitPost(c echo.Context) error { Source: source, Language: lang, SubmittedAt: now, - Verdict: "...", + Verdict: models.VerdictIsInQueue, } if err := sub.Write(tx); err != nil { diff --git a/server/contests/submission.go b/server/contests/submission.go index 8f1dbf22..58fd3d87 100644 --- a/server/contests/submission.go +++ b/server/contests/submission.go @@ -9,7 +9,6 @@ import ( "github.com/natsukagami/kjudge/db" "github.com/natsukagami/kjudge/models" "github.com/natsukagami/kjudge/server/httperr" - "github.com/natsukagami/kjudge/worker" "github.com/pkg/errors" ) @@ -111,7 +110,7 @@ func (g *Group) SubmissionVerdictGet(c echo.Context) error { if err != nil { return err } - if ctx.Submission.Verdict == "..." || ctx.Submission.Verdict == worker.VerdictCompileError { + if ctx.Submission.Verdict == models.VerdictIsInQueue || ctx.Submission.Verdict == models.VerdictCompileError { return c.JSON(http.StatusOK, map[string]interface{}{ "verdict": ctx.Submission.Verdict, }) diff --git a/worker/compile.go b/worker/compile.go index ee3c430d..9f12de3a 100644 --- a/worker/compile.go +++ b/worker/compile.go @@ -60,7 +60,7 @@ func Compile(c *CompileContext) (bool, error) { } else if !hasFile { // Batch compile mode enabled, but this language is not supported. c.Sub.CompiledSource = nil - c.Sub.Verdict = VerdictCompileError + c.Sub.Verdict = models.VerdictCompileError c.Sub.CompilerOutput = []byte("Custom Compilers are not enabled for this language.") return false, c.Sub.Write(c.DB) } @@ -94,7 +94,7 @@ func Compile(c *CompileContext) (bool, error) { c.Sub.CompiledSource = output } else { c.Sub.CompiledSource = nil - c.Sub.Verdict = VerdictCompileError + c.Sub.Verdict = models.VerdictCompileError } log.Printf("[WORKER] Compiling submission %v succeeded (result = %v).", c.Sub.ID, result) diff --git a/worker/score.go b/worker/score.go index 17427467..36406c55 100644 --- a/worker/score.go +++ b/worker/score.go @@ -10,13 +10,6 @@ import ( "github.com/natsukagami/kjudge/models" ) -const ( - VerdictCompileError = "Compile Error" - VerdictScored = "Scored" - VerdictAccepted = "Accepted" - VerdictIsInQueue = "..." -) - // ScoreContext is a context for calculating a submission's score // and update the user's problem scores. type ScoreContext struct { @@ -43,7 +36,7 @@ func Score(s *ScoreContext) error { return models.BatchInsertJobs(s.DB, models.NewJobCompile(s.Sub.ID), models.NewJobScore(s.Sub.ID)) } else if source == nil { log.Printf("[WORKER] Not running a submission that failed to compile.\n") - s.Sub.Verdict = VerdictCompileError + s.Sub.Verdict = models.VerdictCompileError if err := s.Sub.Write(s.DB); err != nil { return err } @@ -102,7 +95,7 @@ func Score(s *ScoreContext) error { func UpdateVerdict(tests []*models.TestGroupWithTests, sub *models.Submission) { score, _, counts := scoreOf(sub) if !counts { - sub.Verdict = VerdictCompileError + sub.Verdict = models.VerdictCompileError return } @@ -114,9 +107,9 @@ func UpdateVerdict(tests []*models.TestGroupWithTests, sub *models.Submission) { } if score == maxPossibleScore { - sub.Verdict = VerdictAccepted + sub.Verdict = models.VerdictAccepted } else { - sub.Verdict = VerdictScored + sub.Verdict = models.VerdictScored } } @@ -230,12 +223,12 @@ func (s *ScoreContext) CompareScores(subs []*models.Submission) *models.ProblemR } if s.Problem.ScoringMode == models.ScoringModeMin { if sub == which { - if sub.Verdict != VerdictAccepted { + if sub.Verdict != models.VerdictAccepted { failedAttempts++ } break } - } else if sub.Verdict == VerdictAccepted { + } else if sub.Verdict == models.VerdictAccepted { break } failedAttempts++ @@ -258,7 +251,7 @@ func (s *ScoreContext) CompareScores(subs []*models.Submission) *models.ProblemR contestType := s.Contest.ContestType if contestType == models.ContestTypeWeighted && maxScore == 0.0 { penalty = 0 - } else if contestType == models.ContestTypeUnweighted && which.Verdict != VerdictAccepted { + } else if contestType == models.ContestTypeUnweighted && which.Verdict != models.VerdictAccepted { penalty = 0 } return &models.ProblemResult{ @@ -266,7 +259,7 @@ func (s *ScoreContext) CompareScores(subs []*models.Submission) *models.ProblemR FailedAttempts: failedAttempts, Penalty: penalty, Score: maxScore, - Solved: which.Verdict == VerdictAccepted, + Solved: which.Verdict == models.VerdictAccepted, ProblemID: s.Problem.ID, UserID: s.Sub.UserID, } From 5e165f289124d07c5e488ee5cac9483aac48b83d Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Tue, 16 May 2023 21:03:30 +0700 Subject: [PATCH 12/23] More detailed comment for the CA server --- server/root_ca.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/root_ca.go b/server/root_ca.go index 13f884e6..336462fd 100644 --- a/server/root_ca.go +++ b/server/root_ca.go @@ -9,8 +9,8 @@ import ( "github.com/pkg/errors" ) -// ServeHTTPRootCA starts a HTTP server running on `address` -// serving the root CA from "/ca". It rejects all other requests. +// ServeHTTPRootCA starts a HTTP server running on `address` using the .pem file at +// rootCA, serving the root CA from "/ca". It rejects all other requests. func (s *Server) ServeHTTPRootCA(address, rootCA string) error { if stat, err := os.Stat(rootCA); err != nil { return errors.WithStack(err) From d88f55eb7006fd3e6be8af66bba6892d1610fda8 Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Wed, 17 May 2023 21:33:21 +0700 Subject: [PATCH 13/23] Fix grammar error --- server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/server.go b/server/server.go index d79f2a87..c7b62e55 100644 --- a/server/server.go +++ b/server/server.go @@ -23,7 +23,7 @@ import ( "github.com/pkg/errors" ) -// Server this the root entry of the server. +// Server is the root entry of the server. type Server struct { db *db.DB echo *echo.Echo From 91d8be3bf3e94ee089eb2ecdf02167118dbe1315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Minh=20Nh=E1=BA=ADt?= <86871862+minhnhatnoe@users.noreply.github.com> Date: Wed, 17 May 2023 22:06:00 +0700 Subject: [PATCH 14/23] Align equal sign for VerdictIsInQueue Was previously a tab. Converted to multiple spaces --- models/submissions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/submissions.go b/models/submissions.go index 5a49b9a4..af52799c 100644 --- a/models/submissions.go +++ b/models/submissions.go @@ -28,7 +28,7 @@ const ( VerdictCompileError = "Compile Error" VerdictScored = "Scored" VerdictAccepted = "Accepted" - VerdictIsInQueue = "..." + VerdictIsInQueue = "..." ) var availableLanguages []string From 8292d343d2b34585d51d92d39d0ccec4a0f430de Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Wed, 17 May 2023 22:17:18 +0700 Subject: [PATCH 15/23] Change powershell script to changes made at upstream --- frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index e6a33a0e..218cf19d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,7 +29,7 @@ "test": "echo No tests... yet", "fmt": "prettier \"css/**/*\" \"ts/**/*\" \"*.json\" \"*.js\"", "dev": "parcel watch \"html/**/*.html\"", - "build": "mkdir -p ../embed/templates && rm -rf ../embed/templates/* && parcel build --no-source-maps --no-cache \"html/**/*.html\"" + "build": "mkdir -p ../embed/templates && rm -rf ../embed/templates/* && parcel build --no-source-maps --no-cache \"html/**/*.html\"", "build:windows": "pwsh --command ../scripts/windows/frontend_build.ps1" }, "alias": { From dcd6ddbdd8de9f27c95c4719ac0a8f6a6a229e91 Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Wed, 17 May 2023 23:11:27 +0700 Subject: [PATCH 16/23] Fix grammar error --- worker/compile.go | 13 +++++++++---- worker/run.go | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/worker/compile.go b/worker/compile.go index 9f12de3a..0c0726d9 100644 --- a/worker/compile.go +++ b/worker/compile.go @@ -2,8 +2,10 @@ package worker // Compiling anything that's more compicated than single file: // -// - Prepare a "compile_%s.sh" file, with %s being the language (cc, go, rs, java, py2, py3, pas). -// - Prepare any more files as needed. They will all be put into the CWD of the script. +// - Prepare a "compile_%s.%ext" file, with %s being the language (cc, go, rs, java, py2, py3, pas) and +// TODO: %ext being the shell extension (.sh for linux and .bat/.ps1 for windows). +// - Prepare any more files as needed. They will all be put into the CWD of the script, +// TODO: except for "special" files. // - The CWD also contains "code.%s" (%s being the language's respective extension) file, which is the contestant's source code. // - The script should do whatever it wants (unsandboxed, because it's not my job to do so) within 20 seconds. // - It should produce a single binary called "code" in the CWD. @@ -101,8 +103,11 @@ func Compile(c *CompileContext) (bool, error) { return result, c.Sub.Write(c.DB) } -// CompileAction is an action revolving writing the source into a file in "Source", -// compile it with "Command" and taking the "Output" as the result. +// CompileAction represents the following steps: +// 1. Write the source into a file in "Source". +// 2. Copy all files in Files into "Source" +// 3. Compile the source with "Command". +// 4. Produce "Output" as the result. type CompileAction struct { Source *models.File Files []*models.File diff --git a/worker/run.go b/worker/run.go index b13f545b..bb2e0b5c 100644 --- a/worker/run.go +++ b/worker/run.go @@ -126,7 +126,7 @@ func RunSingleCommand(sandbox Sandbox, r *RunContext, source []byte) (output *Sa return output, nil } -func RunMutipleCommands(sandbox Sandbox, r *RunContext, source []byte, stages []string) (output *SandboxOutput, err error) { +func RunMultipleCommands(sandbox Sandbox, r *RunContext, source []byte, stages []string) (output *SandboxOutput, err error) { command, args, err := RunCommand(r.Sub.Language) if err != nil { return nil, err @@ -193,7 +193,7 @@ func Run(sandbox Sandbox, r *RunContext) error { } else { // Problem Type is Chained Type, we need to run mutiple commands with arguments from .stages (file) stages := strings.Split(string(file.Content), "\n") - output, err = RunMutipleCommands(sandbox, r, source, stages) + output, err = RunMultipleCommands(sandbox, r, source, stages) if err != nil { return err } From ac473b74fdb354cd6fcff669fad832fdf7595b9f Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 17 May 2023 20:47:00 +0200 Subject: [PATCH 17/23] Formatting --- cmd/kjudge/main.go | 16 ++++++++-------- models/generate/main.go | 2 +- models/scoreboard.go | 36 ++++++++++++++++++------------------ 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/cmd/kjudge/main.go b/cmd/kjudge/main.go index bf074220..a752af73 100644 --- a/cmd/kjudge/main.go +++ b/cmd/kjudge/main.go @@ -35,13 +35,13 @@ func main() { var sandbox worker.Sandbox switch *sandboxImpl { - case "raw": - log.Println("'raw' sandbox selected. WE ARE NOT RESPONSIBLE FOR ANY BREAKAGE CAUSED BY FOREIGN CODE.") - sandbox = &raw.Sandbox{} - case "isolate": - sandbox = isolate.New() - default: - log.Fatalf("Sandbox %s doesn't exists or not yet implemented.", *sandboxImpl); + case "raw": + log.Println("'raw' sandbox selected. WE ARE NOT RESPONSIBLE FOR ANY BREAKAGE CAUSED BY FOREIGN CODE.") + sandbox = &raw.Sandbox{} + case "isolate": + sandbox = isolate.New() + default: + log.Fatalf("Sandbox %s doesn't exists or not yet implemented.", *sandboxImpl) } // Start the queue @@ -61,7 +61,7 @@ func main() { go queue.Start() go startServer(server) - received_signal := <- stop + received_signal := <-stop log.Printf("Shutting down on receiving %s", received_signal) } diff --git a/models/generate/main.go b/models/generate/main.go index dc935156..81ff7ae8 100644 --- a/models/generate/main.go +++ b/models/generate/main.go @@ -340,7 +340,7 @@ func removeLeftoverGeneratedFiles() { for _, file := range files { if err := os.Remove(file); err != nil { - log.Fatal(err); + log.Fatal(err) } } } diff --git a/models/scoreboard.go b/models/scoreboard.go index cfc48cc4..afebba34 100644 --- a/models/scoreboard.go +++ b/models/scoreboard.go @@ -136,24 +136,24 @@ func (s *Scoreboard) JSON() JSONScoreboard { func compareUserRanking(userResult []*UserResult, contestType ContestType, i, j int) (bool, bool) { a, b := userResult[i], userResult[j] switch contestType { - case ContestTypeWeighted: - // sort based on totalScore if two users have same totalScore sort based on totalPenalty in an ascending order - if a.TotalScore != b.TotalScore { - return a.TotalScore > b.TotalScore, false - } - if a.TotalPenalty != b.TotalPenalty { - return a.TotalPenalty < b.TotalPenalty, false - } - return a.User.ID < b.User.ID, true - case ContestTypeUnweighted: - // sort based on solvedProblems if two users have same solvedProblems sort based on totalPenalty in an ascending order - if a.SolvedProblems != b.SolvedProblems { - return a.SolvedProblems > b.SolvedProblems, false - } - if a.TotalPenalty != b.TotalPenalty { - return a.TotalPenalty < b.TotalPenalty, false - } - return a.User.ID < b.User.ID, true + case ContestTypeWeighted: + // sort based on totalScore if two users have same totalScore sort based on totalPenalty in an ascending order + if a.TotalScore != b.TotalScore { + return a.TotalScore > b.TotalScore, false + } + if a.TotalPenalty != b.TotalPenalty { + return a.TotalPenalty < b.TotalPenalty, false + } + return a.User.ID < b.User.ID, true + case ContestTypeUnweighted: + // sort based on solvedProblems if two users have same solvedProblems sort based on totalPenalty in an ascending order + if a.SolvedProblems != b.SolvedProblems { + return a.SolvedProblems > b.SolvedProblems, false + } + if a.TotalPenalty != b.TotalPenalty { + return a.TotalPenalty < b.TotalPenalty, false + } + return a.User.ID < b.User.ID, true } // in no case should this path be reached // this just stays here in case someone implements a custom contest type From 6332ca788178541b1b69ba0a9002bf593ecdfd1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Minh=20Nh=E1=BA=ADt?= <86871862+minhnhatnoe@users.noreply.github.com> Date: Thu, 18 May 2023 08:50:46 +0700 Subject: [PATCH 18/23] Move verdictisinqueue out of the query Co-authored-by: Natsu Kagami --- models/rejudge.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/rejudge.go b/models/rejudge.go index 8e741627..f49b1c88 100644 --- a/models/rejudge.go +++ b/models/rejudge.go @@ -20,7 +20,7 @@ func batchScoreJobs(subIDs ...int) []*Job { // Remove the submission's `score`, `penalty` and `verdict`. func resetScore(db db.DBContext, subIDs ...int) error { - query, params, err := sqlx.In(`UPDATE submissions SET score = NULL, penalty = NULL, verdict = `+VerdictIsInQueue+`WHERE id IN (?)`, subIDs) + query, params, err := sqlx.In(`UPDATE submissions SET score = NULL, penalty = NULL, verdict = ? WHERE id IN (?)`, VerdictIsInQueue, subIDs) if err != nil { return errors.WithStack(err) } From f8f7bd38ade9605abfcb9e2f548c14ee76710f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Minh=20Nh=E1=BA=ADt?= <86871862+minhnhatnoe@users.noreply.github.com> Date: Thu, 18 May 2023 08:57:46 +0700 Subject: [PATCH 19/23] Simpler log for undetected contest type Co-authored-by: Natsu Kagami --- models/scoreboard.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/models/scoreboard.go b/models/scoreboard.go index afebba34..0505b1e4 100644 --- a/models/scoreboard.go +++ b/models/scoreboard.go @@ -155,9 +155,7 @@ func compareUserRanking(userResult []*UserResult, contestType ContestType, i, j } return a.User.ID < b.User.ID, true } - // in no case should this path be reached - // this just stays here in case someone implements a custom contest type - log.Panicf("Contest type %s does not exists or not yet implemented", contestType) + log.Panicf("unexpected contest type %s", contestType) return true, true } From 982e736dcbd8db6a45394d3cd6d3dbb7bd68440a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nh=E1=BA=ADt=20Nguy=E1=BB=85n?= <86871862+minhnhatnoe@users.noreply.github.com> Date: Thu, 18 May 2023 09:03:58 +0700 Subject: [PATCH 20/23] Revert capitalization of logs --- embed/embed_dev.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embed/embed_dev.go b/embed/embed_dev.go index 4d868d7d..2a9c5c08 100644 --- a/embed/embed_dev.go +++ b/embed/embed_dev.go @@ -16,16 +16,16 @@ var Content fs.FS func init() { wd, err := os.Getwd() if err != nil { - log.Panicf("Cannot get current directory: %v", err) + log.Panicf("cannot get current directory: %v", err) } embedDir := filepath.Join(wd, "embed") stat, err := os.Stat(embedDir) if err != nil { - log.Panicf("Cannot stat embed directory: %v", err) + log.Panicf("cannot stat embed directory: %v", err) } if !stat.IsDir() { - log.Panicf("Embed directory is not a directory: %s", embedDir) + log.Panicf("embed directory is not a directory: %s", embedDir) } log.Printf("[dev] serving embedded content from %s", embedDir) From 5e5b338df772adc1af0ae830742874a34ebe0687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nh=E1=BA=ADt=20Nguy=E1=BB=85n?= <86871862+minhnhatnoe@users.noreply.github.com> Date: Thu, 18 May 2023 09:11:17 +0700 Subject: [PATCH 21/23] Minor fixes --- scripts/windows/gen_cert.ps1 | 4 ++-- server/root_ca.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/windows/gen_cert.ps1 b/scripts/windows/gen_cert.ps1 index d856686b..0aacb22e 100644 --- a/scripts/windows/gen_cert.ps1 +++ b/scripts/windows/gen_cert.ps1 @@ -64,7 +64,7 @@ Write-Host "- Common name = $CERT_CN" Write-Host "- Email address = $CERT_EMAIL" Write-Host "- Alt hosts = $CERT_ALTNAMES" -Function generateKey { +Function Build-Key { If ([System.IO.File]::Exists([IO.Path]::Combine($ROOT_DIR, ".certs_generated"))){ Write-Host "Certificate has already been generated." return 0 @@ -93,7 +93,7 @@ Function generateKey { Write-Host "Certificate generation complete." Out-File -FilePath "$CERT_GPATH" } -generateKey +Build-Key Write-Host "To re-generate the keys, delete " "$CERT_GPATH" Write-Host "Please keep $ROOT_KEY and $KJUDGE_KEY secret, while distributing" ` diff --git a/server/root_ca.go b/server/root_ca.go index 336462fd..57a79bee 100644 --- a/server/root_ca.go +++ b/server/root_ca.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" ) -// ServeHTTPRootCA starts a HTTP server running on `address` using the .pem file at +// ServeHTTPRootCA starts a HTTP server running on `address` serving the .pem file at // rootCA, serving the root CA from "/ca". It rejects all other requests. func (s *Server) ServeHTTPRootCA(address, rootCA string) error { if stat, err := os.Stat(rootCA); err != nil { From 054df8ce1e4fdab8225362126250919e95714d67 Mon Sep 17 00:00:00 2001 From: minhnhatnoe <86871862+minhnhatnoe@users.noreply.github.com> Date: Sat, 20 May 2023 18:42:04 +0700 Subject: [PATCH 22/23] Undo TODOs --- worker/compile.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/worker/compile.go b/worker/compile.go index 0c0726d9..7f087a6f 100644 --- a/worker/compile.go +++ b/worker/compile.go @@ -2,10 +2,8 @@ package worker // Compiling anything that's more compicated than single file: // -// - Prepare a "compile_%s.%ext" file, with %s being the language (cc, go, rs, java, py2, py3, pas) and -// TODO: %ext being the shell extension (.sh for linux and .bat/.ps1 for windows). -// - Prepare any more files as needed. They will all be put into the CWD of the script, -// TODO: except for "special" files. +// - Prepare a "compile_%s.%ext" file, with %s being the language (cc, go, rs, java, py2, py3, pas) +// - Prepare any more files as needed. They will all be put into the CWD of the script // - The CWD also contains "code.%s" (%s being the language's respective extension) file, which is the contestant's source code. // - The script should do whatever it wants (unsandboxed, because it's not my job to do so) within 20 seconds. // - It should produce a single binary called "code" in the CWD. From 910dadced9474ba580ff85deeb3c451f7a237a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Minh=20Nh=E1=BA=ADt?= <86871862+minhnhatnoe@users.noreply.github.com> Date: Fri, 26 May 2023 18:58:32 +0700 Subject: [PATCH 23/23] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ad80bae2..ba456ea7 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ Usage of ./kjudge: ## Build Instructions +Warning: Windows support for kjudge is a WIP (and by that we mean machine-wrecking WIP). Run at your own risk. + External Dependencies: ```yaml