cvsserver: generalize getmeta() to recognize commit refs
This allows getmeta() to recognize any commitish (sha1, tag/branch name, etc). Signed-off-by: Matthew Ogilvie <mmogilvi_git@miniinfo.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
eb5dcb2c02
commit
bfdafa099e
@ -4041,6 +4041,19 @@ sub getlog
|
||||
This function takes a filename (with path) argument and returns a hashref of
|
||||
metadata for that file.
|
||||
|
||||
There are several ways $revision can be specified:
|
||||
|
||||
- A reference to hash that contains a "tag" that is the
|
||||
actual revision (one of the below). TODO: Also allow it to
|
||||
specify a "date" in the hash.
|
||||
- undef, to refer to the latest version on the main branch.
|
||||
- Full CVS client revision number (mapped to integer in DB, without the
|
||||
"1." prefix),
|
||||
- Complex CVS-compatible "special" revision number for
|
||||
non-linear history (see comment below)
|
||||
- git commit sha1 hash
|
||||
- branch or tag name
|
||||
|
||||
=cut
|
||||
|
||||
sub getmeta
|
||||
@ -4051,23 +4064,144 @@ sub getmeta
|
||||
my $tablename_rev = $self->tablename("revision");
|
||||
my $tablename_head = $self->tablename("head");
|
||||
|
||||
my $db_query;
|
||||
if ( defined($revision) and $revision =~ /^1\.(\d+)$/ )
|
||||
if ( ref($revision) eq "HASH" )
|
||||
{
|
||||
my ($intRev) = $1;
|
||||
$db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND revision=?",{},1);
|
||||
$db_query->execute($filename, $intRev);
|
||||
}
|
||||
elsif ( defined($revision) and $revision =~ /^[a-zA-Z0-9]{40}$/ )
|
||||
{
|
||||
$db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND commithash=?",{},1);
|
||||
$db_query->execute($filename, $revision);
|
||||
} else {
|
||||
$db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_head WHERE name=?",{},1);
|
||||
$db_query->execute($filename);
|
||||
$revision = $revision->{tag};
|
||||
}
|
||||
|
||||
# Overview of CVS revision numbers:
|
||||
#
|
||||
# General CVS numbering scheme:
|
||||
# - Basic mainline branch numbers: "1.1", "1.2", "1.3", etc.
|
||||
# - Result of "cvs checkin -r" (possible, but not really
|
||||
# recommended): "2.1", "2.2", etc
|
||||
# - Branch tag: "1.2.0.n", where "1.2" is revision it was branched
|
||||
# from, "0" is a magic placeholder that identifies it as a
|
||||
# branch tag instead of a version tag, and n is 2 times the
|
||||
# branch number off of "1.2", starting with "2".
|
||||
# - Version on a branch: "1.2.n.x", where "1.2" is branch-from, "n"
|
||||
# is branch number off of "1.2" (like n above), and "x" is
|
||||
# the version number on the branch.
|
||||
# - Branches can branch off of branches: "1.3.2.7.4.1" (even number
|
||||
# of components).
|
||||
# - Odd "n"s are used by "vendor branches" that result
|
||||
# from "cvs import". Vendor branches have additional
|
||||
# strangeness in the sense that the main rcs "head" of the main
|
||||
# branch will (temporarily until first normal commit) point
|
||||
# to the version on the vendor branch, rather than the actual
|
||||
# main branch. (FUTURE: This may provide an opportunity
|
||||
# to use "strange" revision numbers for fast-forward-merged
|
||||
# branch tip when CVS client is asking for the main branch.)
|
||||
#
|
||||
# git-cvsserver CVS-compatible special numbering schemes:
|
||||
# - Currently git-cvsserver only tries to be identical to CVS for
|
||||
# simple "1.x" numbers on the "main" branch (as identified
|
||||
# by the module name that was originally cvs checkout'ed).
|
||||
# - The database only stores the "x" part, for historical reasons.
|
||||
# But most of the rest of the cvsserver preserves
|
||||
# and thinks using the full revision number.
|
||||
# - To handle non-linear history, it uses a version of the form
|
||||
# "2.1.1.2000.b.b.b."..., where the 2.1.1.2000 is to help uniquely
|
||||
# identify this as a special revision number, and there are
|
||||
# 20 b's that together encode the sha1 git commit from which
|
||||
# this version of this file originated. Each b is
|
||||
# the numerical value of the corresponding byte plus
|
||||
# 100.
|
||||
# - "plus 100" avoids "0"s, and also reduces the
|
||||
# likelyhood of a collision in the case that someone someday
|
||||
# writes an import tool that tries to preserve original
|
||||
# CVS revision numbers, and the original CVS data had done
|
||||
# lots of branches off of branches and other strangeness to
|
||||
# end up with a real version number that just happens to look
|
||||
# like this special revision number form. Also, if needed
|
||||
# there are several ways to extend/identify alternative encodings
|
||||
# within the "2.1.1.2000" part if necessary.
|
||||
# - Unlike real CVS revisions, you can't really reconstruct what
|
||||
# relation a revision of this form has to other revisions.
|
||||
# - FUTURE: TODO: Rework database somehow to make up and remember
|
||||
# fully-CVS-compatible branches and branch version numbers.
|
||||
|
||||
my $meta;
|
||||
if ( defined($revision) )
|
||||
{
|
||||
if ( $revision =~ /^1\.(\d+)$/ )
|
||||
{
|
||||
my ($intRev) = $1;
|
||||
my $db_query;
|
||||
$db_query = $self->{dbh}->prepare_cached(
|
||||
"SELECT * FROM $tablename_rev WHERE name=? AND revision=?",
|
||||
{},1);
|
||||
$db_query->execute($filename, $intRev);
|
||||
$meta = $db_query->fetchrow_hashref;
|
||||
}
|
||||
elsif ( $revision =~ /^2\.1\.1\.2000(\.[1-3][0-9][0-9]){20}$/ )
|
||||
{
|
||||
my ($commitHash)=($revision=~/^2\.1\.1\.2000(.*)$/);
|
||||
$commitHash=~s/\.([0-9]+)/sprintf("%02x",$1-100)/eg;
|
||||
if($commitHash=~/^[0-9a-f]{40}$/)
|
||||
{
|
||||
return $self->getMetaFromCommithash($filename,$commitHash);
|
||||
}
|
||||
|
||||
# error recovery: fall back on head version below
|
||||
print "E Failed to find $filename version=$revision or commit=$commitHash\n";
|
||||
$log->warning("failed get $revision with commithash=$commitHash");
|
||||
undef $revision;
|
||||
}
|
||||
elsif ( $revision =~ /^[0-9a-f]{40}$/ )
|
||||
{
|
||||
# Try DB first. This is mostly only useful for req_annotate(),
|
||||
# which only calls this for stuff that should already be in
|
||||
# the DB. It is fairly likely to be a waste of time
|
||||
# in most other cases [unless the file happened to be
|
||||
# modified in $revision specifically], but
|
||||
# it is probably in the noise compared to how long
|
||||
# getMetaFromCommithash() will take.
|
||||
my $db_query;
|
||||
$db_query = $self->{dbh}->prepare_cached(
|
||||
"SELECT * FROM $tablename_rev WHERE name=? AND commithash=?",
|
||||
{},1);
|
||||
$db_query->execute($filename, $revision);
|
||||
$meta = $db_query->fetchrow_hashref;
|
||||
|
||||
if(! $meta)
|
||||
{
|
||||
my($revCommit)=$self->lookupCommitRef($revision);
|
||||
if($revCommit=~/^[0-9a-f]{40}$/)
|
||||
{
|
||||
return $self->getMetaFromCommithash($filename,$revCommit);
|
||||
}
|
||||
|
||||
# error recovery: nothing found:
|
||||
print "E Failed to find $filename version=$revision\n";
|
||||
$log->warning("failed get $revision");
|
||||
return $meta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my($revCommit)=$self->lookupCommitRef($revision);
|
||||
if($revCommit=~/^[0-9a-f]{40}$/)
|
||||
{
|
||||
return $self->getMetaFromCommithash($filename,$revCommit);
|
||||
}
|
||||
|
||||
# error recovery: fall back on head version below
|
||||
print "E Failed to find $filename version=$revision\n";
|
||||
$log->warning("failed get $revision");
|
||||
undef $revision; # Allow fallback
|
||||
}
|
||||
}
|
||||
|
||||
if(!defined($revision))
|
||||
{
|
||||
my $db_query;
|
||||
$db_query = $self->{dbh}->prepare_cached(
|
||||
"SELECT * FROM $tablename_head WHERE name=?",{},1);
|
||||
$db_query->execute($filename);
|
||||
$meta = $db_query->fetchrow_hashref;
|
||||
}
|
||||
|
||||
my $meta = $db_query->fetchrow_hashref;
|
||||
if($meta)
|
||||
{
|
||||
$meta->{revision} = "1.$meta->{revision}";
|
||||
|
Loading…
Reference in New Issue
Block a user