From 0f99e937fd580bcd4a8282b46e5248dd86c25065 Mon Sep 17 00:00:00 2001 From: Eli Barzilay Date: Mon, 18 Feb 2008 19:44:13 +0000 Subject: [PATCH] many imrovements svn: r8706 --- .../scribblings/handin-server.scrbl | 920 +++++++++--------- 1 file changed, 476 insertions(+), 444 deletions(-) diff --git a/collects/handin-server/scribblings/handin-server.scrbl b/collects/handin-server/scribblings/handin-server.scrbl index 6d725ae76b..38aa96a091 100644 --- a/collects/handin-server/scribblings/handin-server.scrbl +++ b/collects/handin-server/scribblings/handin-server.scrbl @@ -355,7 +355,7 @@ This directory contains the following files and sub-directories: @defproc[(hook [operation symbol?] [connection-context (or/c number? symbol? false?)] [relevant-info (listof (list/c symbol? any))]) - void?]{ + void?]{ The @scheme[operation] argument indicates the operation that is now taking place. It can be one of the following: @@ -421,11 +421,12 @@ This directory contains the following files and sub-directories: (( ( )) ...)} - Usernames that begin with ``solution'' are special. They are used by the - HTTPS status server. Independent of the @scheme['user-regexp] and - @scheme['username-case-sensitive?] configuration items, usernames are not - allowed to contain characters that are illegal in Windows pathnames, and they - cannot end or begin in spaces or periods. + Usernames that begin with ``solution'' are special. They are used + by the HTTPS status server. Independent of the + @scheme['user-regexp] and @scheme['username-case-sensitive?] + configuration items, usernames are not allowed to contain characters + that are illegal in Windows pathnames, and they cannot end or begin + in spaces or periods. If the @scheme['allow-new-users] configuration allows new users, the @filepath{users.ss} file can be updated by the server with new @@ -543,90 +544,93 @@ This directory contains the following files and sub-directories: student. The module is loaded when the current directory is the main server directory, so it can read files from there (but note that to read values from @filepath{config.ss} it is better to use - @scheme[get-conf]). Also, the module will be reloaded if the checker - file is modified; there's no need to restart the server, but make sure - that you do not save a broken checker (ie, do not save in - mid-edit). + @scheme[get-conf]). Also, the module will be reloaded if the + checker file is modified; there's no need to restart the server, + but make sure that you do not save a broken checker (i.e., do not + save in mid-edit). The first argument is a list of usernames with at least one username, and more than one if this is a joint submission (where the submission username was a concatenation of usernames separated by ``@tt{+}''). - The @scheme[checker] function is called with the current directory as - @filepath{//ATTEMPT}, and the submission is - saved in the file @filepath{handin}, and the timeout clock is reset to the - value of the @scheme[session-timeout] configuration. The checker function - can change @filepath{handin}, and it can create additional files in this - directory. (Extra files in the current directory will be - preserved as it is later renamed to @filepath{SUCCESS-0}, and copied to the - submission's root (@filepath{//}), etc.) - To hide generated files from the HTTPS status web server - interface, put the files in a subdirectory, it is preserved but - hidden from the status interface. + The @scheme[checker] function is called with the current directory + as @filepath{//ATTEMPT}, and the + submission is saved in the file @filepath{handin}, and the timeout + clock is reset to the value of the @scheme[session-timeout] + configuration. The checker function can change @filepath{handin}, + and it can create additional files in this directory. (Extra + files in the current directory will be preserved as it is later + renamed to @filepath{SUCCESS-0}, and copied to the submission's + root (@filepath{//}), etc.) To + hide generated files from the HTTPS status web server interface, + put the files in a subdirectory, it is preserved but hidden from + the status interface. - The checker should return a string, such as @filepath{handin.scm}, to use - in naming the submission file, or @scheme[#f] to indicate that he file - should be deleted (e.g., when the checker alrady created the - submission file(s) in a different place). + The checker should return a string, such as @filepath{handin.scm}, + to use in naming the submission file, or @scheme[#f] to indicate + that he file should be deleted (e.g., when the checker alrady + created the submission file(s) in a different place). - Alternatively, the module can bind @scheme[checker] to a list of three - procedures: a pre-checker, a checker, and a post-checker. All - three are applied in exactly the same way as the checker (same + Alternatively, the module can bind @scheme[checker] to a list of + three procedures: a pre-checker, a checker, and a post-checker. + All three are applied in exactly the same way as the checker (same arguments, and always within the submission directory), except that: @itemize{ - -@item{If there was an error during the pre-checker, and the submission - directory does not have a @filepath{SUCCESS-*} directory, then the whole - submission directory is removed. This is useful for checking - that the user/s are valid; if you allow a submission only when - @scheme[users] is @scheme['("foo" "bar")], and ``@tt{foo}'' tries to submit alone, then - the submission directory for ``@tt{foo}'' should be removed to allow a - proper submission later. Note that the timeout clock is reset - only once, before the pre-checker is used.} -@item{The post-checker is used at the end of the process, after the - @filepath{ATTEMPT} directory was renamed to @filepath{SUCCESS-0}. At this stage, - the submission is considered successful, so this function should - avoid throwing an exception (it can, but the submission will - still be in place). This is useful for things like notifying - the user of the successful submission (see @scheme[message]), or - sending a `receipt' email.}} + @item{If there was an error during the pre-checker, and the + submission directory does not have a @filepath{SUCCESS-*} + directory, then the whole submission directory is removed. This + is useful for checking that the user/s are valid; if you allow a + submission only when @scheme[users] is @scheme['("foo" "bar")], + and ``@tt{foo}'' tries to submit alone, then the submission + directory for ``@tt{foo}'' should be removed to allow a proper + submission later. Note that the timeout clock is reset only + once, before the pre-checker is used.} - To specify only pre/post-checker, use @scheme[#f] for the one you want to - omit. -} + @item{The post-checker is used at the end of the process, after + the @filepath{ATTEMPT} directory was renamed to + @filepath{SUCCESS-0}. At this stage, the submission is + considered successful, so this function should avoid throwing an + exception (it can, but the submission will still be in place). + This is useful for things like notifying the user of the + successful submission (see @scheme[message]), or sending a + ``receipt'' email.}} -@item{@filepath{<[in]active-assignment>//} (if submitted) : - the most recent submission for @tt{<[in]active-assignment>} by - @tt{} where was returned by the checker (or the - value of the `default-file-name' configuration option if there's - no checker). If the submission is from multiple users, then - ``@tt{}'' is actually ``@tt{+}'' etc. Also, if the - cleanup process was interrupted (by a machine failure, etc.), the - submission may actually be in @filepath{SUCCESS-n} as described above, but - will move up when the server performs a cleanup (or when - restarted).} + To specify only pre/post-checker, use @scheme[#f] for the one you + want to omit.} -@item{@filepath{<[in]active-assignment>//grade} (optional) : the - @tt{}'s grade for @tt{<[in]active-assignment>}, to be reported by - the HTTPS status web server} +@item{@filepath{<[in]active-assignment>//} (if + submitted): the most recent submission for + @tt{<[in]active-assignment>} by @tt{} where was + returned by the checker (or the value of the + @scheme[default-file-name] configuration option if there's no + checker). If the submission is from multiple users, then + ``@tt{}'' is actually ``@tt{+}'' etc. Also, + if the cleanup process was interrupted (by a machine failure, etc.), + the submission may actually be in @filepath{SUCCESS-n} as described + above, but will move up when the server performs a cleanup (or when + restarted).} -@item{@filepath{<[in]active-assignment>/solution*} : the solution to the - assignment, made available by the status server to any user who - logs in. The solution can be either a file or a directory with a - name that begins with @filepath{solution}. In the first case, the status - web server will have a ``Solution'' link to the file, and in the - second case, all files in the @filepath{solution*} directory will be listed - and accessible.} +@item{@filepath{<[in]active-assignment>//grade} (optional): + the @tt{}'s grade for @tt{<[in]active-assignment>}, to be + reported by the HTTPS status web server} + +@item{@filepath{<[in]active-assignment>/solution*}: the solution to + the assignment, made available by the status server to any user who + logs in. The solution can be either a file or a directory with a + name that begins with @filepath{solution}. In the first case, the + status web server will have a ``Solution'' link to the file, and in + the second case, all files in the @filepath{solution*} directory + will be listed and accessible.} } The server can be run within either MzScheme or MrEd, but -@schememodname[handin-server/utils] requires MrEd (which means that @scheme[checker] -modules will likely require the server to run under MrEd). It is best to use -MrEd3m so memory accounting is possible and the server will be protected from -memory related crashes. +@schememodname[handin-server/utils] requires MrEd (which means that +@scheme[checker] modules will likely require the server to run under +MrEd). Remember that if you're not using the (default) 3m garbage +collector you don't get memory accounting. The server currently provides no mechanism for a graceful shutdown, but terminating the server is no worse than a network outage. (In @@ -634,18 +638,19 @@ particular, no data should be lost.) The server reloads the configuration file, checker modules etc, so there should not be any need to restart it for reconfigurations. -The client and server are designed to be robust against network problems and -timeouts. The client-side tool always provides a @onscreen{cancel} button for -any network transaction. For handins, @onscreen{cancel} is guaranteed to work -up to the point that the client sends a ``commit'' command; this command is -sent only after the server is ready to record the submission (having run it -through the checker, if any), but before renaming @filepath{ATTEMPT}. Also, -the server responds to a commit with @onscreen{ok} only after it has written -the file. Thus, when the client-side tool reports that the handin was -successful, the report is reliable. Meanwhile, the tool can also report -successful cancels most of the time. In the (normally brief) time between a -commit and an @onscreen{ok} response, the tool gives the student a suitable -warning that the cancel is unreliable. +The client and server are designed to be robust against network +problems and timeouts. The client-side tool always provides a +@onscreen{cancel} button for any network transaction. For handins, +@onscreen{cancel} is guaranteed to work up to the point that the +client sends a ``commit'' command; this command is sent only after the +server is ready to record the submission (having run it through the +checker, if any), but before renaming @filepath{ATTEMPT}. Also, the +server responds to a commit with @onscreen{ok} only after it has +written the file. Thus, when the client-side tool reports that the +handin was successful, the report is reliable. Meanwhile, the tool +can also report successful cancels most of the time. In the (normally +brief) time between a commit and an @onscreen{ok} response, the tool +gives the student a suitable warning that the cancel is unreliable. To minimize human error, the number of active assignments should be limited to one whenever possible. When multiple assignments are @@ -672,23 +677,25 @@ They are provided in a few layers, each layer provides new functionality in addition to the lower one. These modules are (in order): - @itemize{ @comment{scheme/sandbox or mzlib/sandbox?} -@item{@schememodname[scheme/sandbox] : contains basic sandbox evaluation utilities. This is in - MzLib since it can be used independently.} +@item{@schememodname[scheme/sandbox]: contains basic sandbox + evaluation utilities. This is in MzLib since it can be used + independently.} -@item{@schememodname[handin-server/sandbox] : contains a wrapper that configures MzLib's sandbox for the -handin server.} +@item{@schememodname[handin-server/sandbox]: contains a wrapper that + configures MzLib's sandbox for the handin server.} -@item{@schememodname[handin-server/utils] : contains additional utilities for dealing with handin -submissions, as well as a few helpers for testing code.} +@item{@schememodname[handin-server/utils]: contains additional + utilities for dealing with handin submissions, as well as a few + helpers for testing code.} -@item{@schememodname[handin-server/checker] : automates the task of creating a checker -function (in @filepath{/checker.ss} modules) to cope with -common submission situations.}} +@item{@schememodname[handin-server/checker]: automates the task of + creating a checker function (in + @filepath{/checker.ss} modules) to cope with + common submission situations.}} The following sections describe each of these modules. @@ -697,8 +704,8 @@ The following sections describe each of these modules. @defmodule[handin-server/sandbox] -This is just a wrapper around the sandbox engine from MzLib. It configures it -for use with the handin server. +This is just a wrapper around the sandbox engine from MzLib. It +configures it for use with the handin server. @section{Utils} @@ -709,59 +716,57 @@ for use with the handin server. @defproc[(get-conf [key symbol?]) any/c]{ -Returns a value from the configuration file (useful for reading - things like field names, etc.). -} + Returns a value from the configuration file (useful for reading + things like field names, etc.).} -@comment{ list or values as result?} +@defproc[(unpack-submission [submission bytes?]) + (values (is-a?/c text%) (is-a?/c text%))]{ -@defproc[(unpack-submission [submission bytes?]) (list/c (is-a?/c text%) - (is-a?/c text%))]{ + Returns two @scheme[text%] objects corresponding to the submitted + definitions and interactions windows.} - Returns two @scheme[text%] objects corresponding to the submitted definitions - and interactions windows.} +@defproc[(make-evaluator/submission + [language (or/c module-path? + (list/c (one-of/c 'special) symbol?) + (cons/c (one-of/c 'begin) list?))] + [teachpack-paths (listof path-string?)] + [content bytes?]) + (any/c . -> . any)]{ -@defproc[(make-evaluator/submission [language - (or/c module-path? - (list/c (one-of/c 'special) symbol?) - (cons/c (one-of/c 'begin) list?))] - [teachpack-paths (listof path-string?)] - [content bytes?]) - (any/c . -> . any)]{ + Like @scheme[make-evaluator], but the definitions content is + supplied as a submission byte string. The byte string is opened for + reading, with line-counting enabled.} -Like @scheme[make-evaluator], but the definitions content is supplied as a - submission byte string. The byte string is opened for reading, with - line-counting enabled.} +@defproc[(call-with-evaluator + [language (or/c module-path? + (list/c (one-of/c 'special) symbol?) + (cons/c (one-of/c 'begin) list?))] + [teachpack-paths (listof path-string?)] + [input-program any/c] + [proc (any/c . -> . any)]) + any]{ -@defproc[(call-with-evaluator [language - (or/c module-path? - (list/c (one-of/c 'special) symbol?) - (cons/c (one-of/c 'begin) list?))] - [teachpack-paths (listof path-string?)] - [input-program any/c] - [proc (any/c . -> . any)]) - any]{ - - Calls @scheme[proc] with an evaluator for the given language, teachpack - paths, and initial definition content as supplied by @scheme[input-program] - (see @scheme[make-evaluator]). It also sets the current error-value print - handler to print values in a way suitable for @scheme[language], it initializes - @scheme[set-run-status] with @scheme["executing your code"], and it catches all - exceptions to re-raise them in a form suitable as a submission - error.} + Calls @scheme[proc] with an evaluator for the given language, + teachpack paths, and initial definition content as supplied by + @scheme[input-program] (see @scheme[make-evaluator]). It also sets + the current error-value print handler to print values in a way + suitable for @scheme[language], it initializes + @scheme[set-run-status] with @scheme["executing your code"], and it + catches all exceptions to re-raise them in a form suitable as a + submission error.} @defproc[(call-with-evaluator/submission [language - (or/c module-path? - (list/c (one-of/c 'special) symbol?) - (cons/c (one-of/c 'begin) list?))] - [teachpack-paths (listof path-string?)] - [submission bytes?] - [proc (any/c . -> . any)]) - any]{ - - Like @scheme[call-with-evaluator], but the definitions content is supplied - as a byte string. The byte string is opened for reading, with - line-counting enabled.} + (or/c module-path? + (list/c (one-of/c 'special) symbol?) + (cons/c (one-of/c 'begin) list?))] + [teachpack-paths (listof path-string?)] + [submission bytes?] + [proc (any/c . -> . any)]) + any]{ + + Like @scheme[call-with-evaluator], but the definitions content is + supplied as a byte string. The byte string is opened for reading, + with line-counting enabled.} @comment{this contract is probably wrong} @comment{does this eval accept an optional namespace?} @@ -771,8 +776,9 @@ Like @scheme[make-evaluator], but the definitions content is supplied as a Like @scheme[load] on an input port.} @defproc[(evaluate-submission [submission bytes?] - [eval (any/c . -> . any)]) any]{ - + [eval (any/c . -> . any)]) + any]{ + Like @scheme[load] on a submission byte string.} @defproc[(check-proc [eval (any/c . -> . any)] @@ -780,114 +786,115 @@ Like @scheme[make-evaluator], but the definitions content is supplied as a [compare-proc (any/c any/c . -> . any)] [proc-name symbol?] [arg any/c] ...) - any]{ + any]{ - Calls the function named @scheme[proc-name] using the evaluator @scheme[eval], - giving it the (unquoted) arguments @scheme[arg ...] Let @scheme[result-v] be the - result of the call; unless @scheme[(compare-proc result-v expect-v)] is - true, an exception is raised.} + Calls the function named @scheme[proc-name] using the evaluator + @scheme[eval], giving it the (unquoted) arguments @scheme[arg ...] + Let @scheme[result-v] be the result of the call; unless + @scheme[(compare-proc result-v expect-v)] is true, an exception is + raised.} -Every exception or result mismatch during the call to @scheme[compare-proc] -is phrased suitably for the handin client. +Every exception or result mismatch during the call to +@scheme[compare-proc] is phrased suitably for the handin client. @defproc[(check-defined [eval (any/c . -> . any)] [name symbol?]) any]{ -Checks whether @scheme[name] is defined in the evaluator @scheme[eval], and - raises an error if not (suitably phrased for the handin client). If it is - defined as non-syntax, its value is returned. Warning: in the beginner - language level, procedure definitions are bound as syntax.} + Checks whether @scheme[name] is defined in the evaluator + @scheme[eval], and raises an error if not (suitably phrased for the + handin client). If it is defined as non-syntax, its value is + returned. Warning: in the beginner language level, procedure + definitions are bound as syntax.} @comment{returns what? signals error?} @defproc[(look-for-tests [text (is-a?/c text%)] [name symbol?] [n number?]) any]{ - Inspects the given @scheme[text%] object to determine whether it contains at - least @scheme[n] tests for the function @scheme[name]. The tests must be - top-level expressions.} + Inspects the given @scheme[text%] object to determine whether it + contains at least @scheme[n] tests for the function @scheme[name]. + The tests must be top-level expressions.} @defproc[(user-construct [eval (any/c . -> . any)] [name symbol?] [arg any/c] ...) any]{ - Like @scheme[check-proc], but with no result checking. This function is - often useful for calling a student-defined constructor.} + Like @scheme[check-proc], but with no result checking. This + function is often useful for calling a student-defined constructor.} @defparam[test-history-enabled on? any/c]{ - Controls how run-time errors are reported to the - handin client. If the parameter's value is true, then the complete - sequence of tested expressions is reported to the handin client for - any test failure. Set this parameter to true when testing programs - that use state.} + Controls how run-time errors are reported to the handin client. If + the parameter's value is true, then the complete sequence of tested + expressions is reported to the handin client for any test failure. + Set this parameter to true when testing programs that use state.} @defproc*[([(message [string string?]) void?] [(message [string string?] [styles (or/c (symbols 'final) - (listof (one-of/c 'ok 'ok-cancel 'yes-no 'caution 'stop)))]) + (listof (one-of/c 'ok 'ok-cancel + 'yes-no 'caution 'stop)))]) any])]{ If given only a string, this string will be shown on the client's - submission dialog; if @scheme[styles] is also given, it can be the symbol - @scheme['final], which will be used as the text on the handin dialog after a - successful submission instead of ``Handin successful.'' (useful for - submissions that were saved, but had problems); finally, @scheme[styles] - can be used as a list of styles for a @scheme[message-box] dialog on the - client side, and the resulting value is returned as the result of - @scheme[message]. You can use this to send warnings to the student or ask - confirmation.} + submission dialog; if @scheme[styles] is also given, it can be the + symbol @scheme['final], which will be used as the text on the handin + dialog after a successful submission instead of ``Handin + successful.'' (useful for submissions that were saved, but had + problems); finally, @scheme[styles] can be used as a list of styles + for a @scheme[message-box] dialog on the client side, and the + resulting value is returned as the result of @scheme[message]. You + can use this to send warnings to the student or ask confirmation.} @defproc[(set-run-status [status (or/c false? string?)]) void?]{ Registers information about the current actions of the checker, in - case the session is terminated due to excessive memory consumption. - For example, a checker might set the status to indicate which - instructor-supplied test was being executed when the session ran out - of memory. This status is only used when per-session memory limits - are supported (i.e., under MrEd3m or MzScheme3m with memory - accounting), but in both cases, a string value will also be passed - on to @scheme[message] above.} + case the session is terminated due to excessive memory consumption + or a timeout. For example, a checker might set the status to + indicate which instructor-supplied test was being executed when the + session aborted.} @defparam[current-value-printer proc (any/c . -> . string?)]{ - Controls how values are printed. The @scheme[proc] must be a procedure that - expects a Scheme value and returns a string representation for it. - The default value printer uses @scheme[pretty-print], with DrScheme-like - settings.} + Controls how values are printed. The @scheme[proc] must be a + procedure that expects a Scheme value and returns a string + representation for it. The default value printer uses + @scheme[pretty-print], with DrScheme-like settings.} @defproc[(reraise-exn-as-submission-problem [thunk (-> any)]) any]{ - Calls @scheme[thunk] in a context that catches exceptions and re-raises them - in a form suitable as a submission error. It returns the value returned by - @scheme[thunk] if no exception occurs.} + Calls @scheme[thunk] in a context that catches exceptions and + re-raises them in a form suitable as a submission error. It returns + the value returned by @scheme[thunk] if no exception occurs.} @defproc[(log-line [fmt string?] [args any/c] ...) void?]{ Produces a line in the server log file, using the given format - string and arguments. This function arranges to print - the line fast (to avoid mixing lines from different threads) to the - error port, and flush it. (The log port will prefix all lines with - a time stamp and connection identifier.)} + string and arguments. This function arranges to print the line fast + (to avoid mixing lines from different threads) to the error port, + and flush it. (The log port will prefix all lines with a time stamp + and a connection identifier.)} @defproc[(timeout-control [msg string?]) void?]{ - Control the timeout for this session. The timeout is initialized by the - value of the @scheme[session-timeout] configuration entry, and the checker - can use this procedure to further control it: if @scheme[msg] is - @scheme['reset] the timeout is reset to @scheme[session-timeout] seconds; if - @scheme[msg] is a number the timeout will be set to that many seconds in the - future. The timeout can be completely disabled by @scheme[(timeout-control - #f)]. (Note that before the checker is used (after the pre-checker, if - specified), the timer will be reset to the @scheme['session-timeout] value.)} + Controls the timeout for this session. The timeout is initialized + by the value of the @scheme[session-timeout] configuration entry, + and the checker can use this procedure to further control it: if + @scheme[msg] is @scheme['reset] the timeout is reset to + @scheme[session-timeout] seconds; if @scheme[msg] is a number the + timeout will be set to that many seconds in the future. The timeout + can be completely disabled by @scheme[(timeout-control #f)]. (Note + that before the checker is used (after the pre-checker, if + specified), the timer will be reset to the @scheme['session-timeout] + value.)} @section{checker} @defmodulelang[handin-server/checker]{ -The @schememodname[handin-server/checker] module provides a higher-level of utilities, helpful -in implementing `checker' functions that are intended for a more -automated system. This module is a language module---a typical -checker that uses it looks like this: +The @schememodname[handin-server/checker] module provides a +higher-level of utilities, helpful in implementing `checker' functions +that are intended for a more automated system. This module is a +language module---a typical checker that uses it looks like this: @schemeblock[ (module checker (lib "checker.ss" "handin-server") @@ -906,115 +913,128 @@ checker that uses it looks like this: ([keys-n-vals code:blank (code:line :key val keys-n-vals)])]{ -Constructs (and provides) an appropriate checker -function, using keywords for features that you want, the body of the -checker can contain arbitrary code, using all utilities from -@schememodname[handin-server/utils], as well as additional ones (see below).} +Constructs (and provides) an appropriate checker function, using +keywords for features that you want, the body of the checker can +contain arbitrary code, using all utilities from +@schememodname[handin-server/utils], as well as additional ones (see +below).} Keywords for configuring @scheme[check:]: @itemize{ -@item{@indexed-scheme[:users]---specification of users that are acceptable for - submission. Can be either a list of user lists, each representing a known - team, or procedure which will accept a list of users and throw an exception - if they are unacceptable. The default is to accept only single-user - submissions. The @scheme[pairs-or-singles-with-warning] procedure is a - useful value for pair submission where the pairs are unknown.} +@item{@indexed-scheme[:users]---specification of users that are + acceptable for submission. Can be either a list of user lists, each + representing a known team, or procedure which will accept a list of + users and throw an exception if they are unacceptable. The default + is to accept only single-user submissions. The + @scheme[pairs-or-singles-with-warning] procedure is a useful value + for pair submission where the pairs are unknown.} -@item{@indexed-scheme[:eval?]---whether submissions should be evaluated. Defaults to - @scheme[#t]. Note that if it is specified as @scheme[#f], then the checker body - will not be able to run any tests on the code, unless it contains - code that performs some evaluation (e.g., using the facilities of +@item{@indexed-scheme[:eval?]---whether submissions should be + evaluated. Defaults to @scheme[#t]. Note that if it is specified + as @scheme[#f], then the checker body will not be able to run any + tests on the code, unless it contains code that performs some + evaluation (e.g., using the facilities of @schememodname[handin-server/utils]).} -@item{@indexed-scheme[:language]---the language that is used for evaluating - submissions, same as the @scheme[_language] argument for +@item{@indexed-scheme[:language]---the language that is used for + evaluating submissions, same as the @scheme[_language] argument for @scheme[make-evaluator] (see @schememodname[handin-server/sandbox]). - There is no default for this, so it must be set or an error is raised.} + There is no default for this, so it must be set or an error is + raised.} -@item{@indexed-scheme[:teachpacks]---teachpacks for evaluating submissions, - same as the @scheme[_teachpacks] argument for @scheme[make-evaluator] (see - @schememodname[handin-server/sandbox]). This defaults to null---no - teachpacks.} +@item{@indexed-scheme[:teachpacks]---teachpacks for evaluating + submissions, same as the @scheme[_teachpacks] argument for + @scheme[make-evaluator] (see @schememodname[handin-server/sandbox]). + This defaults to null---no teachpacks.} -@item{@indexed-scheme[:create-text?]---if true, then a textual version of the submission - is saved as @filepath{text.scm} in a @filepath{grading} subdirectory (or any suffix - that is specified by @scheme[:output] below, for example @filepath{hw.java} is - converted into a textual @filepath{grading/text.java}). This is intended for +@item{@indexed-scheme[:create-text?]---if true, then a textual version + of the submission is saved as @filepath{text.scm} in a + @filepath{grading} subdirectory (or any suffix that is specified by + @scheme[:output] below, for example @filepath{hw.java} is converted + into a textual @filepath{grading/text.java}). This is intended for printouts and grading, and is in a subdirectory so students will not see it on the status web server. Defaults to @scheme[#t].} -@item{@indexed-scheme[:untabify?]---if true, then tabs are converted to spaces, assuming a - standard tab width of 8 places. This is needed for a correct - computation of line lengths, but note that DrScheme does not insert - tabs in Scheme mode. Defaults to @scheme[#t].} +@item{@indexed-scheme[:untabify?]---if true, then tabs are converted + to spaces, assuming a standard tab width of 8 places. This is + needed for a correct computation of line lengths, but note that + DrScheme does not insert tabs in Scheme mode. Defaults to + @scheme[#t].} -@item{@indexed-scheme[:textualize?]---if true, then all submissions are converted to text, - trying to convert objects like comment boxes and test cases to some - form of text. Defaults to @scheme[#f], meaning that an exception is raised - for submissions that are not all text.} +@item{@indexed-scheme[:textualize?]---if true, then all submissions + are converted to text, trying to convert objects like comment boxes + and test cases to some form of text. Defaults to @scheme[#f], + meaning that an exception is raised for submissions that are not all + text.} -@item{@indexed-scheme[:maxwidth]---a number that specifies maximum line lengths for - submissions (a helpful feature for reading student code). Defaults - to 79. This feature can be disabled if set to @scheme[#f].} +@item{@indexed-scheme[:maxwidth]---a number that specifies maximum + line lengths for submissions (a helpful feature for reading student + code). Defaults to 79. This feature can be disabled if set to + @scheme[#f].} -@item{@indexed-scheme[:output]---the name of the original handin file (unrelated to the - text-converted files). Defaults to @filepath{hw.scm}. (The suffix changes - the defaults of @scheme[:markup-prefix] and @scheme[:prefix-re].) Can be +@item{@indexed-scheme[:output]---the name of the original handin file + (unrelated to the text-converted files). Defaults to + @filepath{hw.scm}. (The suffix changes the defaults of + @scheme[:markup-prefix] and @scheme[:prefix-re].) Can be @scheme[#f] for removing the original file after processing.} -@item{@indexed-scheme[:multi-file]---by default, this is set to @scheme[#f], - which means that only DrScheme is used to send submissions as usual. See - @secref{multi-file} for setting up multi-file submissions.} +@item{@indexed-scheme[:multi-file]---by default, this is set to + @scheme[#f], which means that only DrScheme is used to send + submissions as usual. See @secref{multi-file} for setting up + multi-file submissions.} -@item{@indexed-scheme[:names-checker]---used for multi-file submissions; see - @secref{multi-file} for details.} +@item{@indexed-scheme[:names-checker]---used for multi-file + submissions; see @secref{multi-file} for details.} -@item{@indexed-scheme[:markup-prefix]---used as the prefix for @scheme[:student-lines] and - @scheme[:extra-lines] below. The default is @scheme[";;> "] or @scheme["//> "], depending on - the suffix of @scheme[:output] above. (Note: if you change this, make sure - to change @scheme[:prefix-re] too.)} +@item{@indexed-scheme[:markup-prefix]---used as the prefix for + @scheme[:student-lines] and @scheme[:extra-lines] below. The + default is @scheme[";;> "] or @scheme["//> "], depending on the + suffix of @scheme[:output] above. (Note: if you change this, make + sure to change @scheme[:prefix-re] too.)} -@item{@indexed-scheme[:prefix-re]---used to identify lines with markup (@scheme[";>"] or @scheme["//>"] - etc), so students cannot fool the system by writing marked-up code. - The default is @scheme[";>"] or @scheme["//>"], depending on the suffix of :output - above.} +@item{@indexed-scheme[:prefix-re]---used to identify lines with markup + (@scheme[";>"] or @scheme["//>"] etc), so students cannot fool the + system by writing marked-up code. The default is @scheme[";>"] or + @scheme["//>"], depending on the suffix of :output above.} -@item{@indexed-scheme[:student-line]---when a submission is converted to text, it begins - with lines describing the students that have submitted it; this is - used to specify the format of these lines. It is a string with - holes that that @scheme[user-substs] fills out. The default is - @scheme["Student: {username} ({Full Name} <{Email}>)"], which requires - @scheme["Full Name"] and @scheme["Email"] entries in the server's extra-fields - configuration. These lines are prefixed with @scheme[";;> "] or the prefix - specified by @scheme[:makup-prefix] above.} +@item{@indexed-scheme[:student-line]---when a submission is converted + to text, it begins with lines describing the students that have + submitted it; this is used to specify the format of these lines. It + is a string with holes that that @scheme[user-substs] fills out. + The default is @scheme["Student: {username} ({Full Name} <{Email}>)"], + which requires @scheme["Full Name"] and @scheme["Email"] entries in + the server's extra-fields configuration. These lines are prefixed + with @scheme[";;> "] or the prefix specified by + @scheme[:makup-prefix] above.} -@item{@indexed-scheme[:extra-lines]---a list of lines to add after the student lines, all - with a @scheme[";;> "] or :markup-prefix too. Defaults to a single line: +@item{@indexed-scheme[:extra-lines]---a list of lines to add after the + student lines, all with a @scheme[";;> "] or :markup-prefix too. + Defaults to a single line: @scheme["Maximum points for this assignment: <+100>"]. (Can use @scheme["{submission}"] for the submission directory.) See also @scheme[add-header-line!].} -@item{@indexed-scheme[:user-error-message]---a string that is used to report an error that - occurred during evaluation of the submitted code (not during - additional tests). It can be a plain string which will be used as - the error message, or a string with single a @scheme["~a"] (or @scheme["~e"], @scheme["~s"], - @scheme["~v"]) that will be used as a format string with the actual error - message. The default is @scheme["Error in your code --\n~a"]. Useful - examples of these messages: +@item{@indexed-scheme[:user-error-message]---a string that is used to + report an error that occurred during evaluation of the submitted + code (not during additional tests). It can be a plain string which + will be used as the error message, or a string with single a + @scheme["~a"] (or @scheme["~e"], @scheme["~s"], @scheme["~v"]) that + will be used as a format string with the actual error message. The + default is @scheme["Error in your code --\n~a"]. Useful examples of + these messages: @scheme["There is an error in your program, hit \"Run\" to debug"] - - @scheme["There is an error in your program:\n----\n~a\n----\n - Hit \"Run\" and debug your code."] + + @scheme["There is an error in your program:\n----\n~a\n----\nHit \"Run\" and debug your code."] Alternatively, the value can be a procedure that will be invoked with the error message. The procedure can do anything it wants, and if it does not raise an exception, then the checker will proceed as usual. For example: - -@schemeblock{ + + @schemeblock{ (lambda (msg) (add-header-line! "Erroneous submission!") (add-header-line! (format " --> ~a" msg)) @@ -1031,67 +1051,68 @@ Keywords for configuring @scheme[check:]: (Note that if you do this, then additional tests should be adjusted to not raise an exception too.)} -@item{@indexed-scheme[:value-printer]---if specified, this will be used for - @scheme[current-value-printer].} +@item{@indexed-scheme[:value-printer]---if specified, this will be + used for @scheme[current-value-printer].} @item{@indexed-scheme[:coverage?]---collect coverage information when - evaluating the submission. This will cause an error if some input is not - covered. This check happens after checker tests are run, but the information - is collected and stored before, so checker tests do not change the result. - Also, you can use the @scheme[!all-covered] procedure in the checker before other - tests, if you want that feedback earlier.}} + evaluating the submission. This will cause an error if some input + is not covered. This check happens after checker tests are run, but + the information is collected and stored before, so checker tests do + not change the result. Also, you can use the @scheme[!all-covered] + procedure in the checker before other tests, if you want that + feedback earlier.}} -Within the body of @scheme[check:], @scheme[users] and @scheme[submission] will be bound to -the checker arguments---a (sorted) list of usernames and the -submission as a byte string. In addition to the functionality below, -you can use @scheme[((submission-eval) expr)] to evaluate expressions in the -submitted code context, and you can use @scheme[(with-submission-bindings (id -...) body ...)] to evaluate the body when @scheme[id]'s are bound to their -values from the submission code. -} +Within the body of @scheme[check:], @scheme[users] and +@scheme[submission] will be bound to the checker arguments---a +(sorted) list of usernames and the submission as a byte string. In +addition to the functionality below, you can use +@scheme[((submission-eval) expr)] to evaluate expressions in the +submitted code context, and you can use +@scheme[(with-submission-bindings (id ...) body ...)] to evaluate the +body when @scheme[id]'s are bound to their values from the submission +code.} -@deftogether[( -@defform[(pre: body ...)] -@defform[(post: body ...)] -)]{ +@deftogether[(@defform[(pre: body ...)] + @defform[(post: body ...)])]{ These two macros define a pre- and a post-checker. In their bodies, - @scheme[_users] and @scheme[_submission] are bound as in @scheme[check:], but - there is nothing else special about these. See the description of the - @scheme[pre-checker] and @scheme[post-checker] values for what can be done - with these, and note that the check for valid users is always first. An - example for a sophisticated @scheme[post:] block is below---it will first disable - timeouts for this session, then it will send a email with a submission - receipt, with CC to the TA (assuming a single TA), and pop-up a message - telling the student about it: + @scheme[_users] and @scheme[_submission] are bound as in + @scheme[check:], but there is nothing else special about these. See + the description of the @scheme[pre-checker] and + @scheme[post-checker] values for what can be done with these, and + note that the check for valid users is always first. An example for + a sophisticated @scheme[post:] block is below---it will first + disable timeouts for this session, then it will send a email with a + submission receipt, with CC to the TA (assuming a single TA), and + pop-up a message telling the student about it: -@schemeblock[ - (require (lib "sendmail.ss" "net")) - (post: - (define info - (format "hw.scm: ~a ~a" - (file-size "hw.scm") - (file-or-directory-modify-seconds "hw.scm"))) - (timeout-control 'disable) - (log-line "Sending a receipt: ~a" info) - (send-mail-message - "course-staff@university.edu" - "Submission Receipt" - (map (lambda (user) (user-substs user "{Full Name} <{Email}>")) - users) - (list (user-substs (car users) "{TA Name} <{TA Email}>")) - null - `("Your submission was received" ,info)) - (message (string-append - "Your submission was successfully saved." - " You will get an email receipt within 30 minutes;" - " if not, please contact the course staff.") - '(ok)))]} + @schemeblock[ + (require (lib "sendmail.ss" "net")) + (post: + (define info + (format "hw.scm: ~a ~a" + (file-size "hw.scm") + (file-or-directory-modify-seconds "hw.scm"))) + (timeout-control 'disable) + (log-line "Sending a receipt: ~a" info) + (send-mail-message + "course-staff@university.edu" + "Submission Receipt" + (map (lambda (user) (user-substs user "{Full Name} <{Email}>")) + users) + (list (user-substs (car users) "{TA Name} <{TA Email}>")) + null + `("Your submission was received" ,info)) + (message (string-append + "Your submission was successfully saved." + " You will get an email receipt within 30 minutes;" + " if not, please contact the course staff.") + '(ok)))]} @defparam[submission-eval eval (any/c . -> . any)]{ - Holds an evaluation procedure for evaluating code - in the submission context.} + Holds an evaluation procedure for evaluating code in the submission + context.} @comment{is this always just a list of strings?} @defproc[(user-data [user string?]) (listof string?)]{ @@ -1102,101 +1123,109 @@ values from the submission code. @defproc[(user-substs [user string?] [fmt string?]) string]{ - Uses the mappings in @scheme[user-data] to substitute user information for - substrings of the form ``@tt{{some-field-name}}'' in @scheme[fmt]. This - procedure signals an error if a field name is missing in the user data. Also, - ``@tt{{username}}'' will always be replaced by the username and - ``@tt{{submission}}'' by the current submission directory. + Uses the mappings in @scheme[user-data] to substitute user + information for substrings of the form ``@tt{{some-field-name}}'' in + @scheme[fmt]. This procedure signals an error if a field name is + missing in the user data. Also, ``@tt{{username}}'' will always be + replaced by the username and ``@tt{{submission}}'' by the current + submission directory. - This is used to process the @scheme[:student-line] value in the checker, - but it is provided for additional uses. See the above sample code - for @scheme[post:] for using this procedure.} + This is used to process the @scheme[:student-line] value in the + checker, but it is provided for additional uses. See the above + sample code for @scheme[post:] for using this procedure.} -@defproc[(pairs-or-singles-with-warning [users (listof string?)]) any]{ +@defproc[(pairs-or-singles-with-warning [users (listof string?)]) + any]{ - Intended for use as the @scheme[:users] entry in a checker. - It will do nothing if there are two users, and throw an error if there are - more. If there is a single user, then the user will be asked to verify a - single submission. If the student cancels, then an exception is raised so the - submission directory is retracted. If the student approves this, the - question is not repeated (this is marked by creating a directory with a known - name). This is useful for cases where you want to allow free pair - submissions---students will often try to submit their work alone, and later - on re-submit with a partner.} + Intended for use as the @scheme[:users] entry in a checker. It will + do nothing if there are two users, and throw an error if there are + more. If there is a single user, then the user will be asked to + verify a single submission. If the student cancels, then an + exception is raised so the submission directory is retracted. If + the student approves this, the question is not repeated (this is + marked by creating a directory with a known name). This is useful + for cases where you want to allow free pair submissions---students + will often try to submit their work alone, and later on re-submit + with a partner.} -@defproc[(teams-in-file [team-file path-string?]) ((listof string?) . -> . void?)]{ +@defproc[(teams-in-file [team-file path-string?]) + ((listof string?) . -> . void?)]{ - @italic{Returns} a procedure that can be used for the :users - entry in a checker. The team file (relative from the server's main + @italic{Returns} a procedure that can be used for the :users entry + in a checker. The team file (relative from the server's main directory) is expected to have user entries---a sequence of s-expressions, each one a string or a list of strings. The resulting procedure will allow submission only by teams that are specified in this file. Furthermore, if this file is modified, the new contents will be used immediately, so there is no need to restart the server of you want to change student teams. (But - remember that if you change @scheme[("foo" "bar")] to @scheme[("foo" "baz")], and - there is already a @filepath{bar+foo} submission directory, then the system - will not allow ``@tt{foo}'' to submit with ``@tt{bar}''.)} + remember that if you change @scheme[("foo" "bar")] to + @scheme[("foo" "baz")], and there is already a @filepath{bar+foo} + submission directory, then the system will not allow ``@tt{foo}'' to + submit with ``@tt{bar}''.)} @defproc[(add-header-line! [line string?]) void?]{ - During the checker operation, can be used to add - header lines to the text version of the submitted file (in addition - to the @scheme[:extra-lines] setting). It will not have an effect if + During the checker operation, can be used to add header lines to the + text version of the submitted file (in addition to the + @scheme[:extra-lines] setting). It will not have an effect if @scheme[:create-text?] is false.} -@defproc[(procedure/arity? [proc procedure?] [arity number?]) boolean?]{ - Returns @scheme[#t] if @scheme[proc] is a procedure that accepts @scheme[arity] - arguments.} +@defproc[(procedure/arity? [proc procedure?] [arity number?]) + boolean?]{ + Returns @scheme[#t] if @scheme[proc] is a procedure that accepts + @scheme[arity] arguments.} @defform[(!defined id ...)]{ - Checks that the given identifiers are defined in the - (evaluated) submission, and throws an error otherwise.} + Checks that the given identifiers are defined in the (evaluated) + submission, and throws an error otherwise.} -@defform[(!procedure id arity)] +@defform[(!procedure id arity)]{ - Checks that @scheme[id] is defined, and is bound to a procedure. + Checks that @scheme[id] is defined, and is bound to a procedure.} @defform[(!procedure* expr arity)]{ - Similar to @scheme[!procedure] but omits the defined - check, making it usable with any expression, which is then evaluated in the + Similar to @scheme[!procedure] but omits the defined check, making + it usable with any expression, which is then evaluated in the submission context.} -@deftogether[( -@defform[(!integer id)] -@defform[(!integer* expr)] -)]{ +@deftogether[(@defform[(!integer id)] + @defform[(!integer* expr)])]{ - Similar to @scheme[!procedure] and @scheme[!procedure*] for integers.} + Similar to @scheme[!procedure] and @scheme[!procedure*] for + integers.} @defform*[((!test expr) (!test expr result) (!test expr result equal?))]{ The first form checks that the given expression evaluates to a - non-@scheme[#f] value in the submission context, throwing an error otherwise. - The second form compares the result of evaluation, requiring it to be equal - to @scheme[result]. The third allows specifying an equality procedure. Note - that the @scheme[result] and @scheme[equal?] forms are @italic{not} evaluated - in the submission context. + non-@scheme[#f] value in the submission context, throwing an error + otherwise. The second form compares the result of evaluation, + requiring it to be equal to @scheme[result]. The third allows + specifying an equality procedure. Note that the @scheme[result] and + @scheme[equal?] forms are @italic{not} evaluated in the submission + context.} @defproc*[([(!all-covered) void?] [(!all-covered [proc (string? . -> . any)]) void?])]{ - - When coverage information is enabled (see @scheme[:coverage?] above), checks - the collected coverage information and throws an error with source - information if some code is left uncovered. If @scheme[proc] is provided, it - is applied to a string argument that describes the location of the uncovered - expression (@scheme[":"], @scheme["#"], or - @scheme["(unknown position)"]) instead of throwing an error. The collected - information includes only execution coverage by submission code, excluding - additional checker tests. You do not have to call this explicitly---it is - called at the end of the process automatically when @scheme[:coverage?] is - enabled. It is made available so you can call it earlier (e.g., before - testing) to show clients a coverage error first, or if you want to avoid an - error. For example, you can do this: -@schemeblock[ + When coverage information is enabled (see @scheme[:coverage?] + above), checks the collected coverage information and throws an + error with source information if some code is left uncovered. If + @scheme[proc] is provided, it is applied to a string argument that + describes the location of the uncovered expression + (@scheme[":"], @scheme["#"], or + @scheme["(unknown position)"]) instead of throwing an error. The + collected information includes only execution coverage by submission + code, excluding additional checker tests. You do not have to call + this explicitly---it is called at the end of the process + automatically when @scheme[:coverage?] is enabled. It is made + available so you can call it earlier (e.g., before testing) to show + clients a coverage error first, or if you want to avoid an error. + For example, you can do this: + + @schemeblock[ (!all-covered (lambda (where) (case (message (string-append @@ -1204,63 +1233,64 @@ values from the submission code. " to save this submission with 10% penalty?")) [(yes) (add-header-line! "No full coverage <*90%>") (message "Handin saved with penalty.")] - [else (error "aborting submission")])))] - - } -} + [else (error "aborting submission")])))]} @section[#:tag "multi-file"]{Multiple-File Submissions} By default, the system is set up for submissions of single a single file, straight fom DrScheme using the handin-client. There is some -support for multi-file submissions in @schememodname[handin-server/checker] and in the -handin-client. It is possible to submit multiple files, and have the -system generate a single file that is the concatenation of all -submission files (used only with text files). To set up multi-file -submissions, do the following: +support for multi-file submissions in +@schememodname[handin-server/checker] and in the handin-client. It is +possible to submit multiple files, and have the system generate a +single file that is the concatenation of all submission files (used +only with text files). To set up multi-file submissions, do the +following: @itemize{ -@item{Add a @scheme[:multi-file] keyword in @scheme[check:], and as a value, use the - suffix that should be used for the single concatenated output file.} +@item{Add a @scheme[:multi-file] keyword in @scheme[check:], and as a + value, use the suffix that should be used for the single + concatenated output file.} -@item{You can also add a @scheme[:names-checker] keyword--the value can be a - regexp that all submitted files must follow (e.g., @scheme[".*[.]scm$"]), or a - list of expected file names. Alternatively, it can be a 1-argument - procedure that will receive the (sorted) list of submitted files and - can throw an error if some files are missing or some files are - forbidden.} +@item{You can also add a @scheme[:names-checker] keyword--the value + can be a regexp that all submitted files must follow (e.g., + @scheme[".*[.]scm$"]), or a list of expected file names. + Alternatively, it can be a 1-argument procedure that will receive + the (sorted) list of submitted files and can throw an error if some + files are missing or some files are forbidden.} -@item{In the @filepath{info.ss} file of the handin-client you need to set - @scheme[enable-multifile-handin] to @scheme[#t], and adjust - @scheme[selection-default] to patterns that are common to your course. (It - can be a single pattern, or a list of them.)}} +@item{In the @filepath{info.ss} file of the handin-client you need to + set @scheme[enable-multifile-handin] to @scheme[#t], and adjust + @scheme[selection-default] to patterns that are common to your + course. (It can be a single pattern, or a list of them.)}} -On the server side, each submission is saved in a file called @filepath{raw}, -which contains all submitted files. In the @filepath{grading} directory, you -will get a @filepath{text.} file (@filepath{} is the suffix that is -used as a value for @scheme[:multi-file]) that contains all submitted files with clear -separators. A possible confusion is that every submission is a complete set of -files that overwrites any existing submission, whereas students may think that -the server accumulates incoming files. To avoid such confusion, when a -submission arrives an there is already an existing previous submission, the -contents is compared, and if there are files that existed in the old submission -but not in the new ones, the student will see a warning pop-up that allows -aborting the submission. +On the server side, each submission is saved in a file called +@filepath{raw}, which contains all submitted files. In the +@filepath{grading} directory, you will get a @filepath{text.} +file (@filepath{} is the suffix that is used as a value for +@scheme[:multi-file]) that contains all submitted files with clear +separators. A possible confusion is that every submission is a +complete set of files that overwrites any existing submission, whereas +students may think that the server accumulates incoming files. To +avoid such confusion, when a submission arrives an there is already an +existing previous submission, the contents is compared, and if there +are files that existed in the old submission but not in the new ones, +the student will see a warning pop-up that allows aborting the +submission. On the client side, students will have an additional file-menu entry for submitting multiple files, which pops up a dialog that can be used to submit multiple files. In this dialog, students choose their working directory, and the @scheme[selection-default] entry from the -@filepath{handin-client/info.ss} file specifies a few patterns that can be used -to automatically select files. The dialog provides all handin-related -functionality that is available in DrScheme. For further convenience, -it can be used as a standalone application: in the account management -dialog, the @onscreen{Un/Install} tab has a button that will ask for a -directory where it will create an executable for the multi-file -submission utility---the resulting executable can be used outside of -DrScheme (but PLT Scheme is still required, so it cannot be -uninstalled). +@filepath{handin-client/info.ss} file specifies a few patterns that +can be used to automatically select files. The dialog provides all +handin-related functionality that is available in DrScheme. For +further convenience, it can be used as a standalone application: in +the account management dialog, the @onscreen{Un/Install} tab has a +button that will ask for a directory where it will create an +executable for the multi-file submission utility---the resulting +executable can be used outside of DrScheme (but PLT Scheme is still +required, so it cannot be uninstalled). @section{Auto-Updater} @@ -1271,24 +1301,26 @@ additional functionality (collections, teachpacks, language-levels etc), and this functionality can change (or expected to change, for example, distributing per-homework teachpacks). -To enable this, uncomment the relevant part of the @filepath{info.ss} file in -the client code. It has the following three keys: +To enable this, uncomment the relevant part of the @filepath{info.ss} +file in the client code. It has the following three keys: @indexed-scheme[enable-auto-update] that turns this facility on, and -@indexed-scheme[version-filename] and @indexed-scheme[package-filename] which -are the expected file names of the version file and the @filepath{.plt} file -relative to the course web address (the value of the @scheme[web-address] key). -Also, include in your client collection a @filepath{version} file that contains -a single number that is its version. Use a big integer that holds the time of this -collection in a @tt{YYYYMMDDHHMM} format. +@indexed-scheme[version-filename] and +@indexed-scheme[package-filename] which are the expected file names of +the version file and the @filepath{.plt} file relative to the course +web address (the value of the @scheme[web-address] key). Also, +include in your client collection a @filepath{version} file that +contains a single number that is its version. Use a big integer that +holds the time of this collection in a @tt{YYYYMMDDHHMM} format. When students install the client, every time DrScheme starts, it will automatically check the version from the web page (as specified by the -@scheme[web-address] and @scheme[version-filename] keys), and if that contains -a bigger number, it will offer the students to download and install the new -version. So, every time you want to distribute a new version, you build a new -@filepath{.plt} file that contains a new version file, then copy these version -and @filepath{.plt} files to your web page, and students will be notified -automatically. Note: to get this to work, you need to create your -@filepath{.plt} file using mzc's @DFlag{--replace} flag, so it will be possible to -overwrite existing files. (Also note that there is no way to delete files when +@scheme[web-address] and @scheme[version-filename] keys), and if that +contains a bigger number, it will offer the students to download and +install the new version. So, every time you want to distribute a new +version, you build a new @filepath{.plt} file that contains a new +version file, then copy these version and @filepath{.plt} files to +your web page, and students will be notified automatically. Note: to +get this to work, you need to create your @filepath{.plt} file using +mzc's @DFlag{--replace} flag, so it will be possible to overwrite +existing files. (Also note that there is no way to delete files when a new @filepath{.plt} is installed.)