Skip to content

Commit bfdafa0

Browse files
Matthew Ogilviegitster
authored andcommitted
cvsserver: generalize getmeta() to recognize commit refs
This allows getmeta() to recognize any commitish (sha1, tag/branch name, etc). Signed-off-by: Matthew Ogilvie <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent eb5dcb2 commit bfdafa0

File tree

1 file changed

+145
-11
lines changed

1 file changed

+145
-11
lines changed

git-cvsserver.perl

Lines changed: 145 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4041,6 +4041,19 @@ =head2 getmeta
40414041
This function takes a filename (with path) argument and returns a hashref of
40424042
metadata for that file.
40434043
4044+
There are several ways $revision can be specified:
4045+
4046+
- A reference to hash that contains a "tag" that is the
4047+
actual revision (one of the below). TODO: Also allow it to
4048+
specify a "date" in the hash.
4049+
- undef, to refer to the latest version on the main branch.
4050+
- Full CVS client revision number (mapped to integer in DB, without the
4051+
"1." prefix),
4052+
- Complex CVS-compatible "special" revision number for
4053+
non-linear history (see comment below)
4054+
- git commit sha1 hash
4055+
- branch or tag name
4056+
40444057
=cut
40454058

40464059
sub getmeta
@@ -4051,23 +4064,144 @@ sub getmeta
40514064
my $tablename_rev = $self->tablename("revision");
40524065
my $tablename_head = $self->tablename("head");
40534066

4054-
my $db_query;
4055-
if ( defined($revision) and $revision =~ /^1\.(\d+)$/ )
4067+
if ( ref($revision) eq "HASH" )
40564068
{
4057-
my ($intRev) = $1;
4058-
$db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND revision=?",{},1);
4059-
$db_query->execute($filename, $intRev);
4069+
$revision = $revision->{tag};
4070+
}
4071+
4072+
# Overview of CVS revision numbers:
4073+
#
4074+
# General CVS numbering scheme:
4075+
# - Basic mainline branch numbers: "1.1", "1.2", "1.3", etc.
4076+
# - Result of "cvs checkin -r" (possible, but not really
4077+
# recommended): "2.1", "2.2", etc
4078+
# - Branch tag: "1.2.0.n", where "1.2" is revision it was branched
4079+
# from, "0" is a magic placeholder that identifies it as a
4080+
# branch tag instead of a version tag, and n is 2 times the
4081+
# branch number off of "1.2", starting with "2".
4082+
# - Version on a branch: "1.2.n.x", where "1.2" is branch-from, "n"
4083+
# is branch number off of "1.2" (like n above), and "x" is
4084+
# the version number on the branch.
4085+
# - Branches can branch off of branches: "1.3.2.7.4.1" (even number
4086+
# of components).
4087+
# - Odd "n"s are used by "vendor branches" that result
4088+
# from "cvs import". Vendor branches have additional
4089+
# strangeness in the sense that the main rcs "head" of the main
4090+
# branch will (temporarily until first normal commit) point
4091+
# to the version on the vendor branch, rather than the actual
4092+
# main branch. (FUTURE: This may provide an opportunity
4093+
# to use "strange" revision numbers for fast-forward-merged
4094+
# branch tip when CVS client is asking for the main branch.)
4095+
#
4096+
# git-cvsserver CVS-compatible special numbering schemes:
4097+
# - Currently git-cvsserver only tries to be identical to CVS for
4098+
# simple "1.x" numbers on the "main" branch (as identified
4099+
# by the module name that was originally cvs checkout'ed).
4100+
# - The database only stores the "x" part, for historical reasons.
4101+
# But most of the rest of the cvsserver preserves
4102+
# and thinks using the full revision number.
4103+
# - To handle non-linear history, it uses a version of the form
4104+
# "2.1.1.2000.b.b.b."..., where the 2.1.1.2000 is to help uniquely
4105+
# identify this as a special revision number, and there are
4106+
# 20 b's that together encode the sha1 git commit from which
4107+
# this version of this file originated. Each b is
4108+
# the numerical value of the corresponding byte plus
4109+
# 100.
4110+
# - "plus 100" avoids "0"s, and also reduces the
4111+
# likelyhood of a collision in the case that someone someday
4112+
# writes an import tool that tries to preserve original
4113+
# CVS revision numbers, and the original CVS data had done
4114+
# lots of branches off of branches and other strangeness to
4115+
# end up with a real version number that just happens to look
4116+
# like this special revision number form. Also, if needed
4117+
# there are several ways to extend/identify alternative encodings
4118+
# within the "2.1.1.2000" part if necessary.
4119+
# - Unlike real CVS revisions, you can't really reconstruct what
4120+
# relation a revision of this form has to other revisions.
4121+
# - FUTURE: TODO: Rework database somehow to make up and remember
4122+
# fully-CVS-compatible branches and branch version numbers.
4123+
4124+
my $meta;
4125+
if ( defined($revision) )
4126+
{
4127+
if ( $revision =~ /^1\.(\d+)$/ )
4128+
{
4129+
my ($intRev) = $1;
4130+
my $db_query;
4131+
$db_query = $self->{dbh}->prepare_cached(
4132+
"SELECT * FROM $tablename_rev WHERE name=? AND revision=?",
4133+
{},1);
4134+
$db_query->execute($filename, $intRev);
4135+
$meta = $db_query->fetchrow_hashref;
4136+
}
4137+
elsif ( $revision =~ /^2\.1\.1\.2000(\.[1-3][0-9][0-9]){20}$/ )
4138+
{
4139+
my ($commitHash)=($revision=~/^2\.1\.1\.2000(.*)$/);
4140+
$commitHash=~s/\.([0-9]+)/sprintf("%02x",$1-100)/eg;
4141+
if($commitHash=~/^[0-9a-f]{40}$/)
4142+
{
4143+
return $self->getMetaFromCommithash($filename,$commitHash);
4144+
}
4145+
4146+
# error recovery: fall back on head version below
4147+
print "E Failed to find $filename version=$revision or commit=$commitHash\n";
4148+
$log->warning("failed get $revision with commithash=$commitHash");
4149+
undef $revision;
4150+
}
4151+
elsif ( $revision =~ /^[0-9a-f]{40}$/ )
4152+
{
4153+
# Try DB first. This is mostly only useful for req_annotate(),
4154+
# which only calls this for stuff that should already be in
4155+
# the DB. It is fairly likely to be a waste of time
4156+
# in most other cases [unless the file happened to be
4157+
# modified in $revision specifically], but
4158+
# it is probably in the noise compared to how long
4159+
# getMetaFromCommithash() will take.
4160+
my $db_query;
4161+
$db_query = $self->{dbh}->prepare_cached(
4162+
"SELECT * FROM $tablename_rev WHERE name=? AND commithash=?",
4163+
{},1);
4164+
$db_query->execute($filename, $revision);
4165+
$meta = $db_query->fetchrow_hashref;
4166+
4167+
if(! $meta)
4168+
{
4169+
my($revCommit)=$self->lookupCommitRef($revision);
4170+
if($revCommit=~/^[0-9a-f]{40}$/)
4171+
{
4172+
return $self->getMetaFromCommithash($filename,$revCommit);
4173+
}
4174+
4175+
# error recovery: nothing found:
4176+
print "E Failed to find $filename version=$revision\n";
4177+
$log->warning("failed get $revision");
4178+
return $meta;
4179+
}
4180+
}
4181+
else
4182+
{
4183+
my($revCommit)=$self->lookupCommitRef($revision);
4184+
if($revCommit=~/^[0-9a-f]{40}$/)
4185+
{
4186+
return $self->getMetaFromCommithash($filename,$revCommit);
4187+
}
4188+
4189+
# error recovery: fall back on head version below
4190+
print "E Failed to find $filename version=$revision\n";
4191+
$log->warning("failed get $revision");
4192+
undef $revision; # Allow fallback
4193+
}
40604194
}
4061-
elsif ( defined($revision) and $revision =~ /^[a-zA-Z0-9]{40}$/ )
4195+
4196+
if(!defined($revision))
40624197
{
4063-
$db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND commithash=?",{},1);
4064-
$db_query->execute($filename, $revision);
4065-
} else {
4066-
$db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_head WHERE name=?",{},1);
4198+
my $db_query;
4199+
$db_query = $self->{dbh}->prepare_cached(
4200+
"SELECT * FROM $tablename_head WHERE name=?",{},1);
40674201
$db_query->execute($filename);
4202+
$meta = $db_query->fetchrow_hashref;
40684203
}
40694204

4070-
my $meta = $db_query->fetchrow_hashref;
40714205
if($meta)
40724206
{
40734207
$meta->{revision} = "1.$meta->{revision}";

0 commit comments

Comments
 (0)