rev |
line source |
jerojasro@481
|
1 \chapter{Usos avanzados de las Colas de Mercurial}
|
jerojasro@336
|
2 \label{chap:mq-collab}
|
jerojasro@336
|
3
|
jerojasro@481
|
4 Auunque es fácil aprender los usos más directos de las Colas de
|
jerojasro@481
|
5 Mercurial, tener algo de disciplina junto con algunas de las
|
jerojasro@481
|
6 capacidadees menos usadas de MQ hace posible trabajar en entornos de
|
jerojasro@481
|
7 desarrollo complejos.
|
jerojasro@481
|
8
|
jerojasro@481
|
9 En este capítulo, usaré como ejemplo una técnica que he usado para
|
jerojasro@481
|
10 administrar el desarrollo de un controlador de dispositivo Infiniband
|
jerojasro@481
|
11 para el kernel de Linux. El controlador en cuestión es grande
|
jerojasro@481
|
12 (al menos en lo que se refiere a controladores), con 25,000 líneas de
|
jerojasro@481
|
13 código esparcidas en 35 ficheros fuente. Es mantenido por un equipo
|
jerojasro@481
|
14 pequeño de desarrolladores.
|
jerojasro@481
|
15
|
jerojasro@481
|
16 Aunque mucho del material en este capítulo es específico de Linux, los
|
jerojasro@481
|
17 mismos principios aplican a cualquier base de código de la que usted
|
jerojasro@481
|
18 no sea el propietario principal, y sobre la que usted necesita hacer
|
jerojasro@481
|
19 un montón de desarrollo.
|
jerojasro@481
|
20
|
jerojasro@481
|
21 \section{El problema de múltiples objetivos}
|
jerojasro@481
|
22
|
jerojasro@481
|
23 El kernel de Linux cambia con rapidez, y nunca ha sido estable
|
jerojasro@481
|
24 internamente; los desarrolladores hacen cambios drásticos entre
|
jerojasro@481
|
25 %TODO no encontré una traducción adecuada para "release". Por eso el
|
jerojasro@481
|
26 %cambio
|
jerojasro@481
|
27 versiones frecuentemente. Esto significa que una versión del
|
jerojasro@481
|
28 controlador que funciona bien con una versión particular del kernel ni
|
jerojasro@481
|
29 siquiera \emph{compilará} correctamente contra, típicamente, cualquier
|
jerojasro@481
|
30 otra versión.
|
jerojasro@481
|
31
|
jerojasro@481
|
32 Para mantener un controlador, debemos tener en cuenta una buena
|
jerojasro@481
|
33 cantidad de versiones de Linux en mente.
|
jerojasro@336
|
34 \begin{itemize}
|
jerojasro@481
|
35 \item Un objetivo es el árbol de desarrollo principal del kernel de
|
jerojasro@481
|
36 Linux. En este caso el mantenimiento del código es compartido
|
jerojasro@481
|
37 parcialmente por otros desarrolladores en la comunidad del kernel,
|
jerojasro@481
|
38 %TODO drive-by.
|
jerojasro@481
|
39 quienes hacen modificaciones ``de-afán'' al controlador a medida que
|
jerojasro@481
|
40 desarrollan y refinan subsistemas en el kernel.
|
jerojasro@481
|
41 %TODO backport
|
jerojasro@481
|
42 \item También mantenemos algunos ``backports'' para versiones antiguas
|
jerojasro@481
|
43 del kernel de Linux, para dar soporte a las necesidades de los
|
jerojasro@481
|
44 clientes que están corriendo versiones antiguas de Linux que no
|
jerojasro@481
|
45 incorporan nuestros controladores. (Hacer el \emph{backport} de un
|
jerojasro@481
|
46 pedazo de código es modificarlo para que trabaje en una versión
|
jerojasro@481
|
47 de su entorno objetivo anterior a aquella para la cual fue escrito.)
|
jerojasro@481
|
48 \item Finalmente, nosotros liberamos nuestro software de acuerdo a un
|
jerojasro@481
|
49 cronograma que no necesariamente está alineado con el que usan los
|
jerojasro@481
|
50 distribuidores de Linux y los desarrolladores del kernel, así que
|
jerojasro@481
|
51 podemos entregar nuevas características a los clientes sin forzarlos
|
jerojasro@481
|
52 a actualizar kernels completos o distribuciones.
|
jerojasro@336
|
53 \end{itemize}
|
jerojasro@336
|
54
|
jerojasro@481
|
55 \subsection{Aproximaciones tentadoras que no funcionan adecuadamente}
|
jerojasro@481
|
56
|
jerojasro@481
|
57 Hay dos maneras estándar de mantener una porción de software que debe
|
jerojasro@481
|
58 funcionar en muchos entornos diferentes.
|
jerojasro@336
|
59
|
jerojasro@485
|
60 La primera es mantener varias ramas, cada una pensada para un único
|
jerojasro@485
|
61 entorno. El problema de esta aproximación es que usted debe tener una
|
jerojasro@485
|
62 disciplina férrea con el flujo de cambios entre repositorios. Una
|
jerojasro@485
|
63 nueva característica o un arreglo de fallo deben empezar su vida en un
|
jerojasro@485
|
64 repositorio ``prístino'', y luego propagarse a cada repositorio de
|
jerojasro@485
|
65 backport. Los cambios para backports están más limitados respecto a
|
jerojasro@485
|
66 las ramas a las que deberían propagarse; un cambio para backport que
|
jerojasro@485
|
67 es aplicado a una rama en la que no corresponde probablemente hará que
|
jerojasro@485
|
68 el controlador no compile.
|
jerojasro@485
|
69
|
jerojasro@485
|
70 La segunda es mantener un único árbol de código fuente lleno de
|
jerojasro@485
|
71 declaraciones que activen o desactiven secciones de código dependiendo
|
jerojasro@485
|
72 del entorno objetivo. Ya que estos ``ifdefs'' no están permitidos en
|
jerojasro@485
|
73 el árbol del kernel de Linux, debe seguirse algún proceso manual o
|
jerojasro@485
|
74 automático para eliminarlos y producir un árbol limpio. Una base de
|
jerojasro@485
|
75 código mantenida de esta manera se convierte rápidamente en un nido de
|
jerojasro@485
|
76 ratas de bloques condicionales que son difíciles de entender y
|
jerojasro@485
|
77 mantener.
|
jerojasro@485
|
78
|
jerojasro@485
|
79 %TODO canónica?
|
jerojasro@485
|
80 Ninguno de estos enfoques es adecuado para situaciones en las que
|
jerojasro@485
|
81 usted no es ``dueño'' de la copia canónica de un árbol de fuentes. En
|
jerojasro@485
|
82 el caso de un controlador de Linux que es distribuido con el kernel
|
jerojasro@485
|
83 estándar, el árbol de Linux contiene la copia del código que será
|
jerojasro@485
|
84 considerada por el mundo como la canónica. La versión oficial de
|
jerojasro@485
|
85 ``mi'' controlador puede ser modificada por gente que no conozco, sin
|
jerojasro@485
|
86 que yo siquiera me entere de ello hasta después de que los cambios
|
jerojasro@485
|
87 aparecen en el árbol de Linus.
|
jerojasro@485
|
88
|
jerojasro@485
|
89 Estos enfoques tienen la debilidad adicional de dificultar la
|
jerojasro@485
|
90 %TODO upstream. no no es río arriba
|
jerojasro@485
|
91 generación de parches bien formados para enviarlos a la versión
|
jerojasro@485
|
92 oficial.
|
jerojasro@485
|
93
|
jerojasro@485
|
94 En principio, las Colas de Mercurial parecen ser un buen candidato
|
jerojasro@485
|
95 para administrar un escenario de desarrollo como el de arriba. Aunque
|
jerojasro@485
|
96 este es de hecho el caso, MQ tiene unas cuantas características
|
jerojasro@485
|
97 adicionales que hacen el trabajo más agradable.
|
jerojasro@336
|
98
|
jerojasro@489
|
99 \section{Aplicar parches condicionalmente mediante guardias}
|
jerojasro@489
|
100
|
jerojasro@489
|
101 Tal vez la mejor manera de conservar la cordura con tantos entornos
|
jerojasro@489
|
102 objetivo es poder escoger parches específicos para aplicar para cada
|
jerojasro@489
|
103 situación. MQ provee una característica llamada ``guardias''
|
jerojasro@489
|
104 (que se origina del comando \texttt{guards} de Quilt) que hace
|
jerojasro@489
|
105 precisamente ésto. Para empezar, creemos un repositorio sencillo para
|
jerojasro@489
|
106 experimentar.
|
jerojasro@336
|
107 \interaction{mq.guards.init}
|
jerojasro@489
|
108 Esto nos brinda un pequeño repositorio que contiene dos parches que no
|
jerojasro@489
|
109 tienen ninguna dependencia respecto al otro, porque tocan ficheros
|
jerojasro@489
|
110 diferentes.
|
jerojasro@489
|
111
|
jerojasro@489
|
112 La idea detrás de la aplicación condicional es que usted puede
|
jerojasro@489
|
113 ``etiquetar'' un parche con un \emph{guardia}, que simplemente es una
|
jerojasro@489
|
114 cadena de texto de su elección, y luego decirle a MQ que seleccione
|
jerojasro@489
|
115 guardias específicos para usar cuando aplique parches. MQ entonces
|
jerojasro@489
|
116 aplicará, u omitirá, un parche vigilado, dependiendo de los guardias
|
jerojasro@489
|
117 que usted haya seleccionado.
|
jerojasro@489
|
118
|
jerojasro@489
|
119 Un parche puede tener una cantidad arbitraria de guardias; cada uno es
|
jerojasro@489
|
120 \emph{positivo} (``aplique el parche si este guardia es
|
jerojasro@489
|
121 seleccionado'') o \emph{negativo} (``omita este parche si este guardia
|
jerojasro@489
|
122 es seleccionado''). Un parche sin guardias siempre es aplicado.
|
jerojasro@336
|
123
|
jerojasro@490
|
124 \section{Controlar los guardias de un parche}
|
jerojasro@490
|
125
|
jerojasro@491
|
126 %TODO tal vez no decir determinar, sino definir?
|
jerojasro@490
|
127 El comando \hgxcmd{mq}{qguard} le permite determinar qué guardias
|
jerojasro@490
|
128 deben aplicarse a un parche, o mostrar los guardias que están en
|
jerojasro@490
|
129 efecto. Sin ningún argumento, el comando muestra los guardias del
|
jerojasro@490
|
130 parche actual de la parte más alta de la pila.
|
jerojasro@336
|
131 \interaction{mq.guards.qguard}
|
jerojasro@490
|
132 Para poner un guardia positivo en un parche, prefije el nombre del
|
jerojasro@490
|
133 guardia con un ``\texttt{+}''.
|
jerojasro@336
|
134 \interaction{mq.guards.qguard.pos}
|
jerojasro@490
|
135 Para poner un guardia negativo en un parche, prefije el nombre del
|
jerojasro@490
|
136 guardia con un ``\texttt{-}''.
|
jerojasro@336
|
137 \interaction{mq.guards.qguard.neg}
|
jerojasro@336
|
138
|
jerojasro@336
|
139 \begin{note}
|
jerojasro@490
|
140 El comando \hgxcmd{mq}{qguard} \emph{pone} los guardias en un
|
jerojasro@490
|
141 parche; no los \emph{modifica}. Esto significa que si usted ejecuta
|
jerojasro@490
|
142 \hgcmdargs{qguard}{+a +b} sobre un parche, y luego
|
jerojasro@490
|
143 \hgcmdargs{qguard}{+c} en el mismo parche, el único guardia sobre el
|
jerojasro@490
|
144 parche después del comando será \texttt{+c}.
|
jerojasro@336
|
145 \end{note}
|
jerojasro@336
|
146
|
jerojasro@490
|
147 Mercurial almacena los guardias en el fichero \sfilename{series}; la
|
jerojasro@490
|
148 forma en que son almacenados es fácil tanto de entender como de editar
|
jerojasro@490
|
149 a mano. (En otras palabras, usted no tiene que usar el comando
|
jerojasro@490
|
150 \hgxcmd{mq}{qguard} si no lo desea; está bien simplemente editar el
|
jerojasro@490
|
151 fichero \sfilename{series})
|
jerojasro@336
|
152 \interaction{mq.guards.series}
|
jerojasro@336
|
153
|
jerojasro@491
|
154 \section{Selecccionar los guardias a usar}
|
jerojasro@491
|
155
|
jerojasro@491
|
156 %TODO tal vez no decir determinar, sino definir?
|
jerojasro@491
|
157 El comando \hgxcmd{mq}{qselect} determina qué guardias están activos
|
jerojasro@491
|
158 en cualquier momento. El efecto de esto es determinar qué parches
|
jerojasro@491
|
159 aplicará MQ la próxima vez que usted ejecute \hgxcmd{mq}{qpush}. No
|
jerojasro@491
|
160 tiene ningún otro efecto; en particular, no hace nada a los parches
|
jerojasro@491
|
161 que ya han sido aplicados.
|
jerojasro@491
|
162
|
jerojasro@491
|
163 Sin argumentos, el comando \hgxcmd{mq}{qselect} lista los guardias en
|
jerojasro@491
|
164 efecto actualmente, uno por cada línea de salida. Cada argumento es
|
jerojasro@491
|
165 tratado como el nombre de un guardia a aplicar.
|
jerojasro@336
|
166 \interaction{mq.guards.qselect.foo}
|
jerojasro@491
|
167 Si está interesado, los guardias seleccionados actualmente están
|
jerojasro@491
|
168 almacenados en el fichero \sfilename{guards}.
|
jerojasro@336
|
169 \interaction{mq.guards.qselect.cat}
|
jerojasro@491
|
170 Podemos ver el efecto que tienen los guardias seleccionados cuando
|
jerojasro@491
|
171 ejecutamos \hgxcmd{mq}{qpush}.
|
jerojasro@336
|
172 \interaction{mq.guards.qselect.qpush}
|
jerojasro@336
|
173
|
jerojasro@491
|
174 Un guardia no puede empezar con un caracter ``\texttt{+}'' o
|
jerojasro@491
|
175 ``\texttt{-}''. El nombre del guardia no debe contener espacios en
|
jerojasro@491
|
176 blanco, pero muchos otros caracteres son aceptables. Si usted trata de
|
jerojasro@491
|
177 usar un guardia con un nombre inválido, MQ se quejará:
|
jerojasro@336
|
178 \interaction{mq.guards.qselect.error}
|
jerojasro@491
|
179 Cambiar los guardias seleccionados cambia los parches que son
|
jerojasro@491
|
180 aplicados.
|
jerojasro@336
|
181 \interaction{mq.guards.qselect.quux}
|
jerojasro@491
|
182 Usted puede ver en el ejemplo de abajo que los guardias negativos
|
jerojasro@491
|
183 tienen precedencia sobre los guardias positivos.
|
jerojasro@336
|
184 \interaction{mq.guards.qselect.foobar}
|
jerojasro@336
|
185
|
jerojasro@494
|
186 \section{Reglas de MQ para aplicar parches}
|
jerojasro@494
|
187
|
jerojasro@494
|
188 Las reglas que MQ usa para decidir si debe aplicar un parche son las
|
jerojasro@494
|
189 siguientes.
|
jerojasro@336
|
190 \begin{itemize}
|
jerojasro@494
|
191 \item Un parche sin guardias es aplicado siempre.
|
jerojasro@494
|
192 \item Si el parche tiene algún guardia negativo que corresponda con
|
jerojasro@494
|
193 cualquiera de los guardias seleccionados, se salta el parche.
|
jerojasro@494
|
194 \item Si el parche tiene algún guardia positivo que corresponda con
|
jerojasro@494
|
195 cualquiera de los guardias seleccionados, se aplica el parche.
|
jerojasro@494
|
196 \item Si el parche tiene guardias positivos o negativos, pero ninguno
|
jerojasro@494
|
197 corresponde con cualquiera de los guardias seleccionados, se salta
|
jerojasro@494
|
198 el parche.
|
jerojasro@336
|
199 \end{itemize}
|
jerojasro@336
|
200
|
jerojasro@494
|
201 \section{Podar el entorno de trabajo}
|
jerojasro@494
|
202
|
jerojasro@494
|
203 En el trabajo del controlador de dispositivo que mencioné
|
jerojasro@494
|
204 anteriormente, yo no aplico los parches a un árbol normal del kernel
|
jerojasro@494
|
205 de Linux. En cambio, uso un repositorio que sólo contiene una
|
jerojasro@494
|
206 instantánea de los ficheros fuente y de cabecera que son relevantes
|
jerojasro@494
|
207 para el desarrollo de Infiniband. Este repositorio tiene un~1\% del
|
jerojasro@494
|
208 tamaño del repositorio del kernel, por lo que es más fácil trabajar
|
jerojasro@494
|
209 con él.
|
jerojasro@494
|
210
|
jerojasro@494
|
211 Luego escojo una versión ``base'' sobre la cual son aplicados los
|
jerojasro@494
|
212 parches. Es una instantánea del árbol del kernel de Linux en una
|
jerojasro@494
|
213 revisión de mi elección. Cuando tomo la instantánea, almaceno el ID de
|
jerojasro@494
|
214 conjunto de cambios en el mensaje de consignación. Ya que la
|
jerojasro@494
|
215 instantánea preserva la ``forma'' y el contenido de las partes
|
jerojasro@494
|
216 relevantes del árbol del kernel, puedo aplicar mis parches sobre mi
|
jerojasro@494
|
217 pequeño repositorio o sobre un árbol normal del kernel.
|
jerojasro@494
|
218
|
jerojasro@494
|
219 Normalmente, el árbol base sobre el que se aplican los parches debería
|
jerojasro@494
|
220 ser una instantánea de un árbol de desarrollo muy reciente. Esto
|
jerojasro@494
|
221 facilita mucho el desarrollo de parches que puedan ser enviados al
|
jerojasro@494
|
222 árbol oficial con pocas o ninguna modificación.
|
jerojasro@494
|
223
|
jerojasro@494
|
224 \section{Dividir el fichero \sfilename{series}}
|
jerojasro@494
|
225
|
jerojasro@494
|
226 Yo categorizo los parches en el fichero \sfilename{series} en una
|
jerojasro@494
|
227 serie de grupos lógicos. Cada sección de parches similares empieza con
|
jerojasro@494
|
228 un bloque de comentarios que describen el propósito de los parches que
|
jerojasro@494
|
229 le siguen.
|
jerojasro@494
|
230
|
jerojasro@494
|
231 La secuencia de grupos de parches que mantengo se muestra a
|
jerojasro@494
|
232 continuación. El orden de los grupos es importante; explicaré porqué
|
jerojasro@494
|
233 luego de que presente los grupos.
|
jerojasro@336
|
234 \begin{itemize}
|
jerojasro@494
|
235 \item El grupo ``aceptado''. Son parches que el equipo de desarrollo
|
jerojasro@494
|
236 ha enviado al mantenedor del subsistema Infiniband, y que él ha
|
jerojasro@494
|
237 aceptado, pero que no están presentes en la instantánea en la cual
|
jerojasro@494
|
238 está basada el repositorio pequeño. Estos son parches de
|
jerojasro@494
|
239 ``sólo lectura'', presentes únicamente para transformar el árbol en
|
jerojasro@494
|
240 un estado similar al del repositorio del mantenedor oficial.
|
jerojasro@494
|
241 \item El grupo ``revisar''. Parches que yo he enviado, pero sobre los
|
jerojasro@494
|
242 que que el mantenedor oficial ha solicitado modificaciones antes de
|
jerojasro@494
|
243 aceptarlos.
|
jerojasro@494
|
244 \item El grupo ``pendiente''. Parches que no he enviado al mantenedor
|
jerojasro@494
|
245 oficial, pero que ya están terminados. Estos parches serán de
|
jerojasro@494
|
246 ``sólo lectura'' por un buen tiempo. Si el mantenedor oficial los
|
jerojasro@494
|
247 acepta cuando los envíe, los moveré al final del grupo ``aceptado''.
|
jerojasro@494
|
248 Si él solicita que modificaciones en alguno de ellos, los moveré al
|
jerojasro@494
|
249 principio del grupo ``revisar''.
|
jerojasro@494
|
250 \item El grupo ``en proceso''. Parches que están siendo activamente
|
jerojasro@494
|
251 desarrollados, y no deberían ser enviados a ninguna parte aún.
|
jerojasro@494
|
252 \item El grupo ``backport''. Parches que adaptan el árbol de fuentes a
|
jerojasro@494
|
253 versiones antiguas del árbol del kernel.
|
jerojasro@494
|
254 \item El grupo ``no enviar''. Parches que por alguna razón nunca deben
|
jerojasro@494
|
255 ser enviados al mantenedor oficial del kernel. Por ejemplo, alguno
|
jerojasro@494
|
256 de esos parches podría cambiar las cadenas de identificación
|
jerojasro@494
|
257 embebidas del controlador para hacer más fácil la distinción, en
|
jerojasro@494
|
258 pruebas de campo, entre una versión del controlador de
|
jerojasro@494
|
259 salida-del-árbol y una versión entregada por un vendedor de alguna
|
jerojasro@494
|
260 distribución.
|
jerojasro@336
|
261 \end{itemize}
|
jerojasro@336
|
262
|
jerojasro@494
|
263 Ahora volvemos a las razones para ordenar los grupos de parches en
|
jerojasro@494
|
264 esta manera. Quisiéramos que los parches del fondo de la pila sean tan
|
jerojasro@494
|
265 estables como sea posible, para no tener que revisar parches más
|
jerojasro@494
|
266 arriba debido a cambios de contexto. Poner los parches que nunca
|
jerojasro@494
|
267 cambiarán en el primer lugar del fichero \sfilename{series} sirve a
|
jerojasro@494
|
268 este propósito.
|
jerojasro@494
|
269
|
jerojasro@494
|
270 También desearíamos que los parches que sabemos que debemos modificar
|
jerojasro@494
|
271 sean aplicados sobre un árbol de fuentes que se parezca al oficial
|
jerojasro@494
|
272 tanto como sea posible. Es por esto que mantenemos los parches
|
jerojasro@494
|
273 aceptados disponibles por una buena cantidad de tiempo.
|
jerojasro@494
|
274
|
jerojasro@494
|
275 Los parches ``backport'' y ``no enviar'' flotan al final del fichero
|
jerojasro@494
|
276 \sfilename{series}. Los parches de backport deben ser aplicados encima
|
jerojasro@494
|
277 de todos los otros parches, y los parches ``no enviar'' pueden
|
jerojasro@494
|
278 perfectamente quedarse fuera del camino.
|
jerojasro@336
|
279
|
jerojasro@495
|
280 \section{Mantener la serie de parches}
|
jerojasro@495
|
281
|
jerojasro@495
|
282 En mi trabajo, uso varios guardias para controlar qué parches deben
|
jerojasro@495
|
283 ser aplicados.
|
jerojasro@336
|
284
|
jerojasro@336
|
285 \begin{itemize}
|
jerojasro@495
|
286 \item Los parches ``aceptados'' son vigilados con
|
jerojasro@495
|
287 \texttt{accepted}. Yo habilito este guardia la mayoría de las veces.
|
jerojasro@495
|
288 Cuando aplico los parches sobre un árbol donde los parches ya están
|
jerojasro@495
|
289 %TODO no será ``desactivar este guardia''? si sí, corregir versión
|
jerojasro@495
|
290 %en inglés también
|
jerojasro@495
|
291 presentes, puedo desactivar este parche, y los parches que lo siguen
|
jerojasro@495
|
292 se aplicarán sin problemas.
|
jerojasro@495
|
293 \item Los parches que están ``terminados'', pero no han sido enviados,
|
jerojasro@495
|
294 no tienen guardias. Si estoy aplicando la pila de parches a una
|
jerojasro@495
|
295 copia del árbol oficial, no necesito habilitar ningún guardia para
|
jerojasro@495
|
296 obtener un árbol de fuentes razonablemente seguro.
|
jerojasro@495
|
297 \item Los parches que necesitan revisión antes de ser reenviados
|
jerojasro@495
|
298 tienen el guardia \texttt{rework}.
|
jerojasro@495
|
299 \item Para aquellos parches que aún están bajo desarrollo, uso
|
jerojasro@336
|
300 \texttt{devel}.
|
jerojasro@495
|
301 \item Un parche de backport puede tener varios guardias, uno para cada
|
jerojasro@495
|
302 versión del kernel a la que aplica. Por ejemplo, un parche que hace
|
jerojasro@495
|
303 backport de un segmento de código a~2.6.9 tendrá un guardia~\texttt{2.6.9}.
|
jerojasro@336
|
304 \end{itemize}
|
jerojasro@495
|
305 La variedad de guardias me brinda una flexibilidad considerable para
|
jerojasro@495
|
306 determinar qué tipo de árbol de fuentes acabaré por obtener. En la
|
jerojasro@495
|
307 mayoría de las situaciones, la selección de guardias apropiados es
|
jerojasro@495
|
308 automatizada durante el proceso de compilación, pero puedo ajustar
|
jerojasro@495
|
309 manualmente los guardias a usar para circunstancias poco comunes.
|
jerojasro@336
|
310
|
jerojasro@336
|
311 \subsection{The art of writing backport patches}
|
jerojasro@336
|
312
|
jerojasro@336
|
313 Using MQ, writing a backport patch is a simple process. All such a
|
jerojasro@336
|
314 patch has to do is modify a piece of code that uses a kernel feature
|
jerojasro@336
|
315 not present in the older version of the kernel, so that the driver
|
jerojasro@336
|
316 continues to work correctly under that older version.
|
jerojasro@336
|
317
|
jerojasro@336
|
318 A useful goal when writing a good backport patch is to make your code
|
jerojasro@336
|
319 look as if it was written for the older version of the kernel you're
|
jerojasro@336
|
320 targeting. The less obtrusive the patch, the easier it will be to
|
jerojasro@336
|
321 understand and maintain. If you're writing a collection of backport
|
jerojasro@336
|
322 patches to avoid the ``rat's nest'' effect of lots of
|
jerojasro@336
|
323 \texttt{\#ifdef}s (hunks of source code that are only used
|
jerojasro@336
|
324 conditionally) in your code, don't introduce version-dependent
|
jerojasro@336
|
325 \texttt{\#ifdef}s into the patches. Instead, write several patches,
|
jerojasro@336
|
326 each of which makes unconditional changes, and control their
|
jerojasro@336
|
327 application using guards.
|
jerojasro@336
|
328
|
jerojasro@336
|
329 There are two reasons to divide backport patches into a distinct
|
jerojasro@336
|
330 group, away from the ``regular'' patches whose effects they modify.
|
jerojasro@336
|
331 The first is that intermingling the two makes it more difficult to use
|
jerojasro@336
|
332 a tool like the \hgext{patchbomb} extension to automate the process of
|
jerojasro@336
|
333 submitting the patches to an upstream maintainer. The second is that
|
jerojasro@336
|
334 a backport patch could perturb the context in which a subsequent
|
jerojasro@336
|
335 regular patch is applied, making it impossible to apply the regular
|
jerojasro@336
|
336 patch cleanly \emph{without} the earlier backport patch already being
|
jerojasro@336
|
337 applied.
|
jerojasro@336
|
338
|
jerojasro@336
|
339 \section{Useful tips for developing with MQ}
|
jerojasro@336
|
340
|
jerojasro@336
|
341 \subsection{Organising patches in directories}
|
jerojasro@336
|
342
|
jerojasro@336
|
343 If you're working on a substantial project with MQ, it's not difficult
|
jerojasro@336
|
344 to accumulate a large number of patches. For example, I have one
|
jerojasro@336
|
345 patch repository that contains over 250 patches.
|
jerojasro@336
|
346
|
jerojasro@336
|
347 If you can group these patches into separate logical categories, you
|
jerojasro@336
|
348 can if you like store them in different directories; MQ has no
|
jerojasro@336
|
349 problems with patch names that contain path separators.
|
jerojasro@336
|
350
|
jerojasro@336
|
351 \subsection{Viewing the history of a patch}
|
jerojasro@336
|
352 \label{mq-collab:tips:interdiff}
|
jerojasro@336
|
353
|
jerojasro@336
|
354 If you're developing a set of patches over a long time, it's a good
|
jerojasro@336
|
355 idea to maintain them in a repository, as discussed in
|
jerojasro@336
|
356 section~\ref{sec:mq:repo}. If you do so, you'll quickly discover that
|
jerojasro@336
|
357 using the \hgcmd{diff} command to look at the history of changes to a
|
jerojasro@336
|
358 patch is unworkable. This is in part because you're looking at the
|
jerojasro@336
|
359 second derivative of the real code (a diff of a diff), but also
|
jerojasro@336
|
360 because MQ adds noise to the process by modifying time stamps and
|
jerojasro@336
|
361 directory names when it updates a patch.
|
jerojasro@336
|
362
|
jerojasro@336
|
363 However, you can use the \hgext{extdiff} extension, which is bundled
|
jerojasro@336
|
364 with Mercurial, to turn a diff of two versions of a patch into
|
jerojasro@336
|
365 something readable. To do this, you will need a third-party package
|
jerojasro@336
|
366 called \package{patchutils}~\cite{web:patchutils}. This provides a
|
jerojasro@336
|
367 command named \command{interdiff}, which shows the differences between
|
jerojasro@336
|
368 two diffs as a diff. Used on two versions of the same diff, it
|
jerojasro@336
|
369 generates a diff that represents the diff from the first to the second
|
jerojasro@336
|
370 version.
|
jerojasro@336
|
371
|
jerojasro@336
|
372 You can enable the \hgext{extdiff} extension in the usual way, by
|
jerojasro@336
|
373 adding a line to the \rcsection{extensions} section of your \hgrc.
|
jerojasro@336
|
374 \begin{codesample2}
|
jerojasro@336
|
375 [extensions]
|
jerojasro@336
|
376 extdiff =
|
jerojasro@336
|
377 \end{codesample2}
|
jerojasro@336
|
378 The \command{interdiff} command expects to be passed the names of two
|
jerojasro@336
|
379 files, but the \hgext{extdiff} extension passes the program it runs a
|
jerojasro@336
|
380 pair of directories, each of which can contain an arbitrary number of
|
jerojasro@336
|
381 files. We thus need a small program that will run \command{interdiff}
|
jerojasro@336
|
382 on each pair of files in these two directories. This program is
|
jerojasro@336
|
383 available as \sfilename{hg-interdiff} in the \dirname{examples}
|
jerojasro@336
|
384 directory of the source code repository that accompanies this book.
|
jerojasro@336
|
385 \excode{hg-interdiff}
|
jerojasro@336
|
386
|
jerojasro@336
|
387 With the \sfilename{hg-interdiff} program in your shell's search path,
|
jerojasro@336
|
388 you can run it as follows, from inside an MQ patch directory:
|
jerojasro@336
|
389 \begin{codesample2}
|
jerojasro@336
|
390 hg extdiff -p hg-interdiff -r A:B my-change.patch
|
jerojasro@336
|
391 \end{codesample2}
|
jerojasro@336
|
392 Since you'll probably want to use this long-winded command a lot, you
|
jerojasro@336
|
393 can get \hgext{hgext} to make it available as a normal Mercurial
|
jerojasro@336
|
394 command, again by editing your \hgrc.
|
jerojasro@336
|
395 \begin{codesample2}
|
jerojasro@336
|
396 [extdiff]
|
jerojasro@336
|
397 cmd.interdiff = hg-interdiff
|
jerojasro@336
|
398 \end{codesample2}
|
jerojasro@336
|
399 This directs \hgext{hgext} to make an \texttt{interdiff} command
|
jerojasro@336
|
400 available, so you can now shorten the previous invocation of
|
jerojasro@336
|
401 \hgxcmd{extdiff}{extdiff} to something a little more wieldy.
|
jerojasro@336
|
402 \begin{codesample2}
|
jerojasro@336
|
403 hg interdiff -r A:B my-change.patch
|
jerojasro@336
|
404 \end{codesample2}
|
jerojasro@336
|
405
|
jerojasro@336
|
406 \begin{note}
|
jerojasro@336
|
407 The \command{interdiff} command works well only if the underlying
|
jerojasro@336
|
408 files against which versions of a patch are generated remain the
|
jerojasro@336
|
409 same. If you create a patch, modify the underlying files, and then
|
jerojasro@336
|
410 regenerate the patch, \command{interdiff} may not produce useful
|
jerojasro@336
|
411 output.
|
jerojasro@336
|
412 \end{note}
|
jerojasro@336
|
413
|
jerojasro@336
|
414 The \hgext{extdiff} extension is useful for more than merely improving
|
jerojasro@336
|
415 the presentation of MQ~patches. To read more about it, go to
|
jerojasro@336
|
416 section~\ref{sec:hgext:extdiff}.
|
jerojasro@336
|
417
|
jerojasro@336
|
418 %%% Local Variables:
|
jerojasro@336
|
419 %%% mode: latex
|
jerojasro@336
|
420 %%% TeX-master: "00book"
|
jerojasro@336
|
421 %%% End:
|