{"thread":{"id":"20862","subject":"[PATCH v7 0/6] fast-import: add new feature and option command","startedAt":"2009-09-06T14:35:42Z","lastAt":"2009-09-13T13:20:58Z","messageCount":15,"participants":["Sverre Rabbelier","Shawn O. Pearce","Miklos Vajna"],"isPatch":true,"patchVersion":7,"patchTotal":6},"messages":[{"id":"122555","messageId":"1252247748-14507-1-git-send-email-srabbelier@gmail.com","threadId":"20862","inReplyTo":null,"subject":"[PATCH v7 0/6] fast-import: add new feature and option command","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-06T14:35:42Z","receivedAt":"2009-09-06T14:35:42Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Only changes are in 5/6 and 6/6, as suggested by Junio we now ignore\ngit options that we do not recognise. If desired we could add a\nfeature command for each option so that the frontend can make it\nrequired with 'feature git-option-marks'.\n\nSverre Rabbelier (6):\n      fast-import: put option parsing code in separate functions\n      fast-import: put marks reading in it's own function\n      fast-import: add feature command\n      fast-import: test the new feature command\n      fast-import: add option command\n      fast-import: test the new option command\n\n Documentation/git-fast-import.txt |   40 ++++++\n fast-import.c                     |  264 ++++++++++++++++++++++++++-----------\n t/t9300-fast-import.sh            |  107 +++++++++++++++\n 3 files changed, 334 insertions(+), 77 deletions(-)\n"},{"id":"122557","messageId":"1252247748-14507-2-git-send-email-srabbelier@gmail.com","threadId":"20862","inReplyTo":"1252247748-14507-1-git-send-email-srabbelier@gmail.com","subject":"[PATCH v7 1/6] fast-import: put option parsing code in separate functions","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-06T14:35:43Z","receivedAt":"2009-09-06T14:35:43Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Putting the options in their own functions increases readability of\nthe option parsing block and makes it easier to reuse the option\nparsing code later on.\n\nSigned-off-by: Sverre Rabbelier <srabbelier@gmail.com>\n---\n\n  Unchanged again.\n\n fast-import.c |  115 +++++++++++++++++++++++++++++++++++++--------------------\n 1 files changed, 75 insertions(+), 40 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 7ef9865..b904f20 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -291,6 +291,7 @@ static unsigned long branch_count;\n static unsigned long branch_load_count;\n static int failure;\n static FILE *pack_edges;\n+static unsigned int show_stats = 1;\n \n /* Memory pools */\n static size_t mem_pool_alloc = 2*1024*1024 - sizeof(struct mem_pool);\n@@ -2337,7 +2338,7 @@ static void parse_progress(void)\n \tskip_optional_lf();\n }\n \n-static void import_marks(const char *input_file)\n+static void option_import_marks(const char *input_file)\n {\n \tchar line[512];\n \tFILE *f = fopen(input_file, \"r\");\n@@ -2372,6 +2373,76 @@ static void import_marks(const char *input_file)\n \tfclose(f);\n }\n \n+static void option_date_format(const char *fmt)\n+{\n+\tif (!strcmp(fmt, \"raw\"))\n+\t\twhenspec = WHENSPEC_RAW;\n+\telse if (!strcmp(fmt, \"rfc2822\"))\n+\t\twhenspec = WHENSPEC_RFC2822;\n+\telse if (!strcmp(fmt, \"now\"))\n+\t\twhenspec = WHENSPEC_NOW;\n+\telse\n+\t\tdie(\"unknown --date-format argument %s\", fmt);\n+}\n+\n+static void option_max_pack_size(const char *packsize)\n+{\n+\tmax_packsize = strtoumax(packsize, NULL, 0) * 1024 * 1024;\n+}\n+\n+static void option_depth(const char *depth)\n+{\n+\tmax_depth = strtoul(depth, NULL, 0);\n+\tif (max_depth > MAX_DEPTH)\n+\t\tdie(\"--depth cannot exceed %u\", MAX_DEPTH);\n+}\n+\n+static void option_active_branches(const char *branches)\n+{\n+\tmax_active_branches = strtoul(branches, NULL, 0);\n+}\n+\n+static void option_export_marks(const char *marks)\n+{\n+\tmark_file = xstrdup(marks);\n+}\n+\n+static void option_export_pack_edges(const char *edges)\n+{\n+\tif (pack_edges)\n+\t\tfclose(pack_edges);\n+\tpack_edges = fopen(edges, \"a\");\n+\tif (!pack_edges)\n+\t\tdie_errno(\"Cannot open '%s'\", edges);\n+}\n+\n+static void parse_one_option(const char *option)\n+{\n+\tif (!prefixcmp(option, \"date-format=\")) {\n+\t\toption_date_format(option + 12);\n+\t} else if (!prefixcmp(option, \"max-pack-size=\")) {\n+\t\toption_max_pack_size(option + 14);\n+\t} else if (!prefixcmp(option, \"depth=\")) {\n+\t\toption_depth(option + 6);\n+\t} else if (!prefixcmp(option, \"active-branches=\")) {\n+\t\toption_active_branches(option + 16);\n+\t} else if (!prefixcmp(option, \"import-marks=\")) {\n+\t\toption_import_marks(option + 13);\n+\t} else if (!prefixcmp(option, \"export-marks=\")) {\n+\t\toption_export_marks(option + 13);\n+\t} else if (!prefixcmp(option, \"export-pack-edges=\")) {\n+\t\toption_export_pack_edges(option + 18);\n+\t} else if (!prefixcmp(option, \"force\")) {\n+\t\tforce_update = 1;\n+\t} else if (!prefixcmp(option, \"quiet\")) {\n+\t\tshow_stats = 0;\n+\t} else if (!prefixcmp(option, \"stats\")) {\n+\t\tshow_stats = 1;\n+\t} else {\n+\t\tdie(\"Unsupported option: %s\", option);\n+\t}\n+}\n+\n static int git_pack_config(const char *k, const char *v, void *cb)\n {\n \tif (!strcmp(k, \"pack.depth\")) {\n@@ -2398,7 +2469,7 @@ static const char fast_import_usage[] =\n \n int main(int argc, const char **argv)\n {\n-\tunsigned int i, show_stats = 1;\n+\tunsigned int i;\n \n \tgit_extract_argv0_path(argv[0]);\n \n@@ -2419,44 +2490,8 @@ int main(int argc, const char **argv)\n \n \t\tif (*a != '-' || !strcmp(a, \"--\"))\n \t\t\tbreak;\n-\t\telse if (!prefixcmp(a, \"--date-format=\")) {\n-\t\t\tconst char *fmt = a + 14;\n-\t\t\tif (!strcmp(fmt, \"raw\"))\n-\t\t\t\twhenspec = WHENSPEC_RAW;\n-\t\t\telse if (!strcmp(fmt, \"rfc2822\"))\n-\t\t\t\twhenspec = WHENSPEC_RFC2822;\n-\t\t\telse if (!strcmp(fmt, \"now\"))\n-\t\t\t\twhenspec = WHENSPEC_NOW;\n-\t\t\telse\n-\t\t\t\tdie(\"unknown --date-format argument %s\", fmt);\n-\t\t}\n-\t\telse if (!prefixcmp(a, \"--max-pack-size=\"))\n-\t\t\tmax_packsize = strtoumax(a + 16, NULL, 0) * 1024 * 1024;\n-\t\telse if (!prefixcmp(a, \"--depth=\")) {\n-\t\t\tmax_depth = strtoul(a + 8, NULL, 0);\n-\t\t\tif (max_depth > MAX_DEPTH)\n-\t\t\t\tdie(\"--depth cannot exceed %u\", MAX_DEPTH);\n-\t\t}\n-\t\telse if (!prefixcmp(a, \"--active-branches=\"))\n-\t\t\tmax_active_branches = strtoul(a + 18, NULL, 0);\n-\t\telse if (!prefixcmp(a, \"--import-marks=\"))\n-\t\t\timport_marks(a + 15);\n-\t\telse if (!prefixcmp(a, \"--export-marks=\"))\n-\t\t\tmark_file = a + 15;\n-\t\telse if (!prefixcmp(a, \"--export-pack-edges=\")) {\n-\t\t\tif (pack_edges)\n-\t\t\t\tfclose(pack_edges);\n-\t\t\tpack_edges = fopen(a + 20, \"a\");\n-\t\t\tif (!pack_edges)\n-\t\t\t\tdie_errno(\"Cannot open '%s'\", a + 20);\n-\t\t} else if (!strcmp(a, \"--force\"))\n-\t\t\tforce_update = 1;\n-\t\telse if (!strcmp(a, \"--quiet\"))\n-\t\t\tshow_stats = 0;\n-\t\telse if (!strcmp(a, \"--stats\"))\n-\t\t\tshow_stats = 1;\n-\t\telse\n-\t\t\tdie(\"unknown option %s\", a);\n+\n+\t\tparse_one_option(a + 2);\n \t}\n \tif (i != argc)\n \t\tusage(fast_import_usage);\n-- \n1.6.4.16.g72c66.dirty\n"},{"id":"122556","messageId":"1252247748-14507-3-git-send-email-srabbelier@gmail.com","threadId":"20862","inReplyTo":"1252247748-14507-2-git-send-email-srabbelier@gmail.com","subject":"[PATCH v7 2/6] fast-import: put marks reading in it's own function","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-06T14:35:44Z","receivedAt":"2009-09-06T14:35:44Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"All options do nothing but set settings, with the exception of the\n--input-marks option. Delay the reading of the marks file till after\nall options have been parsed.\n\nSigned-off-by: Sverre Rabbelier <srabbelier@gmail.com>\n---\n\n  Unchanged again.\n\n fast-import.c |   73 ++++++++++++++++++++++++++++++++-------------------------\n 1 files changed, 41 insertions(+), 32 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex b904f20..812fcf0 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -315,6 +315,7 @@ static struct object_entry_pool *blocks;\n static struct object_entry *object_table[1 << 16];\n static struct mark_set *marks;\n static const char *mark_file;\n+static const char *input_file;\n \n /* Our last blob */\n static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 };\n@@ -1643,6 +1644,42 @@ static void dump_marks(void)\n \t}\n }\n \n+static void read_marks(void)\n+{\n+\tchar line[512];\n+\tFILE *f = fopen(input_file, \"r\");\n+\tif (!f)\n+\t\tdie_errno(\"cannot read '%s'\", input_file);\n+\twhile (fgets(line, sizeof(line), f)) {\n+\t\tuintmax_t mark;\n+\t\tchar *end;\n+\t\tunsigned char sha1[20];\n+\t\tstruct object_entry *e;\n+\n+\t\tend = strchr(line, '\\n');\n+\t\tif (line[0] != ':' || !end)\n+\t\t\tdie(\"corrupt mark line: %s\", line);\n+\t\t*end = 0;\n+\t\tmark = strtoumax(line + 1, &end, 10);\n+\t\tif (!mark || end == line + 1\n+\t\t\t|| *end != ' ' || get_sha1(end + 1, sha1))\n+\t\t\tdie(\"corrupt mark line: %s\", line);\n+\t\te = find_object(sha1);\n+\t\tif (!e) {\n+\t\t\tenum object_type type = sha1_object_info(sha1, NULL);\n+\t\t\tif (type < 0)\n+\t\t\t\tdie(\"object not found: %s\", sha1_to_hex(sha1));\n+\t\t\te = insert_object(sha1);\n+\t\t\te->type = type;\n+\t\t\te->pack_id = MAX_PACK_ID;\n+\t\t\te->offset = 1; /* just not zero! */\n+\t\t}\n+\t\tinsert_mark(mark, e);\n+\t}\n+\tfclose(f);\n+}\n+\n+\n static int read_next_command(void)\n {\n \tstatic int stdin_eof = 0;\n@@ -2338,39 +2375,9 @@ static void parse_progress(void)\n \tskip_optional_lf();\n }\n \n-static void option_import_marks(const char *input_file)\n+static void option_import_marks(const char *marks)\n {\n-\tchar line[512];\n-\tFILE *f = fopen(input_file, \"r\");\n-\tif (!f)\n-\t\tdie_errno(\"cannot read '%s'\", input_file);\n-\twhile (fgets(line, sizeof(line), f)) {\n-\t\tuintmax_t mark;\n-\t\tchar *end;\n-\t\tunsigned char sha1[20];\n-\t\tstruct object_entry *e;\n-\n-\t\tend = strchr(line, '\\n');\n-\t\tif (line[0] != ':' || !end)\n-\t\t\tdie(\"corrupt mark line: %s\", line);\n-\t\t*end = 0;\n-\t\tmark = strtoumax(line + 1, &end, 10);\n-\t\tif (!mark || end == line + 1\n-\t\t\t|| *end != ' ' || get_sha1(end + 1, sha1))\n-\t\t\tdie(\"corrupt mark line: %s\", line);\n-\t\te = find_object(sha1);\n-\t\tif (!e) {\n-\t\t\tenum object_type type = sha1_object_info(sha1, NULL);\n-\t\t\tif (type < 0)\n-\t\t\t\tdie(\"object not found: %s\", sha1_to_hex(sha1));\n-\t\t\te = insert_object(sha1);\n-\t\t\te->type = type;\n-\t\t\te->pack_id = MAX_PACK_ID;\n-\t\t\te->offset = 1; /* just not zero! */\n-\t\t}\n-\t\tinsert_mark(mark, e);\n-\t}\n-\tfclose(f);\n+\tinput_file = xstrdup(marks);\n }\n \n static void option_date_format(const char *fmt)\n@@ -2495,6 +2502,8 @@ int main(int argc, const char **argv)\n \t}\n \tif (i != argc)\n \t\tusage(fast_import_usage);\n+\tif (input_file)\n+\t\tread_marks();\n \n \trc_free = pool_alloc(cmd_save * sizeof(*rc_free));\n \tfor (i = 0; i < (cmd_save - 1); i++)\n-- \n1.6.4.16.g72c66.dirty\n"},{"id":"122559","messageId":"1252247748-14507-4-git-send-email-srabbelier@gmail.com","threadId":"20862","inReplyTo":"1252247748-14507-3-git-send-email-srabbelier@gmail.com","subject":"[PATCH v7 3/6] fast-import: add feature command","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-06T14:35:45Z","receivedAt":"2009-09-06T14:35:45Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"This allows the fronted to require a specific feature to be supported\nby the frontend, or abort.\n\nAlso add support for the first feature, date-format=.\n\nSigned-off-by: Sverre Rabbelier <srabbelier@gmail.com>\n---\n\n  Unchanged since v6.\n\n Documentation/git-fast-import.txt |   16 ++++++++++++++++\n fast-import.c                     |   13 +++++++++++++\n 2 files changed, 29 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\nindex c2f483a..1e293f2 100644\n--- a/Documentation/git-fast-import.txt\n+++ b/Documentation/git-fast-import.txt\n@@ -303,6 +303,10 @@ and control the current import process.  More detailed discussion\n \tstandard output.  This command is optional and is not needed\n \tto perform an import.\n \n+`feature`::\n+\tRequire that fast-import supports the specified feature, or\n+\tabort if it does not.\n+\n `commit`\n ~~~~~~~~\n Create or update a branch with a new commit, recording one logical\n@@ -813,6 +817,18 @@ Placing a `progress` command immediately after a `checkpoint` will\n inform the reader when the `checkpoint` has been completed and it\n can safely access the refs that fast-import updated.\n \n+`feature`\n+~~~~~~~~~\n+Require that fast-import supports the specified feature, or abort if\n+it does not.\n+\n+....\n+\t'feature' SP <feature> LF\n+....\n+\n+The <feature> part of the command may be any string matching\n+[a-zA-Z-] and should be understood by a version of fast-import.\n+\n Crash Reports\n -------------\n If fast-import is supplied invalid input it will terminate with a\ndiff --git a/fast-import.c b/fast-import.c\nindex 812fcf0..9bf06a4 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -2450,6 +2450,17 @@ static void parse_one_option(const char *option)\n \t}\n }\n \n+static void parse_feature(void)\n+{\n+\tchar *feature = command_buf.buf + 8;\n+\n+\tif (!prefixcmp(feature, \"date-format=\")) {\n+\t\toption_date_format(feature + 12);\n+\t} else {\n+\t\tdie(\"This version of fast-import does not support feature %s.\", feature);\n+\t}\n+}\n+\n static int git_pack_config(const char *k, const char *v, void *cb)\n {\n \tif (!strcmp(k, \"pack.depth\")) {\n@@ -2526,6 +2537,8 @@ int main(int argc, const char **argv)\n \t\t\tparse_checkpoint();\n \t\telse if (!prefixcmp(command_buf.buf, \"progress \"))\n \t\t\tparse_progress();\n+\t\telse if (!prefixcmp(command_buf.buf, \"feature \"))\n+\t\t\tparse_feature();\n \t\telse\n \t\t\tdie(\"Unsupported command: %s\", command_buf.buf);\n \t}\n-- \n1.6.4.16.g72c66.dirty\n"},{"id":"122558","messageId":"1252247748-14507-5-git-send-email-srabbelier@gmail.com","threadId":"20862","inReplyTo":"1252247748-14507-4-git-send-email-srabbelier@gmail.com","subject":"[PATCH v7 4/6] fast-import: test the new feature command","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-06T14:35:46Z","receivedAt":"2009-09-06T14:35:46Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Test that an unknown feature causes fast-import to abort, and that a\nknown feature is accepted.\n\nSigned-off-by: Sverre Rabbelier <srabbelier@gmail.com>\n---\n\n  Unchanged since v6.\n\n t/t9300-fast-import.sh |   20 ++++++++++++++++++++\n 1 files changed, 20 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh\nindex 821be7c..564ed6b 100755\n--- a/t/t9300-fast-import.sh\n+++ b/t/t9300-fast-import.sh\n@@ -1088,4 +1088,24 @@ INPUT_END\n test_expect_success 'P: fail on blob mark in gitlink' '\n     test_must_fail git fast-import <input'\n \n+###\n+### series R (feature)\n+###\n+\n+cat >input <<EOF\n+feature no-such-feature-exists\n+EOF\n+\n+test_expect_success 'R: abort on unsupported feature' '\n+\ttest_must_fail git fast-import <input\n+'\n+\n+cat >input <<EOF\n+feature date-format=now\n+EOF\n+\n+test_expect_success 'R: supported feature is accepted' '\n+\tgit fast-import <input\n+'\n+\n test_done\n-- \n1.6.4.16.g72c66.dirty\n"},{"id":"122560","messageId":"1252247748-14507-6-git-send-email-srabbelier@gmail.com","threadId":"20862","inReplyTo":"1252247748-14507-5-git-send-email-srabbelier@gmail.com","subject":"[PATCH v7 5/6] fast-import: add option command","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-06T14:35:47Z","receivedAt":"2009-09-06T14:35:47Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"This allows the frontend to specify any of the supported options as\nlong as no non-option command has been given. This way the\nuser does not have to include any frontend-specific options, but\ninstead she can rely on the frontend to tell fast-import what it\nneeds.\n\nAlso factor out parsing of argv and have it execute when we reach the\nfirst non-option command, or after all commands have been read and\nno non-option command has been encountered.\n\nNon-git options and unrecognised git options are ignored, although\nunrecognised options on the commandline still result in an error.\n\nSigned-off-by: Sverre Rabbelier <srabbelier@gmail.com>\n---\n\n  Fixed a few style errors pointed out by Junio and ignore\n  unrecognised git options.\n\n Documentation/git-fast-import.txt |   24 +++++++++++\n fast-import.c                     |   81 ++++++++++++++++++++++++++++++------\n 2 files changed, 91 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt\nindex 1e293f2..f1c94b4 100644\n--- a/Documentation/git-fast-import.txt\n+++ b/Documentation/git-fast-import.txt\n@@ -307,6 +307,11 @@ and control the current import process.  More detailed discussion\n \tRequire that fast-import supports the specified feature, or\n \tabort if it does not.\n \n+`option`::\n+    Specify any of the options listed under OPTIONS to change\n+    fast-import's behavior to suit the frontend's needs. This command\n+    is optional and is not needed to perform an import.\n+\n `commit`\n ~~~~~~~~\n Create or update a branch with a new commit, recording one logical\n@@ -829,6 +834,25 @@ it does not.\n The <feature> part of the command may be any string matching\n [a-zA-Z-] and should be understood by a version of fast-import.\n \n+`option`\n+~~~~~~~~\n+Processes the specified option so that git fast-import behaves in a\n+way that suits the frontend's needs.\n+Note that options specified by the frontend are overridden by any\n+options the user may specify to git fast-import itself.\n+\n+....\n+    'option' SP <option> LF\n+....\n+\n+The `<option>` part of the command may contain any of the options\n+listed in the OPTIONS section, without the leading '--' and is\n+treated in the same way.\n+\n+Option commands must be the first commands on the input (not counting\n+feature commands), to give an option command after any non-option\n+command is an error.\n+\n Crash Reports\n -------------\n If fast-import is supplied invalid input it will terminate with a\ndiff --git a/fast-import.c b/fast-import.c\nindex 9bf06a4..dcfb8fa 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -292,6 +292,8 @@ static unsigned long branch_load_count;\n static int failure;\n static FILE *pack_edges;\n static unsigned int show_stats = 1;\n+static int global_argc;\n+static const char **global_argv;\n \n /* Memory pools */\n static size_t mem_pool_alloc = 2*1024*1024 - sizeof(struct mem_pool);\n@@ -349,6 +351,10 @@ static struct recent_command *rc_free;\n static unsigned int cmd_save = 100;\n static uintmax_t next_mark;\n static struct strbuf new_data = STRBUF_INIT;\n+static int options_enabled;\n+static int seen_non_option_command;\n+\n+static void parse_argv(void);\n \n static void write_branch_report(FILE *rpt, struct branch *b)\n {\n@@ -1700,6 +1706,12 @@ static int read_next_command(void)\n \t\t\tif (stdin_eof)\n \t\t\t\treturn EOF;\n \n+\t\t\tif (!seen_non_option_command\n+\t\t\t\t&& prefixcmp(command_buf.buf, \"feature \")\n+\t\t\t\t&& prefixcmp(command_buf.buf, \"option \")) {\n+\t\t\t\tparse_argv();\n+\t\t\t}\n+\n \t\t\trc = rc_free;\n \t\t\tif (rc)\n \t\t\t\trc_free = rc->next;\n@@ -2423,7 +2435,7 @@ static void option_export_pack_edges(const char *edges)\n \t\tdie_errno(\"Cannot open '%s'\", edges);\n }\n \n-static void parse_one_option(const char *option)\n+static void parse_one_option(const char *option, int optional)\n {\n \tif (!prefixcmp(option, \"date-format=\")) {\n \t\toption_date_format(option + 12);\n@@ -2445,7 +2457,7 @@ static void parse_one_option(const char *option)\n \t\tshow_stats = 0;\n \t} else if (!prefixcmp(option, \"stats\")) {\n \t\tshow_stats = 1;\n-\t} else {\n+\t} else if (!optional) {\n \t\tdie(\"Unsupported option: %s\", option);\n \t}\n }\n@@ -2456,11 +2468,32 @@ static void parse_feature(void)\n \n \tif (!prefixcmp(feature, \"date-format=\")) {\n \t\toption_date_format(feature + 12);\n+\t} else if (!strcmp(\"git-options\", feature)) {\n+\t\toptions_enabled = 1;\n \t} else {\n \t\tdie(\"This version of fast-import does not support feature %s.\", feature);\n \t}\n }\n \n+static void parse_option(void)\n+{\n+\tchar *option = command_buf.buf + 11;\n+\n+\tif (!options_enabled)\n+\t\tdie(\"Got option command '%s' before options feature'\", option);\n+\n+\tif (seen_non_option_command)\n+\t\tdie(\"Got option command '%s' after non-option command\", option);\n+\n+\t/* ignore unknown options, instead of erroring */\n+\tparse_one_option(option, 1);\n+}\n+\n+static void parse_nongit_option(void)\n+{\n+\t/* do nothing */\n+}\n+\n static int git_pack_config(const char *k, const char *v, void *cb)\n {\n \tif (!strcmp(k, \"pack.depth\")) {\n@@ -2485,6 +2518,27 @@ static int git_pack_config(const char *k, const char *v, void *cb)\n static const char fast_import_usage[] =\n \"git fast-import [--date-format=f] [--max-pack-size=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]\";\n \n+static void parse_argv(void)\n+{\n+\tunsigned int i;\n+\n+\tfor (i = 1; i < global_argc; i++) {\n+\t\tconst char *a = global_argv[i];\n+\n+\t\tif (*a != '-' || !strcmp(a, \"--\"))\n+\t\t\tbreak;\n+\n+\t\t/* error on unknown options */\n+\t\tparse_one_option(a + 2, 0);\n+\t}\n+\tif (i != global_argc)\n+\t\tusage(fast_import_usage);\n+\n+\tseen_non_option_command = 1;\n+\tif (input_file)\n+\t\tread_marks();\n+}\n+\n int main(int argc, const char **argv)\n {\n \tunsigned int i;\n@@ -2503,18 +2557,8 @@ int main(int argc, const char **argv)\n \tavail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*));\n \tmarks = pool_calloc(1, sizeof(struct mark_set));\n \n-\tfor (i = 1; i < argc; i++) {\n-\t\tconst char *a = argv[i];\n-\n-\t\tif (*a != '-' || !strcmp(a, \"--\"))\n-\t\t\tbreak;\n-\n-\t\tparse_one_option(a + 2);\n-\t}\n-\tif (i != argc)\n-\t\tusage(fast_import_usage);\n-\tif (input_file)\n-\t\tread_marks();\n+\tglobal_argc = argc;\n+\tglobal_argv = argv;\n \n \trc_free = pool_alloc(cmd_save * sizeof(*rc_free));\n \tfor (i = 0; i < (cmd_save - 1); i++)\n@@ -2539,9 +2583,18 @@ int main(int argc, const char **argv)\n \t\t\tparse_progress();\n \t\telse if (!prefixcmp(command_buf.buf, \"feature \"))\n \t\t\tparse_feature();\n+\t\telse if (!prefixcmp(command_buf.buf, \"option git \"))\n+\t\t\tparse_option();\n+\t\telse if (!prefixcmp(command_buf.buf, \"option \"))\n+\t\t\tparse_nongit_option();\n \t\telse\n \t\t\tdie(\"Unsupported command: %s\", command_buf.buf);\n \t}\n+\n+\t/* argv hasn't been parsed yet, do so */\n+\tif (!seen_non_option_command)\n+\t\tparse_argv();\n+\n \tend_packfile();\n \n \tdump_branches();\n-- \n1.6.4.16.g72c66.dirty\n"},{"id":"122561","messageId":"1252247748-14507-7-git-send-email-srabbelier@gmail.com","threadId":"20862","inReplyTo":"1252247748-14507-6-git-send-email-srabbelier@gmail.com","subject":"[PATCH v7 6/6] fast-import: test the new option command","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-06T14:35:48Z","receivedAt":"2009-09-06T14:35:48Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Test three options (quiet and import/export-marks) and verify that the\ncommandline options override these.\n\nAlso make sure that a option command without a preceeding feature\ngit-options command is rejected and that non-git options are ignored.\n\nLastly, make sure that git options that we do not recognise are\nignored as well, but that they are rejected when parsed on the\ncommandline.\n\nSigned-off-by: Sverre Rabbelier <srabbelier@gmail.com>\n---\n\n  Updated tests for the new behavior.\n\n t/t9300-fast-import.sh |   89 +++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 88 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh\nindex 564ed6b..d33fc55 100755\n--- a/t/t9300-fast-import.sh\n+++ b/t/t9300-fast-import.sh\n@@ -1089,7 +1089,7 @@ test_expect_success 'P: fail on blob mark in gitlink' '\n     test_must_fail git fast-import <input'\n \n ###\n-### series R (feature)\n+### series R (feature and option)\n ###\n \n cat >input <<EOF\n@@ -1108,4 +1108,91 @@ test_expect_success 'R: supported feature is accepted' '\n \tgit fast-import <input\n '\n \n+cat >input << EOF\n+feature git-options\n+option git quiet\n+blob\n+data 3\n+hi\n+\n+EOF\n+\n+touch empty\n+\n+test_expect_success 'R: quiet option results in no stats being output' '\n+    cat input | git fast-import 2> output &&\n+    test_cmp empty output\n+'\n+\n+cat >input << EOF\n+feature git-options\n+option git export-marks=git.marks\n+blob\n+mark :1\n+data 3\n+hi\n+\n+EOF\n+\n+test_expect_success \\\n+    'R: export-marks option results in a marks file being created' \\\n+    'cat input | git fast-import &&\n+    grep :1 git.marks'\n+\n+test_expect_success \\\n+    'R: export-marks options can be overriden by commandline options' \\\n+    'cat input | git fast-import --export-marks=other.marks &&\n+    grep :1 other.marks'\n+\n+cat >input << EOF\n+feature git-options\n+option git import-marks=marks.out\n+option git export-marks=marks.new\n+EOF\n+\n+test_expect_success \\\n+    'R: import to output marks works without any content' \\\n+    'cat input | git fast-import &&\n+    test_cmp marks.out marks.new'\n+\n+cat >input <<EOF\n+feature git-options\n+option git import-marks=nonexistant.marks\n+option git export-marks=marks.new\n+EOF\n+\n+test_expect_success \\\n+    'R: import marks prefers commandline marks file over the stream' \\\n+    'cat input | git fast-import --import-marks=marks.out &&\n+    test_cmp marks.out marks.new'\n+\n+cat >input <<EOF\n+feature git-options\n+option git non-existing-option\n+EOF\n+\n+test_expect_success \\\n+    'R: feature option is accepted and ignores unknown options' \\\n+    'git fast-import <input'\n+\n+cat >input <<EOF\n+option git quiet\n+EOF\n+\n+test_expect_success 'R: unknown commandline options are rejected' '\\\n+    test_must_fail git fast-import --non-existing-option < /dev/null\n+'\n+\n+test_expect_success \\\n+    'R: option without preceeding feature command is rejected' \\\n+    'test_must_fail git fast-import <input'\n+\n+cat >input <<EOF\n+option non-existing-vcs non-existing-option\n+EOF\n+\n+test_expect_success 'R: ignore non-git options' '\n+    git fast-import <input\n+'\n+\n test_done\n-- \n1.6.4.16.g72c66.dirty\n"},{"id":"122978","messageId":"20090912184706.GP1033@spearce.org","threadId":"20862","inReplyTo":"1252247748-14507-3-git-send-email-srabbelier@gmail.com","subject":"Re: [PATCH v7 2/6] fast-import: put marks reading in it's own function","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-09-12T18:47:06Z","receivedAt":"2009-09-12T18:47:06Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sverre Rabbelier <srabbelier@gmail.com> wrote:\n> All options do nothing but set settings, with the exception of the\n> --input-marks option. Delay the reading of the marks file till after\n> all options have been parsed.\n...\n> diff --git a/fast-import.c b/fast-import.c\n> index b904f20..812fcf0 100644\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -315,6 +315,7 @@ static struct object_entry_pool *blocks;\n>  static struct object_entry *object_table[1 << 16];\n>  static struct mark_set *marks;\n>  static const char *mark_file;\n> +static const char *input_file;\n\nSorry I didn't notice this earlier in the series, but input_file\nis too generic of a name for a global in this program.  Its *not*\nthe input stream, and I fear that it might be confused as such.\n\nLikewise now mark_file is also confusing.  I would suggest renaming\nthese two:\n  \n  static const char *export_marks_file;\n  static const char *import_marks_file;\n\n-- \nShawn.\n"},{"id":"122979","messageId":"20090912185122.GQ1033@spearce.org","threadId":"20862","inReplyTo":"1252247748-14507-4-git-send-email-srabbelier@gmail.com","subject":"Re: [PATCH v7 3/6] fast-import: add feature command","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-09-12T18:51:22Z","receivedAt":"2009-09-12T18:51:22Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sverre Rabbelier <srabbelier@gmail.com> wrote:\n> This allows the fronted to require a specific feature to be supported\n> by the frontend, or abort.\n>\n> Also add support for the first feature, date-format=.\n...\n> +`feature`\n> +~~~~~~~~~\n> +Require that fast-import supports the specified feature, or abort if\n> +it does not.\n> +\n> +....\n> +\t'feature' SP <feature> LF\n> +....\n> +\n> +The <feature> part of the command may be any string matching\n> +[a-zA-Z-] and should be understood by a version of fast-import.\n> +\n\nWhere is the documentation for 'feature date-format=<FORMAT>'?\n\nAlso, IIRC the fast-import list agreed that the <feature> name must\nmatch the re ^[a-zA-Z][a-zA-Z-]*$.  Saying that here does somewhat\nhelp another fast-import developer to use the same stream format,\nbut it does not help a user to understand what features they can\nask for in their stream.\n\n> diff --git a/fast-import.c b/fast-import.c\n> index 812fcf0..9bf06a4 100644\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -2450,6 +2450,17 @@ static void parse_one_option(const char *option)\n>  \t}\n>  }\n>  \n> +static void parse_feature(void)\n> +{\n> +\tchar *feature = command_buf.buf + 8;\n> +\n> +\tif (!prefixcmp(feature, \"date-format=\")) {\n> +\t\toption_date_format(feature + 12);\n> +\t} else {\n> +\t\tdie(\"This version of fast-import does not support feature %s.\", feature);\n> +\t}\n> +}\n> +\n>  static int git_pack_config(const char *k, const char *v, void *cb)\n>  {\n>  \tif (!strcmp(k, \"pack.depth\")) {\n> @@ -2526,6 +2537,8 @@ int main(int argc, const char **argv)\n>  \t\t\tparse_checkpoint();\n>  \t\telse if (!prefixcmp(command_buf.buf, \"progress \"))\n>  \t\t\tparse_progress();\n> +\t\telse if (!prefixcmp(command_buf.buf, \"feature \"))\n> +\t\t\tparse_feature();\n\nSo its legal to change the data format in the middle of a stream?\nI thought we agreed on fast-import list that \"feature\" needs to come\nbefore any data commands, and isn't legal once data commands have\nappeared in the stream.  Thus it should not be possible to request\na change in the date-format once a blob or commit has been stored.\n\n-- \nShawn.\n"},{"id":"122980","messageId":"20090912185212.GR1033@spearce.org","threadId":"20862","inReplyTo":"1252247748-14507-5-git-send-email-srabbelier@gmail.com","subject":"Re: [PATCH v7 4/6] fast-import: test the new feature command","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-09-12T18:52:12Z","receivedAt":"2009-09-12T18:52:12Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sverre Rabbelier <srabbelier@gmail.com> wrote:\n> Test that an unknown feature causes fast-import to abort, and that a\n> known feature is accepted.\n\nThis should be squashed with the prior patch.\n \n>  t/t9300-fast-import.sh |   20 ++++++++++++++++++++\n>  1 files changed, 20 insertions(+), 0 deletions(-)\n\n-- \nShawn.\n"},{"id":"122983","messageId":"20090912190416.GS1033@spearce.org","threadId":"20862","inReplyTo":"1252247748-14507-6-git-send-email-srabbelier@gmail.com","subject":"Re: [PATCH v7 5/6] fast-import: add option command","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-09-12T19:04:16Z","receivedAt":"2009-09-12T19:04:16Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sverre Rabbelier <srabbelier@gmail.com> wrote:\n> This allows the frontend to specify any of the supported options as\n> long as no non-option command has been given. This way the\n> user does not have to include any frontend-specific options, but\n> instead she can rely on the frontend to tell fast-import what it\n> needs.\n...\n> @@ -2456,11 +2468,32 @@ static void parse_feature(void)\n>  \n>  \tif (!prefixcmp(feature, \"date-format=\")) {\n>  \t\toption_date_format(feature + 12);\n> +\t} else if (!strcmp(\"git-options\", feature)) {\n> +\t\toptions_enabled = 1;\n\nNo.  We do not want to require \"feature git-options\" in order to\nuse \"option git foo\", because \"feature git-options\" will cause an\nHg importer to abort on the same stream.\n\nOptions are meant to be optional.  If the importer recognizes the\nline, it should use it.  But if it does not, it should continue\nanyway.\n\nThe more I think about this, I may have to agree with Ian, I'm not\nsure option makes much sense.\n\nYou started this series so you could embed Git specific command line\noptions in the stream, rather than on the command line for git-hg.\n\nBut what should happen if \"option import-marks=bleh\" isn't\nunderstood by fast-import?  Wouldn't the stream be useless anyway,\nbecause the marks it assumes aren't present?  Or worse, \"option\nexport-marks=bleh\" isn't recognized.  The stream imports, but any\nmarks it was supposed to store for the frontend to reuse later\nare gone.\n\n> +static void parse_nongit_option(void)\n> +{\n> +\t/* do nothing */\n> +}\n\nPlease don't do this.  What a waste of code.\n\n> @@ -2485,6 +2518,27 @@ static int git_pack_config(const char *k, const char *v, void *cb)\n>  static const char fast_import_usage[] =\n>  \"git fast-import [--date-format=f] [--max-pack-size=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]\";\n>  \n> +static void parse_argv(void)\n> +{\n> +\tunsigned int i;\n> +\n> +\tfor (i = 1; i < global_argc; i++) {\n> +\t\tconst char *a = global_argv[i];\n> +\n> +\t\tif (*a != '-' || !strcmp(a, \"--\"))\n> +\t\t\tbreak;\n> +\n> +\t\t/* error on unknown options */\n> +\t\tparse_one_option(a + 2, 0);\n> +\t}\n> +\tif (i != global_argc)\n> +\t\tusage(fast_import_usage);\n> +\n> +\tseen_non_option_command = 1;\n\nSo if I pass a single command line option, like --export-marks,\nwe die if we see an \"option git \" inside of the stream?  That's not\nwhat we wanted to do.\n\n> @@ -2539,9 +2583,18 @@ int main(int argc, const char **argv)\n>  \t\t\tparse_progress();\n>  \t\telse if (!prefixcmp(command_buf.buf, \"feature \"))\n>  \t\t\tparse_feature();\n> +\t\telse if (!prefixcmp(command_buf.buf, \"option git \"))\n> +\t\t\tparse_option();\n> +\t\telse if (!prefixcmp(command_buf.buf, \"option \"))\n> +\t\t\tparse_nongit_option();\n\nI thought on fast-import list we agreed that the syntax of option was:\n\n  'option' SP vcs SP option\n\n  vcs ::= 'git' | 'hg' | 'bzr' | ...\n  option ::= name ('=' value)?\n  name = ^[a-zA-Z][a-zA-Z-]*$\n  value = quoted_string\n\nSo what is this parse_nongit_option() for, other than to obfuscate\nthe code?  Can't we handle all of this in parse_option, have it\ncheck the VCS tag, and return early there?\n\n-- \nShawn.\n"},{"id":"122984","messageId":"fabb9a1e0909121231l7586bb5cn90f3153e22988f42@mail.gmail.com","threadId":"20862","inReplyTo":"20090912185212.GR1033@spearce.org","subject":"Re: [PATCH v7 4/6] fast-import: test the new feature command","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-12T19:31:46Z","receivedAt":"2009-09-12T19:31:46Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sat, Sep 12, 2009 at 20:52, Shawn O. Pearce <spearce@spearce.org> wrote:\n> Sverre Rabbelier <srabbelier@gmail.com> wrote:\n>> Test that an unknown feature causes fast-import to abort, and that a\n>> known feature is accepted.\n>\n> This should be squashed with the prior patch.\n\nIs that still possible since the series is in next now? Also, with the\nseries being in next, should I send incremental patches?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"122985","messageId":"fabb9a1e0909121240q67dbcd11ube72dcbbd276168e@mail.gmail.com","threadId":"20862","inReplyTo":"20090912190416.GS1033@spearce.org","subject":"Re: [PATCH v7 5/6] fast-import: add option command","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-12T19:40:00Z","receivedAt":"2009-09-12T19:40:00Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sat, Sep 12, 2009 at 21:04, Shawn O. Pearce <spearce@spearce.org> wrote:\n> The more I think about this, I may have to agree with Ian, I'm not\n> sure option makes much sense.\n\nPerhaps instead we can replace the option series with a few extra\nfeatures? That is 'feature git-quiet' (or maybe just 'feature quiet')\nand 'feature git-marks' (or just 'feature marks', since its' fairly\ngeneric)?\n\n> But what should happen if \"option import-marks=bleh\" isn't\n> understood by fast-import?  Wouldn't the stream be useless anyway,\n> because the marks it assumes aren't present?  Or worse, \"option\n> export-marks=bleh\" isn't recognized.  The stream imports, but any\n> marks it was supposed to store for the frontend to reuse later\n> are gone.\n\nThis was why originally we aborted when we see an unrecognized option,\nI agree that due to how the series has evolved this is not such a good\nidea anymore.\n\n> @@ -2485,6 +2518,27 @@ static int git_pack_config(const char *k, const char *v, void *cb)\n>>  static const char fast_import_usage[] =\n>>  \"git fast-import [--date-format=f] [--max-pack-size=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]\";\n>>\n>> +static void parse_argv(void)\n>> +{\n>> +     unsigned int i;\n>> +\n>> +     for (i = 1; i < global_argc; i++) {\n>> +             const char *a = global_argv[i];\n>> +\n>> +             if (*a != '-' || !strcmp(a, \"--\"))\n>> +                     break;\n>> +\n>> +             /* error on unknown options */\n>> +             parse_one_option(a + 2, 0);\n>> +     }\n>> +     if (i != global_argc)\n>> +             usage(fast_import_usage);\n>> +\n>> +     seen_non_option_command = 1;\n>\n> So if I pass a single command line option, like --export-marks,\n> we die if we see an \"option git \" inside of the stream?  That's not\n> what we wanted to do.\n\nNope, parse_argv isn't called until after we encounter a non-git\noption. I think there's a test that makes sure this works too.\n\n> I thought on fast-import list we agreed that the syntax of option was:\n\nRight.\n\n> So what is this parse_nongit_option() for, other than to obfuscate\n> the code?  Can't we handle all of this in parse_option, have it\n> check the VCS tag, and return early there?\n\nI wanted to make it obvious that we ignore non-git options; depending\non whether we want to keep the option part of this series in the first\nplace I'll either handle it all in parse_option or drop those patches.\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"122986","messageId":"fabb9a1e0909121243l240dcb68jbd0207bd4b21d4ca@mail.gmail.com","threadId":"20862","inReplyTo":"20090912185122.GQ1033@spearce.org","subject":"Re: [PATCH v7 3/6] fast-import: add feature command","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-09-12T19:43:41Z","receivedAt":"2009-09-12T19:43:41Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sat, Sep 12, 2009 at 20:51, Shawn O. Pearce <spearce@spearce.org> wrote:\n> Where is the documentation for 'feature date-format=<FORMAT>'?\n\nD'oh, I forgot, my bad.\n\n> Also, IIRC the fast-import list agreed that the <feature> name must\n> match the re ^[a-zA-Z][a-zA-Z-]*$.\n\nAh, yes, of course, I'll update that.\n\n> Saying that here does somewhat\n> help another fast-import developer to use the same stream format,\n> but it does not help a user to understand what features they can\n> ask for in their stream.\n\nNo, you're absolutely right, there should be a section on supported features.\n\n> So its legal to change the data format in the middle of a stream?\n\nI'll add a !seen_non_option_command check to parse_feature, perhaps\nrenaming it to 'seen_data_command'?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"123054","messageId":"20090913132058.GN32702@genesis.frugalware.org","threadId":"20862","inReplyTo":"fabb9a1e0909121231l7586bb5cn90f3153e22988f42@mail.gmail.com","subject":"Re: [PATCH v7 4/6] fast-import: test the new feature command","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2009-09-13T13:20:58Z","receivedAt":"2009-09-13T13:20:58Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Sat, Sep 12, 2009 at 09:31:46PM +0200, Sverre Rabbelier <srabbelier@gmail.com> wrote:\n> Is that still possible since the series is in next now? Also, with the\n> series being in next, should I send incremental patches?\n\nI think so.\n"}]}