Base Docker image for the Repl.it evaluation server
Repl.it allows you to quickly get started with any programming language online. In order to provide this capability, our evaluation server uses Docker to ensure that all these languages are installed with the appropriate environment set up.
We previously used a separate Docker image for each language, but concluded that it was both simpler and more efficient to use a single image which contains all supported languages simultaneously. The code necessary to build this combined image, Polygott, resides in this repository. If you're lost and need some reference, we have a blog where we added elisp.
You can build either the entire image, or a version that is limited to a single language. The latter is recommended when you are adding or modifying support for a particular language, since building the entire image takes an extremely long time. Makefile targets are provided for each of these cases:
% make help usage: make image Build Docker image with all languages make image-LANG Build Docker image with single language LANG make run Build and run image with all languages make run-LANG Build and run image with single language LANG make test Build and test all languages make test-LANG Build and test single language LANG make changed-test Build and test only changed/added languages make help Show this message
As you can see, there is a facility for testing that languages have been installed and configured correctly. This involves running commands which are specified in the languages' configuration files, and checking that the output is as expected. To debug, you can also use the
make run-LANGtargets to launch shells within the images.
You may want to bypass Docker's cache temporarily, for example to debug an intermittent network error while building one of the languages. To do this, identify the
docker buildcommand which is run by the Makefile, and run it yourself with the
entrypoint: The name of the file which will be executed on Repl.it when you press the Run button. This is used in the
detect-languagescript built into the Polygott image: if a file exists with this name, then the project is detected to have this language. (Ties are resolved by
popularity.) It is also used by the
run-projectscript in order to identify the main file of the project.
extensions: List of file extensions (use
".py") which files of this language may have. This is used in the
detect-languagescript built into the Polygott image: if a file exists with one of these extensions, then the project is detected to have this language. (Ties are resolved by
name: The name of the language. The TOML file should then be named
.toml. This is also what you pass to the Makefile's
aliases: List of strings indicating alternate names for the language, in addition to
name. This is used to allow the
run-language-serverscript to accept
-l c++in addition to
-l cpp, among other things.
aptKeys: List of PGP key IDs that must be passed to
apt-keyin order for the custom
aptReposconfigured to be trusted. For example,
aptRepos: List of repository strings that must be passed to
add-apt-repositoryin order for the custom
packagesconfigured to be available. For example,
"deb https://dist.crystal-lang.org/apt crystal main".
command: The full command to compile the
entrypointfile, as a list, including the filename. This is run before the
command: Command to start an LSP language server, as a list. This is used in the
run-language-serverscript built into the Polygott image.
packages: List of additional Ubuntu packages to install for this language. (Packages which are required by all or many languages should be placed instead in
packages.txt.) Check the Ubuntu Bionic package listing to see what your options are.
popularity: Floating-point number indicating how popular the language is. Defaults to
2.0. This is used in the
detect-languagescript built into the Polygott image: if a project is detected as more than one language, the winner is chosen by comparing popularity scores.
run: Required, unless you provide no
testsor you have asked to
skipall of them.
command: The full command to run the
entrypointfile, as a list, including the filename. It is run after the
compilecommand, if one is provided. This is used to run tests.
runtimeSetup: List of shell commands to be run by the
polygott-lang-setupscript built into the Polygott image.
setup: List of shell commands to be run in phase 2 of the build process, as post-install steps.
code: String to write to the
entrypointfile before invoking the
output: String expected to be written to stdout (not stderr) by running the code.
skip: Boolean, optional. If true, then the test is skipped. This allows you to easily "comment out" a test if there is something wrong with the infrastructure.
versionCommand: A command to output the version of the language, as a list of strings. For example,
["kotlin", "-version"]. This is used in the
polygott-surveycommand built into the Polygott image. (If
versionCommandis omitted, some heuristics are used to guess it.)
.ejsfiles in the
gendirectory are transformed into shell scripts using the language configuration via the EJS templating system. This is done by a Node.js script inside the Docker image.
Dockerfileis created from the language configuration files.
packages.txtare installed. In phase 1, APT keys and repositories are configured, and language-specific packages are installed. In phase 2, language-specific
setupcommands are run.
Aside from all the language executables (
rust, etc.), there are several additional scripts available within the Docker image. They are documented below.
Run the tests defined in each language's configuration file, as in
make test-LANG. Always run all the tests, but if one of them fails, exit with a non-zero return code.
versionCommandspecified for every language, and output the results in tabular format to stdout.
polygott-lang-setup [-l LANG]
Copy the contents of
/home/runner/, and run the
runtimeSetupcommands for it, if any were provided.
LANGdefaults to the output of
Try to identify the language used by the project in the current directory. This first checks if the
entrypointfile exists for any language, and then checks if a file with any of the registered
extensionsexists for a language. If multiple languages match in either of those two phases, then the
popularityof the two languages is used to resolve ties.
Output the language name to
stdoutif one is detected, otherwise do nothing.
run-project [-s] [-b] [-l LANG]
runcommands on the
entrypointfile in the current directory.
LANGdefaults to the output of
-sis passed, then the
entrypointfile is written with the contents of stdin. If
-bis passed, then some special logic is used instead of the
runcommands; see the source for details.
run-language-server [-l LANG]
languageServercommand configured in the language's configuration file.
LANGdefaults to the output of
When a commit is merged to
master, CircleCI automatically builds Polygott and pushes the image to Docker Hub. A Repl.it engineer has to then push the new Polygott to production.