hgbook

view es/mq-collab.tex @ 489:b1ae672fd92b

translated a section
author Javier Rojas <jerojasro@devnull.li>
date Wed Jan 07 21:27:01 2009 -0500 (2009-01-07)
parents 039ed6f5935b
children 254888ffaf0a
line source
1 \chapter{Usos avanzados de las Colas de Mercurial}
2 \label{chap:mq-collab}
4 Auunque es fácil aprender los usos más directos de las Colas de
5 Mercurial, tener algo de disciplina junto con algunas de las
6 capacidadees menos usadas de MQ hace posible trabajar en entornos de
7 desarrollo complejos.
9 En este capítulo, usaré como ejemplo una técnica que he usado para
10 administrar el desarrollo de un controlador de dispositivo Infiniband
11 para el kernel de Linux. El controlador en cuestión es grande
12 (al menos en lo que se refiere a controladores), con 25,000 líneas de
13 código esparcidas en 35 ficheros fuente. Es mantenido por un equipo
14 pequeño de desarrolladores.
16 Aunque mucho del material en este capítulo es específico de Linux, los
17 mismos principios aplican a cualquier base de código de la que usted
18 no sea el propietario principal, y sobre la que usted necesita hacer
19 un montón de desarrollo.
21 \section{El problema de múltiples objetivos}
23 El kernel de Linux cambia con rapidez, y nunca ha sido estable
24 internamente; los desarrolladores hacen cambios drásticos entre
25 %TODO no encontré una traducción adecuada para "release". Por eso el
26 %cambio
27 versiones frecuentemente. Esto significa que una versión del
28 controlador que funciona bien con una versión particular del kernel ni
29 siquiera \emph{compilará} correctamente contra, típicamente, cualquier
30 otra versión.
32 Para mantener un controlador, debemos tener en cuenta una buena
33 cantidad de versiones de Linux en mente.
34 \begin{itemize}
35 \item Un objetivo es el árbol de desarrollo principal del kernel de
36 Linux. En este caso el mantenimiento del código es compartido
37 parcialmente por otros desarrolladores en la comunidad del kernel,
38 %TODO drive-by.
39 quienes hacen modificaciones ``de-afán'' al controlador a medida que
40 desarrollan y refinan subsistemas en el kernel.
41 %TODO backport
42 \item También mantenemos algunos ``backports'' para versiones antiguas
43 del kernel de Linux, para dar soporte a las necesidades de los
44 clientes que están corriendo versiones antiguas de Linux que no
45 incorporan nuestros controladores. (Hacer el \emph{backport} de un
46 pedazo de código es modificarlo para que trabaje en una versión
47 de su entorno objetivo anterior a aquella para la cual fue escrito.)
48 \item Finalmente, nosotros liberamos nuestro software de acuerdo a un
49 cronograma que no necesariamente está alineado con el que usan los
50 distribuidores de Linux y los desarrolladores del kernel, así que
51 podemos entregar nuevas características a los clientes sin forzarlos
52 a actualizar kernels completos o distribuciones.
53 \end{itemize}
55 \subsection{Aproximaciones tentadoras que no funcionan adecuadamente}
57 Hay dos maneras estándar de mantener una porción de software que debe
58 funcionar en muchos entornos diferentes.
60 La primera es mantener varias ramas, cada una pensada para un único
61 entorno. El problema de esta aproximación es que usted debe tener una
62 disciplina férrea con el flujo de cambios entre repositorios. Una
63 nueva característica o un arreglo de fallo deben empezar su vida en un
64 repositorio ``prístino'', y luego propagarse a cada repositorio de
65 backport. Los cambios para backports están más limitados respecto a
66 las ramas a las que deberían propagarse; un cambio para backport que
67 es aplicado a una rama en la que no corresponde probablemente hará que
68 el controlador no compile.
70 La segunda es mantener un único árbol de código fuente lleno de
71 declaraciones que activen o desactiven secciones de código dependiendo
72 del entorno objetivo. Ya que estos ``ifdefs'' no están permitidos en
73 el árbol del kernel de Linux, debe seguirse algún proceso manual o
74 automático para eliminarlos y producir un árbol limpio. Una base de
75 código mantenida de esta manera se convierte rápidamente en un nido de
76 ratas de bloques condicionales que son difíciles de entender y
77 mantener.
79 %TODO canónica?
80 Ninguno de estos enfoques es adecuado para situaciones en las que
81 usted no es ``dueño'' de la copia canónica de un árbol de fuentes. En
82 el caso de un controlador de Linux que es distribuido con el kernel
83 estándar, el árbol de Linux contiene la copia del código que será
84 considerada por el mundo como la canónica. La versión oficial de
85 ``mi'' controlador puede ser modificada por gente que no conozco, sin
86 que yo siquiera me entere de ello hasta después de que los cambios
87 aparecen en el árbol de Linus.
89 Estos enfoques tienen la debilidad adicional de dificultar la
90 %TODO upstream. no no es río arriba
91 generación de parches bien formados para enviarlos a la versión
92 oficial.
94 En principio, las Colas de Mercurial parecen ser un buen candidato
95 para administrar un escenario de desarrollo como el de arriba. Aunque
96 este es de hecho el caso, MQ tiene unas cuantas características
97 adicionales que hacen el trabajo más agradable.
99 \section{Aplicar parches condicionalmente mediante guardias}
101 Tal vez la mejor manera de conservar la cordura con tantos entornos
102 objetivo es poder escoger parches específicos para aplicar para cada
103 situación. MQ provee una característica llamada ``guardias''
104 (que se origina del comando \texttt{guards} de Quilt) que hace
105 precisamente ésto. Para empezar, creemos un repositorio sencillo para
106 experimentar.
107 \interaction{mq.guards.init}
108 Esto nos brinda un pequeño repositorio que contiene dos parches que no
109 tienen ninguna dependencia respecto al otro, porque tocan ficheros
110 diferentes.
112 La idea detrás de la aplicación condicional es que usted puede
113 ``etiquetar'' un parche con un \emph{guardia}, que simplemente es una
114 cadena de texto de su elección, y luego decirle a MQ que seleccione
115 guardias específicos para usar cuando aplique parches. MQ entonces
116 aplicará, u omitirá, un parche vigilado, dependiendo de los guardias
117 que usted haya seleccionado.
119 Un parche puede tener una cantidad arbitraria de guardias; cada uno es
120 \emph{positivo} (``aplique el parche si este guardia es
121 seleccionado'') o \emph{negativo} (``omita este parche si este guardia
122 es seleccionado''). Un parche sin guardias siempre es aplicado.
124 \section{Controlling the guards on a patch}
126 The \hgxcmd{mq}{qguard} command lets you determine which guards should
127 apply to a patch, or display the guards that are already in effect.
128 Without any arguments, it displays the guards on the current topmost
129 patch.
130 \interaction{mq.guards.qguard}
131 To set a positive guard on a patch, prefix the name of the guard with
132 a ``\texttt{+}''.
133 \interaction{mq.guards.qguard.pos}
134 To set a negative guard on a patch, prefix the name of the guard with
135 a ``\texttt{-}''.
136 \interaction{mq.guards.qguard.neg}
138 \begin{note}
139 The \hgxcmd{mq}{qguard} command \emph{sets} the guards on a patch; it
140 doesn't \emph{modify} them. What this means is that if you run
141 \hgcmdargs{qguard}{+a +b} on a patch, then \hgcmdargs{qguard}{+c} on
142 the same patch, the \emph{only} guard that will be set on it
143 afterwards is \texttt{+c}.
144 \end{note}
146 Mercurial stores guards in the \sfilename{series} file; the form in
147 which they are stored is easy both to understand and to edit by hand.
148 (In other words, you don't have to use the \hgxcmd{mq}{qguard} command if
149 you don't want to; it's okay to simply edit the \sfilename{series}
150 file.)
151 \interaction{mq.guards.series}
153 \section{Selecting the guards to use}
155 The \hgxcmd{mq}{qselect} command determines which guards are active at a
156 given time. The effect of this is to determine which patches MQ will
157 apply the next time you run \hgxcmd{mq}{qpush}. It has no other effect; in
158 particular, it doesn't do anything to patches that are already
159 applied.
161 With no arguments, the \hgxcmd{mq}{qselect} command lists the guards
162 currently in effect, one per line of output. Each argument is treated
163 as the name of a guard to apply.
164 \interaction{mq.guards.qselect.foo}
165 In case you're interested, the currently selected guards are stored in
166 the \sfilename{guards} file.
167 \interaction{mq.guards.qselect.cat}
168 We can see the effect the selected guards have when we run
169 \hgxcmd{mq}{qpush}.
170 \interaction{mq.guards.qselect.qpush}
172 A guard cannot start with a ``\texttt{+}'' or ``\texttt{-}''
173 character. The name of a guard must not contain white space, but most
174 other characters are acceptable. If you try to use a guard with an
175 invalid name, MQ will complain:
176 \interaction{mq.guards.qselect.error}
177 Changing the selected guards changes the patches that are applied.
178 \interaction{mq.guards.qselect.quux}
179 You can see in the example below that negative guards take precedence
180 over positive guards.
181 \interaction{mq.guards.qselect.foobar}
183 \section{MQ's rules for applying patches}
185 The rules that MQ uses when deciding whether to apply a patch
186 are as follows.
187 \begin{itemize}
188 \item A patch that has no guards is always applied.
189 \item If the patch has any negative guard that matches any currently
190 selected guard, the patch is skipped.
191 \item If the patch has any positive guard that matches any currently
192 selected guard, the patch is applied.
193 \item If the patch has positive or negative guards, but none matches
194 any currently selected guard, the patch is skipped.
195 \end{itemize}
197 \section{Trimming the work environment}
199 In working on the device driver I mentioned earlier, I don't apply the
200 patches to a normal Linux kernel tree. Instead, I use a repository
201 that contains only a snapshot of the source files and headers that are
202 relevant to Infiniband development. This repository is~1\% the size
203 of a kernel repository, so it's easier to work with.
205 I then choose a ``base'' version on top of which the patches are
206 applied. This is a snapshot of the Linux kernel tree as of a revision
207 of my choosing. When I take the snapshot, I record the changeset ID
208 from the kernel repository in the commit message. Since the snapshot
209 preserves the ``shape'' and content of the relevant parts of the
210 kernel tree, I can apply my patches on top of either my tiny
211 repository or a normal kernel tree.
213 Normally, the base tree atop which the patches apply should be a
214 snapshot of a very recent upstream tree. This best facilitates the
215 development of patches that can easily be submitted upstream with few
216 or no modifications.
218 \section{Dividing up the \sfilename{series} file}
220 I categorise the patches in the \sfilename{series} file into a number
221 of logical groups. Each section of like patches begins with a block
222 of comments that describes the purpose of the patches that follow.
224 The sequence of patch groups that I maintain follows. The ordering of
225 these groups is important; I'll describe why after I introduce the
226 groups.
227 \begin{itemize}
228 \item The ``accepted'' group. Patches that the development team has
229 submitted to the maintainer of the Infiniband subsystem, and which
230 he has accepted, but which are not present in the snapshot that the
231 tiny repository is based on. These are ``read only'' patches,
232 present only to transform the tree into a similar state as it is in
233 the upstream maintainer's repository.
234 \item The ``rework'' group. Patches that I have submitted, but that
235 the upstream maintainer has requested modifications to before he
236 will accept them.
237 \item The ``pending'' group. Patches that I have not yet submitted to
238 the upstream maintainer, but which we have finished working on.
239 These will be ``read only'' for a while. If the upstream maintainer
240 accepts them upon submission, I'll move them to the end of the
241 ``accepted'' group. If he requests that I modify any, I'll move
242 them to the beginning of the ``rework'' group.
243 \item The ``in progress'' group. Patches that are actively being
244 developed, and should not be submitted anywhere yet.
245 \item The ``backport'' group. Patches that adapt the source tree to
246 older versions of the kernel tree.
247 \item The ``do not ship'' group. Patches that for some reason should
248 never be submitted upstream. For example, one such patch might
249 change embedded driver identification strings to make it easier to
250 distinguish, in the field, between an out-of-tree version of the
251 driver and a version shipped by a distribution vendor.
252 \end{itemize}
254 Now to return to the reasons for ordering groups of patches in this
255 way. We would like the lowest patches in the stack to be as stable as
256 possible, so that we will not need to rework higher patches due to
257 changes in context. Putting patches that will never be changed first
258 in the \sfilename{series} file serves this purpose.
260 We would also like the patches that we know we'll need to modify to be
261 applied on top of a source tree that resembles the upstream tree as
262 closely as possible. This is why we keep accepted patches around for
263 a while.
265 The ``backport'' and ``do not ship'' patches float at the end of the
266 \sfilename{series} file. The backport patches must be applied on top
267 of all other patches, and the ``do not ship'' patches might as well
268 stay out of harm's way.
270 \section{Maintaining the patch series}
272 In my work, I use a number of guards to control which patches are to
273 be applied.
275 \begin{itemize}
276 \item ``Accepted'' patches are guarded with \texttt{accepted}. I
277 enable this guard most of the time. When I'm applying the patches
278 on top of a tree where the patches are already present, I can turn
279 this patch off, and the patches that follow it will apply cleanly.
280 \item Patches that are ``finished'', but not yet submitted, have no
281 guards. If I'm applying the patch stack to a copy of the upstream
282 tree, I don't need to enable any guards in order to get a reasonably
283 safe source tree.
284 \item Those patches that need reworking before being resubmitted are
285 guarded with \texttt{rework}.
286 \item For those patches that are still under development, I use
287 \texttt{devel}.
288 \item A backport patch may have several guards, one for each version
289 of the kernel to which it applies. For example, a patch that
290 backports a piece of code to~2.6.9 will have a~\texttt{2.6.9} guard.
291 \end{itemize}
292 This variety of guards gives me considerable flexibility in
293 qdetermining what kind of source tree I want to end up with. For most
294 situations, the selection of appropriate guards is automated during
295 the build process, but I can manually tune the guards to use for less
296 common circumstances.
298 \subsection{The art of writing backport patches}
300 Using MQ, writing a backport patch is a simple process. All such a
301 patch has to do is modify a piece of code that uses a kernel feature
302 not present in the older version of the kernel, so that the driver
303 continues to work correctly under that older version.
305 A useful goal when writing a good backport patch is to make your code
306 look as if it was written for the older version of the kernel you're
307 targeting. The less obtrusive the patch, the easier it will be to
308 understand and maintain. If you're writing a collection of backport
309 patches to avoid the ``rat's nest'' effect of lots of
310 \texttt{\#ifdef}s (hunks of source code that are only used
311 conditionally) in your code, don't introduce version-dependent
312 \texttt{\#ifdef}s into the patches. Instead, write several patches,
313 each of which makes unconditional changes, and control their
314 application using guards.
316 There are two reasons to divide backport patches into a distinct
317 group, away from the ``regular'' patches whose effects they modify.
318 The first is that intermingling the two makes it more difficult to use
319 a tool like the \hgext{patchbomb} extension to automate the process of
320 submitting the patches to an upstream maintainer. The second is that
321 a backport patch could perturb the context in which a subsequent
322 regular patch is applied, making it impossible to apply the regular
323 patch cleanly \emph{without} the earlier backport patch already being
324 applied.
326 \section{Useful tips for developing with MQ}
328 \subsection{Organising patches in directories}
330 If you're working on a substantial project with MQ, it's not difficult
331 to accumulate a large number of patches. For example, I have one
332 patch repository that contains over 250 patches.
334 If you can group these patches into separate logical categories, you
335 can if you like store them in different directories; MQ has no
336 problems with patch names that contain path separators.
338 \subsection{Viewing the history of a patch}
339 \label{mq-collab:tips:interdiff}
341 If you're developing a set of patches over a long time, it's a good
342 idea to maintain them in a repository, as discussed in
343 section~\ref{sec:mq:repo}. If you do so, you'll quickly discover that
344 using the \hgcmd{diff} command to look at the history of changes to a
345 patch is unworkable. This is in part because you're looking at the
346 second derivative of the real code (a diff of a diff), but also
347 because MQ adds noise to the process by modifying time stamps and
348 directory names when it updates a patch.
350 However, you can use the \hgext{extdiff} extension, which is bundled
351 with Mercurial, to turn a diff of two versions of a patch into
352 something readable. To do this, you will need a third-party package
353 called \package{patchutils}~\cite{web:patchutils}. This provides a
354 command named \command{interdiff}, which shows the differences between
355 two diffs as a diff. Used on two versions of the same diff, it
356 generates a diff that represents the diff from the first to the second
357 version.
359 You can enable the \hgext{extdiff} extension in the usual way, by
360 adding a line to the \rcsection{extensions} section of your \hgrc.
361 \begin{codesample2}
362 [extensions]
363 extdiff =
364 \end{codesample2}
365 The \command{interdiff} command expects to be passed the names of two
366 files, but the \hgext{extdiff} extension passes the program it runs a
367 pair of directories, each of which can contain an arbitrary number of
368 files. We thus need a small program that will run \command{interdiff}
369 on each pair of files in these two directories. This program is
370 available as \sfilename{hg-interdiff} in the \dirname{examples}
371 directory of the source code repository that accompanies this book.
372 \excode{hg-interdiff}
374 With the \sfilename{hg-interdiff} program in your shell's search path,
375 you can run it as follows, from inside an MQ patch directory:
376 \begin{codesample2}
377 hg extdiff -p hg-interdiff -r A:B my-change.patch
378 \end{codesample2}
379 Since you'll probably want to use this long-winded command a lot, you
380 can get \hgext{hgext} to make it available as a normal Mercurial
381 command, again by editing your \hgrc.
382 \begin{codesample2}
383 [extdiff]
384 cmd.interdiff = hg-interdiff
385 \end{codesample2}
386 This directs \hgext{hgext} to make an \texttt{interdiff} command
387 available, so you can now shorten the previous invocation of
388 \hgxcmd{extdiff}{extdiff} to something a little more wieldy.
389 \begin{codesample2}
390 hg interdiff -r A:B my-change.patch
391 \end{codesample2}
393 \begin{note}
394 The \command{interdiff} command works well only if the underlying
395 files against which versions of a patch are generated remain the
396 same. If you create a patch, modify the underlying files, and then
397 regenerate the patch, \command{interdiff} may not produce useful
398 output.
399 \end{note}
401 The \hgext{extdiff} extension is useful for more than merely improving
402 the presentation of MQ~patches. To read more about it, go to
403 section~\ref{sec:hgext:extdiff}.
405 %%% Local Variables:
406 %%% mode: latex
407 %%% TeX-master: "00book"
408 %%% End: