diff --git a/bin/bamc b/bin/bamc index 4ff30d6..09abbdf 100755 --- a/bin/bamc +++ b/bin/bamc @@ -1,32 +1,35 @@ #!/bin/bash # Set SNAME, SDIR and SPATH if [ -h $0 ]; then SNAME=$(readlink $0); else SNAME=$0; fi SDIR=$(dirname $SNAME) if [[ "$SDIR" =~ ^/ ]]; then SPATH=$SDIR; else SPATH=$(realpath $(pwd)/$SDIR); fi # Set DIR_LIB DIR_LIB=$(realpath $SPATH/../lib/bash) # Source libs +source $DIR_LIB/tools.sh source $DIR_LIB/colors.sh source $DIR_LIB/io.sh source $DIR_LIB/debugging.sh source $DIR_LIB/cmdline_parser.sh source $DIR_LIB/bamc_configuration.sh +source $DIR_LIB/bamc_sanity.sh source $DIR_LIB/bamc_help.sh source $DIR_LIB/bamc_actions.sh source $DIR_LIB/bamc_workspace.sh source $DIR_LIB/bamc_exams.sh source $DIR_LIB/bamc_templates.sh source $DIR_LIB/bamc_projects.sh +source $DIR_LIB/bamc_amc-commands.sh DEFAULT_ITEMS=$(get_exam_list) DEFAULT_ACTIONS="help" CALLBACK_PREFIX="action_" run $@ RC=$? debug "Return code: $RC" exit $RC diff --git a/conf/bamc.conf b/conf/bamc.conf index 995c48d..50b271c 100644 --- a/conf/bamc.conf +++ b/conf/bamc.conf @@ -1,52 +1,54 @@ #!/bin/bash # Worspace DIR_QUESTIONS='questions' DIR_EXAMS='exams' DIR_PROJECTS='projects' FILE_WORKSPACE_ROOT=".workspace_root" # Configuration dirs DIR_DATA=$(realpath $SPATH/../data) DIR_WORKSPACE_TEMPLATE=$DIR_DATA/workspace DIR_EXAM_TEMPLATES=$DIR_DATA/templates # Template DEFAULT_EXAM_TEMPLATE="default" # Configuration files FILE_AMC_OPTIONS='options.xml' # Output dirs DIR_PROJECTS='projects' DIR_SAMPLES='pdf-samples' DIR_BLANKS='pdf-blanks' DIR_PDFS='pdf-exams' DIR_LISTS='pdf-lists' -# INTPUT FILES +# Intput files FILE_SECTIONS='sections.conf' FILE_EXAM='exam.conf' +FILE_STUDENTS='students.csv' + +# Variables +EXTRA_STUDENTS=9 +PDFLATEX_RUNS=1 return 0 -FILE_STUDENTS='students.csv' FILE_SAMPLE_CSV='sample.csv' FILE_EXTRA_CSV='extra.csv' FILE_BLANK_CSV='blank.csv' FILE_AMC_MAILING='mailing.xml' FILE_LIST_MAIN='list.tex' FILE_LIST_TSTART='start_tab.tex' FILE_LIST_TEND='end_tab.tex' # OUTPUT FILES FILE_RESULTS='raw' FILE_EMAILS_SCRIPT='send_emails.sh' FILE_LIST_ROWS='rows.tex' # VARIABLES -PDFLATEX_RUNS=1 -EXTRA_COPIES=9 DEFAULT_EMAIL='pierre-olivier.valles@epfl.ch' LIST_ROWS_PER_PAGE=50 LIST_MAX_CHAR=30 diff --git a/data/templates/maths/CSV/blank.csv b/data/templates/maths/csv/blank.csv similarity index 100% rename from data/templates/maths/CSV/blank.csv rename to data/templates/maths/csv/blank.csv diff --git a/data/templates/maths/CSV/extra.csv b/data/templates/maths/csv/extra.csv similarity index 100% rename from data/templates/maths/CSV/extra.csv rename to data/templates/maths/csv/extra.csv diff --git a/data/templates/maths/CSV/sample.csv b/data/templates/maths/csv/sample.csv similarity index 100% rename from data/templates/maths/CSV/sample.csv rename to data/templates/maths/csv/sample.csv diff --git a/data/templates/maths/de/first_page.tex b/data/templates/maths/de/first_page.tex index fc2aa56..8ffbe10 100644 --- a/data/templates/maths/de/first_page.tex +++ b/data/templates/maths/de/first_page.tex @@ -1,54 +1,54 @@ % First page - GERMAN \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~Dauer: \Time \end{minipage} \begin{minipage}[c]{100pt} \includegraphics[scale=0.24]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \hfill\fontsize{40}{48}{\selectfont{\NOM{}}}\hfill~ \end{minipage} \vfill \noindent \namefield{SCIPER: {\Large \bf \SCIPER{} }} \\ ~ \\ \noindent \textbf{Drehen Sie diese Seite nicht um, bevor Sie dazu aufgefordert werden.} \textbf{Jedes Blatt hat eine Vorder- und eine R\"uckseite. Es gibt \totalPages\ Seiten, die letzten sind m\"oglicherweise leer.} \textbf{L\"osen Sie nicht die Heftklammer.} \begin{itemize} \item[-] Legen Sie Ihren Studentenausweis auf den Tisch. \item[-] Es sind \textbf{keine} Unterlagen zugelassen. \item[-] Die Nutzung eines \textbf{Taschenrechners} oder jedes anderen elektronischen Hilfsmittels ist w\"ahrend der Pr\"ufung nicht gestattet. \item[-] F\"ur die \textbf{Multiple Choice} Fragen erh\"alt man: \begin{itemize} \item [$+3$] Punkte, wenn die Antwort korrekt ist, \item [0] Punkte, wenn die Frage nicht beantwortet ist oder mehrere M\"oglichkeiten angekreuzt sind, und \item [$-1$] Punkt, wenn die Antwort falsch ist. \end{itemize} \item [-] F\"ur die \textbf{Wahr/Falsch }Fragen erh\"alt man: \begin{itemize} \item [$+1$] Punkt, wenn die Antwort korrekt ist, \item [0] Punkte, wenn die Frage nicht beantwortet ist oder mehrere M\"oglichkeiten angekreuzt sind, und \item [$-1$] Punkt, wenn die Antwort falsch ist. \end{itemize} -\item[-] Benutzen Sie einen \textbf{Bleistift} und radieren Sie, falls n\"otig, sorgf\"altig aus. +\item[-] Benutzen Sie einen \textbf{Kugelschreiber} und falls n\"otig l\"oschen Sie mit Tipp-Ex sorgf\"altig aus. \item[-] Beachten Sie bitte diese Richtlinien bei der Markierung \textbf{der Antworten}: \end{itemize} \hfill \includegraphics[scale=0.2]{good_bad_square} \hfill % End of first page diff --git a/data/templates/maths/en/first_page.tex b/data/templates/maths/en/first_page.tex index 4779243..14aca90 100644 --- a/data/templates/maths/en/first_page.tex +++ b/data/templates/maths/en/first_page.tex @@ -1,55 +1,55 @@ % First page - ENGLISH \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~duration : \Time \end{minipage} \begin{minipage}[c]{100pt} \includegraphics[scale=0.24]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \hfill\fontsize{40}{48}{\selectfont{\NOM{}}}\hfill~ \end{minipage} \vfill \noindent \namefield{SCIPER: {\Large \bf \SCIPER{} }} \\ ~ \\ \noindent \textbf{Do not turn the page before the start of the exam.} \textbf{This document is double-sided, has \totalPages\ pages, the last ones possibly blank.} \textbf{Do not unstaple.} \medskip \begin{itemize} \item[-] Place your student card on your table. \item[-] \textbf{No other paper materials} are allowed to be used during the exam. \item[-] Using a \textbf{calculator} or any electronic device is not permitted during the exam. \item[-] For the \textbf{multiple choice} questions, we give \begin{itemize} \item [$+3$] points if your answer is correct, \item [$0$ ] points if you give no answer or more than one, \item [$-1$] points if your answer is incorrect. \end{itemize} \item[-] For the \textbf{true/false} questions, we give \begin{itemize} \item [$+1$] points if your answer is correct, \item [$0$ ] points if you give no answer or more than one, \item [$-1$] points if your answer is incorrect. \end{itemize} -\item[-] \textbf{Use a pencil} and clearly erase with an eraser if necessary. +\item[-] Use a \textbf{ballpen} and clearly erase with \textbf{correction fluid} if necessary. \item[-] Observe these guidelines when \textbf{recording your answers}: \end{itemize} \hfill \includegraphics[scale=0.2]{good_bad_square} \hfill % End of first page diff --git a/data/templates/maths/fr/first_page.tex b/data/templates/maths/fr/first_page.tex index d4880f8..d35123e 100644 --- a/data/templates/maths/fr/first_page.tex +++ b/data/templates/maths/fr/first_page.tex @@ -1,55 +1,55 @@ % First page - FRENCH \noindent \begin{minipage}[c]{350pt} \bf \prof~-~\ExamName~-~\SECTION \\ ~ \\ \bf \ExamDate~-~durée : \Time \end{minipage} \begin{minipage}[c]{100pt} \includegraphics[scale=0.24]{Logo_EPFL} \end{minipage} \vfill \begin{minipage}[c]{\textwidth} \noindent \hfill\fontsize{100}{120}{\selectfont{\ID{}}}\hfill \vspace{1cm} \par \noindent \hfill\fontsize{40}{48}{\selectfont{\NOM{}}}\hfill~ \end{minipage} \vfill \noindent \namefield{SCIPER: {\Large \bf \SCIPER{} }} \\ ~ \\ \noindent \textbf{Attendez le d\'ebut de l'\'epreuve avant de tourner la page.} \textbf{Ce document est imprim\'e recto-verso, il contient \totalPages\ pages, les derni\`eres pouvant \^etre vides.} \textbf{Ne pas d\'egrafer.} \medskip \begin{itemize} \item[-] Posez votre carte d'\'etudiant sur la table. \item[-] \textbf{Aucun} document n'est autoris\'{e}. \item[-] L'utilisation d'une \textbf{calculatrice} et de tout outil \'electronique est interdite pendant l'\'epreuve. \item[-] Pour les questions \`a \textbf{choix multiple}, on comptera: \begin{itemize} \item [$+3$] points si la r\'eponse est correcte, \item [0] point si la question n'est pas r\'epondue ou s'il y a plusieurs croix, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} \item [-]Pour les questions de type \textbf{vrai-faux}, on comptera: \begin{itemize} \item [$+1$] point si la r\'eponse est correcte, \item [0] point si la question n'est pas r\'epondue ou s'il y a plusieurs croix, \item [$-1$] point si la r\'eponse est incorrecte. \end{itemize} -\item[-] Utilisez un \textbf{crayon} et effacez proprement avec une \textbf{gomme} si n\'ecessaire. +\item[-] Utilisez un \textbf{stylo} et effacez proprement avec du \textbf{correcteur blanc} si n\'ecessaire. \item[-] Respectez les consignes suivantes pour \textbf{marquer vos réponses} : \end{itemize} \hfill \includegraphics[scale=0.2]{good_bad_square} \hfill %% End of first page diff --git a/data/templates/maths/media/good_bad_square.png b/data/templates/maths/media/good_bad_square.png index 6d272b2..60360db 100644 Binary files a/data/templates/maths/media/good_bad_square.png and b/data/templates/maths/media/good_bad_square.png differ diff --git a/data/templates/maths/media/good_bad_square.png b/data/templates/maths/media/good_bad_square_v1.png similarity index 100% copy from data/templates/maths/media/good_bad_square.png copy to data/templates/maths/media/good_bad_square_v1.png diff --git a/install/install_bins.sh b/install/install_bins.sh index 6fd2357..cde4406 100755 --- a/install/install_bins.sh +++ b/install/install_bins.sh @@ -1,67 +1,68 @@ #!/bin/bash # Set SNAME, SDIR and SPATH if [ -h $0 ]; then SNAME=$(readlink $0); else SNAME=$0; fi SDIR=$(dirname $SNAME) if [[ "$SDIR" =~ ^/ ]]; then SPATH=$SDIR; else SPATH=$(realpath $(pwd)/$SDIR); fi # Set DIR_LIB DIR_LIB=$(realpath $SPATH/../lib/bash) # Source libs source $DIR_LIB/colors.sh source $DIR_LIB/io.sh # Set DESTINATION if [ -n "$1" ]; then DESTINATION="$(realpath $1)" else DESTINATION=$(realpath ${HOME}/bin) fi if [ ! -d $DESTINATION/ ]; then error_echo "'$DESTINATION' is not a valid directory." exit 1 fi info_echo "Using '$DESTINATION' as binary directory." function link_to_binaries() { for bin in $(echo $BINS); do if [ -r $DESTINATION/$bin ]; then if [ -h $DESTINATION/$bin ]; then OLD=$(realpath $DESTINATION/$bin) if [ "$OLD" == "$DIR_BIN/$bin" ]; then color_echo_n "Command '$bin' already exists... " else color_echo_n "Moving command '$bin' from '$OLD' to '$DIR_BIN/$bin'... " rm $DESTINATION/$bin ln -s $DIR_BIN/$bin $DESTINATION/$bin fi else error_echo "A similar command already exists: '$OLD'" exit 2 fi else color_echo_n "Installing command '$bin' to '$DESTINATION/'... " ln -s $DIR_BIN/$bin $DESTINATION/$bin fi [ -h $DESTINATION/$bin ] check_rc_echo $? + if [ $(which $bin 2> /dev/null | wc -l) -eq 0 ]; then + warning_echo "Make sure '$DESTINATION' is in your \$PATH variable. (Looks like it is not the case.)"; + fi done + } DIR_BIN=$(realpath $SPATH/../bin) BINS='bamc' link_to_binaries DIR_BIN=$(realpath $SPATH/../local/epfl) BINS='search-epfl' link_to_binaries -# Done -warning_echo "Make sure '$DESTINATION' is in your \$PATH variable."; - # RIP exit 0 diff --git a/lib/bash/bamc_amc-commands.sh b/lib/bash/bamc_amc-commands.sh new file mode 100644 index 0000000..661de6b --- /dev/null +++ b/lib/bash/bamc_amc-commands.sh @@ -0,0 +1,128 @@ +#!/bin/bash + +function action_blank() { + local rc=0 + while [ $# -gt 0 ]; do + local item=$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$item + local lang=$(get_lang $item) + amc_prepare $item "blank" + if [ $? -eq 0 ]; then + mkdir -p $DIR_WORKSPACE/$DIR_BLANKS + mv $project/BLANK-exam.pdf $DIR_WORKSPACE/$DIR_BLANKS/BLANK-${lang}-${item}.pdf + amc_clean $item + else + ((rc++)) + fi + shift + done + return $rc; +} + +function action_sample() { + local rc=0 + while [ $# -gt 0 ]; do + local item=$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$item + local lang=$(get_lang $item) + amc_prepare $item "sample" + if [ $? -eq 0 ]; then + mkdir -p $DIR_WORKSPACE/$DIR_SAMPLES + mv $project/SAMPLE-exam.pdf $DIR_WORKSPACE/$DIR_SAMPLES/SAMPLE-${lang}-${item}.pdf + mv $project/SAMPLE-correction.pdf $DIR_WORKSPACE/$DIR_SAMPLES/SAMPLE-CORRECTION-${lang}-${item}.pdf + amc_clean $item + else + ((rc++)) + fi + shift + done + return $rc; +} + +function action_check() { + local rc=0 + while [ $# -gt 0 ]; do + local item=$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$item + local lang=$(get_lang $item) + amc_prepare $item "check" + if [ $? -ne 0 ]; then ((rc++)); else amc_clean $item; fi + shift + done + return $rc; +} + +function amc_clean() { + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 + rm -f $project/*-exam.pdf $project/*-correction.pdf $project/amc-compiled.* +} + +function amc_prepare() { + assert_exam $1; if [ $? -ne 0 ]; then return 1; fi + assert_template; if [ $? -ne 0 ]; then return 1; fi + + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 + local runs=$PDFLATEX_RUNS ok=0 + local mode=$2 prefix + + case $mode in + "blank"|"sample") + verbose "Building $mode exam '$1'" + if [ -r $project/INVALID ]; then + error "This AMC project is marked as invalid. Please correct project and run the 'check' action again." + return 1 + fi + prefix=$(echo $mode | tr '[a-z]' '[A-Z]');; + "check") + verbose "Checking exam '$1'" + prefix=BLANK;; + esac + + + # Save real students.csv file + case $mode in + "blank"|"check") + mv $project/$FILE_STUDENTS $project/${FILE_STUDENTS}.sav + cp $DIR_EXAM_TEMPLATE/csv/blank.csv $project/$FILE_STUDENTS + ;; + "sample") + mv $project/$FILE_STUDENTS $project/${FILE_STUDENTS}.sav + cp $DIR_EXAM_TEMPLATE/csv/sample.csv $project/$FILE_STUDENTS + ;; + esac + + # Clean before compiling project + amc_clean $1 + + while [ $runs -gt 0 ]; do + auto-multiple-choice prepare \ + --mode s \ + --with pdflatex \ + --filter latex \ + --prefix $project \ + --out-sujet ${prefix}-exam.pdf \ + --out-corrige ${prefix}-correction.pdf \ + $project/exam.tex > /dev/null 2>&1 + if [ ! -r $project/${prefix}-exam.pdf ]; then runs=0; else ok=1; fi; + if [ ! -r $project/${prefix}-correction.pdf ]; then runs=0; else ok=1; fi; + ((runs--)) + done + + # Restore students.csv + case $mode in + "blank"|"check"|"sample") + mv $project/${FILE_STUDENTS}.sav $project/$FILE_STUDENTS + ;; + esac + + if [ $ok -eq 0 ]; then + error "This AMC/LaTeX project does not compile with AMC." + touch $project/INVALID + return 1 + else + rm -f $project/INVALID + fi + return 0 +} + +# EOF diff --git a/lib/bash/bamc_configuration.sh b/lib/bash/bamc_configuration.sh index 482e9e0..7eb83b1 100644 --- a/lib/bash/bamc_configuration.sh +++ b/lib/bash/bamc_configuration.sh @@ -1,22 +1,24 @@ #!/bin/bash +# Read global configuration DIR_CONF=$SPATH/../conf/ FILE_CONF=$DIR_CONF/$(basename $0).conf if [ ! -r $FILE_CONF ]; then echo "Could not read configuration file ($FILE_CONF)" exit 1; fi source $FILE_CONF +# Source local configuration (on request) function source_workspace_configuration() { # Check workspace assert_workspace "quiet"; if [ $? -eq 1 ]; then return 1; fi local FILE_LOCAL_CONF=$DIR_WORKSPACE/$(basename $FILE_CONF) if [ -r $FILE_LOCAL_CONF ]; then source $FILE_LOCAL_CONF fi } # EOF diff --git a/lib/bash/bamc_exams.sh b/lib/bash/bamc_exams.sh index 0f1e159..dc77a34 100644 --- a/lib/bash/bamc_exams.sh +++ b/lib/bash/bamc_exams.sh @@ -1,70 +1,70 @@ #/bin/bash function action_list() { # Check workspace assert_workspace; if [ $? -eq 1 ]; then return 1; fi # List exams verbose "List of exams in current workspace:" for exam in $(find $DIR_WORKSPACE/$DIR_EXAMS -mindepth 1 -maxdepth 1 -type d -exec basename {} \;); do color_echo "- \"$exam\"" done # Done return 0 } function get_exam_list() { assert_workspace "quiet"; if [ $? -eq 1 ]; then return 1; fi find $DIR_WORKSPACE/$DIR_EXAMS -mindepth 1 -maxdepth 1 -type d -exec basename {} \; } function action_add-exam() { # Check workspace assert_workspace; if [ $? -eq 1 ]; then return 1; fi # Set source DIR_EXAM=$DIR_WORKSPACE_TEMPLATE/$DIR_EXAMS/skel if [ ! -d $DIR_EXAM ]; then error_echo "Directory '$DIR_EXAM' not found." return 1 fi is_set 'exam' if [ $? -eq 1 ]; then DESTINATION=$(get_parameter 'exam'); fi is_set 'e' if [ $? -eq 1 ]; then DESTINATION=$(get_parameter 'e'); fi - if [ -z "$DESTINATION" ]; then error_echo "No exam name provided. Add parameter 'exam=exam-name' to your command line"; fi + if [ -z "$DESTINATION" ]; then error_echo "No exam name provided. Add parameter 'exam=exam-name' to your command line"; return 1; fi # Set destination DESTINATION=$DIR_WORKSPACE/$DIR_EXAMS/$DESTINATION if [ -d $DESTINATION ]; then warn "This exam already exists!" confirm "Do you want to write in existing exam '$(basename $DESTINATION)' ?" if [ $? -eq 0 ]; then return 1; fi fi # Copy color_echo_n "Creating new exam '$(basename $DESTINATION)' from '$DIR_EXAM'... " cp -rp $DIR_EXAM $DESTINATION check_rc_echo $? return $? } function assert_exam() { # Check workspace assert_workspace; if [ $? -eq 1 ]; then return 1; fi local exam=$1 local mode=$2 if [ ! -d $DIR_WORKSPACE/$DIR_EXAMS/$exam ]; then if [ "$mode" != "quiet" ]; then error_echo "This exam does not exists: '$exam'. Please check the list of exams in this workspace using the 'list' action."; fi return 1 fi return 0 } # EOF diff --git a/lib/bash/bamc_help.sh b/lib/bash/bamc_help.sh index 766c659..3ff4b20 100644 --- a/lib/bash/bamc_help.sh +++ b/lib/bash/bamc_help.sh @@ -1,42 +1,44 @@ #!/bin/bash function action_help() { local item=$1 # Useless... echo -e "${DarkGreen}USAGE:${NoColor} "$(basename $0)" [-p|--params p1=v1,p2-v2,...] [-o|--only item1,item2,...] action1 [action2 ...] e.g.: $(basename $0) --params workspace=~/AMC_Workspace init e.g.: $(basename $0) show Parameters: ----------- ${DarkGreen}debug${NoColor} (GENERAL) print debugging messages ${DarkGreen}force${NoColor} (GENERAL) do not ask for user confirmation ${DarkGreen}workspace|w${NoColor} (GENERAL) name a specific workspace ${DarkGreen}exam|e${NoColor} (GENERAL) name a specific exam within the workspace Items: ----------- ${DarkGreen}item1${NoColor} (GENERAL) items are the existing exams (as printed by the 'list' action) Actions: -------- +${DarkGreen}sanity-checks${NoColor} (GENERAL) check system + ${DarkGreen}init${NoColor} (WORKSPACE) create a new workspace in the current directory ${DarkGreen}add-exam${NoColor} (EXAMS) add a new exam in the current workspace ${DarkGreen}list${NoColor} (EXAMS) print list of exams in the current workspace ${DarkGreen}clean${NoColor} (PROJECTS) remove project and output directories ${DarkGreen}project${NoColor} (PROJECTS) (re)build the AMC project(s) ${DarkGreen}check-latex${NoColor} (PROJECTS) check LaTeX syntax ${DarkGreen}check-cvs${NoColor} (PROJECTS) check CSV files syntax ${DarkGreen}check-amc${NoColor} (PROJECTS) check AMC specific syntax ${DarkGreen}check${NoColor} (PROJECTS) do all checks ${DarkGreen}blank${NoColor} (PDF) build a blank (anonymous) exam ${DarkGreen}catalog${NoColor} (PDF) build a catalog of questions ${DarkGreen}sample${NoColor} (PDF) build a sample (4 exams) exam ${DarkGreen}exam${NoColor} (PDF) build PDF exam" return 0 } diff --git a/lib/bash/bamc_projects.sh b/lib/bash/bamc_projects.sh index 2c1c2fd..5848d2f 100644 --- a/lib/bash/bamc_projects.sh +++ b/lib/bash/bamc_projects.sh @@ -1,202 +1,234 @@ #!/bin/bash function action_clean() { local exams=$@ local exam for exam in $(echo $exams); do assert_exam $exam if [ $? -eq 1 ]; then return 1; fi verbose "Cleaning '$exam' in workspace '$DIR_WORKSPACE'..." confirm "Clean project and outputs for exam '$exam' ?" if [ $? -eq 0 ]; then return 0; fi - for dir in $(echo $DIR_PROJECTS $DIR_SAMPLES $DIR_BLANKS $DIR_PDFS $DIR_LISTS); do - if [ -d "$DIR_WORKSPACE/$dir/$exam" ]; then + for dir in $(echo $DIR_WORKSPACE/$DIR_PROJECTS $DIR_WORKSPACE/$DIR_SAMPLES $DIR_WORKSPACE/$DIR_BLANKS $DIR_WORKSPACE/$DIR_PDFS $DIR_WORKSPACE/$DIR_LISTS); do + if [ -d "$dir/$exam" ]; then verbose "Removing directory: '$dir/$exam'" - rm -rf "$DIR_WORKSPACE/$dir/$exam/" + rm -rf "$dir/$exam/" else verbose "Removing files: '$dir/$exam*'" - rm -rf $DIR_WORKSPACE/$dir/$exam* + rm -rf $dir/$exam-* + rm -rf $dir/*-$exam* fi - if [ -d "$DIR_WORKSPACE/$dir" ]; then - if [ $(ls -1A $DIR_WORKSPACE/$dir/ | wc -l) -eq 0 ]; then + if [ -d "$dir" ]; then + if [ $(ls -1A $dir/ | wc -l) -eq 0 ]; then verbose "Removing now empty directory: '$dir'" - rmdir $DIR_WORKSPACE/$dir/ + rmdir $dir/ fi fi done done return 0 } function action_project() { # Get exam template to use assert_template if [ $? -ne 0 ]; then return 1; fi local exams=$@ local exam lang for exam in $(echo $exams); do assert_exam $exam lang=$(get_lang $exam) verbose "Project '$exam' uses '$lang' language" if [ $? -eq 1 ]; then return 1; fi verbose "Building AMC project for '$exam' in workspace '$DIR_WORKSPACE'..." # Project structure build_amc_project $exam if [ $? -ne 0 ]; then error "Could not build AMC project :("; return 1; fi # Build LaTeX sections build_sections $exam $lang if [ $? -ne 0 ]; then error "Could not build project sections :("; return 1; fi import_tex_files $exam $lang if [ $? -ne 0 ]; then error "Could not import LaTeX files :("; return 1; fi override_tex_files $exam if [ $? -ne 0 ]; then error "Could not override LaTeX files :("; return 1; fi customize_tex_files $exam $lang if [ $? -ne 0 ]; then error "Could not customize LaTeX files :("; return 1; fi add_media_files $exam if [ $? -ne 0 ]; then error "Could import media files :("; return 1; fi - #import_student_file $exam + import_student_file $exam done return 0 } +function import_student_file() { + verbose "Customizing LaTeX files" + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 + local exam=$DIR_WORKSPACE/$DIR_EXAMS/$1 + local lang=$2 + + local FILE=$exam/$FILE_STUDENTS + check_file_exists $FILE + if [ $? -ne 0 ]; then return 1; fi + + cp $FILE $project/$FILE_STUDENTS + + # Add extra students + local nb IFS=$'\n' + local id=$(tail -n 1 $project/$FILE_STUDENTS | cut -d ',' -f 1) + local sample=$(head -n 1 $DIR_EXAM_TEMPLATE/csv/extra.csv) + nb=0 + while [ $nb -lt $EXTRA_STUDENTS ]; do + ((nb++)) + ((id++)) + echo $sample |\ + sed "s/#NB#/$nb/g" |\ + sed "s/#ID#/$id/g" |\ + sed "s/#SCIPER#/FAKE-$nb/g" |\ + sed "s/#EMAIL#/$DEFAULT_EMAIL/g" |\ + sed "s/#SEMESTER#/$SEMESTER/g" >> $project/$FILE_STUDENTS + done + return 0 +} + + function add_media_files() { verbose "Importing media files" - local project=$DIR_PROJECTS/$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 cp $DIR_EXAM_TEMPLATE/media/* $project/media/ } function replace_in_file() { local pattern=$1 string=$2 filename=$3 sed "s/$pattern/$string/g" $filename > /tmp/sed.tmp.$$ mv /tmp/sed.tmp.$$ $filename return 0 } function customize_tex_files() { verbose "Customizing LaTeX files" - local project=$DIR_PROJECTS/$1 - local exam=$DIR_EXAMS/$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 + local exam=$DIR_WORKSPACE/$DIR_EXAMS/$1 local lang=$2 local replace IFS=$'\n' local FILE=$exam/$FILE_EXAM check_file_exists $FILE if [ $? -ne 0 ]; then return 1; fi # professor.tex local prof_file=$project/professor.tex check_file_exists $prof_file if [ $? -ne 0 ]; then return 1; fi for replace in $(cat $FILE); do replace_in_file "#$(echo $replace | cut -d ':' -f 1)#" "$(echo $replace | cut -d ':' -f 2-)" $prof_file done # exam.tex replace_in_file "#LANG#" $(echo $lang | tr '[a-z]' '[A-Z]') $project/exam.tex # Add extra_section.tex file if [ -r $exam/extra_section.tex ]; then sed -i 's?% #EXTRA_SECTION#?\\input{./extra_section.tex}?g' $project/exam.tex fi # Add extra_packages.tex file if [ -r $exam/extra_packages.tex ]; then sed -i 's?% #EXTRA_PACKAGES#?\\input{./extra_packages.tex}?g' $project/exam.tex fi return 0 } function override_tex_files() { verbose "Overriding LaTeX files (if needed)" - local exam=$DIR_EXAMS/$1 - local project=$DIR_PROJECTS/$1 + local exam=$DIR_WORKSPACE/$DIR_EXAMS/$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 local f for f in $(find $exam/ -type f -name '*.tex'); do verbose "- LaTeX override file found: $f" done find $exam/ -type f -name '*.tex' -exec cp {} $project/ \; } function import_tex_files() { verbose "Importing LaTeX files" - local project=$DIR_PROJECTS/$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 local lang=$2 cp $DIR_EXAM_TEMPLATE/base/* $project/ cp $DIR_EXAM_TEMPLATE/$lang/* $project/ return 0 } function build_amc_project() { - local project=$DIR_PROJECTS/$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 verbose "Creating AMC project structure" mkdir -p $project/cr/corrections/jpg mkdir -p $project/cr/corrections/pdf mkdir -p $project/cr/diagnostic mkdir -p $project/cr/zooms mkdir -p $project/data mkdir -p $project/exports mkdir -p $project/scans mkdir -p $project/copies mkdir -p $project/media cp $DIR_EXAM_TEMPLATE/config/$FILE_AMC_OPTIONS $project/$FILE_AMC_OPTIONS return $? } function get_exam_parameter() { - cat $DIR_EXAMS/$1/$FILE_EXAM | grep "^$2:" | cut -d ':' -f 2- + cat $DIR_WORKSPACE/$DIR_EXAMS/$1/$FILE_EXAM | grep "^$2:" | cut -d ':' -f 2- } function get_lang() { get_exam_parameter $1 'LANG' } function build_sections() { - local project=$DIR_PROJECTS/$1 - local exam=$DIR_EXAMS/$1 + local project=$DIR_WORKSPACE/$DIR_PROJECTS/$1 + local exam=$DIR_WORKSPACE/$DIR_EXAMS/$1 local lang=$2 local question_file question section_file section local IFS=$'\n' FILE=$exam/$FILE_SECTIONS verbose "Importing questions" check_file_exists $FILE if [ $? -ne 0 ]; then return 1; fi local section_num=0 rm -f $project/sections.tex $project/random-sections.tex for section in $(cat $FILE); do ((section_num++)) section_file=$project/section_${section_num}.tex rm -f $section_file for question in $(echo $section | tr ',' '\n'); do verbose "Adding $question to section $section_file..."; - question_file=$DIR_QUESTIONS/$lang/$question + question_file=$DIR_WORKSPACE/$DIR_QUESTIONS/$lang/$question check_file_exists $question_file if [ $? -ne 0 ]; then return 1; fi echo "%% From $lang/$question =======================================" >> $section_file echo '\element{section'$section_num'}{' >> $section_file cat $question_file >> $section_file echo '}' >> $section_file done echo "\input{./section_${section_num}.tex}" >> $project/sections.tex echo "\input{./header_${section_num}.tex} \melangegroupe{section${section_num}} \restituegroupe{section${section_num}} " >> $project/random-sections.tex done return 0 } # EOF diff --git a/lib/bash/bamc_sanity.sh b/lib/bash/bamc_sanity.sh new file mode 100644 index 0000000..40f22bf --- /dev/null +++ b/lib/bash/bamc_sanity.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +function action_sanity-checks() { + verbose "Checking system..." + local rc=0 + + check_OS + rc=$((rc+$?)) + check_OS_subtype + rc=$((rc+$?)) + check_AMC_version + rc=$((rc+$?)) + + color_echo "OS_TYPE=$OS" + color_echo "OS_SUBTYPE=$OS_SUBTYPE" + color_echo "AMC_VERSION=$AMC_VERSION" + + if [ $rc -gt 0 ]; then + error "Something might not be setup correclty" + else + verbose "System looks OK" + fi + + return $rc +} + +# EOF diff --git a/lib/bash/functions.sh b/lib/bash/functions.sh index b47ad28..7e5cdef 100644 --- a/lib/bash/functions.sh +++ b/lib/bash/functions.sh @@ -1,775 +1,777 @@ #!/bin/bash function get_targets() { # TARGETS TARGETS="check:do_check|\ blank:do_blank|\ test:do_test|\ project:do_project|\ clean:do_clean|\ sample:do_sample|\ pdf:do_pdf|\ all:do_check,do_blank,do_sample,do_pdf,do_list|\ webdav_catalog:do_webdav_catalog|\ webdav_sample:do_webdav_sample|\ webdav_list:do_webdav_list|\ webdav_pdf:do_webdav_pdf|\ webdav_all:do_webdav_catalog,do_webdav_sample,do_webdav_list,do_webdav_pdf|\ list:do_list|\ help:do_help|\ scans:do_scans|\ analyse:do_analyse|\ associate:do_associate|\ export:do_export|\ annotate:do_annotate|\ mailing:do_mailing" echo $TARGETS | tr '|' '\n' | grep "^$1:" | cut -d ':' -f 2- | tr ',' ' ' } function parse_arguments() { if [ $# -lt 1 ]; then set 'test'; fi while [ $# -gt 0 ]; do case "$1" in '--only'|'-o') shift echo teacher_list:$1 | tr ',' ' ' shift ;; '--params'|'-p') shift echo parameters:$1 | tr ',' ' ' shift ;; *) echo target:$(get_targets $1) shift ;; esac done } function get_param_value() { local IFS=' ' for p in $(echo $PARAMETERS | tr ',' ' '); do echo $p | grep "$1=" | cut -d '=' -f 2 done } function do_actions() { ACTIONS=$(parse_arguments $@ | grep "^target:" | cut -d ':' -f 2-) TEACHERS=$(parse_arguments $@ | grep "^teacher_list:" | cut -d ':' -f 2-) PARAMETERS=$(parse_arguments $@ | grep "^parameters:" | cut -d ':' -f 2-) local rc=0 if [ -z "$ACTIONS" ]; then echo "Nothing to do!"; exit 0; fi for ACTION in $(echo "$ACTIONS"); do tell_if_verbose "Processing : ($ACTION)" process_action $ACTION rc=$((rc+$?)) done if [ $rc -gt 0 ]; then echo "RC=$rc" fi exit $rc } function tell_if_verbose() { if [ "$(get_param_value 'mode')" = 'verbose' ]; then echo "$@"; fi } function do_help() { echo $(basename $0)" [--only teacher,teacher] [--params ask=no,lang=xx] action [action ...] Options: --only, -o: only process the following teachers (comma separated list) --params, -p: set/force some parameters (e.g. ask=no,mode=verbose,lang=fr) Actions: help: print this help test: do nothing - usefull for testing with --only ... # Exam preparation project: build AMC project clean: clean output dirs, projects, etc sample: build samples PDF (sample) blank: build blank exam PDF (blank and catalog) pdf: build final PDF (exam and correction) list: build exam students list all: build blank, sample, final and list PDF files # Exam publication webdav_catalog: publish catalog PDF files to \$DIR_WEBDAV_CATALOGS webdav_sample: publish sample PDF files to \$DIR_WEBDAV_SAMPLES [...]" #echo $TARGETS | tr '|' '\n' | sed "s/:/ => /g" | sed "s/,/, /g" } function process_action() { case "$1" in "do_clean") do_clean;; "do_project") do_project;; "do_sample") do_sample;; "do_pdf") do_pdf;; "do_help") do_help;; "do_scans") do_scans;; "do_analyse") do_analyse;; "do_associate") do_associate;; "do_annotate") do_annotate;; "do_export") do_export;; "do_mailing") do_mailing;; "do_test") do_test;; "do_blank") do_blank;; "do_check") do_check;; "do_list") do_list;; "do_webdav_catalog") do_webdav_catalog;; "do_webdav_sample") do_webdav_sample;; "do_webdav_list") do_webdav_list;; "do_webdav_pdf") do_webdav_pdf;; *) echo "Unimplemented action: '$1'" return 1 ;; esac return $? } function do_list() { local rc=0 local lang line id sciper name section IFS i tab FILE list_file for teacher in $(get_teachers); do tell_if_verbose " - $teacher" if [ ! -d $DIR_TEACHERS/$teacher ]; then echo "ERROR: [$teacher] teacher not found." ((rc++)) else lang=$(get_lang $teacher) FILE=$DIR_TEACHERS/$teacher/$FILE_PROF IFS=$'\n' cp $DIR_LIST/$lang/list.tex $DIR_EXAMS/$teacher/$FILE_LIST_MAIN list_file=$DIR_EXAMS/$teacher/$FILE_LIST_MAIN check_file_exists $list_file for replace in $(cat $FILE); do pattern="#$(echo $replace | cut -d ':' -f 1)#" string=$(echo $replace | cut -d ':' -f 2-) - sed -i "s/$pattern/$string/g" $list_file + sed "s/$pattern/$string/g" $list_file > tmp.$$ + mv tmp.$$ $list_file done rm -f $DIR_EXAMS/$teacher/$FILE_LIST_ROWS i=0 tab=1 prev_section='' for line in $(tail -n +2 $DIR_EXAMS/$teacher/$FILE_STUDENTS); do ((i++)) if [ $tab -eq 1 ]; then cat $DIR_LIST/$lang/$FILE_LIST_TSTART >> $DIR_EXAMS/$teacher/$FILE_LIST_ROWS tab=0 fi # id field id=$(echo $line | cut -d ',' -f 1) id=$(printf "%3s" $id) id=$(echo $id | sed "s/ /~/g") name=$(echo $line | cut -d ',' -f 2) if [ $(echo -n $name | wc -c) -gt $LIST_MAX_CHAR ]; then name=$(echo $name | cut -c 1-$LIST_MAX_CHAR)"…"; fi sciper=$(echo $line | cut -d ',' -f 3) section=$(echo $line | cut -d ',' -f 4) comment=$(echo $line | cut -d ',' -f 10) if [ "$comment" == "n/a" ]; then comment=''; fi if [ "$section" == "XXX" ]; then section=''; name="SCIPER:"; fi name=$(printf "%-${LIST_MAX_CHAR}s" $name) name=$(echo $name | sed "s/ /~/g") if [ "$section" != "$prev_section" ]; then if [ $i -ne 1 ]; then cat $DIR_LIST/$lang/$FILE_LIST_TEND >> $DIR_EXAMS/$teacher/$FILE_LIST_ROWS cat $DIR_LIST/$lang/$FILE_LIST_TSTART >> $DIR_EXAMS/$teacher/$FILE_LIST_ROWS i=1 fi prev_section=$section fi echo "\texttt{$id} & \texttt{$sciper} & \texttt{$section} & \texttt{$name} & & & {\tiny \texttt{$comment}} "'\\ \hline' >> $DIR_EXAMS/$teacher/$FILE_LIST_ROWS if [ $(($i % $LIST_ROWS_PER_PAGE)) -eq 0 ]; then cat $DIR_LIST/$lang/$FILE_LIST_TEND >> $DIR_EXAMS/$teacher/$FILE_LIST_ROWS tab=1 fi done if [ $(($i % $LIST_ROWS_PER_PAGE)) -ne 0 ]; then cat $DIR_LIST/$lang/$FILE_LIST_TEND >> $DIR_EXAMS/$teacher/$FILE_LIST_ROWS fi pdf_list=$(echo $FILE_LIST_MAIN | cut -d '.' -f 1)'.pdf' cd $DIR_EXAMS/$teacher/ # Run pdflatex twice to get total number of pages pdflatex ./$FILE_LIST_MAIN 2>&1 > /dev/null pdflatex ./$FILE_LIST_MAIN 2>&1 > /dev/null cd - > /dev/null mkdir -p $DIR_LIST_OUT cp $DIR_EXAMS/$teacher/$pdf_list $DIR_LIST_OUT/List-$teacher.pdf cp $DIR_TEACHERS/$teacher/$FILE_STUDENTS $DIR_LIST_OUT/List-$teacher.csv fi done return $rc } function check_project_exists() { local teacher=$1 if [ ! -d $DIR_EXAMS/$teacher ]; then echo "No project found for teacher: $1" echo "Did you run \"project\" action ?" exit 1 fi } function get_teachers() { if [ -n "$TEACHERS" ]; then echo "$TEACHERS"; return; fi find $DIR_TEACHERS -maxdepth 1 -mindepth 1 -type d -exec basename {} \; | grep -v ".ignore$" | sort } function do_test() { local rc=0 for teacher in $(get_teachers); do tell_if_verbose " - $teacher" if [ ! -d $DIR_TEACHERS/$teacher ]; then echo "ERROR: [$teacher] teacher not found." ((rc++)) else echo " Nothing done. just testing." fi done return $rc } function check_file_exists() { if [ ! -r $1 ]; then if [ $# -lt 2 ]; then echo "ERROR: File not found: $1"; fi if [ -n "$2" ]; then return $2; else exit 1; fi fi return 0 } function get_lang() { local forced_lang=$(get_param_value 'lang') if [ -n "$forced_lang" ]; then echo $forced_lang; else local FILE=$DIR_TEACHERS/$1/$FILE_LANG check_file_exists $FILE cat $FILE fi } function import_tex_files() { local teacher=$1 local lang=$(get_lang $teacher) cp $DIR_DATA/base/* $DIR_EXAMS/$teacher/ cp $DIR_DATA/$lang/* $DIR_EXAMS/$teacher/ } function override_tex_files() { local teacher=$1 find $DIR_TEACHERS/$teacher/ -name '*.tex' -exec cp {} $DIR_EXAMS/$teacher/ \; } function import_student_file() { local teacher=$1 local lang=$(get_lang $teacher) local FILE=$DIR_TEACHERS/$teacher/$FILE_STUDENTS check_file_exists $FILE cp $FILE $DIR_EXAMS/$teacher/$FILE_STUDENTS # Add extra students local nb=0 local IFS=$'\n' local id=$(tail -n 1 $DIR_EXAMS/$teacher/$FILE_STUDENTS | cut -d ',' -f 1) local sample=$(head -n 1 $DIR_CSV/extra.csv) while [ $nb -lt $EXTRA_COPIES ]; do ((nb++)) ((id++)) echo $sample | sed "s/#NB#/$nb/g" | sed "s/#ID#/$id/g" | sed "s/#SCIPER#/FAKE-$nb/g" | sed "s/#EMAIL#/$DEFAULT_EMAIL/g" | sed "s/#SEMESTER#/$SEMESTER/g" >> $DIR_EXAMS/$teacher/$FILE_STUDENTS done } function get_expected_page_per_exam() { local teacher=$1 local FILE=$DIR_TEACHERS/$teacher/$FILE_PROF cat $FILE | grep '^TOTAL_PAGES:' | cut -d ':' -f 2 } function customize_tex_files() { local teacher=$1 replace local lang=$(get_lang $teacher) local FILE=$DIR_TEACHERS/$teacher/$FILE_PROF check_file_exists $FILE # professor.tex local prof_file=$DIR_EXAMS/$teacher/$FILE_PROF_TEX IFS=$'\n' check_file_exists $prof_file for replace in $(cat $FILE); do pattern="#$(echo $replace | cut -d ':' -f 1)#" string=$(echo $replace | cut -d ':' -f 2-) - sed -i "s/$pattern/$string/g" $prof_file + sed "s/$pattern/$string/g" $prof_file > tmp.$$ + mv tmp.$$ $prof_file done # exam.tex lang=$(echo $lang | tr '[a-z]' '[A-Z]') - sed -i "s/#LANG#/$lang/g" $DIR_EXAMS/$teacher/$FILE_EXAM_BASENAME.tex + sed "s/#LANG#/$lang/g" $DIR_EXAMS/$teacher/$FILE_EXAM_BASENAME.tex > tmp.$$ + mv tmp.$$ $DIR_EXAMS/$teacher/$FILE_EXAM_BASENAME.tex # Add specific.tex file if [ -r $DIR_EXAMS/$teacher/specific.tex ]; then - sed -i 's?% #SPECIFIC#?\\input{./specific.tex}?g' $DIR_EXAMS/$teacher/$FILE_EXAM_BASENAME.tex + sed 's?% #SPECIFIC#?\\input{./specific.tex}?g' $DIR_EXAMS/$teacher/$FILE_EXAM_BASENAME.tex > tmp.$$ + mv tmp.$$ $DIR_EXAMS/$teacher/$FILE_EXAM_BASENAME.tex fi } function build_sections() { local question_file question section_file section teacher=$1 local lang=$(get_lang $teacher) IFS=$'\n' FILE=$DIR_TEACHERS/$teacher/$FILE_SECTIONS mkdir -p $DIR_EXAMS/$teacher check_file_exists $FILE local section_num=0 rm -f $DIR_EXAMS/$teacher/sections.tex $DIR_EXAMS/$teacher/random-sections.tex for section in $(cat $FILE); do ((section_num++)) section_file=$DIR_EXAMS/$teacher/section_${section_num}.tex rm -f $section_file for question in $(echo $section | tr ',' '\n'); do #echo "Adding $question to section $section_file..."; question_file=$DIR_QUESTIONS/$lang/$question check_file_exists $question_file echo "%% From $lang/$question =======================================" >> $section_file echo '\element{section'$section_num'}{' >> $section_file cat $question_file >> $section_file echo '}' >> $section_file done #echo "Updating 'sections.tex' file" echo "\input{./section_${section_num}.tex}" >> $DIR_EXAMS/$teacher/sections.tex #echo "Updating 'random-sections.tex' file" echo "\input{./header_${section_num}.tex} \melangegroupe{section${section_num}} \restituegroupe{section${section_num}} " >> $DIR_EXAMS/$teacher/random-sections.tex done } function do_sample() { local teacher local lang local runs local ok local rc=0 for teacher in $(get_teachers); do ok=0 tell_if_verbose " - $teacher" check_project_exists $teacher if [ -r $DIR_EXAMS/$teacher/INVALID ]; then ((rc++)); break; fi runs=$PDFLATEX_RUNS mv $DIR_EXAMS/$teacher/$FILE_STUDENTS $DIR_EXAMS/$teacher/$FILE_STUDENTS.sav cp $DIR_CSV/$FILE_SAMPLE_CSV $DIR_EXAMS/$teacher/$FILE_STUDENTS cd $DIR_EXAMS/$teacher - rm -f EXAM-sujet.pdf EXAM-corrige.pdf EXAM-catalog.pdf catalog.pdf + rm -f DOC-subject.pdf DOC-correction.pdf catalog.pdf while [ $runs -gt 0 ]; do - auto-multiple-choice prepare --mode s --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --out-sujet EXAM-sujet.pdf --out-corrige EXAM-corrige.pdf 2>&1 > /dev/null | grep -v 'deprecated' - rm -f $DIR_EXAMS/$teacher/catalog.pdf - check_file_exists EXAM-sujet.pdf 1 - if [ $? -ne 0 ]; then runs=0; continue; else ok=1; fi; + auto-multiple-choice prepare --mode s --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --out-sujet DOC-subject.pdf --out-corrige DOC-correction.pdf 2>&1 > /dev/null | grep -v 'deprecated' + check_file_exists DOC-subject.pdf 1 + if [ $? -ne 0 ]; then runs=0; else ok=1; fi; ((runs--)) done cd - 2>&1 > /dev/null mv $DIR_EXAMS/$teacher/$FILE_STUDENTS.sav $DIR_EXAMS/$teacher/$FILE_STUDENTS if [ $ok -eq 1 ]; then mkdir -p $DIR_SAMPLES lang=$(get_lang $teacher) - mv $DIR_EXAMS/$teacher/EXAM-sujet.pdf $DIR_SAMPLES/Sample-$teacher-$lang.pdf - rm -f $DIR_EXAMS/$teacher/catalog.pdf $DIR_EXAMS/$teacher/EXAM-corrige.pdf + mv $DIR_EXAMS/$teacher/DOC-subject.pdf $DIR_SAMPLES/Sample-$teacher-$lang.pdf else ((rc++)) echo "ERROR: [$teacher] Sample not generated." fi done; return $rc } function do_check() { local teacher local runs local ok local rc=0 for teacher in $(get_teachers); do ok=0 tell_if_verbose " - $teacher" check_project_exists $teacher runs=$PDFLATEX_RUNS mv $DIR_EXAMS/$teacher/$FILE_STUDENTS $DIR_EXAMS/$teacher/$FILE_STUDENTS.sav cp $DIR_CSV/$FILE_BLANK_CSV $DIR_EXAMS/$teacher/$FILE_STUDENTS cd $DIR_EXAMS/$teacher - rm -f EXAM-sujet.pdf EXAM-corrige.pdf EXAM-catalog.pdf catalog.pdf + rm -f DOC-subject.pdf DOC-correction.pdf catalog.pdf while [ $runs -gt 0 ]; do - auto-multiple-choice prepare --mode s --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --out-sujet EXAM-sujet.pdf --out-corrige EXAM-corrige.pdf 2>&1 > /dev/null | grep -v 'deprecated' - rm -f catalog.pdf - if [ ! -r EXAM-sujet.pdf ]; then runs=0; continue; else ok=1; fi; - if [ ! -r EXAM-corrige.pdf ]; then runs=0; continue; else ok=1; fi; + auto-multiple-choice prepare --mode s --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --out-sujet DOC-subject.pdf --out-corrige DOC-correction.pdf 2>&1 > /dev/null | grep -v 'deprecated' + if [ ! -r DOC-subject.pdf ]; then runs=0; else ok=1; fi; + if [ ! -r DOC-correction.pdf ]; then runs=0; else ok=1; fi; + if [ ! -r catalog.pdf ]; then runs=0; else ok=1; fi; ((runs--)) done cd - 2>&1 > /dev/null mv $DIR_EXAMS/$teacher/$FILE_STUDENTS.sav $DIR_EXAMS/$teacher/$FILE_STUDENTS if [ $ok -eq 0 ]; then echo "ERROR: [$teacher] exam.tex does not compile." touch $DIR_EXAMS/$teacher/INVALID ((rc++)) else rm -f $DIR_EXAMS/$teacher/INVALID fi done; return $rc } function do_blank() { local teacher local lang local runs local ok local rc=0 for teacher in $(get_teachers); do ok=0 tell_if_verbose " - $teacher" check_project_exists $teacher if [ -r $DIR_EXAMS/$teacher/INVALID ]; then ((rc++)); break; fi runs=$PDFLATEX_RUNS mv $DIR_EXAMS/$teacher/$FILE_STUDENTS $DIR_EXAMS/$teacher/$FILE_STUDENTS.sav cp $DIR_CSV/$FILE_BLANK_CSV $DIR_EXAMS/$teacher/$FILE_STUDENTS cd $DIR_EXAMS/$teacher - rm -f EXAM-sujet.pdf EXAM-corrige.pdf EXAM-catalog.pdf catalog.pdf + rm -f DOC-subject.pdf DOC-correction.pdf catalog.pdf while [ $runs -gt 0 ]; do - auto-multiple-choice prepare --mode s --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --out-sujet EXAM-sujet.pdf --out-corrige EXAM-corrige.pdf 2>&1 > /dev/null | grep -v 'deprecated' - check_file_exists EXAM-sujet.pdf 1 - if [ $? -ne 0 ]; then runs=0; continue; else ok=1; fi; - check_file_exists EXAM-corrige.pdf 1 - if [ $? -ne 0 ]; then runs=0; continue; else ok=1; fi; + auto-multiple-choice prepare --mode s --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --out-sujet DOC-subject.pdf --out-corrige DOC-correction.pdf 2>&1 > /dev/null | grep -v 'deprecated' + check_file_exists DOC-subject.pdf 1 + if [ $? -ne 0 ]; then runs=0; else ok=1; fi; + check_file_exists DOC-correction.pdf 1 + if [ $? -ne 0 ]; then runs=0; else ok=1; fi; check_file_exists catalog.pdf 1 - if [ $? -ne 0 ]; then runs=0; continue ;else ok=1; fi; + if [ $? -ne 0 ]; then runs=0; else ok=1; fi; ((runs--)) done cd - 2>&1 > /dev/null mv $DIR_EXAMS/$teacher/$FILE_STUDENTS.sav $DIR_EXAMS/$teacher/$FILE_STUDENTS if [ $ok -eq 1 ]; then mkdir -p $DIR_BLANKS lang=$(get_lang $teacher) - mv $DIR_EXAMS/$teacher/EXAM-sujet.pdf $DIR_BLANKS/Blank-$teacher-$lang.pdf - mv $DIR_EXAMS/$teacher/EXAM-corrige.pdf $DIR_BLANKS/Correction-Blank-$teacher-$lang.pdf + mv $DIR_EXAMS/$teacher/DOC-subject.pdf $DIR_BLANKS/Blank-$teacher-$lang.pdf + mv $DIR_EXAMS/$teacher/DOC-correction.pdf $DIR_BLANKS/Correction-Blank-$teacher-$lang.pdf mv $DIR_EXAMS/$teacher/catalog.pdf $DIR_BLANKS/Catalog-$teacher-$lang.pdf else ((rc++)) echo "ERROR: [$teacher] Blank not generated." fi done; return $rc } function do_pdf() { local teacher local lang local runs local ok=0 local rc for teacher in $(get_teachers); do ok=0 tell_if_verbose " - $teacher" check_project_exists $teacher if [ -r $DIR_EXAMS/$teacher/INVALID ]; then ((rc++)); break; fi runs=$PDFLATEX_RUNS cd $DIR_EXAMS/$teacher while [ $runs -gt 0 ]; do tell_if_verbose " (step 1/3)" - auto-multiple-choice prepare --mode s --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --out-sujet EXAM-sujet.pdf --out-corrige EXAM-corrige.pdf --out-calage DOC-calage.xy 2>&1 > /dev/null | grep -v 'deprecated' + auto-multiple-choice prepare --mode s --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --out-sujet DOC-subject.pdf --out-corrige DOC-correction.pdf --out-calage DOC-calage.xy 2>&1 > /dev/null | grep -v 'deprecated' ((runs--)) - check_file_exists EXAM-sujet.pdf 1 - if [ $? -ne 0 ]; then runs=0; continue; else ok=1; fi; - check_file_exists EXAM-corrige.pdf 1 - if [ $? -ne 0 ]; then runs=0; continue; else ok=1; fi; + check_file_exists DOC-subject.pdf 1 + if [ $? -ne 0 ]; then runs=0; else ok=1; fi; + check_file_exists DOC-correction.pdf 1 + if [ $? -ne 0 ]; then runs=0; else ok=1; fi; check_file_exists DOC-calage.xy 1 - if [ $? -ne 0 ]; then runs=0; continue; else ok=1; fi; + if [ $? -ne 0 ]; then runs=0; else ok=1; fi; done if [ $ok -eq 1 ]; then tell_if_verbose " (step 2/3)" auto-multiple-choice prepare --mode b --with pdflatex --filter latex --prefix ./ ./$FILE_EXAM_BASENAME.tex --data ./data/ 2>&1 > /dev/null | grep -v 'deprecated' tell_if_verbose " (step 3/3)" auto-multiple-choice meptex --src ./DOC-calage.xy --data ./data --debug /dev/null 2>&1 > /dev/null fi cd - 2>&1 > /dev/null if [ $ok -eq 1 ]; then mkdir -p $DIR_PDF lang=$(get_lang $teacher) - cp $DIR_EXAMS/$teacher/EXAM-sujet.pdf $DIR_PDF/Exam-$teacher-$lang.pdf - cp $DIR_EXAMS/$teacher/EXAM-corrige.pdf $DIR_PDF/Exam-$teacher-$lang-CORRECTION.pdf - mv $DIR_EXAMS/$teacher/catalog.pdf $DIR_EXAMS/$teacher/EXAM-catalog.pdf + cp $DIR_EXAMS/$teacher/DOC-subject.pdf $DIR_PDF/Exam-$teacher-$lang.pdf + cp $DIR_EXAMS/$teacher/DOC-correction.pdf $DIR_PDF/Exam-$teacher-$lang-CORRECTION.pdf # Validate page count nb_of_students=$(tail -n 1 $DIR_EXAMS/$teacher/$FILE_STUDENTS | cut -d ',' -f 1) ppe=$(get_expected_page_per_exam $teacher) expected_page_count=$(echo "$ppe * $nb_of_students" | bc) actual_page_count=$(pdfinfo $DIR_PDF/Exam-$teacher-$lang.pdf | grep '^Pages:' | rev | cut -d ' ' -f 1 | rev) if [ $expected_page_count -ne $actual_page_count ]; then ((rc++)) echo "Unexpected number of pages generated." fi echo "$actual_page_count page(s) generated for $nb_of_students students. $expected_page_count pag(s) were expected." > $DIR_PDF/Exam-$teacher-$lang.log else ((rc++)) echo "Exam not generated for $teacher." fi done return $rc } function build_amc_project() { local teacher=$1 mkdir -p $DIR_EXAMS/$teacher/cr/corrections/jpg mkdir -p $DIR_EXAMS/$teacher/cr/corrections/pdf mkdir -p $DIR_EXAMS/$teacher/cr/diagnostic mkdir -p $DIR_EXAMS/$teacher/cr/zooms mkdir -p $DIR_EXAMS/$teacher/data mkdir -p $DIR_EXAMS/$teacher/exports mkdir -p $DIR_EXAMS/$teacher/scans mkdir -p $DIR_EXAMS/$teacher/copies mkdir -p $DIR_EXAMS/$teacher/media cp $DIR_CONFIG/$FILE_AMC_OPTIONS $DIR_EXAMS/$teacher/$FILE_AMC_OPTIONS } function add_media_files() { local teacher=$1 cp $DIR_MEDIA/* $DIR_EXAMS/$teacher/media/ } function do_project() { mkdir -p $DIR_EXAMS local teacher for teacher in $(get_teachers); do tell_if_verbose " - $teacher" build_amc_project $teacher build_sections $teacher import_tex_files $teacher override_tex_files $teacher customize_tex_files $teacher add_media_files $teacher import_student_file $teacher done } function do_scans() { local teacher for teacher in $(get_teachers); do echo "Processing teacher $teacher" if [ ! -d $DIR_SCANS/$teacher ]; then echo "No scans found! (looked in $DIR_SCANS/$teacher)" break; fi rm -rf $DIR_EXAMS/$teacher/scans/ mkdir $DIR_EXAMS/$teacher/scans/ cp $DIR_SCANS/$teacher/* $DIR_EXAMS/$teacher/scans/ local file_count=$(find $DIR_EXAMS/$teacher/scans/ -type f | wc -l) echo "Number of files: $file_count" local page_count=0 for tif in $(find $DIR_EXAMS/$teacher/scans/ -type f); do if [ $(tiffinfo $tif 2> /dev/null | grep 'Page Number:' | cut -d '-' -f 2 ) -eq 0 ]; then ((page_count++)) else echo "Invalid page count for file: $tif"; fi done echo "Number of pages: $page_count" local students_count=$(cat $DIR_EXAMS/$teacher/$FILE_STUDENTS | grep -vc '^ID,') echo "Number of students: $students_count" local ppc=$(grep 'TOTAL_PAGES:' $DIR_TEACHERS/$teacher/$FILE_PROF | cut -d ':' -f 2) local expected=$((ppc*students_count)) echo "Expected number of pages: $expected" if [ ! $expected -eq $page_count ]; then echo "MISSING COPIES :" cat $DIR_EXAMS/$teacher/$FILE_STUDENTS | grep -v '^ID,' | cut -d ',' -f 1 >> /tmp/$$ find $DIR_EXAMS/$teacher/scans/ -type f | rev | cut -d '_' -f 1 | rev | cut -d '-' -f 1 | sed 's/^0*//g' | sort -u >> /tmp/$$ for missing in $(sort -n /tmp/$$ | uniq -u); do grep "^$missing," $DIR_EXAMS/$teacher/$FILE_STUDENTS done rm -f /tmp/$$ fi done } function do_analyse() { local teacher for teacher in $(get_teachers); do echo "Processing teacher $teacher" cd $DIR_EXAMS/$teacher/ auto-multiple-choice analyse --projet ./ ./scans/* # auto-multiple-choice note --data ./data --seuil 0.05 # ignored anyway... check "seuil" in options.xml cd - > /dev/null 2>&1 done } function do_associate() { local teacher for teacher in $(get_teachers); do echo "Processing teacher $teacher" cd $DIR_EXAMS/$teacher/ for csv in $(grep -v '^ID,' $FILE_STUDENTS | cut -d ',' -f 1,3); do local id=$(echo $csv | cut -d ',' -f 1) local sciper=$(echo $csv | cut -d ',' -f 2) auto-multiple-choice association --data ./data --set --student $id --id $sciper done cd - > /dev/null 2>&1 done } function do_annotate() { local teacher for teacher in $(get_teachers); do echo "Processing teacher $teacher" cd $DIR_EXAMS/$teacher/ auto-multiple-choice annote --projet ./ --data ./data --fich-noms $FILE_STUDENTS - auto-multiple-choice regroupe --projet ./ --sujet EXAM-sujet.pdf --fich-noms $FILE_STUDENTS --tex-src $FILE_EXAM_BASENAME.tex --compose + auto-multiple-choice regroupe --projet ./ --sujet DOC-subject.pdf --fich-noms $FILE_STUDENTS --tex-src $FILE_EXAM_BASENAME.tex --compose cd - > /dev/null 2>&1 done } function do_mailing() { local teacher for teacher in $(get_teachers); do echo "Processing teacher $teacher" local lang=$(get_lang $teacher) check_file_exists $DIR_CONFIG/$lang-$FILE_AMC_MAILING cp $DIR_CONFIG/$lang-$FILE_AMC_MAILING $DIR_EXAMS/$teacher/$FILE_AMC_MAILING - sed -i "s?%FILE_STUDENTS%?./$FILE_STUDENTS?g" $DIR_EXAMS/$teacher/$FILE_AMC_MAILING + sed "s?%FILE_STUDENTS%?./$FILE_STUDENTS?g" $DIR_EXAMS/$teacher/$FILE_AMC_MAILING > tmp.$$ + mv tmp.$$ $DIR_EXAMS/$teacher/$FILE_AMC_MAILING echo "#!/bin/bash auto-multiple-choice mailing --xmlargs ./$FILE_AMC_MAILING exit 0" > $DIR_EXAMS/$teacher/$FILE_EMAILS_SCRIPT chmod +x $DIR_EXAMS/$teacher/$FILE_EMAILS_SCRIPT done } function do_export() { local teacher for teacher in $(get_teachers); do tell_if_verbose " - $teacher" cd $DIR_EXAMS/$teacher/ auto-multiple-choice export --data ./data --module CSV --fich-noms $FILE_STUDENTS --o $FILE_RESULTS.csv cd - > /dev/null 2>&1 done } function check_webdav_mounted() { if [ ! -d $DIR_WEBDAV_BASE ]; then echo "ERROR: webdav dir ($DIR_WEBDAV_BASE) is not accessible."; exit 1; fi } function do_webdav_catalog() { local teacher local rc=0 check_webdav_mounted for teacher in $(get_teachers); do tell_if_verbose " - $teacher" local lang=$(get_lang $teacher) mkdir -p $DIR_WEBDAV_CATALOGS for f in $(echo $DIR_BLANKS/Catalog-$teacher-$lang.pdf); do check_file_exists $f 1 if [ $? -eq 0 ]; then cp $f $DIR_WEBDAV_CATALOGS/ else echo "ERROR: [$teacher] "$f" not found. Did you run 'blank' action?" ((rc++)) break; fi done done return $rc } function do_webdav_sample() { local teacher local rc=0 check_webdav_mounted for teacher in $(get_teachers); do tell_if_verbose " - $teacher" local lang=$(get_lang $teacher) mkdir -p $DIR_WEBDAV_SAMPLES for f in $(echo $DIR_SAMPLES/Sample-$teacher-$lang.pdf); do check_file_exists $f 1 if [ $? -eq 0 ]; then cp $f $DIR_WEBDAV_SAMPLES/ else echo "ERROR: [$teacher] "$f" not found. Did you run 'sample' action?" ((rc++)) break; fi done done return $rc } function do_webdav_pdf() { local teacher local rc=0 check_webdav_mounted for teacher in $(get_teachers); do tell_if_verbose " - $teacher" local lang=$(get_lang $teacher) mkdir -p $DIR_WEBDAV_EXAMS for f in $(echo $DIR_PDF/Exam-$teacher-$lang.log $DIR_PDF/Exam-$teacher-$lang.pdf $DIR_PDF/Exam-$teacher-$lang-CORRECTION.pdf); do check_file_exists $f 1 if [ $? -eq 0 ]; then cp $f $DIR_WEBDAV_EXAMS/ else echo "ERROR: [$teacher] "$f" not found. Did you run 'list' action?" ((rc++)) break; fi done done return $rc } function do_webdav_list() { local teacher local rc=0 check_webdav_mounted for teacher in $(get_teachers); do tell_if_verbose " - $teacher" local lang=$(get_lang $teacher) mkdir -p $DIR_WEBDAV_LISTS for f in $(echo $DIR_LIST_OUT/List-$teacher.pdf $DIR_LIST_OUT/List-$teacher.csv); do check_file_exists $f 1 if [ $? -eq 0 ]; then cp $f $DIR_WEBDAV_LISTS/ else echo "ERROR: [$teacher] "$f" not found. Did you run 'list' action?" ((rc++)) break; fi done done return $rc } function do_clean() { local teacher local ask=$(get_param_value 'ask') for teacher in $(get_teachers); do tell_if_verbose " - $teacher" lang=$(get_lang $teacher) if [ "$ask" != "no" ]; then echo "Cleaning all generated data for teacher '$teacher' ? CTRL-C to abort." echo "(Use '--params ask=no' to force)" read a fi # Projects rm -rf $DIR_EXAMS/$teacher # Blanks rm -f $DIR_BLANKS/Blank-$teacher-$lang.pdf $DIR_BLANKS/Correction-Blank-$teacher-$lang.pdf $DIR_BLANKS/Catalog-$teacher-$lang.pdf # Samples rm -f $DIR_SAMPLES/Sample-$teacher-$lang.pdf # PDF rm -f $DIR_PDF/Exam-$teacher-$lang.log $DIR_PDF/Exam-$teacher-$lang.pdf $DIR_PDF/Exam-$teacher-$lang-CORRECTION.pdf # Lists rm -f $DIR_LIST_OUT/List-$teacher.pdf $DIR_LIST_OUT/List-$teacher.csv done for dir_to_clean in $(echo "$DIR_EXAMS $DIR_BLANKS $DIR_SAMPLES $DIR_PDF $DIR_LIST_OUT"); do if [ -d $dir_to_clean ]; then rmdir --ignore-fail-on-non-empty $dir_to_clean; fi; done } diff --git a/lib/bash/tools.sh b/lib/bash/tools.sh new file mode 100644 index 0000000..f6165c7 --- /dev/null +++ b/lib/bash/tools.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +function check_OS() { + OS=$(uname | tr "[A-Z]" "[a-z]") + if [ "$OS" == "linux" ]; then return 0; fi + OS="unknown" + return 1 +} + +function check_OS_subtype() { + OS_SUBTYPE="unknown" + if [ -r /etc/gentoo-release ]; then OS_SUBTYPE="gentoo"; return 0; fi + return 1 +} + +function check_AMC_version() { + AMC_VERSION="unknown" + which auto-multiple-choice > /dev/null 2>&1 + if [ $? -gt 0 ]; then + AMC_VERSION="none" + return 1 + fi + + case $OS in + "linux") + case $OS_SUBTYPE in + "gentoo") + AMC_VERSION=$(eix --xml auto-multiple-choice | grep 'installed="1"' | tr " " "\n" | grep '^id' | cut -d '"' -f 2) + return 0;; + esac + esac + return 1 +} + +# EOF