codingame_tools.language.toolchain¶
toolchain
¶
Composable multi-language toolchain images.
One image serves several languages, built from dependency-ordered fragments -- see
fragment for the model and why it exists, and subsystems for the shared toolchains
languages install onto.
ENV_DIR
module-attribute
¶
ENV_DIR = '/opt/cg/env.d'
Where activation scripts live inside the image--see the module docstring.
Under /opt rather than /etc/profile.d deliberately: these are not meant to apply to every
shell. Sourcing them all would defeat the point, since two of them may set JAVA_HOME
incompatibly. They are opt-in, one at a time, by the command that needs one.
BASE_IMAGE
module-attribute
¶
BASE_IMAGE = 'debian:bookworm-slim'
The one neutral base every fragment installs onto.
Deliberately not a language image such as gcc:14. A per-language base cannot compose--two of
them cannot both be FROM--and it hides the toolchain version in an image tag, which is exactly
how the C++ build came to be silently two major gcc releases ahead of CodinGame's.
PREAMBLE
module-attribute
¶
PREAMBLE = '# Common to every cg toolchain image, whatever languages it carries.\nENV DEBIAN_FRONTEND=noninteractive\nRUN apt-get update \\\n && apt-get install -y --no-install-recommends ca-certificates coreutils \\\n && rm -rf /var/lib/apt/lists/*\nRUN mkdir -p /opt/cg/env.d /build\nWORKDIR /build\n'
Statements shared by every image, before any fragment.
coreutils supplies the timeout and stdbuf the run and debug paths depend on (already present
on Debian; named so a swapped base still gets them).
SUBSYSTEMS
module-attribute
¶
SUBSYSTEMS = (_GCC11, _PYTHON311, _JDK21, _DOTNET8, _NODE20)
Every subsystem cg ships. Collected by codingame_tools.language.toolchain.registry.
CgToolchainError
¶
Bases: Exception
Raised for an unresolvable fragment set--an unknown slug, or a dependency cycle.
CgToolchainFragment
dataclass
¶
CgToolchainFragment(slug, version, depends_on=(), dockerfile='', env_script='')
One composable piece of a toolchain image.
slug
instance-attribute
¶
slug
Stable identifier, used in dependency edges, in the generated header, and as the activation script's filename. Lowercase, no spaces--it appears in shell and Dockerfile contexts.
version
instance-attribute
¶
version
Bumped whenever dockerfile or env_script changes, so an unmodified generated Dockerfile
can be detected as stale and regenerated. Deliberately per fragment rather than one global
template version: changing the Rust fragment shouldn't invalidate a C++-only image.
depends_on
class-attribute
instance-attribute
¶
depends_on = ()
Slugs that must be installed before this one. The mechanism that lets several languages share
a toolchain (C and C++ -> gcc11) and lets conflicting ones coexist (java -> jdk21
while scala -> jvm8).
dockerfile
class-attribute
instance-attribute
¶
dockerfile = ''
Statements inserted verbatim. Legitimately empty: a language whose toolchain is entirely supplied by a subsystem contributes only its dependency edge and its activation script, and emits nothing here. An empty fragment produces no Dockerfile section and so no extra layer.
env_script
class-attribute
instance-attribute
¶
env_script = ''
Body of /opt/cg/env.d/<slug>.sh, if this fragment needs one. The composer prepends the
. <dep>.sh lines itself, so a fragment only writes its own exports.
render_dockerfile
¶
render_dockerfile(fragments, *, base_image, preamble='')
The full cg-owned Dockerfile for fragments, already in install order.
Renders cg's own base.dockerfile content. Distinct from
codingame_tools.language._docker.compose_dockerfile, which composes that file on disk with
the user's custom.dockerfile -- generation versus merging.
The header is machine-readable in the same spirit as the single-language one it replaces: it records every fragment and its version, so a generated file can be recognized as cg's, checked for staleness, and told apart from one the user has edited.
Parameters:
-
fragments(list[CgToolchainFragment]) –In install order, as returned by
resolve_fragments. -
base_image(str) –Value for the
CG_BASE_IMAGEbuild arg--one pinned neutral base that every fragment installs onto, rather than a per-language base image. -
preamble(str, default:'') –Statements common to every image, inserted before any fragment.
Source code in codingame_tools/language/toolchain/fragment.py
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | |
resolve_fragments
¶
resolve_fragments(requested, registry)
Every fragment needed for requested, dependencies first, in deterministic order.
Ties are broken by slug so the result is stable across runs and, more importantly, so a subset's order is a prefix of a superset's--see the module docstring on layer sharing.
Parameters:
-
requested(Iterable[str]) –Slugs asked for, in any order. Duplicates are harmless.
-
registry(Mapping[str, CgToolchainFragment]) –Every known fragment, keyed by slug.
Returns:
-
list[CgToolchainFragment]–Fragments in install order.
Raises:
-
CgToolchainError–on an unknown slug or a dependency cycle.
Source code in codingame_tools/language/toolchain/fragment.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |
all_fragments
¶
all_fragments()
Every fragment cg knows, keyed by slug.
Built fresh rather than cached: the language registry is itself lazily discovered, and a stale copy here would be a second source of truth for something that already has one.
Source code in codingame_tools/language/toolchain/registry.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
default_languages
¶
default_languages()
Every language cg can put in an image -- the default contents of the toolchain.
Derived, never a hardcoded list. A language is in the default set exactly when it declares
a toolchain_fragment, so adding one is a single-module change and the two can never drift
apart.
The default is everything rather than a minimal subset because the whole set costs about
1.9 GB: the languages that dominate (JDK, .NET, Node) share one Debian base instead of each
dragging its own, so trimming saves far less than the confusion of having to choose. Subset
builds remain available for anyone who wants one -- see CgSettingsData.toolchain_languages
-- they are just not something a user should have to think about.
Source code in codingame_tools/language/toolchain/registry.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | |
fragments_for_languages
¶
fragments_for_languages(languages)
Everything needed to build an image for languages, in install order.
The whole pipeline in one call: names to slugs, slugs to fragments, dependencies pulled in and ordered deterministically.
Source code in codingame_tools/language/toolchain/registry.py
100 101 102 103 104 105 | |
resolve_language_slugs
¶
resolve_language_slugs(languages)
Fragment slugs for CodinGame language names, e.g. ["C++"] -> ["cpp"].
Raises:
-
CgToolchainError–if a name isn't a known language, or is one with no container support -- distinguished, because "you typed it wrong" and "cg can't containerize that yet" need different fixes.
Source code in codingame_tools/language/toolchain/registry.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | |