replit / polygott

Base Docker image for the Repl.it evaluation server
https://replit.com
MIT License
395 stars 103 forks source link

Polygott

Warning: This repository is now obsolete. Replit is no longer developing Polygott and is fully betting on nix to expose tools and languages on Repls. This repository will still exist for archiving and historical purposes.


Overview

Replit.com allows you to quickly get started with any programming language online. In order to provide this capability, our evaluation server uses Docker with the buildx CLI plugin 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.

Because of the fact that building a monolithic image is unwieldy and takes too much time, the build itself is made of a directed graph of intermediate nodes, where each language is a node, and they all get stitched together at the end to build the final combined image.

Build and run

You can build either the entire image, a version that has a bundle of languages, and a version that is limited to a single language. The second one is used for CI, and 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-ci      Build Docker image with all languages needed for CI
  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 and make run-LANG targets 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 build command which is run by the Makefile, and run it yourself with the --no-cache flag.

The CI requires having up-to-date generated artifacts (the files in out/) committed to ensure a consistent Docker build environment. These will be refreshed by running the tests, or by running make -B build/stamps/out).

Language configuration

Each supported language has a TOML file in the languages subdirectory. The meaningful keys are as follows:

Mandatory

Optional

Build process

Usage

Aside from all the language executables (python3, ruby, rust, etc.), there are several additional scripts available within the Docker image. They are documented below.

polygott-self-test

Run the tests defined in each language's configuration file, as in make test or make test-LANG. Always run all the tests, but if one of them fails, exit with a non-zero return code.

polygott-survey

Run the versionCommand specified for every language, and output the results in tabular format to stdout.

polygott-lang-setup [-l LANG]

Copy the contents of /opt/homes/LANG/ to /home/runner/, and run the runtimeSetup commands for it, if any were provided. LANG defaults to the output of detect-language.

detect-language

Try to identify the language used by the project in the current directory. This first checks if the entrypoint file exists for any language, and then checks if a file with any of the registered extensions exists for a language. If multiple languages match in either of those two phases, then the popularity of the two languages is used to resolve ties.

Output the language name to stdout if one is detected, otherwise do nothing.

run-project [-s] [-b] [-l LANG]

Execute the compile and run commands on the entrypoint file in the current directory. LANG defaults to the output of detect-language. If -s is passed, then the entrypoint file is written with the contents of stdin. If -b is passed, then some special logic is used instead of the compile and run commands; see the source for details.

run-language-server [-l LANG]

Run the languageServer command configured in the language's configuration file. LANG defaults to the output of detect-language.

Deployment

When a commit is merged to master, CircleCI automatically builds Polygott and pushes the image to Docker Hub. A Replit engineer has to then push the new Polygott to production.