@@ -4041,6 +4041,19 @@ =head2 getmeta
40414041This function takes a filename (with path) argument and returns a hashref of
40424042metadata 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
40464059sub 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