@@ -4041,6 +4041,19 @@ =head2 getmeta
4041
4041
This function takes a filename (with path) argument and returns a hashref of
4042
4042
metadata for that file.
4043
4043
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
+
4044
4057
=cut
4045
4058
4046
4059
sub getmeta
@@ -4051,23 +4064,144 @@ sub getmeta
4051
4064
my $tablename_rev = $self -> tablename(" revision" );
4052
4065
my $tablename_head = $self -> tablename(" head" );
4053
4066
4054
- my $db_query ;
4055
- if ( defined ($revision ) and $revision =~ / ^1\. (\d +)$ / )
4067
+ if ( ref ($revision ) eq " HASH" )
4056
4068
{
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
+ }
4060
4194
}
4061
- elsif ( defined ($revision ) and $revision =~ / ^[a-zA-Z0-9]{40}$ / )
4195
+
4196
+ if (!defined ($revision ))
4062
4197
{
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);
4067
4201
$db_query -> execute($filename );
4202
+ $meta = $db_query -> fetchrow_hashref;
4068
4203
}
4069
4204
4070
- my $meta = $db_query -> fetchrow_hashref;
4071
4205
if ($meta )
4072
4206
{
4073
4207
$meta -> {revision } = " 1.$meta ->{revision}" ;
0 commit comments