From: David Barr <hidden> Date: 2016-06-15 22:49:47
This series follows Jonathan Nieder's svn diff applier series.
Patch 1 adds the required infrastructure to fast-import.
This features the addition of the cat-blob command to
fast-import. This allows access to blobs written to the
the current pack prior to a checkpoint and is critical to
retrieving full-texts to drive the diff applier.
Patch 2 adds the basic parsing necessary to process the v3 format.
Patch 3 adds logic around decoding prop deltas.
Patch 5 integrates svn-fe with svn-da to decode text deltas.
It is based on a large patch authored by Jonathan and inspired by Ram.
It has been heavily trimmed to reduce code bloat and enabled me to
determine the logic for the previous patches.
A bit shout-out to Jonathan Nieder and Ramkumar Ramachandra for
their help in bring this series into existence.
I have tried to incorporate all the feedback on the list and over
at #git-devel. I hope to impress.
--
David Barr.
From: David Barr <hidden> Date: 2016-06-15 22:49:47
Use the new cat-blob command for fast-import to extract
blobs so that text-deltas may be applied.
The backchannel should only need to be configured when
parsing v3 svn dump streams.
Based-on-patch-by: Ramkumar Ramachandra [off-list ref]
Based-on-patch-by: Jonathan Nieder [off-list ref]
Tested-by: David Barr <redacted>
Signed-off-by: David Barr <redacted>
---
contrib/svn-fe/svn-fe.txt | 6 +++-
t/t9010-svn-fe.sh | 6 ++--
vcs-svn/fast_export.c | 86 +++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 92 insertions(+), 6 deletions(-)
@@ -63,16 +70,91 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log,printf("progress Imported commit %"PRIu32".\n\n",revision);}+staticintfast_export_save_blob(FILE*out)+{+size_tlen;+char*header;+char*end;+char*tail;++if(!backchannel.infile)+backchannel.infile=fdopen(REPORT_FILENO,"r");+if(!backchannel.infile)+returnerror("Could not open backchannel fd: %d",REPORT_FILENO);+header=buffer_read_line(&backchannel);+if(header==NULL)+return1;+end=strchr(header,'\0');+if(end-header>7&&!strcmp(end-7,"missing"))+returnerror("cat-blob reports missing blob: %s",header);+if(end-header<SHA1_HEX_LENGTH)+returnerror("cat-blob header too short for SHA1: %s",header);+if(strncmp(header+SHA1_HEX_LENGTH," blob ",6))+returnerror("cat-blob header has wrong object type: %s",header);+len=strtoumax(header+SHA1_HEX_LENGTH+6,&end,10);+if(end==header+SHA1_HEX_LENGTH+6)+returnerror("cat-blob header did not contain length: %s",header);+if(*end)+returnerror("cat-blob header contained garbage after length: %s",header);+buffer_copy_bytes(&backchannel,out,len);+tail=buffer_read_line(&backchannel);+if(!tail)+return1;+if(*tail)+returnerror("cat-blob trailing line contained garbage: %s",tail);+return0;+}+voidfast_export_blob(uint32_tmode,uint32_tmark,uint32_tlen,uint32_tdelta,uint32_tsrcMark,uint32_tsrcMode,structline_buffer*input){+longpreimage_len=0;++if(delta){+if(!preimage.infile)+preimage.infile=tmpfile();+if(!preimage.infile)+die("Unable to open temp file for blob retrieval");+if(srcMark){+printf("cat-blob :%"PRIu32"\n",srcMark);+fflush(stdout);+if(srcMode==REPO_MODE_LNK)+fwrite("link ",1,5,preimage.infile);+if(fast_export_save_blob(preimage.infile))+die("Failed to retrieve blob for delta application");+}+preimage_len=ftell(preimage.infile);+fseek(preimage.infile,0,SEEK_SET);+if(!postimage.infile)+postimage.infile=tmpfile();+if(!postimage.infile)+die("Unable to open temp file for blob application");+svndiff0_apply(input,len,&preimage,postimage.infile);+len=ftell(postimage.infile);+fseek(postimage.infile,0,SEEK_SET);+}+if(mode==REPO_MODE_LNK){/* svn symlink blobs start with "link " */-buffer_skip_bytes(input,5);+if(delta)+buffer_skip_bytes(&postimage,5);+else+buffer_skip_bytes(input,5);len-=5;}printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n",mark,len);-buffer_copy_bytes(input,stdout,len);+if(!delta)+buffer_copy_bytes(input,stdout,len);+else+buffer_copy_bytes(&postimage,stdout,len);fputc('\n',stdout);++if(preimage.infile){+fseek(preimage.infile,0,SEEK_SET);+}++if(postimage.infile){+fseek(postimage.infile,0,SEEK_SET);+}}
From: David Barr <hidden> Date: 2016-06-15 22:49:47
By testing against the Apache Software Foundation
repository, some simple rules for decoding prop
deltas were derived.
'Node-action: replace' implies the empty prop set
as the base for the delta.
Otherwise, if a copyfrom source is given that node
forms the basis for the delta.
Lastly, if the destination path exists in the active
revision it forms the basis.
The same rules ought to apply to text deltas as well.
Apply these rules to prop handling.
Add a placeholder srcMark parameter to fast_export_blob().
Signed-off-by: David Barr <redacted>
---
vcs-svn/fast_export.c | 4 +++-
vcs-svn/fast_export.h | 3 ++-
vcs-svn/repo_tree.c | 23 +++++++++++++++++++++++
vcs-svn/repo_tree.h | 2 ++
vcs-svn/svndump.c | 35 +++++++++++++++++++++++++++++++----
5 files changed, 61 insertions(+), 6 deletions(-)
From: David Barr <hidden> Date: 2016-06-15 22:49:47
As the description of the "progress" option in git-fast-import.1
hints, there is no convenient way to immediately access the blobs
written to a new repository through fast-import. Until a checkpoint
has been started and finishes writing the pack index, any new blobs
will not be accessible using standard git tools.
So introduce another way: a "cat-blob" command introduced in the
command stream requests for fast-import to print a blob to stdout
or a file descriptor specified by the argument --cat-blob-fd.
The output uses the same format as "git cat-file --batch".
Cc: Shawn O. Pearce <redacted>
Cc: Ramkumar Ramachandra <redacted>
Helped-by: Sverre Rabbelier [off-list ref]
Based-on-patch-by: Jonathan Nieder [off-list ref]
Signed-off-by: David Barr <redacted>
---
Documentation/git-fast-import.txt | 34 ++++++++++++++
fast-import.c | 92 +++++++++++++++++++++++++++++++++++++
2 files changed, 126 insertions(+), 0 deletions(-)
@@ -92,6 +92,17 @@ OPTIONS --(no-)-relative-marks= with the --(import|export)-marks= options.+--cat-blob-fd=<fd>::+ Specify the file descriptor that will be written to+ when the `cat-blob` command is encountered in the stream.+ The default behaviour is to write to `stdout`.+++The described objects are not necessarily accessible+using standard git plumbing tools until a little while+after the next checkpoint. To request access to the+blobs before then, use `cat-blob` lines in the command+stream.+ --export-pack-edges=<file>:: After creating a packfile, print a line of data to <file> listing the filename of the packfile and the last
@@ -320,6 +331,11 @@ and control the current import process. More detailed discussion standard output. This command is optional and is not needed to perform an import.+`cat-blob`::+ Causes fast-import to print a blob in 'cat-file --batch'+ format to the file descriptor set with `--cat-blob-fd` or+ `stdout` if unspecified.+ `feature`:: Require that fast-import supports the specified feature, or abort if it does not.
@@ -876,6 +892,23 @@ Placing a `progress` command immediately after a `checkpoint` will inform the reader when the `checkpoint` has been completed and it can safely access the refs that fast-import updated.+`cat-blob`+~~~~~+Causes fast-import to print a blob to a file descriptor previously+arranged with the `--cat-blob-fd` argument. The command otherwise+has no impact on the current import; its main purpose is to+retrieve blobs that may be in fast-import's memory but not+accessible from the target repository a little quicker than by the+method suggested by the description of the `progress` option.++....+ 'cat-blob' SP <dataref> LF+....++The `<dataref>` can be either a mark reference (`:<idnum>`)+set previously, or a full 40-byte SHA-1 of any Git blob,+preexisting or ready to be written.+ `feature` ~~~~~~~~~ Require that fast-import supports the specified feature, or abort if
@@ -896,6 +929,7 @@ The following features are currently supported: * date-format * import-marks * export-marks+* cat-blob * relative-marks * no-relative-marks * force
@@ -55,6 +55,8 @@ Format of STDIN stream:('from'spcommittishlf)?lf?;+cat_blob::='cat-blob'sp(hexsha1|idnum)lf;+checkpoint::='checkpoint'lflf?;
@@ -361,6 +363,9 @@ static uintmax_t next_mark;staticstructstrbufnew_data=STRBUF_INIT;staticintseen_data_command;+/* Where to write output of cat-blob commands */+staticintcat_blob_fd=1;+staticvoidparse_argv(void);staticvoidwrite_branch_report(FILE*rpt,structbranch*b)
@@ -2680,6 +2685,77 @@ static void parse_reset_branch(void)unread_command_buf=1;}+staticvoidcat_blob_write(constchar*buf,unsignedlongsize)+{+if(write_in_full(cat_blob_fd,buf,size)!=size)+die_errno("Write to frontend failed");+}++staticvoidcat_blob(structobject_entry*oe,unsignedcharsha1[20])+{+structstrbufline=STRBUF_INIT;+unsignedlongsize;+enumobject_typetype=0;+char*buf;++if(oe&&oe->pack_id!=MAX_PACK_ID){+type=oe->type;+buf=gfi_unpack_entry(oe,&size);+}else{+buf=read_sha1_file(sha1,&type,&size);+}+if(!buf)+die("Can't read object %s",sha1_to_hex(sha1));++/*+*Outputbasedonbatch_one_object()fromcat-file.c.+*/+if(type<=0){+strbuf_reset(&line);+strbuf_addf(&line,"%s missing\n",sha1_to_hex(sha1));+cat_blob_write(line.buf,line.len);+return;+}elseif(type!=OBJ_BLOB){+die("Object %s is a %s but a blob was expected.",+sha1_to_hex(sha1),typename(type));+}+strbuf_reset(&line);+strbuf_addf(&line,"%s %s %lu\n",sha1_to_hex(sha1),+typename(type),size);+cat_blob_write(line.buf,line.len);+cat_blob_write(buf,size);+cat_blob_write("\n",1);+free(buf);+}+++staticvoidparse_cat_blob(void)+{+constchar*p;+structobject_entry*oe=oe;+unsignedcharsha1[20];++/* cat SP <object> */+p=command_buf.buf+strlen("cat-blob ");+if(*p==':'){+char*x;+oe=find_mark(strtoumax(p+1,&x,10));+if(x==p+1)+die("Invalid mark: %s",command_buf.buf);+if(!oe)+die("Unknown mark: %s",command_buf.buf);+p=x;+hashcpy(sha1,oe->idx.sha1);+}else{+if(get_sha1_hex(p,sha1))+die("Invalid SHA1: %s",command_buf.buf);+p+=40;+oe=find_object(sha1);+}++cat_blob(oe,sha1);+}+staticvoidparse_checkpoint(void){if(object_count){
@@ -2808,6 +2892,8 @@ static int parse_one_feature(const char *feature, int from_stream)option_import_marks(feature+13,from_stream);}elseif(!prefixcmp(feature,"export-marks=")){option_export_marks(feature+13);+}elseif(!prefixcmp(feature,"cat-blob")){+/* Don't die - this feature is supported */}elseif(!prefixcmp(feature,"relative-marks")){relative_marks_paths=1;}elseif(!prefixcmp(feature,"no-relative-marks")){
Note to reviewers: The function looks like this in `master`:
void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len)
New parameters intrduced in the svn-fe3 series: srcMark, srcMode,
delta, input.
+ long preimage_len = 0;
+
+ if (delta) {
+ if (!preimage.infile)
+ preimage.infile = tmpfile();
Didn't you later decide against this and use one tmpfile instead? In
this case, the temporary file will be automatically deleted when
`preimage.infile` goes out of scope.
+ if (!preimage.infile)
+ die("Unable to open temp file for blob retrieval");
+ if (srcMark) {
+ printf("cat-blob :%"PRIu32"\n", srcMark);
+ fflush(stdout);
+ if (srcMode == REPO_MODE_LNK)
+ fwrite("link ", 1, 5, preimage.infile);
Special handling for symbolic links. Perhaps you should mention it in
a comment here?
+ if (fast_export_save_blob(preimage.infile))
+ die("Failed to retrieve blob for delta application");
+ }
+ preimage_len = ftell(preimage.infile);
+ fseek(preimage.infile, 0, SEEK_SET);
+ if (!postimage.infile)
+ postimage.infile = tmpfile();
One tmpfile?
+ if (!postimage.infile)
+ die("Unable to open temp file for blob application");
+ svndiff0_apply(input, len, &preimage, postimage.infile);
+ len = ftell(postimage.infile);
Since you already have a preimage_len, perhaps name this postimage_len
to avoid confusion?
As the description of the "progress" option in git-fast-import.1
hints, there is no convenient way to immediately access the blobs
written to a new repository through fast-import. Until a checkpoint
has been started and finishes writing the pack index, any new blobs
will not be accessible using standard git tools.
So introduce another way: a "cat-blob" command introduced in the
command stream requests for fast-import to print a blob to stdout
or a file descriptor specified by the argument --cat-blob-fd.
The output uses the same format as "git cat-file --batch".
Nice :) It looks like we finally have a nice polished version.
Caution: Most of the review are just notes to self, or style
nitpicks. Feel free to ignore.
@@ -92,6 +92,17 @@ OPTIONS --(no-)-relative-marks= with the --(import|export)-marks= options.+--cat-blob-fd=<fd>::+ Specify the file descriptor that will be written to+ when the `cat-blob` command is encountered in the stream.+ The default behaviour is to write to `stdout`.+++The described objects are not necessarily accessible+using standard git plumbing tools until a little while+after the next checkpoint. To request access to the+blobs before then, use `cat-blob` lines in the command+stream.+ --export-pack-edges=<file>:: After creating a packfile, print a line of data to <file> listing the filename of the packfile and the last
@@ -320,6 +331,11 @@ and control the current import process. More detailed discussion standard output. This command is optional and is not needed to perform an import.+`cat-blob`::+ Causes fast-import to print a blob in 'cat-file --batch'+ format to the file descriptor set with `--cat-blob-fd` or+ `stdout` if unspecified.+ `feature`:: Require that fast-import supports the specified feature, or abort if it does not.
@@ -876,6 +892,23 @@ Placing a `progress` command immediately after a `checkpoint` will inform the reader when the `checkpoint` has been completed and it can safely access the refs that fast-import updated.+`cat-blob`+~~~~~+Causes fast-import to print a blob to a file descriptor previously+arranged with the `--cat-blob-fd` argument. The command otherwise+has no impact on the current import; its main purpose is to+retrieve blobs that may be in fast-import's memory but not+accessible from the target repository a little quicker than by the+method suggested by the description of the `progress` option.++....+ 'cat-blob' SP <dataref> LF+....++The `<dataref>` can be either a mark reference (`:<idnum>`)+set previously, or a full 40-byte SHA-1 of any Git blob,+preexisting or ready to be written.+ `feature` ~~~~~~~~~ Require that fast-import supports the specified feature, or abort if
@@ -896,6 +929,7 @@ The following features are currently supported: * date-format * import-marks * export-marks+* cat-blob * relative-marks * no-relative-marks * force
@@ -55,6 +55,8 @@ Format of STDIN stream:('from'spcommittishlf)?lf?;+cat_blob::='cat-blob'sp(hexsha1|idnum)lf;+checkpoint::='checkpoint'lflf?;
@@ -361,6 +363,9 @@ static uintmax_t next_mark;staticstructstrbufnew_data=STRBUF_INIT;staticintseen_data_command;+/* Where to write output of cat-blob commands */+staticintcat_blob_fd=1;+
Right. Defaults to stdout, as described in documentation.
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:49:48
(+cc: Sam)
Hi,
David Barr wrote:
So introduce another way: a "cat-blob" command introduced in the
command stream requests for fast-import to print a blob to stdout
or a file descriptor specified by the argument --cat-blob-fd.
Yes, please!
Cc: Shawn O. Pearce <redacted>
Cc: Ramkumar Ramachandra <redacted>
It turns out these Cc tags are not supposed to be used except in
some very weird circumstances. See [1] if curious.
[...]
@@ -92,6 +92,17 @@ OPTIONS --(no-)-relative-marks= with the --(import|export)-marks= options.+--cat-blob-fd=<fd>::+ Specify the file descriptor that will be written to+ when the `cat-blob` command is encountered in the stream.+ The default behaviour is to write to `stdout`.
Sounds good.
++
+The described objects are not necessarily accessible
+using standard git plumbing tools until a little while
+after the next checkpoint. To request access to the
+blobs before then, use `cat-blob` lines in the command
+stream.
This is stale explanation from --report-fd, I think, to explain
why the commit ids it printed were not very useful. It would
be possible to reword it to describe cat-blob-fd but since the
frontend does not have easy access to blob names as it is, I
think cat-blob motivates itself on its own.
[...]
quoted hunk
@@ -876,6 +892,23 @@ Placing a `progress` command immediately after a `checkpoint` will inform the reader when the `checkpoint` has been completed and it can safely access the refs that fast-import updated.+`cat-blob`+~~~~~
~~~~~~~~~~
quoted hunk
@@ -896,6 +929,7 @@ The following features are currently supported: * date-format * import-marks * export-marks+* cat-blob
The explanation says (paraphrased) "Features work identically to their
option counterparts, with the exception of import-marks as described
below".
Maybe ought to be reworded?
date-format::
export-marks::
relative-marks::
no-relative-marks::
force::
See the corresponding command-line option.
import-marks::
Like --import-marks, except in two respects. First, only one
"feature import-marks" command is allowed per stream. Second,
an --import-marks= specified on the command line will override it.
cat-blob::
No-op to check that the importer supports the cat-blob command.
By the way, it might be nice to make cat-blob not just check the importer
but the environment in which it was invoked, like this:
exporter says:
feature this
feature that
feature cat-blob
feature another
...
importer says:
feature cat-blob
That is, after writing "feature cat-blob\n", an exporter could tell if
the backchannel was set up correctly by reading for "feature cat-blob\n"
from the importer.
quoted hunk
--- a/fast-import.c+++ b/fast-import.c
@@ -2680,6 +2685,77 @@ static void parse_reset_branch(void)unread_command_buf=1;}+staticvoidcat_blob_write(constchar*buf,unsignedlongsize)+{+if(write_in_full(cat_blob_fd,buf,size)!=size)+die_errno("Write to frontend failed");+}
An odd operation, since if the pipe_buf gets filled then it blocks
until the exporter finds time to read. Maybe in some future version
this would write to a private ring buffer and there would be an
event loop or seperate thread to flush it out when the exporter is
ready.
Upshot: I am happy with this as a separate function.
[...]
quoted hunk
@@ -2808,6 +2892,8 @@ static int parse_one_feature(const char *feature, int from_stream) option_import_marks(feature + 13, from_stream); } else if (!prefixcmp(feature, "export-marks=")) { option_export_marks(feature + 13);+ } else if (!prefixcmp(feature, "cat-blob")) {+ /* Don't die - this feature is supported */
Probably worth mentioning in the manual, under the option command:
The following command-line option describes the environment
in which fast-import was executed and may not be passed to
'option':
* cat-blob-fd
quoted hunk
@@ -2953,6 +3043,8 @@ int main(int argc, const char **argv) parse_new_tag(); else if (!prefixcmp(command_buf.buf, "reset ")) parse_reset_branch();+ else if (!prefixcmp(command_buf.buf, "cat-blob "))+ parse_cat_blob();
You don't display an appropriate error when n < 0.
How can n be < 0? strtoul returns an unsigned long.
But more to the point, yes, this does not return an appropriate
error when "--cat-blob-fd=" is not followed by an unsigned
integer. At least it's consistent with --depth=nonsense et al.
Rough patch below (needs tests).
Ok. I'm eager to see this go through to `master`.
Reviewed-by: Ramkumar Ramachandra <redacted>
Thanks.
Signed-off-by: Jonathan Nieder <redacted>
---
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:49:48
David Barr wrote:
Explicitly declare that output is to stdout for existing use.
Allow users of buffer_copy_bytes() to specify the output file.
Probably worth mentioning the motivation, which is presumably
that svn-fe will be streaming the preimage for files expressed as
deltas from the cat-file-fd to a temporary file.
Signed-off-by: David Barr <redacted>
Reviewed-by: Jonathan Nieder <redacted>
Thanks. (It's a good API change.)
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:49:48
Hi Ram,
Glad to see you are feeling a little better.
Ramkumar Ramachandra wrote:
David Barr writes:
quoted
+ if (!backchannel.infile)
+ backchannel.infile = fdopen(REPORT_FILENO, "r");
+ if (!backchannel.infile)
+ return error("Could not open backchannel fd: %d", REPORT_FILENO);
REPORT_FILENO = 3 is hard-coded. Is this intended? Maybe a
command-line option to specify the fd?
fast-import gets the --cat-file-fd parameter to choose between stdout,
stdin-as-socket, stderr, or another fd (not necessarily 3 because it
might have to compete with other similar features some day).
For svn-fe, it is just like another stdin. stdin is always fd 0,
so...
For callers other than svn-fe, it would be especially useful to
make it configurable, yes.
quoted
+ tail = buffer_read_line(&backchannel);
+ if (!tail)
+ return 1;
Could you clarify when exactly will this happen?
buffer_read_line() returns NULL on error and when data is exhausted
without the trailing newline appearing. The input here is supposed to
be just a single newline (trimmed to an empty string).
quoted
+ long preimage_len = 0;
+
+ if (delta) {
+ if (!preimage.infile)
+ preimage.infile = tmpfile();
Didn't you later decide against this and use one tmpfile instead?
This is a single tempfile (because static). Or am I missing
something?
quoted
+ if (!preimage.infile)
+ die("Unable to open temp file for blob retrieval");
+ if (srcMark) {
+ printf("cat-blob :%"PRIu32"\n", srcMark);
+ fflush(stdout);
+ if (srcMode == REPO_MODE_LNK)
+ fwrite("link ", 1, 5, preimage.infile);
Special handling for symbolic links. Perhaps you should mention it in
a comment here?
Or better yet, a comment in the commit message. :)
quoted
+ if (fast_export_save_blob(preimage.infile))
+ die("Failed to retrieve blob for delta application");
+ }
+ preimage_len = ftell(preimage.infile);
+ fseek(preimage.infile, 0, SEEK_SET);
+ if (!postimage.infile)
+ postimage.infile = tmpfile();
One tmpfile?
Do you mean letting the preimage and postimage share a file?
[...]
I should have asked this a long time ago: why the extra newline?
From the fast-import manual:
The LF after <raw> is optional (it used to be required)
but recommended. Always including it makes debugging a
fast-import stream easier as the next command always
starts in column 0 of the next line, even if <raw> did
not end with an LF.
Overall, pleasant read. Thanks for taking this forward.
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:49:48
David Barr wrote:
Patch 1 adds the required infrastructure to fast-import.
This features the addition of the cat-blob command
Patch 1: maybe someone wants to pick this up and make the minor
changes it needs (a test or two to maintain sanity)?
Patch 2 adds the basic parsing necessary to process the v3 format.
The log message doesn't give context but the patch is good
and safe. Unknown keys are ignored so it is basically a
no-op except for using a little more memory.
Patch 3 adds logic around decoding prop deltas.
It would be nice if someone who is not Junio cleans up the style.
Patch 4 (unmentioned for some reason): the log message doesn't give
context but the patch is good. I think this could be picked up right
away. There would be semantically unimportant merge conflicts if
cherry-picking without the patches introducing buffer_read_binary()
and changing buffer_copy_bytes() to take an off_t.
Patch 5 integrates svn-fe with svn-da to decode text deltas.
I like it a lot but am interested in the follow-ups to Ram's comments.
Of course this requires the svn-da series so I'd prefer to give it
a few more days' cooking.
Summary:
- patch 4 could be picked up right away imho
- the rest need some work, but not much
- the series is available from
git://github.com/barrbrain/git.git svn-fe3
Regards,
Jonathan
+ if (!backchannel.infile)
+ backchannel.infile = fdopen(REPORT_FILENO, "r");
+ if (!backchannel.infile)
+ return error("Could not open backchannel fd: %d", REPORT_FILENO);
REPORT_FILENO = 3 is hard-coded. Is this intended? Maybe a
command-line option to specify the fd?
fast-import gets the --cat-file-fd parameter to choose between stdout,
stdin-as-socket, stderr, or another fd (not necessarily 3 because it
might have to compete with other similar features some day).
For svn-fe, it is just like another stdin. stdin is always fd 0,
so...
For callers other than svn-fe, it would be especially useful to
make it configurable, yes.
Right, got it.
quoted
quoted
+ tail = buffer_read_line(&backchannel);
+ if (!tail)
+ return 1;
Could you clarify when exactly will this happen?
buffer_read_line() returns NULL on error and when data is exhausted
without the trailing newline appearing. The input here is supposed to
be just a single newline (trimmed to an empty string).
Thanks for the clarification.
quoted
quoted
+ long preimage_len = 0;
+
+ if (delta) {
+ if (!preimage.infile)
+ preimage.infile = tmpfile();
Didn't you later decide against this and use one tmpfile instead?
This is a single tempfile (because static). Or am I missing
something?
Er, sorry about that. When I saw this code, it immediately reminded me
of one of David's commits that used several temporary files- a later
one made it a global variable. I didn't notice the static here.
quoted
quoted
+ if (!preimage.infile)
+ die("Unable to open temp file for blob retrieval");
+ if (srcMark) {
+ printf("cat-blob :%"PRIu32"\n", srcMark);
+ fflush(stdout);
+ if (srcMode == REPO_MODE_LNK)
+ fwrite("link ", 1, 5, preimage.infile);
Special handling for symbolic links. Perhaps you should mention it in
a comment here?
Or better yet, a comment in the commit message. :)
*nod*
quoted
quoted
+ if (fast_export_save_blob(preimage.infile))
+ die("Failed to retrieve blob for delta application");
+ }
+ preimage_len = ftell(preimage.infile);
+ fseek(preimage.infile, 0, SEEK_SET);
+ if (!postimage.infile)
+ postimage.infile = tmpfile();
One tmpfile?
Do you mean letting the preimage and postimage share a file?
I should have asked this a long time ago: why the extra newline?
From the fast-import manual:
The LF after <raw> is optional (it used to be required)
but recommended. Always including it makes debugging a
fast-import stream easier as the next command always
starts in column 0 of the next line, even if <raw> did
not end with an LF.
Thanks for the explanation. I really should have looked this up
earlier, but I suppose it's not a biggie.
-- Ram
Hi again,
Here's another review.
David Barr writes:
By testing against the Apache Software Foundation
repository, some simple rules for decoding prop
deltas were derived.
'Node-action: replace' implies the empty prop set
as the base for the delta.
Otherwise, if a copyfrom source is given that node
forms the basis for the delta.
Lastly, if the destination path exists in the active
revision it forms the basis.
The same rules ought to apply to text deltas as well.
Apply these rules to prop handling.
Add a placeholder srcMark parameter to fast_export_blob().
Is this related to the Prop-delta handling? Why is it in this patch?
Signed-off-by: David Barr <redacted>
Nit: I don't know how you managed to wrap your commit message like
that- it looks like you did it by hand. My Emacs wraps at 70
characters, and that seems to be the convention in git.git as well.
Also, I don't like the commit message. Maybe something like this would
be clearer?
-- 8< --
Handle property deltas that occur in dumpfile v3. While "Prop-delta:
false" trivially implies that all the properties are given in full,
"Prop-delta: true" implies a delta against:
1. The props of the previous revision of the node when `Node-action`
is `change`.
2. Nothing when `Node-action` is `add`. However, when
`Node-copyfrom-path`/ `Node-copyfrom-rev` headers are present, the
delta is against the node being copied.
3. Nothing when `Node-action` is `replace` and the destination path
doesn't already exist in the current revision. If
`Node-copyfrom-path`/ `Node-copyfrom-rev` headers are present, the
delta is against the node being copied. Finally, if the destination
path already exists in the current revision, the delta is against
the props of that node.
Note to self: You've switched indentation style from "tabs to align +
spaces to indent" to the "Linux tabs only" style used in linux.git.
Wait, does this change belong here?
Make this clearer with an `if` statement perhaps? This looks ugly,
especially with the reader having to parse it with the correct
operator precedence in mind.
Style nit: Unnecessary braces around `if` statement.
Wait, what does all this have to do with prop deltas? Ok, I found this
slightly confusing -- I just went through the rest of the patch and
found that repo_read_mode and repo_read_mark are dependencies of the
prop-delta handling code. Maybe put them in a separate patch
immediately preceeding this one?
Deleted props have to be printed in dumpfile v3 (for obvious reasons:
how else would we indicate a delta?). I know this, but I don't know
what another reviewer would make of this. You should mention it
explicitly in a comment or in the commit message.
Note to other reviewers:
Props are printed as
V <key length>
<key>
K <value length>
<value>
Deleted props are printed as
D <key length>
<key>
Yes, value is omitted.
This change populates the context with deleted props (more precisely:
changes the context when deleted props are encountered). I'm not
entirely happy that it's part of this patch: why not squash it into
2/5?
Okay, the code to handle prop deltas. As a note to self and for the
benefit of other reviewers, here's the English version of the above:
0. Mode can be one of REPO_MODE_DIR, REPO_MODE_BLB, REPO_MODE_EXE, and
REPO_MODE_LNK.
1. If Node-copyfrom-rev/ Node-copyfrom-path are present, set srcMode
to the mode of the source node (as present in the source revision
ofcourse).
2. If not, set the srcMode to the mode of the dst path in the previous
revision.
After doing this, if srcMode is present and if Node-action is not
replace, set the mode (called `type` for historical reasons*?) of the
destination node to that of the source node. Now that we've copied the
props successfully, the call to read_props() in line 200 will reads
the props of the current revision and update the mode accordingly.
* Wait, why must we be stuck with this historical cruft?
Signed-off-by: Ramkumar Ramachandra <redacted>
-- 8< --
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:50:07
[resending since git@vger doesn't seem to have accepted the previous
copy. Sorry for the noise.]
David Barr wrote:
So introduce another way: a "cat-blob" command introduced in the
command stream requests for fast-import to print a blob to stdout
or a file descriptor specified by the argument --cat-blob-fd.
The output uses the same format as "git cat-file --batch".
I am very fond of this patch. Still, the fact remains that until this
command is implemented by some other fast-import backend, it is hard
to know what git-specific concepts are encoded in its current
implementation. (I am in particular worried about what should be
gauranteed about the blob_identifier in the
blob blob_identifier 1823
line and whether
cat-blob blob_name
cat-blob :11
are going to overlap and cause trouble for some backends.)
On the other hand, development of svn-fe continues to benefit from
cat-blob and its cousins ls-tree and ls[1]. and there has been brief
discussion of using cat-blob to make cvs2git more friendly. So here's
a reroll, since it seems clear that this feature should be in future
versions of fast-import in some form.
Thoughts welcome, as always (even as simple as "I have a bad feeling
about this" or "everything in this patch looks ready to go").
Patches based against v1.7.0.7 for no particular reason.
David Barr (1):
fast-import: let importers retrieve blobs
Jonathan Nieder (3):
fast-import: stricter parsing of integer options
fast-import: clarify documentation of "feature" command
fast-import: Allow cat-blob requests at arbitrary points in stream
Documentation/git-fast-import.txt | 76 ++++++++---
fast-import.c | 128 ++++++++++++++++--
t/t9300-fast-import.sh | 267 ++++++++++++++++++++++++++++++++++++-
3 files changed, 442 insertions(+), 29 deletions(-)
[1] ls-tree commit_name "path/to/file" would have output format
100644 blob blob_identifier path/to/file and within a commit
command, ls "path/to/file" would produce output in the same
format.
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:50:07
Check the result from strtoul to avoid accepting arguments like
--depth=-1 and --active-branches=foo,bar,baz.
Requested-by: Ramkumar Ramachandra [off-list ref]
Signed-off-by: Jonathan Nieder <redacted>
---
See http://thread.gmane.org/gmane.comp.version-control.git/159117/focus=159236
for context.
fast-import.c | 13 +++++++++++--
t/t9300-fast-import.sh | 8 ++++++++
2 files changed, 19 insertions(+), 2 deletions(-)
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:50:07
The "feature" command allows streams to specify options for the import
that must not be ignored. Logically, they are part of the stream,
even though technically most supported features are synonyms to
command-line options.
Make this more obvious by being more explicit about how the analogy
between most "feature" commands and command-line options works. Treat
the feature (import-marks) that does not fit this analogy separately.
Signed-off-by: Jonathan Nieder <redacted>
Acked-by: Sverre Rabbelier <redacted>
---
Side note: I am thinking of introducing a syntax
'feature' SP 'command' SP <command name> LF
which would just check if <command name> is a recognized command.
This way, when a feature introduces a new command, it would get
a feature name to go along with that with no extra effort.
In particular, it is not obvious to me whether cat-blob, ls-tree,
and so on ought to be considered a single feature but with the
feature command syntax, we could dodge the issue. :) Sane?
Documentation/git-fast-import.txt | 33 +++++++++++++++------------------
1 files changed, 15 insertions(+), 18 deletions(-)
@@ -878,28 +878,25 @@ Require that fast-import supports the specified feature, or abort if it does not. ....- 'feature' SP <feature> LF+ 'feature' SP <feature> ('=' <argument>)? LF ....-The <feature> part of the command may be any string matching-^[a-zA-Z][a-zA-Z-]*$ and should be understood by fast-import.+The <feature> part of the command may be any one of the following:-Feature work identical as their option counterparts with the-exception of the import-marks feature, see below.+date-format::+export-marks::+relative-marks::+no-relative-marks::+force::+ Act as though the corresponding command-line option with+ a leading '--' was passed on the command line+ (see OPTIONS, above).-The following features are currently supported:--* date-format-* import-marks-* export-marks-* relative-marks-* no-relative-marks-* force--The import-marks behaves differently from when it is specified as-commandline option in that only one "feature import-marks" is allowed-per stream. Also, any --import-marks= specified on the commandline-will override those from the stream (if any).+import-marks::+ Like --import-marks except in two respects: first, only one+ "feature import-marks" command is allowed per stream;+ second, an --import-marks= command-line option overrides+ any "feature import-marks" command in the stream. `option` ~~~~~~~~
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:50:07
From: David Barr <redacted>
New objects written by fast-import are not available immediately.
Until a checkpoint has been started and finishes writing the pack
index, any new blobs will not be accessible using standard git tools.
So introduce a new way to access them: a "cat-blob" command in the
command stream requests for fast-import to print a blob to stdout or a
file descriptor specified by the argument to --cat-blob-fd. The value
for cat-blob-fd cannot be specified in the stream because that would
be a layering violation: the decision of where to direct a stream has
to be made when fast-import is started anyway, so we might as well
make the stream format is independent of that detail.
Output uses the same format as "git cat-file --batch".
Thanks to Sverre Rabbelier and Sam Vilain for guidance in designing
the protocol.
Based-on-patch-by: Jonathan Nieder [off-list ref]
Signed-off-by: David Barr <redacted>
Acked-by: Ramkumar Ramachandra <redacted>
Signed-off-by: Jonathan Nieder <redacted>
---
If you use this, you might want to do something like:
blob
mark :1
data <<EOT
testing 1 2 3
EOT
cat-blob :1
before proceeding with the rest of the stream. This allows wiring
mistakes to be caught early.
Documentation/git-fast-import.txt | 41 ++++++++
fast-import.c | 95 ++++++++++++++++++
t/t9300-fast-import.sh | 193 ++++++++++++++++++++++++++++++++++++-
3 files changed, 327 insertions(+), 2 deletions(-)
@@ -92,6 +92,11 @@ OPTIONS --(no-)-relative-marks= with the --(import|export)-marks= options.+--cat-blob-fd=<fd>::+ Specify the file descriptor that will be written to+ when the `cat-blob` command is encountered in the stream.+ The default behaviour is to write to `stdout`.+ --export-pack-edges=<file>:: After creating a packfile, print a line of data to <file> listing the filename of the packfile and the last
@@ -320,6 +325,11 @@ and control the current import process. More detailed discussion standard output. This command is optional and is not needed to perform an import.+`cat-blob`::+ Causes fast-import to print a blob in 'cat-file --batch'+ format to the file descriptor set with `--cat-blob-fd` or+ `stdout` if unspecified.+ `feature`:: Require that fast-import supports the specified feature, or abort if it does not.
@@ -872,6 +882,29 @@ Placing a `progress` command immediately after a `checkpoint` will inform the reader when the `checkpoint` has been completed and it can safely access the refs that fast-import updated.+`cat-blob`+~~~~~~~~~~+Causes fast-import to print a blob to a file descriptor previously+arranged with the `--cat-blob-fd` argument. The command otherwise+has no impact on the current import; its main purpose is to+retrieve blobs that may be in fast-import's memory but not+accessible from the target repository.++....+ 'cat-blob' SP <dataref> LF+....++The `<dataref>` can be either a mark reference (`:<idnum>`)+set previously or a full 40-byte SHA-1 of a Git blob, preexisting or+ready to be written.++output uses the same format as `git cat-file --batch`:++====+ <sha1> SP 'blob' SP <size> LF+ <contents> LF+====+ `feature` ~~~~~~~~~ Require that fast-import supports the specified feature, or abort if
@@ -898,6 +931,13 @@ import-marks:: second, an --import-marks= command-line option overrides any "feature import-marks" command in the stream.+cat-blob::+ Ignored. Versions of fast-import not supporting the+ "cat-blob" command will exit with a message indicating so.+ This lets the import error out early with a clear message,+ rather than wasting time on the early part of an import+ before the unsupported command is detected.+ `option` ~~~~~~~~ Processes the specified option so that git fast-import behaves in a
@@ -923,6 +963,7 @@ not be passed as option: * date-format * import-marks * export-marks+* cat-blob-fd * force Crash Reports
@@ -55,6 +55,8 @@ Format of STDIN stream:('from'spcommittishlf)?lf?;+cat_blob::='cat-blob'sp(hexsha1|idnum)lf;+checkpoint::='checkpoint'lflf?;
@@ -361,6 +363,9 @@ static uintmax_t next_mark;staticstructstrbufnew_data=STRBUF_INIT;staticintseen_data_command;+/* Where to write output of cat-blob commands */+staticintcat_blob_fd=STDOUT_FILENO;+staticvoidparse_argv(void);staticvoidwrite_branch_report(FILE*rpt,structbranch*b)
@@ -2689,6 +2694,79 @@ static void parse_reset_branch(void)unread_command_buf=1;}+staticvoidcat_blob_write(constchar*buf,unsignedlongsize)+{+if(write_in_full(cat_blob_fd,buf,size)!=size)+die_errno("Write to frontend failed");+}++staticvoidcat_blob(structobject_entry*oe,unsignedcharsha1[20])+{+structstrbufline=STRBUF_INIT;+unsignedlongsize;+enumobject_typetype=0;+char*buf;++if(!oe||oe->pack_id==MAX_PACK_ID){+buf=read_sha1_file(sha1,&type,&size);+}else{+type=oe->type;+buf=gfi_unpack_entry(oe,&size);+}++/*+*Outputbasedonbatch_one_object()fromcat-file.c.+*/+if(type<=0){+strbuf_reset(&line);+strbuf_addf(&line,"%s missing\n",sha1_to_hex(sha1));+cat_blob_write(line.buf,line.len);+free(buf);+return;+}+if(!buf)+die("Can't read object %s",sha1_to_hex(sha1));+if(type!=OBJ_BLOB)+die("Object %s is a %s but a blob was expected.",+sha1_to_hex(sha1),typename(type));+strbuf_reset(&line);+strbuf_addf(&line,"%s %s %lu\n",sha1_to_hex(sha1),+typename(type),size);+cat_blob_write(line.buf,line.len);+cat_blob_write(buf,size);+cat_blob_write("\n",1);+free(buf);+}++staticvoidparse_cat_blob(void)+{+constchar*p;+structobject_entry*oe=oe;+unsignedcharsha1[20];++/* cat-blob SP <object> LF */+p=command_buf.buf+strlen("cat-blob ");+if(*p==':'){+char*x;+oe=find_mark(strtoumax(p+1,&x,10));+if(x==p+1)+die("Invalid mark: %s",command_buf.buf);+if(!oe)+die("Unknown mark: %s",command_buf.buf);+if(*x)+die("Garbage after mark: %s",command_buf.buf);+hashcpy(sha1,oe->idx.sha1);+}else{+if(get_sha1_hex(p,sha1))+die("Invalid SHA1: %s",command_buf.buf);+if(p[40])+die("Garbage after SHA1: %s",command_buf.buf);+oe=find_object(sha1);+}++cat_blob(oe,sha1);+}+staticvoidparse_checkpoint(void){if(object_count){
@@ -2824,6 +2910,8 @@ static int parse_one_feature(const char *feature, int from_stream)option_import_marks(feature+13,from_stream);}elseif(!prefixcmp(feature,"export-marks=")){option_export_marks(feature+13);+}elseif(!strcmp(feature,"cat-blob")){+;/* Don't die - this feature is supported */}elseif(!prefixcmp(feature,"relative-marks")){relative_marks_paths=1;}elseif(!prefixcmp(feature,"no-relative-marks")){
@@ -1501,6 +1508,190 @@ test_expect_success 'R: feature no-relative-marks should be honoured' 'test_cmpmarks.newnon-relative.out'+test_expect_success'R: feature cat-blob supported''+echo"feature cat-blob"|+gitfast-import+'++test_expect_success'R: cat-blob-fd must be a nonnegative integer''+test_must_failgitfast-import--cat-blob-fd=-1</dev/null+'++test_expect_success'R: print old blob''+blob=$(echo"yes it can"|githash-object-w--stdin)&&+cat>expect<<-EOF&&+${blob}blob11+yesitcan++EOF+echo"cat-blob $blob"|+gitfast-import--cat-blob-fd=66>actual&&+test_cmpexpectactual+'++test_expect_success'R: in-stream cat-blob-fd not respected''+echohello>greeting&&+blob=$(githash-object-wgreeting)&&+cat>expect<<-EOF&&+${blob}blob6+hello++EOF+gitfast-import--cat-blob-fd=33>actual.3>actual.1<<-EOF&&+cat-blob$blob+EOF+test_cmpexpectactual.3&&+test_cmpemptyactual.1&&+gitfast-import3>actual.3>actual.1<<-EOF&&+optioncat-blob-fd=3+cat-blob$blob+EOF+test_cmpemptyactual.3&&+test_cmpexpectactual.1+'++test_expect_success'R: print new blob''+blob=$(echo"yep yep yep"|githash-object--stdin)&&+cat>expect<<-EOF&&+${blob}blob12+yepyepyep++EOF+gitfast-import--cat-blob-fd=66>actual<<-\EOF&&+blob+mark:1+data<<BLOB_END+yepyepyep+BLOB_END+cat-blob:1+EOF+test_cmpexpectactual+'++test_expect_success'R: print new blob by sha1''+blob=$(echo"a new blob named by sha1"|githash-object--stdin)&&+cat>expect<<-EOF&&+${blob}blob25+anewblobnamedbysha1++EOF+gitfast-import--cat-blob-fd=66>actual<<-EOF&&+blob+data<<BLOB_END+anewblobnamedbysha1+BLOB_END+cat-blob$blob+EOF+test_cmpexpectactual+'++test_expect_success'setup: big file''+(+echo"the quick brown fox jumps over the lazy dog">big&&+foriin123+do+catbigbigbigbig>bigger&&+catbiggerbiggerbiggerbigger>big||+exit+done+)+'++test_expect_success'R: print two blobs to stdout''+blob1=$(githash-objectbig)&&+blob1_len=$(wc-c<big)&&+blob2=$(echohello|githash-object--stdin)&&+{+echo${blob1}blob$blob1_len&&+catbig&&+cat<<-EOF++${blob2}blob6+hello++EOF+}>expect&&+{+cat<<-\END_PART1&&+blob+mark:1+data<<data_end+END_PART1+catbig&&+cat<<-\EOF+data_end+blob+mark:2+data<<data_end+hello+data_end+cat-blob:1+cat-blob:2+EOF+}|+gitfast-import>actual&&+test_cmpexpectactual+'++test_expect_success'setup: have pipes?''+rm-ffrob&&+ifmkfifofrob+then+test_set_prereqPIPE+fi+'++test_expect_successPIPE'R: copy using cat-file''+expect_id=$(githash-objectbig)&&+expect_len=$(wc-c<big)&&+echo$expect_idblob$expect_len>expect.response&&++rm-fblobs&&+cat>frontend<<-\FRONTEND_END&&+#!/bin/sh+cat<<EOF&&+featurecat-blob+blob+mark:1+data<<BLOB+EOF+catbig+cat<<EOF+BLOB+cat-blob:1+EOF++readblob_idtypesize<&3&&+echo"$blob_id$type$size">response&&+ddif=/dev/stdinof=blobbs=$sizecount=1<&3&&+readnewline<&3&&++cat<<EOF&&+commitrefs/heads/copied+committer$GIT_COMMITTER_NAME<$GIT_COMMITTER_EMAIL>$GIT_COMMITTER_DATE+data<<COMMIT+copybigfileasfile3+COMMIT+M644inlinefile3+data<<BLOB+EOF+catblob&&+cat<<EOF+BLOB+EOF+FRONTEND_END++mkfifoblobs&&+(+exportGIT_COMMITTER_NAMEGIT_COMMITTER_EMAILGIT_COMMITTER_DATE&&+shfrontend3<blobs|+gitfast-import--cat-blob-fd=33>blobs+)&&+gitshowcopied:file3>actual&&+test_cmpexpect.responseresponse&&+test_cmpbigactual+'+ cat>input<<EOF optiongitquiet blob
@@ -1509,8 +1700,6 @@ hi EOF-touchempty- test_expect_success'R: quiet option results in no stats being output''catinput|gitfast-import2>output&&test_cmpemptyoutput
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:50:07
The new rule: a "cat-blob" can be inserted wherever a comment is
allowed, which means at the start of any line except in the middle of
a "data" command.
This saves frontends from having to loop over everything they want to
commit in the next commit and cat-ing the necessary objects in
advance.
Signed-off-by: Jonathan Nieder <redacted>
Signed-off-by: David Barr <redacted>
Signed-off-by: Jonathan Nieder <redacted>
---
That's the end of the series. Thanks for reading.
The early history is at [1] if that's your kind of thing.
[1] http://thread.gmane.org/gmane.comp.version-control.git/150005/focus=155417
Documentation/git-fast-import.txt | 4 ++
fast-import.c | 28 +++++++++-------
t/t9300-fast-import.sh | 66 +++++++++++++++++++++++++++++++++++++
3 files changed, 86 insertions(+), 12 deletions(-)
@@ -905,6 +905,10 @@ output uses the same format as `git cat-file --batch`: <contents> LF ====+This command can be used anywhere in the stream that comments are+accepted. In particular, the `cat-blob` command can be used in the+middle of a commit but not in the middle of a `data` command.+ `feature` ~~~~~~~~~ Require that fast-import supports the specified feature, or abort if
@@ -55,8 +55,6 @@ Format of STDIN stream:('from'spcommittishlf)?lf?;-cat_blob::='cat-blob'sp(hexsha1|idnum)lf;-checkpoint::='checkpoint'lflf?;
@@ -134,14 +132,17 @@ Format of STDIN stream:ts::=#timesincetheepochinseconds,asciibase10notation;tz::=#GITstyletimezone;-# note: comments may appear anywhere in the input, except-# within a data command. Any form of the data command-# always escapes the related input from comment processing.+# note: comments and cat requests may appear anywhere+# in the input, except within a data command. Any form+# of the data command always escapes the related input+# from comment processing.## In case it is not clear, the '#' that starts the comment# must be the first character on that line (an lf# preceded it).#+cat_blob::='cat-blob'sp(hexsha1|idnum)lf;+comment::='#'not_lf*lf;not_lf::=#AnybytethatisnotASCIInewline(LF);*/
@@ -367,6 +368,7 @@ static int seen_data_command;staticintcat_blob_fd=STDOUT_FILENO;staticvoidparse_argv(void);+staticvoidparse_cat_blob(void);staticvoidwrite_branch_report(FILE*rpt,structbranch*b){
@@ -1692,6 +1692,72 @@ test_expect_success PIPE 'R: copy using cat-file' 'test_cmpbigactual'+test_expect_successPIPE'R: print blob mid-commit''+rm-fblobs&&+echo"A blob from _before_ the commit.">expect&&+mkfifoblobs&&+(+exec3<blobs&&+cat<<-EOF&&+featurecat-blob+blob+mark:1+data<<BLOB+Ablobfrom_before_thecommit.+BLOB+commitrefs/heads/temporary+committer$GIT_COMMITTER_NAME<$GIT_COMMITTER_EMAIL>$GIT_COMMITTER_DATE+data<<COMMIT+Emptycommit+COMMIT+cat-blob:1+EOF++readblob_idtypesize<&3&&+ddif=/dev/stdinof=actualbs=$sizecount=1<&3&&+readnewline<&3&&++echo+)|+gitfast-import--cat-blob-fd=33>blobs&&+test_cmpexpectactual+'++test_expect_successPIPE'R: print staged blob within commit''+rm-fblobs&&+echo"A blob from _within_ the commit.">expect&&+mkfifoblobs&&+(+exec3<blobs&&+cat<<-EOF&&+featurecat-blob+commitrefs/heads/within+committer$GIT_COMMITTER_NAME<$GIT_COMMITTER_EMAIL>$GIT_COMMITTER_DATE+data<<COMMIT+Emptycommit+COMMIT+M644inlinewithin+data<<BLOB+Ablobfrom_within_thecommit.+BLOB+EOF++to_get=$(+echo"A blob from _within_ the commit."|+githash-object--stdin+)&&+echo"cat-blob $to_get"&&++readblob_idtypesize<&3&&+ddif=/dev/stdinof=actualbs=$sizecount=1<&3&&+readnewline<&3&&++echodeleteall+)|+gitfast-import--cat-blob-fd=33>blobs&&+test_cmpexpectactual+'+ cat>input<<EOF optiongitquiet blob
From: David Barr <hidden> Date: 2016-06-15 22:50:08
David Barr wrote:
[plug two memory leaks in "[PATCH 3/4] fast-import: let importers retr..."]
quoted
Signed-off-by: David Barr <redacted>
Good eyes, thanks!
Acked-by: Jonathan Nieder <redacted>
I only caught it because I was copying and adapting the same bit of code for
my 'ls' implementation. The svndiff0 implementation taught me to feel nervous
wherever I see STRBUF_INIT ;)
--
David Barr
This breaks my automated tester, though I am not sure exactly why. It
runs RHEL5, and I have
$ ls -l /dev/std*
lrwxrwxrwx 1 root root 15 Sep 1 09:25 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Sep 1 09:25 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Sep 1 09:25 /dev/stdout -> /proc/self/fd/1
But from the tests I get back
dd: opening `/dev/stdin': No such file or directory
error: git-fast-import died of signal 13
not ok - 110 R: copy using cat-file
In any case I cannot see a reason to use this construct: 'dd' reads
from stdin by default, so you could just leave away the option.
--
Thomas Rast
trast@{inf,student}.ethz.ch
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:50:10
Jonathan Nieder wrote:
The value
for cat-blob-fd cannot be specified in the stream because that would
be a layering violation: the decision of where to direct a stream has
to be made when fast-import is started anyway, so we might as well
make the stream format is independent of that detail.
Ungrammatical. I think I meant:
There is no POSIX facility to open a file descriptor from outside
after a process has already started; therefore, the frontend has to
prepare a file descriptor for writing blobs before executing
git fast-import. The --cat-blob-fd command line option indicates
which file descriptor that is, defaulting to 1.
It does not make sense to wait until the stream starts to specify
which fd so it is not allowed, avoiding a potential layering
violation. Other fast-import backends might provide other ways to
specify where the blob stream should be written.
quoted hunk
+++ b/fast-import.c
@@ -2824,6 +2910,8 @@ static int parse_one_feature(const char *feature, int from_stream)option_import_marks(feature+13,from_stream);}elseif(!prefixcmp(feature,"export-marks=")){option_export_marks(feature+13);+}elseif(!strcmp(feature,"cat-blob")){+;/* Don't die - this feature is supported */
Implies support for a "--cat-blob" command line option
that checks for cat-blob support. Is this wanted?
(If so, it should be documented. If not, the condition should be
"from_stream && !strcmp(...)".)
Would be simpler and more explicit to put in parse_one_feature:
} else if (!from_stream && !prefixcmp(feature, "cat-blob-fd=")) {
Sorry this is taking so long to get right. :-/
Jonathan
This breaks my automated tester, though I am not sure exactly why. It
runs RHEL5, and I have
lrwxrwxrwx 1 root root 15 Sep 1 09:25 /dev/stdin -> /proc/self/fd/0
Ah, answering my own question: on my normal box, strace'ing dd[1] in
such an invocation uses
open("/dev/stdin", O_RDONLY) = 3
dup2(3, 0) = 0
close(3) = 0
OTOH on RHEL5[2] it tries a different order:
close(0) = 0
open("/dev/stdin", O_RDONLY) = -1 ENOENT (No such file or directory)
Oops.
[1] dd --version says: dd (coreutils) 7.1
[2] dd (coreutils) 5.97
--
Thomas Rast
trast@{inf,student}.ethz.ch
@@ -905,7 +905,7 @@ The `<dataref>` can be either a mark reference (`:<idnum>`) set previously or a full 40-byte SHA-1 of a Git blob, preexisting or ready to be written.-output uses the same format as `git cat-file --batch`:+Output uses the same format as `git cat-file --batch`: ==== <sha1> SP 'blob' SP <size> LF