# # add_file "tests/t_automate_format.at" # # patch "Makefile.am" # from [1ace8e4181f96a79a445af69c56a1a0c963f27fc] # to [ade7e9015742e14cb226ae65e43d570fb12f3e30] # # patch "app_state.cc" # from [99273877068314cdc8d24e06032a022e72e01352] # to [8661a46d1ea69e5caab3fe6bd61c240e5b6b63f5] # # patch "app_state.hh" # from [a5ac3a99f998fee5a71b4f6201e6d26b086c7589] # to [002d9392a42c97aefa17f17002bc72503f1a5f99] # # patch "automate.cc" # from [104a3a0307c16c724da0fed33f087175aaaba5bf] # to [2868e45e313a940eea570fd0662136c13174695d] # # patch "commands.cc" # from [82065a698ea04492cefc84b2935774b9fc3b92a8] # to [e6ebd2ecb997572d1b7238a152116440f3279cfc] # # patch "monotone.1" # from [2b4b5dcbaba333709862fe47c0f02647e138a315] # to [56aebdc5617d60b0957860b309168447cd35c5fd] # # patch "monotone.cc" # from [42020d9e45090f7a39457f9e376a968fcb003fb4] # to [fe2895619e3ff270e3c5e308066b8ae3263c8e04] # # patch "monotone.texi" # from [1043aaa99cad1d0060f75058661a71ad85c12ac5] # to [db6e79ef90f20e447aff4024f13e8f481504542f] # # patch "options.hh" # from [de2a21d88f641eeb889184d57af3c433b91556ec] # to [333a0069b1ef52bbe421797e3cc0a77bc55d4dcb] # # patch "tests/t_automate_format.at" # from [] # to [b0406b619741910d673390a85a3a17269cb49520] # # patch "testsuite.at" # from [2c6c52294b3e4f89a0b7d917d732a83ab6ee99ac] # to [71159154c381d9555e5fc7483254640aa4fddd4e] # --- Makefile.am +++ Makefile.am @@ -40,6 +40,7 @@ selectors.cc selectors.hh \ annotate.cc annotate.hh \ restrictions.cc restrictions.hh \ + format.cc format.hh \ \ cleanup.hh unit_tests.hh interner.hh \ cycle_detector.hh randomfile.hh adler32.hh quick_alloc.hh \ --- app_state.cc +++ app_state.cc @@ -31,7 +31,8 @@ app_state::app_state() : branch_name(""), db(""), stdhooks(true), rcfiles(true), - search_root("/"), depth(-1) + search_root("/"), depth(-1), + format_string("%i\\n"), xml_enabled(false) { db.set_app(this); } @@ -294,6 +295,18 @@ } void +app_state::set_fmtstring(utf8 const & f) +{ + format_string = f; +} + +void +app_state::set_xml() +{ + xml_enabled = true; +} + +void app_state::set_pidfile(utf8 const & p) { pidfile = mkpath(p()); --- app_state.hh +++ app_state.hh @@ -43,6 +43,8 @@ bool found_working_copy; long depth; fs::path pidfile; + utf8 format_string; + bool xml_enabled; void allow_working_copy(); void require_working_copy(); @@ -75,6 +77,9 @@ void set_rcfiles(bool b); void add_rcfile(utf8 const & filename); + void set_fmtstring(utf8 const & fmtstring); + void set_xml(); + explicit app_state(); ~app_state(); --- automate.cc +++ automate.cc @@ -16,8 +16,9 @@ #include "restrictions.hh" #include "revision.hh" #include "vocab.hh" +#include "format.hh" -static std::string const interface_version = "0.2"; +static std::string const interface_version = "0.3"; // Name: interface_version // Arguments: none @@ -64,8 +65,9 @@ } std::set heads; get_branch_heads(app.branch_name(), app, heads); - for (std::set::const_iterator i = heads.begin(); i != heads.end(); ++i) - output << (*i).inner()() << std::endl; + + FormatFunc fmt(output, app); + for_each(heads.begin(), heads.end(), fmt); } // Name: ancestors @@ -161,9 +163,9 @@ } } } - for (std::set::const_iterator i = descendents.begin(); - i != descendents.end(); ++i) - output << (*i).inner()() << std::endl; + + FormatFunc fmt(output, app); + for_each(descendents.begin(), descendents.end(), fmt); } @@ -194,8 +196,9 @@ revs.insert(rid); } erase_ancestors(revs, app); - for (std::set::const_iterator i = revs.begin(); i != revs.end(); ++i) - output << (*i).inner()() << std::endl; + + FormatFunc fmt(output, app); + for_each(revs.begin(), revs.end(), fmt); } // Name: toposort @@ -223,9 +226,9 @@ } std::vector sorted; toposort(revs, sorted, app); - for (std::vector::const_iterator i = sorted.begin(); - i != sorted.end(); ++i) - output << (*i).inner()() << std::endl; + + FormatFunc fmt(output, app); + for_each(sorted.begin(), sorted.end(), fmt); } // Name: ancestry_difference @@ -269,9 +272,9 @@ std::vector sorted; toposort(ancestors, sorted, app); - for (std::vector::const_iterator i = sorted.begin(); - i != sorted.end(); ++i) - output << (*i).inner()() << std::endl; + + FormatFunc fmt(output, app); + for_each(sorted.begin(), sorted.end(), fmt); } // Name: leaves @@ -304,8 +307,9 @@ for (std::multimap::const_iterator i = graph.begin(); i != graph.end(); ++i) leaves.erase(i->first); - for (std::set::const_iterator i = leaves.begin(); i != leaves.end(); ++i) - output << (*i).inner()() << std::endl; + + FormatFunc fmt(output, app); + for_each(leaves.begin(), leaves.end(), fmt); } // Name: parents --- commands.cc +++ commands.cc @@ -3597,7 +3597,7 @@ "leaves\n" "inventory", "automation interface", - OPT_NONE) + OPT_FORMAT % OPT_XML) { if (args.size() == 0) throw usage(name); --- monotone.1 +++ monotone.1 @@ -290,7 +290,67 @@ \fB-@ \fI\fP An alias for \fB--xargs=\fI\fP .TP +\fB--format \fI\fP +Applies the specified format string at automate output. +The format string is made by a common part, applied to each revision, +and one or more optional changeset subformats, applied to changeset +data. +Special changeset placeholders put in the common expression are +substituted by the formatted changeset informations. +The common formatting expression is separated from the changeset ones by apposite markers. + +Common formatting specifiers: +%a : value of author certificate +.br +%b : value of branch certificate +.br +%d : value of date certificate +.br +%e : value of comment certificate +.br +%i : revision id +.br +%l : value of changelog certificate +.br +%s : value of testresult certificate +.br +%t : value of tag certificate +.br +%m : manifest id + +Changeset Placeholders: + +%P : ancestors (marker @P) +.br +%A : added files (marker @A) +.br +%D : deleted files (marker @D) +.br +%E : deleted dirs (marker @E) +.br +%R : renamed files (marker @R) +.br +%C : renamed dirs (marker @C) +.br +%M : modified files (marker @M) + +The %P,%A,%D,%E,%M changeset placeholders supports the private +specifier %f, substituted with the file/directory/ancestor name/id +The %R and %M placeholders supports the specifiers %f, current +file/directory name and %o, old file/directory name. + +Plus, all format string support the \\n, \\r, \\a, \\t, \\b, \\f, \\v +modifiers with the usual c-like meaning. +\\\\, \\% and \\@ are used to obtain the \\, % and @ char respectively. + +The default format string is '%i\\n'. +.TP +\fB--xml\fP +Generate an xml document based on automate output and containing full +revision and changeset data. + + .SH ENVIRONMENT .TP \fBEDITOR\fP --- monotone.cc +++ monotone.cc @@ -48,6 +48,8 @@ {"author", 0, POPT_ARG_STRING, &argstr, OPT_AUTHOR, "override author for commit", NULL}, {"depth", 0, POPT_ARG_LONG, &arglong, OPT_DEPTH, "limit the log output to the given number of entries", NULL}, {"pid-file", 0, POPT_ARG_STRING, &argstr, OPT_PIDFILE, "record process id of server", NULL}, + {"format", 0, POPT_ARG_STRING, &argstr, OPT_FORMAT, "specifies a format string on automate output", NULL}, + {"xml", 0, POPT_ARG_NONE, NULL, OPT_XML, "automate output will be in XML", NULL}, { NULL, 0, 0, NULL, 0, NULL, NULL } }; @@ -182,8 +184,8 @@ // the argv array be null-terminated. I(argv[argc] == NULL); N((rc = poptStuffArgs(con, argv)) >= 0, - F("weird error when stuffing arguments read from %s: %s\n") - % filename % poptStrerror(rc)); + F("weird error when stuffing arguments read from %s: %s\n") + % filename % poptStrerror(rc)); } free(argv); @@ -357,6 +359,14 @@ my_poptStuffArgFile(ctx(), utf8(string(argstr))); break; + case OPT_FORMAT: + app.set_fmtstring(string(argstr)); + break; + + case OPT_XML: + app.set_xml(); + break; + case OPT_HELP: default: requested_help = true; --- monotone.texi +++ monotone.texi @@ -4291,7 +4291,6 @@ may also give useful chatter on stderr, including warnings and error messages. - @ftable @command @item monotone automate interface_version @@ -4845,6 +4844,58 @@ @end ftable +Every automation command except @code{interface_version} supports two +optional formatting specifiers: + address@hidden --xml} +Generate an xml document based on automate output and containing full +revision and changeset data. + address@hidden address@hidden} +Applies the specified format string at automate output. +The format string is made by a common part, applied to each revision, +and one or more optional changeset subformats, applied to changeset +data. +Special changeset placeholders put in the common expression are +substituted by the formatted changeset informations. +The separate the common formatting expression is separated from the +changeset ones by apposite markers. + +Common formatting specifiers: address@hidden +%a : value of author certificate +%b : value of branch certificate +%d : value of date certificate +%e : value of comment certificate +%i : revision id +%l : value of changelog certificate +%s : value of testresult certificate +%t : value of tag certificate +%m : manifest id address@hidden verbatim + +Changeset Placeholders: address@hidden +%P : ancestors (marker @P) +%A : added files (marker @A) +%D : deleted files (marker @D) +%E : deleted dirs (marker @E) +%R : renamed files (marker @R) +%C : renamed dirs (marker @C) +%M : modified files (marker @M) address@hidden verbatim + +The %P,%A,%D,%E,%M changeset placeholders supports the private +specifier %f, substituted with the file/directory/ancestor name/id +The %R and %M placeholders supports the specifiers %f, current +file/directory name and %o, old file/directory name. + +Plus, all format string support the \\n, \\r, \\a, \\t, \\b, \\f, \\v +modifiers with the usual c-like meaning. +\\\\, \\% and \\@ are used to obtain the \\, % and @ char respectively. + +The default format string is '%i\\n'. + @page @node RCS @section RCS @@ -4852,6 +4903,8 @@ @ftable @command @item monotone rcs_import @var{filename...} + + This command imports all the file versions in each RCS file listed in @var{filename...}. These files should be raw RCS files, ending in @code{,v}. Monotone parses them directly and inserts them into your @@ -6509,6 +6562,56 @@ @item @b{-@@} @i{} An alias for @address@hidden}. address@hidden @address@hidden} +Applies the specified format string at automate output. +The format string is made by a common part, applied to each revision, +and one or more optional changeset subformats, applied to changeset +data. +Special changeset placeholders put in the common expression are +substituted by the formatted changeset informations. +The separate the common formatting expression is separated from the +changeset ones by apposite markers. + +Common formatting specifiers: address@hidden +%a : value of author certificate +%b : value of branch certificate +%d : value of date certificate +%e : value of comment certificate +%i : revision id +%l : value of changelog certificate +%s : value of testresult certificate +%t : value of tag certificate +%m : manifest id address@hidden verbatim + +Changeset Placeholders: address@hidden +%P : ancestors (marker @P) +%A : added files (marker @A) +%D : deleted files (marker @D) +%E : deleted dirs (marker @E) +%R : renamed files (marker @R) +%C : renamed dirs (marker @C) +%M : modified files (marker @M) address@hidden verbatim + +The %P,%A,%D,%E,%M changeset placeholders supports the private +specifier %f, substituted with the file/directory/ancestor name/id +The %R and %M placeholders supports the specifiers %f, current +file/directory name and %o, old file/directory name. + +Plus, all format string support the \\n, \\r, \\a, \\t, \\b, \\f, \\v +modifiers with the usual c-like meaning. +\\\\, \\% and \\@ are used to obtain the \\, % and @ char respectively. + +The default format string is '%i\\n'. + address@hidden @b{--xml} +Generate an xml document based on automate output and containing full +revision and changeset data. + + @comment TROFF INPUT: .SH ENVIRONMENT @end table --- options.hh +++ options.hh @@ -29,3 +29,5 @@ #define OPT_AUTHOR 20 #define OPT_ALL_FILES 21 #define OPT_PIDFILE 22 +#define OPT_FORMAT 23 +#define OPT_XML 24 --- tests/t_automate_format.at +++ tests/t_automate_format.at @@ -0,0 +1,49 @@ +AT_SETUP([test automate output formatting]) +MONOTONE_SETUP + +# Common formatting specifiers: +# +# %a : value of author certificate +# %b : value of branch certificate +# %d : value of date certificate +# %e : value of comment certificate +# %i : revision id +# %l : value of changelog certificate +# %s : value of testresult certificate +# %t : value of tag certificate +# %m : manifest id +# +# Changeset Placeholders: +# +# %P : ancestors (marker @P) +# %A : added files (marker @A) +# %D : deleted files (marker @D) +# %E : deleted dirs (marker @E) +# %R : renamed files (marker @R) +# %C : renamed dirs (marker @C) +# %M : modified files (marker @M) +# +# The %P,%A,%D,%E,%M changeset placeholders supports the private +# specifier %f, substituted with the file/directory/ancestor name/id +# The %R and %M placeholders supports the specifiers %f, current +# file/directory name and %o, old file/directory name. +# +# Plus, all format string support the \n, \r, \a, \t, \b, \f, \v +# modifiers with the usual c-like meaning. +# \\, \% and \@ are used to obtain the \, % and @ char respectively. +# +# The default format string is '%i\n'. +# + +ADD_FILE(foo0, [one line file +]) +COMMIT(testbranch) +REV0=`BASE_REVISION` + +AT_CHECK(MONOTONE automate heads --format="%i %b\n", [], [stdout], [ignore]) +AT_CHECK(echo $REV0 > tmp) +AT_CHECK(cmp stdout tmp, [1], [ignore], [ignore]) # make sure cmp fails for just the rev +AT_CHECK(echo $REV0 testbranch > tmp) +AT_CHECK(cmp stdout tmp) + +AT_CLEANUP --- testsuite.at +++ testsuite.at @@ -635,3 +635,4 @@ m4_include(tests/t_monotone_up.at) m4_include(tests/t_drop_vs_patch_rename.at) m4_include(tests/t_unreadable_MT.at) +m4_include(tests/t_automate_format.at)