hgbook

view es/mq-collab.tex @ 481:6cf30b3ed48f

translated some paragraphs
author Javier Rojas <jerojasro@devnull.li>
date Mon Jan 05 00:18:31 2009 -0500 (2009-01-05)
parents 7e52f0cc4516
children 039ed6f5935b
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 The first is to maintain a number of branches, each intended for a
61 single target. The trouble with this approach is that you must
62 maintain iron discipline in the flow of changes between repositories.
63 A new feature or bug fix must start life in a ``pristine'' repository,
64 then percolate out to every backport repository. Backport changes are
65 more limited in the branches they should propagate to; a backport
66 change that is applied to a branch where it doesn't belong will
67 probably stop the driver from compiling.
69 The second is to maintain a single source tree filled with conditional
70 statements that turn chunks of code on or off depending on the
71 intended target. Because these ``ifdefs'' are not allowed in the
72 Linux kernel tree, a manual or automatic process must be followed to
73 strip them out and yield a clean tree. A code base maintained in this
74 fashion rapidly becomes a rat's nest of conditional blocks that are
75 difficult to understand and maintain.
77 Neither of these approaches is well suited to a situation where you
78 don't ``own'' the canonical copy of a source tree. In the case of a
79 Linux driver that is distributed with the standard kernel, Linus's
80 tree contains the copy of the code that will be treated by the world
81 as canonical. The upstream version of ``my'' driver can be modified
82 by people I don't know, without me even finding out about it until
83 after the changes show up in Linus's tree.
85 These approaches have the added weakness of making it difficult to
86 generate well-formed patches to submit upstream.
88 In principle, Mercurial Queues seems like a good candidate to manage a
89 development scenario such as the above. While this is indeed the
90 case, MQ contains a few added features that make the job more
91 pleasant.
93 \section{Conditionally applying patches with
94 guards}
96 Perhaps the best way to maintain sanity with so many targets is to be
97 able to choose specific patches to apply for a given situation. MQ
98 provides a feature called ``guards'' (which originates with quilt's
99 \texttt{guards} command) that does just this. To start off, let's
100 create a simple repository for experimenting in.
101 \interaction{mq.guards.init}
102 This gives us a tiny repository that contains two patches that don't
103 have any dependencies on each other, because they touch different files.
105 The idea behind conditional application is that you can ``tag'' a
106 patch with a \emph{guard}, which is simply a text string of your
107 choosing, then tell MQ to select specific guards to use when applying
108 patches. MQ will then either apply, or skip over, a guarded patch,
109 depending on the guards that you have selected.
111 A patch can have an arbitrary number of guards;
112 each one is \emph{positive} (``apply this patch if this guard is
113 selected'') or \emph{negative} (``skip this patch if this guard is
114 selected''). A patch with no guards is always applied.
116 \section{Controlling the guards on a patch}
118 The \hgxcmd{mq}{qguard} command lets you determine which guards should
119 apply to a patch, or display the guards that are already in effect.
120 Without any arguments, it displays the guards on the current topmost
121 patch.
122 \interaction{mq.guards.qguard}
123 To set a positive guard on a patch, prefix the name of the guard with
124 a ``\texttt{+}''.
125 \interaction{mq.guards.qguard.pos}
126 To set a negative guard on a patch, prefix the name of the guard with
127 a ``\texttt{-}''.
128 \interaction{mq.guards.qguard.neg}
130 \begin{note}
131 The \hgxcmd{mq}{qguard} command \emph{sets} the guards on a patch; it
132 doesn't \emph{modify} them. What this means is that if you run
133 \hgcmdargs{qguard}{+a +b} on a patch, then \hgcmdargs{qguard}{+c} on
134 the same patch, the \emph{only} guard that will be set on it
135 afterwards is \texttt{+c}.
136 \end{note}
138 Mercurial stores guards in the \sfilename{series} file; the form in
139 which they are stored is easy both to understand and to edit by hand.
140 (In other words, you don't have to use the \hgxcmd{mq}{qguard} command if
141 you don't want to; it's okay to simply edit the \sfilename{series}
142 file.)
143 \interaction{mq.guards.series}
145 \section{Selecting the guards to use}
147 The \hgxcmd{mq}{qselect} command determines which guards are active at a
148 given time. The effect of this is to determine which patches MQ will
149 apply the next time you run \hgxcmd{mq}{qpush}. It has no other effect; in
150 particular, it doesn't do anything to patches that are already
151 applied.
153 With no arguments, the \hgxcmd{mq}{qselect} command lists the guards
154 currently in effect, one per line of output. Each argument is treated
155 as the name of a guard to apply.
156 \interaction{mq.guards.qselect.foo}
157 In case you're interested, the currently selected guards are stored in
158 the \sfilename{guards} file.
159 \interaction{mq.guards.qselect.cat}
160 We can see the effect the selected guards have when we run
161 \hgxcmd{mq}{qpush}.
162 \interaction{mq.guards.qselect.qpush}
164 A guard cannot start with a ``\texttt{+}'' or ``\texttt{-}''
165 character. The name of a guard must not contain white space, but most
166 other characters are acceptable. If you try to use a guard with an
167 invalid name, MQ will complain:
168 \interaction{mq.guards.qselect.error}
169 Changing the selected guards changes the patches that are applied.
170 \interaction{mq.guards.qselect.quux}
171 You can see in the example below that negative guards take precedence
172 over positive guards.
173 \interaction{mq.guards.qselect.foobar}
175 \section{MQ's rules for applying patches}
177 The rules that MQ uses when deciding whether to apply a patch
178 are as follows.
179 \begin{itemize}
180 \item A patch that has no guards is always applied.
181 \item If the patch has any negative guard that matches any currently
182 selected guard, the patch is skipped.
183 \item If the patch has any positive guard that matches any currently
184 selected guard, the patch is applied.
185 \item If the patch has positive or negative guards, but none matches
186 any currently selected guard, the patch is skipped.
187 \end{itemize}
189 \section{Trimming the work environment}
191 In working on the device driver I mentioned earlier, I don't apply the
192 patches to a normal Linux kernel tree. Instead, I use a repository
193 that contains only a snapshot of the source files and headers that are
194 relevant to Infiniband development. This repository is~1\% the size
195 of a kernel repository, so it's easier to work with.
197 I then choose a ``base'' version on top of which the patches are
198 applied. This is a snapshot of the Linux kernel tree as of a revision
199 of my choosing. When I take the snapshot, I record the changeset ID
200 from the kernel repository in the commit message. Since the snapshot
201 preserves the ``shape'' and content of the relevant parts of the
202 kernel tree, I can apply my patches on top of either my tiny
203 repository or a normal kernel tree.
205 Normally, the base tree atop which the patches apply should be a
206 snapshot of a very recent upstream tree. This best facilitates the
207 development of patches that can easily be submitted upstream with few
208 or no modifications.
210 \section{Dividing up the \sfilename{series} file}
212 I categorise the patches in the \sfilename{series} file into a number
213 of logical groups. Each section of like patches begins with a block
214 of comments that describes the purpose of the patches that follow.
216 The sequence of patch groups that I maintain follows. The ordering of
217 these groups is important; I'll describe why after I introduce the
218 groups.
219 \begin{itemize}
220 \item The ``accepted'' group. Patches that the development team has
221 submitted to the maintainer of the Infiniband subsystem, and which
222 he has accepted, but which are not present in the snapshot that the
223 tiny repository is based on. These are ``read only'' patches,
224 present only to transform the tree into a similar state as it is in
225 the upstream maintainer's repository.
226 \item The ``rework'' group. Patches that I have submitted, but that
227 the upstream maintainer has requested modifications to before he
228 will accept them.
229 \item The ``pending'' group. Patches that I have not yet submitted to
230 the upstream maintainer, but which we have finished working on.
231 These will be ``read only'' for a while. If the upstream maintainer
232 accepts them upon submission, I'll move them to the end of the
233 ``accepted'' group. If he requests that I modify any, I'll move
234 them to the beginning of the ``rework'' group.
235 \item The ``in progress'' group. Patches that are actively being
236 developed, and should not be submitted anywhere yet.
237 \item The ``backport'' group. Patches that adapt the source tree to
238 older versions of the kernel tree.
239 \item The ``do not ship'' group. Patches that for some reason should
240 never be submitted upstream. For example, one such patch might
241 change embedded driver identification strings to make it easier to
242 distinguish, in the field, between an out-of-tree version of the
243 driver and a version shipped by a distribution vendor.
244 \end{itemize}
246 Now to return to the reasons for ordering groups of patches in this
247 way. We would like the lowest patches in the stack to be as stable as
248 possible, so that we will not need to rework higher patches due to
249 changes in context. Putting patches that will never be changed first
250 in the \sfilename{series} file serves this purpose.
252 We would also like the patches that we know we'll need to modify to be
253 applied on top of a source tree that resembles the upstream tree as
254 closely as possible. This is why we keep accepted patches around for
255 a while.
257 The ``backport'' and ``do not ship'' patches float at the end of the
258 \sfilename{series} file. The backport patches must be applied on top
259 of all other patches, and the ``do not ship'' patches might as well
260 stay out of harm's way.
262 \section{Maintaining the patch series}
264 In my work, I use a number of guards to control which patches are to
265 be applied.
267 \begin{itemize}
268 \item ``Accepted'' patches are guarded with \texttt{accepted}. I
269 enable this guard most of the time. When I'm applying the patches
270 on top of a tree where the patches are already present, I can turn
271 this patch off, and the patches that follow it will apply cleanly.
272 \item Patches that are ``finished'', but not yet submitted, have no
273 guards. If I'm applying the patch stack to a copy of the upstream
274 tree, I don't need to enable any guards in order to get a reasonably
275 safe source tree.
276 \item Those patches that need reworking before being resubmitted are
277 guarded with \texttt{rework}.
278 \item For those patches that are still under development, I use
279 \texttt{devel}.
280 \item A backport patch may have several guards, one for each version
281 of the kernel to which it applies. For example, a patch that
282 backports a piece of code to~2.6.9 will have a~\texttt{2.6.9} guard.
283 \end{itemize}
284 This variety of guards gives me considerable flexibility in
285 qdetermining what kind of source tree I want to end up with. For most
286 situations, the selection of appropriate guards is automated during
287 the build process, but I can manually tune the guards to use for less
288 common circumstances.
290 \subsection{The art of writing backport patches}
292 Using MQ, writing a backport patch is a simple process. All such a
293 patch has to do is modify a piece of code that uses a kernel feature
294 not present in the older version of the kernel, so that the driver
295 continues to work correctly under that older version.
297 A useful goal when writing a good backport patch is to make your code
298 look as if it was written for the older version of the kernel you're
299 targeting. The less obtrusive the patch, the easier it will be to
300 understand and maintain. If you're writing a collection of backport
301 patches to avoid the ``rat's nest'' effect of lots of
302 \texttt{\#ifdef}s (hunks of source code that are only used
303 conditionally) in your code, don't introduce version-dependent
304 \texttt{\#ifdef}s into the patches. Instead, write several patches,
305 each of which makes unconditional changes, and control their
306 application using guards.
308 There are two reasons to divide backport patches into a distinct
309 group, away from the ``regular'' patches whose effects they modify.
310 The first is that intermingling the two makes it more difficult to use
311 a tool like the \hgext{patchbomb} extension to automate the process of
312 submitting the patches to an upstream maintainer. The second is that
313 a backport patch could perturb the context in which a subsequent
314 regular patch is applied, making it impossible to apply the regular
315 patch cleanly \emph{without} the earlier backport patch already being
316 applied.
318 \section{Useful tips for developing with MQ}
320 \subsection{Organising patches in directories}
322 If you're working on a substantial project with MQ, it's not difficult
323 to accumulate a large number of patches. For example, I have one
324 patch repository that contains over 250 patches.
326 If you can group these patches into separate logical categories, you
327 can if you like store them in different directories; MQ has no
328 problems with patch names that contain path separators.
330 \subsection{Viewing the history of a patch}
331 \label{mq-collab:tips:interdiff}
333 If you're developing a set of patches over a long time, it's a good
334 idea to maintain them in a repository, as discussed in
335 section~\ref{sec:mq:repo}. If you do so, you'll quickly discover that
336 using the \hgcmd{diff} command to look at the history of changes to a
337 patch is unworkable. This is in part because you're looking at the
338 second derivative of the real code (a diff of a diff), but also
339 because MQ adds noise to the process by modifying time stamps and
340 directory names when it updates a patch.
342 However, you can use the \hgext{extdiff} extension, which is bundled
343 with Mercurial, to turn a diff of two versions of a patch into
344 something readable. To do this, you will need a third-party package
345 called \package{patchutils}~\cite{web:patchutils}. This provides a
346 command named \command{interdiff}, which shows the differences between
347 two diffs as a diff. Used on two versions of the same diff, it
348 generates a diff that represents the diff from the first to the second
349 version.
351 You can enable the \hgext{extdiff} extension in the usual way, by
352 adding a line to the \rcsection{extensions} section of your \hgrc.
353 \begin{codesample2}
354 [extensions]
355 extdiff =
356 \end{codesample2}
357 The \command{interdiff} command expects to be passed the names of two
358 files, but the \hgext{extdiff} extension passes the program it runs a
359 pair of directories, each of which can contain an arbitrary number of
360 files. We thus need a small program that will run \command{interdiff}
361 on each pair of files in these two directories. This program is
362 available as \sfilename{hg-interdiff} in the \dirname{examples}
363 directory of the source code repository that accompanies this book.
364 \excode{hg-interdiff}
366 With the \sfilename{hg-interdiff} program in your shell's search path,
367 you can run it as follows, from inside an MQ patch directory:
368 \begin{codesample2}
369 hg extdiff -p hg-interdiff -r A:B my-change.patch
370 \end{codesample2}
371 Since you'll probably want to use this long-winded command a lot, you
372 can get \hgext{hgext} to make it available as a normal Mercurial
373 command, again by editing your \hgrc.
374 \begin{codesample2}
375 [extdiff]
376 cmd.interdiff = hg-interdiff
377 \end{codesample2}
378 This directs \hgext{hgext} to make an \texttt{interdiff} command
379 available, so you can now shorten the previous invocation of
380 \hgxcmd{extdiff}{extdiff} to something a little more wieldy.
381 \begin{codesample2}
382 hg interdiff -r A:B my-change.patch
383 \end{codesample2}
385 \begin{note}
386 The \command{interdiff} command works well only if the underlying
387 files against which versions of a patch are generated remain the
388 same. If you create a patch, modify the underlying files, and then
389 regenerate the patch, \command{interdiff} may not produce useful
390 output.
391 \end{note}
393 The \hgext{extdiff} extension is useful for more than merely improving
394 the presentation of MQ~patches. To read more about it, go to
395 section~\ref{sec:hgext:extdiff}.
397 %%% Local Variables:
398 %%% mode: latex
399 %%% TeX-master: "00book"
400 %%% End: