Exemple #1
0
static void
rev_list_sort_heads (rev_list *rl, cvs_file *cvs)
{
    rev_ref	*h, **hp;
    cvs_symbol	*hs, *hns;

    for (hp = &rl->heads; (h = *hp);) {
	if (!h->next)
	    break;
	hs = cvs_find_symbol (cvs, h->name);
	hns = cvs_find_symbol (cvs, h->next->name);
	if (cvs_symbol_compare (hs, hns) > 0) {
	    *hp = h->next;
	    h->next = h->next->next;
	    (*hp)->next = h;
	    hp = &rl->heads;
	} else {
	    hp = &h->next;
	}
    }
#if DEBUG
    fprintf (stderr, "Sorted heads for %s\n", cvs->name);
    for (h = rl->heads; h;) {
	fprintf (stderr, "\t");
	rev_list_dump_ref_parents (stderr, h->parent);
	dump_number_file (stderr, h->name, &h->number);
	fprintf (stderr, "\n");
	h = h->next;
    }
#endif
}
Exemple #2
0
static void
rev_commit_dump (FILE *f, char *title, rev_commit *c, rev_commit *m)
{
    fprintf (f, "\n%s\n", title);
    while (c) {
	int	i;

	fprintf (f, "%c0x%x %s\n", c == m ? '>' : ' ',
		(int) c, ctime_nonl (&c->date));
	for (i = 0; i < c->nfiles; i++) {
	    fprintf (f, "\t%s", ctime_nonl (&c->files[i]->date));
	    dump_number_file (f, c->files[i]->name, &c->files[i]->number);
	    fprintf (f, "\n");
	}
	fprintf (f, "\n");
	c = c->parent;
    }
}
Exemple #3
0
/*
 * Construct a branch using CVS revision numbers
 */
static rev_commit *
rev_branch_cvs (cvs_file *cvs, cvs_number *branch)
{
    cvs_number	n;
    rev_commit	*head = NULL;
    rev_commit	*c, *p, *gc;
    Node	*node;

    n = *branch;
    n.n[n.c-1] = -1;
    for (node = cvs_find_version (cvs, &n); node; node = node->next) {
	cvs_version *v = node->v;
	cvs_patch *p = node->p;
	rev_commit *c;
	if (!v)
	     continue;
	c = calloc (1, sizeof (rev_commit));
	c->date = v->date;
	c->commitid = v->commitid;
	c->author = v->author;
	if (p)
	    c->log = p->log;
	if (v->dead)
	    c->nfiles = 0;
	else
	    c->nfiles = 1;
	/* leave this around so the branch merging stuff can find numbers */
	c->file = rev_file_rev (cvs->name, &v->number, v->date);
	if (!v->dead) {
	    node->file = c->file;
	    c->file->mode = cvs->mode;
	}
	c->parent = head;
	head = c;
    }

    /*
     * Make sure the dates along the branch are well ordered. As we
     * want to preserve current data, push previous versions back to
     * align with newer revisions.
     */
    for (c = head, gc = NULL; (p = c->parent); gc = c, c = p) {
	if (time_compare (p->file->date, c->file->date) > 0)
	{
	    fprintf (stderr, "Warning: %s:", cvs->name);
	    dump_number_file (stderr, " ", &p->file->number);
	    dump_number_file (stderr, " is newer than", &c->file->number);

	    /* Try to catch an odd one out, such as a commit with the
	     * clock set wrong.  Dont push back all commits for that,
	     * just fix up the current commit instead of the
	     * parent. */
	    if (gc && time_compare (p->file->date, gc->file->date) <= 0)
	    {
	      dump_number_file (stderr, ", adjusting", &c->file->number);
	      c->file->date = p->file->date;
	      c->date = p->date;
	    } else {
	      dump_number_file (stderr, ", adjusting", &c->file->number);
	      p->file->date = c->file->date;
	      p->date = c->date;
	    }
	    fprintf (stderr, "\n");
	}
    }

    return head;
}
Exemple #4
0
static void
rev_list_graft_branches (rev_list *rl, cvs_file *cvs)
{
    rev_ref	*h;
    rev_commit	*c;
    cvs_version	*cv;
    cvs_branch	*cb;

    /*
     * Glue branches together
     */
    for (h = rl->heads; h; h = h->next) {
	/*
	 * skip master branch; it "can't" join
	 * any other branches and it may well end with a vendor
	 * branch revision of the file, which will then create
	 * a loop back to the recorded branch point
	 */
        if (h == rl->heads)
	    continue;
	if (h->tail)
	    continue;
	/*
	 * Find last commit on branch
	 */
	for (c = h->commit; c && c->parent; c = c->parent)
	    if (c->tail) {
		c = NULL;	/* already been done, skip */
		break;
	    }
	if (c) {
	    /*
	     * Walk the version tree, looking for the branch location.
	     * Note that in the presense of vendor branches, the
	     * branch location may actually be out on that vendor branch
	     */
	    for (cv = cvs->versions; cv; cv = cv->next) {
		for (cb = cv->branches; cb; cb = cb->next) {
		    if (cvs_number_compare (&cb->number,
					    &c->file->number) == 0)
		    {
			c->parent = rev_find_cvs_commit (rl, &cv->number);
			c->tail = 1;
			break;
		    }
		}
		if (c->parent)
		{
#if 0
		    /*
		     * check for a parallel vendor branch
		     */
		    for (cb = cv->branches; cb; cb = cb->next) {
			if (cvs_is_vendor (&cb->number)) {
			    cvs_number	v_n;
			    rev_commit	*v_c, *n_v_c;
			    fprintf (stderr, "Found merge into vendor branch\n");
			    v_n = cb->number;
			    v_c = NULL;
			    /*
			     * Walk to head of vendor branch
			     */
			    while ((n_v_c = rev_find_cvs_commit (rl, &v_n)))
			    {
				/*
				 * Stop if we reach a date after the
				 * branch version date
				 */
				if (time_compare (n_v_c->date, c->date) > 0)
				    break;
				v_c = n_v_c;
				v_n.n[v_n.c - 1]++;
			    }
			    if (v_c)
			    {
				fprintf (stderr, "%s: rewrite branch", cvs->name);
				dump_number_file (stderr, " branch point",
						  &v_c->file->number);
				dump_number_file (stderr, " branch version",
						  &c->file->number);
				fprintf (stderr, "\n");
				c->parent = v_c;
			    }
			}
		    }
#endif
		    break;
		}
	    }
	}
    }
}
Exemple #5
0
/*
 * "Vendor branches" (1.1.x) are created by importing sources from
 * an external source. In X.org, this was from XFree86 and DRI. When
 * these trees are imported, cvs sets the 'default' branch in each ,v file
 * to point along this branch. This means that tags made between
 * the time the vendor branch is imported and when a new revision
 * is committed to the head branch are placed on the vendor branch
 * In addition, any files without such a commit appear to adopt
 * the vendor branch as 'head'. We fix this by merging these two
 * branches together as if they were the same
 */
static void
rev_list_patch_vendor_branch (rev_list *rl, cvs_file *cvs)
{
    rev_ref	*trunk = NULL;
    rev_ref	*vendor = NULL;
    rev_ref	*h;
    rev_commit	*t, **tp, *v, **vp;
    rev_commit	*vlast;
    rev_ref	**h_p;
    int		delete_head;

    trunk = rl->heads;
    for (h_p = &rl->heads; (h = *h_p);) {
	delete_head = 0;
	if (h->commit && cvs_is_vendor (&h->commit->file->number))
	{
	    /*
	     * Find version 1.2 on the trunk.
	     * This will reset the default branch set
	     * when the initial import was done.
	     * Subsequent imports will *not* set the default
	     * branch, and should be on their own branch
	     */
	    vendor = h;
	    t = trunk->commit;
	    v = vendor->commit;
	    for (vlast = vendor->commit; vlast; vlast = vlast->parent)
		if (!vlast->parent)
		    break;
	    tp = &trunk->commit;
	    /*
	     * Find the latest trunk revision older than
	     * the entire vendor branch
	     */
	    while ((t = *tp))
	    {
		if (!t->parent || 
		    time_compare (vlast->file->date,
				  t->parent->file->date) >= 0)
		{
		    break;
		}
		tp = &t->parent;
	    }
	    if (t)
	    {
		/*
		 * If the first commit is older than the last element
		 * of the vendor branch, paste them together and
		 * nuke the vendor branch
		 */
		if (time_compare (vlast->file->date,
				  t->file->date) >= 0)
		{
		    delete_head = 1;
		}
		else
		{
		    /*
		     * Splice out any portion of the vendor branch
		     * newer than a the next trunk commit after
		     * the oldest branch commit.
		     */
		    for (vp = &vendor->commit; (v = *vp); vp = &v->parent)
			if (time_compare (v->date, t->date) <= 0)
			    break;
		    if (vp == &vendor->commit)
		    {
			/*
			 * Nothing newer, nuke vendor branch
			 */
			delete_head = 1;
		    }
		    else
		    {
			/*
			 * Some newer stuff, patch parent
			 */
			*vp = NULL;
		    }
		}
	    }
	    else
		delete_head = 1;
	    /*
	     * Patch up the remaining vendor branch pieces
	     */
	    if (!delete_head) {
		rev_commit  *vr;
		if (!vendor->name) {
		    char	rev[CVS_MAX_REV_LEN];
		    char	name[MAXPATHLEN];
		    cvs_number	branch;

		    branch = vlast->file->number;
		    branch.c--;
		    cvs_number_string (&branch, rev);
		    snprintf (name, sizeof (name),
			      "import-%s", rev);
		    vendor->name = atom (name);
		    vendor->parent = trunk;
		    vendor->degree = vlast->file->number.c;
		}
		for (vr = vendor->commit; vr; vr = vr->parent)
		{
		    if (!vr->parent) {
			vr->tail = 1;
			vr->parent = v;
			break;
		    }
		}
	    }
	    
	    /*
	     * Merge two branches based on dates
	     */
	    while (t && v)
	    {
		if (time_compare (v->file->date,
				  t->file->date) >= 0)
		{
		    *tp = v;
		    tp = &v->parent;
		    v = v->parent;
		}
		else
		{
		    *tp = t;
		    tp = &t->parent;
		    t = t->parent;
		}
	    }
	    if (t)
		*tp = t;
	    else
		*tp = v;
	}
	if (delete_head) {
	    *h_p = h->next;
	    free (h);
	} else {
	    h_p = &(h->next);
	}
    }
#if DEBUG
    fprintf (stderr, "%s spliced:\n", cvs->name);
    for (t = trunk->commit; t; t = t->parent) {
	dump_number_file (stderr, "\t", &t->file->number);
	fprintf (stderr, "\n");
    }
#endif
}
Exemple #6
0
/*
 * Merge a set of per-file branches into a global branch
 */
static void
rev_branch_merge (rev_ref **branches, int nbranch,
		  rev_ref *branch, rev_list *rl)
{
	int nlive;
	int n;
	rev_commit *prev = NULL;
	rev_commit *head = NULL, **tail = &head;
	rev_commit **commits;
	rev_commit *commit;
	rev_commit *latest;
	rev_commit **p;
	int lazy = 0;
	time_t start = 0;

	ALLOC((commits = calloc (nbranch, sizeof (rev_commit *))), "rev_branch_merge");
	nlive = 0;

//	printf("rev_branch_merge: nbranch=%d\n", nbranch);
	
	for (n = 0; n < nbranch; n++) {
		rev_commit *c;
		/*
		 * Initialize commits to head of each branch
		 */
		c = commits[n] = branches[n]->commit;
		/*
		* Compute number of branches with remaining entries
		*/
		if (!c)
			continue;
		if (branches[n]->tail) {
			c->tailed = 1;
			continue;
		}
		nlive++;
		while (c && !c->tail) {
			if (!start || time_compare(c->date, start) < 0)
			    {
//				printf("  1:setting start=%ld:%s (from %s)\n", start, ctime_nonl(&start), c->file->name);
				start = c->date;
			    }
			c = c->parent;
		}
		if (c && (c->file || c->date != c->parent->date)) {
			if (!start || time_compare(c->date, start) < 0) {
//				printf("  2:setting start=%ld:%s (from %s)\n", start, ctime_nonl(&start), c->file->name);
				start = c->date;
			}
		}
	}

	for (n = 0; n < nbranch; n++) {
		rev_commit *c = commits[n];

#if 0
		printf("Doing commit %p: @ %ld\n", c, c->date);
		if (c->file) printf("  %s\n", c->file->name);
#endif
		
		if (!c->tailed)
			continue;
		if (!start || time_compare(start, c->date) >= 0)
			continue;
		if (c->file) {
		    /*
		      This case can occur if files have been added to
		      a branch since it's creation.
		    */
			printf(	"Warning: %s too late date %s through branch %s (%ld:%ld=%ld)\n",
				c->file->name, ctime_nonl(&c->date), branch->name, start, c->date, start-c->date);
			continue;
		}
		commits[n] = NULL;
	}
	/*
	 * Walk down branches until each one has merged with the
	 * parent branch
	 */
	while (nlive > 0 && nbranch > 0) {
		for (n = 0, p = commits, latest = NULL; n < nbranch; n++) {
			rev_commit *c = commits[n];
			if (!c)
				continue;
			*p++ = c;
			if (c->tailed)
				continue;
			if (!latest || time_compare(latest->date, c->date) < 0)
				latest = c;
		}
		nbranch = p - commits;

		/*
		 * Construct current commit
		 */
		if (!lazy) {
			commit = rev_commit_build (commits, latest, nbranch);
			if (rev_mode == ExecuteGit)
				lazy = 1;
		} else {
			commit = create_tree(latest);
		}

		/*
		 * Step each branch
		 */
		nlive = 0;
		for (n = 0; n < nbranch; n++) {
			rev_commit *c = commits[n];
			rev_commit *to;
			/* already got to parent branch? */
			if (c->tailed)
				continue;
			/* not affected? */
			if (c != latest && !rev_commit_match(c, latest)) {
				if (c->parent || c->file)
					nlive++;
				continue;
			}
			to = c->parent;
			/* starts here? */
			if (!to)
				goto Kill;

			if (c->tail) {
				/*
				 * Adding file independently added on another
				 * non-trunk branch.
				 */
				if (!to->parent && !to->file)
					goto Kill;
				/*
				 * If the parent is at the beginning of trunk
				 * and it is younger than some events on our
				 * branch, we have old CVS adding file
				 * independently
				 * added on another branch.
				 */
				if (start && time_compare(start, to->date) < 0)
					goto Kill;
				/*
				 * XXX: we still can't be sure that it's
				 * not a file added on trunk after parent
				 * branch had forked off it but before
				 * our branch's creation.
				 */
				to->tailed = 1;
			} else if (to->file) {
				nlive++;
			} else {
				/*
				 * See if it's recent CVS adding a file
				 * independently added on another branch.
				 */
				if (!to->parent)
					goto Kill;
				if (to->tail && to->date == to->parent->date)
					goto Kill;
				nlive++;
			}
			if (to->file)
				set_commit(to);
			else
				delete_commit(c);
			commits[n] = to;
			continue;
Kill:
			delete_commit(c);
			commits[n] = NULL;
		}

		*tail = commit;
		tail = &commit->parent;
		prev = commit;
	}
    /*
     * Connect to parent branch
     */
    nbranch = rev_commit_date_sort (commits, nbranch);
    if (nbranch && branch->parent )
    {
	rev_ref	*lost;
	int	present;

//	present = 0;
	for (present = 0; present < nbranch; present++)
	    if (commits[present]->file) {
		/*
		 * Skip files which appear in the repository after
		 * the first commit along the branch
		 */
		if (prev && commits[present]->date > prev->date &&
		    commits[present]->date == rev_commit_first_date (commits[present]))
		{
		    fprintf (stderr, "Warning: file %s appears after branch %s date\n",
			     commits[present]->file->name, branch->name);
		    continue;
		}
		break;
	    }
	if (present == nbranch)
	    *tail = NULL;
	else if ((*tail = rev_commit_locate_one (branch->parent,
						 commits[present])))
	{
	    if (prev && time_compare ((*tail)->date, prev->date) > 0) {
		fprintf (stderr, "Warning: branch point %s -> %s later than branch\n",
			 branch->name, branch->parent->name);
		fprintf (stderr, "\ttrunk(%3d):  %s %s", n,
			 ctime_nonl (&commits[present]->date),
			 commits[present]->file ? " " : "D" );
		if (commits[present]->file)
		    dump_number_file (stderr,
				      commits[present]->file->name,
				      &commits[present]->file->number);
		fprintf (stderr, "\n");
		fprintf (stderr, "\tbranch(%3d): %s  ", n,
			 prev->file?ctime_nonl (&prev->file->date):"no file");
		if (prev->file) {
		    dump_number_file (stderr,
				  prev->file->name,
				  &prev->file->number);
		}
		fprintf (stderr, "\n");
	    }
	} else if ((*tail = rev_commit_locate_date (branch->parent,
						  commits[present]->date)))
	    fprintf (stderr, "Warning: branch point %s -> %s matched by date\n",
		     branch->name, branch->parent->name);
	else {
	    fprintf (stderr, "Error: branch point %s -> %s not found.",
		     branch->name, branch->parent->name);

	    if ((lost = rev_branch_of_commit (rl, commits[present])))
		fprintf (stderr, " Possible match on %s.", lost->name);
	    fprintf (stderr, "\n");
	}
	if (*tail) {
	    if (prev)
		prev->tail = 1;
	} else 
	    *tail = rev_commit_build (commits, commits[0], nbranch);
    }
    for (n = 0; n < nbranch; n++)
	if (commits[n])
	    commits[n]->tailed = 0;
    free (commits);
    branch->commit = head;
}