From ef94623e03ced898b252704dbdaf500d7d24768e Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 8 Aug 2024 20:51:12 +1000 Subject: [PATCH 01/30] refactor: move latex processing into its own container --- .../project_compile_portfolio_module.rb | 60 ++++++++++++++++++- ...ication.pdf.erbtex => application.pdf.erb} | 1 - lib/shell/texlive/latex-build.sh | 19 ++++++ 3 files changed, 78 insertions(+), 2 deletions(-) rename app/views/layouts/{application.pdf.erbtex => application.pdf.erb} (94%) create mode 100644 lib/shell/texlive/latex-build.sh diff --git a/app/models/pdf_generation/project_compile_portfolio_module.rb b/app/models/pdf_generation/project_compile_portfolio_module.rb index 33e72bca4..083ce49d0 100644 --- a/app/models/pdf_generation/project_compile_portfolio_module.rb +++ b/app/models/pdf_generation/project_compile_portfolio_module.rb @@ -66,8 +66,66 @@ def init(project, is_retry) end def make_pdf - render_to_string(template: '/portfolio/portfolio_pdf', layout: true) + logger.debug "Running make_pdf: (portfolio)" + + # Render the portfolio layout + tex_string = render_to_string(template: '/portfolio/portfolio_pdf', layout: true) + + # Create a new working directory to save input.tex into + workdir_name = "#{Process.pid}-#{Thread.current.hash}" + workdir = Rails.root.join("tmp", "texlive-latex", workdir_name) + FileUtils.mkdir_p(workdir); + + # Copy jupynotex.py over into the working directory + FileUtils.cp(Rails.root.join('app', 'views', 'layouts', 'jupynotex.py'), workdir) + + # Save tex_string as input.tex into the workdir + File.open(workdir.join("input.tex"), 'w') do |fout| + fout.puts tex_string + end + + # TODO: clean up pathnames + container_name = "1-formatif-texlive-container" + latex_build_path = "/texlive/shell/latex-build.sh" # mounted path on the texlive container, as defined in .devcontainer/docker-compose.yml + latex_pdf_output_dir = workdir_name + latex_input_file_path = File.join(workdir_name, "input.tex") + + # Docker command to execute the build script in texlive container + command = "sudo docker exec -it #{container_name} #{latex_build_path} #{latex_pdf_output_dir} #{latex_input_file_path}" + + logger.debug "Executing system command: #{command}" + + success = nil + Process.waitpid( + fork do + begin + # Execute the Docker command + success = system(command) + Process.exit! 1 unless success + rescue + logger.info "PDF Generation failed: #{success}" + ensure + Process.exit! 1 + end + end + ) + + # TODO: verify that input.pdf now exists in the workdir, otherwise throw error + + # unless success + # logger.error "Docker command failed: #{command}" + # return "Error generating PDF" + # end + + # Read the generated PDF file and return it as a string + pdf_string = File.read(workdir.join("input.pdf")) + + # Delete temporary workdir containing input.tex/input.pdf and logs + # FileUtils.rm_rf(workdir) + + pdf_string end + end # Create the portfolio for this project diff --git a/app/views/layouts/application.pdf.erbtex b/app/views/layouts/application.pdf.erb similarity index 94% rename from app/views/layouts/application.pdf.erbtex rename to app/views/layouts/application.pdf.erb index ab70189c8..b4b7cd823 100644 --- a/app/views/layouts/application.pdf.erbtex +++ b/app/views/layouts/application.pdf.erb @@ -1,4 +1,3 @@ -<% @latex_config={ :recipe => [ {:command => "lualatex",:runs => 2} ], :supporting => Rails.root.join('app', 'views', 'layouts', 'jupynotex.py') } %> \DocumentMetadata{uncompress} \documentclass[11pt,a4paper]{article} \usepackage[T1]{fontenc} diff --git a/lib/shell/texlive/latex-build.sh b/lib/shell/texlive/latex-build.sh new file mode 100644 index 000000000..da6873e99 --- /dev/null +++ b/lib/shell/texlive/latex-build.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +OUTPUT_DIR=$1 +INPUT_FILE=$2 + +# OUTPUT_DIR and INPUT_FILE contain the name of the working directory. +# Example: +# +# OUTPUT_DIR = "123-567890" +# INPUT_FILE = "123-567890/input.tex" + +cd /workdir/texlive-latex/${OUTPUT_DIR} + +# TODO: add back -halt-on-error and fix .pygtex related errors +/bin/bash -c "lualatex -output-directory /workdir/texlive-latex/${OUTPUT_DIR} -shell-escape -interaction=batchmode /workdir/texlive-latex/${INPUT_FILE}" + +echo "Running lualatex a second time to remove the temporary last page..." + +/bin/bash -c "lualatex -output-directory /workdir/texlive-latex/${OUTPUT_DIR} -shell-escape -interaction=batchmode /workdir/texlive-latex/${INPUT_FILE}" \ No newline at end of file From 9486bedd2226eb7faeb17beb25c0554b6191dcae Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 11 Aug 2024 00:35:05 +1000 Subject: [PATCH 02/30] refactor: task pdf generation --- .../project_compile_portfolio_module.rb | 37 ++++++------ app/models/task.rb | 59 ++++++++++++++++++- 2 files changed, 77 insertions(+), 19 deletions(-) diff --git a/app/models/pdf_generation/project_compile_portfolio_module.rb b/app/models/pdf_generation/project_compile_portfolio_module.rb index 083ce49d0..2066356f0 100644 --- a/app/models/pdf_generation/project_compile_portfolio_module.rb +++ b/app/models/pdf_generation/project_compile_portfolio_module.rb @@ -68,6 +68,8 @@ def init(project, is_retry) def make_pdf logger.debug "Running make_pdf: (portfolio)" + # TODO: move pdf layout -> tex -> pdf generation into shared module/class + # Render the portfolio layout tex_string = render_to_string(template: '/portfolio/portfolio_pdf', layout: true) @@ -93,35 +95,34 @@ def make_pdf # Docker command to execute the build script in texlive container command = "sudo docker exec -it #{container_name} #{latex_build_path} #{latex_pdf_output_dir} #{latex_input_file_path}" - logger.debug "Executing system command: #{command}" - - success = nil Process.waitpid( fork do begin + logger.debug "Executing system command: #{command}" + # Execute the Docker command - success = system(command) - Process.exit! 1 unless success + clean_exit = system(command) + Process.exit!(1) unless clean_exit rescue logger.info "PDF Generation failed: #{success}" ensure - Process.exit! 1 + Process.exit!(1) end end ) - # TODO: verify that input.pdf now exists in the workdir, otherwise throw error - - # unless success - # logger.error "Docker command failed: #{command}" - # return "Error generating PDF" - # end - - # Read the generated PDF file and return it as a string - pdf_string = File.read(workdir.join("input.pdf")) - - # Delete temporary workdir containing input.tex/input.pdf and logs - # FileUtils.rm_rf(workdir) + status = $?.exitstatus + + if status == 0 && File.exists(File.join(workdir, "input.pdf")) + # Read the generated PDF file and return it as a string + pdf_string = File.read(workdir.join("input.pdf")) + + # Delete temporary workdir containing input.tex/input.pdf and logs + FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't removed in this call + else + # TODO: raise exception + logger.error "PDF Generation failed with exit status: #{status}" + end pdf_string end diff --git a/app/models/task.rb b/app/models/task.rb index e75815f90..b230e7430 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1023,7 +1023,64 @@ def make_pdf end end logger.debug "Preprocessing complete, rendering file." - render_to_string(template: '/task/task_pdf', layout: true) + + # TODO: move pdf layout -> tex -> pdf generation into shared module/class + + # Render the task layout + tex_string = render_to_string(template: '/task/task_pdf', layout: true) + + # Create a new working directory to save input.tex into + workdir_name = "#{Process.pid}-#{Thread.current.hash}" + workdir = Rails.root.join("tmp", "texlive-latex", workdir_name) + FileUtils.mkdir_p(workdir); + + # Copy jupynotex.py over into the working directory + FileUtils.cp(Rails.root.join('app', 'views', 'layouts', 'jupynotex.py'), workdir) + + # Save tex_string as input.tex into the workdir + File.open(workdir.join("input.tex"), 'w') do |fout| + fout.puts tex_string + end + + # TODO: clean up pathnames + container_name = "1-formatif-texlive-container" + latex_build_path = "/texlive/shell/latex-build.sh" # mounted path on the texlive container, as defined in .devcontainer/docker-compose.yml + latex_pdf_output_dir = workdir_name + latex_input_file_path = File.join(workdir_name, "input.tex") + + # Docker command to execute the build script in texlive container + command = "sudo docker exec -it #{container_name} #{latex_build_path} #{latex_pdf_output_dir} #{latex_input_file_path}" + + Process.waitpid( + fork do + begin + logger.debug "Executing system command: #{command}" + + # Execute the Docker command + clean_exit = system(command) + Process.exit!(1) unless clean_exit + rescue + logger.info "PDF Generation failed: #{success}" + ensure + Process.exit!(1) + end + end + ) + + status = $?.exitstatus + + if status == 0 && File.exists(File.join(workdir, "input.pdf")) + # Read the generated PDF file and return it as a string + pdf_string = File.read(workdir.join("input.pdf")) + + # Delete temporary workdir containing input.tex/input.pdf and logs + FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't removed in this call + else + # TODO: raise exception + logger.error "PDF Generation failed with exit status: #{status}" + end + + pdf_string end end From afb98ea54d095a85a539f2d62f14ffdfe37caf70 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 11 Aug 2024 00:54:51 +1000 Subject: [PATCH 03/30] refactor: cleanup latex docker command and compile script --- .../project_compile_portfolio_module.rb | 6 ++--- app/models/task.rb | 8 +++---- lib/shell/texlive/latex-build.sh | 22 ++++++------------- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/app/models/pdf_generation/project_compile_portfolio_module.rb b/app/models/pdf_generation/project_compile_portfolio_module.rb index 2066356f0..3ceb2688f 100644 --- a/app/models/pdf_generation/project_compile_portfolio_module.rb +++ b/app/models/pdf_generation/project_compile_portfolio_module.rb @@ -68,7 +68,7 @@ def init(project, is_retry) def make_pdf logger.debug "Running make_pdf: (portfolio)" - # TODO: move pdf layout -> tex -> pdf generation into shared module/class + # TODO: move pdf layout -> tex -> pdf generation into shared module/class (duplicated in models/task.rb) # Render the portfolio layout tex_string = render_to_string(template: '/portfolio/portfolio_pdf', layout: true) @@ -89,11 +89,9 @@ def make_pdf # TODO: clean up pathnames container_name = "1-formatif-texlive-container" latex_build_path = "/texlive/shell/latex-build.sh" # mounted path on the texlive container, as defined in .devcontainer/docker-compose.yml - latex_pdf_output_dir = workdir_name - latex_input_file_path = File.join(workdir_name, "input.tex") # Docker command to execute the build script in texlive container - command = "sudo docker exec -it #{container_name} #{latex_build_path} #{latex_pdf_output_dir} #{latex_input_file_path}" + command = "sudo docker exec -it #{container_name} #{latex_build_path} #{workdir_name}" Process.waitpid( fork do diff --git a/app/models/task.rb b/app/models/task.rb index b230e7430..025d0ebf0 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1024,7 +1024,7 @@ def make_pdf end logger.debug "Preprocessing complete, rendering file." - # TODO: move pdf layout -> tex -> pdf generation into shared module/class + # TODO: move pdf layout -> tex -> pdf generation into shared module/class (duplicated in models/pdf_generation/project_compile_portfolio_module.rb) # Render the task layout tex_string = render_to_string(template: '/task/task_pdf', layout: true) @@ -1045,12 +1045,10 @@ def make_pdf # TODO: clean up pathnames container_name = "1-formatif-texlive-container" latex_build_path = "/texlive/shell/latex-build.sh" # mounted path on the texlive container, as defined in .devcontainer/docker-compose.yml - latex_pdf_output_dir = workdir_name - latex_input_file_path = File.join(workdir_name, "input.tex") # Docker command to execute the build script in texlive container - command = "sudo docker exec -it #{container_name} #{latex_build_path} #{latex_pdf_output_dir} #{latex_input_file_path}" - + command = "sudo docker exec -it #{container_name} #{latex_build_path} #{workdir_name}" + Process.waitpid( fork do begin diff --git a/lib/shell/texlive/latex-build.sh b/lib/shell/texlive/latex-build.sh index da6873e99..3dbc4cc43 100644 --- a/lib/shell/texlive/latex-build.sh +++ b/lib/shell/texlive/latex-build.sh @@ -1,19 +1,11 @@ #!/bin/sh -OUTPUT_DIR=$1 -INPUT_FILE=$2 +# Name of the working directory +WORK_DIR=$1 -# OUTPUT_DIR and INPUT_FILE contain the name of the working directory. -# Example: -# -# OUTPUT_DIR = "123-567890" -# INPUT_FILE = "123-567890/input.tex" +cd /workdir/texlive-latex/${WORK_DIR} -cd /workdir/texlive-latex/${OUTPUT_DIR} - -# TODO: add back -halt-on-error and fix .pygtex related errors -/bin/bash -c "lualatex -output-directory /workdir/texlive-latex/${OUTPUT_DIR} -shell-escape -interaction=batchmode /workdir/texlive-latex/${INPUT_FILE}" - -echo "Running lualatex a second time to remove the temporary last page..." - -/bin/bash -c "lualatex -output-directory /workdir/texlive-latex/${OUTPUT_DIR} -shell-escape -interaction=batchmode /workdir/texlive-latex/${INPUT_FILE}" \ No newline at end of file +# TODO: debug test file submissions: '002-code.cs', 'java_with_invalid_unicode.java', 'long.ipynb' ... (are they supposed to fail lualatex compile?) +/bin/bash -c "lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex" +echo "Running lualatex a second time to remove temporary last page..." +/bin/bash -c "lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex" \ No newline at end of file From a63cee85efb0c1c4980743d18660af7da805d491 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 11 Aug 2024 01:12:26 +1000 Subject: [PATCH 04/30] fix: set correct exit status --- .../pdf_generation/project_compile_portfolio_module.rb | 6 +++--- app/models/task.rb | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/models/pdf_generation/project_compile_portfolio_module.rb b/app/models/pdf_generation/project_compile_portfolio_module.rb index 3ceb2688f..4d19aef23 100644 --- a/app/models/pdf_generation/project_compile_portfolio_module.rb +++ b/app/models/pdf_generation/project_compile_portfolio_module.rb @@ -104,19 +104,19 @@ def make_pdf rescue logger.info "PDF Generation failed: #{success}" ensure - Process.exit!(1) + Process.exit!(0) if clean_exit end end ) status = $?.exitstatus - if status == 0 && File.exists(File.join(workdir, "input.pdf")) + if status == 0 && File.exist?(File.join(workdir, "input.pdf")) # Read the generated PDF file and return it as a string pdf_string = File.read(workdir.join("input.pdf")) # Delete temporary workdir containing input.tex/input.pdf and logs - FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't removed in this call + FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call else # TODO: raise exception logger.error "PDF Generation failed with exit status: #{status}" diff --git a/app/models/task.rb b/app/models/task.rb index 025d0ebf0..111c15d21 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1048,7 +1048,7 @@ def make_pdf # Docker command to execute the build script in texlive container command = "sudo docker exec -it #{container_name} #{latex_build_path} #{workdir_name}" - + Process.waitpid( fork do begin @@ -1060,19 +1060,19 @@ def make_pdf rescue logger.info "PDF Generation failed: #{success}" ensure - Process.exit!(1) + Process.exit!(0) if clean_exit end end ) status = $?.exitstatus - if status == 0 && File.exists(File.join(workdir, "input.pdf")) + if status == 0 && File.exist?(File.join(workdir, "input.pdf")) # Read the generated PDF file and return it as a string pdf_string = File.read(workdir.join("input.pdf")) # Delete temporary workdir containing input.tex/input.pdf and logs - FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't removed in this call + FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call else # TODO: raise exception logger.error "PDF Generation failed with exit status: #{status}" From a6632c561372ba8bb8eeff6df676616f3da3495b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 12 Aug 2024 23:02:22 +1000 Subject: [PATCH 05/30] refactor: create a new working directory for each unique latex render --- .../pdf_generation/project_compile_portfolio_module.rb | 10 +++++----- app/models/task.rb | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/models/pdf_generation/project_compile_portfolio_module.rb b/app/models/pdf_generation/project_compile_portfolio_module.rb index 4d19aef23..26620f4aa 100644 --- a/app/models/pdf_generation/project_compile_portfolio_module.rb +++ b/app/models/pdf_generation/project_compile_portfolio_module.rb @@ -74,7 +74,7 @@ def make_pdf tex_string = render_to_string(template: '/portfolio/portfolio_pdf', layout: true) # Create a new working directory to save input.tex into - workdir_name = "#{Process.pid}-#{Thread.current.hash}" + workdir_name = "portfolio-#{Process.pid}-#{Thread.current.hash}-#{project.id}" workdir = Rails.root.join("tmp", "texlive-latex", workdir_name) FileUtils.mkdir_p(workdir); @@ -104,19 +104,19 @@ def make_pdf rescue logger.info "PDF Generation failed: #{success}" ensure - Process.exit!(0) if clean_exit + Process.exit!(0) if clean_exit end end ) status = $?.exitstatus - + if status == 0 && File.exist?(File.join(workdir, "input.pdf")) # Read the generated PDF file and return it as a string pdf_string = File.read(workdir.join("input.pdf")) - + # Delete temporary workdir containing input.tex/input.pdf and logs - FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call + # FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call else # TODO: raise exception logger.error "PDF Generation failed with exit status: #{status}" diff --git a/app/models/task.rb b/app/models/task.rb index 111c15d21..201113f5b 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1030,7 +1030,7 @@ def make_pdf tex_string = render_to_string(template: '/task/task_pdf', layout: true) # Create a new working directory to save input.tex into - workdir_name = "#{Process.pid}-#{Thread.current.hash}" + workdir_name = "task-#{Process.pid}-#{Thread.current.hash}-#{task.id}" workdir = Rails.root.join("tmp", "texlive-latex", workdir_name) FileUtils.mkdir_p(workdir); @@ -1060,7 +1060,7 @@ def make_pdf rescue logger.info "PDF Generation failed: #{success}" ensure - Process.exit!(0) if clean_exit + Process.exit!(0) if clean_exit end end ) @@ -1070,9 +1070,9 @@ def make_pdf if status == 0 && File.exist?(File.join(workdir, "input.pdf")) # Read the generated PDF file and return it as a string pdf_string = File.read(workdir.join("input.pdf")) - + # Delete temporary workdir containing input.tex/input.pdf and logs - FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call + # FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call else # TODO: raise exception logger.error "PDF Generation failed with exit status: #{status}" From 7f2e3e959eb174f96b09d1aef01b378223f75cf3 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 13 Aug 2024 00:08:00 +1000 Subject: [PATCH 06/30] chore: fix .ipynb latex math tests --- test/models/task_test.rb | 7 ++++++- test_files/submissions/vectorial_graph.ipynb | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/test/models/task_test.rb b/test/models/task_test.rb index d88a28ee6..840b3c0f5 100644 --- a/test/models/task_test.rb +++ b/test/models/task_test.rb @@ -360,7 +360,12 @@ def test_ipynb_to_pdf # Test if latex math was rendered properly reader = PDF::Reader.new(task.final_pdf_path) - assert reader.pages.last.text.include?("weight\n") + + # PDF-reader incorrectly parses "weight (kg) / height (m)^2" as "weight (2g) / height (m)", misplacing the ^2 + # Detecting "height" and "weight" confirms correct LaTeX rendering + assert reader.pages.last.text.include?("BMI: bmi =") + assert reader.pages.last.text.include?("weight") + assert reader.pages.last.text.include?("height (m)\n") # ensure the notice is not included when the notebook doesn't have long lines source code cells # and no errors diff --git a/test_files/submissions/vectorial_graph.ipynb b/test_files/submissions/vectorial_graph.ipynb index 610505cce..fcec0aa6d 100644 --- a/test_files/submissions/vectorial_graph.ipynb +++ b/test_files/submissions/vectorial_graph.ipynb @@ -101,7 +101,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -951,7 +951,7 @@ "source": [ "Formula for calculating\n", "\n", - "BMI: $\\text{bmi}=\\frac{\\text{weight}}{\\text{height}^2}$" + "BMI: $\\text{bmi}=\\frac{\\text{weig}\\text{ht (kg)}}{\\text{hei} \\text{ght (m)}^2}$" ] } ], From 9bb71a84c203daa9f978f921d33c06ec1d73ece5 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 13 Aug 2024 00:21:08 +1000 Subject: [PATCH 07/30] chore: simplify check --- test/models/task_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/task_test.rb b/test/models/task_test.rb index 840b3c0f5..b56644063 100644 --- a/test/models/task_test.rb +++ b/test/models/task_test.rb @@ -365,7 +365,7 @@ def test_ipynb_to_pdf # Detecting "height" and "weight" confirms correct LaTeX rendering assert reader.pages.last.text.include?("BMI: bmi =") assert reader.pages.last.text.include?("weight") - assert reader.pages.last.text.include?("height (m)\n") + assert reader.pages.last.text.include?("height (m)") # ensure the notice is not included when the notebook doesn't have long lines source code cells # and no errors From 6d388c1ce1a39657b9398cbdb26b7e2e2974cbbe Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 13 Aug 2024 01:51:50 +1000 Subject: [PATCH 08/30] refactor: move pdf generation into latex helper module --- app/helpers/latex_helper.rb | 57 ++++++++++++++++++ .../project_compile_portfolio_module.rb | 59 +------------------ app/models/task.rb | 59 +------------------ 3 files changed, 63 insertions(+), 112 deletions(-) create mode 100644 app/helpers/latex_helper.rb diff --git a/app/helpers/latex_helper.rb b/app/helpers/latex_helper.rb new file mode 100644 index 000000000..b920f7c6a --- /dev/null +++ b/app/helpers/latex_helper.rb @@ -0,0 +1,57 @@ +module LatexHelper + def generate_pdf(template:, unique_render_id:) + # TODO: clean up pathnames - environment vars? + container_name = "1-formatif-texlive-container" + latex_build_path = "/texlive/shell/latex-build.sh" # mounted path on the texlive container, as defined in .devcontainer/docker-compose.yml + + logger.debug "Running make_pdf: (#{template})" + + # Render the portfolio layout + tex_string = render_to_string(template: template, layout: true) + + # Create a new working directory to save input.tex into + workdir_name = "#{unique_render_id}-#{Process.pid}-#{Thread.current.hash}" + workdir = Rails.root.join("tmp", "texlive-latex", workdir_name) + FileUtils.mkdir_p(workdir) + + # Copy jupynotex.py over into the working directory + FileUtils.cp(Rails.root.join('app', 'views', 'layouts', 'jupynotex.py'), workdir) + + # Save tex_string as input.tex into the workdir + File.open(workdir.join("input.tex"), 'w') do |fout| + fout.puts tex_string + end + + # Docker command to execute the build script in texlive container + command = "sudo docker exec -it #{container_name} #{latex_build_path} #{workdir_name}" + + Process.waitpid( + fork do + logger.debug "Executing system command: #{command}" + + # Execute the Docker command + clean_exit = system(command) + Process.exit!(1) unless clean_exit + rescue StandardError + logger.info "PDF Generation failed: #{clean_exit}" + ensure + Process.exit!(0) if clean_exit + end + ) + + status = $?.exitstatus + + if status == 0 && File.exist?(File.join(workdir, "input.pdf")) + # Read the generated PDF file and return it as a string + pdf_string = File.read(workdir.join("input.pdf")) + + # Delete temporary workdir containing input.tex/input.pdf and logs + # FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call + else + # TODO: raise exception + logger.error "PDF Generation failed with exit status: #{status}" + end + + pdf_string + end +end diff --git a/app/models/pdf_generation/project_compile_portfolio_module.rb b/app/models/pdf_generation/project_compile_portfolio_module.rb index 26620f4aa..3c6cedba0 100644 --- a/app/models/pdf_generation/project_compile_portfolio_module.rb +++ b/app/models/pdf_generation/project_compile_portfolio_module.rb @@ -35,6 +35,8 @@ def compress_portfolio # This class scaffolds the creation of the portfolio - mapping the required data into the erb template class ProjectAppController < ApplicationController + include LatexHelper + attr_accessor :student, :project, :base_path, @@ -67,62 +69,7 @@ def init(project, is_retry) def make_pdf logger.debug "Running make_pdf: (portfolio)" - - # TODO: move pdf layout -> tex -> pdf generation into shared module/class (duplicated in models/task.rb) - - # Render the portfolio layout - tex_string = render_to_string(template: '/portfolio/portfolio_pdf', layout: true) - - # Create a new working directory to save input.tex into - workdir_name = "portfolio-#{Process.pid}-#{Thread.current.hash}-#{project.id}" - workdir = Rails.root.join("tmp", "texlive-latex", workdir_name) - FileUtils.mkdir_p(workdir); - - # Copy jupynotex.py over into the working directory - FileUtils.cp(Rails.root.join('app', 'views', 'layouts', 'jupynotex.py'), workdir) - - # Save tex_string as input.tex into the workdir - File.open(workdir.join("input.tex"), 'w') do |fout| - fout.puts tex_string - end - - # TODO: clean up pathnames - container_name = "1-formatif-texlive-container" - latex_build_path = "/texlive/shell/latex-build.sh" # mounted path on the texlive container, as defined in .devcontainer/docker-compose.yml - - # Docker command to execute the build script in texlive container - command = "sudo docker exec -it #{container_name} #{latex_build_path} #{workdir_name}" - - Process.waitpid( - fork do - begin - logger.debug "Executing system command: #{command}" - - # Execute the Docker command - clean_exit = system(command) - Process.exit!(1) unless clean_exit - rescue - logger.info "PDF Generation failed: #{success}" - ensure - Process.exit!(0) if clean_exit - end - end - ) - - status = $?.exitstatus - - if status == 0 && File.exist?(File.join(workdir, "input.pdf")) - # Read the generated PDF file and return it as a string - pdf_string = File.read(workdir.join("input.pdf")) - - # Delete temporary workdir containing input.tex/input.pdf and logs - # FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call - else - # TODO: raise exception - logger.error "PDF Generation failed with exit status: #{status}" - end - - pdf_string + generate_pdf(template: "/portfolio/portfolio_pdf", unique_render_id: "portfolio-#{project.id}") end end diff --git a/app/models/task.rb b/app/models/task.rb index 201113f5b..d67ad83f3 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -998,6 +998,8 @@ def in_process_files_for_task(is_retry) end class TaskAppController < ApplicationController + include LatexHelper + attr_accessor :task attr_accessor :files attr_accessor :base_path @@ -1023,62 +1025,7 @@ def make_pdf end end logger.debug "Preprocessing complete, rendering file." - - # TODO: move pdf layout -> tex -> pdf generation into shared module/class (duplicated in models/pdf_generation/project_compile_portfolio_module.rb) - - # Render the task layout - tex_string = render_to_string(template: '/task/task_pdf', layout: true) - - # Create a new working directory to save input.tex into - workdir_name = "task-#{Process.pid}-#{Thread.current.hash}-#{task.id}" - workdir = Rails.root.join("tmp", "texlive-latex", workdir_name) - FileUtils.mkdir_p(workdir); - - # Copy jupynotex.py over into the working directory - FileUtils.cp(Rails.root.join('app', 'views', 'layouts', 'jupynotex.py'), workdir) - - # Save tex_string as input.tex into the workdir - File.open(workdir.join("input.tex"), 'w') do |fout| - fout.puts tex_string - end - - # TODO: clean up pathnames - container_name = "1-formatif-texlive-container" - latex_build_path = "/texlive/shell/latex-build.sh" # mounted path on the texlive container, as defined in .devcontainer/docker-compose.yml - - # Docker command to execute the build script in texlive container - command = "sudo docker exec -it #{container_name} #{latex_build_path} #{workdir_name}" - - Process.waitpid( - fork do - begin - logger.debug "Executing system command: #{command}" - - # Execute the Docker command - clean_exit = system(command) - Process.exit!(1) unless clean_exit - rescue - logger.info "PDF Generation failed: #{success}" - ensure - Process.exit!(0) if clean_exit - end - end - ) - - status = $?.exitstatus - - if status == 0 && File.exist?(File.join(workdir, "input.pdf")) - # Read the generated PDF file and return it as a string - pdf_string = File.read(workdir.join("input.pdf")) - - # Delete temporary workdir containing input.tex/input.pdf and logs - # FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call - else - # TODO: raise exception - logger.error "PDF Generation failed with exit status: #{status}" - end - - pdf_string + generate_pdf(template: "/task/task_pdf", unique_render_id: "task-#{task.id}") end end From 4227d9eadb0137c9f0d7f28b901fce5cd2c9d915 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 17 Aug 2024 00:42:49 +1000 Subject: [PATCH 09/30] refactor: create additional work subfolder * solves current permission issues that prevented the working folder from being rm -rf'd from the api * this ensures that input.pdf and input.log still exist when the script successfully completes --- lib/shell/texlive/latex-build.sh | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/shell/texlive/latex-build.sh b/lib/shell/texlive/latex-build.sh index 3dbc4cc43..d85bb8a94 100644 --- a/lib/shell/texlive/latex-build.sh +++ b/lib/shell/texlive/latex-build.sh @@ -1,11 +1,29 @@ #!/bin/sh # Name of the working directory -WORK_DIR=$1 +WORK_DIR=$1 -cd /workdir/texlive-latex/${WORK_DIR} +mkdir -p /workdir/texlive-latex/${WORK_DIR}/work -# TODO: debug test file submissions: '002-code.cs', 'java_with_invalid_unicode.java', 'long.ipynb' ... (are they supposed to fail lualatex compile?) +# Copy input.tex and jupynotex.py into the /work folder +cp -r /workdir/texlive-latex/${WORK_DIR}/*.tex /workdir/texlive-latex/${WORK_DIR}/work/ +cp -r /workdir/texlive-latex/${WORK_DIR}/*.py /workdir/texlive-latex/${WORK_DIR}/work/ + +cd /workdir/texlive-latex/${WORK_DIR}/work + +# Compile PDFs /bin/bash -c "lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex" echo "Running lualatex a second time to remove temporary last page..." -/bin/bash -c "lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex" \ No newline at end of file +/bin/bash -c "lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex" + +# Copy input.pdf and input.log into #{WORK_DIR} +if [ -f "input.pdf" ]; then + cp input.pdf ../ +fi +if [ -f "input.log" ]; then + cp input.log ../ +fi + +# Remove /work directory - leaving input.pdf, input.log, and +cd .. +rm -rf work From 01acc4394766d97b6c358485c43c88da9fd9d9c6 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 17 Aug 2024 01:29:41 +1000 Subject: [PATCH 10/30] chore: remove work directory on completion --- app/helpers/latex_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/latex_helper.rb b/app/helpers/latex_helper.rb index b920f7c6a..d53fd351d 100644 --- a/app/helpers/latex_helper.rb +++ b/app/helpers/latex_helper.rb @@ -46,7 +46,7 @@ def generate_pdf(template:, unique_render_id:) pdf_string = File.read(workdir.join("input.pdf")) # Delete temporary workdir containing input.tex/input.pdf and logs - # FileUtils.rm_rf(workdir) # TODO: .pygtex files are still in use and aren't always removed in this call + FileUtils.rm_rf(workdir) else # TODO: raise exception logger.error "PDF Generation failed with exit status: #{status}" From 01803849be4af44d297b0e885686ce41f0a4cca4 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 17 Aug 2024 01:40:57 +1000 Subject: [PATCH 11/30] refactor: raise error on failed pdf generation --- app/helpers/latex_helper.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/helpers/latex_helper.rb b/app/helpers/latex_helper.rb index d53fd351d..863c618e7 100644 --- a/app/helpers/latex_helper.rb +++ b/app/helpers/latex_helper.rb @@ -48,8 +48,7 @@ def generate_pdf(template:, unique_render_id:) # Delete temporary workdir containing input.tex/input.pdf and logs FileUtils.rm_rf(workdir) else - # TODO: raise exception - logger.error "PDF Generation failed with exit status: #{status}" + raise "PDF Generation failed. See tmp/texlive-latex/#{workdir_name}/input.log for details." end pdf_string From 38b109aaf32ee982a57badea8b4f4f489e6ddbcc Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 17 Aug 2024 01:49:30 +1000 Subject: [PATCH 12/30] chore: comment --- lib/shell/texlive/latex-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/shell/texlive/latex-build.sh b/lib/shell/texlive/latex-build.sh index d85bb8a94..903ec3cee 100644 --- a/lib/shell/texlive/latex-build.sh +++ b/lib/shell/texlive/latex-build.sh @@ -24,6 +24,6 @@ if [ -f "input.log" ]; then cp input.log ../ fi -# Remove /work directory - leaving input.pdf, input.log, and +# Remove /work directory, preserving input.pdf + input.log + original input files cd .. rm -rf work From b779475d28542b2d95261499fca58883426eca94 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 17 Aug 2024 04:10:08 +1000 Subject: [PATCH 13/30] chore: use latex env variables --- app/helpers/latex_helper.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/helpers/latex_helper.rb b/app/helpers/latex_helper.rb index 863c618e7..bcd00c71b 100644 --- a/app/helpers/latex_helper.rb +++ b/app/helpers/latex_helper.rb @@ -1,8 +1,7 @@ module LatexHelper def generate_pdf(template:, unique_render_id:) - # TODO: clean up pathnames - environment vars? - container_name = "1-formatif-texlive-container" - latex_build_path = "/texlive/shell/latex-build.sh" # mounted path on the texlive container, as defined in .devcontainer/docker-compose.yml + container_name = ENV.fetch('LATEX_CONTAINER_NAME', nil) + latex_build_path = ENV.fetch('LATEX_BUILD_PATH', nil) logger.debug "Running make_pdf: (#{template})" From 0cd611fc86cae745c4adbe038f2dc8b7bf27d66a Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 18 Aug 2024 04:03:55 +1000 Subject: [PATCH 14/30] refactor: reorganise latex script --- lib/shell/texlive/latex-build.sh | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/lib/shell/texlive/latex-build.sh b/lib/shell/texlive/latex-build.sh index 903ec3cee..727cfb358 100644 --- a/lib/shell/texlive/latex-build.sh +++ b/lib/shell/texlive/latex-build.sh @@ -1,29 +1,20 @@ #!/bin/sh -# Name of the working directory -WORK_DIR=$1 +OUTPUT_DIR=$1 -mkdir -p /workdir/texlive-latex/${WORK_DIR}/work +cd /workdir/texlive-latex/${OUTPUT_DIR} -# Copy input.tex and jupynotex.py into the /work folder -cp -r /workdir/texlive-latex/${WORK_DIR}/*.tex /workdir/texlive-latex/${WORK_DIR}/work/ -cp -r /workdir/texlive-latex/${WORK_DIR}/*.py /workdir/texlive-latex/${WORK_DIR}/work/ +# Initialise work subfolder +mkdir -p work +cp *.tex *.py work/ +cd work -cd /workdir/texlive-latex/${WORK_DIR}/work - -# Compile PDFs -/bin/bash -c "lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex" +# Compile PDF +lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex echo "Running lualatex a second time to remove temporary last page..." -/bin/bash -c "lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex" - -# Copy input.pdf and input.log into #{WORK_DIR} -if [ -f "input.pdf" ]; then - cp input.pdf ../ -fi -if [ -f "input.log" ]; then - cp input.log ../ -fi +lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex -# Remove /work directory, preserving input.pdf + input.log + original input files +# Copy PDF to parent directory and cleanup +cp *.pdf *.log ../ cd .. rm -rf work From dd6f0de3f24ad42d9c781751977d98428bd21c59 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 18 Aug 2024 04:38:08 +1000 Subject: [PATCH 15/30] chore: remove texlive shell folder --- lib/shell/{texlive => }/latex-build.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/shell/{texlive => }/latex-build.sh (100%) diff --git a/lib/shell/texlive/latex-build.sh b/lib/shell/latex-build.sh similarity index 100% rename from lib/shell/texlive/latex-build.sh rename to lib/shell/latex-build.sh From cba910d12c6b304f0d3c1df01c44d80e98a53753 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 18 Aug 2024 07:26:21 +1000 Subject: [PATCH 16/30] chore: rename latex build script --- lib/shell/{latex-build.sh => latex_build.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/shell/{latex-build.sh => latex_build.sh} (100%) diff --git a/lib/shell/latex-build.sh b/lib/shell/latex_build.sh similarity index 100% rename from lib/shell/latex-build.sh rename to lib/shell/latex_build.sh From a8dead91f7866f090d3fd314f01ca6e1c58cf728 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:53:03 +1000 Subject: [PATCH 17/30] chore: use english library to replace global vars --- app/helpers/latex_helper.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/helpers/latex_helper.rb b/app/helpers/latex_helper.rb index bcd00c71b..1d95e1f3b 100644 --- a/app/helpers/latex_helper.rb +++ b/app/helpers/latex_helper.rb @@ -1,3 +1,4 @@ +require 'English' module LatexHelper def generate_pdf(template:, unique_render_id:) container_name = ENV.fetch('LATEX_CONTAINER_NAME', nil) @@ -38,9 +39,7 @@ def generate_pdf(template:, unique_render_id:) end ) - status = $?.exitstatus - - if status == 0 && File.exist?(File.join(workdir, "input.pdf")) + if $CHILD_STATUS.exitstatus == 0 && File.exist?(File.join(workdir, "input.pdf")) # Read the generated PDF file and return it as a string pdf_string = File.read(workdir.join("input.pdf")) From 1cacc20eb8c7f98c97156632d360b3547e31b9db Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 20 Aug 2024 19:02:38 +1000 Subject: [PATCH 18/30] ci: add texlive dockerfile --- Dockerfile | 2 -- deployAppSvr.Dockerfile | 7 ------- docker-compose.yml | 17 +++++++++++++++++ texlive.Dockerfile | 14 ++++++++++++++ 4 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 texlive.Dockerfile diff --git a/Dockerfile b/Dockerfile index f85630367..d22269779 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,8 +34,6 @@ RUN apt-get update \ WORKDIR /doubtfire COPY ./.ci-setup/ /doubtfire/.ci-setup/ -RUN ./.ci-setup/texlive-install.sh -ENV PATH /tmp/texlive/bin/x86_64-linux:/tmp/texlive/bin/aarch64-linux:$PATH RUN gem install bundler -v '2.4.5' diff --git a/deployAppSvr.Dockerfile b/deployAppSvr.Dockerfile index 424924957..748f56a1f 100644 --- a/deployAppSvr.Dockerfile +++ b/deployAppSvr.Dockerfile @@ -36,10 +36,6 @@ RUN apt-get update \ # Setup the folder where we will deploy the code WORKDIR /doubtfire -# Install LaTex -COPY ./.ci-setup /doubtfire/.ci-setup -RUN /doubtfire/.ci-setup/texlive-install.sh - # Install bundler RUN gem install bundler -v '2.4.5' RUN bundle config set --global without development test staging @@ -48,9 +44,6 @@ RUN bundle config set --global without development test staging COPY ./Gemfile ./Gemfile.lock /doubtfire/ RUN bundle install -# Setup path -ENV PATH /tmp/texlive/bin/x86_64-linux:/tmp/texlive/bin/aarch64-linux:$PATH - # Copy doubtfire-api source COPY . /doubtfire/ diff --git a/docker-compose.yml b/docker-compose.yml index 22520ccaa..ce807bf46 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,7 @@ services: - ./:/doubtfire - ../data/tmp:/doubtfire/tmp - ../data/student-work:/student-work + - /var/run/docker.sock:/var/run/docker.sock depends_on: - dev-db environment: @@ -61,6 +62,10 @@ services: # RABBITMQ_USERNAME: secure_credentials # RABBITMQ_PASSWORD: secure_credentials + # Latex details + LATEX_CONTAINER_NAME: "doubtfire-texlive" + LATEX_BUILD_PATH: "/texlive/shell/latex_build.sh" + dev-db: container_name: doubtfire-dev-db image: mariadb @@ -71,3 +76,15 @@ services: MYSQL_PASSWORD: pwd volumes: - ../data/database:/var/lib/mysql + + texlive: + container_name: doubtfire-texlive + build: texlive.Dockerfile + volumes: + - ../data/student-work:/student-work + - ./public/assets/images:/doubtfire/public/assets/images + - ./test_files:/doubtfire/test_files + - ./tmp/texlive-latex:/workdir/texlive-latex + depends_on: + - df-api + command: /bin/sh -c "while sleep 5000; do :; done" diff --git a/texlive.Dockerfile b/texlive.Dockerfile new file mode 100644 index 000000000..293ee8bff --- /dev/null +++ b/texlive.Dockerfile @@ -0,0 +1,14 @@ +FROM texlive/texlive:latest + +RUN apt-get update \ + && apt-get install -y \ + imagemagick \ + inkscape \ + librsvg2-bin \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +COPY ./lib/shell/latex_build.sh /texlive/shell/latex_build.sh +RUN chmod +x /texlive/shell/latex_build.sh + +CMD ["sh", "-c", "while sleep 5000; do :; done"] From ce988b26de5b18a919ff980f33cf08aff584bbeb Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:57:56 +1000 Subject: [PATCH 19/30] refactor: implement texlive docker workflow back into rails-latex --- app/helpers/latex_helper.rb | 55 ++----------------- .../project_compile_portfolio_module.rb | 2 +- app/models/task.rb | 2 +- ...ication.pdf.erb => application.pdf.erbtex} | 14 +++++ docker-compose.yml | 6 +- lib/shell/latex_build.sh | 2 + lib/shell/latex_run.sh | 5 ++ 7 files changed, 30 insertions(+), 56 deletions(-) rename app/views/layouts/{application.pdf.erb => application.pdf.erbtex} (88%) create mode 100755 lib/shell/latex_run.sh diff --git a/app/helpers/latex_helper.rb b/app/helpers/latex_helper.rb index 1d95e1f3b..37a9d90e4 100644 --- a/app/helpers/latex_helper.rb +++ b/app/helpers/latex_helper.rb @@ -1,54 +1,7 @@ -require 'English' module LatexHelper - def generate_pdf(template:, unique_render_id:) - container_name = ENV.fetch('LATEX_CONTAINER_NAME', nil) - latex_build_path = ENV.fetch('LATEX_BUILD_PATH', nil) - - logger.debug "Running make_pdf: (#{template})" - - # Render the portfolio layout - tex_string = render_to_string(template: template, layout: true) - - # Create a new working directory to save input.tex into - workdir_name = "#{unique_render_id}-#{Process.pid}-#{Thread.current.hash}" - workdir = Rails.root.join("tmp", "texlive-latex", workdir_name) - FileUtils.mkdir_p(workdir) - - # Copy jupynotex.py over into the working directory - FileUtils.cp(Rails.root.join('app', 'views', 'layouts', 'jupynotex.py'), workdir) - - # Save tex_string as input.tex into the workdir - File.open(workdir.join("input.tex"), 'w') do |fout| - fout.puts tex_string - end - - # Docker command to execute the build script in texlive container - command = "sudo docker exec -it #{container_name} #{latex_build_path} #{workdir_name}" - - Process.waitpid( - fork do - logger.debug "Executing system command: #{command}" - - # Execute the Docker command - clean_exit = system(command) - Process.exit!(1) unless clean_exit - rescue StandardError - logger.info "PDF Generation failed: #{clean_exit}" - ensure - Process.exit!(0) if clean_exit - end - ) - - if $CHILD_STATUS.exitstatus == 0 && File.exist?(File.join(workdir, "input.pdf")) - # Read the generated PDF file and return it as a string - pdf_string = File.read(workdir.join("input.pdf")) - - # Delete temporary workdir containing input.tex/input.pdf and logs - FileUtils.rm_rf(workdir) - else - raise "PDF Generation failed. See tmp/texlive-latex/#{workdir_name}/input.log for details." - end - - pdf_string + def generate_pdf(template:) + raise "LATEX_CONTAINER_NAME is not set" if ENV['LATEX_CONTAINER_NAME'].nil? + raise "LATEX_BUILD_PATH is not set" if ENV['LATEX_BUILD_PATH'].nil? + render_to_string(template: template, layout: true) end end diff --git a/app/models/pdf_generation/project_compile_portfolio_module.rb b/app/models/pdf_generation/project_compile_portfolio_module.rb index 3c6cedba0..a7a69af2b 100644 --- a/app/models/pdf_generation/project_compile_portfolio_module.rb +++ b/app/models/pdf_generation/project_compile_portfolio_module.rb @@ -69,7 +69,7 @@ def init(project, is_retry) def make_pdf logger.debug "Running make_pdf: (portfolio)" - generate_pdf(template: "/portfolio/portfolio_pdf", unique_render_id: "portfolio-#{project.id}") + generate_pdf(template: "/portfolio/portfolio_pdf") end end diff --git a/app/models/task.rb b/app/models/task.rb index d67ad83f3..2f8172967 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1025,7 +1025,7 @@ def make_pdf end end logger.debug "Preprocessing complete, rendering file." - generate_pdf(template: "/task/task_pdf", unique_render_id: "task-#{task.id}") + generate_pdf(template: "/task/task_pdf") end end diff --git a/app/views/layouts/application.pdf.erb b/app/views/layouts/application.pdf.erbtex similarity index 88% rename from app/views/layouts/application.pdf.erb rename to app/views/layouts/application.pdf.erbtex index b4b7cd823..e678411b8 100644 --- a/app/views/layouts/application.pdf.erb +++ b/app/views/layouts/application.pdf.erbtex @@ -1,3 +1,17 @@ +<% +@latex_config = { + :supporting => [ + Rails.root.join('app', 'views', 'layouts', 'jupynotex.py'), + Rails.root.join('lib', 'shell', 'latex_run.sh') + ], + :recipe => [ + { :command => "./latex_run.sh", :runs => 1 } + ], + :preservework => false, + :workdir => -> { "#{Process.pid}-#{Thread.current.object_id}-#{Time.now.to_i}" } +} +%> + \DocumentMetadata{uncompress} \documentclass[11pt,a4paper]{article} \usepackage[T1]{fontenc} diff --git a/docker-compose.yml b/docker-compose.yml index ce807bf46..4ac8ac0ac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,8 +63,8 @@ services: # RABBITMQ_PASSWORD: secure_credentials # Latex details - LATEX_CONTAINER_NAME: "doubtfire-texlive" - LATEX_BUILD_PATH: "/texlive/shell/latex_build.sh" + LATEX_CONTAINER_NAME: doubtfire-texlive + LATEX_BUILD_PATH: /texlive/shell/latex_build.sh dev-db: container_name: doubtfire-dev-db @@ -84,7 +84,7 @@ services: - ../data/student-work:/student-work - ./public/assets/images:/doubtfire/public/assets/images - ./test_files:/doubtfire/test_files - - ./tmp/texlive-latex:/workdir/texlive-latex + - ./tmp/rails-latex:/workdir/texlive-latex depends_on: - df-api command: /bin/sh -c "while sleep 5000; do :; done" diff --git a/lib/shell/latex_build.sh b/lib/shell/latex_build.sh index 727cfb358..b6952351d 100644 --- a/lib/shell/latex_build.sh +++ b/lib/shell/latex_build.sh @@ -1,5 +1,7 @@ #!/bin/sh +# This script is copied into the TeX Live container and remotely executed by run_latex.sh + OUTPUT_DIR=$1 cd /workdir/texlive-latex/${OUTPUT_DIR} diff --git a/lib/shell/latex_run.sh b/lib/shell/latex_run.sh new file mode 100755 index 000000000..6191e98df --- /dev/null +++ b/lib/shell/latex_run.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# This script is copied into tmp/rails-latex/$WORK_DIR/ and executed by rails-latex + +WORK_DIR=$(basename "$PWD") +sudo docker exec -it $LATEX_CONTAINER_NAME $LATEX_BUILD_PATH $WORK_DIR From 0f993a993dcb8636804fabcff23331d5a097b1ec Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:48:36 +1000 Subject: [PATCH 20/30] fix: set dockerfile context --- docker-compose.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4ac8ac0ac..b255f4de8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -79,7 +79,9 @@ services: texlive: container_name: doubtfire-texlive - build: texlive.Dockerfile + build: + context: . + dockerfile: texlive.Dockerfile volumes: - ../data/student-work:/student-work - ./public/assets/images:/doubtfire/public/assets/images From 807f567b636b2830458ed3368fef0861c27d956e Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 22 Sep 2024 00:57:23 +1000 Subject: [PATCH 21/30] fix: allow docker exec to work in gh actions --- lib/shell/latex_run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/shell/latex_run.sh b/lib/shell/latex_run.sh index 6191e98df..d9fbbac07 100755 --- a/lib/shell/latex_run.sh +++ b/lib/shell/latex_run.sh @@ -2,4 +2,4 @@ # This script is copied into tmp/rails-latex/$WORK_DIR/ and executed by rails-latex WORK_DIR=$(basename "$PWD") -sudo docker exec -it $LATEX_CONTAINER_NAME $LATEX_BUILD_PATH $WORK_DIR +docker exec -t $LATEX_CONTAINER_NAME $LATEX_BUILD_PATH $WORK_DIR From 9a76044bdad23589291ab952085ed035ac35a665 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 22 Sep 2024 02:34:46 +1000 Subject: [PATCH 22/30] ci: add new texlive container to gh actions --- .github/workflows/push.yml | 40 ++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 482af4d78..b8ce866b9 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -27,6 +27,8 @@ env: DF_ENCRYPTION_DETERMINISTIC_KEY: "anlmuJ6cB3bN3biXRbYvmPsC5ALPFqGG" DF_ENCRYPTION_KEY_DERIVATION_SALT: "hzPR8D4qpOnAg7VeAhkhWw6JmmzKJB10" DF_REDIS_SIDEKIQ_URL: "redis://redis:6379/0" + LATEX_CONTAINER_NAME: doubtfire-texlive + LATEX_BUILD_PATH: /texlive/shell/latex_build.sh jobs: unit-tests: @@ -49,6 +51,16 @@ jobs: uses: actions/checkout@v4 - name: Set up docker buildx uses: docker/setup-buildx-action@v3 + - name: Build TexLive image + uses: docker/build-push-action@v5 + with: + context: . + file: texlive.Dockerfile + push: false + load: true + tags: doubtfire-texlive-development:local + cache-from: type=gha + cache-to: type=gha,mode=max - name: Build base doubtfire-api development image uses: docker/build-push-action@v5 with: @@ -58,12 +70,34 @@ jobs: tags: doubtfire-api-development:local cache-from: type=gha cache-to: type=gha,mode=max + - name: Start TexLive service + uses: addnab/docker-run-action@v3 + with: + image: doubtfire-texlive-development:local + options: > + --name ${{ env.LATEX_CONTAINER_NAME }} + -v ${{ github.workspace }}/student-work:/student-work + -v ${{ github.workspace }}/public/assets/images:/doubtfire/public/assets/images + -v ${{ github.workspace }}/test_files:/doubtfire/test_files + -v ${{ github.workspace }}/tmp/rails-latex:/workdir/texlive-latex + --detach + run: /bin/sh -c "while sleep 5000; do :; done" + - name: Test TexLive container + uses: addnab/docker-run-action@v3 + with: + image: doubtfire-api-development:local + options: > + -v ${{ github.workspace }}:/doubtfire + -v /var/run/docker.sock:/var/run/docker.sock + run: docker exec -t ${{ env.LATEX_CONTAINER_NAME }} lualatex -v - name: Populate database uses: addnab/docker-run-action@v3 with: image: doubtfire-api-development:local options: > -v ${{ github.workspace }}:/doubtfire + -v ${{ github.workspace }}/student-work:/student-work + -v /var/run/docker.sock:/var/run/docker.sock -e RAILS_ENV -e DF_STUDENT_WORK_DIR -e DF_INSTITUTION_HOST @@ -81,6 +115,8 @@ jobs: -e DF_ENCRYPTION_DETERMINISTIC_KEY -e DF_ENCRYPTION_KEY_DERIVATION_SALT -e DF_REDIS_SIDEKIQ_URL + -e LATEX_CONTAINER_NAME + -e LATEX_BUILD_PATH run: bundle exec rake db:populate - name: Run unit tests uses: addnab/docker-run-action@v3 @@ -88,6 +124,8 @@ jobs: image: doubtfire-api-development:local options: > -v ${{ github.workspace }}:/doubtfire + -v ${{ github.workspace }}/student-work:/student-work + -v /var/run/docker.sock:/var/run/docker.sock -e RAILS_ENV -e DF_STUDENT_WORK_DIR -e DF_INSTITUTION_HOST @@ -105,4 +143,6 @@ jobs: -e DF_ENCRYPTION_DETERMINISTIC_KEY -e DF_ENCRYPTION_KEY_DERIVATION_SALT -e DF_REDIS_SIDEKIQ_URL + -e LATEX_CONTAINER_NAME + -e LATEX_BUILD_PATH run: TERM=xterm bundle exec rails test diff --git a/docker-compose.yml b/docker-compose.yml index b255f4de8..711d492ae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -79,7 +79,7 @@ services: texlive: container_name: doubtfire-texlive - build: + build: context: . dockerfile: texlive.Dockerfile volumes: From 0370df41ce119b8fba2a09ab108840f55b6007d6 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 22 Sep 2024 02:38:23 +1000 Subject: [PATCH 23/30] fix: ensure log is still copied if pdf gen fails --- lib/shell/latex_build.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/shell/latex_build.sh b/lib/shell/latex_build.sh index b6952351d..1ba8c8de3 100644 --- a/lib/shell/latex_build.sh +++ b/lib/shell/latex_build.sh @@ -1,6 +1,6 @@ #!/bin/sh -# This script is copied into the TeX Live container and remotely executed by run_latex.sh +# This script is copied into the TeX Live container and remotely executed by latex_run.sh OUTPUT_DIR=$1 @@ -17,6 +17,7 @@ echo "Running lualatex a second time to remove temporary last page..." lualatex -shell-escape -interaction=batchmode -halt-on-error input.tex # Copy PDF to parent directory and cleanup -cp *.pdf *.log ../ +cp *.log ../ +cp *.pdf ../ cd .. rm -rf work From 8f682e61fe3d02dffc81b34e23db5e4b711692a8 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 22 Sep 2024 02:50:30 +1000 Subject: [PATCH 24/30] chore: remove texlive install scripts --- .ci-setup/texlive-install.sh | 57 ------------------------------------ .ci-setup/texlive.profile | 11 ------- 2 files changed, 68 deletions(-) delete mode 100755 .ci-setup/texlive-install.sh delete mode 100644 .ci-setup/texlive.profile diff --git a/.ci-setup/texlive-install.sh b/.ci-setup/texlive-install.sh deleted file mode 100755 index 83b57f147..000000000 --- a/.ci-setup/texlive-install.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -set -e -APP_PATH="$(readlink -f "$(dirname "$0")")" -TEX_COMPILER=lualatex - -CTAN_REPO="https://mirror.aarnet.edu.au/pub/CTAN/systems/texlive/tlnet" - -# See if there is a cached version of TL available -# shellcheck disable=SC2155 -export PATH="/tmp/texlive/bin/$(uname -m)-linux:$PATH" -if ! command -v "$TEX_COMPILER" > /dev/null; then - echo "----------------------------------------" - echo "Downloading texlive installer archive from CTAN:" - wget "$CTAN_REPO/install-tl-unx.tar.gz" - tar -xzf install-tl-unx.tar.gz - cd install-tl-20* - - echo "----------------------------------------" - echo "Installing texlive using profile:" - cat "${APP_PATH}"/texlive.profile - echo - ./install-tl --profile="${APP_PATH}/texlive.profile" -repository "$CTAN_REPO" - - echo "----------------------------------------" - echo "Set tlmgr repository:" - tlmgr option repository "$CTAN_REPO" - - echo "----------------------------------------" - echo "Installing additional texlive packages:" - tlmgr install fontawesome luatextra luacode minted fvextra catchfile xstring framed lastpage pdfmanagement-testphase newpax tcolorbox environ pdfcol tikzfill markdown paralist csvsimple gobble upquote tagpdf - - echo "----------------------------------------" - echo "Ensuring the newpax package is sufficiently up to date:" - if NEWPAX_VERSION=$(tlmgr info --only-installed --data cat-version newpax) ; then - if [[ $(echo "$NEWPAX_VERSION < 0.53" | bc) == 1 ]]; then - echo >&2 "Package newpax version lower than 0.53 contain several bugs that are now fixed, giving up."; exit 1; - else - echo "Version $NEWPAX_VERSION found." - fi - else - echo >&2 "Package newpax not found!"; exit 1; - fi - - cd .. - - # Keep no backups (not required, simply makes cache bigger) - tlmgr option -- autobackup 0 -fi - -echo "----------------------------------------" -echo "Installation complete, verifying installation of $TEX_COMPILER." -command -v "$TEX_COMPILER" >/dev/null 2>&1 || { echo >&2 "$TEX_COMPILER is not found."; exit 1; } -# Do a test compile recommended by https://www.tug.org/texlive/quickinstall.html -"$TEX_COMPILER" small2e || { echo >&2 "Failed to process test file with $TEX_COMPILER."; exit 1; } -# remove test files -rm small2e.aux small2e.log small2e.pdf diff --git a/.ci-setup/texlive.profile b/.ci-setup/texlive.profile deleted file mode 100644 index ca5e417b6..000000000 --- a/.ci-setup/texlive.profile +++ /dev/null @@ -1,11 +0,0 @@ -selected_scheme scheme-medium -TEXDIR /tmp/texlive -TEXMFCONFIG ~/.texlive/texmf-config -TEXMFHOME ~/texmf -TEXMFLOCAL /tmp/texlive/texmf-local -TEXMFSYSCONFIG /tmp/texlive/texmf-config -TEXMFSYSVAR /tmp/texlive/texmf-var -TEXMFVAR ~/.texlive/texmf-var -option_doc 0 -option_src 0 -instopt_write18_restricted 1 From b1153dfff548a03ceec0f44b98b4ba848ada1b73 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 22 Sep 2024 13:19:05 +1000 Subject: [PATCH 25/30] ci: manually stop texlive service after unit tests complete --- .github/workflows/push.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index b8ce866b9..264367525 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -146,3 +146,5 @@ jobs: -e LATEX_CONTAINER_NAME -e LATEX_BUILD_PATH run: TERM=xterm bundle exec rails test + - name: Stop TexLive service + run: docker rm -f ${{ env.LATEX_CONTAINER_NAME }} From c104a30f262d4cfcc787f311101793a2851b4432 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 22 Sep 2024 19:25:41 +1000 Subject: [PATCH 26/30] ci: add unique image scopes to fix cache conflicts --- .github/workflows/push.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 264367525..a196b9ed4 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -59,8 +59,8 @@ jobs: push: false load: true tags: doubtfire-texlive-development:local - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=gha,scope=texlive + cache-to: type=gha,mode=max,scope=texlive - name: Build base doubtfire-api development image uses: docker/build-push-action@v5 with: @@ -68,8 +68,8 @@ jobs: push: false load: true tags: doubtfire-api-development:local - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=gha,scope=doubtfire-api + cache-to: type=gha,mode=max,scope=doubtfire-api - name: Start TexLive service uses: addnab/docker-run-action@v3 with: From 722dbebd6561f6bf8c73c910a423a3f5fbeda1d7 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:49:07 +1000 Subject: [PATCH 27/30] refactor: keep containers alive with sleep infinity --- .github/workflows/push.yml | 2 +- texlive.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index a196b9ed4..72b8eca1f 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -81,7 +81,7 @@ jobs: -v ${{ github.workspace }}/test_files:/doubtfire/test_files -v ${{ github.workspace }}/tmp/rails-latex:/workdir/texlive-latex --detach - run: /bin/sh -c "while sleep 5000; do :; done" + run: sleep infinity - name: Test TexLive container uses: addnab/docker-run-action@v3 with: diff --git a/texlive.Dockerfile b/texlive.Dockerfile index 293ee8bff..e7a7f0e3e 100644 --- a/texlive.Dockerfile +++ b/texlive.Dockerfile @@ -11,4 +11,4 @@ RUN apt-get update \ COPY ./lib/shell/latex_build.sh /texlive/shell/latex_build.sh RUN chmod +x /texlive/shell/latex_build.sh -CMD ["sh", "-c", "while sleep 5000; do :; done"] +CMD ["sh", "-c", "sleep infinity"] From 7bd16492948c581b8304247834a0c2abae6ac3de Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:12:10 +1000 Subject: [PATCH 28/30] chore: remove unused packages --- Dockerfile | 1 - deployAppSvr.Dockerfile | 2 -- 2 files changed, 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index d22269779..b01c43cba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,6 @@ RUN apt-get update \ wget \ redis \ libc6-dev \ - librsvg2-bin \ docker-ce \ docker-ce-cli \ containerd.io \ diff --git a/deployAppSvr.Dockerfile b/deployAppSvr.Dockerfile index 192118282..cee52099c 100644 --- a/deployAppSvr.Dockerfile +++ b/deployAppSvr.Dockerfile @@ -27,11 +27,9 @@ RUN apt-get update \ cron \ msmtp-mta bsd-mailx \ redis \ - librsvg2-bin \ docker-ce \ docker-ce-cli \ containerd.io \ - librsvg2-bin \ && apt-get clean # Setup the folder where we will deploy the code From cb75e65a3e5aec76dff331bc9332e65057dd9631 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:30:59 +1000 Subject: [PATCH 29/30] chore: replace double quotes with single quotes --- app/helpers/latex_helper.rb | 4 ++-- .../pdf_generation/project_compile_portfolio_module.rb | 5 ++--- app/models/task.rb | 4 ++-- app/views/layouts/application.pdf.erbtex | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/helpers/latex_helper.rb b/app/helpers/latex_helper.rb index 37a9d90e4..d4c6f0c12 100644 --- a/app/helpers/latex_helper.rb +++ b/app/helpers/latex_helper.rb @@ -1,7 +1,7 @@ module LatexHelper def generate_pdf(template:) - raise "LATEX_CONTAINER_NAME is not set" if ENV['LATEX_CONTAINER_NAME'].nil? - raise "LATEX_BUILD_PATH is not set" if ENV['LATEX_BUILD_PATH'].nil? + raise 'LATEX_CONTAINER_NAME is not set' if ENV['LATEX_CONTAINER_NAME'].nil? + raise 'LATEX_BUILD_PATH is not set' if ENV['LATEX_BUILD_PATH'].nil? render_to_string(template: template, layout: true) end end diff --git a/app/models/pdf_generation/project_compile_portfolio_module.rb b/app/models/pdf_generation/project_compile_portfolio_module.rb index a13aea350..8d44c93e0 100644 --- a/app/models/pdf_generation/project_compile_portfolio_module.rb +++ b/app/models/pdf_generation/project_compile_portfolio_module.rb @@ -68,10 +68,9 @@ def init(project, is_retry) end def make_pdf - logger.debug "Running make_pdf: (portfolio)" - generate_pdf(template: "/portfolio/portfolio_pdf") + logger.debug 'Running make_pdf: (portfolio)' + generate_pdf(template: '/portfolio/portfolio_pdf') end - end # Create the portfolio for this project diff --git a/app/models/task.rb b/app/models/task.rb index 1fe030ccb..3abf33fa4 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1088,8 +1088,8 @@ def make_pdf FileHelper.qpdf(f[:path]) end end - logger.debug "Preprocessing complete, rendering file." - generate_pdf(template: "/task/task_pdf") + logger.debug 'Preprocessing complete, rendering file.' + generate_pdf(template: '/task/task_pdf') end end diff --git a/app/views/layouts/application.pdf.erbtex b/app/views/layouts/application.pdf.erbtex index 0ddb2d3f5..fc8051528 100644 --- a/app/views/layouts/application.pdf.erbtex +++ b/app/views/layouts/application.pdf.erbtex @@ -5,7 +5,7 @@ Rails.root.join('lib', 'shell', 'latex_run.sh') ], :recipe => [ - { :command => "./latex_run.sh", :runs => 1 } + { :command => './latex_run.sh', :runs => 1 } ], :preservework => false, :workdir => -> { "#{Process.pid}-#{Thread.current.object_id}-#{Time.now.to_i}" } From 3400a5405af6315c1e4addc9002a6cf91f1934cb Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:51:00 +1000 Subject: [PATCH 30/30] refactor: keep containers alive with sleep infinity --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 711d492ae..3987c71a7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,4 +89,4 @@ services: - ./tmp/rails-latex:/workdir/texlive-latex depends_on: - df-api - command: /bin/sh -c "while sleep 5000; do :; done" + command: sleep infinity