Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
#include "cache.h"
|
2007-04-13 07:30:05 +02:00
|
|
|
#include "attr.h"
|
2007-04-22 04:09:02 +02:00
|
|
|
#include "run-command.h"
|
2010-12-22 15:40:13 +01:00
|
|
|
#include "quote.h"
|
2012-02-20 21:53:37 +01:00
|
|
|
#include "sigchain.h"
|
2007-04-13 07:30:05 +02:00
|
|
|
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
/*
|
|
|
|
* convert.c - convert a file when checking it out and checking it in.
|
|
|
|
*
|
|
|
|
* This should use the pathname to decide on whether it wants to do some
|
|
|
|
* more interesting conversions (automatic gzip/unzip, general format
|
|
|
|
* conversions etc etc), but by default it just does automatic CRLF<->LF
|
2010-06-04 21:29:08 +02:00
|
|
|
* translation when the "text" attribute or "auto_crlf" option is set.
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
*/
|
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
enum crlf_action {
|
2010-05-19 22:43:10 +02:00
|
|
|
CRLF_GUESS = -1,
|
|
|
|
CRLF_BINARY = 0,
|
|
|
|
CRLF_TEXT,
|
|
|
|
CRLF_INPUT,
|
|
|
|
CRLF_CRLF,
|
2011-03-16 07:59:10 +01:00
|
|
|
CRLF_AUTO
|
2010-05-19 22:43:10 +02:00
|
|
|
};
|
2007-04-20 07:37:19 +02:00
|
|
|
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
struct text_stat {
|
2008-01-16 02:59:12 +01:00
|
|
|
/* NUL, CR, LF and CRLF counts */
|
|
|
|
unsigned nul, cr, lf, crlf;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
|
|
|
/* These are just approximations! */
|
|
|
|
unsigned printable, nonprintable;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)
|
|
|
|
{
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
memset(stats, 0, sizeof(*stats));
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
unsigned char c = buf[i];
|
|
|
|
if (c == '\r') {
|
|
|
|
stats->cr++;
|
|
|
|
if (i+1 < size && buf[i+1] == '\n')
|
|
|
|
stats->crlf++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '\n') {
|
|
|
|
stats->lf++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == 127)
|
|
|
|
/* DEL */
|
|
|
|
stats->nonprintable++;
|
|
|
|
else if (c < 32) {
|
|
|
|
switch (c) {
|
|
|
|
/* BS, HT, ESC and FF */
|
|
|
|
case '\b': case '\t': case '\033': case '\014':
|
|
|
|
stats->printable++;
|
|
|
|
break;
|
2008-01-16 02:59:12 +01:00
|
|
|
case 0:
|
|
|
|
stats->nul++;
|
|
|
|
/* fall through */
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
default:
|
|
|
|
stats->nonprintable++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
stats->printable++;
|
|
|
|
}
|
2008-07-11 18:48:16 +02:00
|
|
|
|
|
|
|
/* If file ends with EOF then don't count this EOF as non-printable. */
|
|
|
|
if (size >= 1 && buf[size-1] == '\032')
|
|
|
|
stats->nonprintable--;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The same heuristics as diff.c::mmfile_is_binary()
|
|
|
|
*/
|
|
|
|
static int is_binary(unsigned long size, struct text_stat *stats)
|
|
|
|
{
|
|
|
|
|
2008-01-16 02:59:12 +01:00
|
|
|
if (stats->nul)
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
if ((stats->printable >> 7) < stats->nonprintable)
|
|
|
|
return 1;
|
|
|
|
/*
|
|
|
|
* Other heuristics? Average line length might be relevant,
|
|
|
|
* as might LF vs CR vs CRLF counts..
|
|
|
|
*
|
|
|
|
* NOTE! It might be normal to have a low ratio of CRLF to LF
|
|
|
|
* (somebody starts with a LF-only file and edits it with an editor
|
|
|
|
* that adds CRLF only to lines that are added..). But do we
|
|
|
|
* want to support CR-only? Probably not.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
static enum eol output_eol(enum crlf_action crlf_action)
|
2010-07-02 21:20:47 +02:00
|
|
|
{
|
2011-05-09 22:12:57 +02:00
|
|
|
switch (crlf_action) {
|
2010-06-04 21:29:08 +02:00
|
|
|
case CRLF_BINARY:
|
|
|
|
return EOL_UNSET;
|
|
|
|
case CRLF_CRLF:
|
|
|
|
return EOL_CRLF;
|
|
|
|
case CRLF_INPUT:
|
|
|
|
return EOL_LF;
|
|
|
|
case CRLF_GUESS:
|
|
|
|
if (!auto_crlf)
|
|
|
|
return EOL_UNSET;
|
|
|
|
/* fall through */
|
|
|
|
case CRLF_TEXT:
|
|
|
|
case CRLF_AUTO:
|
|
|
|
if (auto_crlf == AUTO_CRLF_TRUE)
|
|
|
|
return EOL_CRLF;
|
|
|
|
else if (auto_crlf == AUTO_CRLF_INPUT)
|
|
|
|
return EOL_LF;
|
2011-05-09 21:52:12 +02:00
|
|
|
else if (core_eol == EOL_UNSET)
|
2010-06-04 21:29:08 +02:00
|
|
|
return EOL_NATIVE;
|
|
|
|
}
|
2011-05-09 21:52:12 +02:00
|
|
|
return core_eol;
|
2010-06-04 21:29:08 +02:00
|
|
|
}
|
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 12:25:58 +01:00
|
|
|
struct text_stat *stats, enum safe_crlf checksafe)
|
|
|
|
{
|
|
|
|
if (!checksafe)
|
|
|
|
return;
|
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
if (output_eol(crlf_action) == EOL_LF) {
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 12:25:58 +01:00
|
|
|
/*
|
|
|
|
* CRLFs would not be restored by checkout:
|
|
|
|
* check if we'd remove CRLFs
|
|
|
|
*/
|
|
|
|
if (stats->crlf) {
|
|
|
|
if (checksafe == SAFE_CRLF_WARN)
|
2010-06-04 21:29:08 +02:00
|
|
|
warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.", path);
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 12:25:58 +01:00
|
|
|
else /* i.e. SAFE_CRLF_FAIL */
|
|
|
|
die("CRLF would be replaced by LF in %s.", path);
|
|
|
|
}
|
2011-05-09 22:12:57 +02:00
|
|
|
} else if (output_eol(crlf_action) == EOL_CRLF) {
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 12:25:58 +01:00
|
|
|
/*
|
|
|
|
* CRLFs would be added by checkout:
|
|
|
|
* check if we have "naked" LFs
|
|
|
|
*/
|
|
|
|
if (stats->lf != stats->crlf) {
|
|
|
|
if (checksafe == SAFE_CRLF_WARN)
|
2010-06-04 21:29:08 +02:00
|
|
|
warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.", path);
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 12:25:58 +01:00
|
|
|
else /* i.e. SAFE_CRLF_FAIL */
|
|
|
|
die("LF would be replaced by CRLF in %s", path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 00:37:57 +02:00
|
|
|
static int has_cr_in_index(const char *path)
|
|
|
|
{
|
|
|
|
int pos, len;
|
|
|
|
unsigned long sz;
|
|
|
|
enum object_type type;
|
|
|
|
void *data;
|
|
|
|
int has_cr;
|
|
|
|
struct index_state *istate = &the_index;
|
|
|
|
|
|
|
|
len = strlen(path);
|
|
|
|
pos = index_name_pos(istate, path, len);
|
|
|
|
if (pos < 0) {
|
|
|
|
/*
|
|
|
|
* We might be in the middle of a merge, in which
|
|
|
|
* case we would read stage #2 (ours).
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
for (i = -pos - 1;
|
|
|
|
(pos < 0 && i < istate->cache_nr &&
|
|
|
|
!strcmp(istate->cache[i]->name, path));
|
|
|
|
i++)
|
|
|
|
if (ce_stage(istate->cache[i]) == 2)
|
|
|
|
pos = i;
|
|
|
|
}
|
|
|
|
if (pos < 0)
|
|
|
|
return 0;
|
|
|
|
data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
|
|
|
|
if (!data || type != OBJ_BLOB) {
|
|
|
|
free(data);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
has_cr = memchr(data, '\r', sz) != NULL;
|
|
|
|
free(data);
|
|
|
|
return has_cr;
|
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
static int crlf_to_git(const char *path, const char *src, size_t len,
|
2011-05-09 22:12:57 +02:00
|
|
|
struct strbuf *buf,
|
|
|
|
enum crlf_action crlf_action, enum safe_crlf checksafe)
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
{
|
|
|
|
struct text_stat stats;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
char *dst;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
if (crlf_action == CRLF_BINARY ||
|
2012-02-24 23:05:03 +01:00
|
|
|
(crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) ||
|
|
|
|
(src && !len))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
2012-02-24 23:05:03 +01:00
|
|
|
/*
|
|
|
|
* If we are doing a dry-run and have no source buffer, there is
|
|
|
|
* nothing to analyze; we must assume we would convert.
|
|
|
|
*/
|
|
|
|
if (!buf && !src)
|
|
|
|
return 1;
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
gather_stats(src, len, &stats);
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) {
|
2007-04-15 22:35:45 +02:00
|
|
|
/*
|
|
|
|
* We're currently not going to even try to convert stuff
|
|
|
|
* that has bare CR characters. Does anybody do that crazy
|
|
|
|
* stuff?
|
|
|
|
*/
|
|
|
|
if (stats.cr != stats.crlf)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
2007-04-15 22:35:45 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* And add some heuristics for binary vs text, of course...
|
|
|
|
*/
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
if (is_binary(len, &stats))
|
|
|
|
return 0;
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 00:37:57 +02:00
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
if (crlf_action == CRLF_GUESS) {
|
2010-05-19 22:43:10 +02:00
|
|
|
/*
|
|
|
|
* If the file in the index has any CR in it, do not convert.
|
|
|
|
* This is the new safer autocrlf handling.
|
|
|
|
*/
|
|
|
|
if (has_cr_in_index(path))
|
|
|
|
return 0;
|
|
|
|
}
|
2007-04-15 22:35:45 +02:00
|
|
|
}
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
check_safe_crlf(path, crlf_action, &stats, checksafe);
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 12:25:58 +01:00
|
|
|
|
|
|
|
/* Optimization: No CR? Nothing to convert, regardless. */
|
|
|
|
if (!stats.cr)
|
|
|
|
return 0;
|
|
|
|
|
2012-02-24 23:02:37 +01:00
|
|
|
/*
|
|
|
|
* At this point all of our source analysis is done, and we are sure we
|
|
|
|
* would convert. If we are in dry-run mode, we can give an answer.
|
|
|
|
*/
|
|
|
|
if (!buf)
|
|
|
|
return 1;
|
|
|
|
|
2007-10-05 10:11:59 +02:00
|
|
|
/* only grow if not in place */
|
|
|
|
if (strbuf_avail(buf) + buf->len < len)
|
|
|
|
strbuf_grow(buf, len - buf->len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
dst = buf->buf;
|
2011-05-09 22:12:57 +02:00
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) {
|
2007-04-20 07:37:19 +02:00
|
|
|
/*
|
|
|
|
* If we guessed, we already know we rejected a file with
|
|
|
|
* lone CR, and we can strip a CR without looking at what
|
|
|
|
* follow it.
|
|
|
|
*/
|
2007-04-15 22:35:45 +02:00
|
|
|
do {
|
2007-04-19 02:05:03 +02:00
|
|
|
unsigned char c = *src++;
|
2007-04-15 22:35:45 +02:00
|
|
|
if (c != '\r')
|
2007-04-19 02:05:03 +02:00
|
|
|
*dst++ = c;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
} while (--len);
|
2007-04-15 22:35:45 +02:00
|
|
|
} else {
|
|
|
|
do {
|
2007-04-19 02:05:03 +02:00
|
|
|
unsigned char c = *src++;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
if (! (c == '\r' && (1 < len && *src == '\n')))
|
2007-04-19 02:05:03 +02:00
|
|
|
*dst++ = c;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
} while (--len);
|
2007-04-15 22:35:45 +02:00
|
|
|
}
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
strbuf_setlen(buf, dst - buf->buf);
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
static int crlf_to_worktree(const char *path, const char *src, size_t len,
|
2011-05-09 22:12:57 +02:00
|
|
|
struct strbuf *buf, enum crlf_action crlf_action)
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
{
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
char *to_free = NULL;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
struct text_stat stats;
|
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
if (!len || output_eol(crlf_action) != EOL_CRLF)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
gather_stats(src, len, &stats);
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
|
|
|
/* No LF? Nothing to convert, regardless. */
|
|
|
|
if (!stats.lf)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
|
|
|
/* Was it already in CRLF format? */
|
|
|
|
if (stats.lf == stats.crlf)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) {
|
|
|
|
if (crlf_action == CRLF_GUESS) {
|
2010-05-19 22:43:10 +02:00
|
|
|
/* If we have any CR or CRLF line endings, we do not touch it */
|
|
|
|
/* This is the new safer autocrlf-handling */
|
|
|
|
if (stats.cr > 0 || stats.crlf > 0)
|
|
|
|
return 0;
|
|
|
|
}
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 00:37:57 +02:00
|
|
|
|
2007-04-15 22:35:45 +02:00
|
|
|
/* If we have any bare CR characters, we're not going to touch it */
|
|
|
|
if (stats.cr != stats.crlf)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
if (is_binary(len, &stats))
|
|
|
|
return 0;
|
2007-04-15 22:35:45 +02:00
|
|
|
}
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
/* are we "faking" in place editing ? */
|
|
|
|
if (src == buf->buf)
|
2007-09-27 12:58:23 +02:00
|
|
|
to_free = strbuf_detach(buf, NULL);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
|
|
|
|
strbuf_grow(buf, len + stats.lf - stats.crlf);
|
|
|
|
for (;;) {
|
|
|
|
const char *nl = memchr(src, '\n', len);
|
|
|
|
if (!nl)
|
|
|
|
break;
|
|
|
|
if (nl > src && nl[-1] == '\r') {
|
|
|
|
strbuf_add(buf, src, nl + 1 - src);
|
|
|
|
} else {
|
|
|
|
strbuf_add(buf, src, nl - src);
|
|
|
|
strbuf_addstr(buf, "\r\n");
|
|
|
|
}
|
|
|
|
len -= nl + 1 - src;
|
|
|
|
src = nl + 1;
|
|
|
|
}
|
|
|
|
strbuf_add(buf, src, len);
|
|
|
|
|
|
|
|
free(to_free);
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-13 20:07:23 +01:00
|
|
|
}
|
2007-04-13 07:30:05 +02:00
|
|
|
|
2007-10-19 21:48:06 +02:00
|
|
|
struct filter_params {
|
|
|
|
const char *src;
|
|
|
|
unsigned long size;
|
|
|
|
const char *cmd;
|
2010-12-22 15:40:13 +01:00
|
|
|
const char *path;
|
2007-10-19 21:48:06 +02:00
|
|
|
};
|
|
|
|
|
2010-02-05 21:57:38 +01:00
|
|
|
static int filter_buffer(int in, int out, void *data)
|
2007-04-21 12:14:13 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Spawn cmd and feed the buffer contents through its stdin.
|
|
|
|
*/
|
|
|
|
struct child_process child_process;
|
2007-10-19 21:48:06 +02:00
|
|
|
struct filter_params *params = (struct filter_params *)data;
|
2007-04-21 12:14:13 +02:00
|
|
|
int write_err, status;
|
2010-05-14 11:31:33 +02:00
|
|
|
const char *argv[] = { NULL, NULL };
|
|
|
|
|
2010-12-22 15:40:13 +01:00
|
|
|
/* apply % substitution to cmd */
|
|
|
|
struct strbuf cmd = STRBUF_INIT;
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
struct strbuf_expand_dict_entry dict[] = {
|
|
|
|
{ "f", NULL, },
|
|
|
|
{ NULL, NULL, },
|
|
|
|
};
|
|
|
|
|
|
|
|
/* quote the path to preserve spaces, etc. */
|
|
|
|
sq_quote_buf(&path, params->path);
|
|
|
|
dict[0].value = path.buf;
|
|
|
|
|
|
|
|
/* expand all %f with the quoted path */
|
|
|
|
strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
|
|
|
|
strbuf_release(&path);
|
|
|
|
|
|
|
|
argv[0] = cmd.buf;
|
2007-04-21 12:14:13 +02:00
|
|
|
|
|
|
|
memset(&child_process, 0, sizeof(child_process));
|
2007-10-19 21:47:55 +02:00
|
|
|
child_process.argv = argv;
|
2009-12-30 11:53:57 +01:00
|
|
|
child_process.use_shell = 1;
|
2007-10-19 21:47:55 +02:00
|
|
|
child_process.in = -1;
|
2010-02-05 21:57:38 +01:00
|
|
|
child_process.out = out;
|
2007-04-21 12:14:13 +02:00
|
|
|
|
2007-10-19 21:47:55 +02:00
|
|
|
if (start_command(&child_process))
|
2007-10-19 21:48:06 +02:00
|
|
|
return error("cannot fork to run external filter %s", params->cmd);
|
2007-04-21 12:14:13 +02:00
|
|
|
|
2012-02-20 21:53:37 +01:00
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
|
|
|
|
2007-10-19 21:48:06 +02:00
|
|
|
write_err = (write_in_full(child_process.in, params->src, params->size) < 0);
|
2007-10-19 21:47:55 +02:00
|
|
|
if (close(child_process.in))
|
2007-04-21 12:14:13 +02:00
|
|
|
write_err = 1;
|
|
|
|
if (write_err)
|
2007-10-19 21:48:06 +02:00
|
|
|
error("cannot feed the input to external filter %s", params->cmd);
|
2007-04-21 12:14:13 +02:00
|
|
|
|
2012-02-20 21:53:37 +01:00
|
|
|
sigchain_pop(SIGPIPE);
|
|
|
|
|
2007-04-21 12:14:13 +02:00
|
|
|
status = finish_command(&child_process);
|
|
|
|
if (status)
|
2009-07-04 21:26:39 +02:00
|
|
|
error("external filter %s failed %d", params->cmd, status);
|
2010-12-22 15:40:13 +01:00
|
|
|
|
|
|
|
strbuf_release(&cmd);
|
2007-04-21 12:14:13 +02:00
|
|
|
return (write_err || status);
|
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
static int apply_filter(const char *path, const char *src, size_t len,
|
|
|
|
struct strbuf *dst, const char *cmd)
|
2007-04-21 12:14:13 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Create a pipeline to have the command filter the buffer's
|
|
|
|
* contents.
|
|
|
|
*
|
|
|
|
* (child --> cmd) --> us
|
|
|
|
*/
|
2007-10-19 21:48:06 +02:00
|
|
|
int ret = 1;
|
2008-10-09 21:12:12 +02:00
|
|
|
struct strbuf nbuf = STRBUF_INIT;
|
2007-10-19 21:48:06 +02:00
|
|
|
struct async async;
|
|
|
|
struct filter_params params;
|
2007-04-21 12:14:13 +02:00
|
|
|
|
|
|
|
if (!cmd)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
2007-04-21 12:14:13 +02:00
|
|
|
|
2012-02-24 23:02:37 +01:00
|
|
|
if (!dst)
|
|
|
|
return 1;
|
|
|
|
|
2007-10-19 21:48:06 +02:00
|
|
|
memset(&async, 0, sizeof(async));
|
|
|
|
async.proc = filter_buffer;
|
|
|
|
async.data = ¶ms;
|
2010-02-05 21:57:38 +01:00
|
|
|
async.out = -1;
|
2007-10-19 21:48:06 +02:00
|
|
|
params.src = src;
|
|
|
|
params.size = len;
|
|
|
|
params.cmd = cmd;
|
2010-12-22 15:40:13 +01:00
|
|
|
params.path = path;
|
2007-04-21 12:14:13 +02:00
|
|
|
|
|
|
|
fflush(NULL);
|
2007-10-19 21:48:06 +02:00
|
|
|
if (start_async(&async))
|
|
|
|
return 0; /* error was already reported */
|
2007-04-21 12:14:13 +02:00
|
|
|
|
2007-10-19 21:48:06 +02:00
|
|
|
if (strbuf_read(&nbuf, async.out, len) < 0) {
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
error("read from external filter %s failed", cmd);
|
|
|
|
ret = 0;
|
2007-04-21 12:14:13 +02:00
|
|
|
}
|
2007-10-19 21:48:06 +02:00
|
|
|
if (close(async.out)) {
|
2007-10-05 10:11:59 +02:00
|
|
|
error("read from external filter %s failed", cmd);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
ret = 0;
|
2007-04-21 12:14:13 +02:00
|
|
|
}
|
2007-10-19 21:48:06 +02:00
|
|
|
if (finish_async(&async)) {
|
|
|
|
error("external filter %s failed", cmd);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
ret = 0;
|
2007-04-21 12:14:13 +02:00
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
if (ret) {
|
2007-10-05 10:11:59 +02:00
|
|
|
strbuf_swap(dst, &nbuf);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
}
|
2007-10-05 10:11:59 +02:00
|
|
|
strbuf_release(&nbuf);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return ret;
|
2007-04-21 12:14:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct convert_driver {
|
|
|
|
const char *name;
|
|
|
|
struct convert_driver *next;
|
2008-07-05 07:24:42 +02:00
|
|
|
const char *smudge;
|
|
|
|
const char *clean;
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
int required;
|
2007-04-21 12:14:13 +02:00
|
|
|
} *user_convert, **user_convert_tail;
|
|
|
|
|
2008-05-14 19:46:53 +02:00
|
|
|
static int read_convert_config(const char *var, const char *value, void *cb)
|
2007-04-21 12:14:13 +02:00
|
|
|
{
|
|
|
|
const char *ep, *name;
|
|
|
|
int namelen;
|
|
|
|
struct convert_driver *drv;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* External conversion drivers are configured using
|
|
|
|
* "filter.<name>.variable".
|
|
|
|
*/
|
|
|
|
if (prefixcmp(var, "filter.") || (ep = strrchr(var, '.')) == var + 6)
|
|
|
|
return 0;
|
|
|
|
name = var + 7;
|
|
|
|
namelen = ep - name;
|
|
|
|
for (drv = user_convert; drv; drv = drv->next)
|
|
|
|
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
|
|
|
|
break;
|
|
|
|
if (!drv) {
|
|
|
|
drv = xcalloc(1, sizeof(struct convert_driver));
|
2007-09-16 00:32:36 +02:00
|
|
|
drv->name = xmemdupz(name, namelen);
|
2007-04-21 12:14:13 +02:00
|
|
|
*user_convert_tail = drv;
|
|
|
|
user_convert_tail = &(drv->next);
|
|
|
|
}
|
|
|
|
|
|
|
|
ep++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* filter.<name>.smudge and filter.<name>.clean specifies
|
|
|
|
* the command line:
|
|
|
|
*
|
|
|
|
* command-line
|
|
|
|
*
|
|
|
|
* The command-line will not be interpolated in any way.
|
|
|
|
*/
|
|
|
|
|
2008-07-05 07:24:42 +02:00
|
|
|
if (!strcmp("smudge", ep))
|
|
|
|
return git_config_string(&drv->smudge, var, value);
|
|
|
|
|
|
|
|
if (!strcmp("clean", ep))
|
|
|
|
return git_config_string(&drv->clean, var, value);
|
2007-04-21 12:14:13 +02:00
|
|
|
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
if (!strcmp("required", ep)) {
|
|
|
|
drv->required = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-21 12:14:13 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-22 04:09:02 +02:00
|
|
|
static int count_ident(const char *cp, unsigned long size)
|
|
|
|
{
|
|
|
|
/*
|
2007-05-14 15:37:25 +02:00
|
|
|
* "$Id: 0000000000000000000000000000000000000000 $" <=> "$Id$"
|
2007-04-22 04:09:02 +02:00
|
|
|
*/
|
|
|
|
int cnt = 0;
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
while (size) {
|
|
|
|
ch = *cp++;
|
|
|
|
size--;
|
|
|
|
if (ch != '$')
|
|
|
|
continue;
|
2007-05-14 15:37:25 +02:00
|
|
|
if (size < 3)
|
2007-04-22 04:09:02 +02:00
|
|
|
break;
|
2007-05-14 15:37:25 +02:00
|
|
|
if (memcmp("Id", cp, 2))
|
2007-04-22 04:09:02 +02:00
|
|
|
continue;
|
2007-05-14 15:37:25 +02:00
|
|
|
ch = cp[2];
|
|
|
|
cp += 3;
|
|
|
|
size -= 3;
|
2007-04-22 04:09:02 +02:00
|
|
|
if (ch == '$')
|
2007-05-14 15:37:25 +02:00
|
|
|
cnt++; /* $Id$ */
|
2007-04-22 04:09:02 +02:00
|
|
|
if (ch != ':')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
2007-05-14 15:37:25 +02:00
|
|
|
* "$Id: ... "; scan up to the closing dollar sign and discard.
|
2007-04-22 04:09:02 +02:00
|
|
|
*/
|
|
|
|
while (size) {
|
|
|
|
ch = *cp++;
|
|
|
|
size--;
|
|
|
|
if (ch == '$') {
|
|
|
|
cnt++;
|
|
|
|
break;
|
|
|
|
}
|
2010-04-06 14:46:37 +02:00
|
|
|
if (ch == '\n')
|
|
|
|
break;
|
2007-04-22 04:09:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
static int ident_to_git(const char *path, const char *src, size_t len,
|
|
|
|
struct strbuf *buf, int ident)
|
2007-04-22 04:09:02 +02:00
|
|
|
{
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
char *dst, *dollar;
|
2007-04-22 04:09:02 +02:00
|
|
|
|
2012-02-24 23:05:03 +01:00
|
|
|
if (!ident || (src && !count_ident(src, len)))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
|
|
|
|
2012-02-24 23:02:37 +01:00
|
|
|
if (!buf)
|
|
|
|
return 1;
|
|
|
|
|
2007-10-05 10:11:59 +02:00
|
|
|
/* only grow if not in place */
|
|
|
|
if (strbuf_avail(buf) + buf->len < len)
|
|
|
|
strbuf_grow(buf, len - buf->len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
dst = buf->buf;
|
|
|
|
for (;;) {
|
|
|
|
dollar = memchr(src, '$', len);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
2011-08-29 22:06:04 +02:00
|
|
|
memmove(dst, src, dollar + 1 - src);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
dst += dollar + 1 - src;
|
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
|
|
|
|
|
|
|
if (len > 3 && !memcmp(src, "Id:", 3)) {
|
|
|
|
dollar = memchr(src + 3, '$', len - 3);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
2010-04-06 14:46:37 +02:00
|
|
|
if (memchr(src + 3, '\n', dollar - src - 3)) {
|
|
|
|
/* Line break before the next dollar. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-05-14 15:37:25 +02:00
|
|
|
memcpy(dst, "Id$", 3);
|
|
|
|
dst += 3;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
2007-04-22 04:09:02 +02:00
|
|
|
}
|
|
|
|
}
|
2011-08-29 22:06:04 +02:00
|
|
|
memmove(dst, src, len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
strbuf_setlen(buf, dst + len - buf->buf);
|
|
|
|
return 1;
|
2007-04-22 04:09:02 +02:00
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
static int ident_to_worktree(const char *path, const char *src, size_t len,
|
|
|
|
struct strbuf *buf, int ident)
|
2007-04-22 04:09:02 +02:00
|
|
|
{
|
|
|
|
unsigned char sha1[20];
|
2010-04-06 14:46:38 +02:00
|
|
|
char *to_free = NULL, *dollar, *spc;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
int cnt;
|
2007-04-22 04:09:02 +02:00
|
|
|
|
|
|
|
if (!ident)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
2007-04-22 04:09:02 +02:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
cnt = count_ident(src, len);
|
2007-04-22 04:09:02 +02:00
|
|
|
if (!cnt)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
return 0;
|
2007-04-22 04:09:02 +02:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
/* are we "faking" in place editing ? */
|
|
|
|
if (src == buf->buf)
|
2007-09-27 12:58:23 +02:00
|
|
|
to_free = strbuf_detach(buf, NULL);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
hash_sha1_file(src, len, "blob", sha1);
|
2007-04-22 04:09:02 +02:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
strbuf_grow(buf, len + cnt * 43);
|
|
|
|
for (;;) {
|
|
|
|
/* step 1: run to the next '$' */
|
|
|
|
dollar = memchr(src, '$', len);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
|
|
|
strbuf_add(buf, src, dollar + 1 - src);
|
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 12:50:08 +02:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
/* step 2: does it looks like a bit like Id:xxx$ or Id$ ? */
|
|
|
|
if (len < 3 || memcmp("Id", src, 2))
|
2007-04-22 04:09:02 +02:00
|
|
|
continue;
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
/* step 3: skip over Id$ or Id:xxxxx$ */
|
|
|
|
if (src[2] == '$') {
|
|
|
|
src += 3;
|
|
|
|
len -= 3;
|
|
|
|
} else if (src[2] == ':') {
|
|
|
|
/*
|
|
|
|
* It's possible that an expanded Id has crept its way into the
|
2010-04-06 14:46:38 +02:00
|
|
|
* repository, we cope with that by stripping the expansion out.
|
|
|
|
* This is probably not a good idea, since it will cause changes
|
|
|
|
* on checkout, which won't go away by stash, but let's keep it
|
|
|
|
* for git-style ids.
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
*/
|
|
|
|
dollar = memchr(src + 3, '$', len - 3);
|
|
|
|
if (!dollar) {
|
|
|
|
/* incomplete keyword, no more '$', so just quit the loop */
|
|
|
|
break;
|
|
|
|
}
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 12:50:08 +02:00
|
|
|
|
2010-04-06 14:46:37 +02:00
|
|
|
if (memchr(src + 3, '\n', dollar - src - 3)) {
|
|
|
|
/* Line break before the next dollar. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-04-06 14:46:38 +02:00
|
|
|
spc = memchr(src + 4, ' ', dollar - src - 4);
|
|
|
|
if (spc && spc < dollar-1) {
|
|
|
|
/* There are spaces in unexpected places.
|
|
|
|
* This is probably an id from some other
|
|
|
|
* versioning system. Keep it for now.
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
|
|
|
} else {
|
|
|
|
/* it wasn't a "Id$" or "Id:xxxx$" */
|
|
|
|
continue;
|
|
|
|
}
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 12:50:08 +02:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
/* step 4: substitute */
|
|
|
|
strbuf_addstr(buf, "Id: ");
|
|
|
|
strbuf_add(buf, sha1_to_hex(sha1), 40);
|
|
|
|
strbuf_addstr(buf, " $");
|
2007-04-22 04:09:02 +02:00
|
|
|
}
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
strbuf_add(buf, src, len);
|
2007-04-22 04:09:02 +02:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
free(to_free);
|
|
|
|
return 1;
|
2007-04-13 07:30:05 +02:00
|
|
|
}
|
|
|
|
|
2011-11-15 17:59:37 +01:00
|
|
|
static enum crlf_action git_path_check_crlf(const char *path, struct git_attr_check *check)
|
2007-04-13 07:30:05 +02:00
|
|
|
{
|
2007-04-21 08:44:02 +02:00
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
if (ATTR_TRUE(value))
|
|
|
|
return CRLF_TEXT;
|
|
|
|
else if (ATTR_FALSE(value))
|
|
|
|
return CRLF_BINARY;
|
|
|
|
else if (ATTR_UNSET(value))
|
|
|
|
;
|
|
|
|
else if (!strcmp(value, "input"))
|
|
|
|
return CRLF_INPUT;
|
2010-05-19 22:43:10 +02:00
|
|
|
else if (!strcmp(value, "auto"))
|
|
|
|
return CRLF_AUTO;
|
2007-04-20 07:37:19 +02:00
|
|
|
return CRLF_GUESS;
|
2007-04-13 07:30:05 +02:00
|
|
|
}
|
|
|
|
|
2011-11-21 19:42:09 +01:00
|
|
|
static enum eol git_path_check_eol(const char *path, struct git_attr_check *check)
|
2010-05-19 22:43:10 +02:00
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
if (ATTR_UNSET(value))
|
|
|
|
;
|
|
|
|
else if (!strcmp(value, "lf"))
|
|
|
|
return EOL_LF;
|
|
|
|
else if (!strcmp(value, "crlf"))
|
|
|
|
return EOL_CRLF;
|
|
|
|
return EOL_UNSET;
|
|
|
|
}
|
|
|
|
|
2007-04-21 12:14:13 +02:00
|
|
|
static struct convert_driver *git_path_check_convert(const char *path,
|
|
|
|
struct git_attr_check *check)
|
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
struct convert_driver *drv;
|
|
|
|
|
|
|
|
if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
|
|
|
|
return NULL;
|
|
|
|
for (drv = user_convert; drv; drv = drv->next)
|
|
|
|
if (!strcmp(value, drv->name))
|
|
|
|
return drv;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-04-22 04:09:02 +02:00
|
|
|
static int git_path_check_ident(const char *path, struct git_attr_check *check)
|
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
return !!ATTR_TRUE(value);
|
|
|
|
}
|
|
|
|
|
2011-05-09 22:12:57 +02:00
|
|
|
static enum crlf_action input_crlf_action(enum crlf_action text_attr, enum eol eol_attr)
|
2010-07-02 21:20:47 +02:00
|
|
|
{
|
2010-05-19 22:43:11 +02:00
|
|
|
if (text_attr == CRLF_BINARY)
|
2010-05-19 22:43:10 +02:00
|
|
|
return CRLF_BINARY;
|
|
|
|
if (eol_attr == EOL_LF)
|
|
|
|
return CRLF_INPUT;
|
|
|
|
if (eol_attr == EOL_CRLF)
|
|
|
|
return CRLF_CRLF;
|
2010-05-19 22:43:11 +02:00
|
|
|
return text_attr;
|
2010-05-19 22:43:10 +02:00
|
|
|
}
|
|
|
|
|
2011-05-09 22:58:31 +02:00
|
|
|
struct conv_attrs {
|
|
|
|
struct convert_driver *drv;
|
|
|
|
enum crlf_action crlf_action;
|
|
|
|
enum eol eol_attr;
|
|
|
|
int ident;
|
|
|
|
};
|
|
|
|
|
2011-05-09 20:23:04 +02:00
|
|
|
static const char *conv_attr_name[] = {
|
|
|
|
"crlf", "ident", "filter", "eol", "text",
|
|
|
|
};
|
|
|
|
#define NUM_CONV_ATTRS ARRAY_SIZE(conv_attr_name)
|
|
|
|
|
2011-05-09 22:58:31 +02:00
|
|
|
static void convert_attrs(struct conv_attrs *ca, const char *path)
|
2011-05-09 20:23:04 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
static struct git_attr_check ccheck[NUM_CONV_ATTRS];
|
|
|
|
|
|
|
|
if (!ccheck[0].attr) {
|
|
|
|
for (i = 0; i < NUM_CONV_ATTRS; i++)
|
|
|
|
ccheck[i].attr = git_attr(conv_attr_name[i]);
|
|
|
|
user_convert_tail = &user_convert;
|
|
|
|
git_config(read_convert_config, NULL);
|
|
|
|
}
|
2011-05-09 22:58:31 +02:00
|
|
|
|
2011-08-04 06:36:33 +02:00
|
|
|
if (!git_check_attr(path, NUM_CONV_ATTRS, ccheck)) {
|
2011-05-09 22:58:31 +02:00
|
|
|
ca->crlf_action = git_path_check_crlf(path, ccheck + 4);
|
|
|
|
if (ca->crlf_action == CRLF_GUESS)
|
|
|
|
ca->crlf_action = git_path_check_crlf(path, ccheck + 0);
|
|
|
|
ca->ident = git_path_check_ident(path, ccheck + 1);
|
|
|
|
ca->drv = git_path_check_convert(path, ccheck + 2);
|
|
|
|
ca->eol_attr = git_path_check_eol(path, ccheck + 3);
|
|
|
|
} else {
|
|
|
|
ca->drv = NULL;
|
|
|
|
ca->crlf_action = CRLF_GUESS;
|
|
|
|
ca->eol_attr = EOL_UNSET;
|
|
|
|
ca->ident = 0;
|
|
|
|
}
|
2011-05-09 20:23:04 +02:00
|
|
|
}
|
|
|
|
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 12:25:58 +01:00
|
|
|
int convert_to_git(const char *path, const char *src, size_t len,
|
|
|
|
struct strbuf *dst, enum safe_crlf checksafe)
|
2007-04-13 07:30:05 +02:00
|
|
|
{
|
2011-05-09 22:58:31 +02:00
|
|
|
int ret = 0;
|
2008-07-05 07:24:42 +02:00
|
|
|
const char *filter = NULL;
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
int required = 0;
|
2011-05-09 22:58:31 +02:00
|
|
|
struct conv_attrs ca;
|
2007-04-21 08:44:02 +02:00
|
|
|
|
2011-05-09 22:58:31 +02:00
|
|
|
convert_attrs(&ca, path);
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
if (ca.drv) {
|
2011-05-09 22:58:31 +02:00
|
|
|
filter = ca.drv->clean;
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
required = ca.drv->required;
|
|
|
|
}
|
2007-04-22 04:09:02 +02:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
ret |= apply_filter(path, src, len, dst, filter);
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
if (!ret && required)
|
|
|
|
die("%s: clean filter '%s' failed", path, ca.drv->name);
|
|
|
|
|
2012-02-24 23:02:37 +01:00
|
|
|
if (ret && dst) {
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
2007-04-21 12:14:13 +02:00
|
|
|
}
|
2011-05-09 22:58:31 +02:00
|
|
|
ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
|
|
|
|
ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);
|
2012-02-24 23:02:37 +01:00
|
|
|
if (ret && dst) {
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
2007-04-21 08:44:02 +02:00
|
|
|
}
|
2011-05-09 22:58:31 +02:00
|
|
|
return ret | ident_to_git(path, src, len, dst, ca.ident);
|
2007-04-13 07:30:05 +02:00
|
|
|
}
|
|
|
|
|
2010-07-02 21:20:49 +02:00
|
|
|
static int convert_to_working_tree_internal(const char *path, const char *src,
|
|
|
|
size_t len, struct strbuf *dst,
|
|
|
|
int normalizing)
|
2007-04-13 07:30:05 +02:00
|
|
|
{
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
int ret = 0, ret_filter = 0;
|
2008-07-05 07:24:42 +02:00
|
|
|
const char *filter = NULL;
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
int required = 0;
|
2011-05-09 22:58:31 +02:00
|
|
|
struct conv_attrs ca;
|
2007-04-21 08:44:02 +02:00
|
|
|
|
2011-05-09 22:58:31 +02:00
|
|
|
convert_attrs(&ca, path);
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
if (ca.drv) {
|
2011-05-09 22:58:31 +02:00
|
|
|
filter = ca.drv->smudge;
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
required = ca.drv->required;
|
|
|
|
}
|
2007-04-22 04:09:02 +02:00
|
|
|
|
2011-05-09 22:58:31 +02:00
|
|
|
ret |= ident_to_worktree(path, src, len, dst, ca.ident);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 15:51:04 +02:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
2007-04-22 04:09:02 +02:00
|
|
|
}
|
2010-07-02 21:20:49 +02:00
|
|
|
/*
|
|
|
|
* CRLF conversion can be skipped if normalizing, unless there
|
|
|
|
* is a smudge filter. The filter might expect CRLFs.
|
|
|
|
*/
|
|
|
|
if (filter || !normalizing) {
|
2011-05-09 22:58:31 +02:00
|
|
|
ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
|
|
|
|
ret |= crlf_to_worktree(path, src, len, dst, ca.crlf_action);
|
2010-07-02 21:20:49 +02:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
2007-04-21 12:14:13 +02:00
|
|
|
}
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 02:19:03 +01:00
|
|
|
|
|
|
|
ret_filter = apply_filter(path, src, len, dst, filter);
|
|
|
|
if (!ret_filter && required)
|
|
|
|
die("%s: smudge filter %s failed", path, ca.drv->name);
|
|
|
|
|
|
|
|
return ret | ret_filter;
|
2007-04-13 07:30:05 +02:00
|
|
|
}
|
2010-07-02 21:20:47 +02:00
|
|
|
|
2010-07-02 21:20:49 +02:00
|
|
|
int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
|
|
|
|
{
|
|
|
|
return convert_to_working_tree_internal(path, src, len, dst, 0);
|
|
|
|
}
|
|
|
|
|
2010-07-02 21:20:47 +02:00
|
|
|
int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)
|
|
|
|
{
|
2010-07-02 21:20:49 +02:00
|
|
|
int ret = convert_to_working_tree_internal(path, src, len, dst, 1);
|
2010-07-02 21:20:47 +02:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
2011-11-15 17:59:37 +01:00
|
|
|
return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);
|
2010-07-02 21:20:47 +02:00
|
|
|
}
|
2011-05-12 23:31:08 +02:00
|
|
|
|
2011-05-20 23:33:31 +02:00
|
|
|
/*****************************************************************
|
|
|
|
*
|
|
|
|
* Streaming converison support
|
|
|
|
*
|
|
|
|
*****************************************************************/
|
|
|
|
|
|
|
|
typedef int (*filter_fn)(struct stream_filter *,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p);
|
|
|
|
typedef void (*free_fn)(struct stream_filter *);
|
|
|
|
|
|
|
|
struct stream_filter_vtbl {
|
|
|
|
filter_fn filter;
|
|
|
|
free_fn free;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct stream_filter {
|
|
|
|
struct stream_filter_vtbl *vtbl;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int null_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
2011-05-21 23:05:51 +02:00
|
|
|
size_t count;
|
|
|
|
|
|
|
|
if (!input)
|
|
|
|
return 0; /* we do not keep any states */
|
|
|
|
count = *isize_p;
|
2011-05-20 23:33:31 +02:00
|
|
|
if (*osize_p < count)
|
|
|
|
count = *osize_p;
|
|
|
|
if (count) {
|
|
|
|
memmove(output, input, count);
|
|
|
|
*isize_p -= count;
|
|
|
|
*osize_p -= count;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void null_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
; /* nothing -- null instances are shared */
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl null_vtbl = {
|
|
|
|
null_filter_fn,
|
|
|
|
null_free_fn,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct stream_filter null_filter_singleton = {
|
|
|
|
&null_vtbl,
|
|
|
|
};
|
|
|
|
|
|
|
|
int is_null_stream_filter(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
return filter == &null_filter_singleton;
|
|
|
|
}
|
|
|
|
|
2011-05-21 03:28:00 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* LF-to-CRLF filter
|
|
|
|
*/
|
2011-11-28 11:48:12 +01:00
|
|
|
|
|
|
|
struct lf_to_crlf_filter {
|
|
|
|
struct stream_filter filter;
|
2011-12-17 00:44:18 +01:00
|
|
|
unsigned has_held:1;
|
|
|
|
char held;
|
2011-11-28 11:48:12 +01:00
|
|
|
};
|
|
|
|
|
2011-05-21 01:47:56 +02:00
|
|
|
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
2011-11-28 11:48:12 +01:00
|
|
|
size_t count, o = 0;
|
|
|
|
struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
|
|
|
|
|
2011-12-17 00:44:18 +01:00
|
|
|
/*
|
|
|
|
* We may be holding onto the CR to see if it is followed by a
|
|
|
|
* LF, in which case we would need to go to the main loop.
|
|
|
|
* Otherwise, just emit it to the output stream.
|
|
|
|
*/
|
|
|
|
if (lf_to_crlf->has_held && (lf_to_crlf->held != '\r' || !input)) {
|
|
|
|
output[o++] = lf_to_crlf->held;
|
|
|
|
lf_to_crlf->has_held = 0;
|
2011-11-28 11:48:12 +01:00
|
|
|
}
|
2011-05-21 01:47:56 +02:00
|
|
|
|
2011-12-16 23:39:37 +01:00
|
|
|
/* We are told to drain */
|
|
|
|
if (!input) {
|
|
|
|
*osize_p -= o;
|
|
|
|
return 0;
|
|
|
|
}
|
2011-05-21 01:47:56 +02:00
|
|
|
|
|
|
|
count = *isize_p;
|
2011-12-17 00:44:18 +01:00
|
|
|
if (count || lf_to_crlf->has_held) {
|
2011-11-28 11:48:12 +01:00
|
|
|
size_t i;
|
2011-12-17 00:44:18 +01:00
|
|
|
int was_cr = 0;
|
|
|
|
|
|
|
|
if (lf_to_crlf->has_held) {
|
|
|
|
was_cr = 1;
|
|
|
|
lf_to_crlf->has_held = 0;
|
|
|
|
}
|
|
|
|
|
2011-11-28 11:48:12 +01:00
|
|
|
for (i = 0; o < *osize_p && i < count; i++) {
|
2011-05-21 01:47:56 +02:00
|
|
|
char ch = input[i];
|
2011-12-17 00:44:18 +01:00
|
|
|
|
2011-05-21 01:47:56 +02:00
|
|
|
if (ch == '\n') {
|
2011-11-28 11:48:12 +01:00
|
|
|
output[o++] = '\r';
|
2011-12-17 00:44:18 +01:00
|
|
|
} else if (was_cr) {
|
|
|
|
/*
|
|
|
|
* Previous round saw CR and it is not followed
|
|
|
|
* by a LF; emit the CR before processing the
|
|
|
|
* current character.
|
|
|
|
*/
|
|
|
|
output[o++] = '\r';
|
2011-05-21 01:47:56 +02:00
|
|
|
}
|
2011-12-17 00:44:18 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We may have consumed the last output slot,
|
|
|
|
* in which case we need to break out of this
|
|
|
|
* loop; hold the current character before
|
|
|
|
* returning.
|
|
|
|
*/
|
|
|
|
if (*osize_p <= o) {
|
|
|
|
lf_to_crlf->has_held = 1;
|
|
|
|
lf_to_crlf->held = ch;
|
|
|
|
continue; /* break but increment i */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch == '\r') {
|
|
|
|
was_cr = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
was_cr = 0;
|
2011-05-21 01:47:56 +02:00
|
|
|
output[o++] = ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
*osize_p -= o;
|
|
|
|
*isize_p -= i;
|
2011-12-17 00:44:18 +01:00
|
|
|
|
|
|
|
if (!lf_to_crlf->has_held && was_cr) {
|
|
|
|
lf_to_crlf->has_held = 1;
|
|
|
|
lf_to_crlf->held = '\r';
|
|
|
|
}
|
2011-05-21 01:47:56 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-28 11:48:12 +01:00
|
|
|
static void lf_to_crlf_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
2011-05-21 01:47:56 +02:00
|
|
|
static struct stream_filter_vtbl lf_to_crlf_vtbl = {
|
|
|
|
lf_to_crlf_filter_fn,
|
2011-11-28 11:48:12 +01:00
|
|
|
lf_to_crlf_free_fn,
|
2011-05-21 01:47:56 +02:00
|
|
|
};
|
|
|
|
|
2011-11-28 11:48:12 +01:00
|
|
|
static struct stream_filter *lf_to_crlf_filter(void)
|
|
|
|
{
|
2011-12-16 23:39:37 +01:00
|
|
|
struct lf_to_crlf_filter *lf_to_crlf = xcalloc(1, sizeof(*lf_to_crlf));
|
2011-05-21 01:47:56 +02:00
|
|
|
|
2011-11-28 11:48:12 +01:00
|
|
|
lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl;
|
|
|
|
return (struct stream_filter *)lf_to_crlf;
|
|
|
|
}
|
2011-05-21 03:28:00 +02:00
|
|
|
|
2011-05-22 03:28:41 +02:00
|
|
|
/*
|
|
|
|
* Cascade filter
|
|
|
|
*/
|
|
|
|
#define FILTER_BUFFER 1024
|
|
|
|
struct cascade_filter {
|
|
|
|
struct stream_filter filter;
|
|
|
|
struct stream_filter *one;
|
|
|
|
struct stream_filter *two;
|
|
|
|
char buf[FILTER_BUFFER];
|
|
|
|
int end, ptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int cascade_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cas = (struct cascade_filter *) filter;
|
|
|
|
size_t filled = 0;
|
|
|
|
size_t sz = *osize_p;
|
|
|
|
size_t to_feed, remaining;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* input -- (one) --> buf -- (two) --> output
|
|
|
|
*/
|
|
|
|
while (filled < sz) {
|
|
|
|
remaining = sz - filled;
|
|
|
|
|
|
|
|
/* do we already have something to feed two with? */
|
|
|
|
if (cas->ptr < cas->end) {
|
|
|
|
to_feed = cas->end - cas->ptr;
|
|
|
|
if (stream_filter(cas->two,
|
|
|
|
cas->buf + cas->ptr, &to_feed,
|
|
|
|
output + filled, &remaining))
|
|
|
|
return -1;
|
|
|
|
cas->ptr += (cas->end - cas->ptr) - to_feed;
|
|
|
|
filled = sz - remaining;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* feed one from upstream and have it emit into our buffer */
|
|
|
|
to_feed = input ? *isize_p : 0;
|
|
|
|
if (input && !to_feed)
|
|
|
|
break;
|
|
|
|
remaining = sizeof(cas->buf);
|
|
|
|
if (stream_filter(cas->one,
|
|
|
|
input, &to_feed,
|
|
|
|
cas->buf, &remaining))
|
|
|
|
return -1;
|
|
|
|
cas->end = sizeof(cas->buf) - remaining;
|
|
|
|
cas->ptr = 0;
|
|
|
|
if (input) {
|
|
|
|
size_t fed = *isize_p - to_feed;
|
|
|
|
*isize_p -= fed;
|
|
|
|
input += fed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do we know that we drained one completely? */
|
|
|
|
if (input || cas->end)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* tell two to drain; we have nothing more to give it */
|
|
|
|
to_feed = 0;
|
|
|
|
remaining = sz - filled;
|
|
|
|
if (stream_filter(cas->two,
|
|
|
|
NULL, &to_feed,
|
|
|
|
output + filled, &remaining))
|
|
|
|
return -1;
|
|
|
|
if (remaining == (sz - filled))
|
|
|
|
break; /* completely drained two */
|
|
|
|
filled = sz - remaining;
|
|
|
|
}
|
|
|
|
*osize_p -= filled;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cascade_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cas = (struct cascade_filter *)filter;
|
|
|
|
free_stream_filter(cas->one);
|
|
|
|
free_stream_filter(cas->two);
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl cascade_vtbl = {
|
|
|
|
cascade_filter_fn,
|
|
|
|
cascade_free_fn,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct stream_filter *cascade_filter(struct stream_filter *one,
|
|
|
|
struct stream_filter *two)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cascade;
|
|
|
|
|
|
|
|
if (!one || is_null_stream_filter(one))
|
|
|
|
return two;
|
|
|
|
if (!two || is_null_stream_filter(two))
|
|
|
|
return one;
|
|
|
|
|
|
|
|
cascade = xmalloc(sizeof(*cascade));
|
|
|
|
cascade->one = one;
|
|
|
|
cascade->two = two;
|
|
|
|
cascade->end = cascade->ptr = 0;
|
|
|
|
cascade->filter.vtbl = &cascade_vtbl;
|
|
|
|
return (struct stream_filter *)cascade;
|
|
|
|
}
|
|
|
|
|
2011-05-21 03:28:00 +02:00
|
|
|
/*
|
|
|
|
* ident filter
|
|
|
|
*/
|
|
|
|
#define IDENT_DRAINING (-1)
|
|
|
|
#define IDENT_SKIPPING (-2)
|
|
|
|
struct ident_filter {
|
|
|
|
struct stream_filter filter;
|
|
|
|
struct strbuf left;
|
|
|
|
int state;
|
|
|
|
char ident[45]; /* ": x40 $" */
|
|
|
|
};
|
|
|
|
|
|
|
|
static int is_foreign_ident(const char *str)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (prefixcmp(str, "$Id: "))
|
|
|
|
return 0;
|
|
|
|
for (i = 5; str[i]; i++) {
|
|
|
|
if (isspace(str[i]) && str[i+1] != '$')
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ident_drain(struct ident_filter *ident, char **output_p, size_t *osize_p)
|
|
|
|
{
|
|
|
|
size_t to_drain = ident->left.len;
|
|
|
|
|
|
|
|
if (*osize_p < to_drain)
|
|
|
|
to_drain = *osize_p;
|
|
|
|
if (to_drain) {
|
|
|
|
memcpy(*output_p, ident->left.buf, to_drain);
|
|
|
|
strbuf_remove(&ident->left, 0, to_drain);
|
|
|
|
*output_p += to_drain;
|
|
|
|
*osize_p -= to_drain;
|
|
|
|
}
|
|
|
|
if (!ident->left.len)
|
|
|
|
ident->state = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ident_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
struct ident_filter *ident = (struct ident_filter *)filter;
|
|
|
|
static const char head[] = "$Id";
|
|
|
|
|
|
|
|
if (!input) {
|
|
|
|
/* drain upon eof */
|
|
|
|
switch (ident->state) {
|
|
|
|
default:
|
|
|
|
strbuf_add(&ident->left, head, ident->state);
|
|
|
|
case IDENT_SKIPPING:
|
|
|
|
/* fallthru */
|
|
|
|
case IDENT_DRAINING:
|
|
|
|
ident_drain(ident, &output, osize_p);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*isize_p || (ident->state == IDENT_DRAINING)) {
|
|
|
|
int ch;
|
|
|
|
|
|
|
|
if (ident->state == IDENT_DRAINING) {
|
|
|
|
ident_drain(ident, &output, osize_p);
|
|
|
|
if (!*osize_p)
|
|
|
|
break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch = *(input++);
|
|
|
|
(*isize_p)--;
|
|
|
|
|
|
|
|
if (ident->state == IDENT_SKIPPING) {
|
|
|
|
/*
|
|
|
|
* Skipping until '$' or LF, but keeping them
|
|
|
|
* in case it is a foreign ident.
|
|
|
|
*/
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
if (ch != '\n' && ch != '$')
|
|
|
|
continue;
|
|
|
|
if (ch == '$' && !is_foreign_ident(ident->left.buf)) {
|
|
|
|
strbuf_setlen(&ident->left, sizeof(head) - 1);
|
|
|
|
strbuf_addstr(&ident->left, ident->ident);
|
|
|
|
}
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ident->state < sizeof(head) &&
|
|
|
|
head[ident->state] == ch) {
|
|
|
|
ident->state++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ident->state)
|
|
|
|
strbuf_add(&ident->left, head, ident->state);
|
|
|
|
if (ident->state == sizeof(head) - 1) {
|
|
|
|
if (ch != ':' && ch != '$') {
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch == ':') {
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = IDENT_SKIPPING;
|
|
|
|
} else {
|
|
|
|
strbuf_addstr(&ident->left, ident->ident);
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ident_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
struct ident_filter *ident = (struct ident_filter *)filter;
|
|
|
|
strbuf_release(&ident->left);
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl ident_vtbl = {
|
|
|
|
ident_filter_fn,
|
|
|
|
ident_free_fn,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct stream_filter *ident_filter(const unsigned char *sha1)
|
|
|
|
{
|
|
|
|
struct ident_filter *ident = xmalloc(sizeof(*ident));
|
|
|
|
|
|
|
|
sprintf(ident->ident, ": %s $", sha1_to_hex(sha1));
|
|
|
|
strbuf_init(&ident->left, 0);
|
|
|
|
ident->filter.vtbl = &ident_vtbl;
|
|
|
|
ident->state = 0;
|
|
|
|
return (struct stream_filter *)ident;
|
|
|
|
}
|
|
|
|
|
2011-05-12 23:31:08 +02:00
|
|
|
/*
|
2011-05-20 23:33:31 +02:00
|
|
|
* Return an appropriately constructed filter for the path, or NULL if
|
|
|
|
* the contents cannot be filtered without reading the whole thing
|
|
|
|
* in-core.
|
|
|
|
*
|
|
|
|
* Note that you would be crazy to set CRLF, smuge/clean or ident to a
|
|
|
|
* large binary blob you would want us not to slurp into the memory!
|
2011-05-12 23:31:08 +02:00
|
|
|
*/
|
2011-05-20 23:33:31 +02:00
|
|
|
struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)
|
2011-05-12 23:31:08 +02:00
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
|
|
|
enum crlf_action crlf_action;
|
2011-05-21 03:28:00 +02:00
|
|
|
struct stream_filter *filter = NULL;
|
2011-05-12 23:31:08 +02:00
|
|
|
|
|
|
|
convert_attrs(&ca, path);
|
|
|
|
|
2011-05-21 03:28:00 +02:00
|
|
|
if (ca.drv && (ca.drv->smudge || ca.drv->clean))
|
|
|
|
return filter;
|
|
|
|
|
|
|
|
if (ca.ident)
|
|
|
|
filter = ident_filter(sha1);
|
2011-05-12 23:31:08 +02:00
|
|
|
|
|
|
|
crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
|
2011-05-21 03:28:00 +02:00
|
|
|
|
2011-05-21 01:14:32 +02:00
|
|
|
if ((crlf_action == CRLF_BINARY) || (crlf_action == CRLF_INPUT) ||
|
2011-05-22 03:28:41 +02:00
|
|
|
(crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE))
|
|
|
|
filter = cascade_filter(filter, &null_filter_singleton);
|
|
|
|
|
|
|
|
else if (output_eol(crlf_action) == EOL_CRLF &&
|
|
|
|
!(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
|
2011-11-28 11:48:12 +01:00
|
|
|
filter = cascade_filter(filter, lf_to_crlf_filter());
|
2011-05-21 01:47:56 +02:00
|
|
|
|
2011-05-21 03:28:00 +02:00
|
|
|
return filter;
|
2011-05-20 23:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void free_stream_filter(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
filter->vtbl->free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
int stream_filter(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
return filter->vtbl->filter(filter, input, isize_p, output, osize_p);
|
2011-05-12 23:31:08 +02:00
|
|
|
}
|