or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-commands.mdconfiguration.mdenvironment.mdhooks-plugins.mdindex.mdtask-execution.mdutilities.md

environment.mddocs/

0

# Environment Management

1

2

Template rendering system using Jinja2 for generating Docker Compose configurations, Kubernetes manifests, and application settings. The environment system handles template processing, file generation, and configuration deployment across different execution contexts.

3

4

## Capabilities

5

6

### Template Rendering

7

8

Process Jinja2 templates with configuration data and custom filters to generate deployment files.

9

10

```python { .api }

11

def render_file(config: Config, *path: str) -> Union[str, bytes]:

12

"""

13

Render a template file with configuration data.

14

15

Args:

16

config (Config): Configuration dictionary for template variables

17

*path (str): Path components to the template file

18

19

Returns:

20

Union[str, bytes]: Rendered template content (bytes for binary files)

21

"""

22

23

def render_str(config: Config, text: str) -> str:

24

"""

25

Render a template string with configuration data.

26

27

Args:

28

config (Config): Configuration dictionary for template variables

29

text (str): Template string to render

30

31

Returns:

32

str: Rendered string content

33

"""

34

35

def render_unknown(config: Config, value: Any) -> Any:

36

"""

37

Render unknown value type, handling strings as templates and passing through other types.

38

39

Args:

40

config (Config): Configuration dictionary for template variables

41

value (Any): Value to potentially render

42

43

Returns:

44

Any: Rendered value or original value if not a string

45

"""

46

```

47

48

### File Operations

49

50

Manage environment directories and file operations. File saving is handled internally by the environment rendering system.

51

52

```python { .api }

53

def copy_file(root: str, filename: str) -> None:

54

"""

55

Copy a file from templates to environment directory.

56

57

Args:

58

root (str): Project root directory

59

filename (str): Filename to copy

60

"""

61

62

def delete_file(root: str, filename: str) -> None:

63

"""

64

Delete a file from the environment directory.

65

66

Args:

67

root (str): Project root directory

68

filename (str): Filename to delete

69

"""

70

```

71

72

### Environment Directory Management

73

74

Manage the environment directory structure and lifecycle.

75

76

```python { .api }

77

def create_env_dir(root: str) -> str:

78

"""

79

Create and return the environment directory path.

80

81

Args:

82

root (str): Project root directory

83

84

Returns:

85

str: Path to the environment directory

86

"""

87

88

def clean_env_dir(root: str) -> None:

89

"""

90

Clean the environment directory, removing all generated files.

91

92

Args:

93

root (str): Project root directory

94

"""

95

96

def get_env_path(root: str, *path: str) -> str:

97

"""

98

Get the full path to a file in the environment directory.

99

100

Args:

101

root (str): Project root directory

102

*path (str): Path components within environment directory

103

104

Returns:

105

str: Full path to the file

106

"""

107

```

108

109

### Template System Configuration

110

111

Configure the Jinja2 template environment with custom filters and settings.

112

113

```python { .api }

114

def create_template_environment(config: Config) -> jinja2.Environment:

115

"""

116

Create a Jinja2 environment with Tutor-specific settings and filters.

117

118

Args:

119

config (Config): Configuration dictionary for template context

120

121

Returns:

122

jinja2.Environment: Configured Jinja2 environment

123

"""

124

125

def get_template_filters() -> Dict[str, Callable]:

126

"""

127

Get dictionary of custom Jinja2 filters available in templates.

128

129

Returns:

130

Dict[str, Callable]: Dictionary mapping filter names to functions

131

"""

132

```

133

134

### Patch System

135

136

Apply template patches to customize generated configurations.

137

138

```python { .api }

139

def apply_patches(config: Config, content: str, patches: List[str]) -> str:

140

"""

141

Apply a list of patches to template content.

142

143

Args:

144

config (Config): Configuration dictionary for patch rendering

145

content (str): Original content to patch

146

patches (List[str]): List of patch identifiers

147

148

Returns:

149

str: Content with patches applied

150

"""

151

152

def get_patch_content(config: Config, patch_name: str) -> str:

153

"""

154

Get rendered content for a specific patch.

155

156

Args:

157

config (Config): Configuration dictionary for patch rendering

158

patch_name (str): Name of the patch to retrieve

159

160

Returns:

161

str: Rendered patch content

162

"""

163

```

164

165

## Template Variables

166

167

### Built-in Template Variables

168

169

Variables automatically available in all templates.

170

171

```python { .api }

172

# Configuration access

173

config: Config # Complete configuration dictionary

174

get_config: Callable[[str, Any], Any] # Get config value with default

175

176

# Environment information

177

TUTOR_VERSION: str # Current Tutor version

178

TUTOR_APP: str # Application name (usually "tutor")

179

180

# Docker and deployment

181

DOCKER_REGISTRY: str # Docker registry for images

182

DOCKER_IMAGE_TAG: str # Tag for Docker images

183

184

# Networking

185

HTTP_PORT: int # HTTP port number

186

HTTPS_PORT: int # HTTPS port number

187

188

# Paths

189

TUTOR_ROOT: str # Project root directory

190

ENV_ROOT: str # Environment directory path

191

```

192

193

### Custom Template Filters

194

195

Custom Jinja2 filters available in templates.

196

197

```python { .api }

198

# String processing filters

199

def common_domain(d1: str, d2: str) -> str:

200

"""Find common domain between two domain names."""

201

202

def reverse_host(domain: str) -> str:

203

"""Reverse domain name Java-style (com.example.subdomain)."""

204

205

def random_string(length: int) -> str:

206

"""Generate random string of specified length."""

207

208

# Configuration filters

209

def list_if(services: List[Tuple[str, bool]]) -> str:

210

"""Generate JSON list of enabled services."""

211

212

def walk_templates(obj: Any) -> Any:

213

"""Recursively render templates in nested data structures."""

214

215

# Docker filters

216

def docker_image(service: str) -> str:

217

"""Get Docker image name for a service."""

218

219

def docker_registry_image(image: str) -> str:

220

"""Add registry prefix to image name if configured."""

221

```

222

223

## Template Organization

224

225

### Template Directory Structure

226

227

```python { .api }

228

# Template root directories (configurable via ENV_TEMPLATE_ROOTS filter)

229

TEMPLATES_ROOT: str # Main templates directory

230

PLUGIN_TEMPLATES: List[str] # Plugin template directories

231

232

# Standard template files

233

"docker-compose.yml" # Docker Compose configuration

234

"docker-compose.prod.yml" # Production Docker Compose overrides

235

"docker-compose.dev.yml" # Development Docker Compose overrides

236

"k8s/" # Kubernetes manifests directory

237

"local/" # Local deployment files

238

"dev/" # Development configuration files

239

```

240

241

### Template Targets

242

243

Files generated in the environment directory.

244

245

```python { .api }

246

# Standard targets (configurable via ENV_TEMPLATE_TARGETS filter)

247

("docker-compose.yml", "docker-compose.yml") # Main compose file

248

("docker-compose.prod.yml", "docker-compose.prod.yml") # Production overrides

249

("docker-compose.dev.yml", "docker-compose.dev.yml") # Development overrides

250

("k8s/", "k8s/") # Kubernetes manifests

251

("local/", "local/") # Local deployment files

252

("dev/", "dev/") # Development files

253

```

254

255

## Usage Examples

256

257

### Basic Template Rendering

258

259

```python

260

from tutor import env, config

261

262

# Load configuration

263

config_data = config.load("/path/to/tutor/root")

264

265

# Render a template file

266

content = env.render_file(config_data, "docker-compose.yml")

267

268

# Content is rendered for use by the deployment system

269

print(f"Rendered content length: {len(content)} chars")

270

```

271

272

### Custom Template Processing

273

274

```python

275

from tutor import env, config

276

277

config_data = config.load("/path/to/tutor/root")

278

279

# Render template string

280

template_str = "My platform: {{ PLATFORM_NAME }}"

281

result = env.render_str(config_data, template_str)

282

283

# Process nested templates

284

data = {

285

"name": "{{ PLATFORM_NAME }}",

286

"host": "{{ LMS_HOST }}",

287

"nested": {

288

"port": "{{ HTTP_PORT }}"

289

}

290

}

291

processed = env.render_unknown(config_data, data)

292

```

293

294

### Environment Directory Management

295

296

```python

297

from tutor import env

298

299

root = "/path/to/tutor/root"

300

301

# Create environment directory

302

env_dir = env.create_env_dir(root)

303

304

# Get path to environment file

305

compose_path = env.get_env_path(root, "docker-compose.yml")

306

307

# Clean environment

308

env.clean_env_dir(root)

309

```

310

311

### Working with Patches

312

313

```python

314

from tutor import env, config, hooks

315

316

config_data = config.load("/path/to/tutor/root")

317

318

# Add custom patches via hooks

319

hooks.Filters.ENV_PATCHES.add_items([

320

("docker-compose.yml", "my-custom-patch"),

321

("k8s/ingress.yml", "ingress-customization"),

322

])

323

324

# Render template with patches applied

325

content = env.render_file(config_data, "docker-compose.yml")

326

# Patches are automatically applied during rendering

327

```

328

329

### Custom Template Filters

330

331

```python

332

from tutor import hooks

333

334

# Add custom Jinja2 filter

335

@hooks.Filters.ENV_TEMPLATE_FILTERS.add()

336

def add_custom_filters():

337

def uppercase_filter(text):

338

return text.upper()

339

340

def format_url(host, protocol="https"):

341

return f"{protocol}://{host}"

342

343

return [

344

("uppercase", uppercase_filter),

345

("format_url", format_url),

346

]

347

348

# Use in templates:

349

# {{ PLATFORM_NAME | uppercase }}

350

# {{ LMS_HOST | format_url("http") }}

351

```