From 9600bdc4e1a4c1c44f0110d9b809ef3cfd7d075c Mon Sep 17 00:00:00 2001 From: Jonathan Khoo Date: Wed, 15 May 2024 23:48:39 +1200 Subject: [PATCH 01/10] Pin isolate to 1.10.1 (#266) This is the last version that supports cgroups v1; isolate 2.0 supports only cgroups v2. --- .github/workflows/ci.yml | 2 +- script/install/config.bash | 2 +- script/install/isolate.bash | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fd34ad0..22562e79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: SCHEDULE_BACKUPS: 0 ISOLATE_ROOT: / ISOLATE_CGROUPS: false - ISOLATE_BRANCH: master + ISOLATE_BRANCH: v1.10.1 - name: Back up db/schema.rb # it will be overwritten when install.bash runs migrate.bash; back up the original so we can check if it's up to date run: cp db/schema.rb db/schema.rb.git diff --git a/script/install/config.bash b/script/install/config.bash index 62d830dd..250231f4 100644 --- a/script/install/config.bash +++ b/script/install/config.bash @@ -203,7 +203,7 @@ declare -p ISOLATE_CGROUPS &> /dev/null || while [ -z "$ISOLATE_CGROUPS" ] ; do else ISOLATE_CGROUPS=false; fi done -declare -p ISOLATE_BRANCH &> /dev/null || ISOLATE_BRANCH=master # no prompt +declare -p ISOLATE_BRANCH &> /dev/null || ISOLATE_BRANCH=v1.10.1 # no prompt shopt -u nocasematch; diff --git a/script/install/isolate.bash b/script/install/isolate.bash index d8d3dc8c..a6ecc154 100644 --- a/script/install/isolate.bash +++ b/script/install/isolate.bash @@ -9,7 +9,7 @@ cd $srclocation if [ -d "isolate" ]; then cd isolate done=true - git pull --force | grep -q -v 'Already up-to-date.' && done=false + # git pull --force | grep -q -v 'Already up-to-date.' && done=false if $done; then exit fi From 2f097d0f16ed2b7530e399da2236eaa5b3321292 Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Wed, 26 Feb 2020 00:21:21 +1300 Subject: [PATCH 02/10] Confirm before installing the J programming language (#248) --- script/install/debootstrap.bash | 36 +++++++++++++++++---------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/script/install/debootstrap.bash b/script/install/debootstrap.bash index 187415dc..f259fb38 100644 --- a/script/install/debootstrap.bash +++ b/script/install/debootstrap.bash @@ -145,20 +145,21 @@ chroot "$ISOLATE_ROOT" apt-get install openjdk-11-jdk # Java chroot "$ISOLATE_ROOT" apt-get install ruby2.2 - ## INSTALL J - chroot "$ISOLATE_ROOT" mkdir /home/j -p - J_TAG="J803" - J_DEB="j803_amd64.deb" - J_SAVE="/home/j/$J_DEB" - [ -f "$ISOLATE_ROOT/$J_SAVE" ] || { - echo "wget -O \"$ISOLATE_ROOT/$J_SAVE\" https://github.com/NZOI/J-install/releases/download/$J_TAG/$J_DEB" - wget -O "$ISOLATE_ROOT/$J_SAVE" "https://github.com/NZOI/J-install/releases/download/$J_TAG/$J_DEB" - } - - echo "$chroot_cmd dpkg -i $J_SAVE" - chroot "$ISOLATE_ROOT" dpkg -i "$J_SAVE" - - cat << EOF > "$ISOLATE_ROOT"/home/j/install.ijs + # install J + bash script/confirm.bash 'Install J' && { + chroot "$ISOLATE_ROOT" mkdir /home/j -p + J_TAG="J803" + J_DEB="j803_amd64.deb" + J_SAVE="/home/j/$J_DEB" + [ -f "$ISOLATE_ROOT/$J_SAVE" ] || { + echo "wget -O \"$ISOLATE_ROOT/$J_SAVE\" https://github.com/NZOI/J-install/releases/download/$J_TAG/$J_DEB" + wget -O "$ISOLATE_ROOT/$J_SAVE" "https://github.com/NZOI/J-install/releases/download/$J_TAG/$J_DEB" + } + + echo "$chroot_cmd dpkg -i $J_SAVE" + chroot "$ISOLATE_ROOT" dpkg -i "$J_SAVE" + + cat << EOF > "$ISOLATE_ROOT"/home/j/install.ijs load 'pacman' 'update' jpkg '' 'install' jpkg 'format/printf' @@ -168,9 +169,10 @@ load 'pacman' exit 0 EOF - echo "$chroot_cmd ijconsole /home/j/install.ijs" - chroot "$ISOLATE_ROOT" ijconsole /home/j/install.ijs - ## END INSTALL J + echo "$chroot_cmd ijconsole /home/j/install.ijs" + chroot "$ISOLATE_ROOT" ijconsole /home/j/install.ijs + } + # end install J } From e3d3b4ef80a609c283dd771540d36366fab491ae Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Wed, 26 Feb 2020 00:29:45 +1300 Subject: [PATCH 03/10] Switch to headless JDK in deboostrap (#248) It is smaller, and we don't need the GUI libraries. --- script/install/debootstrap.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/script/install/debootstrap.bash b/script/install/debootstrap.bash index f259fb38..7324634d 100644 --- a/script/install/debootstrap.bash +++ b/script/install/debootstrap.bash @@ -113,7 +113,7 @@ chroot "$ISOLATE_ROOT" apt-get install ruby # Ruby (ruby) # LD_ORIGIN_PATH.) } -if ! chroot "$ISOLATE_ROOT" apt-cache show openjdk-11-jdk &>/dev/null; then +if ! chroot "$ISOLATE_ROOT" apt-cache show openjdk-11-jdk-headless &>/dev/null; then # add java ppa echo "$chroot_cmd add-apt-repository ppa:openjdk-r/ppa -y" chroot "$ISOLATE_ROOT" add-apt-repository ppa:openjdk-r/ppa -y @@ -122,8 +122,8 @@ if ! chroot "$ISOLATE_ROOT" apt-cache show openjdk-11-jdk &>/dev/null; then chroot "$ISOLATE_ROOT" apt-get update fi -echo "$chroot_install openjdk-11-jdk" -chroot "$ISOLATE_ROOT" apt-get install openjdk-11-jdk # Java +echo "$chroot_install openjdk-11-jdk-headless" +chroot "$ISOLATE_ROOT" apt-get install openjdk-11-jdk-headless # Java [ -z "$CI" ] && { # if not in CI From 07fa028dec10d670ddd9b8125721d9459baebdf5 Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Wed, 26 Feb 2020 00:32:10 +1300 Subject: [PATCH 04/10] Skip installation of JDK in deboostrap during CI (#248) There are no test submissions in Java, so it's not required and only makes CI slower. --- script/install/debootstrap.bash | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/script/install/debootstrap.bash b/script/install/debootstrap.bash index 7324634d..4fa725a3 100644 --- a/script/install/debootstrap.bash +++ b/script/install/debootstrap.bash @@ -113,17 +113,20 @@ chroot "$ISOLATE_ROOT" apt-get install ruby # Ruby (ruby) # LD_ORIGIN_PATH.) } -if ! chroot "$ISOLATE_ROOT" apt-cache show openjdk-11-jdk-headless &>/dev/null; then - # add java ppa - echo "$chroot_cmd add-apt-repository ppa:openjdk-r/ppa -y" - chroot "$ISOLATE_ROOT" add-apt-repository ppa:openjdk-r/ppa -y - - echo "$chroot_cmd apt-get update" - chroot "$ISOLATE_ROOT" apt-get update -fi +[ -z "$CI" ] && { # if not in CI + # Java + if ! chroot "$ISOLATE_ROOT" apt-cache show openjdk-11-jdk-headless &>/dev/null; then + # add java ppa + echo "$chroot_cmd add-apt-repository ppa:openjdk-r/ppa -y" + chroot "$ISOLATE_ROOT" add-apt-repository ppa:openjdk-r/ppa -y + + echo "$chroot_cmd apt-get update" + chroot "$ISOLATE_ROOT" apt-get update + fi -echo "$chroot_install openjdk-11-jdk-headless" -chroot "$ISOLATE_ROOT" apt-get install openjdk-11-jdk-headless # Java + echo "$chroot_install openjdk-11-jdk-headless" + chroot "$ISOLATE_ROOT" apt-get install openjdk-11-jdk-headless # Java +} [ -z "$CI" ] && { # if not in CI From 095d12cd35f63b65c657e41ad6563589644a270e Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Thu, 16 May 2024 00:59:08 +1200 Subject: [PATCH 05/10] Remove nokogiri dependency packages (#249) As of Nokogiri 1.6, libxml2 and libxslt are bundled with Nokogiri [1], so we don't need to install the header files. [1] https://github.com/sparklemotion/nokogiri/blob/v1.6.8.1/CHANGELOG.rdoc#label-1.6.0.rc1+-2F+2013-04-14 --- script/install.bash | 2 -- script/install/nokogiri.bash | 7 ------- 2 files changed, 9 deletions(-) delete mode 100644 script/install/nokogiri.bash diff --git a/script/install.bash b/script/install.bash index 9dedd570..029449dc 100755 --- a/script/install.bash +++ b/script/install.bash @@ -40,8 +40,6 @@ bash script/install/nztrain.bash || exit 1 # fix files & directory structure bash script/install/bundler.bash || exit 1 -bash script/install/nokogiri.bash || exit 1 # nokogiri dependencies - bash script/install/jdk.bash || exit 1 # required by yui-compressor sudo bash script/install/isolate.bash || exit 1 # install isolate diff --git a/script/install/nokogiri.bash b/script/install/nokogiri.bash deleted file mode 100644 index 0934922b..00000000 --- a/script/install/nokogiri.bash +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -cmd="sudo apt-get install libxslt-dev libxml2-dev" - -echo "$ $cmd" -$cmd - From 00b3dc3f74edcf038d7cd92422891690a9fc74b9 Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Wed, 26 Feb 2020 00:45:11 +1300 Subject: [PATCH 06/10] Switch to default-jre-headless on server for yui-compressor (#251) Was previously openjdk-8-jdk. - yui-compressor only requires the JRE, not the full JDK - GUI libraries aren't required, headless version is enough - the JRE version doesn't really matter, use the default so it gets automatically updated --- script/install.bash | 2 +- script/install/{jdk.bash => jre.bash} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename script/install/{jdk.bash => jre.bash} (84%) diff --git a/script/install.bash b/script/install.bash index 029449dc..ce1f17f9 100755 --- a/script/install.bash +++ b/script/install.bash @@ -40,7 +40,7 @@ bash script/install/nztrain.bash || exit 1 # fix files & directory structure bash script/install/bundler.bash || exit 1 -bash script/install/jdk.bash || exit 1 # required by yui-compressor +bash script/install/jre.bash || exit 1 # required by yui-compressor sudo bash script/install/isolate.bash || exit 1 # install isolate sudo bash script/install/cgroup.bash || exit 1 # install cgroups diff --git a/script/install/jdk.bash b/script/install/jre.bash similarity index 84% rename from script/install/jdk.bash rename to script/install/jre.bash index 9820b59e..8b9a6f23 100644 --- a/script/install/jdk.bash +++ b/script/install/jre.bash @@ -10,7 +10,7 @@ # } || exit 1 #} -cmd="sudo apt-get install openjdk-8-jdk" # java required by yui-compressor gem +cmd="sudo apt-get install default-jre-headless" # java required by yui-compressor gem echo "$ $cmd" $cmd [[ $? -le 1 ]] || exit 1 # apt-get exit 0 = success, 1 = decline, otherwise unknown error From b29d5f235b3e053e2e22ef8fcbd010ac8cc70bb0 Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Wed, 26 Feb 2020 00:50:50 +1300 Subject: [PATCH 07/10] Remove unrelated commented-out lines from JRE install script (#251) The lines were copied from script/install/imagemagick.bash and are irrelevant. --- script/install/jre.bash | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/script/install/jre.bash b/script/install/jre.bash index 8b9a6f23..5c34bd11 100644 --- a/script/install/jre.bash +++ b/script/install/jre.bash @@ -1,15 +1,5 @@ #!/usr/bin/env bash -#min_version=6 -#convert -version 2>/dev/null | bash script/extract_version.bash | bash script/check_version.bash $min_version || { # already installed -# echo ImageMagick $min_version+ required! -# bash script/confirm.bash "Install ImageMagick" && { -# cmd="sudo apt-get install imagemagick" -# echo "$ $cmd" -# $cmd -# } || exit 1 -#} - cmd="sudo apt-get install default-jre-headless" # java required by yui-compressor gem echo "$ $cmd" $cmd From 7ecce6d70c09ff1eed8348e9b8c49eb73213c9e9 Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Thu, 4 Jan 2024 02:35:22 +1300 Subject: [PATCH 08/10] Skip wkhtmltopdf in CI (#255) It is used by the PDFKit gem, which is only used from app/views/item/label.html.erb. That view is not tested, so we can make CI faster by skipping the install of wkhtmltopdf. (We can add it back if/when we write a test for the view.) --- script/install.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/install.bash b/script/install.bash index ce1f17f9..7b8aef27 100755 --- a/script/install.bash +++ b/script/install.bash @@ -34,7 +34,7 @@ bash script/install/postgresql.bash || exit 1 # create user & db if it doesn't e bash script/install/imagemagick.bash || exit 1 # install imagemagick -sudo apt-get install wkhtmltopdf xvfb || exit 1 +[ -n "$CI" ] || sudo apt-get install wkhtmltopdf xvfb || exit 1 # for pdfkit; skip in CI bash script/install/nztrain.bash || exit 1 # fix files & directory structure From 4b38411042978a6d694b1c3ae2f90ad4b7388b21 Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Thu, 4 Jan 2024 02:39:13 +1300 Subject: [PATCH 09/10] Display the command that installs wkhtmltopdf (#255) It is difficult to tell from the output of apt-get which packages were requested, because they are interleaved with their dependencies. Also factor it out into a separate script. --- script/install.bash | 2 +- script/install/wkhtmltopdf.bash | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 script/install/wkhtmltopdf.bash diff --git a/script/install.bash b/script/install.bash index 7b8aef27..234f6928 100755 --- a/script/install.bash +++ b/script/install.bash @@ -34,7 +34,7 @@ bash script/install/postgresql.bash || exit 1 # create user & db if it doesn't e bash script/install/imagemagick.bash || exit 1 # install imagemagick -[ -n "$CI" ] || sudo apt-get install wkhtmltopdf xvfb || exit 1 # for pdfkit; skip in CI +[ -n "$CI" ] || bash script/install/wkhtmltopdf.bash || exit 1 # for pdfkit; skip in CI bash script/install/nztrain.bash || exit 1 # fix files & directory structure diff --git a/script/install/wkhtmltopdf.bash b/script/install/wkhtmltopdf.bash new file mode 100644 index 00000000..d6c05350 --- /dev/null +++ b/script/install/wkhtmltopdf.bash @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +cmd="sudo apt-get install wkhtmltopdf xvfb" +echo "$ $cmd" +$cmd || exit 1 From ee7d41727ff4a6fee590f9cfeb478cd82f551de3 Mon Sep 17 00:00:00 2001 From: Jonathan Khoo Date: Sun, 19 May 2024 18:44:02 +1200 Subject: [PATCH 10/10] Add support for custom evaluators using compiled langauges (#260) --- app/assets/stylesheets/submission.css | 1 + app/controllers/evaluators_controller.rb | 2 +- app/models/evaluator.rb | 1 + app/models/submission/judge_data.rb | 8 +++ app/views/evaluators/_form.html.erb | 4 ++ app/views/evaluators/index.html.erb | 2 + app/views/evaluators/show.html.erb | 4 +- app/views/problems/_admin.html.erb | 2 +- app/views/submissions/show.html.erb | 25 +++++++--- app/workers/judge_submission_worker.rb | 49 +++++++++++++------ ...225054132_add_language_id_to_evaluators.rb | 5 ++ db/schema.rb | 3 +- 12 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 db/migrate/20230225054132_add_language_id_to_evaluators.rb diff --git a/app/assets/stylesheets/submission.css b/app/assets/stylesheets/submission.css index 0e90889b..8adfcacb 100644 --- a/app/assets/stylesheets/submission.css +++ b/app/assets/stylesheets/submission.css @@ -19,6 +19,7 @@ table.results { border-spacing: 0; border-collapse: collapse; width: 100%; + margin: 15px 0px; } .results th { diff --git a/app/controllers/evaluators_controller.rb b/app/controllers/evaluators_controller.rb index 43b87745..1c61e1fa 100644 --- a/app/controllers/evaluators_controller.rb +++ b/app/controllers/evaluators_controller.rb @@ -2,7 +2,7 @@ class EvaluatorsController < ApplicationController def permitted_params @_permitted_params ||= begin - permitted_attributes = [:name, :description, :source] + permitted_attributes = [:name, :description, :source, :language_id] permitted_attributes << :owner_id if policy(@evaluator || Evaluator).transfer? params.require(:evaluator).permit(*permitted_attributes) end diff --git a/app/models/evaluator.rb b/app/models/evaluator.rb index 1e4d32a3..1011a1e2 100644 --- a/app/models/evaluator.rb +++ b/app/models/evaluator.rb @@ -3,6 +3,7 @@ class Evaluator < ActiveRecord::Base has_many :problems belongs_to :owner, :class_name => :User + belongs_to :language validates :name, :presence => true diff --git a/app/models/submission/judge_data.rb b/app/models/submission/judge_data.rb index 23a577db..ed8f3c87 100644 --- a/app/models/submission/judge_data.rb +++ b/app/models/submission/judge_data.rb @@ -285,10 +285,18 @@ def compiled? data.has_key?('compile') end + def evaluator_compiled? + data.has_key?('evaluator_compile') + end + def compilation @compilation ||= Compilation.new(data['compile']) end + def evaluator_compilation + @evaluator_compilation ||= Compilation.new(data['evaluator_compile']) + end + def prerequisite_sets test_sets.slice(@presets) end diff --git a/app/views/evaluators/_form.html.erb b/app/views/evaluators/_form.html.erb index 35f86b4d..33f4d741 100644 --- a/app/views/evaluators/_form.html.erb +++ b/app/views/evaluators/_form.html.erb @@ -23,6 +23,10 @@ <%= f.label :source %>
<%= f.text_area :source %> +
+ <%= f.label :language_id %>
+ <%= f.select :language_id, grouped_options_for_select(Language.grouped_submission_options, @evaluator.language_id), :include_blank => true %> +
<%= f.label :owner_id %>
<% if policy(@evaluator).transfer? %> diff --git a/app/views/evaluators/index.html.erb b/app/views/evaluators/index.html.erb index 6d5de645..13d0928e 100644 --- a/app/views/evaluators/index.html.erb +++ b/app/views/evaluators/index.html.erb @@ -7,6 +7,7 @@ Name Description User + Langauge <% if policy(Evaluator).update? %> @@ -22,6 +23,7 @@ <%= evaluator.name %> <%= evaluator.description %> <%= evaluator.owner_id %> + <%= evaluator.language&.name %> <%= link_to 'Show', evaluator %> <% if policy(Evaluator).update? %> <%= link_to 'Edit', edit_evaluator_path(evaluator) if policy(evaluator).update? %> diff --git a/app/views/evaluators/show.html.erb b/app/views/evaluators/show.html.erb index 9de7a7c9..d91657de 100644 --- a/app/views/evaluators/show.html.erb +++ b/app/views/evaluators/show.html.erb @@ -8,8 +8,10 @@

<% if policy(@evaluator).inspect? %>

+ Language: + <%= @evaluator.language&.name %>
Source: -

<%= @evaluator.source %>
+ <%= predisplay @evaluator.source, language: @evaluator.language&.lexer %>

<% end %> diff --git a/app/views/problems/_admin.html.erb b/app/views/problems/_admin.html.erb index f8128d3f..c91dec9b 100644 --- a/app/views/problems/_admin.html.erb +++ b/app/views/problems/_admin.html.erb @@ -54,7 +54,7 @@ <% if @problem.evaluator %> <%= link_to @problem.evaluator.name, @problem.evaluator %> <% if policy(@problem.evaluator).inspect? # privilege required to see evaluator source %> - <%= predisplay @problem.evaluator.source, language: :sh %> + <%= predisplay @problem.evaluator.source, language: @problem.evaluator.language&.lexer %> <% end %> <% else %> Default evaluator diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index 13954682..8ebfaae9 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -47,8 +47,8 @@

<% @judge_data = @submission.judge_data %> - - <% if @judge_data.compiled? %> +<% if @judge_data.compiled? %> +
@@ -59,9 +59,22 @@ - <% end %> -
Compilation: <%= @judge_data.compilation.command %><%= @judge_data.compilation.log %>
-  + +<% end %> +<% if @judge_data.evaluator_compiled? && @submission.problem.evaluator && policy(@submission.problem.evaluator).inspect? %> + + + + + + + + + + + +
Evaluator Compilation: <%= @judge_data.evaluator_compilation.command %><%= @judge_data.evaluator_compilation.judgement %> 
<%= @judge_data.evaluator_compilation.log %>
+<% end %> <% if !@judge_data.compiled? || @judge_data.compilation.status == :success %> @@ -152,8 +165,6 @@
-
-

Source: <%= predisplay(@submission.source || "", language: @submission.language.lexer) %> diff --git a/app/workers/judge_submission_worker.rb b/app/workers/judge_submission_worker.rb index 3939ca9e..238e5973 100644 --- a/app/workers/judge_submission_worker.rb +++ b/app/workers/judge_submission_worker.rb @@ -52,7 +52,7 @@ def perform(submission_id) raise end - EvalFileName = "eval.sh" + EvalFileName = "eval" OutputBaseLimit = 1024 * 1024 * 2 attr_accessor :submission, :exe_filename @@ -68,14 +68,34 @@ def judge result = {} setup_judging do if submission.language.compiled - result['compile'] = compile!(exe_filename) # possible caching - return result.merge!(grade_compile_error(result['compile'])) if result['compile']['stat'] != 0 #error + result['compile'] = compile!(submission.source, submission.language, exe_filename) # possible caching + return result.merge!(grade_compile_error(result['compile'])) if result['compile']['stat'] != 0 # error else File.open(File.expand_path(exe_filename, tmpdir),"w") { |f| f.write(submission.source) } end run_command = submission.language.run_command(exe_filename) + if problem.evaluator.nil? + eval_command = nil + else + if problem.evaluator.language.nil? + eval_command = "./#{EvalFileName}" + else + eval_command = problem.evaluator.language.run_command(EvalFileName) + end + + if problem.evaluator.language&.compiled + evaluator_compilation = compile!(problem.evaluator.source, problem.evaluator.language, EvalFileName) # possible caching + return result.merge!('evaluator_compile' => evaluator_compilation, 'status' => 2) if evaluator_compilation['stat'] != 0 # error + else + File.open(File.expand_path(EvalFileName, tmpdir),"w") do |file| + file.chmod(0700) + file.write(problem.evaluator.source.gsub(/\r\n?/, "\n")) + end + end + end + result['test_cases'] = {} result['test_sets'] = {} @@ -85,7 +105,7 @@ def judge prereqs = problem.test_cases.where(:id => problem.prerequisite_sets.joins(:test_case_relations).select(:test_case_relations => :test_case_id)) prereqs.each do |test_case| - result['test_cases'][test_case.id] = judge_test_case(test_case, run_command, resource_limits) unless result['test_cases'].has_key?(test_case.id) + result['test_cases'][test_case.id] = judge_test_case(test_case, run_command, eval_command, resource_limits) unless result['test_cases'].has_key?(test_case.id) end problem.prerequisite_sets.each do |test_set| @@ -100,7 +120,7 @@ def judge # test cases (problem.test_cases - prereqs).each do |test_case| - result['test_cases'][test_case.id] = judge_test_case(test_case, run_command, resource_limits) unless result['test_cases'].has_key?(test_case.id) + result['test_cases'][test_case.id] = judge_test_case(test_case, run_command, eval_command, resource_limits) unless result['test_cases'].has_key?(test_case.id) end # test sets @@ -148,18 +168,18 @@ def setup_judging end end - def compile! output - result = submission.language.compile(box, submission.source, output, :mem => 393216, :wall_time => 60) + def compile!(source, language, output) + result = language.compile(box, source, output, :mem => 393216, :wall_time => 60) FileUtils.copy(box.expand_path(output), File.expand_path(output, tmpdir)) if result['stat'] == 0 return result ensure box.clean! end - def judge_test_case(test_case, run_command, resource_limits) + def judge_test_case(test_case, run_command, eval_command, resource_limits) FileUtils.copy(File.expand_path(exe_filename, tmpdir), box.expand_path(exe_filename)) result = run_test_case(test_case, run_command, resource_limits) - result['evaluator'] = evaluate_output(test_case, result['output'], result['output_size'], problem.evaluator) + result['evaluator'] = evaluate_output(test_case, result['output'], result['output_size'], eval_command) result['log'] = truncate_output(result['log']) # log only a small portion result['output'] = truncate_output(result['output'].slice(0,100)) # store only a small portion result @@ -190,21 +210,18 @@ def run_test_case(test_case, run_command, resource_limits = {}) box.clean! end - def evaluate_output(test_case, output, output_size, evaluator) + def evaluate_output(test_case, output, output_size, eval_command) stream_limit = OutputBaseLimit + test_case.output.bytesize*2 if output_size > stream_limit return {'evaluation' => 0, 'log' => "Output exceeded the streamsize limit of #{stream_limit}.", 'meta' => {'status' => 'OK'}} end expected = conditioned_output(test_case.output) actual = conditioned_output(output) - if evaluator.nil? + if eval_command.nil? {'evaluation' => (actual == expected ? 1 : 0), 'meta' => {'status' => 'OK'}} else r = {} - box.fopen(EvalFileName,"w") do |file| - file.chmod(0700) - file.write(problem.evaluator.source.gsub(/\r\n?/, "\n")) - end + FileUtils.copy(File.expand_path(EvalFileName, tmpdir), box.expand_path(EvalFileName)) resource_limits = { :mem => 524288, :time => time_limit*3+15, :wall_time => time_limit*3+30 } box.fopen("actual","w") { |f| f.write(actual) } # DEPRECATED box.fopen("input","w") { |f| f.write(test_case.input) } # DEPRECATED @@ -213,7 +230,7 @@ def evaluate_output(test_case, output, output_size, evaluator) eval_output = nil str_to_pipe(test_case.input, expected) do |input_stream, output_stream| run_opts = resource_limits.reverse_merge(:processes => true, 3 => input_stream, 4 => output_stream, :stdin_data => actual, :output_limit => OutputBaseLimit + test_case.output.bytesize*4, :clean_utf8 => true, :inherit_fds => true) - (stdout,), (r['log'],r['log_size']), (r['box'],), r['meta'], status = box.capture5("./#{EvalFileName} #{deprecated_args}", run_opts ) + (stdout,), (r['log'],r['log_size']), (r['box'],), r['meta'], status = box.capture5("#{eval_command} #{deprecated_args}", run_opts ) r['log'] = truncate_output(r['log']) return r.merge('stat' => 2, 'box' => 'Output was not a valid UTF-8 encoding\n'+r['box']) if !output.force_encoding("UTF-8").valid_encoding? eval_output = stdout.strip.split(nil,2) diff --git a/db/migrate/20230225054132_add_language_id_to_evaluators.rb b/db/migrate/20230225054132_add_language_id_to_evaluators.rb new file mode 100644 index 00000000..43721961 --- /dev/null +++ b/db/migrate/20230225054132_add_language_id_to_evaluators.rb @@ -0,0 +1,5 @@ +class AddLanguageIdToEvaluators < ActiveRecord::Migration + def change + add_column :evaluators, :language_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index a096daf6..0c980263 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20200418113601) do +ActiveRecord::Schema.define(version: 20230225054132) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -93,6 +93,7 @@ t.integer "owner_id", null: false t.datetime "created_at" t.datetime "updated_at" + t.integer "language_id" end create_table "file_attachments", force: :cascade do |t|