@matheusbsbs / matheus-bagliano / commits / 8a06a63297
Fork 0

implement gitcvs.usecrlfattr

If gitcvs.usecrlfattr is set to true, git-cvsserver will consult the "crlf" for each file to determine if it should mark the file as binary (-kb). Signed-off-by: Matthew Ogilvie <mmogilvi_git@miniinfo.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matthew Ogilvie committed May 14, 2008 at 22:35 UTC 8a06a632976ead891115ad9ac9dea7b99c52158e
4 files changed +276 -22
Documentation/config.txt
+17 -6
@@ -660,11 +660,21 @@ gitcvs.logfile::
660 Path to a log file where the CVS server interface well... logs
661 various stuff. See linkgit:git-cvsserver[1].
662
663 +gitcvs.usecrlfattr
664 + If true, the server will look up the `crlf` attribute for
665 + files to determine the '-k' modes to use. If `crlf` is set,
666 + the '-k' mode will be left blank, so cvs clients will
667 + treat it as text. If `crlf` is explicitly unset, the file
668 + will be set with '-kb' mode, which supresses any newline munging
669 + the client might otherwise do. If `crlf` is not specified,
670 + then 'gitcvs.allbinary' is used. See linkgit:gitattribute[5].
671 +
672 gitcvs.allbinary::
664 - If true, all files are sent to the client in mode '-kb'. This
665 - causes the client to treat all files as binary files which suppresses
666 - any newline munging it otherwise might do. A work-around for the
667 - fact that there is no way yet to set single files to mode '-kb'.
673 + If true, all files not otherwise specified using
674 + 'gitcvs.usecrlfattr' and an explicitly set or unset `crlf`
675 + attribute are sent to the client in mode '-kb'. This
676 + causes the client to treat them as binary files which
677 + suppresses any newline munging it otherwise might do.
678
679 gitcvs.dbname::
680 Database used by git-cvsserver to cache revision information
@@ -695,8 +705,9 @@ gitcvs.dbTableNamePrefix::
705 linkgit:git-cvsserver[1] for details). Any non-alphabetic
706 characters will be replaced with underscores.
707
698 -All gitcvs variables except for 'gitcvs.allbinary' can also be
699 -specified as 'gitcvs.<access_method>.<varname>' (where 'access_method'
708 +All gitcvs variables except for 'gitcvs.usecrlfattr' and
709 +'gitcvs.allbinary' can also be specified as
710 +'gitcvs.<access_method>.<varname>' (where 'access_method'
711 is one of "ext" and "pserver") to make them apply only for the given
712 access method.
713
Documentation/git-cvsserver.txt
+21 -5
@@ -301,11 +301,27 @@ checkout, diff, status, update, log, add, remove, commit.
301 Legacy monitoring operations are not supported (edit, watch and related).
302 Exports and tagging (tags and branches) are not supported at this stage.
303
304 -The server should set the '-k' mode to binary when relevant, however,
305 -this is not really implemented yet. For now, you can force the server
306 -to set '-kb' for all files by setting the `gitcvs.allbinary` config
307 -variable. In proper GIT tradition, the contents of the files are
308 -always respected. No keyword expansion or newline munging is supported.
304 +CRLF Line Ending Conversions
305 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^
306 +
307 +By default the server leaves the '-k' mode blank for all files,
308 +which causes the cvs client to treat them as a text files, subject
309 +to crlf conversion on some platforms.
310 +
311 +You can make the server use `crlf` attributes to set the '-k' modes
312 +for files by setting the `gitcvs.usecrlfattr` config variable.
313 +In this case, if `crlf` is explicitly unset ('-crlf'), then the
314 +will set '-kb' mode, for binary files. If it `crlf` is set,
315 +then the '-k' mode will explicitly be left blank. See
316 +also linkgit:gitattributes[5] for more information about the `crlf`
317 +attribute.
318 +
319 +Alternatively, if `gitcvs.usecrlfattr` config is not enabled
320 +or if the `crlf` attribute is unspecified for a filename, then
321 +the server uses the `gitcvs.allbinary` for the default setting.
322 +If `gitcvs.allbinary` is set, then the files not otherwise
323 +specified will default to '-kb' mode. Otherwise the '-k' mode
324 +is left blank.
325
326 Dependencies
327 ------------
git-cvsserver.perl
+60 -11
@@ -502,7 +502,7 @@ sub req_add
502 print $state->{CVSROOT} . "/$state->{module}/$filename\n";
503
504 # this is an "entries" line
505 - my $kopts = kopts_from_path($filepart);
505 + my $kopts = kopts_from_path($filename);
506 $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
507 print "/$filepart/1.$meta->{revision}//$kopts/\n";
508 # permissions
@@ -533,9 +533,25 @@ sub req_add
533
534 print "Checked-in $dirpart\n";
535 print "$filename\n";
536 - my $kopts = kopts_from_path($filepart);
536 + my $kopts = kopts_from_path($filename);
537 print "/$filepart/0//$kopts/\n";
538
539 + my $requestedKopts = $state->{opt}{k};
540 + if(defined($requestedKopts))
541 + {
542 + $requestedKopts = "-k$requestedKopts";
543 + }
544 + else
545 + {
546 + $requestedKopts = "";
547 + }
548 + if( $kopts ne $requestedKopts )
549 + {
550 + $log->warn("Ignoring requested -k='$requestedKopts'"
551 + . " for '$filename'; detected -k='$kopts' instead");
552 + #TODO: Also have option to send warning to user?
553 + }
554 +
555 $addcount++;
556 }
557
@@ -615,7 +631,7 @@ sub req_remove
631
632 print "Checked-in $dirpart\n";
633 print "$filename\n";
618 - my $kopts = kopts_from_path($filepart);
634 + my $kopts = kopts_from_path($filename);
635 print "/$filepart/-1.$wrev//$kopts/\n";
636
637 $rmcount++;
@@ -785,6 +801,7 @@ sub req_co
801 argsplit("co");
802
803 my $module = $state->{args}[0];
804 + $state->{module} = $module;
805 my $checkout_path = $module;
806
807 # use the user specified directory if we're given it
@@ -862,6 +879,7 @@ sub req_co
879 # Don't want to check out deleted files
880 next if ( $git->{filehash} eq "deleted" );
881
882 + my $fullName = $git->{name};
883 ( $git->{name}, $git->{dir} ) = filenamesplit($git->{name});
884
885 if (length($git->{dir}) && $git->{dir} ne './'
@@ -892,7 +910,7 @@ sub req_co
910 print $state->{CVSROOT} . "/$module/" . ( defined ( $git->{dir} ) and $git->{dir} ne "./" ? $git->{dir} . "/" : "" ) . "$git->{name}\n";
911
912 # this is an "entries" line
895 - my $kopts = kopts_from_path($git->{name});
913 + my $kopts = kopts_from_path($fullName);
914 print "/$git->{name}/1.$git->{revision}//$kopts/\n";
915 # permissions
916 print "u=$git->{mode},g=$git->{mode},o=$git->{mode}\n";
@@ -1101,7 +1119,7 @@ sub req_update
1119 print $state->{CVSROOT} . "/$state->{module}/$filename\n";
1120
1121 # this is an "entries" line
1104 - my $kopts = kopts_from_path($filepart);
1122 + my $kopts = kopts_from_path($filename);
1123 $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
1124 print "/$filepart/1.$meta->{revision}//$kopts/\n";
1125
@@ -1149,7 +1167,7 @@ sub req_update
1167 print "Merged $dirpart\n";
1168 $log->debug($state->{CVSROOT} . "/$state->{module}/$filename");
1169 print $state->{CVSROOT} . "/$state->{module}/$filename\n";
1152 - my $kopts = kopts_from_path($filepart);
1170 + my $kopts = kopts_from_path("$dirpart/$filepart");
1171 $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
1172 print "/$filepart/1.$meta->{revision}//$kopts/\n";
1173 }
@@ -1165,7 +1183,7 @@ sub req_update
1183 {
1184 print "Merged $dirpart\n";
1185 print $state->{CVSROOT} . "/$state->{module}/$filename\n";
1168 - my $kopts = kopts_from_path($filepart);
1186 + my $kopts = kopts_from_path("$dirpart/$filepart");
1187 print "/$filepart/1.$meta->{revision}/+/$kopts/\n";
1188 }
1189 }
@@ -1416,7 +1434,7 @@ sub req_ci
1434 }
1435 print "Checked-in $dirpart\n";
1436 print "$filename\n";
1419 - my $kopts = kopts_from_path($filepart);
1437 + my $kopts = kopts_from_path($filename);
1438 print "/$filepart/1.$meta->{revision}//$kopts/\n";
1439 }
1440 }
@@ -2296,10 +2314,24 @@ sub kopts_from_path
2314 {
2315 my ($path) = @_;
2316
2299 - # Once it exists, the git attributes system should be used to look up
2300 - # what attributes apply to this path.
2317 + if ( defined ( $cfg->{gitcvs}{usecrlfattr} ) and
2318 + $cfg->{gitcvs}{usecrlfattr} =~ /\s*(1|true|yes)\s*$/i )
2319 + {
2320 + my ($val) = check_attr( "crlf", $path );
2321 + if ( $val eq "set" )
2322 + {
2323 + return "";
2324 + }
2325 + elsif ( $val eq "unset" )
2326 + {
2327 + return "-kb"
2328 + }
2329 + else
2330 + {
2331 + $log->info("Unrecognized check_attr crlf $path : $val");
2332 + }
2333 + }
2334
2302 - # Until then, take the setting from the config file
2335 unless ( defined ( $cfg->{gitcvs}{allbinary} ) and $cfg->{gitcvs}{allbinary} =~ /^\s*(1|true|yes)\s*$/i )
2336 {
2337 # Return "" to give no special treatment to any path
@@ -2311,6 +2343,23 @@ sub kopts_from_path
2343 }
2344 }
2345
2346 +sub check_attr
2347 +{
2348 + my ($attr,$path) = @_;
2349 + ensureWorkTree();
2350 + if ( open my $fh, '-|', "git", "check-attr", $attr, "--", $path )
2351 + {
2352 + my $val = <$fh>;
2353 + close $fh;
2354 + $val =~ s/.*: ([^:\r\n]*)\s*$/$1/;
2355 + return $val;
2356 + }
2357 + else
2358 + {
2359 + return undef;
2360 + }
2361 +}
2362 +
2363 # Generate a CVS author name from Git author information, by taking
2364 # the first eight characters of the user part of the email address.
2365 sub cvs_author
t/t9401-git-cvsserver-crlf.sh new
+178
@@ -0,0 +1,178 @@
1 +#!/bin/sh
2 +#
3 +# Copyright (c) 2008 Matthew Ogilvie
4 +# Parts adapted from other tests.
5 +#
6 +
7 +test_description='git-cvsserver -kb modes
8 +
9 +tests -kb mode for binary files when accessing a git
10 +repository using cvs CLI client via git-cvsserver server'
11 +
12 +. ./test-lib.sh
13 +
14 +q_to_nul () {
15 + perl -pe 'y/Q/\000/'
16 +}
17 +
18 +q_to_cr () {
19 + tr Q '\015'
20 +}
21 +
22 +marked_as () {
23 + foundEntry="$(grep "^/$2/" "$1/CVS/Entries")"
24 + if [ x"$foundEntry" = x"" ] ; then
25 + echo "NOT FOUND: $1 $2 1 $3" >> "${WORKDIR}/marked.log"
26 + return 1
27 + fi
28 + test x"$(grep "^/$2/" "$1/CVS/Entries" | cut -d/ -f5)" = x"$3"
29 + stat=$?
30 + echo "$1 $2 $stat '$3'" >> "${WORKDIR}/marked.log"
31 + return $stat
32 +}
33 +
34 +not_present() {
35 + foundEntry="$(grep "^/$2/" "$1/CVS/Entries")"
36 + if [ -r "$1/$2" ] ; then
37 + echo "Error: File still exists: $1 $2" >> "${WORKDIR}/marked.log"
38 + return 1;
39 + fi
40 + if [ x"$foundEntry" != x"" ] ; then
41 + echo "Error: should not have found: $1 $2" >> "${WORKDIR}/marked.log"
42 + return 1;
43 + else
44 + echo "Correctly not found: $1 $2" >> "${WORKDIR}/marked.log"
45 + return 0;
46 + fi
47 +}
48 +
49 +cvs >/dev/null 2>&1
50 +if test $? -ne 1
51 +then
52 + test_expect_success 'skipping git-cvsserver tests, cvs not found' :
53 + test_done
54 + exit
55 +fi
56 +perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
57 + test_expect_success 'skipping git-cvsserver tests, Perl SQLite interface unavailable' :
58 + test_done
59 + exit
60 +}
61 +
62 +unset GIT_DIR GIT_CONFIG
63 +WORKDIR=$(pwd)
64 +SERVERDIR=$(pwd)/gitcvs.git
65 +git_config="$SERVERDIR/config"
66 +CVSROOT=":fork:$SERVERDIR"
67 +CVSWORK="$(pwd)/cvswork"
68 +CVS_SERVER=git-cvsserver
69 +export CVSROOT CVS_SERVER
70 +
71 +rm -rf "$CVSWORK" "$SERVERDIR"
72 +test_expect_success 'setup' '
73 + echo "Simple text file" >textfile.c &&
74 + echo "File with embedded NUL: Q <- there" | q_to_nul > binfile.bin &&
75 + mkdir subdir &&
76 + echo "Another text file" > subdir/file.h &&
77 + echo "Another binary: Q (this time CR)" | q_to_cr > subdir/withCr.bin &&
78 + echo "Mixed up NUL, but marked text: Q <- there" | q_to_nul > mixedUp.c
79 + echo "Unspecified" > subdir/unspecified.other &&
80 + echo "/*.bin -crlf" > .gitattributes &&
81 + echo "/*.c crlf" >> .gitattributes &&
82 + echo "subdir/*.bin -crlf" >> .gitattributes &&
83 + echo "subdir/*.c crlf" >> .gitattributes &&
84 + echo "subdir/file.h crlf" >> .gitattributes &&
85 + git add .gitattributes textfile.c binfile.bin mixedUp.c subdir/* &&
86 + git commit -q -m "First Commit" &&
87 + git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
88 + GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
89 + GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log"
90 +'
91 +
92 +test_expect_success 'cvs co (default crlf)' '
93 + GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
94 + test x"$(grep '/-k' cvswork/CVS/Entries cvswork/subdir/CVS/Entries)" = x""
95 +'
96 +
97 +rm -rf cvswork
98 +test_expect_success 'cvs co (allbinary)' '
99 + GIT_DIR="$SERVERDIR" git config --bool gitcvs.allbinary true &&
100 + GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
101 + marked_as cvswork textfile.c -kb &&
102 + marked_as cvswork binfile.bin -kb &&
103 + marked_as cvswork .gitattributes -kb &&
104 + marked_as cvswork mixedUp.c -kb &&
105 + marked_as cvswork/subdir withCr.bin -kb &&
106 + marked_as cvswork/subdir file.h -kb &&
107 + marked_as cvswork/subdir unspecified.other -kb
108 +'
109 +
110 +rm -rf cvswork cvs.log
111 +test_expect_success 'cvs co (use attributes/allbinary)' '
112 + GIT_DIR="$SERVERDIR" git config --bool gitcvs.usecrlfattr true &&
113 + GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
114 + marked_as cvswork textfile.c "" &&
115 + marked_as cvswork binfile.bin -kb &&
116 + marked_as cvswork .gitattributes -kb &&
117 + marked_as cvswork mixedUp.c "" &&
118 + marked_as cvswork/subdir withCr.bin -kb &&
119 + marked_as cvswork/subdir file.h "" &&
120 + marked_as cvswork/subdir unspecified.other -kb
121 +'
122 +
123 +rm -rf cvswork
124 +test_expect_success 'cvs co (use attributes)' '
125 + GIT_DIR="$SERVERDIR" git config --bool gitcvs.allbinary false &&
126 + GIT_CONFIG="$git_config" cvs -Q co -d cvswork master >cvs.log 2>&1 &&
127 + marked_as cvswork textfile.c "" &&
128 + marked_as cvswork binfile.bin -kb &&
129 + marked_as cvswork .gitattributes "" &&
130 + marked_as cvswork mixedUp.c "" &&
131 + marked_as cvswork/subdir withCr.bin -kb &&
132 + marked_as cvswork/subdir file.h "" &&
133 + marked_as cvswork/subdir unspecified.other ""
134 +'
135 +
136 +test_expect_success 'adding files' '
137 + cd cvswork/subdir &&
138 + echo "more text" > src.c &&
139 + GIT_CONFIG="$git_config" cvs -Q add src.c >cvs.log 2>&1 &&
140 + marked_as . src.c "" &&
141 + echo "psuedo-binary" > temp.bin &&
142 + cd .. &&
143 + GIT_CONFIG="$git_config" cvs -Q add subdir/temp.bin >cvs.log 2>&1 &&
144 + marked_as subdir temp.bin "-kb" &&
145 + cd subdir &&
146 + GIT_CONFIG="$git_config" cvs -Q ci -m "adding files" >cvs.log 2>&1 &&
147 + marked_as . temp.bin "-kb" &&
148 + marked_as . src.c ""
149 +'
150 +
151 +cd "$WORKDIR"
152 +test_expect_success 'updating' '
153 + git pull gitcvs.git &&
154 + echo 'hi' > subdir/newfile.bin &&
155 + echo 'junk' > subdir/file.h &&
156 + echo 'hi' > subdir/newfile.c &&
157 + echo 'hello' >> binfile.bin &&
158 + git add subdir/newfile.bin subdir/file.h subdir/newfile.c binfile.bin &&
159 + git commit -q -m "Add and change some files" &&
160 + git push gitcvs.git >/dev/null &&
161 + cd cvswork &&
162 + GIT_CONFIG="$git_config" cvs -Q update &&
163 + cd .. &&
164 + marked_as cvswork textfile.c "" &&
165 + marked_as cvswork binfile.bin -kb &&
166 + marked_as cvswork .gitattributes "" &&
167 + marked_as cvswork mixedUp.c "" &&
168 + marked_as cvswork/subdir withCr.bin -kb &&
169 + marked_as cvswork/subdir file.h "" &&
170 + marked_as cvswork/subdir unspecified.other "" &&
171 + marked_as cvswork/subdir newfile.bin -kb &&
172 + marked_as cvswork/subdir newfile.c "" &&
173 + echo "File with embedded NUL: Q <- there" | q_to_nul > tmpExpect1 &&
174 + echo "hello" >> tmpExpect1 &&
175 + cmp cvswork/binfile.bin tmpExpect1
176 +'
177 +
178 +test_done