-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathdevcontainer.texi
More file actions
353 lines (266 loc) · 12.9 KB
/
Copy pathdevcontainer.texi
File metadata and controls
353 lines (266 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
98
99
100
101
102
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
\input texinfo @c -*- texinfo -*-
@c %**start of header
@settitle User Manual for devcontainer.el
@setfilename devcontainer.info
@documentencoding UTF-8
@documentlanguage en
@c %**end of header
@copying
@quotation
Copyright (C) 2025 - 2026 Johannes Mueller <github@@johannes-mueller.org>
You can redistribute this document and/or modify it under the terms
of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any
later version.
This document is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE@. See the GNU
General Public License for more details.
@end quotation
@end copying
@dircategory Emacs
@direntry
* devcontainer: (devcontainer). Working on projects that use a devcontainer
@end direntry
@finalout
@titlepage
@title devcontainer.el User Manual
@subtitle Rudimentary devcontainer support for Emacs
@author Johannes Mueller
@page
@insertcopying
@end titlepage
@contents
@node Top
@top The package devcontainer.el
Rudimentary devcontainer support for Emacs
This package lets you handle i.e.@ start, restart devcontainers of your
projects and forwards all your @command{compile} commands into the
devcontainer by advising @command{compilation-start}. So as long you use
@command{compile} to build, test and run (parts of your) software, all will
be executed inside the devcontainer.
@quotation
Please consider this package experimental as long as there is no release yet.
There might be breaking changes like changing function and variable names out
of the blue. So please consider checking the git history when updating.
@end quotation
Source code: @uref{https://github.com/johannes-mueller/devcontainer.el}
@menu
* Usage::
* Configuration::
@end menu
@chapter Introduction
@section What are devcontainers?
@uref{https://containers.dev/,Devcontainers} become increasingly popular
in modern software development. The idea is to put everything the
software you are developing needs in order to run into a docker
container or a stack of @uref{https://docker.com,docker} containers.
Then all your local builds and testing is performed inside that
container. So your development basically takes place inside the docker
container -- hence the name ``devcontainer''.
The initiative came from the Visual Studio Code community. They actually
run the complete tooling inside the container, even their IDE. The
configuration of the IDE -- i.e.@ which extensions are to be installed
-- is also defined by the definition of the devcontainer.
@section Approach for support in Emacs
While you technically don't need to use devcontainers even though your
team is using them, it is convenient for you also to use devcontainers
at least to some degree. Of course, you won't install an Emacs instance
inside the devcontainer, but it is really helpful for you to manage
devcontainers from within Emacs and interact with the installation of
your software inside of it. That's where the @code{devcontainer} package
comes in.
@code{devcontainer} provides a set Emacs commands to build, launch,
stop, erase and rebuild the devcontainer according to its definition in
the project's repo. In order for you to run and test your software
inside the devcontainer, @command{devcontainer-mode} advises Emacs'
@command{compilation-start} function to prepend
@code{devcontainer exec --workspace-folder .} to your compilation
command and thus runs the compilation command inside the container.
Usually you would mount your local working directory into your
devcontainer. Then you edit files just like without using devcontainer.
Then, launching any kind of @command{compile} command, it is actually
performed inside your devcontainer.
@node Usage
@chapter Setup and usage
@section Setup
You need to have the @uref{https://github.com/devcontainers/cli,devcontainers/cli}
command line tool installed into your execution path. For that you need a
working node/npm setup. Then you can install the tool with
@example
npm install -g @@devcontainers/cli
@end example
Of course you also need a working @uref{https://docker.com,docker} installation
and probably also @uref{https://docs.docker.com/compose/,docker compose}.
Alternatively you can also use @uref{https://podman.io/,podman}.
@section Usage
@subsection Activate @command{devcontainer-mode}
In order to use devcontainers you should activate @command{devcontainer-mode}.
It is a global major mode that recognizes if a project needs or supports
devcontainers and then automatically forwards commands to the devcontainer.
@subsection Commands
There are couple of commands to start and stop devcontainers. They are pretty
straight forward.
@subsubsection Launching the devcontainer @command{devcontainer-up}
@command{devcontainer-up} starts the devcontainer of the current
project. Usually you would use it to start the devcontainer, when you start
working on a project after relaunching your computer. You'll get a
notification in the echo area as soon as the container is launched. In order
to examine failures you can examine the buffer @code{*devcontainer startup*}.
If the startup of the container needs secrets to access resources like package
dependencies you can define a file where these secrets are stored in
@var{devcontainer-startup-secrets-file}.
If there is no image for the container available on your system it is built
according the the project's devcontainer definition. Note that this command
does not rebuild the container. Nothing will be updated. The software state
will be the same as when the container has been built lastly.
@subsubsection Restarting the container
@command{devcontainer-restart} stops and restart the devcontainer of the
current project without rebuilding it. There is actually one rare use case and
that is when the container reached a state which can only or easiest be reset
by a reastart.
@command{devcontainer-rebuild-and-restart} stops the current project's
devcontainer, deletes its docker images and rebuilds it. This is useful, when
you for example changed the @code{Dockerfile} of your devcontainer. However,
it also does not rebuild or update the containers that are defined as other
services in @code{docker-compose.yml} in the project's devcontainer definition.
@subsubsection Starting programs inside the devcontainer
@command{devcontainer-execute-command} executes an arbitrary command
inside the devcontainer. This is meant for long running, non-interactive
commands like running a server or some kind of batch job. When called
interactively it prompts for a command.
@command{devcontainer-execute-command-interactive} execute an arbitrary command
inside the devcontainer interactively. This is meant for interactive commands
that you would run in a terminal. When called interactively it prompts for a
command.
@command{devcontainer-term} provides a terminal for a shell inside the
container. By default it tries to launch the @code{bash} shell. You can
customize that by the @var{devcontainer-term-shell}. If you experience wired
control sequences in your terminal you might want to adjust the @code{TERM}
variable inside the container using
@lisp
(setq devcontainer-term-environment '(("TERM" . "xterm-256color")))
@end lisp
@subsection Forwarding commands that are not using @command{compile}
If you need to forward some process call into the devcontainer which is
not done by the @command{compile} command of Emacs, you can use
@command{devcontainer-advise-command} to prepend the
@code{devcontainer exec} call in front of your command. If you are not
sure if @command{devcontainer} is always available you can use the
following call, which modifies your command if @command{devcontainer} is
available and if the command modification is advisable.
@lisp
(funcall (or (symbol-function 'devcontainer-advise-command) #'identity) command)
@end lisp
@subsection Using TRAMP
An alternative way of using the package is to edit the files inside the
container itself using Emacs' builtin
@uref{https://www.gnu.org/software/tramp/,TRAMP} facility. There are
pros and cons to it. In order to use it, you can let
@command{devcontainer-mode} deactivated and use the function
@command{devcontainer-tramp-dired} to open a @command{dired} window inside the
container. Then you can open files of your project inside the container.
If @command{devcontainer-mode} is activated it refrains from advising
@command{compile} functions, if the current buffer is a file inside the
devcontainer.
@subsection Customizations of the devcontainer
Devcontainers can demand customizations to the user's IDE. That is useful to
ensure that all the IDEs of all the teams members are aligned. Whereas in the
VSCode world you can also request extension packages to be installed when
working on the devcontainer driven project, this Emacs package only allows you
to set Emacs variables and call Emacs functions when opening a file that
belongs to a devcontainer driven project.
Customizations are defined in the @code{customization} section of
@code{devcontainer.json} file. For every IDE supporting devcontainers can
there can be a subsection. To set variables for buffers of the project you can
use the @code{emacs} subsection. In order to set the variable
@var{fill-column} you can use the following example.
@verbatim
{
...
"customizations": {
"emacs": {
"fill-column": 79
}
}
}
@end verbatim
Also mode specific settings are possible. The following example sets
@code{fill-column} to 79 for @code{text-mode}, to 88 for @code{python-mode}
and to 80 for all other modes.
@verbatim
{
...
"customizations": {
"emacs": {
"modes": {
"text-mode": {
"fill-column": 79
},
"python-mode": {
"fill-column": 88
}
},
"fill-column": 80
}
}
}
@end verbatim
Note that derived modes are also affected from those settings if they don't
override it. In the above example the @var{fill-column} is also set to 79 in
@code{markdown-mode} as @code{markdown-mode} is a derived mode of
@code{text-mode}.
In order to perform commands as customization you can use lisp commands as
variable name and letting the value @code{null} like so:
@verbatim
{
...
"customizations": {
"emacs": {
"(auto-fill-mode -1)": null
}
}
}
@end verbatim
So theoretically you could perform complicated lisp code there and even install
packages. However it is strongly discouraged to do anything more than setting
variables and ensuring that minor modes are switched on or off.
This customization mechanism in principle allows authors of the project to
perform any lisp code on you Emacs. That is a potential security risk. So you
can decide if you want to trust projects that you work on or not. You can do
that setting @var{devcontainer-apply-customization}.
@node Configuration
@chapter Configuration
The following things are customizable at this point. For a complete list
of configuration options refer to the @command{devcontainer} configuration
group.
@section General configuration and startup
@var{devcontainer-engine} defines the container engine you want to use. The
options are either @code{'docker} (default) or @code{'podman}.
@var{devcontainer-startup-secrets-file} defines the file that is passed to the
@command{devcontainer} command as @code{--secrets-file} option. It can be used
to inject environment variable into the built/startup process of the container
without putting them into the container definition. Thus secrets like tokens
to access resources like package dependencies don't need to be put into the
code base.
@var{devcontainer-apply-customization} defines whether to apply the
customization defined for Emacs in @code{devcontainer.json}. By default
(@code{'ask}) it will ask you if you want to apply it. Other options are
@code{'always} and @code{'never}. For trusted projects you can set it project
local in @code{.dir-locals.el}.
@var{devcontainer-post-startup-hook} is a hook variable that can provide
functions that are called after the container has been started. They take a
couple of arguments. It receives information on the devcontainer as parameters.
See the functions' documentation for details.
One example use case is to hook in the function
@var{devcontainer-tramp-dired} to open a @command{dired} window inside the
container right after the start of the container.
@section Command execution inside the container
@var{devcontainer-execute-outside-container}. Maybe you don't want to execute
all programs that Emacs launches by the @command{compile} command insider the
container. For example programs like @command{grep} are preferably launched
outside the container. You can set list of programs, not to be executed inside
the container but on the host system.
There are the customization variables @var{devcontainer-term-command},
@var{devcontainer-term-shell} and @var{devcontainer-term-environment}
to customize the terminal launched by @command{devcontainer-term}.