2 * Copyright © 2006 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 * Given a single-file tree, locate the specific version number
28 rev_find_cvs_commit (rev_list
*rl
, cvs_number
*number
)
34 for (h
= rl
->heads
; h
; h
= h
->next
) {
37 for (c
= h
->commit
; c
; c
= c
->parent
)
40 if (cvs_number_compare (&f
->number
, number
) == 0)
50 * Construct a branch using CVS revision numbers
53 rev_branch_cvs (cvs_file
*cvs
, cvs_number
*branch
)
56 rev_commit
*head
= NULL
;
62 for (node
= cvs_find_version (cvs
, &n
); node
; node
= node
->next
) {
63 cvs_version
*v
= node
->v
;
64 cvs_patch
*p
= node
->p
;
68 c
= calloc (1, sizeof (rev_commit
));
70 c
->commitid
= v
->commitid
;
71 c
->author
= v
->author
;
78 /* leave this around so the branch merging stuff can find numbers */
79 c
->file
= rev_file_rev (cvs
->name
, &v
->number
, v
->date
);
82 c
->file
->mode
= cvs
->mode
;
88 * Make sure the dates along the branch are well ordered. As we
89 * want to preserve current data, push previous versions back to
90 * align with newer revisions.
92 for (c
= head
; (p
= c
->parent
); c
= p
) {
93 if (time_compare (p
->file
->date
, c
->file
->date
) > 0)
95 fprintf (stderr
, "Warning: %s:", cvs
->name
);
96 dump_number_file (stderr
, " ", &p
->file
->number
);
97 dump_number_file (stderr
, " is newer than", &c
->file
->number
);
98 fprintf (stderr
, ", adjusting\n");
99 p
->file
->date
= c
->file
->date
;
106 * "Vendor branches" (1.1.x) are created by importing sources from
107 * an external source. In X.org, this was from XFree86 and DRI. When
108 * these trees are imported, cvs sets the 'default' branch in each ,v file
109 * to point along this branch. This means that tags made between
110 * the time the vendor branch is imported and when a new revision
111 * is committed to the head branch are placed on the vendor branch
112 * In addition, any files without such a commit appear to adopt
113 * the vendor branch as 'head'. We fix this by merging these two
114 * branches together as if they were the same
117 rev_list_patch_vendor_branch (rev_list
*rl
, cvs_file
*cvs
)
119 rev_ref
*trunk
= NULL
;
120 rev_ref
*vendor
= NULL
, **vendor_p
= NULL
;
122 rev_commit
*t
, **tp
, *v
, **vp
;
129 for (h_p
= &rl
->heads
; (h
= *h_p
);) {
131 if (h
->commit
&& cvs_is_vendor (&h
->commit
->file
->number
))
134 * Find version 1.2 on the trunk.
135 * This will reset the default branch set
136 * when the initial import was done.
137 * Subsequent imports will *not* set the default
138 * branch, and should be on their own branch
144 for (vlast
= vendor
->commit
; vlast
; vlast
= vlast
->parent
)
150 * Find the latest trunk revision older than
151 * the entire vendor branch
156 time_compare (vlast
->file
->date
,
157 t
->parent
->file
->date
) >= 0)
166 * If the first commit is older than the last element
167 * of the vendor branch, paste them together and
168 * nuke the vendor branch
170 if (time_compare (vlast
->file
->date
,
178 * Splice out any portion of the vendor branch
179 * newer than a the next trunk commit after
180 * the oldest branch commit.
182 for (vp
= &vendor
->commit
; (v
= *vp
); vp
= &v
->parent
)
183 if (time_compare (v
->date
, t
->date
) <= 0)
185 if (vp
== &vendor
->commit
)
188 * Nothing newer, nuke vendor branch
195 * Some newer stuff, patch parent
204 * Patch up the remaining vendor branch pieces
209 char rev
[CVS_MAX_REV_LEN
];
210 char name
[MAXPATHLEN
];
213 branch
= vlast
->file
->number
;
215 cvs_number_string (&branch
, rev
);
216 snprintf (name
, sizeof (name
),
218 vendor
->name
= atom (name
);
219 vendor
->parent
= trunk
;
220 vendor
->degree
= vlast
->file
->number
.c
;
222 for (vr
= vendor
->commit
; vr
; vr
= vr
->parent
)
233 * Merge two branches based on dates
237 if (time_compare (v
->file
->date
,
264 fprintf (stderr
, "%s spliced:\n", cvs
->name
);
265 for (t
= trunk
->commit
; t
; t
= t
->parent
) {
266 dump_number_file (stderr
, "\t", &t
->file
->number
);
267 fprintf (stderr
, "\n");
273 * Given a disconnected set of branches, graft the bottom
274 * of each branch where it belongs on the parent branch
278 rev_list_graft_branches (rev_list
*rl
, cvs_file
*cvs
)
286 * Glue branches together
288 for (h
= rl
->heads
; h
; h
= h
->next
) {
290 * skip master branch; it "can't" join
291 * any other branches and it may well end with a vendor
292 * branch revision of the file, which will then create
293 * a loop back to the recorded branch point
300 * Find last commit on branch
302 for (c
= h
->commit
; c
&& c
->parent
; c
= c
->parent
)
304 c
= NULL
; /* already been done, skip */
309 * Walk the version tree, looking for the branch location.
310 * Note that in the presense of vendor branches, the
311 * branch location may actually be out on that vendor branch
313 for (cv
= cvs
->versions
; cv
; cv
= cv
->next
) {
314 for (cb
= cv
->branches
; cb
; cb
= cb
->next
) {
315 if (cvs_number_compare (&cb
->number
,
316 &c
->file
->number
) == 0)
318 c
->parent
= rev_find_cvs_commit (rl
, &cv
->number
);
327 * check for a parallel vendor branch
329 for (cb
= cv
->branches
; cb
; cb
= cb
->next
) {
330 if (cvs_is_vendor (&cb
->number
)) {
332 rev_commit
*v_c
, *n_v_c
;
333 fprintf (stderr
, "Found merge into vendor branch\n");
337 * Walk to head of vendor branch
339 while ((n_v_c
= rev_find_cvs_commit (rl
, &v_n
)))
342 * Stop if we reach a date after the
343 * branch version date
345 if (time_compare (n_v_c
->date
, c
->date
) > 0)
352 fprintf (stderr
, "%s: rewrite branch", cvs
->name
);
353 dump_number_file (stderr
, " branch point",
355 dump_number_file (stderr
, " branch version",
357 fprintf (stderr
, "\n");
371 * For each symbol, locate the appropriate commit
375 rev_list_find_branch (rev_list
*rl
, cvs_number
*number
)
386 for (h
= rl
->heads
; h
; h
= h
->next
) {
387 if (cvs_same_branch (&h
->number
, &n
)) {
399 rev_list_set_refs (rev_list
*rl
, cvs_file
*cvs
)
406 * Locate a symbolic name for this head
408 for (s
= cvs
->symbols
; s
; s
= s
->next
) {
410 if (cvs_is_head (&s
->number
)) {
411 for (h
= rl
->heads
; h
; h
= h
->next
) {
412 if (cvs_same_branch (&h
->commit
->file
->number
, &s
->number
))
418 h
->degree
= cvs_number_degree (&s
->number
);
420 h
= rev_list_add_head (rl
, h
->commit
, s
->name
,
421 cvs_number_degree (&s
->number
));
428 c
= rev_find_cvs_commit (rl
, &n
);
433 h
= rev_list_add_head (rl
, c
, s
->name
,
434 cvs_number_degree (&s
->number
));
437 h
->number
= s
->number
;
439 c
= rev_find_cvs_commit (rl
, &s
->number
);
441 tag_commit(c
, s
->name
);
445 * Fix up unnamed heads
447 for (h
= rl
->heads
; h
; h
= h
->next
) {
453 for (c
= h
->commit
; c
; c
= c
->parent
) {
460 /* convert to branch form */
461 n
.n
[n
.c
-1] = n
.n
[n
.c
-2];
464 h
->degree
= cvs_number_degree (&n
);
465 /* compute name after patching parents */
468 * Link heads together in a tree
470 for (h
= rl
->heads
; h
; h
= h
->next
) {
473 if (h
->number
.c
>= 4) {
476 h
->parent
= rev_list_find_branch (rl
, &n
);
477 if (!h
->parent
&& ! cvs_is_vendor (&h
->number
))
478 fprintf (stderr
, "Warning: %s: branch %s has no parent\n",
481 if (h
->parent
&& !h
->name
) {
483 char rev
[CVS_MAX_REV_LEN
];
485 cvs_number_string (&h
->number
, rev
);
486 fprintf (stderr
, "Warning: %s: unnamed branch %s from %s\n",
487 cvs
->name
, rev
, h
->parent
->name
);
488 sprintf (name
, "%s-UNNAMED-BRANCH", h
->parent
->name
);
489 h
->name
= atom (name
);
495 * Dead file revisions get an extra rev_file object which may be
496 * needed during branch merging. Clean those up before returning
497 * the resulting rev_list
501 rev_list_free_dead_files (rev_list
*rl
)
506 for (h
= rl
->heads
; h
; h
= h
->next
) {
509 for (c
= h
->commit
; c
; c
= c
->parent
) {
510 if (c
->nfiles
== 0) {
511 rev_file_free (c
->file
);
522 rev_order_compare (cvs_number
*a
, cvs_number
*b
)
526 return cvs_number_compare (b
, a
);
531 cvs_find_symbol (cvs_file
*cvs
, char *name
)
535 for (s
= cvs
->symbols
; s
; s
= s
->next
)
542 cvs_symbol_compare (cvs_symbol
*a
, cvs_symbol
*b
)
550 return cvs_number_compare (&a
->number
, &b
->number
);
554 rev_list_dump_ref_parents (FILE *f
, rev_ref
*h
)
557 rev_list_dump_ref_parents (f
, h
->parent
);
558 fprintf (f
, "%s > ", h
->name
);
563 rev_list_sort_heads (rev_list
*rl
, cvs_file
*cvs
)
566 cvs_symbol
*hs
, *hns
;
568 for (hp
= &rl
->heads
; (h
= *hp
);) {
571 hs
= cvs_find_symbol (cvs
, h
->name
);
572 hns
= cvs_find_symbol (cvs
, h
->next
->name
);
573 if (cvs_symbol_compare (hs
, hns
) > 0) {
575 h
->next
= h
->next
->next
;
583 fprintf (stderr
, "Sorted heads for %s\n", cvs
->name
);
584 for (h
= rl
->heads
; h
;) {
585 fprintf (stderr
, "\t");
586 rev_list_dump_ref_parents (stderr
, h
->parent
);
587 dump_number_file (stderr
, h
->name
, &h
->number
);
588 fprintf (stderr
, "\n");
595 rev_list_cvs (cvs_file
*cvs
)
597 rev_list
*rl
= calloc (1, sizeof (rev_list
));
598 cvs_number trunk_number
;
604 cvs_version
*ctrunk
= NULL
;
608 * Locate first revision on trunk branch
610 for (cv
= cvs
->versions
; cv
; cv
= cv
->next
) {
611 if (cvs_is_trunk (&cv
->number
) &&
612 (!ctrunk
|| cvs_number_compare (&cv
->number
,
613 &ctrunk
->number
) < 0))
619 * Generate trunk branch
622 trunk_number
= ctrunk
->number
;
624 trunk_number
= lex_number ("1.1");
625 trunk
= rev_branch_cvs (cvs
, &trunk_number
);
627 t
= rev_list_add_head (rl
, trunk
, atom ("master"), 2);
628 t
->number
= trunk_number
;
631 * Search for other branches
634 printf ("building branches for %s\n", cvs
->name
);
637 for (cv
= cvs
->versions
; cv
; cv
= cv
->next
) {
638 for (cb
= cv
->branches
; cb
; cb
= cb
->next
)
640 branch
= rev_branch_cvs (cvs
, &cb
->number
);
641 rev_list_add_head (rl
, branch
, NULL
, 0);
645 rev_list_patch_vendor_branch (rl
, cvs
);
646 rev_list_graft_branches (rl
, cvs
);
647 rev_list_set_refs (rl
, cvs
);
648 rev_list_sort_heads (rl
, cvs
);
649 rev_list_set_tail (rl
);
650 rev_list_free_dead_files (rl
);
651 rev_list_validate (rl
);